diff options
Diffstat (limited to 'updater/sql/win')
23 files changed, 0 insertions, 4263 deletions
diff --git a/updater/sql/win/LICENSE b/updater/sql/win/LICENSE deleted file mode 100755 index 6c4ce40..0000000 --- a/updater/sql/win/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) MapBox -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -- Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. -- Neither the name "MapBox" nor the names of its contributors may be - used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file diff --git a/updater/sql/win/README.md b/updater/sql/win/README.md deleted file mode 100755 index ffc1f04..0000000 --- a/updater/sql/win/README.md +++ /dev/null @@ -1,249 +0,0 @@ -# ⚙️ node-sqlite3 - -Asynchronous, non-blocking [SQLite3](https://sqlite.org/) bindings for [Node.js](http://nodejs.org/). - -[![Latest release](https://img.shields.io/github/release/TryGhost/node-sqlite3.svg)](https://www.npmjs.com/package/sqlite3) -![Build Status](https://github.com/TryGhost/node-sqlite3/workflows/CI/badge.svg?branch=master) -[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fnode-sqlite3.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fnode-sqlite3?ref=badge_shield) -[![N-API v3 Badge](https://img.shields.io/badge/N--API-v3-green.svg)](https://nodejs.org/dist/latest/docs/api/n-api.html#n_api_n_api) -[![N-API v6 Badge](https://img.shields.io/badge/N--API-v6-green.svg)](https://nodejs.org/dist/latest/docs/api/n-api.html#n_api_n_api) - -# Features - - - Straightforward query and parameter binding interface - - Full Buffer/Blob support - - Extensive [debugging support](https://github.com/tryghost/node-sqlite3/wiki/Debugging) - - [Query serialization](https://github.com/tryghost/node-sqlite3/wiki/Control-Flow) API - - [Extension support](https://github.com/TryGhost/node-sqlite3/wiki/API#databaseloadextensionpath-callback), including bundled support for the [json1 extension](https://www.sqlite.org/json1.html) - - Big test suite - - Written in modern C++ and tested for memory leaks - - Bundles SQLite v3.44.2, or you can build using a local SQLite - -# Installing - -You can use [`npm`](https://github.com/npm/cli) or [`yarn`](https://github.com/yarnpkg/yarn) to install `sqlite3`: - -* (recommended) Latest published package: -```bash -npm install sqlite3 -# or -yarn add sqlite3 -``` -* GitHub's `master` branch: `npm install https://github.com/tryghost/node-sqlite3/tarball/master` - -### Prebuilt binaries - -`sqlite3` v5+ was rewritten to use [Node-API](https://nodejs.org/api/n-api.html) so prebuilt binaries do not need to be built for specific Node versions. `sqlite3` currently builds for both Node-API v3 and v6. Check the [Node-API version matrix](https://nodejs.org/api/n-api.html#node-api-version-matrix) to ensure your Node version supports one of these. The prebuilt binaries should be supported on Node v10+. - -The module uses [`prebuild-install`](https://github.com/prebuild/prebuild-install) to download the prebuilt binary for your platform, if it exists. These binaries are hosted on GitHub Releases for `sqlite3` versions above 5.0.2, and they are hosted on S3 otherwise. The following targets are currently provided: - -* `darwin-arm64` -* `darwin-x64` -* `linux-arm64` -* `linux-x64` -* `linuxmusl-arm64` -* `linuxmusl-x64` -* `win32-ia32` -* `win32-x64` - -Unfortunately, [prebuild](https://github.com/prebuild/prebuild/issues/174) cannot differentiate between `armv6` and `armv7`, and instead uses `arm` as the `{arch}`. Until that is fixed, you will still need to install `sqlite3` from [source](#source-install). - -Support for other platforms and architectures may be added in the future if CI supports building on them. - -If your environment isn't supported, it'll use `node-gyp` to build SQLite, but you will need to install a C++ compiler and linker. - -### Other ways to install - -It is also possible to make your own build of `sqlite3` from its source instead of its npm package ([See below.](#source-install)). - -The `sqlite3` module also works with [node-webkit](https://github.com/rogerwang/node-webkit) if node-webkit contains a supported version of Node.js engine. [(See below.)](#building-for-node-webkit) - -SQLite's [SQLCipher extension](https://github.com/sqlcipher/sqlcipher) is also supported. [(See below.)](#building-for-sqlcipher) - -# API - -See the [API documentation](https://github.com/TryGhost/node-sqlite3/wiki/API) in the wiki. - -# Usage - -**Note:** the module must be [installed](#installing) before use. - -``` js -const sqlite3 = require('sqlite3').verbose(); -const db = new sqlite3.Database(':memory:'); - -db.serialize(() => { - db.run("CREATE TABLE lorem (info TEXT)"); - - const stmt = db.prepare("INSERT INTO lorem VALUES (?)"); - for (let i = 0; i < 10; i++) { - stmt.run("Ipsum " + i); - } - stmt.finalize(); - - db.each("SELECT rowid AS id, info FROM lorem", (err, row) => { - console.log(row.id + ": " + row.info); - }); -}); - -db.close(); -``` - -## Source install - -To skip searching for pre-compiled binaries, and force a build from source, use - -```bash -npm install --build-from-source -``` - -The sqlite3 module depends only on libsqlite3. However, by default, an internal/bundled copy of sqlite will be built and statically linked, so an externally installed sqlite3 is not required. - -If you wish to install against an external sqlite then you need to pass the `--sqlite` argument to `npm` wrapper: - -```bash -npm install --build-from-source --sqlite=/usr/local -``` - -If building against an external sqlite3 make sure to have the development headers available. Mac OS X ships with these by default. If you don't have them installed, install the `-dev` package with your package manager, e.g. `apt-get install libsqlite3-dev` for Debian/Ubuntu. Make sure that you have at least `libsqlite3` >= 3.6. - -Note, if building against homebrew-installed sqlite on OS X you can do: - -```bash -npm install --build-from-source --sqlite=/usr/local/opt/sqlite/ -``` - -## Custom file header (magic) - -The default sqlite file header is "SQLite format 3". You can specify a different magic, though this will make standard tools and libraries unable to work with your files. - -```bash -npm install --build-from-source --sqlite_magic="MyCustomMagic15" -``` - -Note that the magic *must* be exactly 15 characters long (16 bytes including null terminator). - -## Building for node-webkit - -Because of ABI differences, `sqlite3` must be built in a custom to be used with [node-webkit](https://github.com/rogerwang/node-webkit). - -To build `sqlite3` for node-webkit: - -1. Install [`nw-gyp`](https://github.com/rogerwang/nw-gyp) globally: `npm install nw-gyp -g` *(unless already installed)* - -2. Build the module with the custom flags of `--runtime`, `--target_arch`, and `--target`: - -```bash -NODE_WEBKIT_VERSION="0.8.6" # see latest version at https://github.com/rogerwang/node-webkit#downloads -npm install sqlite3 --build-from-source --runtime=node-webkit --target_arch=ia32 --target=$(NODE_WEBKIT_VERSION) -``` - -You can also run this command from within a `sqlite3` checkout: - -```bash -npm install --build-from-source --runtime=node-webkit --target_arch=ia32 --target=$(NODE_WEBKIT_VERSION) -``` - -Remember the following: - -* You must provide the right `--target_arch` flag. `ia32` is needed to target 32bit node-webkit builds, while `x64` will target 64bit node-webkit builds (if available for your platform). - -* After the `sqlite3` package is built for node-webkit it cannot run in the vanilla Node.js (and vice versa). - * For example, `npm test` of the node-webkit's package would fail. - -Visit the “[Using Node modules](https://github.com/rogerwang/node-webkit/wiki/Using-Node-modules)” article in the node-webkit's wiki for more details. - -## Building for SQLCipher - -For instructions on building SQLCipher, see [Building SQLCipher for Node.js](https://coolaj86.com/articles/building-sqlcipher-for-node-js-on-raspberry-pi-2/). Alternatively, you can install it with your local package manager. - -To run against SQLCipher, you need to compile `sqlite3` from source by passing build options like: - -```bash -npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=/usr/ - -node -e 'require("sqlite3")' -``` - -If your SQLCipher is installed in a custom location (if you compiled and installed it yourself), you'll need to set some environment variables: - -### On OS X with Homebrew - -Set the location where `brew` installed it: - -```bash -export LDFLAGS="-L`brew --prefix`/opt/sqlcipher/lib" -export CPPFLAGS="-I`brew --prefix`/opt/sqlcipher/include/sqlcipher" -npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=`brew --prefix` - -node -e 'require("sqlite3")' -``` - -### On most Linuxes (including Raspberry Pi) - -Set the location where `make` installed it: - -```bash -export LDFLAGS="-L/usr/local/lib" -export CPPFLAGS="-I/usr/local/include -I/usr/local/include/sqlcipher" -export CXXFLAGS="$CPPFLAGS" -npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=/usr/local --verbose - -node -e 'require("sqlite3")' -``` - -### Custom builds and Electron - -Running `sqlite3` through [electron-rebuild](https://github.com/electron/electron-rebuild) does not preserve the SQLCipher extension, so some additional flags are needed to make this build Electron compatible. Your `npm install sqlite3 --build-from-source` command needs these additional flags (be sure to replace the target version with the current Electron version you are working with): - -```bash ---runtime=electron --target=18.2.1 --dist-url=https://electronjs.org/headers -``` - -In the case of MacOS with Homebrew, the command should look like the following: - -```bash -npm install sqlite3 --build-from-source --sqlite_libname=sqlcipher --sqlite=`brew --prefix` --runtime=electron --target=18.2.1 --dist-url=https://electronjs.org/headers -``` - -# Testing - -```bash -npm test -``` - -# Contributors - -* [Daniel Lockyer](https://github.com/daniellockyer) -* [Konstantin Käfer](https://github.com/kkaefer) -* [Dane Springmeyer](https://github.com/springmeyer) -* [Will White](https://github.com/willwhite) -* [Orlando Vazquez](https://github.com/orlandov) -* [Artem Kustikov](https://github.com/artiz) -* [Eric Fredricksen](https://github.com/grumdrig) -* [John Wright](https://github.com/mrjjwright) -* [Ryan Dahl](https://github.com/ry) -* [Tom MacWright](https://github.com/tmcw) -* [Carter Thaxton](https://github.com/carter-thaxton) -* [Audrius Kažukauskas](https://github.com/audriusk) -* [Johannes Schauer](https://github.com/pyneo) -* [Mithgol](https://github.com/Mithgol) -* [Kewde](https://github.com/kewde) - -# Acknowledgments - -Thanks to [Orlando Vazquez](https://github.com/orlandov), -[Eric Fredricksen](https://github.com/grumdrig) and -[Ryan Dahl](https://github.com/ry) for their SQLite bindings for node, and to mraleph on Freenode's #v8 for answering questions. - -This module was originally created by [Mapbox](https://mapbox.com/) & is now maintained by [Ghost](https://ghost.org). - -# Changelog - -We use [GitHub releases](https://github.com/TryGhost/node-sqlite3/releases) for notes on the latest versions. See [CHANGELOG.md](https://github.com/TryGhost/node-sqlite3/blob/b05f4594cf8b0de64743561fcd2cfe6f4571754d/CHANGELOG.md) in git history for details on older versions. - -# License - -`node-sqlite3` is [BSD licensed](https://github.com/tryghost/node-sqlite3/raw/master/LICENSE). - -[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fnode-sqlite3.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fnode-sqlite3?ref=badge_large) diff --git a/updater/sql/win/binding.gyp b/updater/sql/win/binding.gyp deleted file mode 100755 index a8fccd0..0000000 --- a/updater/sql/win/binding.gyp +++ /dev/null @@ -1,58 +0,0 @@ -{ - "includes": [ "deps/common-sqlite.gypi" ], - "variables": { - "sqlite%":"internal", - "sqlite_libname%":"sqlite3", - "module_name": "node_sqlite3", - }, - "targets": [ - { - "target_name": "<(module_name)", - "cflags!": [ "-fno-exceptions" ], - "cflags_cc!": [ "-fno-exceptions" ], - "xcode_settings": { "GCC_ENABLE_CPP_EXCEPTIONS": "YES", - "CLANG_CXX_LIBRARY": "libc++", - "MACOSX_DEPLOYMENT_TARGET": "10.7", - }, - "msvs_settings": { - "VCCLCompilerTool": { "ExceptionHandling": 1 }, - }, - "include_dirs": [ - "<!@(node -p \"require('node-addon-api').include\")"], - "conditions": [ - ["sqlite != 'internal'", { - "include_dirs": [ - "<!@(node -p \"require('node-addon-api').include\")", "<(sqlite)/include" ], - "libraries": [ - "-l<(sqlite_libname)" - ], - "conditions": [ - [ "OS=='linux'", {"libraries+":["-Wl,-rpath=<@(sqlite)/lib"]} ], - [ "OS!='win'", {"libraries+":["-L<@(sqlite)/lib"]} ] - ], - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalLibraryDirectories': [ - '<(sqlite)/lib' - ], - }, - } - }, - { - "dependencies": [ - "<!(node -p \"require('node-addon-api').gyp\")", - "deps/sqlite3.gyp:sqlite3" - ] - } - ] - ], - "sources": [ - "src/backup.cc", - "src/database.cc", - "src/node_sqlite3.cc", - "src/statement.cc" - ], - "defines": [ "NAPI_VERSION=<(napi_build_version)", "NAPI_DISABLE_CPP_EXCEPTIONS=1" ] - } - ] -} diff --git a/updater/sql/win/deps/common-sqlite.gypi b/updater/sql/win/deps/common-sqlite.gypi deleted file mode 100755 index a04b1d5..0000000 --- a/updater/sql/win/deps/common-sqlite.gypi +++ /dev/null @@ -1,60 +0,0 @@ -{ - 'variables': { - 'sqlite_version%':'3440200', - "toolset%":'', - }, - 'target_defaults': { - 'default_configuration': 'Release', - 'conditions': [ - [ 'toolset!=""', { - 'msbuild_toolset':'<(toolset)' - }] - ], - 'configurations': { - 'Debug': { - 'defines!': [ - 'NDEBUG' - ], - 'cflags_cc!': [ - '-O3', - '-Os', - '-DNDEBUG' - ], - 'xcode_settings': { - 'OTHER_CPLUSPLUSFLAGS!': [ - '-O3', - '-Os', - '-DDEBUG' - ], - 'GCC_OPTIMIZATION_LEVEL': '0', - 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES' - }, - 'msvs_settings': { - 'VCCLCompilerTool': { - 'ExceptionHandling': 1, # /EHsc - } - } - }, - 'Release': { - 'defines': [ - 'NDEBUG' - ], - 'xcode_settings': { - 'OTHER_CPLUSPLUSFLAGS!': [ - '-Os', - '-O2' - ], - 'GCC_OPTIMIZATION_LEVEL': '3', - 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'NO', - 'DEAD_CODE_STRIPPING': 'YES', - 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES' - }, - 'msvs_settings': { - 'VCCLCompilerTool': { - 'ExceptionHandling': 1, # /EHsc - } - } - } - } - } -} diff --git a/updater/sql/win/deps/extract.js b/updater/sql/win/deps/extract.js deleted file mode 100755 index 46aed47..0000000 --- a/updater/sql/win/deps/extract.js +++ /dev/null @@ -1,10 +0,0 @@ -const tar = require("tar"); -const path = require("path"); -const tarball = path.resolve(process.argv[2]); -const dirname = path.resolve(process.argv[3]); - -tar.extract({ - sync: true, - file: tarball, - cwd: dirname, -}); diff --git a/updater/sql/win/deps/sqlite-autoconf-3440200.tar.gz b/updater/sql/win/deps/sqlite-autoconf-3440200.tar.gz Binary files differdeleted file mode 100755 index 701a614..0000000 --- a/updater/sql/win/deps/sqlite-autoconf-3440200.tar.gz +++ /dev/null diff --git a/updater/sql/win/deps/sqlite3.gyp b/updater/sql/win/deps/sqlite3.gyp deleted file mode 100755 index 660b3b0..0000000 --- a/updater/sql/win/deps/sqlite3.gyp +++ /dev/null @@ -1,121 +0,0 @@ -{ - 'includes': [ 'common-sqlite.gypi' ], - - 'variables': { - 'sqlite_magic%': '', - }, - - 'target_defaults': { - 'default_configuration': 'Release', - 'cflags':[ - '-std=c99' - ], - 'configurations': { - 'Debug': { - 'defines': [ 'DEBUG', '_DEBUG' ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'RuntimeLibrary': 1, # static debug - }, - }, - }, - 'Release': { - 'defines': [ 'NDEBUG' ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'RuntimeLibrary': 0, # static release - }, - }, - } - }, - 'msvs_settings': { - 'VCCLCompilerTool': { - }, - 'VCLibrarianTool': { - }, - 'VCLinkerTool': { - 'GenerateDebugInformation': 'true', - }, - }, - 'conditions': [ - ['OS == "win"', { - 'defines': [ - 'WIN32' - ], - }] - ], - }, - - 'targets': [ - { - 'target_name': 'action_before_build', - 'type': 'none', - 'hard_dependency': 1, - 'actions': [ - { - 'action_name': 'unpack_sqlite_dep', - 'inputs': [ - './sqlite-autoconf-<@(sqlite_version).tar.gz' - ], - 'outputs': [ - '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/sqlite3.c' - ], - 'action': ['node','./extract.js','./sqlite-autoconf-<@(sqlite_version).tar.gz','<(SHARED_INTERMEDIATE_DIR)'] - } - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/', - ] - }, - }, - { - 'target_name': 'sqlite3', - 'type': 'static_library', - 'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/' ], - 'dependencies': [ - 'action_before_build' - ], - 'sources': [ - '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/sqlite3.c' - ], - 'direct_dependent_settings': { - 'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/' ], - 'defines': [ - 'SQLITE_THREADSAFE=1', - 'HAVE_USLEEP=1', - 'SQLITE_ENABLE_FTS3', - 'SQLITE_ENABLE_FTS4', - 'SQLITE_ENABLE_FTS5', - 'SQLITE_ENABLE_RTREE', - 'SQLITE_ENABLE_DBSTAT_VTAB=1', - 'SQLITE_ENABLE_MATH_FUNCTIONS' - ], - }, - 'cflags_cc': [ - '-Wno-unused-value' - ], - 'defines': [ - '_REENTRANT=1', - 'SQLITE_THREADSAFE=1', - 'HAVE_USLEEP=1', - 'SQLITE_ENABLE_FTS3', - 'SQLITE_ENABLE_FTS4', - 'SQLITE_ENABLE_FTS5', - 'SQLITE_ENABLE_RTREE', - 'SQLITE_ENABLE_DBSTAT_VTAB=1', - 'SQLITE_ENABLE_MATH_FUNCTIONS' - ], - 'export_dependent_settings': [ - 'action_before_build', - ], - 'conditions': [ - ["sqlite_magic != ''", { - 'defines': [ - 'SQLITE_FILE_HEADER="<(sqlite_magic)"' - ] - }] - ], - } - ] -} diff --git a/updater/sql/win/lib/sqlite3-binding.js b/updater/sql/win/lib/sqlite3-binding.js deleted file mode 100755 index 98d1b91..0000000 --- a/updater/sql/win/lib/sqlite3-binding.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('bindings')('node_sqlite3.node'); diff --git a/updater/sql/win/lib/sqlite3.d.ts b/updater/sql/win/lib/sqlite3.d.ts deleted file mode 100755 index 15e6623..0000000 --- a/updater/sql/win/lib/sqlite3.d.ts +++ /dev/null @@ -1,205 +0,0 @@ -// Type definitions for sqlite3 -// Project: http://github.com/tryghost/node-sqlite3 - -/// <reference types="node" /> - -import events = require("events"); - -export const OPEN_READONLY: number; -export const OPEN_READWRITE: number; -export const OPEN_CREATE: number; -export const OPEN_FULLMUTEX: number; -export const OPEN_SHAREDCACHE: number; -export const OPEN_PRIVATECACHE: number; -export const OPEN_URI: number; - -export const VERSION: string; -export const SOURCE_ID: string; -export const VERSION_NUMBER: number; - -export const OK: number; -export const ERROR: number; -export const INTERNAL: number; -export const PERM: number; -export const ABORT: number; -export const BUSY: number; -export const LOCKED: number; -export const NOMEM: number; -export const READONLY: number; -export const INTERRUPT: number -export const IOERR: number; -export const CORRUPT: number -export const NOTFOUND: number; -export const FULL: number; -export const CANTOPEN: number; -export const PROTOCOL: number; -export const EMPTY: number; -export const SCHEMA: number; -export const TOOBIG: number -export const CONSTRAINT: number -export const MISMATCH: number; -export const MISUSE: number; -export const NOLFS: number; -export const AUTH: number -export const FORMAT: number; -export const RANGE: number -export const NOTADB: number; - -export const LIMIT_LENGTH: number; -export const LIMIT_SQL_LENGTH: number; -export const LIMIT_COLUMN: number; -export const LIMIT_EXPR_DEPTH: number; -export const LIMIT_COMPOUND_SELECT: number; -export const LIMIT_VDBE_OP: number; -export const LIMIT_FUNCTION_ARG: number; -export const LIMIT_ATTACHED: number; -export const LIMIT_LIKE_PATTERN_LENGTH: number; -export const LIMIT_VARIABLE_NUMBER: number; -export const LIMIT_TRIGGER_DEPTH: number; -export const LIMIT_WORKER_THREADS: number; - -export const cached: { - Database(filename: string, callback?: (this: Database, err: Error | null) => void): Database; - Database(filename: string, mode?: number, callback?: (this: Database, err: Error | null) => void): Database; -}; - -export interface RunResult extends Statement { - lastID: number; - changes: number; -} - -export class Statement extends events.EventEmitter { - bind(callback?: (err: Error | null) => void): this; - bind(...params: any[]): this; - - reset(callback?: (err: null) => void): this; - - finalize(callback?: (err: Error) => void): Database; - - run(callback?: (err: Error | null) => void): this; - run(params: any, callback?: (this: RunResult, err: Error | null) => void): this; - run(...params: any[]): this; - - get<T>(callback?: (err: Error | null, row?: T) => void): this; - get<T>(params: any, callback?: (this: RunResult, err: Error | null, row?: T) => void): this; - get(...params: any[]): this; - - all<T>(callback?: (err: Error | null, rows: T[]) => void): this; - all<T>(params: any, callback?: (this: RunResult, err: Error | null, rows: T[]) => void): this; - all(...params: any[]): this; - - each<T>(callback?: (err: Error | null, row: T) => void, complete?: (err: Error | null, count: number) => void): this; - each<T>(params: any, callback?: (this: RunResult, err: Error | null, row: T) => void, complete?: (err: Error | null, count: number) => void): this; - each(...params: any[]): this; -} - -export class Database extends events.EventEmitter { - constructor(filename: string, callback?: (err: Error | null) => void); - constructor(filename: string, mode?: number, callback?: (err: Error | null) => void); - - close(callback?: (err: Error | null) => void): void; - - run(sql: string, callback?: (this: RunResult, err: Error | null) => void): this; - run(sql: string, params: any, callback?: (this: RunResult, err: Error | null) => void): this; - run(sql: string, ...params: any[]): this; - - get<T>(sql: string, callback?: (this: Statement, err: Error | null, row: T) => void): this; - get<T>(sql: string, params: any, callback?: (this: Statement, err: Error | null, row: T) => void): this; - get(sql: string, ...params: any[]): this; - - all<T>(sql: string, callback?: (this: Statement, err: Error | null, rows: T[]) => void): this; - all<T>(sql: string, params: any, callback?: (this: Statement, err: Error | null, rows: T[]) => void): this; - all(sql: string, ...params: any[]): this; - - each<T>(sql: string, callback?: (this: Statement, err: Error | null, row: T) => void, complete?: (err: Error | null, count: number) => void): this; - each<T>(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; - - prepare(sql: string, callback?: (this: Statement, err: Error | null) => void): Statement; - prepare(sql: string, params: any, callback?: (this: Statement, err: Error | null) => void): Statement; - prepare(sql: string, ...params: any[]): Statement; - - serialize(callback?: () => void): void; - parallelize(callback?: () => void): void; - - on(event: "trace", listener: (sql: string) => void): this; - on(event: "profile", listener: (sql: string, time: number) => void): this; - on(event: "change", listener: (type: string, database: string, table: string, rowid: number) => void): this; - on(event: "error", listener: (err: Error) => void): this; - on(event: "open" | "close", listener: () => void): this; - on(event: string, listener: (...args: any[]) => void): this; - - configure(option: "busyTimeout", value: number): void; - configure(option: "limit", id: number, value: number): void; - - loadExtension(filename: string, callback?: (err: Error | null) => void): this; - - wait(callback?: (param: null) => void): this; - - interrupt(): void; -} - -export function verbose(): sqlite3; - -export interface sqlite3 { - OPEN_READONLY: number; - OPEN_READWRITE: number; - OPEN_CREATE: number; - OPEN_FULLMUTEX: number; - OPEN_SHAREDCACHE: number; - OPEN_PRIVATECACHE: number; - OPEN_URI: number; - - VERSION: string; - SOURCE_ID: string; - VERSION_NUMBER: number; - - OK: number; - ERROR: number; - INTERNAL: number; - PERM: number; - ABORT: number; - BUSY: number; - LOCKED: number; - NOMEM: number; - READONLY: number; - INTERRUPT: number - IOERR: number; - CORRUPT: number - NOTFOUND: number; - FULL: number; - CANTOPEN: number; - PROTOCOL: number; - EMPTY: number; - SCHEMA: number; - TOOBIG: number - CONSTRAINT: number - MISMATCH: number; - MISUSE: number; - NOLFS: number; - AUTH: number - FORMAT: number; - RANGE: number - NOTADB: number; - - LIMIT_LENGTH: number; - LIMIT_SQL_LENGTH: number; - LIMIT_COLUMN: number; - LIMIT_EXPR_DEPTH: number; - LIMIT_COMPOUND_SELECT: number; - LIMIT_VDBE_OP: number; - LIMIT_FUNCTION_ARG: number; - LIMIT_ATTACHED: number; - LIMIT_LIKE_PATTERN_LENGTH: number; - LIMIT_VARIABLE_NUMBER: number; - LIMIT_TRIGGER_DEPTH: number; - LIMIT_WORKER_THREADS: number; - - cached: typeof cached; - RunResult: RunResult; - Statement: typeof Statement; - Database: typeof Database; - verbose(): this; -}
\ No newline at end of file diff --git a/updater/sql/win/lib/sqlite3.js b/updater/sql/win/lib/sqlite3.js deleted file mode 100755 index 430a2b8..0000000 --- a/updater/sql/win/lib/sqlite3.js +++ /dev/null @@ -1,207 +0,0 @@ -const path = require('path'); -const sqlite3 = require('./sqlite3-binding.js'); -const EventEmitter = require('events').EventEmitter; -module.exports = exports = sqlite3; - -function normalizeMethod (fn) { - return function (sql) { - let errBack; - const args = Array.prototype.slice.call(arguments, 1); - - if (typeof args[args.length - 1] === 'function') { - const callback = args[args.length - 1]; - errBack = function(err) { - if (err) { - callback(err); - } - }; - } - const statement = new Statement(this, sql, errBack); - return fn.call(this, statement, args); - }; -} - -function inherits(target, source) { - for (const k in source.prototype) - target.prototype[k] = source.prototype[k]; -} - -sqlite3.cached = { - Database: function(file, a, b) { - if (file === '' || file === ':memory:') { - // Don't cache special databases. - return new Database(file, a, b); - } - - let db; - file = path.resolve(file); - - if (!sqlite3.cached.objects[file]) { - db = sqlite3.cached.objects[file] = new Database(file, a, b); - } - else { - // Make sure the callback is called. - db = sqlite3.cached.objects[file]; - const callback = (typeof a === 'number') ? b : a; - if (typeof callback === 'function') { - function cb() { callback.call(db, null); } - if (db.open) process.nextTick(cb); - else db.once('open', cb); - } - } - - return db; - }, - objects: {} -}; - - -const Database = sqlite3.Database; -const Statement = sqlite3.Statement; -const Backup = sqlite3.Backup; - -inherits(Database, EventEmitter); -inherits(Statement, EventEmitter); -inherits(Backup, EventEmitter); - -// Database#prepare(sql, [bind1, bind2, ...], [callback]) -Database.prototype.prepare = normalizeMethod(function(statement, params) { - return params.length - ? statement.bind.apply(statement, params) - : statement; -}); - -// Database#run(sql, [bind1, bind2, ...], [callback]) -Database.prototype.run = normalizeMethod(function(statement, params) { - statement.run.apply(statement, params).finalize(); - return this; -}); - -// Database#get(sql, [bind1, bind2, ...], [callback]) -Database.prototype.get = normalizeMethod(function(statement, params) { - statement.get.apply(statement, params).finalize(); - return this; -}); - -// Database#all(sql, [bind1, bind2, ...], [callback]) -Database.prototype.all = normalizeMethod(function(statement, params) { - statement.all.apply(statement, params).finalize(); - return this; -}); - -// Database#each(sql, [bind1, bind2, ...], [callback], [complete]) -Database.prototype.each = normalizeMethod(function(statement, params) { - statement.each.apply(statement, params).finalize(); - return this; -}); - -Database.prototype.map = normalizeMethod(function(statement, params) { - statement.map.apply(statement, params).finalize(); - return this; -}); - -// Database#backup(filename, [callback]) -// Database#backup(filename, destName, sourceName, filenameIsDest, [callback]) -Database.prototype.backup = function() { - let backup; - if (arguments.length <= 2) { - // By default, we write the main database out to the main database of the named file. - // This is the most likely use of the backup api. - backup = new Backup(this, arguments[0], 'main', 'main', true, arguments[1]); - } else { - // Otherwise, give the user full control over the sqlite3_backup_init arguments. - backup = new Backup(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]); - } - // Per the sqlite docs, exclude the following errors as non-fatal by default. - backup.retryErrors = [sqlite3.BUSY, sqlite3.LOCKED]; - return backup; -}; - -Statement.prototype.map = function() { - const params = Array.prototype.slice.call(arguments); - const callback = params.pop(); - params.push(function(err, rows) { - if (err) return callback(err); - const result = {}; - if (rows.length) { - const keys = Object.keys(rows[0]); - const key = keys[0]; - if (keys.length > 2) { - // Value is an object - for (let i = 0; i < rows.length; i++) { - result[rows[i][key]] = rows[i]; - } - } else { - const value = keys[1]; - // Value is a plain value - for (let i = 0; i < rows.length; i++) { - result[rows[i][key]] = rows[i][value]; - } - } - } - callback(err, result); - }); - return this.all.apply(this, params); -}; - -let isVerbose = false; - -const supportedEvents = [ 'trace', 'profile', 'change' ]; - -Database.prototype.addListener = Database.prototype.on = function(type) { - const val = EventEmitter.prototype.addListener.apply(this, arguments); - if (supportedEvents.indexOf(type) >= 0) { - this.configure(type, true); - } - return val; -}; - -Database.prototype.removeListener = function(type) { - const val = EventEmitter.prototype.removeListener.apply(this, arguments); - if (supportedEvents.indexOf(type) >= 0 && !this._events[type]) { - this.configure(type, false); - } - return val; -}; - -Database.prototype.removeAllListeners = function(type) { - const val = EventEmitter.prototype.removeAllListeners.apply(this, arguments); - if (supportedEvents.indexOf(type) >= 0) { - this.configure(type, false); - } - return val; -}; - -// Save the stack trace over EIO callbacks. -sqlite3.verbose = function() { - if (!isVerbose) { - const trace = require('./trace'); - [ - 'prepare', - 'get', - 'run', - 'all', - 'each', - 'map', - 'close', - 'exec' - ].forEach(function (name) { - trace.extendTrace(Database.prototype, name); - }); - [ - 'bind', - 'get', - 'run', - 'all', - 'each', - 'map', - 'reset', - 'finalize', - ].forEach(function (name) { - trace.extendTrace(Statement.prototype, name); - }); - isVerbose = true; - } - - return sqlite3; -}; diff --git a/updater/sql/win/lib/trace.js b/updater/sql/win/lib/trace.js deleted file mode 100755 index 1d84cb0..0000000 --- a/updater/sql/win/lib/trace.js +++ /dev/null @@ -1,38 +0,0 @@ -// Inspired by https://github.com/tlrobinson/long-stack-traces -const util = require('util'); - -function extendTrace(object, property, pos) { - const old = object[property]; - object[property] = function() { - const error = new Error(); - const name = object.constructor.name + '#' + property + '(' + - Array.prototype.slice.call(arguments).map(function(el) { - return util.inspect(el, false, 0); - }).join(', ') + ')'; - - if (typeof pos === 'undefined') pos = -1; - if (pos < 0) pos += arguments.length; - const cb = arguments[pos]; - if (typeof arguments[pos] === 'function') { - arguments[pos] = function replacement() { - const err = arguments[0]; - if (err && err.stack && !err.__augmented) { - err.stack = filter(err).join('\n'); - err.stack += '\n--> in ' + name; - err.stack += '\n' + filter(error).slice(1).join('\n'); - err.__augmented = true; - } - return cb.apply(this, arguments); - }; - } - return old.apply(this, arguments); - }; -} -exports.extendTrace = extendTrace; - - -function filter(error) { - return error.stack.split('\n').filter(function(line) { - return line.indexOf(__filename) < 0; - }); -} diff --git a/updater/sql/win/package.json b/updater/sql/win/package.json deleted file mode 100755 index b6496ad..0000000 --- a/updater/sql/win/package.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "name": "sqlite3-win", - "description": "Asynchronous, non-blocking SQLite3 bindings", - "version": "5.1.7", - "homepage": "https://github.com/TryGhost/node-sqlite3", - "author": { - "name": "Mapbox", - "url": "https://mapbox.com/" - }, - "binary": { - "napi_versions": [ - 3, - 6 - ] - }, - "contributors": [ - "Daniel Lockyer <hi@daniellockyer.com>", - "Konstantin Käfer <mail@kkaefer.com>", - "Dane Springmeyer <dane@mapbox.com>", - "Will White <will@mapbox.com>", - "Orlando Vazquez <ovazquez@gmail.com>", - "Artem Kustikov <kustikoff@gmail.com>", - "Eric Fredricksen <efredricksen@gmail.com>", - "John Wright <mrjjwright@gmail.com>", - "Ryan Dahl <ry@tinyclouds.org>", - "Tom MacWright <tom@mapbox.com>", - "Carter Thaxton <carter.thaxton@gmail.com>", - "Audrius Kažukauskas <audrius@neutrino.lt>", - "Johannes Schauer <josch@pyneo.org>", - "Nathan Rajlich <nathan@tootallnate.net>", - "AJ ONeal <coolaj86@gmail.com>", - "Mithgol", - "Ben Noordhuis <ben@strongloop.com>" - ], - "files": [ - "binding.gyp", - "deps/", - "lib/*.js", - "lib/*.d.ts", - "src/" - ], - "repository": { - "type": "git", - "url": "https://github.com/TryGhost/node-sqlite3.git" - }, - "dependencies": { - "bindings": "^1.5.0", - "node-addon-api": "^7.0.0", - "prebuild-install": "^7.1.1", - "tar": "^6.1.11" - }, - "devDependencies": { - "eslint": "8.56.0", - "mocha": "10.2.0", - "prebuild": "12.1.0" - }, - "peerDependencies": { - "node-gyp": "8.x" - }, - "peerDependenciesMeta": { - "node-gyp": { - "optional": true - } - }, - "optionalDependencies": { - "node-gyp": "8.x" - }, - "scripts": { - "install": "prebuild-install -r napi || node-gyp rebuild", - "prebuild": "prebuild --runtime napi --all --verbose", - "rebuild": "node-gyp rebuild", - "upload": "prebuild --verbose --prerelease", - "test": "node test/support/createdb.js && mocha -R spec --timeout 480000" - }, - "license": "BSD-3-Clause", - "keywords": [ - "sql", - "sqlite", - "sqlite3", - "database" - ], - "main": "./lib/sqlite3", - "types": "./lib/sqlite3.d.ts", - "renovate": { - "extends": [ - "@tryghost:base" - ] - } -} diff --git a/updater/sql/win/src/async.h b/updater/sql/win/src/async.h deleted file mode 100755 index f36e4cb..0000000 --- a/updater/sql/win/src/async.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef NODE_SQLITE3_SRC_ASYNC_H -#define NODE_SQLITE3_SRC_ASYNC_H - -#include <napi.h> -#include <uv.h> - -#include "threading.h" - -// Generic uv_async handler. -template <class Item, class Parent> class Async { - typedef void (*Callback)(Parent* parent, Item* item); - -protected: - uv_async_t watcher; - NODE_SQLITE3_MUTEX_t - std::vector<Item*> data; - Callback callback; -public: - Parent* parent; - -public: - Async(Parent* parent_, Callback cb_) - : callback(cb_), parent(parent_) { - watcher.data = this; - NODE_SQLITE3_MUTEX_INIT - uv_loop_t *loop; - napi_get_uv_event_loop(parent_->Env(), &loop); - uv_async_init(loop, &watcher, reinterpret_cast<uv_async_cb>(listener)); - } - - static void listener(uv_async_t* handle) { - auto* async = static_cast<Async*>(handle->data); - std::vector<Item*> rows; - NODE_SQLITE3_MUTEX_LOCK(&async->mutex) - rows.swap(async->data); - NODE_SQLITE3_MUTEX_UNLOCK(&async->mutex) - for(auto row : rows) - async->callback(async->parent, row); - } - - static void close(uv_handle_t* handle) { - assert(handle != NULL); - assert(handle->data != NULL); - auto* async = static_cast<Async*>(handle->data); - delete async; - } - - void finish() { - // Need to call the listener again to ensure all items have been - // processed. Is this a bug in uv_async? Feels like uv_close - // should handle that. - listener(&watcher); - uv_close((uv_handle_t*)&watcher, close); - } - - void add(Item* item) { - NODE_SQLITE3_MUTEX_LOCK(&mutex); - data.emplace_back(item); - NODE_SQLITE3_MUTEX_UNLOCK(&mutex) - } - - void send() { - uv_async_send(&watcher); - } - - void send(Item* item) { - add(item); - send(); - } - - ~Async() { - NODE_SQLITE3_MUTEX_DESTROY - } -}; - -#endif diff --git a/updater/sql/win/src/backup.cc b/updater/sql/win/src/backup.cc deleted file mode 100755 index 0f971f5..0000000 --- a/updater/sql/win/src/backup.cc +++ /dev/null @@ -1,418 +0,0 @@ -#include <cstring> -#include <napi.h> -#include "macros.h" -#include "database.h" -#include "backup.h" - -using namespace node_sqlite3; - -Napi::Object Backup::Init(Napi::Env env, Napi::Object exports) { - Napi::HandleScope scope(env); - - // declare napi_default_method here as it is only available in Node v14.12.0+ - auto napi_default_method = static_cast<napi_property_attributes>(napi_writable | napi_configurable); - - auto t = DefineClass(env, "Backup", { - InstanceMethod("step", &Backup::Step, napi_default_method), - InstanceMethod("finish", &Backup::Finish, napi_default_method), - InstanceAccessor("idle", &Backup::IdleGetter, nullptr), - InstanceAccessor("completed", &Backup::CompletedGetter, nullptr), - InstanceAccessor("failed", &Backup::FailedGetter, nullptr), - InstanceAccessor("remaining", &Backup::RemainingGetter, nullptr), - InstanceAccessor("pageCount", &Backup::PageCountGetter, nullptr), - InstanceAccessor("retryErrors", &Backup::RetryErrorGetter, &Backup::RetryErrorSetter), - }); - - exports.Set("Backup", t); - return exports; -} - -void Backup::Process() { - if (finished && !queue.empty()) { - return CleanQueue(); - } - - while (inited && !locked && !queue.empty()) { - auto call = std::move(queue.front()); - queue.pop(); - - call->callback(call->baton); - } -} - -void Backup::Schedule(Work_Callback callback, Baton* baton) { - if (finished) { - queue.emplace(new Call(callback, baton)); - CleanQueue(); - } - else if (!inited || locked || !queue.empty()) { - queue.emplace(new Call(callback, baton)); - } - else { - callback(baton); - } -} - -template <class T> void Backup::Error(T* baton) { - auto env = baton->backup->Env(); - Napi::HandleScope scope(env); - - Backup* backup = baton->backup; - // Fail hard on logic errors. - assert(backup->status != 0); - EXCEPTION(Napi::String::New(env, backup->message), backup->status, exception); - - Napi::Function cb = baton->callback.Value(); - - if (!cb.IsEmpty() && cb.IsFunction()) { - Napi::Value argv[] = { exception }; - TRY_CATCH_CALL(backup->Value(), cb, 1, argv); - } - else { - Napi::Value argv[] = { Napi::String::New(env, "error"), exception }; - EMIT_EVENT(backup->Value(), 2, argv); - } -} - -void Backup::CleanQueue() { - auto env = this->Env(); - Napi::HandleScope scope(env); - - if (inited && !queue.empty()) { - // This backup has already been initialized and is now finished. - // Fire error for all remaining items in the queue. - EXCEPTION(Napi::String::New(env, "Backup is already finished"), SQLITE_MISUSE, exception); - Napi::Value argv[] = { exception }; - bool called = false; - - // Clear out the queue so that this object can get GC'ed. - while (!queue.empty()) { - auto call = std::move(queue.front()); - queue.pop(); - - std::unique_ptr<Baton> baton(call->baton); - Napi::Function cb = baton->callback.Value(); - - if (inited && !cb.IsEmpty() && - cb.IsFunction()) { - TRY_CATCH_CALL(Value(), cb, 1, argv); - called = true; - } - } - - // When we couldn't call a callback function, emit an error on the - // Backup object. - if (!called) { - Napi::Value info[] = { Napi::String::New(env, "error"), exception }; - EMIT_EVENT(Value(), 2, info); - } - } - else while (!queue.empty()) { - // Just delete all items in the queue; we already fired an event when - // initializing the backup failed. - auto call = std::move(queue.front()); - queue.pop(); - - // We don't call the actual callback, so we have to make sure that - // the baton gets destroyed. - delete call->baton; - } -} - -Backup::Backup(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Backup>(info) { - auto env = info.Env(); - if (!info.IsConstructCall()) { - Napi::TypeError::New(env, "Use the new operator to create new Backup objects").ThrowAsJavaScriptException(); - return; - } - - auto length = info.Length(); - - if (length <= 0 || !Database::HasInstance(info[0])) { - Napi::TypeError::New(env, "Database object expected").ThrowAsJavaScriptException(); - return; - } - else if (length <= 1 || !info[1].IsString()) { - Napi::TypeError::New(env, "Filename expected").ThrowAsJavaScriptException(); - return; - } - else if (length <= 2 || !info[2].IsString()) { - Napi::TypeError::New(env, "Source database name expected").ThrowAsJavaScriptException(); - return; - } - else if (length <= 3 || !info[3].IsString()) { - Napi::TypeError::New(env, "Destination database name expected").ThrowAsJavaScriptException(); - return; - } - else if (length <= 4 || !info[4].IsBoolean()) { - Napi::TypeError::New(env, "Direction flag expected").ThrowAsJavaScriptException(); - return; - } - else if (length > 5 && !info[5].IsUndefined() && !info[5].IsFunction()) { - Napi::TypeError::New(env, "Callback expected").ThrowAsJavaScriptException(); - return; - } - - this->db = Napi::ObjectWrap<Database>::Unwrap(info[0].As<Napi::Object>()); - this->db->Ref(); - - auto filename = info[1].As<Napi::String>(); - auto sourceName = info[2].As<Napi::String>(); - auto destName = info[3].As<Napi::String>(); - auto filenameIsDest = info[4].As<Napi::Boolean>(); - - info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("filename", filename)); - info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("sourceName", sourceName)); - info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("destName", destName)); - info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("filenameIsDest", filenameIsDest)); - - auto* baton = new InitializeBaton(this->db, info[5].As<Napi::Function>(), this); - baton->filename = filename.Utf8Value(); - baton->sourceName = sourceName.Utf8Value(); - baton->destName = destName.Utf8Value(); - baton->filenameIsDest = filenameIsDest.Value(); - - this->db->Schedule(Work_BeginInitialize, baton); -} - -void Backup::Work_BeginInitialize(Database::Baton* baton) { - assert(baton->db->open); - baton->db->pending++; - auto env = baton->db->Env(); - CREATE_WORK("sqlite3.Backup.Initialize", Work_Initialize, Work_AfterInitialize); -} - -void Backup::Work_Initialize(napi_env e, void* data) { - BACKUP_INIT(InitializeBaton); - - // In case stepping fails, we use a mutex to make sure we get the associated - // error message. - auto* mtx = sqlite3_db_mutex(baton->db->_handle); - sqlite3_mutex_enter(mtx); - - backup->status = sqlite3_open(baton->filename.c_str(), &backup->_otherDb); - - if (backup->status == SQLITE_OK) { - backup->_handle = sqlite3_backup_init( - baton->filenameIsDest ? backup->_otherDb : backup->db->_handle, - baton->destName.c_str(), - baton->filenameIsDest ? backup->db->_handle : backup->_otherDb, - baton->sourceName.c_str()); - } - backup->_destDb = baton->filenameIsDest ? backup->_otherDb : backup->db->_handle; - - if (backup->status != SQLITE_OK) { - backup->message = std::string(sqlite3_errmsg(backup->_destDb)); - sqlite3_close(backup->_otherDb); - backup->_otherDb = NULL; - backup->_destDb = NULL; - } - - sqlite3_mutex_leave(mtx); -} - -void Backup::Work_AfterInitialize(napi_env e, napi_status status, void* data) { - std::unique_ptr<InitializeBaton> baton(static_cast<InitializeBaton*>(data)); - auto* backup = baton->backup; - - auto env = backup->Env(); - Napi::HandleScope scope(env); - - if (backup->status != SQLITE_OK) { - Error(baton.get()); - backup->FinishAll(); - } - else { - backup->inited = true; - Napi::Function cb = baton->callback.Value(); - if (!cb.IsEmpty() && cb.IsFunction()) { - Napi::Value argv[] = { env.Null() }; - TRY_CATCH_CALL(backup->Value(), cb, 1, argv); - } - } - BACKUP_END(); -} - -Napi::Value Backup::Step(const Napi::CallbackInfo& info) { - auto* backup = this; - auto env = backup->Env(); - - REQUIRE_ARGUMENT_INTEGER(0, pages); - OPTIONAL_ARGUMENT_FUNCTION(1, callback); - - auto* baton = new StepBaton(backup, callback, pages); - backup->GetRetryErrors(baton->retryErrorsSet); - backup->Schedule(Work_BeginStep, baton); - return info.This(); -} - -void Backup::Work_BeginStep(Baton* baton) { - BACKUP_BEGIN(Step); -} - -void Backup::Work_Step(napi_env e, void* data) { - BACKUP_INIT(StepBaton); - if (backup->_handle) { - backup->status = sqlite3_backup_step(backup->_handle, baton->pages); - backup->remaining = sqlite3_backup_remaining(backup->_handle); - backup->pageCount = sqlite3_backup_pagecount(backup->_handle); - } - if (backup->status != SQLITE_OK) { - // Text of message is a little awkward to get, since the error is not associated - // with a db connection. -#if SQLITE_VERSION_NUMBER >= 3007015 - // sqlite3_errstr is a relatively new method - backup->message = std::string(sqlite3_errstr(backup->status)); -#else - backup->message = "Sqlite error"; -#endif - if (baton->retryErrorsSet.size() > 0) { - if (baton->retryErrorsSet.find(backup->status) == baton->retryErrorsSet.end()) { - backup->FinishSqlite(); - } - } - } -} - -void Backup::Work_AfterStep(napi_env e, napi_status status, void* data) { - std::unique_ptr<StepBaton> baton(static_cast<StepBaton*>(data)); - auto* backup = baton->backup; - - auto env = backup->Env(); - Napi::HandleScope scope(env); - - if (backup->status == SQLITE_DONE) { - backup->completed = true; - } else if (!backup->_handle) { - backup->failed = true; - } - - if (backup->status != SQLITE_OK && backup->status != SQLITE_DONE) { - Error(baton.get()); - } - else { - // Fire callbacks. - Napi::Function cb = baton->callback.Value(); - if (!cb.IsEmpty() && cb.IsFunction()) { - Napi::Value argv[] = { env.Null(), Napi::Boolean::New(env, backup->status == SQLITE_DONE) }; - TRY_CATCH_CALL(backup->Value(), cb, 2, argv); - } - } - - BACKUP_END(); -} - -Napi::Value Backup::Finish(const Napi::CallbackInfo& info) { - auto* backup = this; - auto env = backup->Env(); - - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - auto* baton = new Baton(backup, callback); - backup->Schedule(Work_BeginFinish, baton); - return info.This(); -} - -void Backup::Work_BeginFinish(Baton* baton) { - BACKUP_BEGIN(Finish); -} - -void Backup::Work_Finish(napi_env e, void* data) { - BACKUP_INIT(Baton); - backup->FinishSqlite(); -} - -void Backup::Work_AfterFinish(napi_env e, napi_status status, void* data) { - std::unique_ptr<Baton> baton(static_cast<Baton*>(data)); - auto* backup = baton->backup; - - auto env = backup->Env(); - Napi::HandleScope scope(env); - - backup->FinishAll(); - - // Fire callback in case there was one. - Napi::Function cb = baton->callback.Value(); - if (!cb.IsEmpty() && cb.IsFunction()) { - TRY_CATCH_CALL(backup->Value(), cb, 0, NULL); - } - - BACKUP_END(); -} - -void Backup::FinishAll() { - assert(!finished); - if (!completed && !failed) { - failed = true; - } - finished = true; - CleanQueue(); - FinishSqlite(); - db->Unref(); -} - -void Backup::FinishSqlite() { - if (_handle) { - sqlite3_backup_finish(_handle); - _handle = NULL; - } - if (_otherDb) { - sqlite3_close(_otherDb); - _otherDb = NULL; - } - _destDb = NULL; -} - -Napi::Value Backup::IdleGetter(const Napi::CallbackInfo& info) { - auto* backup = this; - bool idle = backup->inited && !backup->locked && backup->queue.empty(); - return Napi::Boolean::New(this->Env(), idle); -} - -Napi::Value Backup::CompletedGetter(const Napi::CallbackInfo& info) { - auto* backup = this; - return Napi::Boolean::New(this->Env(), backup->completed); -} - -Napi::Value Backup::FailedGetter(const Napi::CallbackInfo& info) { - auto* backup = this; - return Napi::Boolean::New(this->Env(), backup->failed); -} - -Napi::Value Backup::RemainingGetter(const Napi::CallbackInfo& info) { - auto* backup = this; - return Napi::Number::New(this->Env(), backup->remaining); -} - -Napi::Value Backup::PageCountGetter(const Napi::CallbackInfo& info) { - auto* backup = this; - return Napi::Number::New(this->Env(), backup->pageCount); -} - -Napi::Value Backup::RetryErrorGetter(const Napi::CallbackInfo& info) { - auto* backup = this; - return backup->retryErrors.Value(); -} - -void Backup::RetryErrorSetter(const Napi::CallbackInfo& info, const Napi::Value& value) { - auto* backup = this; - auto env = backup->Env(); - if (!value.IsArray()) { - Napi::Error::New(env, "retryErrors must be an array").ThrowAsJavaScriptException(); - return; - } - Napi::Array array = value.As<Napi::Array>(); - backup->retryErrors.Reset(array, 1); -} - -void Backup::GetRetryErrors(std::set<int>& retryErrorsSet) { - retryErrorsSet.clear(); - Napi::Array array = retryErrors.Value(); - auto length = array.Length(); - for (size_t i = 0; i < length; i++) { - Napi::Value code = (array).Get(static_cast<uint32_t>(i)); - if (code.IsNumber()) { - retryErrorsSet.insert(code.As<Napi::Number>().Int32Value()); - } - } -} diff --git a/updater/sql/win/src/backup.h b/updater/sql/win/src/backup.h deleted file mode 100755 index b894aca..0000000 --- a/updater/sql/win/src/backup.h +++ /dev/null @@ -1,209 +0,0 @@ -#ifndef NODE_SQLITE3_SRC_BACKUP_H -#define NODE_SQLITE3_SRC_BACKUP_H - -#include "database.h" - -#include <string> -#include <queue> -#include <set> - -#include <sqlite3.h> -#include <napi.h> - -using namespace Napi; - -namespace node_sqlite3 { - -/** - * - * A class for managing an sqlite3_backup object. For consistency - * with other node-sqlite3 classes, it maintains an internal queue - * of calls. - * - * Intended usage from node: - * - * var db = new sqlite3.Database('live.db'); - * var backup = db.backup('backup.db'); - * ... - * // in event loop, move backup forward when we have time. - * if (backup.idle) { backup.step(NPAGES); } - * if (backup.completed) { ... success ... } - * if (backup.failed) { ... sadness ... } - * // do other work in event loop - fine to modify live.db - * ... - * - * Here is how sqlite's backup api is exposed: - * - * - `sqlite3_backup_init`: This is implemented as - * `db.backup(filename, [callback])` or - * `db.backup(filename, destDbName, sourceDbName, filenameIsDest, [callback])`. - * - `sqlite3_backup_step`: `backup.step(pages, [callback])`. - * - `sqlite3_backup_finish`: `backup.finish([callback])`. - * - `sqlite3_backup_remaining`: `backup.remaining`. - * - `sqlite3_backup_pagecount`: `backup.pageCount`. - * - * There are the following read-only properties: - * - * - `backup.completed` is set to `true` when the backup - * succeeeds. - * - `backup.failed` is set to `true` when the backup - * has a fatal error. - * - `backup.idle` is set to `true` when no operation - * is currently in progress or queued for the backup. - * - `backup.remaining` is an integer with the remaining - * number of pages after the last call to `backup.step` - * (-1 if `step` not yet called). - * - `backup.pageCount` is an integer with the total number - * of pages measured during the last call to `backup.step` - * (-1 if `step` not yet called). - * - * There is the following writable property: - * - * - `backup.retryErrors`: an array of sqlite3 error codes - * that are treated as non-fatal - meaning, if they occur, - * backup.failed is not set, and the backup may continue. - * By default, this is `[sqlite3.BUSY, sqlite3.LOCKED]`. - * - * The `db.backup(filename, [callback])` shorthand is sufficient - * for making a backup of a database opened by node-sqlite3. If - * using attached or temporary databases, or moving data in the - * opposite direction, the more complete (but daunting) - * `db.backup(filename, destDbName, sourceDbName, filenameIsDest, [callback])` - * signature is provided. - * - * A backup will finish automatically when it succeeds or a fatal - * error occurs, meaning it is not necessary to call `db.finish()`. - * By default, SQLITE_LOCKED and SQLITE_BUSY errors are not - * treated as failures, and the backup will continue if they - * occur. The set of errors that are tolerated can be controlled - * by setting `backup.retryErrors`. To disable automatic - * finishing and stick strictly to sqlite's raw api, set - * `backup.retryErrors` to `[]`. In that case, it is necessary - * to call `backup.finish()`. - * - * In the same way as node-sqlite3 databases and statements, - * backup methods can be called safely without callbacks, due - * to an internal call queue. So for example this naive code - * will correctly back up a db, if there are no errors: - * - * var backup = db.backup('backup.db'); - * backup.step(-1); - * backup.finish(); - * - */ -class Backup : public Napi::ObjectWrap<Backup> { -public: - static Napi::Object Init(Napi::Env env, Napi::Object exports); - - struct Baton { - napi_async_work request = NULL; - Backup* backup; - Napi::FunctionReference callback; - - Baton(Backup* backup_, Napi::Function cb_) : backup(backup_) { - backup->Ref(); - callback.Reset(cb_, 1); - } - virtual ~Baton() { - if (request) napi_delete_async_work(backup->Env(), request); - backup->Unref(); - callback.Reset(); - } - }; - - struct InitializeBaton : Database::Baton { - Backup* backup; - std::string filename; - std::string sourceName; - std::string destName; - bool filenameIsDest; - InitializeBaton(Database* db_, Napi::Function cb_, Backup* backup_) : - Baton(db_, cb_), backup(backup_), filenameIsDest(true) { - backup->Ref(); - } - virtual ~InitializeBaton() override { - backup->Unref(); - if (!db->IsOpen() && db->IsLocked()) { - // The database handle was closed before the backup could be opened. - backup->FinishAll(); - } - } - }; - - struct StepBaton : Baton { - int pages; - std::set<int> retryErrorsSet; - StepBaton(Backup* backup_, Napi::Function cb_, int pages_) : - Baton(backup_, cb_), pages(pages_) {} - virtual ~StepBaton() override = default; - }; - - typedef void (*Work_Callback)(Baton* baton); - - struct Call { - Call(Work_Callback cb_, Baton* baton_) : callback(cb_), baton(baton_) {}; - Work_Callback callback; - Baton* baton; - }; - - Backup(const Napi::CallbackInfo& info); - - ~Backup() { - if (!finished) { - FinishAll(); - } - retryErrors.Reset(); - } - - WORK_DEFINITION(Step) - WORK_DEFINITION(Finish) - - Napi::Value IdleGetter(const Napi::CallbackInfo& info); - Napi::Value CompletedGetter(const Napi::CallbackInfo& info); - Napi::Value FailedGetter(const Napi::CallbackInfo& info); - Napi::Value PageCountGetter(const Napi::CallbackInfo& info); - Napi::Value RemainingGetter(const Napi::CallbackInfo& info); - Napi::Value FatalErrorGetter(const Napi::CallbackInfo& info); - Napi::Value RetryErrorGetter(const Napi::CallbackInfo& info); - - void FatalErrorSetter(const Napi::CallbackInfo& info, const Napi::Value& value); - void RetryErrorSetter(const Napi::CallbackInfo& info, const Napi::Value& value); - -protected: - static void Work_BeginInitialize(Database::Baton* baton); - static void Work_Initialize(napi_env env, void* data); - static void Work_AfterInitialize(napi_env env, napi_status status, void* data); - - void Schedule(Work_Callback callback, Baton* baton); - void Process(); - void CleanQueue(); - template <class T> static void Error(T* baton); - - void FinishAll(); - void FinishSqlite(); - void GetRetryErrors(std::set<int>& retryErrorsSet); - - Database* db; - - sqlite3_backup* _handle = NULL; - sqlite3* _otherDb = NULL; - sqlite3* _destDb = NULL; - - bool inited = false; - bool locked = true; - bool completed = false; - bool failed = false; - int remaining = -1; - int pageCount = -1; - bool finished = false; - - int status; - std::string message; - std::queue<std::unique_ptr<Call>> queue; - - Napi::Reference<Array> retryErrors; -}; - -} - -#endif diff --git a/updater/sql/win/src/database.cc b/updater/sql/win/src/database.cc deleted file mode 100755 index d495ce9..0000000 --- a/updater/sql/win/src/database.cc +++ /dev/null @@ -1,751 +0,0 @@ -#include <cstring> -#include <napi.h> - -#include "macros.h" -#include "database.h" -#include "statement.h" - -using namespace node_sqlite3; - -#if NAPI_VERSION < 6 -Napi::FunctionReference Database::constructor; -#endif - -Napi::Object Database::Init(Napi::Env env, Napi::Object exports) { - Napi::HandleScope scope(env); - // declare napi_default_method here as it is only available in Node v14.12.0+ - auto napi_default_method = static_cast<napi_property_attributes>(napi_writable | napi_configurable); - - auto t = DefineClass(env, "Database", { - InstanceMethod("close", &Database::Close, napi_default_method), - InstanceMethod("exec", &Database::Exec, napi_default_method), - InstanceMethod("wait", &Database::Wait, napi_default_method), - InstanceMethod("loadExtension", &Database::LoadExtension, napi_default_method), - InstanceMethod("serialize", &Database::Serialize, napi_default_method), - InstanceMethod("parallelize", &Database::Parallelize, napi_default_method), - InstanceMethod("configure", &Database::Configure, napi_default_method), - InstanceMethod("interrupt", &Database::Interrupt, napi_default_method), - InstanceAccessor("open", &Database::Open, nullptr) - }); - -#if NAPI_VERSION < 6 - constructor = Napi::Persistent(t); - constructor.SuppressDestruct(); -#else - Napi::FunctionReference* constructor = new Napi::FunctionReference(); - *constructor = Napi::Persistent(t); - env.SetInstanceData<Napi::FunctionReference>(constructor); -#endif - - exports.Set("Database", t); - return exports; -} - -void Database::Process() { - auto env = this->Env(); - Napi::HandleScope scope(env); - - if (!open && locked && !queue.empty()) { - EXCEPTION(Napi::String::New(env, "Database handle is closed"), SQLITE_MISUSE, exception); - Napi::Value argv[] = { exception }; - bool called = false; - - // Call all callbacks with the error object. - while (!queue.empty()) { - auto call = std::unique_ptr<Call>(queue.front()); - queue.pop(); - auto baton = std::unique_ptr<Baton>(call->baton); - Napi::Function cb = baton->callback.Value(); - if (IS_FUNCTION(cb)) { - TRY_CATCH_CALL(this->Value(), cb, 1, argv); - called = true; - } - } - - // When we couldn't call a callback function, emit an error on the - // Database object. - if (!called) { - Napi::Value info[] = { Napi::String::New(env, "error"), exception }; - EMIT_EVENT(Value(), 2, info); - } - return; - } - - while (open && (!locked || pending == 0) && !queue.empty()) { - Call *c = queue.front(); - - if (c->exclusive && pending > 0) { - break; - } - - queue.pop(); - std::unique_ptr<Call> call(c); - locked = call->exclusive; - call->callback(call->baton); - - if (locked) break; - } -} - -void Database::Schedule(Work_Callback callback, Baton* baton, bool exclusive) { - auto env = this->Env(); - Napi::HandleScope scope(env); - - if (!open && locked) { - EXCEPTION(Napi::String::New(env, "Database is closed"), SQLITE_MISUSE, exception); - Napi::Function cb = baton->callback.Value(); - // We don't call the actual callback, so we have to make sure that - // the baton gets destroyed. - delete baton; - if (IS_FUNCTION(cb)) { - Napi::Value argv[] = { exception }; - TRY_CATCH_CALL(Value(), cb, 1, argv); - } - else { - Napi::Value argv[] = { Napi::String::New(env, "error"), exception }; - EMIT_EVENT(Value(), 2, argv); - } - return; - } - - if (!open || ((locked || exclusive || serialize) && pending > 0)) { - queue.emplace(new Call(callback, baton, exclusive || serialize)); - } - else { - locked = exclusive; - callback(baton); - } -} - -Database::Database(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Database>(info) { - auto env = info.Env(); - - if (info.Length() <= 0 || !info[0].IsString()) { - Napi::TypeError::New(env, "String expected").ThrowAsJavaScriptException(); - return; - } - auto filename = info[0].As<Napi::String>().Utf8Value(); - - unsigned int pos = 1; - - int mode; - if (info.Length() >= pos && info[pos].IsNumber() && OtherIsInt(info[pos].As<Napi::Number>())) { - mode = info[pos++].As<Napi::Number>().Int32Value(); - } - else { - mode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX; - } - - Napi::Function callback; - if (info.Length() >= pos && info[pos].IsFunction()) { - callback = info[pos++].As<Napi::Function>(); - } - - info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("filename", info[0].As<Napi::String>(), napi_default)); - info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("mode", Napi::Number::New(env, mode), napi_default)); - - // Start opening the database. - auto* baton = new OpenBaton(this, callback, filename.c_str(), mode); - Work_BeginOpen(baton); -} - -void Database::Work_BeginOpen(Baton* baton) { - auto env = baton->db->Env(); - CREATE_WORK("sqlite3.Database.Open", Work_Open, Work_AfterOpen); -} - -void Database::Work_Open(napi_env e, void* data) { - auto* baton = static_cast<OpenBaton*>(data); - auto* db = baton->db; - - baton->status = sqlite3_open_v2( - baton->filename.c_str(), - &db->_handle, - baton->mode, - NULL - ); - - if (baton->status != SQLITE_OK) { - baton->message = std::string(sqlite3_errmsg(db->_handle)); - sqlite3_close(db->_handle); - db->_handle = NULL; - } - else { - // Set default database handle values. - sqlite3_busy_timeout(db->_handle, 1000); - } -} - -void Database::Work_AfterOpen(napi_env e, napi_status status, void* data) { - std::unique_ptr<OpenBaton> baton(static_cast<OpenBaton*>(data)); - - auto* db = baton->db; - - auto env = db->Env(); - Napi::HandleScope scope(env); - - Napi::Value argv[1]; - if (baton->status != SQLITE_OK) { - EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception); - argv[0] = exception; - } - else { - db->open = true; - argv[0] = env.Null(); - } - - Napi::Function cb = baton->callback.Value(); - - if (IS_FUNCTION(cb)) { - TRY_CATCH_CALL(db->Value(), cb, 1, argv); - } - else if (!db->open) { - Napi::Value info[] = { Napi::String::New(env, "error"), argv[0] }; - EMIT_EVENT(db->Value(), 2, info); - } - - if (db->open) { - Napi::Value info[] = { Napi::String::New(env, "open") }; - EMIT_EVENT(db->Value(), 1, info); - db->Process(); - } -} - -Napi::Value Database::Open(const Napi::CallbackInfo& info) { - auto env = this->Env(); - auto* db = this; - return Napi::Boolean::New(env, db->open); -} - -Napi::Value Database::Close(const Napi::CallbackInfo& info) { - auto env = info.Env(); - auto* db = this; - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - auto* baton = new Baton(db, callback); - db->Schedule(Work_BeginClose, baton, true); - - return info.This(); -} - -void Database::Work_BeginClose(Baton* baton) { - assert(baton->db->locked); - assert(baton->db->open); - assert(baton->db->_handle); - assert(baton->db->pending == 0); - - baton->db->pending++; - baton->db->RemoveCallbacks(); - baton->db->closing = true; - - auto env = baton->db->Env(); - CREATE_WORK("sqlite3.Database.Close", Work_Close, Work_AfterClose); -} - -void Database::Work_Close(napi_env e, void* data) { - auto* baton = static_cast<Baton*>(data); - auto* db = baton->db; - - baton->status = sqlite3_close(db->_handle); - - if (baton->status != SQLITE_OK) { - baton->message = std::string(sqlite3_errmsg(db->_handle)); - } - else { - db->_handle = NULL; - } -} - -void Database::Work_AfterClose(napi_env e, napi_status status, void* data) { - std::unique_ptr<Baton> baton(static_cast<Baton*>(data)); - - auto* db = baton->db; - - auto env = db->Env(); - Napi::HandleScope scope(env); - - db->pending--; - db->closing = false; - - Napi::Value argv[1]; - if (baton->status != SQLITE_OK) { - EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception); - argv[0] = exception; - } - else { - db->open = false; - // Leave db->locked to indicate that this db object has reached - // the end of its life. - argv[0] = env.Null(); - } - - Napi::Function cb = baton->callback.Value(); - - // Fire callbacks. - if (IS_FUNCTION(cb)) { - TRY_CATCH_CALL(db->Value(), cb, 1, argv); - } - else if (db->open) { - Napi::Value info[] = { Napi::String::New(env, "error"), argv[0] }; - EMIT_EVENT(db->Value(), 2, info); - } - - if (!db->open) { - Napi::Value info[] = { Napi::String::New(env, "close") }; - EMIT_EVENT(db->Value(), 1, info); - db->Process(); - } -} - -Napi::Value Database::Serialize(const Napi::CallbackInfo& info) { - auto env = this->Env(); - auto* db = this; - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - bool before = db->serialize; - db->serialize = true; - - if (!callback.IsEmpty() && callback.IsFunction()) { - TRY_CATCH_CALL(info.This(), callback, 0, NULL, info.This()); - db->serialize = before; - } - - db->Process(); - - return info.This(); -} - -Napi::Value Database::Parallelize(const Napi::CallbackInfo& info) { - auto env = this->Env(); - auto* db = this; - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - auto before = db->serialize; - db->serialize = false; - - if (!callback.IsEmpty() && callback.IsFunction()) { - TRY_CATCH_CALL(info.This(), callback, 0, NULL, info.This()); - db->serialize = before; - } - - db->Process(); - - return info.This(); -} - -Napi::Value Database::Configure(const Napi::CallbackInfo& info) { - auto env = this->Env(); - auto* db = this; - - REQUIRE_ARGUMENTS(2); - - Napi::Function handle; - if (info[0].StrictEquals( Napi::String::New(env, "trace"))) { - auto* baton = new Baton(db, handle); - db->Schedule(RegisterTraceCallback, baton); - } - else if (info[0].StrictEquals( Napi::String::New(env, "profile"))) { - auto* baton = new Baton(db, handle); - db->Schedule(RegisterProfileCallback, baton); - } - else if (info[0].StrictEquals( Napi::String::New(env, "busyTimeout"))) { - if (!info[1].IsNumber()) { - Napi::TypeError::New(env, "Value must be an integer").ThrowAsJavaScriptException(); - return env.Null(); - } - auto* baton = new Baton(db, handle); - baton->status = info[1].As<Napi::Number>().Int32Value(); - db->Schedule(SetBusyTimeout, baton); - } - else if (info[0].StrictEquals( Napi::String::New(env, "limit"))) { - REQUIRE_ARGUMENTS(3); - if (!info[1].IsNumber()) { - Napi::TypeError::New(env, "limit id must be an integer").ThrowAsJavaScriptException(); - return env.Null(); - } - if (!info[2].IsNumber()) { - Napi::TypeError::New(env, "limit value must be an integer").ThrowAsJavaScriptException(); - return env.Null(); - } - int id = info[1].As<Napi::Number>().Int32Value(); - int value = info[2].As<Napi::Number>().Int32Value(); - Baton* baton = new LimitBaton(db, handle, id, value); - db->Schedule(SetLimit, baton); - } - else if (info[0].StrictEquals(Napi::String::New(env, "change"))) { - auto* baton = new Baton(db, handle); - db->Schedule(RegisterUpdateCallback, baton); - } - else { - Napi::TypeError::New(env, (StringConcat( -#if V8_MAJOR_VERSION > 6 - info.GetIsolate(), -#endif - info[0].As<Napi::String>(), - Napi::String::New(env, " is not a valid configuration option") - )).Utf8Value().c_str()).ThrowAsJavaScriptException(); - return env.Null(); - } - - db->Process(); - - return info.This(); -} - -Napi::Value Database::Interrupt(const Napi::CallbackInfo& info) { - auto env = this->Env(); - auto* db = this; - - if (!db->open) { - Napi::Error::New(env, "Database is not open").ThrowAsJavaScriptException(); - return env.Null(); - } - - if (db->closing) { - Napi::Error::New(env, "Database is closing").ThrowAsJavaScriptException(); - return env.Null(); - } - - sqlite3_interrupt(db->_handle); - return info.This(); -} - -void Database::SetBusyTimeout(Baton* b) { - auto baton = std::unique_ptr<Baton>(b); - - assert(baton->db->open); - assert(baton->db->_handle); - - // Abuse the status field for passing the timeout. - sqlite3_busy_timeout(baton->db->_handle, baton->status); -} - -void Database::SetLimit(Baton* b) { - std::unique_ptr<LimitBaton> baton(static_cast<LimitBaton*>(b)); - - assert(baton->db->open); - assert(baton->db->_handle); - - sqlite3_limit(baton->db->_handle, baton->id, baton->value); -} - -void Database::RegisterTraceCallback(Baton* b) { - auto baton = std::unique_ptr<Baton>(b); - assert(baton->db->open); - assert(baton->db->_handle); - auto* db = baton->db; - - if (db->debug_trace == NULL) { - // Add it. - db->debug_trace = new AsyncTrace(db, TraceCallback); - sqlite3_trace(db->_handle, TraceCallback, db); - } - else { - // Remove it. - sqlite3_trace(db->_handle, NULL, NULL); - db->debug_trace->finish(); - db->debug_trace = NULL; - } -} - -void Database::TraceCallback(void* db, const char* sql) { - // Note: This function is called in the thread pool. - // Note: Some queries, such as "EXPLAIN" queries, are not sent through this. - static_cast<Database*>(db)->debug_trace->send(new std::string(sql)); -} - -void Database::TraceCallback(Database* db, std::string* s) { - std::unique_ptr<std::string> sql(s); - // Note: This function is called in the main V8 thread. - auto env = db->Env(); - Napi::HandleScope scope(env); - - Napi::Value argv[] = { - Napi::String::New(env, "trace"), - Napi::String::New(env, sql->c_str()) - }; - EMIT_EVENT(db->Value(), 2, argv); -} - -void Database::RegisterProfileCallback(Baton* b) { - auto baton = std::unique_ptr<Baton>(b); - assert(baton->db->open); - assert(baton->db->_handle); - auto* db = baton->db; - - if (db->debug_profile == NULL) { - // Add it. - db->debug_profile = new AsyncProfile(db, ProfileCallback); - sqlite3_profile(db->_handle, ProfileCallback, db); - } - else { - // Remove it. - sqlite3_profile(db->_handle, NULL, NULL); - db->debug_profile->finish(); - db->debug_profile = NULL; - } -} - -void Database::ProfileCallback(void* db, const char* sql, sqlite3_uint64 nsecs) { - // Note: This function is called in the thread pool. - // Note: Some queries, such as "EXPLAIN" queries, are not sent through this. - auto* info = new ProfileInfo(); - info->sql = std::string(sql); - info->nsecs = nsecs; - static_cast<Database*>(db)->debug_profile->send(info); -} - -void Database::ProfileCallback(Database *db, ProfileInfo* i) { - auto info = std::unique_ptr<ProfileInfo>(i); - auto env = db->Env(); - Napi::HandleScope scope(env); - - Napi::Value argv[] = { - Napi::String::New(env, "profile"), - Napi::String::New(env, info->sql.c_str()), - Napi::Number::New(env, (double)info->nsecs / 1000000.0) - }; - EMIT_EVENT(db->Value(), 3, argv); -} - -void Database::RegisterUpdateCallback(Baton* b) { - auto baton = std::unique_ptr<Baton>(b); - assert(baton->db->open); - assert(baton->db->_handle); - auto* db = baton->db; - - if (db->update_event == NULL) { - // Add it. - db->update_event = new AsyncUpdate(db, UpdateCallback); - sqlite3_update_hook(db->_handle, UpdateCallback, db); - } - else { - // Remove it. - sqlite3_update_hook(db->_handle, NULL, NULL); - db->update_event->finish(); - db->update_event = NULL; - } -} - -void Database::UpdateCallback(void* db, int type, const char* database, - const char* table, sqlite3_int64 rowid) { - // Note: This function is called in the thread pool. - // Note: Some queries, such as "EXPLAIN" queries, are not sent through this. - auto* info = new UpdateInfo(); - info->type = type; - info->database = std::string(database); - info->table = std::string(table); - info->rowid = rowid; - static_cast<Database*>(db)->update_event->send(info); -} - -void Database::UpdateCallback(Database *db, UpdateInfo* i) { - auto info = std::unique_ptr<UpdateInfo>(i); - auto env = db->Env(); - Napi::HandleScope scope(env); - - Napi::Value argv[] = { - Napi::String::New(env, "change"), - Napi::String::New(env, sqlite_authorizer_string(info->type)), - Napi::String::New(env, info->database.c_str()), - Napi::String::New(env, info->table.c_str()), - Napi::Number::New(env, info->rowid), - }; - EMIT_EVENT(db->Value(), 5, argv); -} - -Napi::Value Database::Exec(const Napi::CallbackInfo& info) { - auto env = this->Env(); - auto* db = this; - - REQUIRE_ARGUMENT_STRING(0, sql); - OPTIONAL_ARGUMENT_FUNCTION(1, callback); - - Baton* baton = new ExecBaton(db, callback, sql.c_str()); - db->Schedule(Work_BeginExec, baton, true); - - return info.This(); -} - -void Database::Work_BeginExec(Baton* baton) { - assert(baton->db->locked); - assert(baton->db->open); - assert(baton->db->_handle); - assert(baton->db->pending == 0); - baton->db->pending++; - - auto env = baton->db->Env(); - CREATE_WORK("sqlite3.Database.Exec", Work_Exec, Work_AfterExec); -} - -void Database::Work_Exec(napi_env e, void* data) { - auto* baton = static_cast<ExecBaton*>(data); - - char* message = NULL; - baton->status = sqlite3_exec( - baton->db->_handle, - baton->sql.c_str(), - NULL, - NULL, - &message - ); - - if (baton->status != SQLITE_OK && message != NULL) { - baton->message = std::string(message); - sqlite3_free(message); - } -} - -void Database::Work_AfterExec(napi_env e, napi_status status, void* data) { - std::unique_ptr<ExecBaton> baton(static_cast<ExecBaton*>(data)); - - auto* db = baton->db; - db->pending--; - - auto env = db->Env(); - Napi::HandleScope scope(env); - - Napi::Function cb = baton->callback.Value(); - - if (baton->status != SQLITE_OK) { - EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception); - - if (IS_FUNCTION(cb)) { - Napi::Value argv[] = { exception }; - TRY_CATCH_CALL(db->Value(), cb, 1, argv); - } - else { - Napi::Value info[] = { Napi::String::New(env, "error"), exception }; - EMIT_EVENT(db->Value(), 2, info); - } - } - else if (IS_FUNCTION(cb)) { - Napi::Value argv[] = { env.Null() }; - TRY_CATCH_CALL(db->Value(), cb, 1, argv); - } - - db->Process(); -} - -Napi::Value Database::Wait(const Napi::CallbackInfo& info) { - auto env = info.Env(); - auto* db = this; - - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - auto* baton = new Baton(db, callback); - db->Schedule(Work_Wait, baton, true); - - return info.This(); -} - -void Database::Work_Wait(Baton* b) { - auto baton = std::unique_ptr<Baton>(b); - - auto env = baton->db->Env(); - Napi::HandleScope scope(env); - - assert(baton->db->locked); - assert(baton->db->open); - assert(baton->db->_handle); - assert(baton->db->pending == 0); - - Napi::Function cb = baton->callback.Value(); - if (IS_FUNCTION(cb)) { - Napi::Value argv[] = { env.Null() }; - TRY_CATCH_CALL(baton->db->Value(), cb, 1, argv); - } - - baton->db->Process(); -} - -Napi::Value Database::LoadExtension(const Napi::CallbackInfo& info) { - auto env = this->Env(); - auto* db = this; - - REQUIRE_ARGUMENT_STRING(0, filename); - OPTIONAL_ARGUMENT_FUNCTION(1, callback); - - Baton* baton = new LoadExtensionBaton(db, callback, filename.c_str()); - db->Schedule(Work_BeginLoadExtension, baton, true); - - return info.This(); -} - -void Database::Work_BeginLoadExtension(Baton* baton) { - assert(baton->db->locked); - assert(baton->db->open); - assert(baton->db->_handle); - assert(baton->db->pending == 0); - baton->db->pending++; - - auto env = baton->db->Env(); - CREATE_WORK("sqlite3.Database.LoadExtension", Work_LoadExtension, Work_AfterLoadExtension); -} - -void Database::Work_LoadExtension(napi_env e, void* data) { - auto* baton = static_cast<LoadExtensionBaton*>(data); - - sqlite3_enable_load_extension(baton->db->_handle, 1); - - char* message = NULL; - baton->status = sqlite3_load_extension( - baton->db->_handle, - baton->filename.c_str(), - 0, - &message - ); - - sqlite3_enable_load_extension(baton->db->_handle, 0); - - if (baton->status != SQLITE_OK && message != NULL) { - baton->message = std::string(message); - sqlite3_free(message); - } -} - -void Database::Work_AfterLoadExtension(napi_env e, napi_status status, void* data) { - std::unique_ptr<LoadExtensionBaton> baton(static_cast<LoadExtensionBaton*>(data)); - - auto* db = baton->db; - db->pending--; - - auto env = db->Env(); - Napi::HandleScope scope(env); - - Napi::Function cb = baton->callback.Value(); - - if (baton->status != SQLITE_OK) { - EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception); - - if (IS_FUNCTION(cb)) { - Napi::Value argv[] = { exception }; - TRY_CATCH_CALL(db->Value(), cb, 1, argv); - } - else { - Napi::Value info[] = { Napi::String::New(env, "error"), exception }; - EMIT_EVENT(db->Value(), 2, info); - } - } - else if (IS_FUNCTION(cb)) { - Napi::Value argv[] = { env.Null() }; - TRY_CATCH_CALL(db->Value(), cb, 1, argv); - } - - db->Process(); -} - -void Database::RemoveCallbacks() { - if (debug_trace) { - debug_trace->finish(); - debug_trace = NULL; - } - if (debug_profile) { - debug_profile->finish(); - debug_profile = NULL; - } - if (update_event) { - update_event->finish(); - update_event = NULL; - } -} diff --git a/updater/sql/win/src/database.h b/updater/sql/win/src/database.h deleted file mode 100755 index 8ffd300..0000000 --- a/updater/sql/win/src/database.h +++ /dev/null @@ -1,188 +0,0 @@ - -#ifndef NODE_SQLITE3_SRC_DATABASE_H -#define NODE_SQLITE3_SRC_DATABASE_H - - -#include <assert.h> -#include <string> -#include <queue> - -#include <sqlite3.h> -#include <napi.h> - -#include "async.h" - -using namespace Napi; - -namespace node_sqlite3 { - -class Database; - - -class Database : public Napi::ObjectWrap<Database> { -public: -#if NAPI_VERSION < 6 - static Napi::FunctionReference constructor; -#endif - static Napi::Object Init(Napi::Env env, Napi::Object exports); - - static inline bool HasInstance(Napi::Value val) { - auto env = val.Env(); - Napi::HandleScope scope(env); - if (!val.IsObject()) return false; - auto obj = val.As<Napi::Object>(); -#if NAPI_VERSION < 6 - return obj.InstanceOf(constructor.Value()); -#else - auto constructor = - env.GetInstanceData<Napi::FunctionReference>(); - return obj.InstanceOf(constructor->Value()); -#endif - } - - struct Baton { - napi_async_work request = NULL; - Database* db; - Napi::FunctionReference callback; - int status; - std::string message; - - Baton(Database* db_, Napi::Function cb_) : - db(db_), status(SQLITE_OK) { - db->Ref(); - if (!cb_.IsUndefined() && cb_.IsFunction()) { - callback.Reset(cb_, 1); - } - } - virtual ~Baton() { - if (request) napi_delete_async_work(db->Env(), request); - db->Unref(); - callback.Reset(); - } - }; - - struct OpenBaton : Baton { - std::string filename; - int mode; - OpenBaton(Database* db_, Napi::Function cb_, const char* filename_, int mode_) : - Baton(db_, cb_), filename(filename_), mode(mode_) {} - virtual ~OpenBaton() override = default; - }; - - struct ExecBaton : Baton { - std::string sql; - ExecBaton(Database* db_, Napi::Function cb_, const char* sql_) : - Baton(db_, cb_), sql(sql_) {} - virtual ~ExecBaton() override = default; - }; - - struct LoadExtensionBaton : Baton { - std::string filename; - LoadExtensionBaton(Database* db_, Napi::Function cb_, const char* filename_) : - Baton(db_, cb_), filename(filename_) {} - virtual ~LoadExtensionBaton() override = default; - }; - - struct LimitBaton : Baton { - int id; - int value; - LimitBaton(Database* db_, Napi::Function cb_, int id_, int value_) : - Baton(db_, cb_), id(id_), value(value_) {} - virtual ~LimitBaton() override = default; - }; - - typedef void (*Work_Callback)(Baton* baton); - - struct Call { - Call(Work_Callback cb_, Baton* baton_, bool exclusive_ = false) : - callback(cb_), exclusive(exclusive_), baton(baton_) {}; - Work_Callback callback; - bool exclusive; - Baton* baton; - }; - - struct ProfileInfo { - std::string sql; - sqlite3_int64 nsecs; - }; - - struct UpdateInfo { - int type; - std::string database; - std::string table; - sqlite3_int64 rowid; - }; - - bool IsOpen() { return open; } - bool IsLocked() { return locked; } - - typedef Async<std::string, Database> AsyncTrace; - typedef Async<ProfileInfo, Database> AsyncProfile; - typedef Async<UpdateInfo, Database> AsyncUpdate; - - friend class Statement; - friend class Backup; - - Database(const Napi::CallbackInfo& info); - - ~Database() { - RemoveCallbacks(); - sqlite3_close(_handle); - _handle = NULL; - open = false; - } - -protected: - WORK_DEFINITION(Open); - WORK_DEFINITION(Exec); - WORK_DEFINITION(Close); - WORK_DEFINITION(LoadExtension); - - void Schedule(Work_Callback callback, Baton* baton, bool exclusive = false); - void Process(); - - Napi::Value Wait(const Napi::CallbackInfo& info); - static void Work_Wait(Baton* baton); - - Napi::Value Serialize(const Napi::CallbackInfo& info); - Napi::Value Parallelize(const Napi::CallbackInfo& info); - Napi::Value Configure(const Napi::CallbackInfo& info); - Napi::Value Interrupt(const Napi::CallbackInfo& info); - - static void SetBusyTimeout(Baton* baton); - static void SetLimit(Baton* baton); - - static void RegisterTraceCallback(Baton* baton); - static void TraceCallback(void* db, const char* sql); - static void TraceCallback(Database* db, std::string* sql); - - static void RegisterProfileCallback(Baton* baton); - static void ProfileCallback(void* db, const char* sql, sqlite3_uint64 nsecs); - static void ProfileCallback(Database* db, ProfileInfo* info); - - static void RegisterUpdateCallback(Baton* baton); - static void UpdateCallback(void* db, int type, const char* database, const char* table, sqlite3_int64 rowid); - static void UpdateCallback(Database* db, UpdateInfo* info); - - void RemoveCallbacks(); - -protected: - sqlite3* _handle = NULL; - - bool open = false; - bool closing = false; - bool locked = false; - unsigned int pending = 0; - - bool serialize = false; - - std::queue<Call*> queue; - - AsyncTrace* debug_trace = NULL; - AsyncProfile* debug_profile = NULL; - AsyncUpdate* update_event = NULL; -}; - -} - -#endif diff --git a/updater/sql/win/src/gcc-preinclude.h b/updater/sql/win/src/gcc-preinclude.h deleted file mode 100755 index 7a52a4d..0000000 --- a/updater/sql/win/src/gcc-preinclude.h +++ /dev/null @@ -1,30 +0,0 @@ -// http://web.archive.org/web/20140401031018/http://rjpower9000.wordpress.com:80/2012/04/09/fun-with-shared-libraries-version-glibc_2-14-not-found/ - -#if defined(__linux__) - -#define _GNU_SOURCE -#include <features.h> -#undef _GNU_SOURCE - -#if defined(__USE_GNU) - -#if defined(__x86_64__) -__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 - -#if defined(__aarch64__) || defined(_M_ARM64) -__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 - -#endif -#endif diff --git a/updater/sql/win/src/macros.h b/updater/sql/win/src/macros.h deleted file mode 100755 index 3bcde83..0000000 --- a/updater/sql/win/src/macros.h +++ /dev/null @@ -1,207 +0,0 @@ -#ifndef NODE_SQLITE3_SRC_MACROS_H -#define NODE_SQLITE3_SRC_MACROS_H - -const char* sqlite_code_string(int code); -const char* sqlite_authorizer_string(int type); -#include <vector> - -// TODO: better way to work around StringConcat? -#include <napi.h> -inline Napi::String StringConcat(Napi::Value str1, Napi::Value str2) { - return Napi::String::New(str1.Env(), str1.As<Napi::String>().Utf8Value() + - str2.As<Napi::String>().Utf8Value() ); -} - -// A Napi substitute IsInt32() -inline bool OtherIsInt(Napi::Number source) { - double orig_val = source.DoubleValue(); - double int_val = static_cast<double>(source.Int32Value()); - if (orig_val == int_val) { - return true; - } else { - return false; - } -} - -#define IS_FUNCTION(cb) \ - !cb.IsUndefined() && cb.IsFunction() - -#define REQUIRE_ARGUMENTS(n) \ - if (info.Length() < (n)) { \ - Napi::TypeError::New(env, "Expected " #n "arguments").ThrowAsJavaScriptException(); \ - return env.Null(); \ - } - - -#define REQUIRE_ARGUMENT_EXTERNAL(i, var) \ - if (info.Length() <= (i) || !info[i].IsExternal()) { \ - Napi::TypeError::New(env, "Argument " #i " invalid").ThrowAsJavaScriptException(); \ - return env.Null(); \ - } \ - Napi::External var = info[i].As<Napi::External>(); - - -#define REQUIRE_ARGUMENT_FUNCTION(i, var) \ - if (info.Length() <= (i) || !info[i].IsFunction()) { \ - Napi::TypeError::New(env, "Argument " #i " must be a function").ThrowAsJavaScriptException(); \ - return env.Null(); \ - } \ - Napi::Function var = info[i].As<Napi::Function>(); - - -#define REQUIRE_ARGUMENT_STRING(i, var) \ - if (info.Length() <= (i) || !info[i].IsString()) { \ - Napi::TypeError::New(env, "Argument " #i " must be a string").ThrowAsJavaScriptException(); \ - return env.Null(); \ - } \ - std::string var = info[i].As<Napi::String>(); - -#define REQUIRE_ARGUMENT_INTEGER(i, var) \ - if (info.Length() <= (i) || !info[i].IsNumber()) { \ - Napi::TypeError::New(env, "Argument " #i " must be an integer").ThrowAsJavaScriptException(); \ - return env.Null(); \ - } \ - int var(info[i].As<Napi::Number>().Int32Value()); - -#define OPTIONAL_ARGUMENT_FUNCTION(i, var) \ - Napi::Function var; \ - if (info.Length() > i && !info[i].IsUndefined()) { \ - if (!info[i].IsFunction()) { \ - Napi::TypeError::New(env, "Argument " #i " must be a function").ThrowAsJavaScriptException(); \ - return env.Null(); \ - } \ - var = info[i].As<Napi::Function>(); \ - } - - -#define OPTIONAL_ARGUMENT_INTEGER(i, var, default) \ - int var; \ - if (info.Length() <= (i)) { \ - var = (default); \ - } \ - else if (info[i].IsNumber()) { \ - if (OtherIsInt(info[i].As<Number>())) { \ - var = info[i].As<Napi::Number>().Int32Value(); \ - } \ - } \ - else { \ - Napi::TypeError::New(env, "Argument " #i " must be an integer").ThrowAsJavaScriptException(); \ - return env.Null(); \ - } - - -#define DEFINE_CONSTANT_INTEGER(target, constant, name) \ - Napi::PropertyDescriptor::Value(#name, Napi::Number::New(env, constant), \ - static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)), - -#define DEFINE_CONSTANT_STRING(target, constant, name) \ - Napi::PropertyDescriptor::Value(#name, Napi::String::New(env, constant), \ - static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)), - -#define EXCEPTION(msg, errno, name) \ - Napi::Value name = Napi::Error::New(env, \ - StringConcat( \ - StringConcat( \ - Napi::String::New(env, sqlite_code_string(errno)), \ - Napi::String::New(env, ": ") \ - ), \ - (msg) \ - ).Utf8Value() \ - ).Value(); \ - Napi::Object name ##_obj = name.As<Napi::Object>(); \ - (name ##_obj).Set( Napi::String::New(env, "errno"), Napi::Number::New(env, errno)); \ - (name ##_obj).Set( Napi::String::New(env, "code"), \ - Napi::String::New(env, sqlite_code_string(errno))); - - -#define EMIT_EVENT(obj, argc, argv) \ - TRY_CATCH_CALL((obj), \ - (obj).Get("emit").As<Napi::Function>(),\ - argc, argv \ - ); - -// The Mac OS compiler complains when argv is NULL unless we -// first assign it to a locally defined variable. -#define TRY_CATCH_CALL(context, callback, argc, argv, ...) \ - Napi::Value* passed_argv = argv;\ - std::vector<napi_value> args;\ - if ((argc != 0) && (passed_argv != NULL)) {\ - args.assign(passed_argv, passed_argv + argc);\ - }\ - Napi::Value res = (callback).Call(Napi::Value(context), args); \ - if (res.IsEmpty()) return __VA_ARGS__; - -#define WORK_DEFINITION(name) \ - Napi::Value name(const Napi::CallbackInfo& info); \ - static void Work_Begin##name(Baton* baton); \ - static void Work_##name(napi_env env, void* data); \ - static void Work_After##name(napi_env env, napi_status status, void* data); - -#ifdef DEBUG - #define ASSERT_STATUS() assert(status == 0); -#else - #define ASSERT_STATUS() (void)status; -#endif - -#define CREATE_WORK(name, workerFn, afterFn) \ - int status = napi_create_async_work(env, NULL, Napi::String::New(env, name),\ - workerFn, afterFn, baton, &baton->request); \ - \ - ASSERT_STATUS(); \ - napi_queue_async_work(env, baton->request); - -#define STATEMENT_BEGIN(type) \ - assert(baton); \ - assert(baton->stmt); \ - assert(!baton->stmt->locked); \ - assert(!baton->stmt->finalized); \ - assert(baton->stmt->prepared); \ - baton->stmt->locked = true; \ - baton->stmt->db->pending++; \ - auto env = baton->stmt->Env(); \ - CREATE_WORK("sqlite3.Statement."#type, Work_##type, Work_After##type); - -#define STATEMENT_INIT(type) \ - type* baton = static_cast<type*>(data); \ - Statement* stmt = baton->stmt; - -#define STATEMENT_MUTEX(name) \ - if (!stmt->db->_handle) { \ - stmt->status = SQLITE_MISUSE; \ - stmt->message = "Database handle is closed"; \ - return; \ - } \ - sqlite3_mutex* name = sqlite3_db_mutex(stmt->db->_handle); - -#define STATEMENT_END() \ - assert(stmt->locked); \ - assert(stmt->db->pending); \ - stmt->locked = false; \ - stmt->db->pending--; \ - stmt->Process(); \ - stmt->db->Process(); - -#define BACKUP_BEGIN(type) \ - assert(baton); \ - assert(baton->backup); \ - assert(!baton->backup->locked); \ - assert(!baton->backup->finished); \ - assert(baton->backup->inited); \ - baton->backup->locked = true; \ - baton->backup->db->pending++; \ - auto env = baton->backup->Env(); \ - CREATE_WORK("sqlite3.Backup."#type, Work_##type, Work_After##type); - -#define BACKUP_INIT(type) \ - type* baton = static_cast<type*>(data); \ - Backup* backup = baton->backup; - -#define BACKUP_END() \ - assert(backup->locked); \ - assert(backup->db->pending); \ - backup->locked = false; \ - backup->db->pending--; \ - backup->Process(); \ - backup->db->Process(); - -#endif
\ No newline at end of file diff --git a/updater/sql/win/src/node_sqlite3.cc b/updater/sql/win/src/node_sqlite3.cc deleted file mode 100755 index 6f47a68..0000000 --- a/updater/sql/win/src/node_sqlite3.cc +++ /dev/null @@ -1,128 +0,0 @@ -#include <stdint.h> -#include <sstream> -#include <cstring> -#include <string> -#include <sqlite3.h> - -#include "macros.h" -#include "database.h" -#include "statement.h" -#include "backup.h" - -using namespace node_sqlite3; - -namespace { - -Napi::Object RegisterModule(Napi::Env env, Napi::Object exports) { - Napi::HandleScope scope(env); - - Database::Init(env, exports); - Statement::Init(env, exports); - Backup::Init(env, exports); - - exports.DefineProperties({ - DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_READONLY, OPEN_READONLY) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_READWRITE, OPEN_READWRITE) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_CREATE, OPEN_CREATE) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_FULLMUTEX, OPEN_FULLMUTEX) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_URI, OPEN_URI) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_SHAREDCACHE, OPEN_SHAREDCACHE) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_PRIVATECACHE, OPEN_PRIVATECACHE) - DEFINE_CONSTANT_STRING(exports, SQLITE_VERSION, VERSION) -#ifdef SQLITE_SOURCE_ID - DEFINE_CONSTANT_STRING(exports, SQLITE_SOURCE_ID, SOURCE_ID) -#endif - DEFINE_CONSTANT_INTEGER(exports, SQLITE_VERSION_NUMBER, VERSION_NUMBER) - - DEFINE_CONSTANT_INTEGER(exports, SQLITE_OK, OK) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_ERROR, ERROR) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_INTERNAL, INTERNAL) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_PERM, PERM) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_ABORT, ABORT) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_BUSY, BUSY) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LOCKED, LOCKED) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_NOMEM, NOMEM) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_READONLY, READONLY) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_INTERRUPT, INTERRUPT) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_IOERR, IOERR) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_CORRUPT, CORRUPT) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_NOTFOUND, NOTFOUND) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_FULL, FULL) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_CANTOPEN, CANTOPEN) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_PROTOCOL, PROTOCOL) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_EMPTY, EMPTY) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_SCHEMA, SCHEMA) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_TOOBIG, TOOBIG) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_CONSTRAINT, CONSTRAINT) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_MISMATCH, MISMATCH) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_MISUSE, MISUSE) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_NOLFS, NOLFS) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_AUTH, AUTH) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_FORMAT, FORMAT) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_RANGE, RANGE) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_NOTADB, NOTADB) - - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_LENGTH, LIMIT_LENGTH) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_SQL_LENGTH, LIMIT_SQL_LENGTH) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_COLUMN, LIMIT_COLUMN) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_EXPR_DEPTH, LIMIT_EXPR_DEPTH) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_COMPOUND_SELECT, LIMIT_COMPOUND_SELECT) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_VDBE_OP, LIMIT_VDBE_OP) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_FUNCTION_ARG, LIMIT_FUNCTION_ARG) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_ATTACHED, LIMIT_ATTACHED) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_LIKE_PATTERN_LENGTH, LIMIT_LIKE_PATTERN_LENGTH) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_VARIABLE_NUMBER, LIMIT_VARIABLE_NUMBER) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_TRIGGER_DEPTH, LIMIT_TRIGGER_DEPTH) - DEFINE_CONSTANT_INTEGER(exports, SQLITE_LIMIT_WORKER_THREADS, LIMIT_WORKER_THREADS) - }); - - return exports; -} - -} - -const char* sqlite_code_string(int code) { - switch (code) { - case SQLITE_OK: return "SQLITE_OK"; - case SQLITE_ERROR: return "SQLITE_ERROR"; - case SQLITE_INTERNAL: return "SQLITE_INTERNAL"; - case SQLITE_PERM: return "SQLITE_PERM"; - case SQLITE_ABORT: return "SQLITE_ABORT"; - case SQLITE_BUSY: return "SQLITE_BUSY"; - case SQLITE_LOCKED: return "SQLITE_LOCKED"; - case SQLITE_NOMEM: return "SQLITE_NOMEM"; - case SQLITE_READONLY: return "SQLITE_READONLY"; - case SQLITE_INTERRUPT: return "SQLITE_INTERRUPT"; - case SQLITE_IOERR: return "SQLITE_IOERR"; - case SQLITE_CORRUPT: return "SQLITE_CORRUPT"; - case SQLITE_NOTFOUND: return "SQLITE_NOTFOUND"; - case SQLITE_FULL: return "SQLITE_FULL"; - case SQLITE_CANTOPEN: return "SQLITE_CANTOPEN"; - case SQLITE_PROTOCOL: return "SQLITE_PROTOCOL"; - case SQLITE_EMPTY: return "SQLITE_EMPTY"; - case SQLITE_SCHEMA: return "SQLITE_SCHEMA"; - case SQLITE_TOOBIG: return "SQLITE_TOOBIG"; - case SQLITE_CONSTRAINT: return "SQLITE_CONSTRAINT"; - case SQLITE_MISMATCH: return "SQLITE_MISMATCH"; - case SQLITE_MISUSE: return "SQLITE_MISUSE"; - case SQLITE_NOLFS: return "SQLITE_NOLFS"; - case SQLITE_AUTH: return "SQLITE_AUTH"; - case SQLITE_FORMAT: return "SQLITE_FORMAT"; - case SQLITE_RANGE: return "SQLITE_RANGE"; - case SQLITE_NOTADB: return "SQLITE_NOTADB"; - case SQLITE_ROW: return "SQLITE_ROW"; - case SQLITE_DONE: return "SQLITE_DONE"; - default: return "UNKNOWN"; - } -} - -const char* sqlite_authorizer_string(int type) { - switch (type) { - case SQLITE_INSERT: return "insert"; - case SQLITE_UPDATE: return "update"; - case SQLITE_DELETE: return "delete"; - default: return ""; - } -} - -NODE_API_MODULE(node_sqlite3, RegisterModule) diff --git a/updater/sql/win/src/statement.cc b/updater/sql/win/src/statement.cc deleted file mode 100755 index fc49b90..0000000 --- a/updater/sql/win/src/statement.cc +++ /dev/null @@ -1,939 +0,0 @@ -#include <cstring> -#include <napi.h> -#include <uv.h> - -#include "macros.h" -#include "database.h" -#include "statement.h" - -using namespace node_sqlite3; - -Napi::Object Statement::Init(Napi::Env env, Napi::Object exports) { - Napi::HandleScope scope(env); - - // declare napi_default_method here as it is only available in Node v14.12.0+ - auto napi_default_method = static_cast<napi_property_attributes>(napi_writable | napi_configurable); - - auto t = DefineClass(env, "Statement", { - InstanceMethod("bind", &Statement::Bind, napi_default_method), - InstanceMethod("get", &Statement::Get, napi_default_method), - InstanceMethod("run", &Statement::Run, napi_default_method), - InstanceMethod("all", &Statement::All, napi_default_method), - InstanceMethod("each", &Statement::Each, napi_default_method), - InstanceMethod("reset", &Statement::Reset, napi_default_method), - InstanceMethod("finalize", &Statement::Finalize_, napi_default_method), - }); - - exports.Set("Statement", t); - return exports; -} - -// A Napi InstanceOf for Javascript Objects "Date" and "RegExp" -bool OtherInstanceOf(Napi::Object source, const char* object_type) { - if (strncmp(object_type, "Date", 4) == 0) { - return source.InstanceOf(source.Env().Global().Get("Date").As<Function>()); - } else if (strncmp(object_type, "RegExp", 6) == 0) { - return source.InstanceOf(source.Env().Global().Get("RegExp").As<Function>()); - } - - return false; -} - -void Statement::Process() { - if (finalized && !queue.empty()) { - return CleanQueue(); - } - - while (prepared && !locked && !queue.empty()) { - auto call = std::unique_ptr<Call>(queue.front()); - queue.pop(); - - call->callback(call->baton); - } -} - -void Statement::Schedule(Work_Callback callback, Baton* baton) { - if (finalized) { - queue.emplace(new Call(callback, baton)); - CleanQueue(); - } - else if (!prepared || locked) { - queue.emplace(new Call(callback, baton)); - } - else { - callback(baton); - } -} - -template <class T> void Statement::Error(T* baton) { - Statement* stmt = baton->stmt; - - auto env = stmt->Env(); - Napi::HandleScope scope(env); - - // Fail hard on logic errors. - assert(stmt->status != 0); - EXCEPTION(Napi::String::New(env, stmt->message.c_str()), stmt->status, exception); - - Napi::Function cb = baton->callback.Value(); - - if (IS_FUNCTION(cb)) { - Napi::Value argv[] = { exception }; - TRY_CATCH_CALL(stmt->Value(), cb, 1, argv); - } - else { - Napi::Value argv[] = { Napi::String::New(env, "error"), exception }; - EMIT_EVENT(stmt->Value(), 2, argv); - } -} - -// { Database db, String sql, Array params, Function callback } -Statement::Statement(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Statement>(info) { - auto env = info.Env(); - int length = info.Length(); - - if (length <= 0 || !Database::HasInstance(info[0])) { - Napi::TypeError::New(env, "Database object expected").ThrowAsJavaScriptException(); - return; - } - else if (length <= 1 || !info[1].IsString()) { - Napi::TypeError::New(env, "SQL query expected").ThrowAsJavaScriptException(); - return; - } - else if (length > 2 && !info[2].IsUndefined() && !info[2].IsFunction()) { - Napi::TypeError::New(env, "Callback expected").ThrowAsJavaScriptException(); - return; - } - - this->db = Napi::ObjectWrap<Database>::Unwrap(info[0].As<Napi::Object>()); - this->db->Ref(); - - auto sql = info[1].As<Napi::String>(); - - info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("sql", sql, napi_default)); - - - Statement* stmt = this; - - auto* baton = new PrepareBaton(this->db, info[2].As<Napi::Function>(), stmt); - baton->sql = std::string(sql.As<Napi::String>().Utf8Value().c_str()); - this->db->Schedule(Work_BeginPrepare, baton); -} - -void Statement::Work_BeginPrepare(Database::Baton* baton) { - assert(baton->db->open); - baton->db->pending++; - - auto env = baton->db->Env(); - CREATE_WORK("sqlite3.Statement.Prepare", Work_Prepare, Work_AfterPrepare); -} - -void Statement::Work_Prepare(napi_env e, void* data) { - STATEMENT_INIT(PrepareBaton); - - // In case preparing fails, we use a mutex to make sure we get the associated - // error message. - STATEMENT_MUTEX(mtx); - sqlite3_mutex_enter(mtx); - - stmt->status = sqlite3_prepare_v2( - baton->db->_handle, - baton->sql.c_str(), - baton->sql.size(), - &stmt->_handle, - NULL - ); - - if (stmt->status != SQLITE_OK) { - stmt->message = std::string(sqlite3_errmsg(baton->db->_handle)); - stmt->_handle = NULL; - } - - sqlite3_mutex_leave(mtx); -} - -void Statement::Work_AfterPrepare(napi_env e, napi_status status, void* data) { - std::unique_ptr<PrepareBaton> baton(static_cast<PrepareBaton*>(data)); - auto* stmt = baton->stmt; - - auto env = stmt->Env(); - Napi::HandleScope scope(env); - - if (stmt->status != SQLITE_OK) { - Error(baton.get()); - stmt->Finalize_(); - } - else { - stmt->prepared = true; - if (!baton->callback.IsEmpty() && baton->callback.Value().IsFunction()) { - Napi::Function cb = baton->callback.Value(); - Napi::Value argv[] = { env.Null() }; - TRY_CATCH_CALL(stmt->Value(), cb, 1, argv); - } - } - - STATEMENT_END(); -} - -template <class T> std::unique_ptr<Values::Field> - Statement::BindParameter(const Napi::Value source, T pos) { - if (source.IsString()) { - std::string val = source.As<Napi::String>().Utf8Value(); - return std::make_unique<Values::Text>(pos, val.length(), val.c_str()); - } - else if (OtherInstanceOf(source.As<Object>(), "RegExp")) { - std::string val = source.ToString().Utf8Value(); - return std::make_unique<Values::Text>(pos, val.length(), val.c_str()); - } - else if (source.IsNumber()) { - if (OtherIsInt(source.As<Napi::Number>())) { - return std::make_unique<Values::Integer>(pos, source.As<Napi::Number>().Int32Value()); - } else { - return std::make_unique<Values::Float>(pos, source.As<Napi::Number>().DoubleValue()); - } - } - else if (source.IsBoolean()) { - return std::make_unique<Values::Integer>(pos, source.As<Napi::Boolean>().Value() ? 1 : 0); - } - else if (source.IsNull()) { - return std::make_unique<Values::Null>(pos); - } - else if (source.IsBuffer()) { - Napi::Buffer<char> buffer = source.As<Napi::Buffer<char>>(); - return std::make_unique<Values::Blob>(pos, buffer.Length(), buffer.Data()); - } - else if (OtherInstanceOf(source.As<Object>(), "Date")) { - return std::make_unique<Values::Float>(pos, source.ToNumber().DoubleValue()); - } - else if (source.IsObject()) { - auto napiVal = Napi::String::New(source.Env(), "[object Object]"); - // Check whether toString returned a value that is not undefined. - if(napiVal.Type() == 0) { - return NULL; - } - - std::string val = napiVal.Utf8Value(); - return std::make_unique<Values::Text>(pos, val.length(), val.c_str()); - } - else { - return NULL; - } -} - -template <class T> T* Statement::Bind(const Napi::CallbackInfo& info, int start, int last) { - auto env = info.Env(); - Napi::HandleScope scope(env); - - if (last < 0) last = info.Length(); - Napi::Function callback; - if (last > start && info[last - 1].IsFunction()) { - callback = info[last - 1].As<Napi::Function>(); - last--; - } - - auto *baton = new T(this, callback); - - if (start < last) { - if (info[start].IsArray()) { - auto array = info[start].As<Napi::Array>(); - int length = array.Length(); - // Note: bind parameters start with 1. - for (int i = 0, pos = 1; i < length; i++, pos++) { - baton->parameters.emplace_back(BindParameter((array).Get(i), i + 1)); - } - } - else if (!info[start].IsObject() || OtherInstanceOf(info[start].As<Object>(), "RegExp") - || OtherInstanceOf(info[start].As<Object>(), "Date") || info[start].IsBuffer()) { - // Parameters directly in array. - // Note: bind parameters start with 1. - for (int i = start, pos = 1; i < last; i++, pos++) { - baton->parameters.emplace_back(BindParameter(info[i], pos)); - } - } - else if (info[start].IsObject()) { - auto object = info[start].As<Napi::Object>(); - auto array = object.GetPropertyNames(); - int length = array.Length(); - for (int i = 0; i < length; i++) { - Napi::Value name = (array).Get(i); - Napi::Number num = name.ToNumber(); - - if (num.Int32Value() == num.DoubleValue()) { - baton->parameters.emplace_back( - BindParameter((object).Get(name), num.Int32Value())); - } - else { - baton->parameters.emplace_back(BindParameter((object).Get(name), - name.As<Napi::String>().Utf8Value().c_str())); - } - } - } - else { - return NULL; - } - } - - return baton; -} - -bool Statement::Bind(const Parameters & parameters) { - if (parameters.empty()) { - return true; - } - - sqlite3_reset(_handle); - sqlite3_clear_bindings(_handle); - - for (auto& field : parameters) { - if (field == NULL) - continue; - - unsigned int pos; - if (field->index > 0) { - pos = field->index; - } - else { - pos = sqlite3_bind_parameter_index(_handle, field->name.c_str()); - } - - switch (field->type) { - case SQLITE_INTEGER: { - status = sqlite3_bind_int(_handle, pos, - (static_cast<Values::Integer*>(field.get()))->value); - } break; - case SQLITE_FLOAT: { - status = sqlite3_bind_double(_handle, pos, - (static_cast<Values::Float*>(field.get()))->value); - } break; - case SQLITE_TEXT: { - status = sqlite3_bind_text(_handle, pos, - (static_cast<Values::Text*>(field.get()))->value.c_str(), - (static_cast<Values::Text*>(field.get()))->value.size(), SQLITE_TRANSIENT); - } break; - case SQLITE_BLOB: { - status = sqlite3_bind_blob(_handle, pos, - (static_cast<Values::Blob*>(field.get()))->value, - (static_cast<Values::Blob*>(field.get()))->length, SQLITE_TRANSIENT); - } break; - case SQLITE_NULL: { - status = sqlite3_bind_null(_handle, pos); - } break; - } - - if (status != SQLITE_OK) { - message = std::string(sqlite3_errmsg(db->_handle)); - return false; - } - } - - return true; -} - -Napi::Value Statement::Bind(const Napi::CallbackInfo& info) { - auto env = info.Env(); - Statement* stmt = this; - - auto baton = stmt->Bind<Baton>(info); - if (baton == NULL) { - Napi::TypeError::New(env, "Data type is not supported").ThrowAsJavaScriptException(); - return env.Null(); - } - else { - stmt->Schedule(Work_BeginBind, baton); - return info.This(); - } -} - -void Statement::Work_BeginBind(Baton* baton) { - STATEMENT_BEGIN(Bind); -} - -void Statement::Work_Bind(napi_env e, void* data) { - STATEMENT_INIT(Baton); - - STATEMENT_MUTEX(mtx); - sqlite3_mutex_enter(mtx); - stmt->Bind(baton->parameters); - sqlite3_mutex_leave(mtx); -} - -void Statement::Work_AfterBind(napi_env e, napi_status status, void* data) { - std::unique_ptr<Baton> baton(static_cast<Baton*>(data)); - auto* stmt = baton->stmt; - - auto env = stmt->Env(); - Napi::HandleScope scope(env); - - if (stmt->status != SQLITE_OK) { - Error(baton.get()); - } - else { - // Fire callbacks. - Napi::Function cb = baton->callback.Value(); - if (IS_FUNCTION(cb)) { - Napi::Value argv[] = { env.Null() }; - TRY_CATCH_CALL(stmt->Value(), cb, 1, argv); - } - } - - STATEMENT_END(); -} - - - -Napi::Value Statement::Get(const Napi::CallbackInfo& info) { - auto env = info.Env(); - Statement* stmt = this; - - Baton* baton = stmt->Bind<RowBaton>(info); - if (baton == NULL) { - Napi::Error::New(env, "Data type is not supported").ThrowAsJavaScriptException(); - return env.Null(); - } - else { - stmt->Schedule(Work_BeginGet, baton); - return info.This(); - } -} - -void Statement::Work_BeginGet(Baton* baton) { - STATEMENT_BEGIN(Get); -} - -void Statement::Work_Get(napi_env e, void* data) { - STATEMENT_INIT(RowBaton); - - if (stmt->status != SQLITE_DONE || baton->parameters.size()) { - STATEMENT_MUTEX(mtx); - sqlite3_mutex_enter(mtx); - - if (stmt->Bind(baton->parameters)) { - stmt->status = sqlite3_step(stmt->_handle); - - if (!(stmt->status == SQLITE_ROW || stmt->status == SQLITE_DONE)) { - stmt->message = std::string(sqlite3_errmsg(stmt->db->_handle)); - } - } - - sqlite3_mutex_leave(mtx); - - if (stmt->status == SQLITE_ROW) { - // Acquire one result row before returning. - GetRow(&baton->row, stmt->_handle); - } - } -} - -void Statement::Work_AfterGet(napi_env e, napi_status status, void* data) { - std::unique_ptr<RowBaton> baton(static_cast<RowBaton*>(data)); - auto* stmt = baton->stmt; - - auto env = stmt->Env(); - Napi::HandleScope scope(env); - - if (stmt->status != SQLITE_ROW && stmt->status != SQLITE_DONE) { - Error(baton.get()); - } - else { - // Fire callbacks. - Napi::Function cb = baton->callback.Value(); - 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) }; - TRY_CATCH_CALL(stmt->Value(), cb, 2, argv); - } - else { - Napi::Value argv[] = { env.Null() }; - TRY_CATCH_CALL(stmt->Value(), cb, 1, argv); - } - } - } - - STATEMENT_END(); -} - -Napi::Value Statement::Run(const Napi::CallbackInfo& info) { - auto env = info.Env(); - Statement* stmt = this; - - Baton* baton = stmt->Bind<RunBaton>(info); - if (baton == NULL) { - Napi::Error::New(env, "Data type is not supported").ThrowAsJavaScriptException(); - return env.Null(); - } - else { - stmt->Schedule(Work_BeginRun, baton); - return info.This(); - } -} - -void Statement::Work_BeginRun(Baton* baton) { - STATEMENT_BEGIN(Run); -} - -void Statement::Work_Run(napi_env e, void* data) { - STATEMENT_INIT(RunBaton); - - STATEMENT_MUTEX(mtx); - sqlite3_mutex_enter(mtx); - - // Make sure that we also reset when there are no parameters. - if (!baton->parameters.size()) { - sqlite3_reset(stmt->_handle); - } - - if (stmt->Bind(baton->parameters)) { - stmt->status = sqlite3_step(stmt->_handle); - - if (!(stmt->status == SQLITE_ROW || stmt->status == SQLITE_DONE)) { - stmt->message = std::string(sqlite3_errmsg(stmt->db->_handle)); - } - else { - baton->inserted_id = sqlite3_last_insert_rowid(stmt->db->_handle); - baton->changes = sqlite3_changes(stmt->db->_handle); - } - } - - sqlite3_mutex_leave(mtx); -} - -void Statement::Work_AfterRun(napi_env e, napi_status status, void* data) { - std::unique_ptr<RunBaton> baton(static_cast<RunBaton*>(data)); - auto* stmt = baton->stmt; - - auto env = stmt->Env(); - Napi::HandleScope scope(env); - - if (stmt->status != SQLITE_ROW && stmt->status != SQLITE_DONE) { - Error(baton.get()); - } - else { - // Fire callbacks. - Napi::Function cb = baton->callback.Value(); - 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)); - - Napi::Value argv[] = { env.Null() }; - TRY_CATCH_CALL(stmt->Value(), cb, 1, argv); - } - } - - STATEMENT_END(); -} - -Napi::Value Statement::All(const Napi::CallbackInfo& info) { - auto env = info.Env(); - Statement* stmt = this; - - Baton* baton = stmt->Bind<RowsBaton>(info); - if (baton == NULL) { - Napi::Error::New(env, "Data type is not supported").ThrowAsJavaScriptException(); - return env.Null(); - } - else { - stmt->Schedule(Work_BeginAll, baton); - return info.This(); - } -} - -void Statement::Work_BeginAll(Baton* baton) { - STATEMENT_BEGIN(All); -} - -void Statement::Work_All(napi_env e, void* data) { - STATEMENT_INIT(RowsBaton); - - STATEMENT_MUTEX(mtx); - sqlite3_mutex_enter(mtx); - - // Make sure that we also reset when there are no parameters. - if (!baton->parameters.size()) { - sqlite3_reset(stmt->_handle); - } - - if (stmt->Bind(baton->parameters)) { - while ((stmt->status = sqlite3_step(stmt->_handle)) == SQLITE_ROW) { - auto row = std::make_unique<Row>(); - GetRow(row.get(), stmt->_handle); - baton->rows.emplace_back(std::move(row)); - } - - if (stmt->status != SQLITE_DONE) { - stmt->message = std::string(sqlite3_errmsg(stmt->db->_handle)); - } - } - - sqlite3_mutex_leave(mtx); -} - -void Statement::Work_AfterAll(napi_env e, napi_status status, void* data) { - std::unique_ptr<RowsBaton> baton(static_cast<RowsBaton*>(data)); - auto* stmt = baton->stmt; - - auto env = stmt->Env(); - Napi::HandleScope scope(env); - - if (stmt->status != SQLITE_DONE) { - Error(baton.get()); - } - else { - // Fire callbacks. - Napi::Function cb = baton->callback.Value(); - 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())); - auto it = static_cast<Rows::const_iterator>(baton->rows.begin()); - decltype(it) end = baton->rows.end(); - for (int i = 0; it < end; ++it, i++) { - (result).Set(i, RowToJS(env, it->get())); - } - - Napi::Value argv[] = { env.Null(), result }; - TRY_CATCH_CALL(stmt->Value(), cb, 2, argv); - } - else { - // There were no result rows. - Napi::Value argv[] = { - env.Null(), - Napi::Array::New(env, 0) - }; - TRY_CATCH_CALL(stmt->Value(), cb, 2, argv); - } - } - } - - STATEMENT_END(); -} - -Napi::Value Statement::Each(const Napi::CallbackInfo& info) { - auto env = info.Env(); - Statement* stmt = this; - - int last = info.Length(); - - Napi::Function completed; - if (last >= 2 && info[last - 1].IsFunction() && info[last - 2].IsFunction()) { - completed = info[--last].As<Napi::Function>(); - } - - auto baton = stmt->Bind<EachBaton>(info, 0, last); - if (baton == NULL) { - Napi::Error::New(env, "Data type is not supported").ThrowAsJavaScriptException(); - return env.Null(); - } - else { - baton->completed.Reset(completed, 1); - stmt->Schedule(Work_BeginEach, baton); - return info.This(); - } -} - -void Statement::Work_BeginEach(Baton* baton) { - // Only create the Async object when we're actually going into - // the event loop. This prevents dangling events. - auto* each_baton = static_cast<EachBaton*>(baton); - each_baton->async = new Async(each_baton->stmt, reinterpret_cast<uv_async_cb>(AsyncEach)); - each_baton->async->item_cb.Reset(each_baton->callback.Value(), 1); - each_baton->async->completed_cb.Reset(each_baton->completed.Value(), 1); - - STATEMENT_BEGIN(Each); -} - -void Statement::Work_Each(napi_env e, void* data) { - STATEMENT_INIT(EachBaton); - - auto* async = baton->async; - - STATEMENT_MUTEX(mtx); - - // Make sure that we also reset when there are no parameters. - if (!baton->parameters.size()) { - sqlite3_reset(stmt->_handle); - } - - if (stmt->Bind(baton->parameters)) { - while (true) { - sqlite3_mutex_enter(mtx); - stmt->status = sqlite3_step(stmt->_handle); - if (stmt->status == SQLITE_ROW) { - sqlite3_mutex_leave(mtx); - auto row = std::make_unique<Row>(); - GetRow(row.get(), stmt->_handle); - NODE_SQLITE3_MUTEX_LOCK(&async->mutex) - async->data.emplace_back(std::move(row)); - NODE_SQLITE3_MUTEX_UNLOCK(&async->mutex) - - uv_async_send(&async->watcher); - } - else { - if (stmt->status != SQLITE_DONE) { - stmt->message = std::string(sqlite3_errmsg(stmt->db->_handle)); - } - sqlite3_mutex_leave(mtx); - break; - } - } - } - - async->completed = true; - uv_async_send(&async->watcher); -} - -void Statement::CloseCallback(uv_handle_t* handle) { - assert(handle != NULL); - assert(handle->data != NULL); - auto* async = static_cast<Async*>(handle->data); - delete async; -} - -void Statement::AsyncEach(uv_async_t* handle) { - auto* async = static_cast<Async*>(handle->data); - - auto env = async->stmt->Env(); - Napi::HandleScope scope(env); - - while (true) { - // Get the contents out of the data cache for us to process in the JS callback. - Rows rows; - NODE_SQLITE3_MUTEX_LOCK(&async->mutex) - rows.swap(async->data); - NODE_SQLITE3_MUTEX_UNLOCK(&async->mutex) - - if (rows.empty()) { - break; - } - - Napi::Function cb = async->item_cb.Value(); - if (IS_FUNCTION(cb)) { - Napi::Value argv[2]; - argv[0] = env.Null(); - - for(auto& row : rows) { - argv[1] = RowToJS(env,row.get()); - async->retrieved++; - TRY_CATCH_CALL(async->stmt->Value(), cb, 2, argv); - } - } - } - - Napi::Function cb = async->completed_cb.Value(); - if (async->completed) { - if (!cb.IsEmpty() && - cb.IsFunction()) { - Napi::Value argv[] = { - env.Null(), - Napi::Number::New(env, async->retrieved) - }; - TRY_CATCH_CALL(async->stmt->Value(), cb, 2, argv); - } - uv_close(reinterpret_cast<uv_handle_t*>(handle), CloseCallback); - } -} - -void Statement::Work_AfterEach(napi_env e, napi_status status, void* data) { - std::unique_ptr<EachBaton> baton(static_cast<EachBaton*>(data)); - auto* stmt = baton->stmt; - - auto env = stmt->Env(); - Napi::HandleScope scope(env); - - if (stmt->status != SQLITE_DONE) { - Error(baton.get()); - } - - STATEMENT_END(); -} - -Napi::Value Statement::Reset(const Napi::CallbackInfo& info) { - auto env = info.Env(); - Statement* stmt = this; - - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - auto* baton = new Baton(stmt, callback); - stmt->Schedule(Work_BeginReset, baton); - - return info.This(); -} - -void Statement::Work_BeginReset(Baton* baton) { - STATEMENT_BEGIN(Reset); -} - -void Statement::Work_Reset(napi_env e, void* data) { - STATEMENT_INIT(Baton); - - sqlite3_reset(stmt->_handle); - stmt->status = SQLITE_OK; -} - -void Statement::Work_AfterReset(napi_env e, napi_status status, void* data) { - std::unique_ptr<Baton> baton(static_cast<Baton*>(data)); - auto* stmt = baton->stmt; - - auto env = stmt->Env(); - Napi::HandleScope scope(env); - - // Fire callbacks. - Napi::Function cb = baton->callback.Value(); - if (IS_FUNCTION(cb)) { - Napi::Value argv[] = { env.Null() }; - TRY_CATCH_CALL(stmt->Value(), cb, 1, argv); - } - - STATEMENT_END(); -} - -Napi::Value Statement::RowToJS(Napi::Env env, Row* row) { - Napi::EscapableHandleScope scope(env); - - auto result = Napi::Object::New(env); - - for (auto& field : *row) { - - Napi::Value value; - - switch (field->type) { - case SQLITE_INTEGER: { - value = Napi::Number::New(env, (static_cast<Values::Integer*>(field.get()))->value); - } break; - case SQLITE_FLOAT: { - value = Napi::Number::New(env, (static_cast<Values::Float*>(field.get()))->value); - } break; - case SQLITE_TEXT: { - value = Napi::String::New(env, (static_cast<Values::Text*>(field.get()))->value.c_str(), - (static_cast<Values::Text*>(field.get()))->value.size()); - } break; - case SQLITE_BLOB: { - value = Napi::Buffer<char>::Copy(env, (static_cast<Values::Blob*>(field.get()))->value, - (static_cast<Values::Blob*>(field.get()))->length); - } break; - case SQLITE_NULL: { - value = env.Null(); - } break; - } - - result.Set(field->name, value); - } - - return scope.Escape(result); -} - -void Statement::GetRow(Row* row, sqlite3_stmt* stmt) { - int cols = sqlite3_column_count(stmt); - - for (int i = 0; i < cols; i++) { - int type = sqlite3_column_type(stmt, i); - const char* name = sqlite3_column_name(stmt, i); - if (name == NULL) { - assert(false); - } - - switch (type) { - case SQLITE_INTEGER: { - row->emplace_back(std::make_unique<Values::Integer>(name, sqlite3_column_int64(stmt, i))); - } break; - case SQLITE_FLOAT: { - row->emplace_back(std::make_unique<Values::Float>(name, sqlite3_column_double(stmt, i))); - } break; - case SQLITE_TEXT: { - const char* text = (const char*)sqlite3_column_text(stmt, i); - int length = sqlite3_column_bytes(stmt, i); - row->emplace_back(std::make_unique<Values::Text>(name, length, text)); - } break; - case SQLITE_BLOB: { - const void* blob = sqlite3_column_blob(stmt, i); - int length = sqlite3_column_bytes(stmt, i); - row->emplace_back(std::make_unique<Values::Blob>(name, length, blob)); - } break; - case SQLITE_NULL: { - row->emplace_back(std::make_unique<Values::Null>(name)); - } break; - default: - assert(false); - } - } -} - -Napi::Value Statement::Finalize_(const Napi::CallbackInfo& info) { - auto env = info.Env(); - Statement* stmt = this; - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - auto *baton = new Baton(stmt, callback); - stmt->Schedule(Finalize_, baton); - - return stmt->db->Value(); -} - -void Statement::Finalize_(Baton* b) { - auto baton = std::unique_ptr<Baton>(b); - auto env = baton->stmt->Env(); - Napi::HandleScope scope(env); - - baton->stmt->Finalize_(); - - // Fire callback in case there was one. - Napi::Function cb = baton->callback.Value(); - if (IS_FUNCTION(cb)) { - TRY_CATCH_CALL(baton->stmt->Value(), cb, 0, NULL); - } -} - -void Statement::Finalize_() { - assert(!finalized); - finalized = true; - CleanQueue(); - // Finalize returns the status code of the last operation. We already fired - // error events in case those failed. - sqlite3_finalize(_handle); - _handle = NULL; - db->Unref(); -} - -void Statement::CleanQueue() { - auto env = this->Env(); - Napi::HandleScope scope(env); - - if (prepared && !queue.empty()) { - // This statement has already been prepared and is now finalized. - // Fire error for all remaining items in the queue. - EXCEPTION(Napi::String::New(env, "Statement is already finalized"), SQLITE_MISUSE, exception); - Napi::Value argv[] = { exception }; - bool called = false; - - // Clear out the queue so that this object can get GC'ed. - while (!queue.empty()) { - auto call = std::unique_ptr<Call>(queue.front()); - queue.pop(); - - auto baton = std::unique_ptr<Baton>(call->baton); - Napi::Function cb = baton->callback.Value(); - - if (prepared && !cb.IsEmpty() && - cb.IsFunction()) { - TRY_CATCH_CALL(Value(), cb, 1, argv); - called = true; - } - } - - // When we couldn't call a callback function, emit an error on the - // Statement object. - if (!called) { - Napi::Value info[] = { Napi::String::New(env, "error"), exception }; - EMIT_EVENT(Value(), 2, info); - } - } - else while (!queue.empty()) { - // Just delete all items in the queue; we already fired an event when - // preparing the statement failed. - auto call = std::unique_ptr<Call>(queue.front()); - queue.pop(); - // We don't call the actual callback, so we have to make sure that - // the baton gets destroyed. - delete call->baton; - } -} diff --git a/updater/sql/win/src/statement.h b/updater/sql/win/src/statement.h deleted file mode 100755 index c522c0f..0000000 --- a/updater/sql/win/src/statement.h +++ /dev/null @@ -1,244 +0,0 @@ -#ifndef NODE_SQLITE3_SRC_STATEMENT_H -#define NODE_SQLITE3_SRC_STATEMENT_H - -#include <cstdlib> -#include <cstring> -#include <string> -#include <queue> -#include <vector> -#include <sqlite3.h> -#include <napi.h> -#include <uv.h> - -#include "database.h" -#include "threading.h" - -using namespace Napi; - -namespace node_sqlite3 { - -namespace Values { - struct Field { - inline Field(unsigned short _index, unsigned short _type = SQLITE_NULL) : - type(_type), index(_index) {} - inline Field(const char* _name, unsigned short _type = SQLITE_NULL) : - type(_type), index(0), name(_name) {} - - unsigned short type; - unsigned short index; - std::string name; - - virtual ~Field() = default; - }; - - struct Integer : Field { - template <class T> inline Integer(T _name, int64_t val) : - Field(_name, SQLITE_INTEGER), value(val) {} - int64_t value; - virtual ~Integer() override = default; - }; - - struct Float : Field { - template <class T> inline Float(T _name, double val) : - Field(_name, SQLITE_FLOAT), value(val) {} - double value; - virtual ~Float() override = default; - }; - - struct Text : Field { - template <class T> inline Text(T _name, size_t len, const char* val) : - Field(_name, SQLITE_TEXT), value(val, len) {} - std::string value; - virtual ~Text() override = default; - }; - - struct Blob : Field { - template <class T> inline Blob(T _name, size_t len, const void* val) : - Field(_name, SQLITE_BLOB), length(len) { - value = new char[len]; - assert(value != nullptr); - memcpy(value, val, len); - } - inline virtual ~Blob() override { - delete[] value; - } - int length; - char* value; - }; - - typedef Field Null; -} - -typedef std::vector<std::unique_ptr<Values::Field> > Row; -typedef std::vector<std::unique_ptr<Row> > Rows; -typedef Row Parameters; - - - -class Statement : public Napi::ObjectWrap<Statement> { -public: - static Napi::Object Init(Napi::Env env, Napi::Object exports); - static Napi::Value New(const Napi::CallbackInfo& info); - - struct Baton { - napi_async_work request = NULL; - Statement* stmt; - Napi::FunctionReference callback; - Parameters parameters; - - Baton(Statement* stmt_, Napi::Function cb_) : stmt(stmt_) { - stmt->Ref(); - callback.Reset(cb_, 1); - } - virtual ~Baton() { - parameters.clear(); - if (request) napi_delete_async_work(stmt->Env(), request); - stmt->Unref(); - callback.Reset(); - } - }; - - struct RowBaton : Baton { - RowBaton(Statement* stmt_, Napi::Function cb_) : - Baton(stmt_, cb_) {} - Row row; - virtual ~RowBaton() override = default; - }; - - struct RunBaton : Baton { - RunBaton(Statement* stmt_, Napi::Function cb_) : - Baton(stmt_, cb_), inserted_id(0), changes(0) {} - sqlite3_int64 inserted_id; - int changes; - virtual ~RunBaton() override = default; - }; - - struct RowsBaton : Baton { - RowsBaton(Statement* stmt_, Napi::Function cb_) : - Baton(stmt_, cb_) {} - Rows rows; - virtual ~RowsBaton() override = default; - }; - - struct Async; - - struct EachBaton : Baton { - Napi::FunctionReference completed; - Async* async; // Isn't deleted when the baton is deleted. - - EachBaton(Statement* stmt_, Napi::Function cb_) : - Baton(stmt_, cb_) {} - virtual ~EachBaton() override { - completed.Reset(); - } - }; - - struct PrepareBaton : Database::Baton { - Statement* stmt; - std::string sql; - PrepareBaton(Database* db_, Napi::Function cb_, Statement* stmt_) : - Baton(db_, cb_), stmt(stmt_) { - stmt->Ref(); - } - virtual ~PrepareBaton() override { - stmt->Unref(); - if (!db->IsOpen() && db->IsLocked()) { - // The database handle was closed before the statement could be - // prepared. - stmt->Finalize_(); - } - } - }; - - typedef void (*Work_Callback)(Baton* baton); - - struct Call { - Call(Work_Callback cb_, Baton* baton_) : callback(cb_), baton(baton_) {}; - Work_Callback callback; - Baton* baton; - }; - - struct Async { - uv_async_t watcher; - Statement* stmt; - Rows data; - NODE_SQLITE3_MUTEX_t; - bool completed; - int retrieved; - - // Store the callbacks here because we don't have - // access to the baton in the async callback. - Napi::FunctionReference item_cb; - Napi::FunctionReference completed_cb; - - Async(Statement* st, uv_async_cb async_cb) : - stmt(st), completed(false), retrieved(0) { - watcher.data = this; - NODE_SQLITE3_MUTEX_INIT - stmt->Ref(); - uv_loop_t *loop; - napi_get_uv_event_loop(stmt->Env(), &loop); - uv_async_init(loop, &watcher, async_cb); - } - - ~Async() { - stmt->Unref(); - item_cb.Reset(); - completed_cb.Reset(); - NODE_SQLITE3_MUTEX_DESTROY - } - }; - - Statement(const Napi::CallbackInfo& info); - - ~Statement() { - if (!finalized) Finalize_(); - } - - WORK_DEFINITION(Bind) - WORK_DEFINITION(Get) - WORK_DEFINITION(Run) - WORK_DEFINITION(All) - WORK_DEFINITION(Each) - WORK_DEFINITION(Reset) - - Napi::Value Finalize_(const Napi::CallbackInfo& info); - -protected: - static void Work_BeginPrepare(Database::Baton* baton); - static void Work_Prepare(napi_env env, void* data); - static void Work_AfterPrepare(napi_env env, napi_status status, void* data); - - static void AsyncEach(uv_async_t* handle); - static void CloseCallback(uv_handle_t* handle); - - static void Finalize_(Baton* baton); - void Finalize_(); - - template <class T> inline std::unique_ptr<Values::Field> BindParameter(const Napi::Value source, T pos); - template <class T> T* Bind(const Napi::CallbackInfo& info, int start = 0, int end = -1); - bool Bind(const Parameters ¶meters); - - static void GetRow(Row* row, sqlite3_stmt* stmt); - static Napi::Value RowToJS(Napi::Env env, Row* row); - void Schedule(Work_Callback callback, Baton* baton); - void Process(); - void CleanQueue(); - template <class T> static void Error(T* baton); - -protected: - Database* db; - - sqlite3_stmt* _handle = NULL; - int status = SQLITE_OK; - bool prepared = false; - bool locked = true; - bool finalized = false; - - std::queue<Call*> queue; - std::string message; -}; - -} - -#endif diff --git a/updater/sql/win/src/threading.h b/updater/sql/win/src/threading.h deleted file mode 100755 index 7c7139b..0000000 --- a/updater/sql/win/src/threading.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef NODE_SQLITE3_SRC_THREADING_H -#define NODE_SQLITE3_SRC_THREADING_H - -#define NODE_SQLITE3_MUTEX_t uv_mutex_t mutex; -#define NODE_SQLITE3_MUTEX_INIT uv_mutex_init(&mutex); -#define NODE_SQLITE3_MUTEX_LOCK(m) uv_mutex_lock(m); -#define NODE_SQLITE3_MUTEX_UNLOCK(m) uv_mutex_unlock(m); -#define NODE_SQLITE3_MUTEX_DESTROY uv_mutex_destroy(&mutex); - -#endif // NODE_SQLITE3_SRC_THREADING_H |