diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 769b1714e..7bf663afe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: matrix: os: - macos-latest - - ubuntu-latest + - ubuntu-20.04 - windows-latest host: - x64 @@ -57,7 +57,7 @@ jobs: run: npm install -g yarn - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1.1 + uses: microsoft/setup-msbuild@v1.3 if: contains(matrix.os, 'windows') with: msbuild-architecture: ${{ matrix.target }} diff --git a/binding.gyp b/binding.gyp index f1336f6f7..20d418b3c 100644 --- a/binding.gyp +++ b/binding.gyp @@ -25,8 +25,10 @@ "libraries": [ "-l<(sqlite_libname)" ], - "conditions": [ [ "OS=='linux'", {"libraries+":["-Wl,-rpath=<@(sqlite)/lib"]} ] ], - "conditions": [ [ "OS!='win'", {"libraries+":["-L<@(sqlite)/lib"]} ] ], + "conditions": [ + [ "OS=='linux'", {"libraries+":["-Wl,-rpath=<@(sqlite)/lib"]} ], + [ "OS!='win'", {"libraries+":["-L<@(sqlite)/lib"]} ] + ], 'msvs_settings': { 'VCLinkerTool': { 'AdditionalLibraryDirectories': [ diff --git a/deps/common-sqlite.gypi b/deps/common-sqlite.gypi index 4be536c3d..9d70d3b90 100644 --- a/deps/common-sqlite.gypi +++ b/deps/common-sqlite.gypi @@ -1,6 +1,6 @@ { 'variables': { - 'sqlite_version%':'3390400', + 'sqlite_version%':'3410100', "toolset%":'', }, 'target_defaults': { diff --git a/deps/sqlite-autoconf-3390400.tar.gz b/deps/sqlite-autoconf-3390400.tar.gz deleted file mode 100644 index 3ad0548d6..000000000 Binary files a/deps/sqlite-autoconf-3390400.tar.gz and /dev/null differ diff --git a/deps/sqlite-autoconf-3410100.tar.gz b/deps/sqlite-autoconf-3410100.tar.gz new file mode 100644 index 000000000..f0a9142af Binary files /dev/null and b/deps/sqlite-autoconf-3410100.tar.gz differ diff --git a/lib/sqlite3.d.ts b/lib/sqlite3.d.ts index b27b0cf51..15e66230e 100644 --- a/lib/sqlite3.d.ts +++ b/lib/sqlite3.d.ts @@ -80,16 +80,16 @@ export class Statement extends events.EventEmitter { run(params: any, callback?: (this: RunResult, err: Error | null) => void): this; run(...params: any[]): this; - get(callback?: (err: Error | null, row?: any) => void): this; - get(params: any, callback?: (this: RunResult, err: Error | null, row?: any) => void): this; + get(callback?: (err: Error | null, row?: T) => void): this; + get(params: any, callback?: (this: RunResult, err: Error | null, row?: T) => void): this; get(...params: any[]): this; - all(callback?: (err: Error | null, rows: any[]) => void): this; - all(params: any, callback?: (this: RunResult, err: Error | null, rows: any[]) => void): this; + all(callback?: (err: Error | null, rows: T[]) => void): this; + all(params: any, callback?: (this: RunResult, err: Error | null, rows: T[]) => void): this; all(...params: any[]): this; - each(callback?: (err: Error | null, row: any) => void, complete?: (err: Error | null, count: number) => void): this; - each(params: any, callback?: (this: RunResult, err: Error | null, row: any) => void, complete?: (err: Error | null, count: number) => void): this; + each(callback?: (err: Error | null, row: T) => void, complete?: (err: Error | null, count: number) => void): this; + each(params: any, callback?: (this: RunResult, err: Error | null, row: T) => void, complete?: (err: Error | null, count: number) => void): this; each(...params: any[]): this; } @@ -103,16 +103,16 @@ export class Database extends events.EventEmitter { run(sql: string, params: any, callback?: (this: RunResult, err: Error | null) => void): this; run(sql: string, ...params: any[]): this; - get(sql: string, callback?: (this: Statement, err: Error | null, row: any) => void): this; - get(sql: string, params: any, callback?: (this: Statement, err: Error | null, row: any) => void): this; + get(sql: string, callback?: (this: Statement, err: Error | null, row: T) => void): this; + get(sql: string, params: any, callback?: (this: Statement, err: Error | null, row: T) => void): this; get(sql: string, ...params: any[]): this; - all(sql: string, callback?: (this: Statement, err: Error | null, rows: any[]) => void): this; - all(sql: string, params: any, callback?: (this: Statement, err: Error | null, rows: any[]) => void): this; + all(sql: string, callback?: (this: Statement, err: Error | null, rows: T[]) => void): this; + all(sql: string, params: any, callback?: (this: Statement, err: Error | null, rows: T[]) => void): this; all(sql: string, ...params: any[]): this; - each(sql: string, callback?: (this: Statement, err: Error | null, row: any) => void, complete?: (err: Error | null, count: number) => void): this; - each(sql: string, params: any, callback?: (this: Statement, err: Error | null, row: any) => void, complete?: (err: Error | null, count: number) => void): this; + each(sql: string, callback?: (this: Statement, err: Error | null, row: T) => void, complete?: (err: Error | null, count: number) => void): this; + each(sql: string, params: any, callback?: (this: Statement, err: Error | null, row: T) => void, complete?: (err: Error | null, count: number) => void): this; each(sql: string, ...params: any[]): this; exec(sql: string, callback?: (this: Statement, err: Error | null) => void): this; diff --git a/package.json b/package.json index 91455a4f5..a5a20feaa 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "@louislam/sqlite3", "description": "Asynchronous, non-blocking SQLite3 bindings", - "version": "15.1.2", - "homepage": "https://github.com/louislam/node-sqlite3", + "version": "15.1.6", + "homepage": "https://github.com/TryGhost/node-sqlite3", "author": { "name": "Mapbox", "url": "https://mapbox.com/" @@ -57,7 +57,7 @@ "node-pre-gyp-github": "1.4.4" }, "peerDependencies": { - "node-gyp": "7.x" + "node-gyp": "8.x" }, "peerDependenciesMeta": { "node-gyp": { @@ -65,7 +65,7 @@ } }, "optionalDependencies": { - "node-gyp": "^7.1.2" + "node-gyp": "8.x" }, "scripts": { "build": "node-pre-gyp build", diff --git a/src/database.cc b/src/database.cc index b16b1f768..15709ce3d 100644 --- a/src/database.cc +++ b/src/database.cc @@ -56,7 +56,7 @@ void Database::Process() { queue.pop(); std::unique_ptr baton(call->baton); Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { TRY_CATCH_CALL(this->Value(), cb, 1, argv); called = true; } @@ -97,7 +97,7 @@ void Database::Schedule(Work_Callback callback, Baton* baton, bool exclusive) { // We don't call the actual callback, so we have to make sure that // the baton gets destroyed. delete baton; - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { exception }; TRY_CATCH_CALL(Value(), cb, 1, argv); } @@ -202,7 +202,7 @@ void Database::Work_AfterOpen(napi_env e, napi_status status, void* data) { Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { TRY_CATCH_CALL(db->Value(), cb, 1, argv); } else if (!db->open) { @@ -294,7 +294,7 @@ void Database::Work_AfterClose(napi_env e, napi_status status, void* data) { Napi::Function cb = baton->callback.Value(); // Fire callbacks. - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { TRY_CATCH_CALL(db->Value(), cb, 1, argv); } else if (db->open) { @@ -630,7 +630,7 @@ void Database::Work_AfterExec(napi_env e, napi_status status, void* data) { if (baton->status != SQLITE_OK) { EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { exception }; TRY_CATCH_CALL(db->Value(), cb, 1, argv); } @@ -639,7 +639,7 @@ void Database::Work_AfterExec(napi_env e, napi_status status, void* data) { EMIT_EVENT(db->Value(), 2, info); } } - else if (!cb.IsUndefined() && cb.IsFunction()) { + else if (IS_FUNCTION(cb)) { Napi::Value argv[] = { env.Null() }; TRY_CATCH_CALL(db->Value(), cb, 1, argv); } @@ -671,7 +671,7 @@ void Database::Work_Wait(Baton* b) { assert(baton->db->pending == 0); Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { env.Null() }; TRY_CATCH_CALL(baton->db->Value(), cb, 1, argv); } @@ -742,7 +742,7 @@ void Database::Work_AfterLoadExtension(napi_env e, napi_status status, void* dat if (baton->status != SQLITE_OK) { EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { exception }; TRY_CATCH_CALL(db->Value(), cb, 1, argv); } @@ -751,7 +751,7 @@ void Database::Work_AfterLoadExtension(napi_env e, napi_status status, void* dat EMIT_EVENT(db->Value(), 2, info); } } - else if (!cb.IsUndefined() && cb.IsFunction()) { + else if (IS_FUNCTION(cb)) { Napi::Value argv[] = { env.Null() }; TRY_CATCH_CALL(db->Value(), cb, 1, argv); } diff --git a/src/gcc-preinclude.h b/src/gcc-preinclude.h index f7e5ed59f..7a52a4dc1 100644 --- a/src/gcc-preinclude.h +++ b/src/gcc-preinclude.h @@ -12,6 +12,7 @@ __asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); __asm__(".symver exp,exp@GLIBC_2.2.5"); __asm__(".symver log,log@GLIBC_2.2.5"); +__asm__(".symver log2,log2@GLIBC_2.2.5"); __asm__(".symver pow,pow@GLIBC_2.2.5"); __asm__(".symver fcntl64,fcntl@GLIBC_2.2.5"); #endif @@ -20,6 +21,7 @@ __asm__(".symver fcntl64,fcntl@GLIBC_2.2.5"); __asm__(".symver memcpy,memcpy@GLIBC_2.17"); __asm__(".symver exp,exp@GLIBC_2.17"); __asm__(".symver log,log@GLIBC_2.17"); +__asm__(".symver log2,log2@GLIBC_2.17"); __asm__(".symver pow,pow@GLIBC_2.17"); __asm__(".symver fcntl64,fcntl@GLIBC_2.17"); #endif diff --git a/src/macros.h b/src/macros.h index b46a8752a..344642d9d 100644 --- a/src/macros.h +++ b/src/macros.h @@ -23,6 +23,9 @@ inline bool OtherIsInt(Napi::Number source) { } } +#define IS_FUNCTION(cb) \ + !cb.IsUndefined() && cb.IsFunction() + #define REQUIRE_ARGUMENTS(n) \ if (info.Length() < (n)) { \ Napi::TypeError::New(env, "Expected " #n "arguments").ThrowAsJavaScriptException(); \ diff --git a/src/statement.cc b/src/statement.cc index 6adb123f3..29e06f992 100644 --- a/src/statement.cc +++ b/src/statement.cc @@ -77,7 +77,7 @@ template void Statement::Error(T* baton) { Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { exception }; TRY_CATCH_CALL(stmt->Value(), cb, 1, argv); } @@ -208,7 +208,7 @@ template Values::Field* return new Values::Float(pos, source.ToNumber().DoubleValue()); } else if (source.IsObject()) { - Napi::String napiVal = source.ToString(); + Napi::String napiVal = Napi::String::New(source.Env(), "[object Object]"); // Check whether toString returned a value that is not undefined. if(napiVal.Type() == 0) { return NULL; @@ -375,7 +375,7 @@ void Statement::Work_AfterBind(napi_env e, napi_status status, void* data) { else { // Fire callbacks. Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { env.Null() }; TRY_CATCH_CALL(stmt->Value(), cb, 1, argv); } @@ -442,7 +442,7 @@ void Statement::Work_AfterGet(napi_env e, napi_status status, void* data) { else { // Fire callbacks. Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { if (stmt->status == SQLITE_ROW) { // Create the result array from the data we acquired. Napi::Value argv[] = { env.Null(), RowToJS(env, &baton->row) }; @@ -516,7 +516,7 @@ void Statement::Work_AfterRun(napi_env e, napi_status status, void* data) { else { // Fire callbacks. Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { (stmt->Value()).Set(Napi::String::New(env, "lastID"), Napi::Number::New(env, baton->inserted_id)); (stmt->Value()).Set( Napi::String::New(env, "changes"), Napi::Number::New(env, baton->changes)); @@ -586,7 +586,7 @@ void Statement::Work_AfterAll(napi_env e, napi_status status, void* data) { else { // Fire callbacks. Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { if (baton->rows.size()) { // Create the result array from the data we acquired. Napi::Array result(Napi::Array::New(env, baton->rows.size())); @@ -716,7 +716,7 @@ void Statement::AsyncEach(uv_async_t* handle) { } Napi::Function cb = async->item_cb.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[2]; argv[0] = env.Null(); @@ -791,7 +791,7 @@ void Statement::Work_AfterReset(napi_env e, napi_status status, void* data) { // Fire callbacks. Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { Napi::Value argv[] = { env.Null() }; TRY_CATCH_CALL(stmt->Value(), cb, 1, argv); } @@ -893,7 +893,7 @@ void Statement::Finalize_(Baton* b) { // Fire callback in case there was one. Napi::Function cb = baton->callback.Value(); - if (!cb.IsUndefined() && cb.IsFunction()) { + if (IS_FUNCTION(cb)) { TRY_CATCH_CALL(baton->stmt->Value(), cb, 0, NULL); } } diff --git a/test/other_objects.test.js b/test/other_objects.test.js index 718598768..cc516c490 100644 --- a/test/other_objects.test.js +++ b/test/other_objects.test.js @@ -95,4 +95,20 @@ describe('data types', function() { }); }); + it('should ignore faulty toString in array', function(done) { + const faulty = [[{toString: null}], 1]; + db.all('SELECT * FROM txt_table WHERE txt = ? LIMIT ?', faulty, function (err) { + assert.equal(err, null); + done(); + }); + }); + + it('should ignore faulty toString set to function', function(done) { + const faulty = [[{toString: function () {console.log('oh no');}}], 1]; + db.all('SELECT * FROM txt_table WHERE txt = ? LIMIT ?', faulty, function (err) { + assert.equal(err, undefined); + done(); + }); + }); + }); diff --git a/tools/BinaryBuilder.Dockerfile b/tools/BinaryBuilder.Dockerfile index ec0b9e59e..4760dabca 100644 --- a/tools/BinaryBuilder.Dockerfile +++ b/tools/BinaryBuilder.Dockerfile @@ -5,7 +5,7 @@ FROM node:$NODE_VERSION-$VARIANT ARG VARIANT -RUN if [[ "$VARIANT" =~ alpine* ]] ; then apk add build-base python3 --update-cache ; fi +RUN if case $VARIANT in "alpine"*) true;; *) false;; esac; then apk add build-base python3 --update-cache ; fi WORKDIR /usr/src/build @@ -22,7 +22,7 @@ ENV CXXFLAGS="${CXXFLAGS:-} -include ../src/gcc-preinclude.h" RUN npx node-pre-gyp configure RUN npx node-pre-gyp build -RUN if [[ ! "$VARIANT" =~ alpine* ]] ; then ldd lib/binding/*/node_sqlite3.node; nm lib/binding/*/node_sqlite3.node | grep "GLIBC_" | c++filt || true ; fi +RUN if case $VARIANT in "alpine"*) false;; *) true;; esac; then ldd lib/binding/*/node_sqlite3.node; nm lib/binding/*/node_sqlite3.node | grep \"GLIBC_\" | c++filt || true ; fi RUN npm run test RUN npx node-pre-gyp package