Skip to content

Handle read-only Postgres facade tx#221

Open
AivanF wants to merge 1 commit into
mainfrom
aivan/2026-07-03-Postgres-facade-read-only-tx
Open

Handle read-only Postgres facade tx#221
AivanF wants to merge 1 commit into
mainfrom
aivan/2026-07-03-Postgres-facade-read-only-tx

Conversation

@AivanF

@AivanF AivanF commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of transaction-opening statements so BEGIN and START TRANSACTION variants with options like READ ONLY or isolation levels are recognized correctly.
    • Reduced parse failures by retrying transaction statements in a simpler form when needed, while still returning syntax errors for invalid SQL.
    • Kept query description behavior stable when SQL cannot be translated, returning no data cleanly.
  • Tests
    • Added coverage for transaction-opening statement variants and a full read-only transaction cycle.

@AivanF AivanF requested a review from ZmeiGorynych July 3, 2026 13:44
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a pre-parse shim in the facade translator to classify BEGIN/START TRANSACTION statements (with characteristics like READ ONLY or isolation level) as no-ops before sqlglot parsing. In pg_facade connection, adds a retry path stripping these characteristics on sqlglot ParseError, and adjusts _describe_sql error logging. Tests added for both.

Changes

Transaction-open shim

Layer / File(s) Summary
Translator transaction-open classification
slayer/facade/translator.py, tests/facade/test_translator.py
Adds _classify_transaction_open regex matcher for BEGIN/START TRANSACTION characteristic clauses, wires it into translate() to short-circuit sqlglot parsing with a NoOpResult, and adds/extends tests for matching and non-matching cases.
pg_facade simple-query retry and describe handling
slayer/pg_facade/connection.py, tests/pg_facade/test_connection.py
Adds _strip_tx_open_characteristics and retries sqlglot parsing on ParseError in _handle_simple_query; updates _describe_sql to log the TranslationError before emitting NoData; adds an end-to-end test for a BEGIN READ ONLY transaction cycle.

Estimated code review effort: 2 (Simple) | ~15 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ComponentA
  participant ComponentB
  ComponentA->>ComponentB: observable interaction
Loading

Compact metadata

  • Related issues: Not specified
  • Related PRs: Not specified
  • Suggested labels: Not specified
  • Suggested reviewers: Not specified

Poem

A rabbit hopped through BEGIN and START,
stripped off the READ ONLY, ISOLATION apart,
no more parse errors to spoil the query,
just NoOp tags, quick and cheery,
COMMIT complete — back to idle we dart. 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the main change: better handling of read-only Postgres facade transactions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch aivan/2026-07-03-Postgres-facade-read-only-tx

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

sonarqubecloud Bot commented Jul 3, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@slayer/facade/translator.py`:
- Around line 2271-2283: The transaction-open regexes in translator.py are
vulnerable to quadratic backtracking because `_TX_START_RE` and `_TX_BEGIN_RE`
use overlapping whitespace quantifiers in `(?:\s+[^;]*?)?` before the trailing
terminator. Update these patterns to remove the ambiguous overlap and keep only
a single whitespace-consuming path per branch, while preserving the same
accepted `START TRANSACTION` / `BEGIN` variants used by `translate()` and
`_strip_tx_open_characteristics`. Verify the fix against the existing
transaction-opening cases and non-matching whitespace-heavy inputs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c087e6b0-ffea-41ef-a851-418246353f8d

📥 Commits

Reviewing files that changed from the base of the PR and between 0a49c44 and 3a41f88.

📒 Files selected for processing (4)
  • slayer/facade/translator.py
  • slayer/pg_facade/connection.py
  • tests/facade/test_translator.py
  • tests/pg_facade/test_connection.py

Comment on lines +2271 to +2283
# Transaction-open statements. sqlglot's postgres dialect parses bare ``BEGIN``
# / ``START TRANSACTION`` but REJECTS the characteristic forms Metabase emits
# (``BEGIN READ ONLY``, ``START TRANSACTION ISOLATION LEVEL …``). The facade is
# read-only, so every variant is a no-op that just opens a transaction; we
# recognise them BEFORE the parse to avoid the parse error entirely.
_TX_START_RE = re.compile(
r"^\s*START\s+TRANSACTION\b(?:\s+[^;]*?)?\s*;?\s*$",
re.IGNORECASE | re.DOTALL,
)
_TX_BEGIN_RE = re.compile(
r"^\s*BEGIN\b(?:\s+(?:WORK|TRANSACTION))?(?:\s+[^;]*?)?\s*;?\s*$",
re.IGNORECASE | re.DOTALL,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Quadratic regex backtracking on untrusted client SQL (flagged by SonarCloud).

Both _TX_START_RE and _TX_BEGIN_RE contain an optional group (?:\s+[^;]*?)? followed by \s*;?\s*$. Since \s+ and the lazy [^;]*? both match whitespace, the engine has many ways to split ambiguous whitespace runs when the overall match fails, causing super-linear backtracking. This runs on every client-supplied simple-query string via translate() (and again via _strip_tx_open_characteristics's retry path in connection.py), on the asyncio event loop — a crafted long, non-matching string with heavy whitespace could stall the loop for all connections.

🔒 Proposed fix to remove the ambiguous overlap
 _TX_START_RE = re.compile(
-    r"^\s*START\s+TRANSACTION\b(?:\s+[^;]*?)?\s*;?\s*$",
+    r"^\s*START\s+TRANSACTION\b[^;]*;?\s*$",
     re.IGNORECASE | re.DOTALL,
 )
 _TX_BEGIN_RE = re.compile(
-    r"^\s*BEGIN\b(?:\s+(?:WORK|TRANSACTION))?(?:\s+[^;]*?)?\s*;?\s*$",
+    r"^\s*BEGIN\b(?:\s+(?:WORK|TRANSACTION))?[^;]*;?\s*$",
     re.IGNORECASE | re.DOTALL,
 )

This keeps a single quantifier over the ambiguous character class per branch, avoiding the combinatorial backtracking while preserving the same match semantics (verified against the existing/added test cases).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Transaction-open statements. sqlglot's postgres dialect parses bare ``BEGIN``
# / ``START TRANSACTION`` but REJECTS the characteristic forms Metabase emits
# (``BEGIN READ ONLY``, ``START TRANSACTION ISOLATION LEVEL …``). The facade is
# read-only, so every variant is a no-op that just opens a transaction; we
# recognise them BEFORE the parse to avoid the parse error entirely.
_TX_START_RE = re.compile(
r"^\s*START\s+TRANSACTION\b(?:\s+[^;]*?)?\s*;?\s*$",
re.IGNORECASE | re.DOTALL,
)
_TX_BEGIN_RE = re.compile(
r"^\s*BEGIN\b(?:\s+(?:WORK|TRANSACTION))?(?:\s+[^;]*?)?\s*;?\s*$",
re.IGNORECASE | re.DOTALL,
)
# Transaction-open statements. sqlglot's postgres dialect parses bare ``BEGIN``
# / ``START TRANSACTION`` but REJECTS the characteristic forms Metabase emits
# (``BEGIN READ ONLY``, ``START TRANSACTION ISOLATION LEVEL …``). The facade is
# read-only, so every variant is a no-op that just opens a transaction; we
# recognise them BEFORE the parse to avoid the parse error entirely.
_TX_START_RE = re.compile(
r"^\s*START\s+TRANSACTION\b[^;]*;?\s*$",
re.IGNORECASE | re.DOTALL,
)
_TX_BEGIN_RE = re.compile(
r"^\s*BEGIN\b(?:\s+(?:WORK|TRANSACTION))?[^;]*;?\s*$",
re.IGNORECASE | re.DOTALL,
)
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[warning] 2281-2281: Simplify this regular expression to reduce its runtime, as it has super-linear performance due to backtracking.

See more on https://sonarcloud.io/project/issues?id=MotleyAI_slayer&issues=AZ8oOkGJ9gQYZtHC-y8L&open=AZ8oOkGJ9gQYZtHC-y8L&pullRequest=221


[warning] 2277-2277: Simplify this regular expression to reduce its runtime, as it has super-linear performance due to backtracking.

See more on https://sonarcloud.io/project/issues?id=MotleyAI_slayer&issues=AZ8oOkGJ9gQYZtHC-y8K&open=AZ8oOkGJ9gQYZtHC-y8K&pullRequest=221

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@slayer/facade/translator.py` around lines 2271 - 2283, The transaction-open
regexes in translator.py are vulnerable to quadratic backtracking because
`_TX_START_RE` and `_TX_BEGIN_RE` use overlapping whitespace quantifiers in
`(?:\s+[^;]*?)?` before the trailing terminator. Update these patterns to remove
the ambiguous overlap and keep only a single whitespace-consuming path per
branch, while preserving the same accepted `START TRANSACTION` / `BEGIN`
variants used by `translate()` and `_strip_tx_open_characteristics`. Verify the
fix against the existing transaction-opening cases and non-matching
whitespace-heavy inputs.

Source: Linters/SAST tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant