Skip to content

Commit

Permalink
execute didn't work when SQL ends with a comment
Browse files Browse the repository at this point in the history
Calling `execute` with SQL like the following didn't work:

```
INSERT INTO t (x, y, z) VALUES (7, 7, 7);
INSERT INTO t (x, y, z) VALUES (8, 8, 8);
-- this is a comment at the end
```

Executing that SQL results in a `Extralite::Error: not an error` error because `prepare_multi_stmt_impl` can set `stmt` to `NULL` when SQL ends with a comment. The documentation for `sqlite3_prepare_v2` states:

> If the input text contains no SQL (if the input is an empty string or a comment) then *ppStmt is set to NULL.
  • Loading branch information
gschlager committed Mar 20, 2024
1 parent 8d08092 commit 035167b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 3 deletions.
6 changes: 6 additions & 0 deletions ext/extralite/database.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ static inline VALUE Database_perform_query(int argc, VALUE *argv, VALUE self, VA
prepare_multi_stmt(DB_GVL_MODE(db), db->sqlite3_db, &stmt, sql);
RB_GC_GUARD(sql);

if (stmt == NULL) return Qnil;

bind_all_parameters(stmt, argc - 1, argv + 1);
query_ctx ctx = QUERY_CTX(
self, sql, db, stmt, Qnil, transform,
Expand Down Expand Up @@ -485,6 +487,10 @@ VALUE Database_query_single_array(int argc, VALUE *argv, VALUE self) {
* specified using keyword arguments:
*
* db.execute('update foo set x = :bar', bar: 42)
*
* @param sql [String] query SQL
* @param parameters [Array, Hash] parameters to run query with
* @return [Integer, nil] Total number of changes effected or `nil` if the query ends with a comment.
*/
VALUE Database_execute(int argc, VALUE *argv, VALUE self) {
return Database_perform_query(argc, argv, self, safe_query_changes, QUERY_HASH);
Expand Down
48 changes: 45 additions & 3 deletions test/test_database.rb
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,7 @@ def test_database_savepoint

db.execute('insert into foo values (43)')
assert_equal [42, 43], db.query_splat('select x from foo')

db.savepoint(:b)

db.execute('insert into foo values (44)')
Expand Down Expand Up @@ -1046,6 +1046,48 @@ def test_wal_checkpoint
assert File.size(wal_fn) == 0
assert_equal [0, 0], r
end

def test_execute_with_comments
result = @db.execute(<<~SQL)
-- this is a comment
SQL
assert_nil result

result = @db.execute(<<~SQL)
DELETE FROM t;
INSERT INTO t (x, y, z) VALUES (1, 1, 1);
INSERT INTO t (x, y, z) VALUES (2, 2, 2);
SQL
assert_equal 1, result
assert_equal [1, 2], @db.query_splat('SELECT x FROM t ORDER BY x')

result = @db.execute(<<~SQL)
-- this is a comment at the beginning
DELETE FROM t;
INSERT INTO t (x, y, z) VALUES (3, 3, 3);
INSERT INTO t (x, y, z) VALUES (4, 4, 4);
SQL
assert_equal 1, result
assert_equal [3, 4], @db.query_splat('SELECT x FROM t ORDER BY x')

result = @db.execute(<<~SQL)
DELETE FROM t;
INSERT INTO t (x, y, z) VALUES (5, 5, 5);
-- this is a comment in the middle
INSERT INTO t (x, y, z) VALUES (6, 6, 6);
SQL
assert_equal 1, result
assert_equal [5, 6], @db.query_splat('SELECT x FROM t ORDER BY x')

result = @db.execute(<<~SQL)
DELETE FROM t;
INSERT INTO t (x, y, z) VALUES (7, 7, 7);
INSERT INTO t (x, y, z) VALUES (8, 8, 8);
-- this is a comment at the end
SQL
assert_nil result
assert_equal [7, 8], @db.query_splat('SELECT x FROM t ORDER BY x')
end
end

class ScenarioTest < Minitest::Test
Expand Down Expand Up @@ -1438,7 +1480,7 @@ def test_progress_handler_reset

def test_progress_handler_invalid_arg
db = Extralite::Database.new(':memory:')

assert_raises(TypeError) { db.on_progress(period: :foo) }
assert_raises(TypeError) { db.on_progress(tick: :foo) }
assert_raises(ArgumentError) { db.on_progress(mode: :foo) }
Expand Down Expand Up @@ -1635,7 +1677,7 @@ def test_global_progress_handler
class RactorTest < Minitest::Test
def test_ractor_simple
skip if SKIP_RACTOR_TESTS

fn = Tempfile.new('extralite_test_database_in_ractor').path

r = Ractor.new do
Expand Down

0 comments on commit 035167b

Please sign in to comment.