Dia antes primera install

This commit is contained in:
2025-12-08 15:20:28 -06:00
commit 1416478c9c
4130 changed files with 886376 additions and 0 deletions

25
node_modules/sqlite3/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,25 @@
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.

249
node_modules/sqlite3/README.md generated vendored Normal file
View File

@@ -0,0 +1,249 @@
# ⚙️ 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)

58
node_modules/sqlite3/binding.gyp generated vendored Normal file
View File

@@ -0,0 +1,58 @@
{
"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" ]
}
]
}

BIN
node_modules/sqlite3/build/Release/node_sqlite3.node generated vendored Executable file

Binary file not shown.

60
node_modules/sqlite3/deps/common-sqlite.gypi generated vendored Normal file
View File

@@ -0,0 +1,60 @@
{
'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
}
}
}
}
}
}

10
node_modules/sqlite3/deps/extract.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
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,
});

Binary file not shown.

121
node_modules/sqlite3/deps/sqlite3.gyp generated vendored Executable file
View File

@@ -0,0 +1,121 @@
{
'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)"'
]
}]
],
}
]
}

1
node_modules/sqlite3/lib/sqlite3-binding.js generated vendored Normal file
View File

@@ -0,0 +1 @@
module.exports = require('bindings')('node_sqlite3.node');

205
node_modules/sqlite3/lib/sqlite3.d.ts generated vendored Normal file
View File

@@ -0,0 +1,205 @@
// 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;
}

207
node_modules/sqlite3/lib/sqlite3.js generated vendored Normal file
View File

@@ -0,0 +1,207 @@
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;
};

38
node_modules/sqlite3/lib/trace.js generated vendored Normal file
View File

@@ -0,0 +1,38 @@
// 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;
});
}

89
node_modules/sqlite3/package.json generated vendored Normal file
View File

@@ -0,0 +1,89 @@
{
"name": "sqlite3",
"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"
]
}
}

76
node_modules/sqlite3/src/async.h generated vendored Normal file
View File

@@ -0,0 +1,76 @@
#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

418
node_modules/sqlite3/src/backup.cc generated vendored Normal file
View File

@@ -0,0 +1,418 @@
#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());
}
}
}

209
node_modules/sqlite3/src/backup.h generated vendored Normal file
View File

@@ -0,0 +1,209 @@
#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

751
node_modules/sqlite3/src/database.cc generated vendored Normal file
View File

@@ -0,0 +1,751 @@
#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;
}
}

188
node_modules/sqlite3/src/database.h generated vendored Normal file
View File

@@ -0,0 +1,188 @@
#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

30
node_modules/sqlite3/src/gcc-preinclude.h generated vendored Normal file
View File

@@ -0,0 +1,30 @@
// 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

207
node_modules/sqlite3/src/macros.h generated vendored Normal file
View File

@@ -0,0 +1,207 @@
#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

128
node_modules/sqlite3/src/node_sqlite3.cc generated vendored Normal file
View File

@@ -0,0 +1,128 @@
#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)

939
node_modules/sqlite3/src/statement.cc generated vendored Normal file
View File

@@ -0,0 +1,939 @@
#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;
}
}

244
node_modules/sqlite3/src/statement.h generated vendored Normal file
View File

@@ -0,0 +1,244 @@
#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 &parameters);
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

10
node_modules/sqlite3/src/threading.h generated vendored Normal file
View File

@@ -0,0 +1,10 @@
#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