面向对象 API #1 (又称 oo1)

跳转到...

sqlite3.js 从同一个线程加载和运行时,JavaScript 客户端最有可能与之交互的主要 API 是高级面向对象 API(俗称 oo1)。它提供了一个灵活且功能丰富的接口,可以与 低级 C 样式 API 结合使用(如有需要)。

其 API 在其源文件中详细记录,并在 demo-123 中展示了它的用法。

sqlite3.js 从一个线程加载并在另一个线程中运行时,客户端必须通过传递 Worker 样式消息与数据库通信。一个这样的 API 包装器可以在 Worker1 API 中找到,当然客户端可以根据 oo1 API 或 C 样式 API 创建自己的 API 包装器。

oo1 命名空间

sqlite3.oo1 对象充当 oo1 功能的命名空间。为了简洁起见,以下文档省略了这一部分。

异常

这些 API 专门使用异常来报告错误,并且总是抛出 SQLite3Error 对象,除非它们从另一个 API 传播错误(例如,Stmt.getJSON() 可能会这样做)。任何说“在出错时抛出异常”的文档,都专门指该类,除非另有说明。

C 样式 API 的互操作性

本页面上描述的数据库和准备语句对象可以按原样传递给 C 样式 API。例如

const db = new sqlite3.oo1.DB(...);
const filename = sqlite3.capi.sqlite3_db_filename(db, "main");

这些 API 将从对象中提取 pointer 属性并将该值传递给底层的 C API。

DB 类

DB 类的每个实例对应于使用 sqlite3_open() 或其等效函数创建的一个 sqlite3*。它很简单,就像

const db = new sqlite3.oo1.DB();
try {
  db.exec([
    "create table t(a);",
    "insert into t(a) ",
    "values(10),(20),(30)"
  ]);
} finally {
  db.close();
}

可以在 demo-123.js 中找到一个完整的演示,并在 demo-123.md 中演示。

DB 构造函数

对于第二种形式,对象可以包含以下任何内容

{
   filename: db filename,
   flags: open-mode flags,
   vfs: name of the sqlite3_vfs to use,
   (SEE flag - see below (added in v3.46))
}

给定的数据库文件名必须使用为默认 sqlite3 VFS 设置的任何文件系统层(虚拟或其他)可解析。

请注意,特殊的 sqlite3 数据库名称 ":memory:" 和 ""(临时数据库)在这里具有其正常的特殊含义。

第二个参数指定数据库的打开/创建模式。它必须是一个字符串,包含一系列字母(可以按任何顺序,但区分大小写),指定模式

如果没有提供 "w",数据库隐式为只读,请注意 "rc" 没有意义

任何其他字母目前都被忽略。默认值为 "c"。这些模式被忽略,因为特殊名称 ":memory:" 和 "",并且可能被特定的 VFS 忽略。

最后一个参数类似于 sqlite3_open_v2() 的最后一个参数:sqlite3 VFS 的名称。传递一个假值或完全不传递,以使用默认值。如果传递一个值,它必须是 VFS 的字符串名称

filenamevfs 参数可以是 JS 字符串或通过 WASM 分配的 C 字符串。

为了将 DB 实例传递给 C 样式 sqlite3 函数,DB 对象的只读 pointer 属性保存其 sqlite3* 指针值。该属性也可以用来检查这个 DB 实例是否仍然打开。

在主窗口线程中,文件名 ":localStorage:"":sessionStorage:" 是特殊的:它们会导致数据库使用 localStoragesessionStorage 来存储数据库,使用 kvvfs。如果使用了其中一个名称,它们会优先于在参数中设置的任何 VFS 名称。

构造函数在出错时抛出一个 SQLite3Error

参见加密

对于选项对象调用形式,该对象可以从 3.46 版本开始包含一个用于使用商业 SQLite 加密扩展 (SEE) 编码的数据库的加密密钥。

此选项是无操作的,除非它与 支持 SEE 的 JS/WASM 版本 一起使用。

要打开或创建加密的数据库,请在选项对象中提供以下一个属性:keyhexkeytextkey。每个属性可以是字符串、ArrayBuffer 或 Uint8Array,并在打开数据库时应用为数据库密钥,如 SEE 文档中针对具有相同名称的 pragma 的描述。如果提供了多个 keyhexkeytextkey,或者选项类型不支持,则会抛出异常。

DB 类属性和方法

checkRc(db,resultCode)

期望给定一个 DB 实例或一个 sqlite3* 指针(可以为 null)和一个 sqlite3 API 结果代码。如果结果代码不是假值,则此函数将抛出一个 SQLite3Error,其中包含来自 sqlite3_errmsg() 的错误消息,使用给定的数据库句柄,或者如果数据库句柄为假值或已关闭的 DB 实例,则使用 sqlite3_errstr()

请注意,如果传递给它的不是错误代码,比如 SQLITE_ROWSQLITE_DONE,它仍然会抛出异常,但错误字符串可能为“不是错误”。各种非 0 非错误代码需要在客户端代码中检查,因为它们是预期的。

如果它没有抛出异常,则它将返回其 db 参数(this,如果作为成员函数调用)。

DB 非方法属性

DB 方法

该类的实例方法在下面按字母顺序描述。

affirmOpen()

如果给定的 DB 已关闭,则抛出异常,否则返回 this

changes()

int changes(total=false,sixtyFour=false)

返回更改次数,与 sqlite3_changes() 相同(如果第一个参数为假)或 sqlite3_total_changes() 相同(如果为真)。如果第二个参数为真,它将使用 sqlite3_changes64()sqlite3_total_changes64(),如果此版本未启用 BigInt 支持,则会触发异常。

checkRc()

mixed checkRc(resultCode)

db.checkRc(resultCode) 等效于 DB.checkRc(db,resultCode).

close()

完成由该对象打开的所有仍然打开的语句,并关闭此数据库连接。如果数据库已关闭,则此操作为无操作。调用 close() 后,this.pointer 将解析为 undefined,因此可以用它来检查数据库实例是否仍然打开。

如果 this.onclose.before 是一个函数,则在执行任何与关闭相关的清理之前调用它。

如果 this.onclose.after 是一个函数,则在关闭数据库之后,但在清除辅助状态(如 this.filename)之前调用它。

这两个 onclose 处理程序都将此对象作为其唯一参数传递。如果此数据库未打开,则不会调用这两个处理程序。处理程序抛出的任何异常都将被忽略,因为“析构函数不能抛出异常”。

请注意,数据库句柄的垃圾回收(如果发生的话)永远不会触发 close(),因此 onclose 处理程序不是实现关闭时清理或数据库维护的可靠方法。

createFunction()

创建一个新的标量、聚合或窗口 UDF(用户定义函数),可以通过 SQL 代码访问它。此函数可以以以下任何形式调用

在最后两种情况下,函数必须在选项对象中定义,如下所述。在最后一种情况下,函数的名称必须是 name 属性。

前两种调用形式只能用于创建标量函数。创建聚合或窗口函数需要选项对象形式,如下所述。

UDF 目前无法在添加后从 DB 句柄中删除。更确切地说,它们可以根据 sqlite3_create_function_v2() 的文档进行删除,但这样做会“泄露”这些函数的 JS 创建的 WASM 绑定。

在该 API 级别上,这种泄漏可能是不可避免的,因为执行 JS 到 WASM 函数转换存在多个路径,并非所有路径都在 sqlite3 API 的控制之下,并且没有中央机构来跟踪这些转换。由于函数转换的内存是在 WASM 的基础设施中管理的,对 sqlite3 而言是不可见的,因此即使在关闭创建了 UDF 的数据库后,泄漏仍然存在。然而,在实践中,卸载 UDF 很少见,这种泄漏只影响安装和卸载 UDF 的客户端。通过在客户端级别代码中手动执行和管理 JS 到 WASM 函数转换(按需进行),可以避免这种泄漏。

成功时,返回此对象。错误时抛出异常。

从 SQL 调用时,UDF 的参数及其结果将在 JS 和 SQL 之间进行转换,以尽可能高的保真度进行转换,如果无法确定类型转换,则会引发异常。由于 JS 和 C 世界之间的摩擦,数字转换具有一定的灵活性:大于 32 位的整数将被视为双精度数或 BigInt 值。

选项对象所需的值根据函数类型而异

选项对象可以选择地具有 xDestroy 函数类型属性,如 sqlite3_create_function_v2() 中所述。其参数将是 pApp 属性的 WASM 指针类型值,如果定义了 pApp 但它不是 null、undefined 或数字(WASM 指针)值,则此函数将抛出异常。即,如果设置了 pApp,它必须是适合用作 WASM 指针参数的值,注意 nullundefined 将转换为 0 以用于该目的。

选项对象可能包含用于修改函数定义方式的标志

以下选项对象属性对应于 www:/c3ref/create_function.html 中记录的标志

www:/c3ref/create_function.html

dbFilename()

string dbFilename(dbName='main')

这只是 sqlite3_db_filename() 的代理,返回与给定数据库名称关联的文件名,默认为 "main"。参数可以是 JS 字符串,也可以是指向 WASM 分配的 C 字符串的指针。如果此数据库已关闭,则抛出异常。

dbName()

string dbName(dbIndex=0)

返回给定 0 索引数据库编号的名称,如 sqlite3_db_name() 中记录的那样。如果此数据库已关闭,则抛出异常。

dbVfsName()

string dbVfsName(dbName=0)

返回给定数据库的 sqlite_vfs 名称,默认为 "main"。数据库名称可以是 JS 或 WASM C 字符串。如果此数据库已关闭,则抛出异常。

exec()

执行 SQL 语句,并可选地收集查询结果和/或为每个结果行调用回调。调用形式

在后一种情况下,optionsObject.sql 必须包含要执行的 SQL。默认情况下,它返回此对象,但这可以通过下面描述的 returnValue 选项进行更改。错误时抛出异常。

如果未提供 SQL 或提供了非字符串,则会引发异常。另一方面,空 SQL 只是一个无操作。

可选的选项对象可能包含以下任何属性

以下选项仅适用于第一个具有非零结果列计数的语句,无论该语句是否实际生成任何结果行。

传递给回调的第一个参数默认为当前结果行中值的数组,但可以使用...进行更改。

任何其他 rowMode 值都会引发异常。

isOpen()

如果此数据库句柄已打开,则返回 true,否则返回 false。

openStatementCount()

返回此数据库句柄当前打开的 Stmt 句柄数量,如果此对象已 close(),则返回 0。注意,仅通过 this.prepare() 准备的句柄才会被计算,而使用 capi.sqlite3_prepare_v3()(或等效方法)准备的句柄不会被计算。

prepare()

编译给定的 SQL 并返回一个已准备好的 Stmt。这是创建新的 Stmt 对象的唯一方法。错误时抛出异常。

SQL 参数可以是 灵活字符串 转换中描述的任何类型。如果 SQL 不包含任何语句,则会抛出 SQLite3Error

C API 允许使用空 SQL,将其报告为 0 结果代码和 NULL stmt 指针。在这里支持这种情况将导致所有客户端都进行额外的工作:对这种语句使用 Stmt API 必然会抛出异常,因此客户端必须在调用 prepare() 后检查 stmt.pointer,以确定 Stmt 实例是否为空。与其他 sqlite3 脚本绑定的长期实践表明,空准备情况非常罕见,因此在这里支持它只会损害整体可用性。

savepoint()

any savepoint(callback)

这与 transaction() 的工作方式类似,但使用 sqlite3 的 SAVEPOINT 功能。此函数启动一个保存点(使用未指定的名称)并调用给定的回调函数,将此数据库对象传递给它。如果回调返回,则释放保存点(提交)。如果回调抛出异常,则回滚保存点。如果它没有抛出异常,则返回回调的结果。

selectArray()

mixed selectArray(SQL [,bind])

准备 给定的 SQL,执行一次 step(),并返回一个包含第一行结果值的数组。 如果没有结果,则返回 undefined

如果传递第二个参数(除 undefined 外),则将其视为 Stmt.bind() 的参数,因此可以是该函数支持的任何类型。

在错误情况下抛出异常。

selectArrays()

mixed selectArrays(SQL [,bind])

运行 给定的 SQL 并返回一个包含所有结果的数组,其中每一行都表示为一个数组,如 exec() 的 'array' rowMode 选项所示。 空结果集将解析为空数组。 如果存在第二个参数,则将其视为对 exec() 的调用的 bind 选项。

在错误情况下抛出异常。

selectObject()

mixed selectObject(SQL [,bind])

准备 给定的 SQL,执行一次 step(),并返回一个包含第一行结果键值对的对象。 如果没有结果,则返回 undefined

请注意,返回对象的键的顺序不保证与查询字符串中字段的顺序相同。

如果传递第二个参数(除 undefined 外),则将其视为 Stmt.bind() 的参数,因此可以是该函数支持的任何类型。

在错误情况下抛出异常。

selectObjects()

mixed selectObjects(SQL [,bind])

selectArrays() 的工作方式相同,只是返回数组中的每个值都是一个对象,如 exec()"object" rowMode 选项所示。

selectValue()

any selectValue(SQL [,bind [,asType]])

准备给定的 SQL,对生成的结果 Stmt 执行一次 step(),并返回第一列结果的值。 如果没有结果,则返回 undefined

如果传递第二个参数,则将其视为 Stmt.bind() 的参数,因此可以是该函数支持的任何类型。 传递 undefined 值与不传递值相同,这在... 时很有用。

如果传递第三个参数,则它应该是一个 SQLITE_{typename} 常量。 传递 undefined 值与不传递值相同。

在错误情况下抛出异常(例如,格式错误的 SQL)。

selectValues()

array selectValues(SQL [,bind [,asType]])

运行给定的查询并返回结果集中每一行第一列结果值的数组。 第二个参数是一个可选值,用于在对 Stmt.bind() 的单参数调用中使用。 第三个参数可以是任何适合用作 Stmt.get() 的第二个参数的值。 如果需要第三个参数但不需要绑定数据,则将 undefined 作为第二个参数传递。

如果没有结果行,则返回一个空数组。

transaction()

any transaction([beginQualifier,] callback)

启动事务,调用给定的回调,然后根据回调是否抛出异常来回滚或提交事务。 回调将传递此对象作为其唯一参数。 成功时,返回回调的结果。 在错误情况下抛出异常。

请注意,事务不能嵌套,因此如果递归调用此函数,它将抛出异常。 对于嵌套事务,请使用 savepoint() 方法或使用 exec() 手动管理 SAVEPOINT。

如果使用 2 个参数调用,则第一个参数必须是一个关键字,该关键字在 BEGIN 语句后立即合法,例如“DEFERRED”、“IMMEDIATE”或“EXCLUSIVE”之一。 虽然支持的关键字的确切列表并未在此处硬编码,但为了与将来兼容,如果参数看起来不像单个关键字,则将触发一个异常,其中包含问题的描述。

Stmt 类

准备好的语句仅通过 DB.prepare() 方法 创建。 直接调用构造函数将触发异常。

重要的是,语句要及时完成,否则客户端可能会在应用程序中引入锁定错误。

总的来说,客户端可以通过使用 DB.exec() 方法 来避免语句生命周期问题。 但是,对于需要更多控制或灵活性的情况,客户端需要 prepare() 语句,然后确保其生命周期得到正确管理。 最简单的执行此操作的方法是使用 try/finally 块,例如

const stmt = myDb.prepare("...");
try {
  ... use the stmt object ...
} finally {
  stmt.finalize();
}

Stmt 非方法属性

Stmt 方法

该类的实例方法在下面按字母顺序描述。

bind()

Stmt bind([ndx=1,] value)

将一个或多个值绑定到其可绑定参数。 它接受 1 或 2 个参数

如果传递单个参数,则它必须是数组、对象或可绑定类型的值(见下文)。 其绑定索引假定为 1。

如果传递 2 个参数,则第一个参数是 1 基的绑定索引或可绑定参数名称,第二个参数必须是可绑定类型的值。

可绑定值类型

如果传递一个数组,则数组的每个元素都绑定到等于数组索引加 1 的参数索引处(因为数组是 0 基的,但绑定是 1 基的)。

如果传递一个对象,则每个对象键都视为可绑定参数名称。 对象键必须与任何可绑定参数名称匹配,包括任何 $@: 前缀。 由于 $ 是 JavaScript 中的合法标识符字符,因此建议使用它作为可绑定参数的前缀:stmt.bind({$a: 1, $b: 2})

成功时,它返回此对象,在错误情况下抛出异常。 错误包括

bindAsBlob()

Stmt bind([ndx=1,] value)

bind() 的特殊情况,它使用 BLOB 绑定机制而不是为该值选择的默认机制来绑定给定的值。 索引可以是编号绑定索引或命名绑定索引。 该值必须是字符串类型、null/undefined(两者都将视为 null)或 bind() 支持的类型的 TypedArray。

如果传递单个参数,则假定绑定索引为 1,并且第一个参数是值。

clearBindings()

Stmt clearBindings()

清除所有绑定值。 返回此对象。 如果此语句已完成,则抛出异常。

finalize()

void finalize()

“完成”此语句。 如果语句已完成,则这是一个无操作。 返回底层 sqlite3_finalize() 调用的值(成功时为 0,错误时为非 0)或 undefined(如果语句已完成)。 如果 sqlite3_finalize() 返回非 0,则不会抛出异常,因为此函数实际上是一个析构函数,并且“析构函数不会抛出异常”。 如果在通过 DB.exec() 回调积极使用语句时调用此函数,则此函数抛出异常。

此类中的大多数方法在调用此方法后都会抛出异常。

get()

any get(ndx [, asType])

从当前数据行的给定 0 基列索引获取值,如果索引超出范围,则抛出异常。

要求 step() 刚刚返回一个真值,否则将抛出异常。

默认情况下,它将自动确定结果的数据类型。 如果传递第二个参数,则它必须是 sqlite3 类型的枚举值之一,这些值定义为 sqlite3 命名空间的成员:SQLITE_INTEGERSQLITE_FLOATSQLITE_TEXTSQLITE_BLOB。 任何其他值(undefined 除外)都会触发异常。 传递 undefined 与不传递值相同。 可以合法地例如将整数类型的值作为字符串获取,在这种情况下,sqlite3 将将值转换为字符串。

如果索引是一个数组,则此函数的行为不同:它将数组的索引(从 0 到结果列数)分配给相应结果列的值,并返回该数组

const values = stmt.get([]);

将返回一个数组,其中包含语句当前行的每个结果列的一个条目。

如果索引是一个普通对象,则此函数的行为更加不同:它将对象的属性分配给<其相应结果列的值

const values = stmt.get({});

返回一个对象,其属性以结果集的列命名。 请注意,属性的顺序是未定义的。 如果它们的顺序很重要,请改用数组形式。

Blob 返回为 Uint8Array 实例。

64 位整数的特殊情况处理:Number 类型用于浮点数和足够小的整数,以便在不损失精度的情况下适合它。 如果获取了更大的整数,则如果启用了该支持,则将其作为 BigInt 返回;否则将抛出异常。 Number 类的支持的整数范围定义为

getBlob()

Uint8Array|null get(ndx)

等效于 get(ndx),但将结果强制转换为 Uint8Array。

getColumnName()

string getColumnName(ndx)

返回给定索引的结果列名,如果索引超出范围或此语句已完成,则抛出异常。 这可以在不先运行 step() 的情况下使用。

getColumnNames()

array getColumnNames(target=[])

如果此语句可能具有结果列,则此函数将返回所有这些名称的数组。 如果传递了一个数组,则将其用作目标,并将所有名称追加到它。 返回目标数组。 如果此语句不能具有结果列,则抛出异常。 this.columnCount 在准备语句时设置,它保存列数。

getFloat()

number|null get(ndx)

等效于 get(ndx),但将结果强制转换为数字。

getInt()

number|null get(ndx)

等效于 get(ndx),但将结果强制转换为数字。

getJSON()

any get(ndx)

等效于 getString(ndx),但返回通过 JSON.parse() 传递获取的字符串后的结果。 如果 JSON 解析抛出异常,则将传播该异常。

getParamIndex()

int getParamIndex(name)

如果此语句具有命名的可绑定参数,并且给定的名称与其中一个匹配,则返回其基于 1 的绑定索引。如果未找到匹配项,则返回 0。如果没有可绑定参数,则返回 undefined 值。

getParamName()

string getParamName(ndx)

在 3.47 中添加。

行为类似于 sqlite3_bind_parameter_name()。如果 ndx 超出范围,则返回 null;如果此对象没有绑定参数,则返回 undefined

getString()

string|null get(ndx)

等效于 get(ndx),但将结果强制转换为字符串。

isBusy()

bool isBusy()

在 3.47 中添加。

行为类似于 sqlite3_stmt_busy(),但将其结果作为布尔值而不是整数返回。

isBusy()

bool isReadOnly()

在 3.47 中添加。

行为类似于 sqlite3_stmt_readonly(),但将其结果作为布尔值而不是整数返回。

reset()

Stmt reset(alsoClearBinds=false)

重置此语句,以便可以从头开始再次 step()。返回 this。如果此语句已完成,则抛出异常;如果它可能无法合法重置,因为它当前正在从 DB.exec() 回调中使用;或者(从版本 3.42.1 和 3.43 开始)如果底层对 sqlite3_reset() 的调用返回非 0。

如果传递了一个真值参数,则还会调用 this.clearBindings(),否则,任何现有的绑定以及为它们分配的任何内存都将保留。

在版本 3.42.0 及更早版本中,如果 sqlite3_reset() 返回非 0,则此函数不会抛出异常,但已发现抛出异常(或重要的额外客户端代码)对于避免某些静默失败场景是必要的,如 SQLite 论坛中所述

step()

bool step()

执行语句一次。如果结果表明数据行可用,则返回一个真值。如果没有数据行可用,则返回一个假值。在错误时抛出异常。

stepFinalize()

bool stepFinalize()

功能类似于 step(),除了它在执行完一步后立即调用此语句上的 finalize(),除非 step() 抛出异常。

成功后,如果步骤表明数据行可用,则返回 true,否则返回 false。

这旨在简化以下用例

db.prepare("INSERT INTO foo(a) VALUES(?)").bind(123).stepFinalize();

stepReset()

Stmt stepReset()

功能与 step() 完全相同,除了...

这旨在简化类似以下的结构

for(...) {
  stmt.bind(...).stepReset();
}

请注意,reset() 调用使得在执行完一步后调用 this.get() 变得非法。

JsStorageDb

当 sqlite3 API 安装在主线程中时,将添加 JsStorageDb 类(DB 类的子类),它简化了 kvvfs 的使用。

const db = new sqlite3.oo1.JsStorageDb('local' /* or 'session' */);
... use like any other db ...
if( db.storageSize() ) {
  db.clearStorage(); // empty it!
}
db.close();

JsStorageDb 对象包括以下类级方法

它们只是 sqlite3_js_kvvfs_clear()sqlite3_js_kvvfs_size() 的代理。具有相同名称的成员函数仅在其自己的存储对象上操作

const db = new sqlite3.oo1.JsStorageDb('local');
console.log('db size =',db.storageSize()); // only localStorage size
db.clearStorage(); // clears only the localStorage db

从版本 3.46 开始,构造函数可以选择接受与 DB 类构造函数相同的形式的选项对象,而不仅仅是文件名。这使得能够例如在这些对象上激活 SQL 跟踪。

OpfsDb 类

OpfsDb(DB 类的子类)仅在 OPFS VFS 支持 处于活动状态时安装。它可以像这样使用

const db = new sqlite3.oo1.OpfsDb('/path/to/my/db','c');
// Or: new sqlite3.oo1.OpfsDb({filename: ..., flags: 'c'});

参数与 DB 构造函数的含义相同,但如果打开标志包含 'c'(创建),则将创建通向文件的目录部分。如果数据库无法打开,则抛出异常。有关文件锁定的信息,请参阅 OPFS VFS 文档,请注意,任何给定的 DB 都可以被当前访问同一 HTTP 来源的所有浏览器选项卡访问。

此子类向 API 添加了一个静态方法

OpfsDb.importDb()

(在 3.43 中添加)

类级(静态)importDb() 方法可以(异步地)将数据库导入 OPFS 存储。它仅适用于数据库文件,如果传递了其他文件类型,则会抛出异常。用法

sqlite3.oo1.OpfsDb.importDb('filename', byteArray);

说明

它在错误时抛出异常,导致 promise 被拒绝。在这种情况下,它可能会在文件系统中留下一个部分写入的文件。

从版本 3.44 开始,如果传递了一个函数作为其第二个参数,则其行为将更改为以块的形式导入其数据,这些数据由给定的回调函数提供。它会反复调用回调(它可能是异步的),并期望返回一个 Uint8Array 或 ArrayBuffer(表示新输入)或 undefined(表示 EOF)。只要回调继续返回非 undefined,它就会将传入的数据追加到给定的 VFS 托管的数据库文件中。


  1. ^ 回想一下,函数的 length 是它具有的声明参数的数量。