Compare commits
No commits in common. "main" and "v2.3.0" have entirely different histories.
57
.github/workflows/publish.yaml
vendored
57
.github/workflows/publish.yaml
vendored
@ -40,7 +40,7 @@ jobs:
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
with:
|
||||
version: 10.18.1
|
||||
version: 10.3.0
|
||||
|
||||
- name: Get Node version from .nvmrc
|
||||
id: get-nvm-version
|
||||
@ -90,7 +90,7 @@ jobs:
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
with:
|
||||
version: 10.18.1
|
||||
version: 10.3.0
|
||||
|
||||
- name: Get Node version from .nvmrc
|
||||
id: get-nvm-version
|
||||
@ -118,9 +118,11 @@ jobs:
|
||||
publish:
|
||||
name: Publish
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
buildType: ['production', 'profiling']
|
||||
|
||||
permissions:
|
||||
# Required for OIDC
|
||||
id-token: 'write'
|
||||
# Needed for ncipollo/release-action.
|
||||
contents: 'write'
|
||||
|
||||
@ -137,23 +139,24 @@ jobs:
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
with:
|
||||
version: 10.18.1
|
||||
version: 10.3.0
|
||||
- name: Setup node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
registry-url: 'https://registry.npmjs.org/'
|
||||
|
||||
- name: Update npm
|
||||
run: npm install -g npm@latest
|
||||
|
||||
- name: Download built production libraries
|
||||
- name: Download built libraries
|
||||
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.19.1
|
||||
with:
|
||||
pattern: sqlcipher-production-*
|
||||
pattern: sqlcipher-${{matrix.buildType}}-*
|
||||
path: prebuilds
|
||||
merge-multiple: true
|
||||
|
||||
- name: Update package.json
|
||||
if: ${{ matrix.buildType == 'profiling' }}
|
||||
run: pnpm version prerelease --no-git-tag-version --preid profiling
|
||||
|
||||
- name: Install node_modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
@ -163,13 +166,21 @@ jobs:
|
||||
- name: Lint
|
||||
run: pnpm lint
|
||||
|
||||
- name: Production Tests
|
||||
run: pnpm test
|
||||
- run: pnpm test
|
||||
env:
|
||||
PREBUILDS_ONLY: 1
|
||||
|
||||
- name: Publish production
|
||||
if: ${{ matrix.buildType == 'production' }}
|
||||
run: pnpm publish --tag '${{ github.event.inputs.npm_tag }}' --access public --no-git-checks ${{ inputs.dry_run && '--dry-run' || ''}}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Publish profiling
|
||||
if: ${{ matrix.buildType == 'profiling' }}
|
||||
run: pnpm publish --tag 'profiling' --access public --no-git-checks ${{ inputs.dry_run && '--dry-run' || ''}}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Rename symbols
|
||||
run: |
|
||||
@ -183,28 +194,8 @@ jobs:
|
||||
# This step is expected to fail if not run on a tag.
|
||||
- name: Upload debug info to release
|
||||
uses: ncipollo/release-action@440c8c1cb0ed28b9f43e4d1d670870f059653174 # v1.16.0
|
||||
if: ${{ !inputs.dry_run && matrix.buildType == 'production' }}
|
||||
with:
|
||||
allowUpdates: true
|
||||
artifactErrorsFailBuild: true
|
||||
artifacts: prebuilds/node_sqlcipher_*.sym
|
||||
|
||||
- name: Update package.json version to profiling
|
||||
run: pnpm version prerelease --no-git-tag-version --preid profiling
|
||||
|
||||
- name: Remove production prebuilds
|
||||
run: rm -rf prebuilds
|
||||
|
||||
- name: Download built profiling libraries
|
||||
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.19.1
|
||||
with:
|
||||
pattern: sqlcipher-profiling-*
|
||||
path: prebuilds
|
||||
merge-multiple: true
|
||||
|
||||
- name: Profiling build tests
|
||||
run: pnpm test
|
||||
env:
|
||||
PREBUILDS_ONLY: 1
|
||||
|
||||
- name: Publish profiling
|
||||
run: pnpm publish --tag 'profiling' --access public --no-git-checks ${{ inputs.dry_run && '--dry-run' || ''}}
|
||||
|
||||
2
.github/workflows/test.yaml
vendored
2
.github/workflows/test.yaml
vendored
@ -30,7 +30,7 @@ jobs:
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
with:
|
||||
version: 10.18.1
|
||||
version: 10.3.0
|
||||
- name: Setup node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,4 +7,3 @@ docs/
|
||||
.tmp/
|
||||
.eslintcache
|
||||
todo.md
|
||||
.vscode
|
||||
|
||||
13
Dockerfile
13
Dockerfile
@ -2,7 +2,7 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
#
|
||||
|
||||
FROM ubuntu:jammy-20250714@sha256:1ec65b2719518e27d4d25f104d93f9fac60dc437f81452302406825c46fcc9cb
|
||||
FROM ubuntu:focal-20240530@sha256:fa17826afb526a9fc7250e0fbcbfd18d03fe7a54849472f86879d8bf562c629e
|
||||
|
||||
# Avoid getting prompted to configure things during installation.
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
@ -15,15 +15,13 @@ COPY docker/apt.conf docker/sources.list /etc/apt/
|
||||
# But we can't install it because it doesn't trust our mirror!
|
||||
# Temporarily disables APT's certificate signature checking
|
||||
# to download the certificates.
|
||||
RUN apt update -oAcquire::https::Verify-Peer=false
|
||||
RUN apt install -oAcquire::https::Verify-Peer=false -y ca-certificates
|
||||
|
||||
RUN apt-get update -oAcquire::https::Verify-Peer=false \
|
||||
&& apt-get install -oAcquire::https::Verify-Peer=false -y ca-certificates
|
||||
# Back to normal, verification back on
|
||||
|
||||
# Install only what's needed to set up Rust and Node.
|
||||
# We'll install additional tools at the end to take advantage of Docker's caching of earlier steps.
|
||||
RUN apt update
|
||||
RUN apt install -y apt-transport-https xz-utils unzip
|
||||
RUN apt-get update && apt-get install -y apt-transport-https xz-utils unzip
|
||||
|
||||
# User-specific setup!
|
||||
|
||||
@ -67,9 +65,6 @@ RUN tar -xf node.tar.xz \
|
||||
|
||||
ENV PATH="/home/sqlcipher/node/bin:${PATH}"
|
||||
|
||||
# Install pnpm
|
||||
RUN npm install -g pnpm@10.18.1
|
||||
|
||||
# And finally any bonus packages we're going to need
|
||||
# Note that we jump back to root for this.
|
||||
USER root
|
||||
|
||||
@ -37,7 +37,7 @@ cd deps/sqlcipher
|
||||
export OPENSSL_PREFIX=`brew --prefix openssl`
|
||||
export CFLAGS="-I $OPENSSL_PREFIX/include"
|
||||
export LIBRARY_PATH="$LIBRARY_PATH:$OPENSSL_PREFIX/lib"
|
||||
./update.sh v4.10.0
|
||||
./update.sh v4.7.0
|
||||
cd -
|
||||
```
|
||||
|
||||
|
||||
@ -2,8 +2,7 @@ import { Buffer } from 'node:buffer';
|
||||
import { bench, describe } from 'vitest';
|
||||
|
||||
import BDatabase from '@signalapp/better-sqlite3';
|
||||
import { DatabaseSync as NDatabase } from 'node:sqlite';
|
||||
import Database from '../dist/index.mjs';
|
||||
import Database from '../lib/index.js';
|
||||
|
||||
const PREPARE = `
|
||||
CREATE TABLE t (
|
||||
@ -22,15 +21,12 @@ const DELETE = 'DELETE FROM t';
|
||||
describe('INSERT INTO t', () => {
|
||||
const sdb = new Database(':memory:', { cacheStatements: true });
|
||||
const bdb = new BDatabase(':memory:');
|
||||
const ndb = new NDatabase(':memory:');
|
||||
|
||||
sdb.exec(PREPARE);
|
||||
bdb.exec(PREPARE);
|
||||
ndb.exec(PREPARE);
|
||||
|
||||
const sinsert = sdb.prepare(INSERT);
|
||||
const binsert = bdb.prepare(INSERT);
|
||||
const ninsert = ndb.prepare(INSERT);
|
||||
|
||||
bench(
|
||||
'@signalapp/sqlcipher',
|
||||
@ -55,16 +51,4 @@ describe('INSERT INTO t', () => {
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
bench(
|
||||
'node:sqlite',
|
||||
() => {
|
||||
ninsert.run({ b: BLOB });
|
||||
},
|
||||
{
|
||||
teardown: () => {
|
||||
ndb.exec(DELETE);
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
|
||||
import BDatabase from '@signalapp/better-sqlite3';
|
||||
import { DatabaseSync as NDatabase } from 'node:sqlite';
|
||||
import Database from '../dist/index.mjs';
|
||||
import Database from '../lib/index.js';
|
||||
|
||||
const PREPARE = `
|
||||
CREATE TABLE t (
|
||||
@ -25,15 +24,12 @@ const DELETE = 'DELETE FROM t';
|
||||
describe('INSERT INTO t', () => {
|
||||
const sdb = new Database(':memory:', { cacheStatements: true });
|
||||
const bdb = new BDatabase(':memory:');
|
||||
const ndb = new NDatabase(':memory:');
|
||||
|
||||
sdb.exec(PREPARE);
|
||||
bdb.exec(PREPARE);
|
||||
ndb.exec(PREPARE);
|
||||
|
||||
const sinsert = sdb.prepare(INSERT);
|
||||
const binsert = bdb.prepare(INSERT);
|
||||
const ninsert = ndb.prepare(INSERT);
|
||||
|
||||
bench(
|
||||
'@signalapp/sqlcipher',
|
||||
@ -58,16 +54,4 @@ describe('INSERT INTO t', () => {
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
bench(
|
||||
'node:sqlite',
|
||||
() => {
|
||||
ninsert.run({ a1: 1, a2: 2, a3: 3, b1: 'b1', b2: 'b2', b3: 'b3' });
|
||||
},
|
||||
{
|
||||
teardown: () => {
|
||||
ndb.exec(DELETE);
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
|
||||
import BDatabase from '@signalapp/better-sqlite3';
|
||||
import { DatabaseSync as NDatabase } from 'node:sqlite';
|
||||
import Database from '../dist/index.mjs';
|
||||
import Database from '../lib/index.js';
|
||||
|
||||
const PREPARE = `
|
||||
CREATE TABLE t (
|
||||
@ -37,15 +36,12 @@ const SELECT = 'SELECT * FROM t LIMIT 1000';
|
||||
describe('SELECT * FROM t', () => {
|
||||
const sdb = new Database(':memory:', { cacheStatements: true });
|
||||
const bdb = new BDatabase(':memory:');
|
||||
const ndb = new NDatabase(':memory:');
|
||||
|
||||
sdb.exec(PREPARE);
|
||||
bdb.exec(PREPARE);
|
||||
ndb.exec(PREPARE);
|
||||
|
||||
const sinsert = sdb.prepare(INSERT);
|
||||
const binsert = bdb.prepare(INSERT);
|
||||
const ninsert = ndb.prepare(INSERT);
|
||||
|
||||
sdb.transaction(() => {
|
||||
for (const value of VALUES) {
|
||||
@ -59,12 +55,6 @@ describe('SELECT * FROM t', () => {
|
||||
}
|
||||
})();
|
||||
|
||||
ndb.exec('BEGIN');
|
||||
for (const value of VALUES) {
|
||||
ninsert.run(value);
|
||||
}
|
||||
ndb.exec('COMMIT');
|
||||
|
||||
const sselect = sdb.prepare(SELECT);
|
||||
const bselect = bdb.prepare(SELECT);
|
||||
|
||||
@ -75,10 +65,4 @@ describe('SELECT * FROM t', () => {
|
||||
bench('@signalapp/better-sqlite', () => {
|
||||
bselect.all();
|
||||
});
|
||||
|
||||
bench('node:sqlite', () => {
|
||||
// Node.js seems to finalize the statement after `.all()`
|
||||
const nselect = ndb.prepare(SELECT);
|
||||
nselect.all();
|
||||
});
|
||||
});
|
||||
|
||||
14
deps/extension/Cargo.lock
generated
vendored
14
deps/extension/Cargo.lock
generated
vendored
@ -425,17 +425,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
@ -465,7 +454,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-sqlcipher-extension"
|
||||
version = "0.2.2"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"cbc",
|
||||
@ -473,7 +462,6 @@ dependencies = [
|
||||
"hmac",
|
||||
"pbkdf2",
|
||||
"rand_core",
|
||||
"sha1",
|
||||
"sha2",
|
||||
"signal-tokenizer",
|
||||
]
|
||||
|
||||
3
deps/extension/Cargo.toml
vendored
3
deps/extension/Cargo.toml
vendored
@ -5,7 +5,7 @@
|
||||
|
||||
[package]
|
||||
name = "signal-sqlcipher-extension"
|
||||
version = "0.2.2"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-only"
|
||||
|
||||
@ -23,7 +23,6 @@ cbc = "0.1.2"
|
||||
hmac = "0.12.1"
|
||||
pbkdf2 = "0.12.2"
|
||||
rand_core = { version = "0.6.4", "default-features" = false, features = ["getrandom"] }
|
||||
sha1 = { version = "0.10.6", "default-features" = false }
|
||||
sha2 = { version = "0.10.8", "default-features" = false }
|
||||
signal-tokenizer = { git = "https://github.com/signalapp/Signal-FTS5-Extension" }
|
||||
|
||||
|
||||
56
deps/extension/src/lib.rs
vendored
56
deps/extension/src/lib.rs
vendored
@ -10,7 +10,6 @@ use core::ffi::{c_char, c_int, c_uchar, c_void};
|
||||
use hmac::{Hmac, Mac};
|
||||
use pbkdf2::pbkdf2_hmac;
|
||||
use rand_core::{OsRng, RngCore};
|
||||
use sha1::Sha1;
|
||||
use sha2::Sha512;
|
||||
|
||||
pub use signal_tokenizer;
|
||||
@ -71,7 +70,6 @@ extern "C" fn random(_ctx: *mut c_void, buf: *mut c_void, length: c_int) -> c_in
|
||||
extern "C" fn get_hmac_sz(_ctx: *mut c_void, algorithm: c_int) -> c_int {
|
||||
match algorithm {
|
||||
SQLCIPHER_HMAC_SHA512 => 64,
|
||||
SQLCIPHER_HMAC_SHA1 => 20,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
@ -87,6 +85,9 @@ extern "C" fn hmac(
|
||||
in2_sz: c_int,
|
||||
out: *mut c_uchar,
|
||||
) -> c_int {
|
||||
if algorithm != SQLCIPHER_HMAC_SHA512 {
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
if hmac_key.is_null() || in1.is_null() || out.is_null() {
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
@ -98,34 +99,16 @@ extern "C" fn hmac(
|
||||
Some(unsafe { core::slice::from_raw_parts(in2 as *mut c_uchar, in2_sz as usize) })
|
||||
};
|
||||
|
||||
match algorithm {
|
||||
SQLCIPHER_HMAC_SHA512 => {
|
||||
let Ok(mut mac) = Hmac::<Sha512>::new_from_slice(key) else {
|
||||
return SQLITE_ERROR;
|
||||
};
|
||||
mac.update(in1);
|
||||
if let Some(in2) = in2 {
|
||||
mac.update(in2);
|
||||
}
|
||||
let digest = mac.finalize().into_bytes();
|
||||
unsafe {
|
||||
out.copy_from(digest.as_ptr(), digest.len());
|
||||
};
|
||||
}
|
||||
SQLCIPHER_HMAC_SHA1 => {
|
||||
let Ok(mut mac) = Hmac::<Sha1>::new_from_slice(key) else {
|
||||
return SQLITE_ERROR;
|
||||
};
|
||||
mac.update(in1);
|
||||
if let Some(in2) = in2 {
|
||||
mac.update(in2);
|
||||
}
|
||||
let digest = mac.finalize().into_bytes();
|
||||
unsafe {
|
||||
out.copy_from(digest.as_ptr(), digest.len());
|
||||
};
|
||||
}
|
||||
_ => return SQLITE_ERROR,
|
||||
let Ok(mut mac) = Hmac::<Sha512>::new_from_slice(key) else {
|
||||
return SQLITE_ERROR;
|
||||
};
|
||||
mac.update(in1);
|
||||
if let Some(in2) = in2 {
|
||||
mac.update(in2);
|
||||
}
|
||||
let digest = mac.finalize().into_bytes();
|
||||
unsafe {
|
||||
out.copy_from(digest.as_ptr(), digest.len());
|
||||
};
|
||||
SQLITE_OK
|
||||
}
|
||||
@ -141,21 +124,16 @@ extern "C" fn pbkdf(
|
||||
key_sz: c_int,
|
||||
key: *mut c_uchar,
|
||||
) -> c_int {
|
||||
if algorithm != SQLCIPHER_PBKDF2_HMAC_SHA512 {
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
if pass.is_null() || salt.is_null() || key.is_null() {
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
let password = unsafe { core::slice::from_raw_parts(pass as *const c_uchar, pass_sz as usize) };
|
||||
let salt = unsafe { core::slice::from_raw_parts(salt as *const c_uchar, salt_sz as usize) };
|
||||
let buf = unsafe { core::slice::from_raw_parts_mut(key as *mut c_uchar, key_sz as usize) };
|
||||
match algorithm {
|
||||
SQLCIPHER_PBKDF2_HMAC_SHA512 => {
|
||||
pbkdf2_hmac::<Sha512>(password, salt, workfactor as u32, buf);
|
||||
}
|
||||
SQLCIPHER_PBKDF2_HMAC_SHA1 => {
|
||||
pbkdf2_hmac::<Sha1>(password, salt, workfactor as u32, buf);
|
||||
}
|
||||
_ => return SQLITE_ERROR,
|
||||
};
|
||||
pbkdf2_hmac::<Sha512>(password, salt, workfactor as u32, buf);
|
||||
SQLITE_OK
|
||||
}
|
||||
|
||||
|
||||
4
deps/extension/src/sqlcipher.rs
vendored
4
deps/extension/src/sqlcipher.rs
vendored
@ -10,10 +10,6 @@ use core::ffi::{c_char, c_int, c_uchar, c_void};
|
||||
pub const SQLCIPHER_HMAC_SHA512: c_int = 2;
|
||||
pub const SQLCIPHER_PBKDF2_HMAC_SHA512: c_int = 2;
|
||||
|
||||
// Legacy encryption primitives
|
||||
pub const SQLCIPHER_HMAC_SHA1: c_int = 0;
|
||||
pub const SQLCIPHER_PBKDF2_HMAC_SHA1: c_int = 0;
|
||||
|
||||
pub const CIPHER_ENCRYPT: c_int = 1;
|
||||
|
||||
#[repr(C)]
|
||||
|
||||
22
deps/sqlcipher/sqlcipher.gyp
vendored
22
deps/sqlcipher/sqlcipher.gyp
vendored
@ -21,16 +21,13 @@
|
||||
'xcode_settings': {
|
||||
'OTHER_CFLAGS': ['-std=c99'],
|
||||
'WARNING_CFLAGS': ['-w'],
|
||||
'DEAD_CODE_STRIPPING': 'YES',
|
||||
'LLVM_LTO': 'YES',
|
||||
},
|
||||
'defines': [
|
||||
'SQLITE_LIKE_DOESNT_MATCH_BLOBS',
|
||||
'SQLITE_THREADSAFE=2',
|
||||
'SQLITE_USE_URI=0',
|
||||
'SQLITE_USE_ALLOCA',
|
||||
'SQLITE_DEFAULT_MEMSTATUS=0',
|
||||
'SQLITE_OMIT_AUTOINIT',
|
||||
'SQLITE_OMIT_DECLTYPE',
|
||||
'SQLITE_OMIT_DEPRECATED',
|
||||
'SQLITE_OMIT_DESERIALIZE',
|
||||
'SQLITE_OMIT_GET_TABLE',
|
||||
@ -39,22 +36,22 @@
|
||||
'SQLITE_OMIT_SHARED_CACHE',
|
||||
'SQLITE_OMIT_UTF16',
|
||||
'SQLITE_OMIT_COMPLETE',
|
||||
'SQLITE_OMIT_GET_TABLE',
|
||||
'SQLITE_OMIT_AUTHORIZATION',
|
||||
'SQLITE_OMIT_LOAD_EXTENSION',
|
||||
'SQLITE_OMIT_INTROSPECTION_PRAGMAS',
|
||||
'SQLITE_OMIT_TRACE',
|
||||
'SQLITE_TRACE_SIZE_LIMIT=32',
|
||||
'SQLITE_DEFAULT_CACHE_SIZE=-16000',
|
||||
'SQLITE_DEFAULT_FOREIGN_KEYS=1',
|
||||
'SQLITE_DEFAULT_WAL_SYNCHRONOUS=1',
|
||||
'SQLITE_DEFAULT_MEMSTATUS=0',
|
||||
'SQLITE_LIKE_DOESNT_MATCH_BLOBS',
|
||||
'SQLITE_MAX_EXPR_DEPTH=0',
|
||||
'SQLITE_DQS=0',
|
||||
'SQLITE_ENABLE_MATH_FUNCTIONS',
|
||||
'SQLITE_ENABLE_DESERIALIZE',
|
||||
'SQLITE_ENABLE_COLUMN_METADATA',
|
||||
'SQLITE_ENABLE_UPDATE_DELETE_LIMIT',
|
||||
'SQLITE_ENABLE_STAT4',
|
||||
'SQLITE_ENABLE_FTS5',
|
||||
'SQLITE_ENABLE_JSON1',
|
||||
'SQLITE_INTROSPECTION_PRAGMAS',
|
||||
|
||||
'SQLCIPHER_CRYPTO_CUSTOM=signal_crypto_provider_setup',
|
||||
|
||||
@ -101,13 +98,6 @@
|
||||
},
|
||||
}],
|
||||
|
||||
# LTO on Linux
|
||||
['OS == "linux"', {
|
||||
# GCC only for now
|
||||
'cflags': ['-flto=4', '-fuse-linker-plugin', '-ffat-lto-objects'],
|
||||
'ldflags': ['-flto=4', '-fuse-linker-plugin', '-ffat-lto-objects'],
|
||||
}],
|
||||
|
||||
# Profiling
|
||||
["\"-profiling.\" in \"<!(node -p \"require('../../package.json').version\")\"", {
|
||||
'defines': [
|
||||
|
||||
5128
deps/sqlcipher/sqlite3.c
vendored
5128
deps/sqlcipher/sqlite3.c
vendored
File diff suppressed because it is too large
Load Diff
316
deps/sqlcipher/sqlite3.h
vendored
316
deps/sqlcipher/sqlite3.h
vendored
@ -133,7 +133,7 @@ extern "C" {
|
||||
**
|
||||
** Since [version 3.6.18] ([dateof:3.6.18]),
|
||||
** SQLite source code has been stored in the
|
||||
** <a href="http://fossil-scm.org/">Fossil configuration management
|
||||
** <a href="http://www.fossil-scm.org/">Fossil configuration management
|
||||
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
|
||||
** a string which identifies a particular check-in of SQLite
|
||||
** within its configuration management system. ^The SQLITE_SOURCE_ID
|
||||
@ -146,9 +146,9 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.50.4"
|
||||
#define SQLITE_VERSION_NUMBER 3050004
|
||||
#define SQLITE_SOURCE_ID "2025-07-30 19:33:53 4d8adfb30e03f9cf27f800a2c1ba3c48fb4ca1b08b0f5ed59a4d5ecbf45ealt1"
|
||||
#define SQLITE_VERSION "3.49.1"
|
||||
#define SQLITE_VERSION_NUMBER 3049001
|
||||
#define SQLITE_SOURCE_ID "2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f1alt1"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@ -1163,12 +1163,6 @@ struct sqlite3_io_methods {
|
||||
** the value that M is to be set to. Before returning, the 32-bit signed
|
||||
** integer is overwritten with the previous value of M.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_BLOCK_ON_CONNECT]]
|
||||
** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the
|
||||
** VFS to block when taking a SHARED lock to connect to a wal mode database.
|
||||
** This is used to implement the functionality associated with
|
||||
** SQLITE_SETLK_BLOCK_ON_CONNECT.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
|
||||
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
|
||||
** a database file. The argument is a pointer to a 32-bit unsigned integer.
|
||||
@ -1265,7 +1259,6 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_CKSM_FILE 41
|
||||
#define SQLITE_FCNTL_RESET_CACHE 42
|
||||
#define SQLITE_FCNTL_NULL_IO 43
|
||||
#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
@ -1996,16 +1989,13 @@ struct sqlite3_mem_methods {
|
||||
**
|
||||
** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
|
||||
** <dd> ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine
|
||||
** the default size of [lookaside memory] on each [database connection].
|
||||
** the default size of lookaside memory on each [database connection].
|
||||
** The first argument is the
|
||||
** size of each lookaside buffer slot ("sz") and the second is the number of
|
||||
** slots allocated to each database connection ("cnt").)^
|
||||
** ^(SQLITE_CONFIG_LOOKASIDE sets the <i>default</i> lookaside size.
|
||||
** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can
|
||||
** be used to change the lookaside configuration on individual connections.)^
|
||||
** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the
|
||||
** default lookaside configuration at compile-time.
|
||||
** </dd>
|
||||
** size of each lookaside buffer slot and the second is the number of
|
||||
** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE
|
||||
** sets the <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
|
||||
** option to [sqlite3_db_config()] can be used to change the lookaside
|
||||
** configuration on individual connections.)^ </dd>
|
||||
**
|
||||
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
|
||||
** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
|
||||
@ -2242,50 +2232,31 @@ struct sqlite3_mem_methods {
|
||||
** [[SQLITE_DBCONFIG_LOOKASIDE]]
|
||||
** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
|
||||
** <dd> The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the
|
||||
** configuration of the [lookaside memory allocator] within a database
|
||||
** configuration of the lookaside memory allocator within a database
|
||||
** connection.
|
||||
** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are <i>not</i>
|
||||
** in the [DBCONFIG arguments|usual format].
|
||||
** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two,
|
||||
** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE
|
||||
** should have a total of five parameters.
|
||||
** <ol>
|
||||
** <li><p>The first argument ("buf") is a
|
||||
** ^The first argument (the third parameter to [sqlite3_db_config()] is a
|
||||
** pointer to a memory buffer to use for lookaside memory.
|
||||
** The first argument may be NULL in which case SQLite will allocate the
|
||||
** lookaside buffer itself using [sqlite3_malloc()].
|
||||
** <li><P>The second argument ("sz") is the
|
||||
** size of each lookaside buffer slot. Lookaside is disabled if "sz"
|
||||
** is less than 8. The "sz" argument should be a multiple of 8 less than
|
||||
** 65536. If "sz" does not meet this constraint, it is reduced in size until
|
||||
** it does.
|
||||
** <li><p>The third argument ("cnt") is the number of slots. Lookaside is disabled
|
||||
** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so
|
||||
** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt"
|
||||
** parameter is usually chosen so that the product of "sz" and "cnt" is less
|
||||
** than 1,000,000.
|
||||
** </ol>
|
||||
** <p>If the "buf" argument is not NULL, then it must
|
||||
** point to a memory buffer with a size that is greater than
|
||||
** or equal to the product of "sz" and "cnt".
|
||||
** The buffer must be aligned to an 8-byte boundary.
|
||||
** The lookaside memory
|
||||
** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb
|
||||
** may be NULL in which case SQLite will allocate the
|
||||
** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the
|
||||
** size of each lookaside buffer slot. ^The third argument is the number of
|
||||
** slots. The size of the buffer in the first argument must be greater than
|
||||
** or equal to the product of the second and third arguments. The buffer
|
||||
** must be aligned to an 8-byte boundary. ^If the second argument to
|
||||
** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally
|
||||
** rounded down to the next smaller multiple of 8. ^(The lookaside memory
|
||||
** configuration for a database connection can only be changed when that
|
||||
** connection is not currently using lookaside memory, or in other words
|
||||
** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero.
|
||||
** when the "current value" returned by
|
||||
** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
|
||||
** Any attempt to change the lookaside memory configuration when lookaside
|
||||
** memory is in use leaves the configuration unchanged and returns
|
||||
** [SQLITE_BUSY].
|
||||
** If the "buf" argument is NULL and an attempt
|
||||
** to allocate memory based on "sz" and "cnt" fails, then
|
||||
** lookaside is silently disabled.
|
||||
** <p>
|
||||
** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the
|
||||
** default lookaside configuration at initialization. The
|
||||
** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside
|
||||
** configuration at compile-time. Typical values for lookaside are 1200 for
|
||||
** "sz" and 40 to 100 for "cnt".
|
||||
** </dd>
|
||||
** [SQLITE_BUSY].)^</dd>
|
||||
**
|
||||
** [[SQLITE_DBCONFIG_ENABLE_FKEY]]
|
||||
** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt>
|
||||
@ -3022,44 +2993,6 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
|
||||
*/
|
||||
SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Set the Setlk Timeout
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If
|
||||
** the VFS supports blocking locks, it sets the timeout in ms used by
|
||||
** eligible locks taken on wal mode databases by the specified database
|
||||
** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does
|
||||
** not support blocking locks, this function is a no-op.
|
||||
**
|
||||
** Passing 0 to this function disables blocking locks altogether. Passing
|
||||
** -1 to this function requests that the VFS blocks for a long time -
|
||||
** indefinitely if possible. The results of passing any other negative value
|
||||
** are undefined.
|
||||
**
|
||||
** Internally, each SQLite database handle store two timeout values - the
|
||||
** busy-timeout (used for rollback mode databases, or if the VFS does not
|
||||
** support blocking locks) and the setlk-timeout (used for blocking locks
|
||||
** on wal-mode databases). The sqlite3_busy_timeout() method sets both
|
||||
** values, this function sets only the setlk-timeout value. Therefore,
|
||||
** to configure separate busy-timeout and setlk-timeout values for a single
|
||||
** database handle, call sqlite3_busy_timeout() followed by this function.
|
||||
**
|
||||
** Whenever the number of connections to a wal mode database falls from
|
||||
** 1 to 0, the last connection takes an exclusive lock on the database,
|
||||
** then checkpoints and deletes the wal file. While it is doing this, any
|
||||
** new connection that tries to read from the database fails with an
|
||||
** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is
|
||||
** passed to this API, the new connection blocks until the exclusive lock
|
||||
** has been released.
|
||||
*/
|
||||
SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Flags for sqlite3_setlk_timeout()
|
||||
*/
|
||||
#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01
|
||||
|
||||
/*
|
||||
** CAPI3REF: Convenience Routines For Running Queries
|
||||
** METHOD: sqlite3
|
||||
@ -4079,7 +4012,7 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
|
||||
**
|
||||
** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
|
||||
** database filename D with corresponding journal file J and WAL file W and
|
||||
** an array P of N URI Key/Value pairs. The result from
|
||||
** with N URI parameters key/values pairs in the array P. The result from
|
||||
** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that
|
||||
** is safe to pass to routines like:
|
||||
** <ul>
|
||||
@ -4760,7 +4693,7 @@ typedef struct sqlite3_context sqlite3_context;
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants,
|
||||
** literals may be replaced by a [parameter] that matches one of the following
|
||||
** literals may be replaced by a [parameter] that matches one of following
|
||||
** templates:
|
||||
**
|
||||
** <ul>
|
||||
@ -4805,7 +4738,7 @@ typedef struct sqlite3_context sqlite3_context;
|
||||
**
|
||||
** [[byte-order determination rules]] ^The byte-order of
|
||||
** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF)
|
||||
** found in the first character, which is removed, or in the absence of a BOM
|
||||
** found in first character, which is removed, or in the absence of a BOM
|
||||
** the byte order is the native byte order of the host
|
||||
** machine for sqlite3_bind_text16() or the byte order specified in
|
||||
** the 6th parameter for sqlite3_bind_text64().)^
|
||||
@ -4825,7 +4758,7 @@ typedef struct sqlite3_context sqlite3_context;
|
||||
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
|
||||
** that parameter must be the byte offset
|
||||
** where the NUL terminator would occur assuming the string were NUL
|
||||
** terminated. If any NUL characters occur at byte offsets less than
|
||||
** terminated. If any NUL characters occurs at byte offsets less than
|
||||
** the value of the fourth parameter then the resulting string value will
|
||||
** contain embedded NULs. The result of expressions involving strings
|
||||
** with embedded NULs is undefined.
|
||||
@ -5037,7 +4970,7 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^These routines provide a means to determine the database, table, and
|
||||
** table column that is the origin of a particular result column in a
|
||||
** table column that is the origin of a particular result column in
|
||||
** [SELECT] statement.
|
||||
** ^The name of the database or table or column can be returned as
|
||||
** either a UTF-8 or UTF-16 string. ^The _database_ routines return
|
||||
@ -5175,7 +5108,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
|
||||
** other than [SQLITE_ROW] before any subsequent invocation of
|
||||
** sqlite3_step(). Failure to reset the prepared statement using
|
||||
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
|
||||
** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1]),
|
||||
** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1],
|
||||
** sqlite3_step() began
|
||||
** calling [sqlite3_reset()] automatically in this circumstance rather
|
||||
** than returning [SQLITE_MISUSE]. This is not considered a compatibility
|
||||
@ -5606,8 +5539,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
**
|
||||
** For best security, the [SQLITE_DIRECTONLY] flag is recommended for
|
||||
** all application-defined SQL functions that do not need to be
|
||||
** used inside of triggers, views, CHECK constraints, or other elements of
|
||||
** the database schema. This flag is especially recommended for SQL
|
||||
** used inside of triggers, view, CHECK constraints, or other elements of
|
||||
** the database schema. This flags is especially recommended for SQL
|
||||
** functions that have side effects or reveal internal application state.
|
||||
** Without this flag, an attacker might be able to modify the schema of
|
||||
** a database file to include invocations of the function with parameters
|
||||
@ -5638,7 +5571,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
** [user-defined window functions|available here].
|
||||
**
|
||||
** ^(If the final parameter to sqlite3_create_function_v2() or
|
||||
** sqlite3_create_window_function() is not NULL, then it is the destructor for
|
||||
** sqlite3_create_window_function() is not NULL, then it is destructor for
|
||||
** the application data pointer. The destructor is invoked when the function
|
||||
** is deleted, either by being overloaded or when the database connection
|
||||
** closes.)^ ^The destructor is also invoked if the call to
|
||||
@ -6038,7 +5971,7 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
|
||||
** METHOD: sqlite3_value
|
||||
**
|
||||
** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value]
|
||||
** object V and returns a pointer to that copy. ^The [sqlite3_value] returned
|
||||
** object D and returns a pointer to that copy. ^The [sqlite3_value] returned
|
||||
** is a [protected sqlite3_value] object even if the input is not.
|
||||
** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a
|
||||
** memory allocation fails. ^If V is a [pointer value], then the result
|
||||
@ -6076,7 +6009,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
|
||||
** allocation error occurs.
|
||||
**
|
||||
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
|
||||
** determined by the N parameter on the first successful call. Changing the
|
||||
** determined by the N parameter on first successful call. Changing the
|
||||
** value of N in any subsequent call to sqlite3_aggregate_context() within
|
||||
** the same aggregate function instance will not resize the memory
|
||||
** allocation.)^ Within the xFinal callback, it is customary to set
|
||||
@ -6238,7 +6171,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi
|
||||
**
|
||||
** Security Warning: These interfaces should not be exposed in scripting
|
||||
** languages or in other circumstances where it might be possible for an
|
||||
** attacker to invoke them. Any agent that can invoke these interfaces
|
||||
** an attacker to invoke them. Any agent that can invoke these interfaces
|
||||
** can probably also take control of the process.
|
||||
**
|
||||
** Database connection client data is only available for SQLite
|
||||
@ -6352,7 +6285,7 @@ typedef void (*sqlite3_destructor_type)(void*);
|
||||
** pointed to by the 2nd parameter are taken as the application-defined
|
||||
** function result. If the 3rd parameter is non-negative, then it
|
||||
** must be the byte offset into the string where the NUL terminator would
|
||||
** appear if the string were NUL terminated. If any NUL characters occur
|
||||
** appear if the string where NUL terminated. If any NUL characters occur
|
||||
** in the string at a byte offset that is less than the value of the 3rd
|
||||
** parameter, then the resulting string will contain embedded NULs and the
|
||||
** result of expressions operating on strings with embedded NULs is undefined.
|
||||
@ -6410,7 +6343,7 @@ typedef void (*sqlite3_destructor_type)(void*);
|
||||
** string and preferably a string literal. The sqlite3_result_pointer()
|
||||
** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
|
||||
**
|
||||
** If these routines are called from within a different thread
|
||||
** If these routines are called from within the different thread
|
||||
** than the one containing the application-defined function that received
|
||||
** the [sqlite3_context] pointer, the results are undefined.
|
||||
*/
|
||||
@ -6876,7 +6809,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name
|
||||
** for the N-th database on database connection D, or a NULL pointer if N is
|
||||
** for the N-th database on database connection D, or a NULL pointer of N is
|
||||
** out of range. An N value of 0 means the main database file. An N of 1 is
|
||||
** the "temp" schema. Larger values of N correspond to various ATTACH-ed
|
||||
** databases.
|
||||
@ -6971,7 +6904,7 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
|
||||
** <dd>The SQLITE_TXN_READ state means that the database is currently
|
||||
** in a read transaction. Content has been read from the database file
|
||||
** but nothing in the database file has changed. The transaction state
|
||||
** will be advanced to SQLITE_TXN_WRITE if any changes occur and there are
|
||||
** will advanced to SQLITE_TXN_WRITE if any changes occur and there are
|
||||
** no other conflicting concurrent write transactions. The transaction
|
||||
** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or
|
||||
** [COMMIT].</dd>
|
||||
@ -6980,7 +6913,7 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
|
||||
** <dd>The SQLITE_TXN_WRITE state means that the database is currently
|
||||
** in a write transaction. Content has been written to the database file
|
||||
** but has not yet committed. The transaction state will change to
|
||||
** SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
|
||||
** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
|
||||
*/
|
||||
#define SQLITE_TXN_NONE 0
|
||||
#define SQLITE_TXN_READ 1
|
||||
@ -7131,8 +7064,6 @@ SQLITE_API int sqlite3_autovacuum_pages(
|
||||
**
|
||||
** ^The second argument is a pointer to the function to invoke when a
|
||||
** row is updated, inserted or deleted in a rowid table.
|
||||
** ^The update hook is disabled by invoking sqlite3_update_hook()
|
||||
** with a NULL pointer as the second parameter.
|
||||
** ^The first argument to the callback is a copy of the third argument
|
||||
** to sqlite3_update_hook().
|
||||
** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE],
|
||||
@ -7261,7 +7192,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
|
||||
** CAPI3REF: Impose A Limit On Heap Size
|
||||
**
|
||||
** These interfaces impose limits on the amount of heap memory that will be
|
||||
** used by all database connections within a single process.
|
||||
** by all database connections within a single process.
|
||||
**
|
||||
** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
|
||||
** soft limit on the amount of heap memory that may be allocated by SQLite.
|
||||
@ -7319,7 +7250,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
|
||||
** </ul>)^
|
||||
**
|
||||
** The circumstances under which SQLite will enforce the heap limits may
|
||||
** change in future releases of SQLite.
|
||||
** changes in future releases of SQLite.
|
||||
*/
|
||||
SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
|
||||
SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N);
|
||||
@ -7434,8 +7365,8 @@ SQLITE_API int sqlite3_table_column_metadata(
|
||||
** ^The entry point is zProc.
|
||||
** ^(zProc may be 0, in which case SQLite will try to come up with an
|
||||
** entry point name on its own. It first tries "sqlite3_extension_init".
|
||||
** If that does not work, it constructs a name "sqlite3_X_init" where
|
||||
** X consists of the lower-case equivalent of all ASCII alphabetic
|
||||
** If that does not work, it constructs a name "sqlite3_X_init" where the
|
||||
** X is consists of the lower-case equivalent of all ASCII alphabetic
|
||||
** characters in the filename from the last "/" to the first following
|
||||
** "." and omitting any initial "lib".)^
|
||||
** ^The sqlite3_load_extension() interface returns
|
||||
@ -7506,7 +7437,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
|
||||
** ^(Even though the function prototype shows that xEntryPoint() takes
|
||||
** no arguments and returns void, SQLite invokes xEntryPoint() with three
|
||||
** arguments and expects an integer result as if the signature of the
|
||||
** entry point were as follows:
|
||||
** entry point where as follows:
|
||||
**
|
||||
** <blockquote><pre>
|
||||
** int xEntryPoint(
|
||||
@ -7670,7 +7601,7 @@ struct sqlite3_module {
|
||||
** virtual table and might not be checked again by the byte code.)^ ^(The
|
||||
** aConstraintUsage[].omit flag is an optimization hint. When the omit flag
|
||||
** is left in its default setting of false, the constraint will always be
|
||||
** checked separately in byte code. If the omit flag is changed to true, then
|
||||
** checked separately in byte code. If the omit flag is change to true, then
|
||||
** the constraint may or may not be checked in byte code. In other words,
|
||||
** when the omit flag is true there is no guarantee that the constraint will
|
||||
** not be checked again using byte code.)^
|
||||
@ -7696,7 +7627,7 @@ struct sqlite3_module {
|
||||
** The xBestIndex method may optionally populate the idxFlags field with a
|
||||
** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
|
||||
** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
|
||||
** output to show the idxNum as hex instead of as decimal. Another flag is
|
||||
** output to show the idxNum has hex instead of as decimal. Another flag is
|
||||
** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
|
||||
** return at most one row.
|
||||
**
|
||||
@ -7837,7 +7768,7 @@ struct sqlite3_index_info {
|
||||
** the implementation of the [virtual table module]. ^The fourth
|
||||
** parameter is an arbitrary client data pointer that is passed through
|
||||
** into the [xCreate] and [xConnect] methods of the virtual table module
|
||||
** when a new virtual table is being created or reinitialized.
|
||||
** when a new virtual table is be being created or reinitialized.
|
||||
**
|
||||
** ^The sqlite3_create_module_v2() interface has a fifth parameter which
|
||||
** is a pointer to a destructor for the pClientData. ^SQLite will
|
||||
@ -8002,7 +7933,7 @@ typedef struct sqlite3_blob sqlite3_blob;
|
||||
** in *ppBlob. Otherwise an [error code] is returned and, unless the error
|
||||
** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
|
||||
** the API is not misused, it is always safe to call [sqlite3_blob_close()]
|
||||
** on *ppBlob after this function returns.
|
||||
** on *ppBlob after this function it returns.
|
||||
**
|
||||
** This function fails with SQLITE_ERROR if any of the following are true:
|
||||
** <ul>
|
||||
@ -8122,7 +8053,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
|
||||
**
|
||||
** ^Returns the size in bytes of the BLOB accessible via the
|
||||
** successfully opened [BLOB handle] in its only argument. ^The
|
||||
** incremental blob I/O routines can only read or overwrite existing
|
||||
** incremental blob I/O routines can only read or overwriting existing
|
||||
** blob content; they cannot change the size of a blob.
|
||||
**
|
||||
** This routine only works on a [BLOB handle] which has been created
|
||||
@ -8272,7 +8203,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
** ^The sqlite3_mutex_alloc() routine allocates a new
|
||||
** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
|
||||
** routine returns NULL if it is unable to allocate the requested
|
||||
** mutex. The argument to sqlite3_mutex_alloc() must be one of these
|
||||
** mutex. The argument to sqlite3_mutex_alloc() must one of these
|
||||
** integer constants:
|
||||
**
|
||||
** <ul>
|
||||
@ -8505,7 +8436,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
|
||||
** CAPI3REF: Retrieve the mutex for a database connection
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This interface returns a pointer to the [sqlite3_mutex] object that
|
||||
** ^This interface returns a pointer the [sqlite3_mutex] object that
|
||||
** serializes access to the [database connection] given in the argument
|
||||
** when the [threading mode] is Serialized.
|
||||
** ^If the [threading mode] is Single-thread or Multi-thread then this
|
||||
@ -8628,7 +8559,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
||||
** CAPI3REF: SQL Keyword Checking
|
||||
**
|
||||
** These routines provide access to the set of SQL language keywords
|
||||
** recognized by SQLite. Applications can use these routines to determine
|
||||
** recognized by SQLite. Applications can uses these routines to determine
|
||||
** whether or not a specific identifier needs to be escaped (for example,
|
||||
** by enclosing in double-quotes) so as not to confuse the parser.
|
||||
**
|
||||
@ -8796,7 +8727,7 @@ SQLITE_API void sqlite3_str_reset(sqlite3_str*);
|
||||
** content of the dynamic string under construction in X. The value
|
||||
** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X
|
||||
** and might be freed or altered by any subsequent method on the same
|
||||
** [sqlite3_str] object. Applications must not use the pointer returned by
|
||||
** [sqlite3_str] object. Applications must not used the pointer returned
|
||||
** [sqlite3_str_value(X)] after any subsequent method call on the same
|
||||
** object. ^Applications may change the content of the string returned
|
||||
** by [sqlite3_str_value(X)] as long as they do not write into any bytes
|
||||
@ -8882,7 +8813,7 @@ SQLITE_API int sqlite3_status64(
|
||||
** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
|
||||
** buffer and where forced to overflow to [sqlite3_malloc()]. The
|
||||
** returned value includes allocations that overflowed because they
|
||||
** were too large (they were larger than the "sz" parameter to
|
||||
** where too large (they were larger than the "sz" parameter to
|
||||
** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
|
||||
** no space was left in the page cache.</dd>)^
|
||||
**
|
||||
@ -8966,29 +8897,28 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
||||
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
|
||||
** <dd>This parameter returns the number of malloc attempts that were
|
||||
** satisfied using lookaside memory. Only the high-water value is meaningful;
|
||||
** the current value is always zero.</dd>)^
|
||||
** the current value is always zero.)^
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
|
||||
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
|
||||
** <dd>This parameter returns the number of malloc attempts that might have
|
||||
** <dd>This parameter returns the number malloc attempts that might have
|
||||
** been satisfied using lookaside memory but failed due to the amount of
|
||||
** memory requested being larger than the lookaside slot size.
|
||||
** Only the high-water value is meaningful;
|
||||
** the current value is always zero.</dd>)^
|
||||
** the current value is always zero.)^
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]]
|
||||
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
|
||||
** <dd>This parameter returns the number of malloc attempts that might have
|
||||
** <dd>This parameter returns the number malloc attempts that might have
|
||||
** been satisfied using lookaside memory but failed due to all lookaside
|
||||
** memory already being in use.
|
||||
** Only the high-water value is meaningful;
|
||||
** the current value is always zero.</dd>)^
|
||||
** the current value is always zero.)^
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of bytes of heap
|
||||
** memory used by all pager caches associated with the database connection.)^
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
||||
** </dd>
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
|
||||
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
|
||||
@ -8997,10 +8927,10 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
||||
** memory used by that pager cache is divided evenly between the attached
|
||||
** connections.)^ In other words, if none of the pager caches associated
|
||||
** with the database connection are shared, this request returns the same
|
||||
** value as DBSTATUS_CACHE_USED. Or, if one or more of the pager caches are
|
||||
** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
|
||||
** shared, the value returned by this call will be smaller than that returned
|
||||
** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
|
||||
** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.</dd>
|
||||
** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of bytes of heap
|
||||
@ -9010,7 +8940,6 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
||||
** schema memory is shared with other database connections due to
|
||||
** [shared cache mode] being enabled.
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
|
||||
** </dd>
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of bytes of heap
|
||||
@ -9047,7 +8976,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
||||
** been written to disk in the middle of a transaction due to the page
|
||||
** cache overflowing. Transactions are more efficient if they are written
|
||||
** to disk all at once. When pages spill mid-transaction, that introduces
|
||||
** additional overhead. This parameter can be used to help identify
|
||||
** additional overhead. This parameter can be used help identify
|
||||
** inefficiencies that can be resolved by increasing the cache size.
|
||||
** </dd>
|
||||
**
|
||||
@ -9118,13 +9047,13 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
||||
** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt>
|
||||
** <dd>^This is the number of sort operations that have occurred.
|
||||
** A non-zero value in this counter may indicate an opportunity to
|
||||
** improve performance through careful use of indices.</dd>
|
||||
** improvement performance through careful use of indices.</dd>
|
||||
**
|
||||
** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
|
||||
** <dd>^This is the number of rows inserted into transient indices that
|
||||
** were created automatically in order to help joins run faster.
|
||||
** A non-zero value in this counter may indicate an opportunity to
|
||||
** improve performance by adding permanent indices that do not
|
||||
** improvement performance by adding permanent indices that do not
|
||||
** need to be reinitialized each time the statement is run.</dd>
|
||||
**
|
||||
** [[SQLITE_STMTSTATUS_VM_STEP]] <dt>SQLITE_STMTSTATUS_VM_STEP</dt>
|
||||
@ -9133,19 +9062,19 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
||||
** to 2147483647. The number of virtual machine operations can be
|
||||
** used as a proxy for the total work done by the prepared statement.
|
||||
** If the number of virtual machine operations exceeds 2147483647
|
||||
** then the value returned by this statement status code is undefined.</dd>
|
||||
** then the value returned by this statement status code is undefined.
|
||||
**
|
||||
** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
|
||||
** <dd>^This is the number of times that the prepare statement has been
|
||||
** automatically regenerated due to schema changes or changes to
|
||||
** [bound parameters] that might affect the query plan.</dd>
|
||||
** [bound parameters] that might affect the query plan.
|
||||
**
|
||||
** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
|
||||
** <dd>^This is the number of times that the prepared statement has
|
||||
** been run. A single "run" for the purposes of this counter is one
|
||||
** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
|
||||
** The counter is incremented on the first [sqlite3_step()] call of each
|
||||
** cycle.</dd>
|
||||
** cycle.
|
||||
**
|
||||
** [[SQLITE_STMTSTATUS_FILTER_MISS]]
|
||||
** [[SQLITE_STMTSTATUS_FILTER HIT]]
|
||||
@ -9155,7 +9084,7 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
||||
** step was bypassed because a Bloom filter returned not-found. The
|
||||
** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of
|
||||
** times that the Bloom filter returned a find, and thus the join step
|
||||
** had to be processed as normal.</dd>
|
||||
** had to be processed as normal.
|
||||
**
|
||||
** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
|
||||
** <dd>^This is the approximate number of bytes of heap memory
|
||||
@ -9260,9 +9189,9 @@ struct sqlite3_pcache_page {
|
||||
** SQLite will typically create one cache instance for each open database file,
|
||||
** though this is not guaranteed. ^The
|
||||
** first parameter, szPage, is the size in bytes of the pages that must
|
||||
** be allocated by the cache. ^szPage will always be a power of two. ^The
|
||||
** be allocated by the cache. ^szPage will always a power of two. ^The
|
||||
** second parameter szExtra is a number of bytes of extra storage
|
||||
** associated with each page cache entry. ^The szExtra parameter will be
|
||||
** associated with each page cache entry. ^The szExtra parameter will
|
||||
** a number less than 250. SQLite will use the
|
||||
** extra szExtra bytes on each page to store metadata about the underlying
|
||||
** database page on disk. The value passed into szExtra depends
|
||||
@ -9270,17 +9199,17 @@ struct sqlite3_pcache_page {
|
||||
** ^The third argument to xCreate(), bPurgeable, is true if the cache being
|
||||
** created will be used to cache database pages of a file stored on disk, or
|
||||
** false if it is used for an in-memory database. The cache implementation
|
||||
** does not have to do anything special based upon the value of bPurgeable;
|
||||
** does not have to do anything special based with the value of bPurgeable;
|
||||
** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will
|
||||
** never invoke xUnpin() except to deliberately delete a page.
|
||||
** ^In other words, calls to xUnpin() on a cache with bPurgeable set to
|
||||
** false will always have the "discard" flag set to true.
|
||||
** ^Hence, a cache created with bPurgeable set to false will
|
||||
** ^Hence, a cache created with bPurgeable false will
|
||||
** never contain any unpinned pages.
|
||||
**
|
||||
** [[the xCachesize() page cache method]]
|
||||
** ^(The xCachesize() method may be called at any time by SQLite to set the
|
||||
** suggested maximum cache-size (number of pages stored) for the cache
|
||||
** suggested maximum cache-size (number of pages stored by) the cache
|
||||
** instance passed as the first argument. This is the value configured using
|
||||
** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable
|
||||
** parameter, the implementation is not required to do anything with this
|
||||
@ -9307,12 +9236,12 @@ struct sqlite3_pcache_page {
|
||||
** implementation must return a pointer to the page buffer with its content
|
||||
** intact. If the requested page is not already in the cache, then the
|
||||
** cache implementation should use the value of the createFlag
|
||||
** parameter to help it determine what action to take:
|
||||
** parameter to help it determined what action to take:
|
||||
**
|
||||
** <table border=1 width=85% align=center>
|
||||
** <tr><th> createFlag <th> Behavior when page is not already in cache
|
||||
** <tr><td> 0 <td> Do not allocate a new page. Return NULL.
|
||||
** <tr><td> 1 <td> Allocate a new page if it is easy and convenient to do so.
|
||||
** <tr><td> 1 <td> Allocate a new page if it easy and convenient to do so.
|
||||
** Otherwise return NULL.
|
||||
** <tr><td> 2 <td> Make every effort to allocate a new page. Only return
|
||||
** NULL if allocating a new page is effectively impossible.
|
||||
@ -9329,7 +9258,7 @@ struct sqlite3_pcache_page {
|
||||
** as its second argument. If the third parameter, discard, is non-zero,
|
||||
** then the page must be evicted from the cache.
|
||||
** ^If the discard parameter is
|
||||
** zero, then the page may be discarded or retained at the discretion of the
|
||||
** zero, then the page may be discarded or retained at the discretion of
|
||||
** page cache implementation. ^The page cache implementation
|
||||
** may choose to evict unpinned pages at any time.
|
||||
**
|
||||
@ -9347,7 +9276,7 @@ struct sqlite3_pcache_page {
|
||||
** When SQLite calls the xTruncate() method, the cache must discard all
|
||||
** existing cache entries with page numbers (keys) greater than or equal
|
||||
** to the value of the iLimit parameter passed to xTruncate(). If any
|
||||
** of these pages are pinned, they become implicitly unpinned, meaning that
|
||||
** of these pages are pinned, they are implicitly unpinned, meaning that
|
||||
** they can be safely discarded.
|
||||
**
|
||||
** [[the xDestroy() page cache method]]
|
||||
@ -9527,7 +9456,7 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
** external process or via a database connection other than the one being
|
||||
** used by the backup operation, then the backup will be automatically
|
||||
** restarted by the next call to sqlite3_backup_step(). ^If the source
|
||||
** database is modified by using the same database connection as is used
|
||||
** database is modified by the using the same database connection as is used
|
||||
** by the backup operation, then the backup database is automatically
|
||||
** updated at the same time.
|
||||
**
|
||||
@ -9544,7 +9473,7 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
** and may not be used following a call to sqlite3_backup_finish().
|
||||
**
|
||||
** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no
|
||||
** sqlite3_backup_step() errors occurred, regardless of whether or not
|
||||
** sqlite3_backup_step() errors occurred, regardless or whether or not
|
||||
** sqlite3_backup_step() completed.
|
||||
** ^If an out-of-memory condition or IO error occurred during any prior
|
||||
** sqlite3_backup_step() call on the same [sqlite3_backup] object, then
|
||||
@ -9646,7 +9575,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
||||
** application receives an SQLITE_LOCKED error, it may call the
|
||||
** sqlite3_unlock_notify() method with the blocked connection handle as
|
||||
** the first argument to register for a callback that will be invoked
|
||||
** when the blocking connection's current transaction is concluded. ^The
|
||||
** when the blocking connections current transaction is concluded. ^The
|
||||
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
|
||||
** call that concludes the blocking connection's transaction.
|
||||
**
|
||||
@ -9666,7 +9595,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
||||
** blocked connection already has a registered unlock-notify callback,
|
||||
** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is
|
||||
** called with a NULL pointer as its second argument, then any existing
|
||||
** unlock-notify callback is canceled. ^The blocked connection's
|
||||
** unlock-notify callback is canceled. ^The blocked connections
|
||||
** unlock-notify callback may also be canceled by closing the blocked
|
||||
** connection using [sqlite3_close()].
|
||||
**
|
||||
@ -10064,7 +9993,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
|
||||
** support constraints. In this configuration (which is the default) if
|
||||
** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire
|
||||
** statement is rolled back as if [ON CONFLICT | OR ABORT] had been
|
||||
** specified as part of the user's SQL statement, regardless of the actual
|
||||
** specified as part of the users SQL statement, regardless of the actual
|
||||
** ON CONFLICT mode specified.
|
||||
**
|
||||
** If X is non-zero, then the virtual table implementation guarantees
|
||||
@ -10098,7 +10027,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
|
||||
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
|
||||
** <dd>Calls of the form
|
||||
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
|
||||
** [xConnect] or [xCreate] methods of a [virtual table] implementation
|
||||
** the [xConnect] or [xCreate] methods of a [virtual table] implementation
|
||||
** identify that virtual table as being safe to use from within triggers
|
||||
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
|
||||
** virtual table can do no serious harm even if it is controlled by a
|
||||
@ -10266,7 +10195,7 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
||||
** </table>
|
||||
**
|
||||
** ^For the purposes of comparing virtual table output values to see if the
|
||||
** values are the same value for sorting purposes, two NULL values are considered
|
||||
** values are same value for sorting purposes, two NULL values are considered
|
||||
** to be the same. In other words, the comparison operator is "IS"
|
||||
** (or "IS NOT DISTINCT FROM") and not "==".
|
||||
**
|
||||
@ -10276,7 +10205,7 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
||||
**
|
||||
** ^A virtual table implementation is always free to return rows in any order
|
||||
** it wants, as long as the "orderByConsumed" flag is not set. ^When the
|
||||
** "orderByConsumed" flag is unset, the query planner will add extra
|
||||
** the "orderByConsumed" flag is unset, the query planner will add extra
|
||||
** [bytecode] to ensure that the final results returned by the SQL query are
|
||||
** ordered correctly. The use of the "orderByConsumed" flag and the
|
||||
** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful
|
||||
@ -10373,7 +10302,7 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
|
||||
** sqlite3_vtab_in_next(X,P) should be one of the parameters to the
|
||||
** xFilter method which invokes these routines, and specifically
|
||||
** a parameter that was previously selected for all-at-once IN constraint
|
||||
** processing using the [sqlite3_vtab_in()] interface in the
|
||||
** processing use the [sqlite3_vtab_in()] interface in the
|
||||
** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
|
||||
** an xFilter argument that was selected for all-at-once IN constraint
|
||||
** processing, then these routines return [SQLITE_ERROR].)^
|
||||
@ -10428,7 +10357,7 @@ SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut);
|
||||
** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V)
|
||||
** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th
|
||||
** constraint is not available. ^The sqlite3_vtab_rhs_value() interface
|
||||
** can return a result code other than SQLITE_OK or SQLITE_NOTFOUND if
|
||||
** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if
|
||||
** something goes wrong.
|
||||
**
|
||||
** The sqlite3_vtab_rhs_value() interface is usually only successful if
|
||||
@ -10456,8 +10385,8 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
|
||||
** KEYWORDS: {conflict resolution mode}
|
||||
**
|
||||
** These constants are returned by [sqlite3_vtab_on_conflict()] to
|
||||
** inform a [virtual table] implementation of the [ON CONFLICT] mode
|
||||
** for the SQL statement being evaluated.
|
||||
** inform a [virtual table] implementation what the [ON CONFLICT] mode
|
||||
** is for the SQL statement being evaluated.
|
||||
**
|
||||
** Note that the [SQLITE_IGNORE] constant is also used as a potential
|
||||
** return value from the [sqlite3_set_authorizer()] callback and that
|
||||
@ -10497,39 +10426,39 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
|
||||
** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
|
||||
** <dd>^The "double" variable pointed to by the V parameter will be set to the
|
||||
** query planner's estimate for the average number of rows output from each
|
||||
** iteration of the X-th loop. If the query planner's estimate was accurate,
|
||||
** iteration of the X-th loop. If the query planner's estimates was accurate,
|
||||
** then this value will approximate the quotient NVISIT/NLOOP and the
|
||||
** product of this value for all prior loops with the same SELECTID will
|
||||
** be the NLOOP value for the current loop.</dd>
|
||||
** be the NLOOP value for the current loop.
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
|
||||
** <dd>^The "const char *" variable pointed to by the V parameter will be set
|
||||
** to a zero-terminated UTF-8 string containing the name of the index or table
|
||||
** used for the X-th loop.</dd>
|
||||
** used for the X-th loop.
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
|
||||
** <dd>^The "const char *" variable pointed to by the V parameter will be set
|
||||
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
|
||||
** description for the X-th loop.</dd>
|
||||
** description for the X-th loop.
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECTID</dt>
|
||||
** <dd>^The "int" variable pointed to by the V parameter will be set to the
|
||||
** id for the X-th query plan element. The id value is unique within the
|
||||
** statement. The select-id is the same value as is output in the first
|
||||
** column of an [EXPLAIN QUERY PLAN] query.</dd>
|
||||
** column of an [EXPLAIN QUERY PLAN] query.
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_PARENTID]] <dt>SQLITE_SCANSTAT_PARENTID</dt>
|
||||
** <dd>The "int" variable pointed to by the V parameter will be set to the
|
||||
** id of the parent of the current query element, if applicable, or
|
||||
** the id of the parent of the current query element, if applicable, or
|
||||
** to zero if the query element has no parent. This is the same value as
|
||||
** returned in the second column of an [EXPLAIN QUERY PLAN] query.</dd>
|
||||
** returned in the second column of an [EXPLAIN QUERY PLAN] query.
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_NCYCLE]] <dt>SQLITE_SCANSTAT_NCYCLE</dt>
|
||||
** <dd>The sqlite3_int64 output value is set to the number of cycles,
|
||||
** according to the processor time-stamp counter, that elapsed while the
|
||||
** query element was being processed. This value is not available for
|
||||
** all query elements - if it is unavailable the output variable is
|
||||
** set to -1.</dd>
|
||||
** set to -1.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_SCANSTAT_NLOOP 0
|
||||
@ -10570,8 +10499,8 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
|
||||
** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter.
|
||||
**
|
||||
** Parameter "idx" identifies the specific query element to retrieve statistics
|
||||
** for. Query elements are numbered starting from zero. A value of -1 may
|
||||
** retrieve statistics for the entire query. ^If idx is out of range
|
||||
** for. Query elements are numbered starting from zero. A value of -1 may be
|
||||
** to query for statistics regarding the entire query. ^If idx is out of range
|
||||
** - less than -1 or greater than or equal to the total number of query
|
||||
** elements used to implement the statement - a non-zero value is returned and
|
||||
** the variable that pOut points to is unchanged.
|
||||
@ -10614,7 +10543,7 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^If a write-transaction is open on [database connection] D when the
|
||||
** [sqlite3_db_cacheflush(D)] interface is invoked, any dirty
|
||||
** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
|
||||
** pages in the pager-cache that are not currently in use are written out
|
||||
** to disk. A dirty page may be in use if a database cursor created by an
|
||||
** active SQL statement is reading from it, or if it is page 1 of a database
|
||||
@ -10728,8 +10657,8 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
|
||||
** triggers; and so forth.
|
||||
**
|
||||
** When the [sqlite3_blob_write()] API is used to update a blob column,
|
||||
** the pre-update hook is invoked with SQLITE_DELETE, because
|
||||
** the new values are not yet available. In this case, when a
|
||||
** the pre-update hook is invoked with SQLITE_DELETE. This is because the
|
||||
** in this case the new values are not available. In this case, when a
|
||||
** callback made with op==SQLITE_DELETE is actually a write using the
|
||||
** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns
|
||||
** the index of the column being written. In other cases, where the
|
||||
@ -10982,7 +10911,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
|
||||
** For an ordinary on-disk database file, the serialization is just a
|
||||
** copy of the disk file. For an in-memory database or a "TEMP" database,
|
||||
** the serialization is the same sequence of bytes which would be written
|
||||
** to disk if that database were backed up to disk.
|
||||
** to disk if that database where backed up to disk.
|
||||
**
|
||||
** The usual case is that sqlite3_serialize() copies the serialization of
|
||||
** the database into memory obtained from [sqlite3_malloc64()] and returns
|
||||
@ -10991,7 +10920,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
|
||||
** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations
|
||||
** are made, and the sqlite3_serialize() function will return a pointer
|
||||
** to the contiguous memory representation of the database that SQLite
|
||||
** is currently using for that database, or NULL if no such contiguous
|
||||
** is currently using for that database, or NULL if the no such contiguous
|
||||
** memory representation of the database exists. A contiguous memory
|
||||
** representation of the database will usually only exist if there has
|
||||
** been a prior call to [sqlite3_deserialize(D,S,...)] with the same
|
||||
@ -11062,7 +10991,7 @@ SQLITE_API unsigned char *sqlite3_serialize(
|
||||
** database is currently in a read transaction or is involved in a backup
|
||||
** operation.
|
||||
**
|
||||
** It is not possible to deserialize into the TEMP database. If the
|
||||
** It is not possible to deserialized into the TEMP database. If the
|
||||
** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
|
||||
** function returns SQLITE_ERROR.
|
||||
**
|
||||
@ -11084,7 +11013,7 @@ SQLITE_API int sqlite3_deserialize(
|
||||
sqlite3 *db, /* The database connection */
|
||||
const char *zSchema, /* Which DB to reopen with the deserialization */
|
||||
unsigned char *pData, /* The serialized database content */
|
||||
sqlite3_int64 szDb, /* Number of bytes in the deserialization */
|
||||
sqlite3_int64 szDb, /* Number bytes in the deserialization */
|
||||
sqlite3_int64 szBuf, /* Total size of buffer pData[] */
|
||||
unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */
|
||||
);
|
||||
@ -11092,7 +11021,7 @@ SQLITE_API int sqlite3_deserialize(
|
||||
/*
|
||||
** CAPI3REF: Flags for sqlite3_deserialize()
|
||||
**
|
||||
** The following are allowed values for the 6th argument (the F argument) to
|
||||
** The following are allowed values for 6th argument (the F argument) to
|
||||
** the [sqlite3_deserialize(D,S,P,N,M,F)] interface.
|
||||
**
|
||||
** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization
|
||||
@ -11617,10 +11546,9 @@ SQLITE_API void sqlite3session_table_filter(
|
||||
** is inserted while a session object is enabled, then later deleted while
|
||||
** the same session object is disabled, no INSERT record will appear in the
|
||||
** changeset, even though the delete took place while the session was disabled.
|
||||
** Or, if one field of a row is updated while a session is enabled, and
|
||||
** then another field of the same row is updated while the session is disabled,
|
||||
** the resulting changeset will contain an UPDATE change that updates both
|
||||
** fields.
|
||||
** Or, if one field of a row is updated while a session is disabled, and
|
||||
** another field of the same row is updated while the session is enabled, the
|
||||
** resulting changeset will contain an UPDATE change that updates both fields.
|
||||
*/
|
||||
SQLITE_API int sqlite3session_changeset(
|
||||
sqlite3_session *pSession, /* Session object */
|
||||
@ -11692,9 +11620,8 @@ SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession
|
||||
** database zFrom the contents of the two compatible tables would be
|
||||
** identical.
|
||||
**
|
||||
** Unless the call to this function is a no-op as described above, it is an
|
||||
** error if database zFrom does not exist or does not contain the required
|
||||
** compatible table.
|
||||
** It an error if database zFrom does not exist or does not contain the
|
||||
** required compatible table.
|
||||
**
|
||||
** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
|
||||
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
|
||||
@ -11829,7 +11756,7 @@ SQLITE_API int sqlite3changeset_start_v2(
|
||||
** The following flags may passed via the 4th parameter to
|
||||
** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]:
|
||||
**
|
||||
** <dt>SQLITE_CHANGESETSTART_INVERT <dd>
|
||||
** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
|
||||
** Invert the changeset while iterating through it. This is equivalent to
|
||||
** inverting a changeset using sqlite3changeset_invert() before applying it.
|
||||
** It is an error to specify this flag with a patchset.
|
||||
@ -12144,6 +12071,19 @@ SQLITE_API int sqlite3changeset_concat(
|
||||
void **ppOut /* OUT: Buffer containing output changeset */
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
|
||||
*/
|
||||
SQLITE_API int sqlite3changeset_upgrade(
|
||||
sqlite3 *db,
|
||||
const char *zDb,
|
||||
int nIn, const void *pIn, /* Input changeset */
|
||||
int *pnOut, void **ppOut /* OUT: Inverse of input */
|
||||
);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Changegroup Handle
|
||||
**
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
deb [snapshot=20250811T060900Z] http://archive.ubuntu.com/ubuntu/ jammy main universe
|
||||
deb [snapshot=20250811T060900Z] http://archive.ubuntu.com/ubuntu/ jammy-updates main universe
|
||||
deb [snapshot=20250811T060900Z] http://security.ubuntu.com/ubuntu jammy-security main universe
|
||||
deb [snapshot=20240829T060900Z] http://archive.ubuntu.com/ubuntu/ focal main universe
|
||||
deb [snapshot=20240829T060900Z] http://archive.ubuntu.com/ubuntu/ focal-updates main universe
|
||||
deb [snapshot=20240829T060900Z] http://security.ubuntu.com/ubuntu focal-security main universe
|
||||
144
lib/index.ts
144
lib/index.ts
@ -27,16 +27,15 @@ const addon = bindings<{
|
||||
persistent: boolean,
|
||||
pluck: boolean,
|
||||
bigint: boolean,
|
||||
paramNames: Array<string | null>,
|
||||
): NativeStatement;
|
||||
statementRun<Options extends StatementOptions>(
|
||||
stmt: NativeStatement,
|
||||
params: NativeParameters<Options> | undefined,
|
||||
params: StatementParameters<Options> | undefined,
|
||||
result: [number, number],
|
||||
): void;
|
||||
statementStep<Options extends StatementOptions>(
|
||||
stmt: NativeStatement,
|
||||
params: NativeParameters<Options> | null | undefined,
|
||||
params: StatementParameters<Options> | null | undefined,
|
||||
cache: Array<SqliteValue<Options>> | undefined,
|
||||
isGet: boolean,
|
||||
): Array<SqliteValue<Options>>;
|
||||
@ -47,16 +46,6 @@ const addon = bindings<{
|
||||
databaseInitTokenizer(db: NativeDatabase): void;
|
||||
databaseExec(db: NativeDatabase, query: string): void;
|
||||
databaseClose(db: NativeDatabase): void;
|
||||
databaseCreateFunction(
|
||||
db: NativeDatabase,
|
||||
name: string,
|
||||
fn: (...args: ReadonlyArray<unknown>) => void,
|
||||
bigint: boolean,
|
||||
): void;
|
||||
databaseSetWalHook(
|
||||
db: NativeDatabase,
|
||||
fn: (dbName: string, pageCount: number) => void,
|
||||
): void;
|
||||
|
||||
signalTokenize(value: string): Array<string>;
|
||||
|
||||
@ -96,15 +85,11 @@ export type StatementOptions = Readonly<{
|
||||
bigint?: true;
|
||||
}>;
|
||||
|
||||
export type NativeParameters<Options extends StatementOptions> = ReadonlyArray<
|
||||
SqliteValue<Options>
|
||||
>;
|
||||
|
||||
/**
|
||||
* Parameters accepted by `.run()`/`.get()`/`.all()` methods of the statement.
|
||||
*/
|
||||
export type StatementParameters<Options extends StatementOptions> =
|
||||
| NativeParameters<Options>
|
||||
| ReadonlyArray<SqliteValue<Options>>
|
||||
| Readonly<Record<string, SqliteValue<Options>>>;
|
||||
|
||||
/**
|
||||
@ -112,7 +97,7 @@ export type StatementParameters<Options extends StatementOptions> =
|
||||
*/
|
||||
export type SqliteValue<Options extends StatementOptions> =
|
||||
| string
|
||||
| Uint8Array<ArrayBuffer>
|
||||
| Uint8Array
|
||||
| number
|
||||
| null
|
||||
| (Options extends { bigint: true } ? bigint : never);
|
||||
@ -126,14 +111,6 @@ export type RowType<Options extends StatementOptions> = Options extends {
|
||||
? SqliteValue<Options>
|
||||
: Record<string, SqliteValue<Options>>;
|
||||
|
||||
export type FunctionOptions = Readonly<{
|
||||
/**
|
||||
* If `true` - all integers passed to the fucntion will be big
|
||||
* integers instead of regular (floating-point) numbers.
|
||||
*/
|
||||
bigint?: boolean;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* A compiled SQL statement class.
|
||||
*/
|
||||
@ -142,9 +119,6 @@ class Statement<Options extends StatementOptions = object> {
|
||||
|
||||
#cache: Array<SqliteValue<Options>> | undefined;
|
||||
#createRow: undefined | ((result: unknown) => RowType<Options>);
|
||||
#translateParams: (
|
||||
params: StatementParameters<Options>,
|
||||
) => NativeParameters<Options>;
|
||||
#native: NativeStatement | undefined;
|
||||
#onClose: (() => void) | undefined;
|
||||
|
||||
@ -157,47 +131,14 @@ class Statement<Options extends StatementOptions = object> {
|
||||
) {
|
||||
this.#needsTranslation = persistent === true && !pluck;
|
||||
|
||||
const paramNames = new Array<string | null>();
|
||||
|
||||
this.#native = addon.statementNew(
|
||||
db,
|
||||
query,
|
||||
persistent === true,
|
||||
pluck === true,
|
||||
bigint === true,
|
||||
paramNames,
|
||||
);
|
||||
|
||||
const isArrayParams = paramNames.every((name) => name === null);
|
||||
const isObjectParams =
|
||||
!isArrayParams && paramNames.every((name) => typeof name === 'string');
|
||||
|
||||
if (!isArrayParams && !isObjectParams) {
|
||||
throw new TypeError('Cannot mix named and anonymous params in query');
|
||||
}
|
||||
|
||||
if (isArrayParams) {
|
||||
this.#translateParams = (params) => {
|
||||
if (!Array.isArray(params)) {
|
||||
throw new TypeError('Query requires an array of anonymous params');
|
||||
}
|
||||
return params;
|
||||
};
|
||||
} else {
|
||||
this.#translateParams = runInThisContext(`
|
||||
(function translateParams(params) {
|
||||
if (Array.isArray(params)) {
|
||||
throw new TypeError('Query requires an object of named params');
|
||||
}
|
||||
return [
|
||||
${paramNames
|
||||
.map((name) => `params[${JSON.stringify(name)}]`)
|
||||
.join(',\n')}
|
||||
];
|
||||
})
|
||||
`);
|
||||
}
|
||||
|
||||
this.#onClose = onClose;
|
||||
}
|
||||
|
||||
@ -213,8 +154,8 @@ class Statement<Options extends StatementOptions = object> {
|
||||
throw new Error('Statement closed');
|
||||
}
|
||||
const result: [number, number] = [0, 0];
|
||||
const nativeParams = this.#checkParams(params);
|
||||
addon.statementRun(this.#native, nativeParams, result);
|
||||
this.#checkParams(params);
|
||||
addon.statementRun(this.#native, params, result);
|
||||
return { changes: result[0], lastInsertRowid: result[1] };
|
||||
}
|
||||
|
||||
@ -233,13 +174,8 @@ class Statement<Options extends StatementOptions = object> {
|
||||
if (this.#native === undefined) {
|
||||
throw new Error('Statement closed');
|
||||
}
|
||||
const nativeParams = this.#checkParams(params);
|
||||
const result = addon.statementStep(
|
||||
this.#native,
|
||||
nativeParams,
|
||||
this.#cache,
|
||||
true,
|
||||
);
|
||||
this.#checkParams(params);
|
||||
const result = addon.statementStep(this.#native, params, this.#cache, true);
|
||||
if (result === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
@ -266,8 +202,9 @@ class Statement<Options extends StatementOptions = object> {
|
||||
throw new Error('Statement closed');
|
||||
}
|
||||
const result = [];
|
||||
const nativeParams = this.#checkParams(params);
|
||||
let singleUseParams: typeof nativeParams | undefined | null = nativeParams;
|
||||
this.#checkParams(params);
|
||||
let singleUseParams: StatementParameters<Options> | undefined | null =
|
||||
params;
|
||||
while (true) {
|
||||
const single = addon.statementStep(
|
||||
this.#native,
|
||||
@ -345,11 +282,9 @@ class Statement<Options extends StatementOptions = object> {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
#checkParams(
|
||||
params: StatementParameters<Options> | undefined,
|
||||
): NativeParameters<Options> | undefined {
|
||||
#checkParams(params: StatementParameters<Options> | undefined): void {
|
||||
if (params === undefined) {
|
||||
return undefined;
|
||||
return;
|
||||
}
|
||||
if (typeof params !== 'object') {
|
||||
throw new TypeError('Params must be either object or array');
|
||||
@ -357,7 +292,6 @@ class Statement<Options extends StatementOptions = object> {
|
||||
if (params === null) {
|
||||
throw new TypeError('Params cannot be null');
|
||||
}
|
||||
return this.#translateParams(params);
|
||||
}
|
||||
}
|
||||
|
||||
@ -413,13 +347,6 @@ export type DatabaseOptions = Readonly<{
|
||||
cacheStatements?: boolean;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* @param dbName - The name of the database that was written to.
|
||||
* @param pageCount - The number of pages currently in the write-ahead log file,
|
||||
* including those that were just committed.
|
||||
*/
|
||||
export type WalHook = (dbName: string, pageCount: number) => void;
|
||||
|
||||
/**
|
||||
* A sqlite database class.
|
||||
*/
|
||||
@ -477,51 +404,6 @@ export default class Database {
|
||||
addon.databaseExec(this.#native, sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create custom SQL function with a given `name`.
|
||||
*
|
||||
* @param name - name of the function
|
||||
* @param fn - function implementation
|
||||
* @param options - function options.
|
||||
*/
|
||||
public createFunction(
|
||||
name: string,
|
||||
fn: (...args: ReadonlyArray<unknown>) => void,
|
||||
options: FunctionOptions = {},
|
||||
): void {
|
||||
if (this.#native === undefined) {
|
||||
throw new Error('Database closed');
|
||||
}
|
||||
if (typeof name !== 'string') {
|
||||
throw new TypeError('Invalid name argument');
|
||||
}
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('Invalid fn argument');
|
||||
}
|
||||
addon.databaseCreateFunction(
|
||||
this.#native,
|
||||
name,
|
||||
fn,
|
||||
options.bigint === true,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked each time data is commited to a database
|
||||
* in WAL mode.
|
||||
*
|
||||
* @param fn - function implementation
|
||||
*/
|
||||
public setWalHook(fn: WalHook): void {
|
||||
if (this.#native === undefined) {
|
||||
throw new Error('Database closed');
|
||||
}
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('Invalid fn argument');
|
||||
}
|
||||
addon.databaseSetWalHook(this.#native, fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a single SQL statement.
|
||||
*
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
{
|
||||
"packageManager": "pnpm@10.18.1",
|
||||
"name": "@signalapp/sqlcipher",
|
||||
"version": "3.3.5",
|
||||
"version": "2.3.0",
|
||||
"description": "A fast N-API-based Node.js addon wrapping sqlcipher and FTS5 segmenting APIs",
|
||||
"homepage": "http://github.com/signalapp/node-sqlcipher.git",
|
||||
"license": "AGPL-3.0-only",
|
||||
|
||||
@ -1 +1 @@
|
||||
nightly-2025-09-24
|
||||
nightly-2025-02-25
|
||||
|
||||
245
src/addon.cc
245
src/addon.cc
@ -74,122 +74,6 @@ static Napi::Value SignalTokenize(const Napi::CallbackInfo& info) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Functions
|
||||
|
||||
class FunctionWrap {
|
||||
public:
|
||||
FunctionWrap(Napi::Function fn, bool is_bigint) : is_bigint_(is_bigint) {
|
||||
fn_.Reset(fn, 1);
|
||||
}
|
||||
|
||||
static void Run(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
|
||||
auto wrap = static_cast<FunctionWrap*>(sqlite3_user_data(ctx));
|
||||
|
||||
wrap->Call(ctx, argc, argv);
|
||||
}
|
||||
|
||||
static void Final(void* p_app) { delete static_cast<FunctionWrap*>(p_app); }
|
||||
|
||||
protected:
|
||||
void Call(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
|
||||
auto env = fn_.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
|
||||
assert(argc >= 0);
|
||||
|
||||
auto args = std::vector<Napi::Value>(static_cast<size_t>(argc));
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
args[i] = TranslateValue(argv[i]);
|
||||
}
|
||||
|
||||
auto result = fn_.Value().Call(args);
|
||||
|
||||
// Ignore exceptions
|
||||
if (result.IsEmpty()) {
|
||||
auto e = env.GetAndClearPendingException();
|
||||
sqlite3_result_error(ctx, e.Message().c_str(), SQLITE_ERROR);
|
||||
} else if (result.IsUndefined()) {
|
||||
sqlite3_result_null(ctx);
|
||||
} else {
|
||||
sqlite3_result_error(ctx, "Function must not return a value",
|
||||
SQLITE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
Napi::Value TranslateValue(sqlite3_value* value) {
|
||||
auto env = fn_.Env();
|
||||
int type = sqlite3_value_type(value);
|
||||
switch (type) {
|
||||
case SQLITE_INTEGER: {
|
||||
auto val = sqlite3_value_int64(value);
|
||||
if (is_bigint_) {
|
||||
return Napi::BigInt::New(env, static_cast<int64_t>(val));
|
||||
}
|
||||
if (static_cast<int64_t>(INT32_MIN) <= val &&
|
||||
val <= static_cast<int64_t>(INT32_MAX)) {
|
||||
napi_value n_value;
|
||||
NAPI_THROW_IF_FAILED(
|
||||
env, napi_create_int32(env, static_cast<int32_t>(val), &n_value),
|
||||
Napi::Value());
|
||||
return Napi::Value(env, n_value);
|
||||
} else {
|
||||
return Napi::Number::New(env, val);
|
||||
}
|
||||
}
|
||||
case SQLITE_TEXT:
|
||||
return Napi::String::New(
|
||||
env, reinterpret_cast<const char*>(sqlite3_value_text(value)),
|
||||
sqlite3_value_bytes(value));
|
||||
case SQLITE_FLOAT:
|
||||
return Napi::Number::New(env, sqlite3_value_double(value));
|
||||
case SQLITE_BLOB:
|
||||
return Napi::Buffer<uint8_t>::Copy(
|
||||
env, reinterpret_cast<const uint8_t*>(sqlite3_value_blob(value)),
|
||||
sqlite3_value_bytes(value));
|
||||
case SQLITE_NULL:
|
||||
return env.Null();
|
||||
}
|
||||
return Napi::Value();
|
||||
}
|
||||
|
||||
private:
|
||||
Napi::Reference<Napi::Function> fn_;
|
||||
bool is_bigint_;
|
||||
};
|
||||
|
||||
// WAL Hook
|
||||
|
||||
class WalHookWrap {
|
||||
public:
|
||||
explicit WalHookWrap(Napi::Function fn) { fn_.Reset(fn, 1); }
|
||||
|
||||
static int Run(void* p_app, sqlite3* _db, const char* db_name, int n_pages) {
|
||||
auto wrap = static_cast<WalHookWrap*>(p_app);
|
||||
wrap->Call(db_name, n_pages);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
void Call(const char* db_name, int n_pages) {
|
||||
auto env = fn_.Env();
|
||||
Napi::HandleScope scope(env);
|
||||
|
||||
auto result = fn_.Value().Call({
|
||||
Napi::String::New(env, db_name),
|
||||
Napi::Number::New(env, n_pages),
|
||||
});
|
||||
|
||||
// Ignore exceptions
|
||||
if (result.IsEmpty()) {
|
||||
env.GetAndClearPendingException();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Napi::Reference<Napi::Function> fn_;
|
||||
};
|
||||
|
||||
// Global Settings
|
||||
|
||||
thread_local Napi::Reference<Napi::Function> logger_fn_;
|
||||
@ -217,15 +101,10 @@ static void LoggerWrapper(void* _ctx, int code, const char* msg) {
|
||||
|
||||
#undef CODE_STR
|
||||
|
||||
auto result = logger_fn_.Value().Call({
|
||||
logger_fn_.Value().Call({
|
||||
Napi::String::New(env, code_name),
|
||||
Napi::String::New(env, msg),
|
||||
});
|
||||
|
||||
// Ignore exceptions
|
||||
if (result.IsEmpty()) {
|
||||
env.GetAndClearPendingException();
|
||||
}
|
||||
}
|
||||
|
||||
static void SetLogger(const Napi::CallbackInfo& info) {
|
||||
@ -266,10 +145,6 @@ Napi::Object Database::Init(Napi::Env env, Napi::Object exports) {
|
||||
Napi::Function::New(env, &Database::InitTokenizer);
|
||||
exports["databaseClose"] = Napi::Function::New(env, &Database::Close);
|
||||
exports["databaseExec"] = Napi::Function::New(env, &Database::Exec);
|
||||
exports["databaseCreateFunction"] =
|
||||
Napi::Function::New(env, &Database::CreateFunction);
|
||||
exports["databaseSetWalHook"] =
|
||||
Napi::Function::New(env, &Database::SetWalHook);
|
||||
return exports;
|
||||
}
|
||||
|
||||
@ -285,9 +160,6 @@ Database::~Database() {
|
||||
return;
|
||||
}
|
||||
|
||||
delete wal_hook_wrap_;
|
||||
wal_hook_wrap_ = nullptr;
|
||||
|
||||
int r = sqlite3_close(handle_);
|
||||
if (r != SQLITE_OK) {
|
||||
fprintf(stderr, "Cleanup: sqlite3_close failure\n");
|
||||
@ -379,9 +251,6 @@ Napi::Value Database::Close(const Napi::CallbackInfo& info) {
|
||||
}
|
||||
db->statements_.clear();
|
||||
|
||||
delete db->wal_hook_wrap_;
|
||||
db->wal_hook_wrap_ = nullptr;
|
||||
|
||||
int r = sqlite3_close(db->handle_);
|
||||
if (r != SQLITE_OK) {
|
||||
return db->ThrowSqliteError(env, r);
|
||||
@ -415,68 +284,6 @@ Napi::Value Database::Exec(const Napi::CallbackInfo& info) {
|
||||
return Napi::Value();
|
||||
}
|
||||
|
||||
Napi::Value Database::CreateFunction(const Napi::CallbackInfo& info) {
|
||||
auto env = info.Env();
|
||||
|
||||
auto db = FromExternal(info[0]);
|
||||
auto name = info[1].As<Napi::String>();
|
||||
auto fn = info[2].As<Napi::Function>();
|
||||
auto is_bigint = info[3].As<Napi::Boolean>();
|
||||
|
||||
assert(name.IsString());
|
||||
assert(fn.IsFunction());
|
||||
assert(is_bigint.IsBoolean());
|
||||
|
||||
if (db == nullptr) {
|
||||
return Napi::Value();
|
||||
}
|
||||
|
||||
if (db->handle_ == nullptr) {
|
||||
NAPI_THROW(Napi::Error::New(env, "Database closed"), Napi::Value());
|
||||
}
|
||||
|
||||
auto name_utf8 = name.Utf8Value();
|
||||
|
||||
auto fn_wrap = new FunctionWrap(fn, is_bigint);
|
||||
|
||||
int r = sqlite3_create_function_v2(db->handle_, name_utf8.c_str(), -1,
|
||||
SQLITE_UTF8, // TODO(indutny): or UTF16?
|
||||
fn_wrap, FunctionWrap::Run, nullptr,
|
||||
nullptr, FunctionWrap::Final);
|
||||
|
||||
if (r != SQLITE_OK) {
|
||||
delete fn_wrap;
|
||||
return db->ThrowSqliteError(env, r);
|
||||
}
|
||||
return Napi::Value();
|
||||
}
|
||||
|
||||
Napi::Value Database::SetWalHook(const Napi::CallbackInfo& info) {
|
||||
auto env = info.Env();
|
||||
|
||||
auto db = FromExternal(info[0]);
|
||||
auto fn = info[1].As<Napi::Function>();
|
||||
|
||||
assert(fn.IsFunction());
|
||||
|
||||
if (db == nullptr) {
|
||||
return Napi::Value();
|
||||
}
|
||||
|
||||
if (db->handle_ == nullptr) {
|
||||
NAPI_THROW(Napi::Error::New(env, "Database closed"), Napi::Value());
|
||||
}
|
||||
|
||||
auto wal_wrap = new WalHookWrap(fn);
|
||||
|
||||
delete db->wal_hook_wrap_;
|
||||
db->wal_hook_wrap_ = wal_wrap;
|
||||
|
||||
sqlite3_wal_hook(db->handle_, WalHookWrap::Run, wal_wrap);
|
||||
|
||||
return Napi::Value();
|
||||
}
|
||||
|
||||
Napi::Value Database::ThrowSqliteError(Napi::Env env, int error) {
|
||||
assert(handle_ != nullptr);
|
||||
const char* msg = sqlite3_errmsg(handle_);
|
||||
@ -599,14 +406,12 @@ Napi::Value Statement::New(const Napi::CallbackInfo& info) {
|
||||
auto is_persistent = info[2].As<Napi::Boolean>();
|
||||
auto is_pluck = info[3].As<Napi::Boolean>();
|
||||
auto is_bigint = info[4].As<Napi::Boolean>();
|
||||
auto param_names = info[5].As<Napi::Array>();
|
||||
|
||||
assert(db_external.IsExternal());
|
||||
assert(query.IsString());
|
||||
assert(is_persistent.IsBoolean());
|
||||
assert(is_pluck.IsBoolean());
|
||||
assert(is_bigint.IsBoolean());
|
||||
assert(param_names.IsArray());
|
||||
|
||||
auto db = db_external.Data();
|
||||
|
||||
@ -635,18 +440,6 @@ Napi::Value Statement::New(const Napi::CallbackInfo& info) {
|
||||
auto stmt = new Statement(db, db_external, handle, is_persistent, is_pluck,
|
||||
is_bigint);
|
||||
|
||||
int key_count = sqlite3_bind_parameter_count(handle);
|
||||
|
||||
for (int i = 1; i <= key_count; i++) {
|
||||
auto name = sqlite3_bind_parameter_name(handle, i);
|
||||
if (name == nullptr) {
|
||||
param_names[i - 1] = env.Null();
|
||||
} else {
|
||||
// Skip "$"
|
||||
param_names[i - 1] = name + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Napi::External<Statement>::New(
|
||||
env, stmt, [](Napi::Env env, Statement* stmt) { delete stmt; });
|
||||
}
|
||||
@ -940,18 +733,36 @@ bool Statement::BindParams(Napi::Env env, Napi::Value params) {
|
||||
|
||||
for (int i = 1; i <= list_len; i++) {
|
||||
auto name = sqlite3_bind_parameter_name(handle_, i);
|
||||
if (name != nullptr) {
|
||||
NAPI_THROW(FormatError(env, "Unexpected named param %s at %d", name, i),
|
||||
false);
|
||||
}
|
||||
|
||||
auto error = BindParam(env, i, list[i - 1]);
|
||||
if (error != nullptr) {
|
||||
if (name == nullptr) {
|
||||
NAPI_THROW(
|
||||
FormatError(env, "Failed to bind param %d, error %s", i, error),
|
||||
false);
|
||||
} else {
|
||||
NAPI_THROW(FormatError(env, "Failed to bind param %s, error %s",
|
||||
name + 1, error),
|
||||
false);
|
||||
}
|
||||
NAPI_THROW(
|
||||
FormatError(env, "Failed to bind param %d, error %s", i, error),
|
||||
false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto obj = params.As<Napi::Object>();
|
||||
|
||||
for (int i = 1; i <= key_count; i++) {
|
||||
auto name = sqlite3_bind_parameter_name(handle_, i);
|
||||
if (name == nullptr) {
|
||||
NAPI_THROW(FormatError(env, "Unexpected anonymous param at %d", i),
|
||||
false);
|
||||
}
|
||||
|
||||
// Skip "$"
|
||||
name = name + 1;
|
||||
auto value = obj[name];
|
||||
auto error = BindParam(env, i, value);
|
||||
if (error != nullptr) {
|
||||
NAPI_THROW(
|
||||
FormatError(env, "Failed to bind param %s, error %s", name, error),
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
#include "sqlite3.h"
|
||||
|
||||
class Statement;
|
||||
class WalHookWrap;
|
||||
|
||||
class Database {
|
||||
public:
|
||||
@ -31,8 +30,6 @@ class Database {
|
||||
static Napi::Value InitTokenizer(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Close(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Exec(const Napi::CallbackInfo& info);
|
||||
static Napi::Value CreateFunction(const Napi::CallbackInfo& info);
|
||||
static Napi::Value SetWalHook(const Napi::CallbackInfo& info);
|
||||
|
||||
fts5_api* GetFTS5API(Napi::Env env);
|
||||
|
||||
@ -47,8 +44,6 @@ class Database {
|
||||
// All currently open statements for this database. Used to close all open
|
||||
// statements when closing the database.
|
||||
std::list<Statement*> statements_;
|
||||
|
||||
WalHookWrap* wal_hook_wrap_ = nullptr;
|
||||
};
|
||||
|
||||
class AutoResetStatement {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { mkdtemp, rm } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { expect, test, describe, beforeEach, afterEach, vi } from 'vitest';
|
||||
import { expect, test, beforeEach, afterEach } from 'vitest';
|
||||
|
||||
import Database from '../lib/index.js';
|
||||
|
||||
@ -65,80 +65,3 @@ test.each([[false], [true]])('ciphertext=%j', (ciphertext) => {
|
||||
|
||||
expect(row).toEqual({ name: 'Adam', value: 'Sandler' });
|
||||
});
|
||||
|
||||
describe('setWalHook', () => {
|
||||
beforeEach(() => {
|
||||
db.pragma('journal_mode = WAL');
|
||||
db.exec('CREATE TABLE t (a INTEGER)');
|
||||
});
|
||||
|
||||
test('calls hook after WAL commit', () => {
|
||||
const hook = vi.fn();
|
||||
db.setWalHook(hook);
|
||||
|
||||
db.prepare('INSERT INTO t (a) VALUES (1)').run();
|
||||
|
||||
expect(hook).toHaveBeenCalledOnce();
|
||||
expect(hook).toHaveBeenCalledWith('main', expect.any(Number));
|
||||
});
|
||||
|
||||
test('hook receives page count > 0', () => {
|
||||
let pageCount: number | null = null;
|
||||
db.setWalHook((_dbName, n) => {
|
||||
pageCount = n;
|
||||
});
|
||||
|
||||
db.prepare('INSERT INTO t (a) VALUES (1)').run();
|
||||
|
||||
expect(pageCount).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('hook fires once per commit', () => {
|
||||
const hook = vi.fn();
|
||||
db.setWalHook(hook);
|
||||
|
||||
db.transaction(() => {
|
||||
db.prepare('INSERT INTO t (a) VALUES (1)').run();
|
||||
db.prepare('INSERT INTO t (a) VALUES (2)').run();
|
||||
})();
|
||||
|
||||
expect(hook).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
test('replaces previous hook', () => {
|
||||
const first = vi.fn();
|
||||
const second = vi.fn();
|
||||
|
||||
db.setWalHook(first);
|
||||
db.setWalHook(second);
|
||||
|
||||
db.prepare('INSERT INTO t (a) VALUES (1)').run();
|
||||
|
||||
expect(first).not.toHaveBeenCalled();
|
||||
expect(second).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
test('silently ignores exceptions thrown by hook', () => {
|
||||
let called = false;
|
||||
db.setWalHook(() => {
|
||||
called = true;
|
||||
throw new Error('hook error');
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
db.prepare('INSERT INTO t (a) VALUES (1)').run(),
|
||||
).not.toThrow();
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
|
||||
test('throws when database is closed', () => {
|
||||
db.close();
|
||||
expect(() => db.setWalHook(vi.fn())).toThrowError('Database closed');
|
||||
db = new Database(join(dir, 'db2.sqlite'));
|
||||
});
|
||||
|
||||
test('throws for invalid argument', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
expect(() => db.setWalHook(123 as any)).toThrowError('Invalid fn argument');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { describe, expect, test, beforeEach, afterEach, vi } from 'vitest';
|
||||
import { describe, expect, test, beforeEach, afterEach } from 'vitest';
|
||||
|
||||
import Database, { setLogger } from '../lib/index.js';
|
||||
|
||||
@ -212,16 +212,12 @@ describe('list parameters', () => {
|
||||
|
||||
test('object parameters', () => {
|
||||
const stmt = db.prepare('SELECT * FROM t WHERE a > ?');
|
||||
expect(() => stmt.get({})).toThrowError(
|
||||
'Query requires an array of anonymous params',
|
||||
);
|
||||
expect(() => stmt.get({})).toThrowError('Unexpected anonymous param at 1');
|
||||
});
|
||||
|
||||
test('against named parameters', () => {
|
||||
const stmt = db.prepare('SELECT * FROM t WHERE a > $a');
|
||||
expect(() => stmt.get([2])).toThrowError(
|
||||
'Query requires an object of named params',
|
||||
);
|
||||
expect(() => stmt.get([2])).toThrowError('Unexpected named param $a at 1');
|
||||
});
|
||||
});
|
||||
|
||||
@ -243,6 +239,13 @@ describe('object parameters', () => {
|
||||
const stmt = db.prepare('SELECT * FROM t WHERE a > $a');
|
||||
expect(() => stmt.get()).toThrowError('Expected 1 parameters, got 0');
|
||||
});
|
||||
|
||||
test('against anonymous parameters', () => {
|
||||
const stmt = db.prepare('SELECT * FROM t WHERE a > ?');
|
||||
expect(() => stmt.get({ a: 1 })).toThrowError(
|
||||
'Unexpected anonymous param at 1',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('tail', () => {
|
||||
@ -497,51 +500,3 @@ describe('statement cache', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('custom function', () => {
|
||||
let fnDb: Database;
|
||||
let fn: ReturnType<typeof vi.fn>;
|
||||
let bigFn: ReturnType<typeof vi.fn>;
|
||||
beforeEach(() => {
|
||||
fnDb = new Database(':memory:');
|
||||
|
||||
fn = vi.fn();
|
||||
fnDb.createFunction('fn', fn);
|
||||
|
||||
bigFn = vi.fn();
|
||||
fnDb.createFunction('bigFn', bigFn, {
|
||||
bigint: true,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fnDb.close();
|
||||
});
|
||||
|
||||
test('it calls the function without args', () => {
|
||||
fnDb.exec(`SELECT fn()`);
|
||||
expect(fn).toHaveBeenCalledWith();
|
||||
});
|
||||
|
||||
test('it calls the function with multiple args', () => {
|
||||
fnDb.exec(`SELECT fn(1, '123', NULL)`);
|
||||
expect(fn).toHaveBeenCalledWith(1, '123', null);
|
||||
});
|
||||
|
||||
test('it calls the function with blob', () => {
|
||||
fnDb.exec(`SELECT fn(x'abba')`);
|
||||
expect(fn).toHaveBeenCalledWith(Buffer.from('abba', 'hex'));
|
||||
});
|
||||
|
||||
test('it uses bigints when configured', () => {
|
||||
fnDb.exec(`SELECT bigFn(123456)`);
|
||||
expect(bigFn).toHaveBeenCalledWith(123456n);
|
||||
});
|
||||
|
||||
test('it throws when function returns a value', () => {
|
||||
fnDb.createFunction('intFn', () => {
|
||||
return 1;
|
||||
});
|
||||
expect(() => fnDb.exec(`SELECT intFn()`)).toThrowError('SQLITE_ERROR');
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user