Handle read-only Postgres facade tx#221
Conversation
📝 WalkthroughWalkthroughAdds a pre-parse shim in the facade translator to classify ChangesTransaction-open shim
Estimated code review effort: 2 (Simple) | ~15 minutes Sequence Diagram(s)sequenceDiagram
participant ComponentA
participant ComponentB
ComponentA->>ComponentB: observable interaction
Compact metadata
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
There was a problem hiding this comment.
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
📒 Files selected for processing (4)
slayer/facade/translator.pyslayer/pg_facade/connection.pytests/facade/test_translator.pytests/pg_facade/test_connection.py
| # 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, | ||
| ) |
There was a problem hiding this comment.
🩺 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.
| # 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.
[warning] 2277-2277: Simplify this regular expression to reduce its runtime, as it has super-linear performance due to backtracking.
🤖 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



Summary by CodeRabbit
BEGINandSTART TRANSACTIONvariants with options likeREAD ONLYor isolation levels are recognized correctly.