From 011d9e608b44098b1a766df9e50c57e0ce9232fb Mon Sep 17 00:00:00 2001 From: Matthijs van Duin Date: Wed, 19 Jul 2023 12:37:38 +0200 Subject: [PATCH 1/2] Fix binding of explicitly numbered parameters e.g. db.prepare('SELECT ?3, ?2, ?1').get(1, 2, 3) --- src/better_sqlite3.cpp | 29 ++++++++++++++++++----------- src/better_sqlite3.hpp | 18 ++++++++++-------- src/objects/statement.lzz | 2 +- src/util/binder.lzz | 7 ++++++- 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/better_sqlite3.cpp b/src/better_sqlite3.cpp index b0a0f8303..b0f24aa5f 100644 --- a/src/better_sqlite3.cpp +++ b/src/better_sqlite3.cpp @@ -785,7 +785,7 @@ BindMap * Statement::GetBindMap (v8::Isolate * isolate) int param_count = sqlite3_bind_parameter_count(handle); for (int i = 1; i <= param_count; ++i) { const char* name = sqlite3_bind_parameter_name(handle, i); - if (name != NULL) bind_map->Add(isolate, name + 1, i); + if (name != NULL && name[0] != '?') bind_map->Add(isolate, name + 1, i); } has_bind_map = true; return bind_map; @@ -1983,15 +1983,22 @@ void Binder::Fail (void (* Throw) (char const *), char const * message) success = false; } #line 63 "./src/util/binder.lzz" -int Binder::NextAnonIndex () +bool Binder::IsAnonIndex (int index) #line 63 "./src/util/binder.lzz" + { + const char* name = sqlite3_bind_parameter_name(handle, index); + return name == NULL || name[0] == '?'; +} +#line 68 "./src/util/binder.lzz" +int Binder::NextAnonIndex () +#line 68 "./src/util/binder.lzz" { - while (sqlite3_bind_parameter_name(handle, ++anon_index) != NULL) {} + while (!IsAnonIndex(++anon_index)) {} return anon_index; } -#line 69 "./src/util/binder.lzz" +#line 74 "./src/util/binder.lzz" void Binder::BindValue (v8::Isolate * isolate, v8::Local value, int index) -#line 69 "./src/util/binder.lzz" +#line 74 "./src/util/binder.lzz" { int status = Data::BindValueFromJS(isolate, handle, index, value); if (status != SQLITE_OK) { @@ -2010,9 +2017,9 @@ void Binder::BindValue (v8::Isolate * isolate, v8::Local value, int assert(false); } } -#line 90 "./src/util/binder.lzz" +#line 95 "./src/util/binder.lzz" int Binder::BindArray (v8::Isolate * isolate, v8::Local arr) -#line 90 "./src/util/binder.lzz" +#line 95 "./src/util/binder.lzz" { v8 :: Local < v8 :: Context > ctx = isolate -> GetCurrentContext ( ) ; uint32_t length = arr->Length(); @@ -2034,9 +2041,9 @@ int Binder::BindArray (v8::Isolate * isolate, v8::Local arr) } return len; } -#line 116 "./src/util/binder.lzz" +#line 121 "./src/util/binder.lzz" int Binder::BindObject (v8::Isolate * isolate, v8::Local obj, Statement * stmt) -#line 116 "./src/util/binder.lzz" +#line 121 "./src/util/binder.lzz" { v8 :: Local < v8 :: Context > ctx = isolate -> GetCurrentContext ( ) ; BindMap* bind_map = stmt->GetBindMap(isolate); @@ -2073,9 +2080,9 @@ int Binder::BindObject (v8::Isolate * isolate, v8::Local obj, State return len; } -#line 160 "./src/util/binder.lzz" +#line 165 "./src/util/binder.lzz" Binder::Result Binder::BindArgs (v8::FunctionCallbackInfo const & info, int argc, Statement * stmt) -#line 160 "./src/util/binder.lzz" +#line 165 "./src/util/binder.lzz" { v8 :: Isolate * isolate = info . GetIsolate ( ) ; int count = 0; diff --git a/src/better_sqlite3.hpp b/src/better_sqlite3.hpp index 0c0bcfd02..2c3f29334 100644 --- a/src/better_sqlite3.hpp +++ b/src/better_sqlite3.hpp @@ -757,22 +757,24 @@ class Binder #line 55 "./src/util/binder.lzz" void Fail (void (* Throw) (char const *), char const * message); #line 63 "./src/util/binder.lzz" + bool IsAnonIndex (int index); +#line 68 "./src/util/binder.lzz" int NextAnonIndex (); -#line 69 "./src/util/binder.lzz" +#line 74 "./src/util/binder.lzz" void BindValue (v8::Isolate * isolate, v8::Local value, int index); -#line 90 "./src/util/binder.lzz" +#line 95 "./src/util/binder.lzz" int BindArray (v8::Isolate * isolate, v8::Local arr); -#line 116 "./src/util/binder.lzz" +#line 121 "./src/util/binder.lzz" int BindObject (v8::Isolate * isolate, v8::Local obj, Statement * stmt); -#line 160 "./src/util/binder.lzz" +#line 165 "./src/util/binder.lzz" Result BindArgs (v8::FunctionCallbackInfo const & info, int argc, Statement * stmt); -#line 200 "./src/util/binder.lzz" +#line 205 "./src/util/binder.lzz" sqlite3_stmt * handle; -#line 201 "./src/util/binder.lzz" +#line 206 "./src/util/binder.lzz" int param_count; -#line 202 "./src/util/binder.lzz" +#line 207 "./src/util/binder.lzz" int anon_index; -#line 203 "./src/util/binder.lzz" +#line 208 "./src/util/binder.lzz" bool success; }; #line 34 "./src/better_sqlite3.lzz" diff --git a/src/objects/statement.lzz b/src/objects/statement.lzz index 5e2c80570..1c3dd75d4 100644 --- a/src/objects/statement.lzz +++ b/src/objects/statement.lzz @@ -29,7 +29,7 @@ public: int param_count = sqlite3_bind_parameter_count(handle); for (int i = 1; i <= param_count; ++i) { const char* name = sqlite3_bind_parameter_name(handle, i); - if (name != NULL) bind_map->Add(isolate, name + 1, i); + if (name != NULL && name[0] != '?') bind_map->Add(isolate, name + 1, i); } has_bind_map = true; return bind_map; diff --git a/src/util/binder.lzz b/src/util/binder.lzz index 9ccb5e332..39350059e 100644 --- a/src/util/binder.lzz +++ b/src/util/binder.lzz @@ -60,8 +60,13 @@ private: success = false; } + bool IsAnonIndex(int index) { + const char* name = sqlite3_bind_parameter_name(handle, index); + return name == NULL || name[0] == '?'; + } + int NextAnonIndex() { - while (sqlite3_bind_parameter_name(handle, ++anon_index) != NULL) {} + while (!IsAnonIndex(++anon_index)) {} return anon_index; } From ba0df176b6c16ef77294565f254e714bd27db162 Mon Sep 17 00:00:00 2001 From: Matthijs van Duin Date: Wed, 19 Jul 2023 12:41:47 +0200 Subject: [PATCH 2/2] Add tests for explicitly numbered parameters --- test/20.statement.run.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/20.statement.run.js b/test/20.statement.run.js index 7beb1ce56..34122141e 100644 --- a/test/20.statement.run.js +++ b/test/20.statement.run.js @@ -115,6 +115,9 @@ describe('Statement#run()', function () { this.db.prepare('INSERT INTO entries VALUES (?, ?, ?, ?)').run('foo', 25, 25, Buffer.alloc(8).fill(0xdd)); this.db.prepare('INSERT INTO entries VALUES (?, ?, ?, ?)').run(['foo', 25, 25, Buffer.alloc(8).fill(0xdd)]); this.db.prepare('INSERT INTO entries VALUES (?, ?, ?, ?)').run(['foo', 25], [25], Buffer.alloc(8).fill(0xdd)); + this.db.prepare('INSERT INTO entries VALUES (?4, ?3, ?2, ?1)').run(Buffer.alloc(8).fill(0xdd), 25, 25, 'foo'); + this.db.prepare('INSERT INTO entries VALUES (?, ?, ?2, ?)').run('foo', 25, Buffer.alloc(8).fill(0xdd)); + this.db.prepare('INSERT INTO entries VALUES (?1, ?2, ?4, ?5)').run('foo', 25, null, 25, Buffer.alloc(8).fill(0xdd)); this.db.prepare('INSERT INTO entries VALUES (@a, @b, @c, @d)').run({ a: 'foo', b: 25, c: 25, d: Buffer.alloc(8).fill(0xdd) }); this.db.prepare('INSERT INTO entries VALUES ($a, $b, $c, $d)').run({ a: 'foo', b: 25, c: 25, d: Buffer.alloc(8).fill(0xdd) }); this.db.prepare('INSERT INTO entries VALUES (:a, :b, :c, :d)').run({ a: 'foo', b: 25, c: 25, d: Buffer.alloc(8).fill(0xdd) }); @@ -165,6 +168,6 @@ describe('Statement#run()', function () { while (row = this.db.prepare(`SELECT * FROM entries WHERE rowid=${++i}`).get()) { expect(row).to.deep.equal({ a: 'foo', b: 25, c: 25, d: Buffer.alloc(8).fill(0xdd) }); } - expect(i).to.equal(11); + expect(i).to.equal(14); }); });