Skip to content

Comments

fix: Route PRAGMA statements through query() path and fix CI test#82

Open
ocean wants to merge 6 commits intomainfrom
dev
Open

fix: Route PRAGMA statements through query() path and fix CI test#82
ocean wants to merge 6 commits intomainfrom
dev

Conversation

@ocean
Copy link
Owner

@ocean ocean commented Feb 22, 2026

PRAGMA statements can return rows (e.g. PRAGMA wal_checkpoint(FULL) returns busy/log/checkpointed columns), but should_use_query() did not recognise them, causing them to be routed through execute() which fails with "Execute returned rows" from libsql.

Two fixes:

  • native/ecto_libsql/src/utils.rs: Add PRAGMA recognition to should_use_query() so all PRAGMA statements use the query() code path instead of execute(). This is correct behaviour since PRAGMA can always return rows.
  • test/ecto_integration_test.exs: Add PRAGMA wal_checkpoint(FULL) after CREATE UNIQUE INDEX in the composite unique index test setup. On Linux, WAL mode can cause DDL changes to be invisible to concurrent connections until the WAL is checkpointed, causing the ON CONFLICT clause to fail with "does not match any PRIMARY KEY or UNIQUE constraint".

Fixes CI failure introduced by rustler 0.37.1 -> 0.37.3 bump.

Summary by CodeRabbit

  • Bug Fixes

    • Query routing now correctly recognises PRAGMA-style statements (case-insensitive and tolerant of leading whitespace), preventing spurious “Execute returned rows” errors.
  • Tests

    • Expanded tests cover PRAGMA variations, boundary conditions and whitespace handling.
    • Integration test setup moved to a shared setup to create and remove schema objects once, reducing per-test DDL races and improving test reliability.

PRAGMA statements can return rows (e.g. PRAGMA wal_checkpoint(FULL) returns
busy/log/checkpointed columns), but should_use_query() did not recognise them,
causing them to be routed through execute() which fails with "Execute returned
rows" from libsql.

Two fixes:
- native/ecto_libsql/src/utils.rs: Add PRAGMA recognition to should_use_query()
  so all PRAGMA statements use the query() code path instead of execute(). This
  is correct behaviour since PRAGMA can always return rows.
- test/ecto_integration_test.exs: Add PRAGMA wal_checkpoint(FULL) after CREATE
  UNIQUE INDEX in the composite unique index test setup. On Linux, WAL mode can
  cause DDL changes to be invisible to concurrent connections until the WAL is
  checkpointed, causing the ON CONFLICT clause to fail with "does not match any
  PRIMARY KEY or UNIQUE constraint".

Fixes CI failure introduced by rustler 0.37.1 -> 0.37.3 bump.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 22, 2026

Warning

Rate limit exceeded

@ocean has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 7 minutes and 59 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Walkthrough

Adds case-insensitive PRAGMA detection to SQL routing so PRAGMA statements are treated as row-returning queries; updates unit tests to cover PRAGMA variants and whitespace; moves DDL setup to a global test setup and adds WAL checkpointing and teardown in integration tests.

Changes

Cohort / File(s) Summary
Query routing
native/ecto_libsql/src/utils.rs
Updates should_use_query to detect PRAGMA case-insensitively at statement start and route such statements through the query path (alongside EXPLAIN, SELECT, WITH, RETURNING). Documentation comment adjusted to reflect exact matching semantics.
Unit tests (native)
native/ecto_libsql/src/tests/utils_tests.rs
Expands tests to assert should_use_query() returns true for various PRAGMA forms including lowercase, whitespace-prefixed, and edge cases ensuring PRAGMA isn't matched inside larger words.
Integration tests / setup
test/ecto_integration_test.exs
Moves creation of locations table and composite unique index to setup_all, simplifies per-test setup to clearing rows, adds WAL checkpoint PRAGMA after index creation, and ensures test DB state cleanup in on_exit.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

I’m a rabbit reading SQL clay,
PRAGMA whispered, upper or grey.
I hop, I checkpoint, indexes gleam—
Tests hush softly like a stream. 🐇✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes: routing PRAGMA statements through query() and fixing a CI test issue related to DDL visibility.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
native/ecto_libsql/src/utils.rs (1)

362-364: Update the should_use_query doc comment to reflect all routing conditions.

The summary currently says only "SELECT or has RETURNING clause", but the function already handled EXPLAIN and WITH before this PR, and now also handles PRAGMA. The description will continue to mislead future readers.

📝 Proposed doc comment update
-/// Returns true if should use query() (SELECT or has RETURNING clause).
+/// Returns true if the statement should use `query()` rather than `execute()`.
+///
+/// Routes through `query()` when the statement may return rows:
+/// - `SELECT` — always returns rows
+/// - `WITH` — CTE; typically precedes a `SELECT`
+/// - `EXPLAIN` — always returns rows
+/// - `PRAGMA` — may return rows (e.g. `PRAGMA wal_checkpoint(FULL)`)
+/// - Any statement containing a `RETURNING` clause
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@native/ecto_libsql/src/utils.rs` around lines 362 - 364, Update the doc
comment for the function should_use_query to enumerate all routing conditions it
checks (SELECT, statements with RETURNING, EXPLAIN, WITH, and PRAGMA) instead of
only "SELECT or has RETURNING clause"; locate the comment immediately above the
should_use_query function and expand the summary to mention EXPLAIN, WITH, and
PRAGMA so the doc accurately reflects the implemented logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@native/ecto_libsql/src/utils.rs`:
- Around line 362-364: Update the doc comment for the function should_use_query
to enumerate all routing conditions it checks (SELECT, statements with
RETURNING, EXPLAIN, WITH, and PRAGMA) instead of only "SELECT or has RETURNING
clause"; locate the comment immediately above the should_use_query function and
expand the summary to mention EXPLAIN, WITH, and PRAGMA so the doc accurately
reflects the implemented logic.

The test_pragma_statements test incorrectly asserted that PRAGMA statements
should NOT use the query() path. Since PRAGMA can return rows, the correct
behaviour (implemented in the previous commit) is to always route PRAGMA
through query(). Update the test assertions accordingly and add extra cases
to cover wal_checkpoint and lowercase pragma.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
native/ecto_libsql/src/tests/utils_tests.rs (1)

263-271: All assertions are correct and align with the utils.rs implementation.

The five new cases cover the primary happy-path scenarios (mixed statement variants, lowercase pragma, and the wal_checkpoint(FULL) case that motivated this PR).

Two small coverage gaps exist compared to the test patterns already established for EXPLAIN and SELECT:

  1. No word-boundary negative casetest_not_select_if_part_of_word and test_not_cte_if_part_of_word both guard against prefix collisions (e.g. "SELECTED", "WITHDRAW"). A PRAGMA equivalent is absent.
  2. No leading-whitespace positive casetest_explain_with_whitespace verifies that skip_whitespace_and_comments works before EXPLAIN. The same is untested for PRAGMA.
🔍 Suggested additional assertions
 fn test_pragma_statements() {
     // PRAGMA statements always use query() since they can return rows.
     // E.g. PRAGMA wal_checkpoint(FULL) returns busy/log/checkpointed columns.
     assert!(should_use_query("PRAGMA table_info(users)"));
     assert!(should_use_query("PRAGMA foreign_keys = ON"));
     assert!(should_use_query("PRAGMA wal_checkpoint(FULL)"));
     assert!(should_use_query("pragma journal_mode"));
     assert!(should_use_query("PRAGMA foreign_keys"));
+
+    // Leading whitespace should be skipped correctly.
+    assert!(should_use_query("  PRAGMA journal_mode"));
+    assert!(should_use_query("\tPRAGMA table_info(users)"));
+    assert!(should_use_query("\nPRAGMA wal_checkpoint(FULL)"));
+
+    // "PRAGMAtic" and similar must NOT match — keyword boundary check.
+    assert!(!should_use_query("PRAGMAtic settings"));
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@native/ecto_libsql/src/tests/utils_tests.rs` around lines 263 - 271, Add two
small tests to cover the missing PRAGMA edge cases: (1) a negative word-boundary
case that ensures should_use_query does NOT match when "PRAGMA" is part of a
larger word (mirror tests like test_not_select_if_part_of_word /
test_not_cte_if_part_of_word), and (2) a leading-whitespace positive case that
verifies skip_whitespace_and_comments allows matching PRAGMA with leading
spaces/comments (mirror test_explain_with_whitespace). Add these assertions
alongside test_pragma_statements using the same helper should_use_query so the
behavior for should_use_query("...") is validated for both the non-word-boundary
and the whitespace-prefixed PRAGMA variants.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@native/ecto_libsql/src/tests/utils_tests.rs`:
- Around line 263-271: Add two small tests to cover the missing PRAGMA edge
cases: (1) a negative word-boundary case that ensures should_use_query does NOT
match when "PRAGMA" is part of a larger word (mirror tests like
test_not_select_if_part_of_word / test_not_cte_if_part_of_word), and (2) a
leading-whitespace positive case that verifies skip_whitespace_and_comments
allows matching PRAGMA with leading spaces/comments (mirror
test_explain_with_whitespace). Add these assertions alongside
test_pragma_statements using the same helper should_use_query so the behavior
for should_use_query("...") is validated for both the non-word-boundary and the
whitespace-prefixed PRAGMA variants.

…ity races

Creating and dropping the locations table and composite unique index inside
each test's setup callback causes a race: each Ecto.Adapters.SQL.query! call
checks out a different connection from the pool, and on Linux the connection
used for the UPSERT in the test body may not yet see the index written by a
different pool connection during setup.

The fix is to create the locations table and its unique index once in setup_all
alongside the users and posts tables. The per-test setup now simply deletes
rows from the table, which is a plain DML statement visible to all connections
immediately. This eliminates any DDL-visibility race across pool connections.
…tion

Mirror the existing test_not_select_if_part_of_word / test_not_cte_if_part_of_word
and test_explain_with_whitespace patterns for the PRAGMA branch of should_use_query:

- test_not_pragma_if_part_of_word: asserts that "PRAGMATIC" and similar strings
  do NOT match, confirming the word-boundary guard is enforced.
- test_pragma_with_whitespace: asserts that leading spaces, tabs, and newlines
  before PRAGMA are correctly skipped by skip_whitespace_and_comments.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
native/ecto_libsql/src/tests/utils_tests.rs (1)

280-286: Consider adding a mixed-case PRAGMA test for parity with other keywords.

The SELECT tests include mixed-case variants like SeLeCt and sElEcT (lines 128–129), but PRAGMA only tests uppercase and fully lowercase. A quick mixed-case assertion would confirm the per-byte case-insensitive logic end-to-end.

🧪 Optional: add mixed-case coverage
     #[test]
     fn test_pragma_with_whitespace() {
         // Leading whitespace before PRAGMA must be skipped correctly.
         assert!(should_use_query("  PRAGMA foreign_keys"));
         assert!(should_use_query("\tPRAGMA journal_mode"));
         assert!(should_use_query("\n  PRAGMA wal_checkpoint(FULL)"));
     }
+
+    #[test]
+    fn test_pragma_case_insensitive() {
+        assert!(should_use_query("PrAgMa journal_mode"));
+        assert!(should_use_query("pRaGmA foreign_keys"));
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@native/ecto_libsql/src/tests/utils_tests.rs` around lines 280 - 286, Add a
mixed-case PRAGMA assertion to the existing test_pragma_with_whitespace to
mirror the SELECT mixed-case coverage: update the test that calls
should_use_query and add at least one assertion using mixed-case letters (e.g.,
"  PrAgMa journal_mode" or "\tpRaGmA wal_checkpoint(FULL)") so the
should_use_query function's case-insensitive handling for PRAGMA is exercised
end-to-end.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@native/ecto_libsql/src/tests/utils_tests.rs`:
- Around line 280-286: Add a mixed-case PRAGMA assertion to the existing
test_pragma_with_whitespace to mirror the SELECT mixed-case coverage: update the
test that calls should_use_query and add at least one assertion using mixed-case
letters (e.g., "  PrAgMa journal_mode" or "\tpRaGmA wal_checkpoint(FULL)") so
the should_use_query function's case-insensitive handling for PRAGMA is
exercised end-to-end.

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