Skip to content

fix: reject SQL containing more than one statement - #439

Draft
huytdps13400 wants to merge 1 commit into
margelo:mainfrom
huytdps13400:fix/reject-multiple-statements
Draft

huytdps13400 wants to merge 1 commit into
margelo:mainfrom
huytdps13400:fix/reject-multiple-statements

Conversation

@huytdps13400

Copy link
Copy Markdown
Contributor

Fixes #3

Root cause

prepareStatement calls sqlite3_prepare_v2 with a null tail pointer. SQLite compiles only the first statement and reports the rest through that pointer, so execute, executeAsync, batch commands, loadFile lines and prepare ran the first statement and silently dropped the rest. For example, db.execute('CREATE TABLE foo (id INTEGER); CREATE TABLE bar (id INTEGER);') creates foo and reports success, but bar never exists.

Changes

  • prepareStatement now keeps the tail. hasTrailingStatement (new header NitroSQLiteStatementTail.hpp) prepares it and treats a non-null statement or a prepare failure as another statement. The query then fails with SqlExecutionError: Query contains more than one SQL statement. Whitespace, -- and /* */ comments, and extra semicolons prepare to a null statement and still pass. An empty tail skips the extra prepare.
  • This matches the better-sqlite3 Node mock, which already rejects multi-statement SQL ("The supplied SQL string contains more than one statement"). The public JSDoc already says execute, executeAsync and prepare take one SQL statement.
  • I followed the existing NitroSQLiteStatementGroup.hpp pattern: the check is a header shared with a host test (tests/cpp/statementTail.test.cpp). The test is wired into scripts/test-cpp.sh and the cpp_tests CI paths.
  • Added a harness test to execute.spec.ts. It checks that execute, executeAsync and prepare reject the issue's query and that neither table is created.
  • Updated the parameters-and-results and load-sql-file guides.

Behavior change: SQL that used to run only its first statement now throws or rejects. This includes a loadFile line with two statements, which now rolls back the import.

Verification

  • Repro on clean main logic (prepare without tail + step, against the bundled SQLite): step rc=101 (DONE), table foo exists: 1, table bar exists: 0, with no error.
  • statementTail.test.cpp with the tail ignored, as on main: [FAIL] trailing statement was not detected: CREATE TABLE foo (id INTEGER); CREATE TABLE bar (id INTEGER);. With the fix: [PASS] detects SQL after the first statement.
  • bash scripts/test-cpp.sh: all pass.
  • NitroSQLiteOperations.cpp passes clang++ -std=c++20 -Wall -Wextra -fsyntax-only against the Nitro and nitrogen headers.
  • scripts/clang-format.sh (clang-format 18) produces no diff.
  • bun typecheck passes, and both lint commands produce no diff.
  • Jest: packages/react-native-nitro-sqlite 105/105 and example (mocha config) 8/8.
  • I did not run the new harness test in execute.spec.ts because I had no simulator or emulator here. It is modeled on the existing "rejects a query that contains no SQL" test.

Platforms: iOS, Android and macOS (shared C++).

This fix was prepared with AI assistance (Claude Code) and verified locally with the tests above.

馃 Generated with Claude Code

sqlite3_prepare_v2 compiles only the first statement and reports the rest
through its tail pointer, which prepareStatement ignored. execute,
executeAsync, batch commands, loadFile lines and prepare therefore ran the
first statement and silently dropped the rest.

Prepare the tail and throw when it holds another statement. Whitespace,
comments and extra semicolons still pass. This matches the better-sqlite3
Node mock, which already rejects multi-statement SQL.

Fixes margelo#3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 2, 2026

Copy link
Copy Markdown

@huytdps13400 is attempting to deploy a commit to the Margelo Team on Vercel.

A member of the Team first needs to authorize it.

@huytdps13400
huytdps13400 marked this pull request as draft October 2, 2026 19:25

This branch has not been deployed

No deployments
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.

Cannot execute multiple statements with one call

1 participant