The SQLite Bytecode Engine
SQLite 字节码引擎
1. 执行摘要
2.介绍
2.1 VDBE 源代码
2.2 指令格式
2.3 寄存器
2.4 B树游标
2.5 子例程,协程和子程序
2.6 Self-Altering 代码
3.查看字节码
4. 操作码
1 执行摘要
SQLite 的工作方式是将 SQL 语句转换为字节码,然后在虚拟机中运行该字节码。本文档描述了字节码引擎如何工作。
本文档介绍了 SQLite 内部。这里提供的信息对于使用 SQLite 进行日常应用程序开发并不需要。本文档面向想深入研究 SQLite 内部操作的人员。
字节码引擎不是 SQLite 的 API。有关字节码引擎的详细信息从一个 SQLite 版本更改为下一个版本。使用 SQLite 的应用程序不应该依赖于本文档中的任何细节。
2.介绍
SQLite 的工作原理是将每个 SQL 语句翻译成字节码,然后运行该字节码。SQLite 中准备好的语句大多只是实现相应 SQL 所需的字节码。sqlite3_prepare_v2()接口是一个将 SQL 转换为字节码的编译器。sqlite3_step() 接口是运行准备语句中包含的字节码的虚拟机。
字节码虚拟机是 SQLite 的核心。希望了解 SQLite 如何在内部运行的程序员必须熟悉字节码引擎。
历史上,SQLite 中的字节码引擎称为“虚拟数据库引擎”或 “VDBE”。本网站可互换地使用术语“字节码引擎”,“VDBE”,“虚拟机”和“字节码虚拟机”,因为它们都表示相同的东西。
本文也可以互换使用术语“字节码程序”和“准备好的语句”,因为它们大多是相同的。
2.1 VDBE 源代码
字节码引擎的源代码位于 vdbe.c 源文件中。本文档中的操作码定义来源于该源文件中的注释。源代码注释是关于字节码引擎的标准信息源。如有疑问,请参阅源代码。
除了主 vdbe.c 源代码文件之外,源树中还有其他帮助程序代码文件,其所有名称都以 “vdbe” 开头 - “Virtual DataBase Engine” 的缩写。
请记住,操作码的名称和含义通常会从一个 SQLite 版本更改为下一个版本。因此,如果您正在研究 SQLite 的 EXPLAIN 输出,那么应该引用与运行 EXPLAIN 的 SQLite 版本相对应的本文档版本(或 vdbe.c 源代码)。否则,操作码的描述可能不准确。本文档来源于2017年2月24日发布的 SQLite 3.21.0 版签入版1a584e499906b。
2.2 指令格式
SQLite中的字节编码程序由一个或多个指令组成。每条指令都有一个操作码和五个名为P1,P2 P3,P4和P5的操作数。P1,P2和P3操作数是32位有符号整数。这些操作数通常引用寄存器。对于在b-tree游标上运行的指令,P1操作数通常是游标编号。对于跳转指令,P2通常是跳转目标。P4可以是32位有符号整数,64位有符号整数,64位浮点值,字符串文字,Blob文字,指向比对序列比较函数的指针或指向实现应用程序定义的SQL函数或其他各种东西。P5是一个16位无符号整数,通常用于保存标志。P5标志的位有时会以微妙的方式影响操作码。例如,如果在Eq操作码上设置了P5操作数的 SQLITE_NULLEQ(0x0080)位,则 NULL 值彼此相等。否则,NULL 值会彼此不同。
一些操作码使用全部五个操作数。一些操作码使用一个或两个。一些操作码不使用任何操作数。
字节码引擎在指令编号0处开始执行。继续执行直到看到暂停指令,或者直到程序计数器大于最后一条指令的地址,或者直到出现错误。当字节码引擎暂停时,它分配的所有内存被释放,并且它可能打开的所有数据库光标都被关闭。如果执行由于错误而停止,则所有待处理的事务都将终止,并且对数据库所做的更改将被回滚。
ResultRow 操作码会导致字节码引擎暂停,并且相应的 sqlite3_step()调用将返回 SQLITE_ROW。在调用 ResultRow 之前,字节编码的程序会将查询的单行结果加载到一系列寄存器中。C 语言 API(如 sqlite3_column_int()或 sqlite3_column_text())从这些寄存器中提取查询结果。在下一次调用 sqlite3_step()的 ResultRow 之后,字节码引擎将继续执行下一条指令。
2.3 寄存器
每个字节码程序都有一个固定的(但可能很大)的寄存器。一个寄存器可以容纳各种对象:
- 一个 NULL 值
- 一个有符号的64位整数
- IEEE 双精度(64位)浮点数
- 任意长度的字符串
- 任意长度的 BLOB
- RowSet 对象(请参阅 RowSetAdd,RowSetRead 和 RowSetTest 操作码)
- 框架对象(由子程序使用 - 请参阅程序)
寄存器也可以是 “Undefined”,意思是它根本没有任何价值。未定义与 NULL 不同。根据编译时选项,尝试读取未定义的寄存器通常会导致运行时错误。如果代码生成器(sqlite3_prepare_v2())曾经生成一个读取未定义寄存器的预处理语句,那就是代码生成器中的一个错误。
寄存器从0开始编号。大多数操作码至少指一个寄存器。
单个预准备语句中的寄存器数量在编译时是固定的。当准备好的语句被重置或完成时,所有寄存器的内容都会被清除。
内部 Mem 对象存储单个寄存器的值。暴露在 API 中的抽象 sqlite3_value 对象实际上只是一个 Mem 对象或寄存器。
2.4 B 树游标
准备好的语句可以有零个或多个打开的游标。每个游标都由一个小整数标识,该整数通常是使用游标的操作码的 P1参数。可以在同一个索引或表上打开多个游标。所有游标都独立运行,即使是指向相同索引或表的游标。虚拟机与数据库文件交互的唯一方法是通过游标。虚拟机中的指令可以创建一个新的游标(例如:OpenRead 或 OpenWrite),从游标(列)读取数据,将光标前移到表中的下一个条目(例如:Next 或 Prev)等等。准备好的语句被重置或完成时,所有游标都会自动关闭。
2.5 子例程,协程和子程序
字节码引擎没有堆栈来存储子程序的返回地址。返回地址必须存储在寄存器中。因此,字节码子程序不可重入。
Gosub 操作码将当前程序计数器存储到寄存器P1中,然后跳转到地址 P2。返回操作码跳转到地址 P1 + 1。因此,每个子程序都与两个整数相关联:子程序中入口点的地址和用于保存返回地址的寄存器号。
Yield 操作码将程序计数器的值与寄存器 P1中的整数值进行交换。这个操作码用来实现协程。协程常常用来实现子查询,从中可以根据需要提取内容。
触发器必须是可重入的。由于字节码子例程不可重入,因此必须使用不同的机制来实现触发器。每个触发器都使用一个独立的字节码程序来实现,该程序具有自己的操作码,程序计数器和寄存器组。程序操作码调用触发器子程序。程序指令为每个子程序的调用分配并初始化一个新的寄存器组,所以子程序可以是可重入的和递归的。子程序使用 Param 操作码来访问调用字节码程序的寄存器中的内容。
2.6. Self-Altering 代码
一些操作码是自我改变的。例如,Init 操作码(始终是第一个操作码运行一个字节码程序)递增其 P1操作数。后续一次操作码将它们的 P1 操作数与 Init 操作码的 P1值进行比较,以确定是否应该跳过后面的一次性初始化代码。另一个例子是 String8 操作码,它将 P4 操作数从 UTF-8 转换为正确的数据库字符串编码,然后将其自身转换为字符串操作码。
3.查看字节码
SQLite 解释的每条 SQL 语句都会导致虚拟机的程序。但是,如果 SQL 语句以关键字 EXPLAIN 开头,虚拟机将不会执行该程序。相反,程序的指令将被返回,每行一条指令,就像查询结果一样。此功能对于调试和了解虚拟机的运行方式非常有用。例如:
$ sqlite3 ex1.db
sqlite> explain delete from tbl1 where two<20;
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 12 0 00 Start at 12
1 Null 0 1 0 00 r[1]=NULL
2 OpenWrite 0 2 0 3 00 root=2 iDb=0; tbl1
3 Rewind 0 10 0 00
4 Column 0 1 2 00 r[2]=tbl1.two
5 Ge 3 9 2 (BINARY) 51 if r[2]>=r[3] goto 9
6 Rowid 0 4 0 00 r[4]=rowid
7 Once 0 8 0 00
8 Delete 0 1 0 tbl1 02
9 Next 0 4 0 01
10 Noop 0 0 0 00
11 Halt 0 0 0 00
12 Transaction 0 1 1 0 01 usesStmtJournal=0
13 TableLock 0 2 1 tbl1 00 iDb=0 root=2 write=1
14 Integer 20 3 0 00 r[3]=20
15 Goto 0 1 0 00
任何应用程序都可以运行 EXPLAIN 查询来获得与上面类似的输出。但是,显示循环结构的缩进不是由 SQLite 内核生成的。命令行 shell 包含用于缩进循环的额外逻辑。另外,EXPLAIN 输出中的 “comment” 列仅在 SQLite 使用- DSQLITE_ENABLE_EXPLAIN_COMMENTS 选项编译时才提供。
当使用 SQLITE_DEBUG 编译时选项编译 SQLite 时,可以使用额外的 PRAGMA 命令,这些命令对于调试和探索 VDBE 的操作很有用。例如,可以启用 vdbe_trace 编译指示,以便在执行操作码时,将每个 VDBE 操作码的反汇编打印在标准输出上。这些调试编译指示包括:
- PRAGMA parser_trace
- PRAGMA vdbe_addoptrace
- PRAGMA vdbe_debug
- PRAGMA vdbe_listing
- PRAGMA vdbe_trace
4.操作码
目前虚拟机定义了165个操作码。下表中描述了所有当前定义的操作码。该表是通过从文件 vdbe.c 中扫描源代码自动生成的。
记住:VDBE 操作码不是 SQLite 接口定义的一部分。操作码的数量及其名称和含义从一个版本的 SQLite 更改为下一个。下表中显示的操作码适用于2017年3月10日发布的 SQLite 3.21.0 版签入版本1a584e499906b。
操作码名称 | 描述 |
---|---|
Add | 将寄存器P1中的值添加到寄存器P2中的值,并将结果存储在寄存器P3中。如果任一输入为NULL,则结果为NULL。 |
AddImm | 将常数P2添加到寄存器P1中的值。结果总是一个整数。要强制任何寄存器是一个整数,只需加0。 |
Affinity | 对P1开始的一系列P2寄存器应用亲和性。P4是一个长度为P2字符的字符串。字符串的第N个字符指示应该用于范围中第N个存储单元的列亲和度。 |
AggFinal | 执行聚合的终结器函数。P1是聚合的累加器的内存位置。P2是步进函数所需参数的数量,P4是此函数FuncDef的指针。这个操作码不使用P2参数。它只是为了消除可能需要不同数量参数的函数。P4参数仅适用于先前未调用阶跃函数的退化情况。 |
AggStep | 执行聚合的步骤功能。该函数具有P5参数。P4是一个指向sqlite3_context对象的指针,用于运行该函数。寄存器P3作为累加器。P5参数取自寄存器P2及其后继。该操作码最初编码为AggStep0。在第一次评估时,P4中存储的FuncDef被转换为sqlite3_context并且操作码被更改。这样,sqlite3_context的初始化只发生一次,而不是每次调用step函数。 |
AggStep0 | 执行聚合的步骤功能。该函数具有P5参数。P4是指向函数的FuncDef结构的指针。寄存器P3是累加器。P5参数取自寄存器P2及其后继。 |
And | 取寄存器P1和P2中的值的逻辑与,并将结果写入寄存器P3。如果P1或P2为0(假),那么即使其他输入为NULL,结果也为0。NULL和真或两个NULL给出一个NULL输出。 |
AutoCommit | 将数据库自动提交标志设置为P1(1或0)。如果P2为真,则回滚任何当前活动的btree事务。如果有任何活动的虚拟机(除此之外),则ROLLBACK将失败。如果存在使用共享缓存的活动写入VM或活动VM,则COMMIT将失败。该指令会导致VM暂停。 |
BITAND | 将寄存器P1和P2中的值按位进行与运算并将结果存储在寄存器P3中。如果任一输入为NULL,则结果为NULL。 |
BITNOT | 将寄存器P1的内容解释为整数。将P1值的补码存储到寄存器P2中。如果P1保存一个NULL,则在P2中存储一个NULL。 |
BITOR | 取寄存器P1和P2中的值的逐位OR,并将结果存储在寄存器P3中。如果任一输入为NULL,则结果为NULL。 |
Blob | P4指向一个长度为P1字节的数据块。将此Blob存储在寄存器P2中。 |
Cast | 强制将寄存器P1中的值设置为由P2定义的类型。P2 =='A'→BLOB P2 =='B'→TEXT P2 =='C'→NUMERIC P2 =='D'→INTEGER P2 =='E'→REAL这个例程没有改变NULL值。它仍然是NULL。 |
Checkpoint | 检查点数据库P1。如果P1当前不处于WAL模式,则这是不可操作的。参数P2是SQLITE_CHECKPOINT_PASSIVE,FULL,RESTART或TRUNCATE之一。如果检查点分别返回SQLITE_BUSY或不是,则将1或0写入memP3。将检查点之后的WAL中的页面数写入memP3 + 1,并且在检查点完成之后将已检查点的WAL中的页数写入memP3 + 2。但是,在出错时,memP3 + 1和memP3 + 2会初始化为-1。 |
Clear | 删除数据库表中的所有内容或索引,其数据库文件中的根页面由P1给出。但是,与Destroy不同,不要从数据库文件中删除表或索引。如果P2 == 0,表格清晰的位于主数据库文件中。如果P2 == 1,则要清除的表位于用于存储表的辅助数据库文件中使用CREATE TEMPORARY TABLE创建。如果P3值不为零,那么引用的表必须是一个intkey表(一个SQL表,而不是一个索引)。在这种情况下,行更改计数会增加正在清除的表中的行数。如果P3大于零,则存储在寄存器P3中的值也会增加正在清除的表中的行数。另见:销毁 |
Close | 关闭先前打开为P1的光标。如果P1当前未打开,则该指令为空操作。 |
CollSeq | P4是一个指向CollSeq对象的指针。如果下一次调用用户函数或聚合调用sqlite3GetFuncCollSeq(),则会返回此归类序列。这由内建的min(),max()和nullif()函数使用。如果P1不为零,那么它是一个寄存器,如果当前行不是最小值或最大值,则后续的min()或max()聚合将设置为1。该指令将P1寄存器初始化为0。执行前述功能来检索由此操作码设置的归类序列所使用的接口不可公开获得。只有内置功能才能访问此功能。 |
Column | 解释光标P1指向的数据为使用MakeRecord指令构建的结构。(有关数据格式的更多信息,请参阅MakeRecord操作码。)从该记录中提取第P2列。如果记录中的(P2 + 1)值较少,请提取NULL。提取的值存储在寄存器P3中。如果记录包含少于P2字段,则提取一个NULL。或者,如果P4参数是P4_MEM,则使用P4参数的值作为结果。如果在P5上设置了OPFLAG_CLEARCACHE位,并且P1是一个伪表游标,那么在提取列之前会重置游标的缓存。在内容寄存器的值改变之后,针对伪表的第一列应该设置该位。如果在P5上设置OPFLAG_LENGTHARG和OPFLAG_TYPEOFARG位,则结果保证只能分别用作length()或typeof()函数的参数。加载大块可以跳过length(),并且typeof()可以跳过所有内容加载。 |
ColumnsUsed | 这个操作码(只有在SQLite是用SQLITE_ENABLE_COLUMN_USED_MASK编译时才存在)标识使用了表P1或索引P1的哪些列。P4是一个64位整数(P4_INT64),其中前63位是针对游标实际使用的表或索引的前63列中的每一列。如果使用第64个之后的任何列,则设置高位。 |
比较 | 比较reg(P1)... reg(P1 + P3-1)(称为此向量“A”)和reg(P2).. reg(P2 + P3-1)(“B”)中的两个寄存器向量。保存比较结果供下一个跳转指令使用。如果P5设置了OPFLAG_PERMUTE位,则比较顺序由最近的Permutation运算符决定。如果OPFLAG_PERMUTE位清零,则按顺序对寄存器进行比较。P4是一个KeyInfo结构,用于定义比较的整理顺序和排序顺序。该排列仅适用于寄存器。KeyInfo元素按顺序使用。比较是一种排序比较,所以NULL比较相等,NULL小于数字,数字小于字符串,字符串小于blob。 |
CONCAT | 将寄存器P1中的文本添加到寄存器P2中的文本末尾,并将结果存储在寄存器P3中。如果P1或P2文本是NULL,则在P3中存储NULL。P3 = P2 || P1 P1和P3是同一个寄存器是非法的。有时,如果P3与P2的寄存器相同,则实现可以避免使用memcpy()。 |
Copy | 将寄存器P1..P1 + P3复制到寄存器P2..P2 + P3中。这条指令对价值进行了深层次的复制。重复由任何字符串或blob常量组成。另请参阅SCopy。 |
Count | 将由光标P1打开的表或索引中的条目数(整数值)存储在寄存器P2中 |
CreateBtree | 如果P1 == 0,则在主数据库文件中分配一个新的B-树;如果P1 == 1,则在TEMP数据库文件中分配一个新的B-树;如果P1> 1,则在附加数据库中分配一个新的B-树。对于rowid表,P3参数必须是1(BTREE_INTKEY),对于索引或WITHOUT ROWID表,它必须是2(BTREE_BLOBKEY)。新的b-tree的根页码存储在寄存器P2中。 |
CursorHint | 向游标P1提供一个提示,它只需要返回满足P4中Expr的行。P4表达式中的TK_REGISTER条款是指当前寄存器中保存的值。P4表达式中的TK_COLUMN项指的是游标P1所指向的b树中的列。 |
DecrJumpZero | 寄存器P1必须保存一个整数。如果新值恰好为零,则减小P1中的值并跳转到P2。 |
DeferredSeek | P1是一个开放索引游标,P3是相应表中的游标。此操作代码将P3表游标延迟搜索到对应于当前P1行的行。这是一个延期寻找。在光标用于读取记录之前什么也没有发生。这样,如果不发生读取,则不会发生不必要的I / O。P4可能是一个整数数组(P4_INTARRAY类型),其中包含P3表中每列的一个条目。如果数组条目a(i)非零,则从光标P3读取a(i)-1列相当于执行延迟查找,然后从P1读取列i。这些信息存储在P3中,用于将读取操作重定向到P1,从而可能避免需要查找和读取光标P3。 |
Delete | 删除P1光标当前指向的记录。如果设置了P5参数的OPFLAG_SAVEPOSITION位,则光标将指向表中的下一个或前一个记录。如果它指向下一条记录,则下一条下一条指令将为空操作。因此,在这种情况下,可以从Next循环中删除记录。如果P5的OPFLAG_SAVEPOSITION位清零,则光标将保持未定义状态。如果在P5上设置OPFLAG_AUXDELETE位,则表示删除与删除表行及其所有相关索引条目相关的几个中的一个。其中的一个删除是“主要”删除。其他的都在OPFLAG_FORDELETE游标上,或者用AUXDELETE标志标记。如果设置了P2(NB:P2不是P5)的OPFLAG_NCHANGE标志,那么行更改计数会增加(否则不会)。P1不能是伪表。它必须是具有多行的真实表格。如果P4不是NULL,则它指向一个Table对象。在这种情况下,可以调用更新或更新前的钩子,或者两者都可以。在这种情况下,在调用此操作码之前,必须使用NotFound定位P1游标。特别是,如果配置了一个,如果P4不是NULL,则会调用更新前的挂钩。如果配置了更新钩子,则会调用更新挂钩,P4不为NULL,并且在P2中设置OPFLAG_NCHANGE标志。如果在P2中设置了OPFLAG_ISUPDATE标志,则P3包含存储单元的地址,该地址包含该行的rowid将被更新设置为的值。如果P4不是NULL,则它指向一个Table对象。在这种情况下,可以调用更新或更新前的钩子,或者两者都可以。在这种情况下,在调用此操作码之前,必须使用NotFound定位P1游标。特别是,如果配置了一个,如果P4不为NULL,则会调用更新前的钩子。如果配置了更新钩子,则会调用更新挂钩,P4不为NULL,并且在P2中设置OPFLAG_NCHANGE标志。如果在P2中设置了OPFLAG_ISUPDATE标志,则P3包含存储单元的地址,该地址包含该行的rowid将被更新设置为的值。如果P4不是NULL,则它指向一个Table对象。在这种情况下,可以调用更新或更新前的钩子,或者两者都可以。在这种情况下,在调用此操作码之前,必须使用NotFound定位P1游标。特别是,如果配置了一个,如果P4不是NULL,则会调用更新前的挂钩。如果配置了更新钩子,则会调用更新挂钩,P4不为NULL,并且在P2中设置OPFLAG_NCHANGE标志。如果在P2中设置了OPFLAG_ISUPDATE标志,则P3包含存储单元的地址,该地址包含该行的rowid将被更新设置为的值。如果P4不是NULL,则会调用更新前的钩子。如果配置了更新钩子,则会调用更新挂钩,P4不为NULL,并且在P2中设置OPFLAG_NCHANGE标志。如果在P2中设置了OPFLAG_ISUPDATE标志,则P3包含存储单元的地址,该地址包含该行的rowid将被更新设置为的值。如果P4不是NULL,则会调用更新前的钩子。如果配置了更新挂钩,则会调用更新挂钩,P4不为NULL,并且在P2中设置OPFLAG_NCHANGE标志。如果在P2中设置了OPFLAG_ISUPDATE标志,则P3包含存储单元的地址,该地址包含该行的rowid将被更新设置为的值。 |
破坏 | 删除数据库文件中的根页面由P1给出的整个数据库表或索引。如果P3 == 0,被销毁的表位于主数据库文件中。如果P3 == 1,则要清除的表位于用于存储表的辅助数据库文件中,使用CREATE TEMPORARY TABLE创建。如果启用AUTOVACUUM,则可能会将另一个根页面移动到新删除的根页面中,以便将所有的根页面连接在数据库的开头。移动的根页面的前一个值(移动发生前的值)存储在寄存器P2中。如果不需要页面移动(因为被删除的表已经是数据库中的最后一个),则将零存储在寄存器P2中。如果AUTOVACUUM被禁用,则零点被存储在寄存器P2中。如果有任何活动的读取器虚拟机被调用,此操作码会引发错误。这样做是为了避免当在AUTOVACUUM数据库中移动根页面时更新现有游标的困难。即使数据库不是AUTOVACUUM数据库,也会引发此错误,以避免在autovacuum和非autovacuum模式之间引入不兼容。另请参阅:清除 |
划分 | 将寄存器P1中的值除以寄存器P2中的值,并将结果存储到寄存器P3中(P3 = P2 / P1)。如果寄存器P1中的值为零,则结果为NULL。如果任一输入为NULL,则结果为NULL。 |
DropIndex | 删除描述数据库P1中名为P4的索引的内部(内存中)数据结构。这是在从磁盘中删除索引(使用销毁操作码)之后调用的,以便使架构的内部表示与磁盘上的内容保持一致。 |
DROPTABLE | 删除描述数据库P1中名为P4的表的内部(内存中)数据结构。这是在从磁盘中删除一个表(使用Destroy操作码)之后调用的,以便使架构的内部表示与磁盘上的内容保持一致。 |
DropTrigger | 删除描述数据库P1中名为P4的触发器的内部(内存中)数据结构。这是在从磁盘中删除触发器(使用Destroy操作码)之后调用的,以便使架构的内部表示与磁盘上的内容保持一致。 |
ElseNotEq | 该操作码必须紧跟在Lt或Gt比较操作符后面。如果相同两个操作数的Eq比较结果为NULL或false(0),则跳转到P2。如果前两个操作数的Eq比较的结果是真的(1),则通过。 |
EndCoroutine | 寄存器P1中地址的指令是一个收益率。跳转到该收益率的P2参数。跳转后,寄存器P1变得不确定。另请参阅:InitCoroutine |
公式 | 比较寄存器P1和P3中的值。如果reg(P3)== reg(P1)则跳转到地址P2。或者如果在P5中设置了SQLITE_STOREP2标志,则将比较结果存储在寄存器P2中。P5的SQLITE_AFF_MASK部分必须是亲和性字符 - SQLITE_AFF_TEXT,SQLITE_AFF_INTEGER等等。在进行比较之前,试图根据这种相似性强制两个输入。如果SQLITE_AFF_MASK是0x00,则使用数字亲缘关系。请注意,亲和转换被存回输入寄存器P1和P3。所以这个操作码可能会导致寄存器P1和P3的持续变化。一旦发生任何转换,且两个值都不为NULL,则会比较这些值。如果两个值都是斑点,则使用memcmp()来确定比较结果。如果两个值都是文本,然后使用P4中指定的适当的整理功能进行比较。如果未指定P4,则使用memcmp()来比较文本字符串。如果两个值都是数字,则使用数字比较。如果这两个值的类型不同,则认为数字小于字符串,字符串被认为小于blob。如果SQLITE_NULLEQ在P5中设置,那么比较结果总是为真或为假,并且从不为NULL。如果两个操作数均为NULL,则比较结果为true。如果任一操作数为NULL,则结果为false。如果两个操作数都不为NULL,则结果与从P5中省略SQLITE_NULLEQ标志的结果相同。如果同时设置了SQLITE_STOREP2和SQLITE_KEEPNULL标志,则只有在新值为NULL或0(false)时才会更改rP2的内容。换一种说法, |
到期 | 导致预编译语句过期。当使用sqlite3_step()执行过期语句时,它会自动重新自我表示(如果它最初是使用sqlite3_prepare_v2()创建的),否则将失败并显示SQLITE_SCHEMA。如果P1为0,则所有SQL语句都将过期。如果P1不为零,则只有当前执行的语句过期。 |
FkCounter | P2增加一个“约束计数器”(P2可能是负值或正值)。如果P1不为零,则数据库约束计数器递增(延迟的外键约束)。否则,如果P1为零,则语句计数器递增(即时外键约束)。 |
FkIfZero | 此操作码测试外键约束计数器当前是否为零。如果是,跳转到指令P2。否则,转到下一条指令。如果P1不为零,那么如果数据库约束计数器为零(计算延迟约束违规的计数器),则跳转被执行。如果P1为零,如果语句约束计数器为零(即时外键约束违规),则执行跳转。 |
发现 | 如果P4 == 0,则寄存器P3保存由MakeRecord构造的blob。如果P4> 0,那么寄存器P3是P4寄存器中的第一个,它们构成一个未包装的记录。游标P1在索引树上。如果由P3和P4标识的记录是P1中任何条目的前缀,则跳转到P2并且P1被指向匹配条目。该操作使光标处于可向前推进的状态。下一条指令将工作,但不是上一条指令。另请参阅:NotFound,NoConflict,NotExists。SeekGe |
功能 | 调用用户函数(P4是指向包含指向要运行的函数的指针的sqlite3_context对象的指针),并使用从寄存器P2和后继生成的P5参数。该功能的结果存储在寄存器P3中。寄存器P3不能是功能输入之一。P1是一个32位的位掩码,指示函数的每个参数是否在编译时被确定为常量。如果第一个参数是常量,则P1的位0被设置。这用于确定是否可以安全地保留使用sqlite3_set_auxdata()API与用户函数参数关联的元数据,直到下次调用此操作码。SQL函数最初编码为Function0,P4指向一个FuncDef对象。但在第一次评估时,P4操作数会自动转换为sqlite3_context对象,并将操作更改为此函数操作码。这样,sqlite3_context对象的初始化只发生一次,而不是每次评估函数一次。另请参阅:函数0,AggStep,AggFinal |
Function0 | 调用一个用户函数(P4是一个指向定义该函数的FuncDef对象的指针),P5参数取自寄存器P2和后继。函数的结果存储在寄存器P3中。寄存器P3不能是功能输入之一。P1是一个32位的位掩码,指示函数的每个参数是否在编译时被确定为常量。如果第一个参数是常量,则P1的位0被设置。这用于确定是否可以安全地保留使用sqlite3_set_auxdata()API与用户函数参数关联的元数据,直到下次调用此操作码。另请参阅:函数,AggStep,AggFinal |
Ge | 这与Lt操作码一样工作,只是如果寄存器P3的内容大于或等于寄存器P1的内容就会跳转。请参阅Lt操作码了解更多信息。 |
GOSUB | 将当前地址写入寄存器P1,然后跳转到地址P2。 |
去 | 无条件跳转到地址P2。执行的下一条指令将是从程序开始的索引P2处的指令。这个操作码实际上并未使用P1参数。但是,它有时设置为1而不是0作为命令行shell的提示,即此Goto是循环的底部,并且P2至当前行的行应该缩进EXPLAIN输出。 |
GT | 这与Lt操作码一样工作,只是如果寄存器P3的内容大于寄存器P1的内容就会跳转。请参阅Lt操作码了解更多信息。 |
停止 | 立即退出。所有打开的游标等都会自动关闭。P1是sqlite3_exec(),sqlite3_reset()或sqlite3_finalize()返回的结果代码。对于正常停顿,这应该是SQLITE_OK(0)。对于错误,它可以是其他值。如果P1!= 0,则P2将决定是否回滚当前事务。如果P2 == OE_Fail不回滚。如果P2 == OE_Rollback,则执行回滚。如果P2 == OE_Abort,则退出执行VDBE期间发生的所有更改,但不要回滚事务。如果P4不为空,那么它是一个错误消息字符串。P5是一个介于0和4之间(包括0和4)的值,用于修改P4字符串。0:(无变化)1:NOT NULL约束失败:P4 2:UNIQUE约束失败:P4 3:CHECK约束失败:P4 4:FOREIGN KEY约束失败:P4如果P5不为零且P4为NULL,那么“:”之后的所有内容都将被省略。在每个程序的最后插入一个隐含的“Halt 0 0 0”指令。所以跳过程序的最后一条指令就像执行中止一样。 |
HaltIfNull | 检查寄存器P3中的值。如果它是NULL,则暂停使用参数P1,P2和P4,就好像这是一个暂停指令。如果寄存器P3中的值不是NULL,那么这个例程是空操作。P5参数应该是1。 |
IdxDelete | 从寄存器P2开始的P3寄存器的内容形成一个未包装的索引键。该操作码从由光标P1打开的索引中删除该条目。 |
IdxGE | 以P3开头的P4寄存器值形成一个未包装的索引键,省略了PRIMARY KEY。将此键值与P1当前指向的索引进行比较,忽略末尾的PRIMARY KEY或ROWID字段。如果P1索引条目大于或等于键值,则跳转到P2。否则,直到下一条指令。 |
IdxGT | 以P3开头的P4寄存器值形成一个未包装的索引键,省略了PRIMARY KEY。将此键值与P1当前指向的索引进行比较,忽略末尾的PRIMARY KEY或ROWID字段。如果P1索引条目大于键值,则跳转到P2。否则,直到下一条指令。 |
IdxInsert | 寄存器P2保存使用MakeRecord指令创建的SQL索引键。该操作码将该密钥写入索引P1。该条目的数据为零。如果P4不为零,则它是reg(P2)的解压缩密钥中的值的数量。在这种情况下,P3是解压缩密钥的第一个寄存器的索引。解压密钥的可用性有时可能是一种优化。如果P5设置了OPFLAG_APPEND位,则这是向b-tree层提示该插入可能是附加的。如果P5设置了OPFLAG_NCHANGE位,则更改计数器将按照该指令递增。如果OPFLAG_NCHANGE位清零,则更改计数器保持不变。如果设置了P5的OPFLAG_USESEEKRESULT标志,则通过避免在光标P1上进行不必要的查找,实现可能运行得更快。然而,OPFLAG_USESEEKRESULT标志只有在光标上没有事先查询或者最近一次查找使用与P2等效的键时才能被设置。该指令仅适用于指数。表格的等效指令是Insert。 |
IdxLE | 以P3开头的P4寄存器值形成一个未包装的索引键,省略了PRIMARY KEY或ROWID。将此键值与P1当前指向的索引进行比较,忽略P1索引上的PRIMARY KEY或ROWID。如果P1索引条目小于或等于键值,则跳转到P2。否则,直到下一条指令。 |
IdxLT | 以P3开头的P4寄存器值形成一个未包装的索引键,省略了PRIMARY KEY或ROWID。将此键值与P1当前指向的索引进行比较,忽略P1索引上的PRIMARY KEY或ROWID。如果P1索引条目小于键值,则跳转到P2。否则,直到下一条指令。 |
IdxRowid | 在寄存器P2中写入一个整数,该整数是光标P1指向的索引关键字末尾记录中的最后一个条目。此整数应该是此索引条目指向的表项的rowid。另请参阅:Rowid,MakeRecord。 |
如果 | 如果寄存器P1中的值为真,则跳转到P2。如果数值为非零值,则认为该值为真。如果P1中的值为NULL,则当且仅当P3不为零时才跳转。 |
如果不 | 如果寄存器P1中的值为False,则跳转到P2。如果数值为零,则该值被视为false。如果P1中的值为NULL,则当且仅当P3不为零时才跳转。 |
IfNotZero | 寄存器P1必须包含一个整数。如果寄存器P1的内容最初大于零,则将寄存器P1中的值减1。如果它不是零(负值或正值),然后也跳到P2。如果寄存器P1初始为零,则保持不变并通过。 |
IfNullRow | 检查游标P1以查看它是否当前指向NULL行。如果是,则将寄存器P3设置为NULL并立即跳转到P2。如果P1不在NULL行上,则不做任何更改。 |
IfPos | 寄存器P1必须包含一个整数。如果寄存器P1的值为1或更大,则从P1中的值减去P3并跳转到P2。如果寄存器P1的初始值小于1,则该值不变并且控制权转到下一条指令。 |
IfSmaller | 估计表格P1中的行数。如果估计值小于2 **(0.1 * P3),则跳至P2。 |
IncrVacuum | 在P1数据库上执行增量真空程序的单个步骤。如果真空完成,跳转到指令P2。否则,转到下一条指令。 |
在里面 | 程序包含此操作码的单个实例作为第一个操作码。如果启用了跟踪(通过sqlite3_trace())接口,则包含在P4中的UTF-8字符串将在跟踪回调中发出。或者如果P4空白,使用sqlite3_sql()返回的字符串。如果P2不为零,则跳转到指令P2。增加P1的值,以便一次操作码在第一次对此运行进行评估时跳转。如果P3不为零,那么如果遇到SQLITE_CORRUPT错误,它就是要跳转到的地址。 |
InitCoroutine | 设置寄存器P1,使其产生到位于地址P3的协程。如果P2!= 0,那么协程执行紧跟在这个操作码之后。所以跳过协程实现来解决P2。另请参阅:EndCoroutine |
插 | 在游标P1的表格中写入一个条目。如果一个新条目不存在或者现有条目的数据被覆盖,则创建一个新条目。该数据是存储在寄存器号P2中的值MEM_Blob。密钥存储在寄存器P3中。密钥必须是MEM_Int。如果P5的OPFLAG_NCHANGE标志置位,则行更改计数递增(否则)。如果设置了P5的OPFLAG_LASTROWID标志,则存储rowid以供sqlite3_last_insert_rowid()函数的后续返回(否则它未被修改)。如果设置了P5的OPFLAG_USESEEKRESULT标志,则通过避免在光标P1上进行不必要的查找,实现可能运行得更快。但是,只有在光标上没有事先查询或者最近一次查找使用的键等于P3时,才能设置OPFLAG_USESEEKRESULT标志。如果OPFLAG_ISUPDATE标志被设置,那么这个操作码是UPDATE操作的一部分。否则(如果标志清除),那么这个操作码是INSERT操作的一部分。这个区别只对更新钩子很重要。参数P4可能指向一个Table结构,或者可能是NULL。如果它不是NULL,则在成功插入后调用update-hook(sqlite3.xUpdateCallback)。(WARNING / TODO:如果P1是伪游标并且P2是动态分配的,则P2的所有权转移到伪游标,并且寄存器P2变为短暂的,如果光标改变,则寄存器P2的值将改变。确保这不会导致任何问题。)该指令仅适用于表格。索引的等价指令是IdxInsert。这个区别只对更新钩子很重要。参数P4可能指向一个Table结构,或者可能是NULL。如果它不是NULL,则在成功插入后调用update-hook(sqlite3.xUpdateCallback)。(WARNING / TODO:如果P1是伪游标并且P2是动态分配的,则P2的所有权转移到伪游标,并且寄存器P2变为短暂的,如果光标改变,则寄存器P2的值将改变。确保这不会导致任何问题。)该指令仅适用于表格。索引的等价指令是IdxInsert。这个区别只对更新钩子很重要。参数P4可能指向一个Table结构,或者可能是NULL。如果它不是NULL,则在成功插入后调用update-hook(sqlite3.xUpdateCallback)。(WARNING / TODO:如果P1是伪游标并且P2是动态分配的,则P2的所有权转移到伪游标,并且寄存器P2变为短暂的,如果光标改变,则寄存器P2的值将改变。确保这不会导致任何问题。)该指令仅适用于表格。索引的等价指令是IdxInsert。如果P1是伪游标并且P2是动态分配的,则P2的所有权转移到伪游标,并且寄存器P2变为短暂的。如果光标改变,寄存器P2的值将会改变。确保这不会导致任何问题。)该指令仅适用于表格。索引的等价指令是IdxInsert。如果P1是伪游标并且P2是动态分配的,则P2的所有权转移到伪游标,并且寄存器P2变为短暂的。如果光标改变,寄存器P2的值将会改变。确保这不会导致任何问题。)该指令仅适用于表格。索引的等价指令是IdxInsert。 |
InsertInt | 这与Insert完全相同,只是键是整数值P3,而不是存储在寄存器P3中的整数值。 |
Int64的 | P4是一个指向64位整数值的指针。将该值写入寄存器P2。 |
IntCopy | 将保存在寄存器P1中的整数值传送到寄存器P2中。这是SCopy的优化版本,仅适用于整数值。 |
整数 | 32位整数值P1被写入寄存器P2。 |
IntegrityCk | 对当前打开的数据库进行分析。在寄存器P1中存储描述任何问题的错误消息文本。如果没有发现问题,则在寄存器P1中存储一个NULL。寄存器P3包含一个比允许的错误的最大数量少的一个。大部分注册(P3)错误都会被报告。换句话说,只要发现reg(P1)错误,分析就会停止。Reg(P1)更新为剩余的错误数量。数据库中所有表的根页码是存储在P4_INTARRAY参数中的整数。如果P5不为零,则检查在辅助数据库文件上完成,而不是在主数据库文件上完成。该操作码用于实现integrity_check编译指示。 |
一片空白 | 如果寄存器P1中的值为NULL,则跳转到P2。 |
JournalMode | 将数据库P1的日记模式更改为P3。P3必须是PAGER_JOURNALMODE_XXX值之一。如果在各种回滚模式(删除,截断,持续,关闭和内存)之间切换,这是一个简单的操作。不需要IO。如果换入或退出WAL模式,程序会更复杂。写一个包含最终日志模式的字符串来注册P2。 |
跳 | 取决于在最近的比较指令中P1矢量是小于等于还是大于P2矢量,跳转到地址P1,P2或P3的指令。 |
持续 | P1的Rowid或Column或Prev指令的下一次使用将引用数据库表或索引中的最后一项。如果表或索引为空且P2> 0,则立即跳至P2。如果P2为0或者表或索引不为空,则转至以下指令。该操作码将光标配置为按照相反的顺序移动,从末端开始。换句话说,游标被配置为使用Prev,而不是Next。 |
Le | 这与Lt操作码一样工作,只是如果寄存器P3的内容小于或等于寄存器P1的内容,则会跳转。请参阅Lt操作码了解更多信息。 |
LoadAnalysis | 读取数据库P1的sqlite_stat1表并将该表的内容加载到内部索引散列表中。这将导致在准备所有后续查询时使用分析。 |
£ | 比较寄存器P1和P3中的值。如果reg(P3)<reg(P1),则跳转到地址P2。或者如果在P5中设置了SQLITE_STOREP2标志,则将比较结果(0或1或NULL)存储到寄存器P2中。如果P5的SQLITE_JUMPIFNULL位置1并且reg(P1)或reg(P3)为NULL,则跳转。如果SQLITE_JUMPIFNULL位清零,则如果任一操作数为NULL,则通过该位。P5的SQLITE_AFF_MASK部分必须是亲和性字符 - SQLITE_AFF_TEXT,SQLITE_AFF_INTEGER等等。在进行比较之前,试图根据这种相似性强制两个输入。如果SQLITE_AFF_MASK是0x00,则使用数字亲缘关系。请注意,亲和转换被存回输入寄存器P1和P3。所以这个操作码可能会导致寄存器P1和P3的持续变化。一旦发生任何转换,并且两个值都不是NULL,则会比较这些值。如果两个值都是斑点,则使用memcmp()来确定比较结果。如果两个值均为文本,则使用P4中指定的适当的整理函数进行比较。如果未指定P4,则使用memcmp()来比较文本字符串。如果两个值都是数字,则使用数字比较。如果这两个值的类型不同,则认为数字小于字符串,字符串被认为小于blob。如果两个值都是数字,则使用数字比较。如果这两个值的类型不同,则认为数字小于字符串,字符串被认为小于blob。如果两个值都是数字,则使用数字比较。如果这两个值的类型不同,则认为数字小于字符串,字符串被认为小于blob。 |
MakeRecord | 将从P1开始的P2寄存器转换为记录格式,用作数据库表中的数据记录或索引中的键。列操作码可以稍后解码记录。P4可能是一个长度为P2的字符串。字符串的第N个字符指示应该用于索引关键字的第N个字段的列关联。从字符到关联的映射由sqliteInt.h中定义的SQLITE_AFF_宏给出。如果P4为NULL,则所有索引字段都具有亲和性BLOB。 |
MaxPgcnt | 尝试将数据库P1的最大页数设置为P3中的值。不要让最大页数低于当前页数,并且不要更改P3 == 0时的最大页数。将更改后的最大页数存储在寄存器P2中。 |
MemMax | P1是该VM根框架中的寄存器(如果在子程序中执行该指令,则根框架与当前框架不同)。将寄存器P1的值设置为当前值的最大值和寄存器P2中的值。如果存储单元最初不是整数,则该指令会引发错误。 |
移动 | 将寄存器P1..P1 + P3-1中的P3值移入寄存器P2..P2 + P3-1。寄存器P1..P1 + P3-1保留NULL。寄存器范围P1..P1 + P3-1和P2..P2 + P3-1重叠是错误的。P3小于1是错误的。 |
乘 | 将寄存器P1中的值乘以寄存器P2中的值,并将结果存储在寄存器P3中。如果任一输入为NULL,则结果为NULL。 |
MustBeInt | 强制寄存器P1中的值为整数。如果P1中的值不是整数并且不能在没有数据丢失的情况下转换为整数,则立即跳转到P2,或者如果P2 == 0引发SQLITE_MISMATCH异常。 |
不 | 这与Eq操作码一样工作,只是如果寄存器P1和P3中的操作数不相等,则会跳转。请参阅Eq操作码了解更多信息。如果同时设置了SQLITE_STOREP2和SQLITE_KEEPNULL标志,则只有在新值为NULL或1(真)时,才会更改rP2的内容。换句话说,先前的rP2值不会被0(假)覆盖。 |
NewRowid | 获取用作表的关键字的新整数记录号(又名“rowid”)。记录号先前未用作游标P1指向的数据库表中的键。新的记录号码被写入寄存器P2。如果P3> 0,则P3是该VDBE的根帧中的寄存器,该寄存器保存先前生成的最大记录编号。没有新的记录号码被允许小于这个值。当此值达到其最大值时,会生成SQLITE_FULL错误。P3寄存器用'生成的记录号码更新。这个P3机制用于帮助实现AUTOINCREMENT功能。 |
下一个 | 提前移动光标P1,使其指向表格或索引中的下一个键/数据对。如果没有更多的键/值对,则转到以下指令。但是如果光标前进成功,立即跳转到P2。Next操作码仅在用于定位光标的SeekGT,SeekGE或Rewind操作码之后有效。接下来不允许关注SeekLT,SeekLE或Last。P1游标必须用于真实表格,而不是伪表格。P1必须在这个操作码之前打开,否则程序会出错。P3值是btree实现的提示。如果P3 == 1,这意味着P1是一个SQL索引,并且如果该索引是唯一的,则可以省略该指令。P3通常为0. P3总是为0或1. P4总是P4_ADVANCE类型。函数指针指向sqlite3BtreeNext()。如果P5为正值并跳转,则准备语句中的事件计数器编号P5-1将递增。另请参阅:Prev,NextIfOpen |
NextIfOpen | 这个操作码就像Next一样工作,只是如果光标P1没有打开,它就表现为无操作。 |
NoConflict | 如果P4 == 0,则寄存器P3保存由MakeRecord构造的blob。如果P4> 0,那么寄存器P3是P4寄存器中的第一个,它们构成一个未包装的记录。游标P1在索引树上。如果由P3和P4标识的记录包含任何空值,则立即跳转到P2。如果记录的所有条款都不是NULL,则执行检查以确定P1索引btree中的任何行是否具有匹配的关键字前缀。如果没有匹配,立即跳到P2。如果存在匹配,则跳过并将P1光标指向匹配的行。这个操作码与NotFound相似,除了在搜索关键字输入的任何部分为NULL时总是采用分支。该操作使光标处于无法向任一方向前进的状态。换句话说,在此操作之后,Next和Prev操作码不起作用。也可以看看: |
空操作 | 没做什么。这条指令通常用作跳转目标。 |
不 | 将寄存器P1中的值解释为布尔值。将布尔补码存储在寄存器P2中。如果寄存器P1中的值为NULL,则在P2中存储NULL。 |
不存在 | P1是在SQL表btree(带整数键)上打开的游标的索引。P3是一个整数rowid。如果P1不包含rowid P3的记录,则立即跳至P2。或者,如果P2为0,则引发SQLITE_CORRUPT错误。如果P1确实包含rowid P3的记录,则将光标指向该记录并落入下一条指令。SeekRowid操作码执行相同的操作,但也允许P3寄存器包含一个非整数值,在这种情况下跳转总是被采用。这个操作码要求P3总是包含一个整数。NotFound操作码在索引btree上执行相同的操作(使用任意多值键)。该操作码将光标置于无法在任一方向上前进的状态。换句话说,在此操作码之后,Next和Prev操作码将不起作用。另见:Found,NotFound, |
未找到 | 如果P4 == 0,则寄存器P3保存由MakeRecord构造的blob。如果P4> 0,那么寄存器P3是P4寄存器中的第一个,它们构成一个未包装的记录。游标P1在索引树上。如果由P3和P4标识的记录不是P1中任何条目的前缀,则跳转到P2。如果P1包含一个前缀与P3 / P4记录匹配的条目,则控制转入下一条指令,并且P1指向匹配的条目。该操作使光标处于无法向任一方向前进的状态。换句话说,在此操作之后,Next和Prev操作码不起作用。另见:Found,NotExists,NoConflict |
NOTNULL | 如果寄存器P1中的值不是NULL,则跳转到P2。 |
空值 | 写一个NULL到寄存器P2。如果P3大于P2,则还要将NULL写入寄存器P3以及P2和P3之间的每个寄存器。如果P3小于P2(通常P3为零),则只有寄存器P2被设置为NULL。如果P1值不为零,那么还要设置MEM_Cleared标志,以便即使在Ne或Eq上设置了SQLITE_NULLEQ,NULL值也不会相等。 |
NullRow | 将光标P1移至空行。游标位于空行上时发生的任何列操作将始终写入NULL。 |
OffsetLimit | 该操作码执行与LIMIT和OFFSET过程相关的常用计算。rP1拥有限制计数器。rP3保存偏移计数器。操作码计算LIMIT和OFFSET的组合值,并将该值存储在rP2中。计算的rP2值是完成查询需要访问的总行数。如果rP3为零或负数,则表示没有OFFSET,且rP2设置为LIMIT的值rP1。如果rP1为零或负值,则表示没有LIMIT且rP2设置为-1。否则,rP2被设置为rP1和rP3之和。 |
一旦 | 在每次调用字节码程序时第一次遇到此操作码时,转到下一条指令。在同一次调用期间,在第二次和所有后续遇到的情况下跳转到P2。顶层程序通过将P1操作数与程序开始处的Init操作码上的P1操作数进行比较来确定第一次调用。如果P1值不同,则通过并使该操作码的P1等于Init的P1。如果P1值相同,则跳转。对于子程序,VdbeFrame中有一个位掩码,用于确定是否应该进行跳转。位掩码是必要的,因为自变更代码技巧不适用于递归触发器。 |
OpenAutoindex | 这个操作码和OpenEphemeral一样。它有一个不同的名称来区分它的用途。使用此操作码创建的表格将用于连接中自动创建的瞬态索引。 |
OpenDup | 打开一个新的光标P1,指向与光标P2相同的临时表。P2游标必须已经被之前的OpenEphemeral操作码打开。只有短暂的光标可能会重复。重复的短暂游标用于物化视图的自连接。 |
OpenEphemeral | 打开一个新的光标P1到一个瞬态表。即使主数据库是只读的,光标始终以读/写方式打开。当光标关闭时,临时表会自动删除。P2是临时表中的列数。如果P4 == 0,则光标指向BTree表;如果P4不为0,则指向BTree索引。如果P4不为NULL,则它指向一个KeyInfo结构,该结构定义索引中的键的格式。P5参数可以是btree.h中定义的BTREE_ *标志的掩码。这些标志控制btree的操作方面。BTREE_OMIT_JOURNAL和BTREE_SINGLE标志会自动添加。 |
OpenPseudo | 打开一个指向包含单行数据的假表的新光标。该行的内容是存储器寄存器P2的内容。换句话说,光标P1成为寄存器P2中包含的MEM_Blob内容的别名。由此操作码创建的伪表格用于保存分类程序的单个行输出,以便可以使用列操作码将该行分解为单独的列。Column操作码是与伪表一起使用的唯一游标操作码。P3是将由伪表存储的记录中的字段数。 |
打开读取 | 为数据库文件中的根页面为P2的数据库表打开只读游标。数据库文件由P3确定。P3 == 0表示主数据库,P3 == 1表示用于临时表的数据库,P3> 1表示使用相应的附加数据库。给新的光标一个P1的标识符。P1值不必是连续的,但所有的P1值都应该是小整数。P1是负面的错误。如果P5!= 0,则使用寄存器P2的内容作为根页面,而不是P2本身的值。只要有一个打开的光标,数据库就会有一个读锁定。如果在该指令之前数据库被解锁,那么作为该指令的一部分获取读锁。读锁允许其他进程读取数据库,但禁止其他进程修改数据库。当所有游标关闭时,读锁定被释放。如果此指令尝试获取读取锁但失败,则脚本将以SQLITE_BUSY错误代码终止。P4值可以是整数(P4_INT32)或指向KeyInfo结构的指针(P4_KEYINFO)。如果它是指向KeyInfo结构的指针,则所述结构定义打开的索引的内容和整理顺序。否则,如果P4是整数值,则将其设置为表中的列数。另请参阅:OpenWrite,ReopenIdx 那么所述结构定义打开索引的内容和整理顺序。否则,如果P4是整数值,则将其设置为表中的列数。另请参阅:OpenWrite,ReopenIdx 那么所述结构定义打开索引的内容和整理顺序。否则,如果P4是整数值,则将其设置为表中的列数。另请参阅:OpenWrite,ReopenIdx |
OpenWrite | 在根页面为P2的表或索引上打开名为P1的读/写游标。或者如果P5!= 0使用寄存器P2的内容来查找根页面。P4值可以是整数(P4_INT32)或指向KeyInfo结构的指针(P4_KEYINFO)。如果它是指向KeyInfo结构的指针,则所述结构定义打开的索引的内容和整理顺序。否则,如果P4是一个整数值,则将其设置为表中的列数或实际使用的表中任何列的最大索引。该指令的工作原理与OpenRead类似,不同之处在于它以读/写模式打开光标。对于给定的表,可以有一个或多个只读游标或单个读/写游标,但不能同时包含两者。另请参阅OpenRead。 |
要么 | 取寄存器P1和P2中的值的逻辑或,并将答案存储在寄存器P3中。如果P1或P2非零(真),那么即使其他输入为NULL,结果也为1(真)。NULL和false或两个NULL给出一个NULL输出。 |
页页次 | 将数据库P1中的当前页数写入存储单元P2。 |
PARAM | 此操作码只存在于通过程序指令调用的子程序中。将当前存储在调用(父)帧的存储单元中的值复制到当前帧地址空间中的单元P2。这由触发器程序用于访问新的。*和旧的*值。父框架中单元格的地址是通过将P1参数的值添加到调用的程序指令的P1参数值来确定的。 |
ParseSchema | 读取并解析数据库P1的SQLITE_MASTER表中与WHERE子句P4匹配的所有条目。这个操作码调用解析器创建一个新的虚拟机,然后运行新的虚拟机。因此它是一个重入操作码。 |
排列 | 在下一条指令中设置比较运算符使用的排列。置换被存储在P4操作数中。只有在P5中设置了OPFLAG_PERMUTE位的下一个比较之后,置换才有效。通常,排列应该在比较之前立即发生。P4整数数组中的第一个整数是数组的长度,不会成为置换的一部分。 |
上一页 | 备份光标P1,使其指向表或索引中的上一个键/数据对。如果没有以前的键/值对,则转到以下指令。但是如果光标备份成功,立即跳到P2。Prev操作码仅在用于定位光标的SeekLT,SeekLE或Last操作码之后有效。上一个不允许关注SeekGT,SeekGE或后退。P1游标必须用于真实表格,而不是伪表格。如果P1未打开,则行为未定义。P3值是btree实现的提示。如果P3 == 1,这意味着P1是一个SQL索引,并且如果该索引是唯一的,则可以省略该指令。P3通常为0. P3总是为0或1. P4总是P4_ADVANCE类型。函数指针指向sqlite3BtreePrevious()。如果P5是正数并跳转, |
PrevIf打开 | 这个操作码就像Prev一样工作,只是如果光标P1没有打开,它就表现为无操作。 |
程序 | 执行以P4形式传递的触发程序(键入P4_SUBPROGRAM)。P1包含内存单元的地址,该单元包含用作子程序参数的值数组中的第一个内存单元。如果子程序使用RAISE()函数抛出IGNORE异常,则P2包含要跳转到的地址。寄存器P3包含此(父)VM中的存储器单元的地址,用于在运行时分配sub-vdbe所需的存储器。P4是指向包含触发程序的虚拟机的指针。如果P5不为零,则启用递归程序调用。 |
读取Cookie | 从数据库P1读取cookie数字P3并将其写入寄存器P2。P3 == 1是模式版本。P3 == 2是数据库格式。P3 == 3是推荐的寻呼机高速缓存大小,等等。P1 == 0是主数据库文件,P1 == 1是用于存储临时表的数据库文件。在执行该指令之前,数据库必须有一个读锁(无论是必须启动一个事务还是必须打开游标)。 |
真实 | P4是一个指向64位浮点值的指针。将该值写入寄存器P2。 |
RealAffinity | 如果寄存器P1保存一个整数,则将其转换为实数值。从具有REAL关联性的列提取信息时使用此操作码。这样的列值仍然可以作为整数存储,以提高空间利用率,但是在提取之后,我们希望它们只有一个实际值。 |
余 | 计算整数寄存器P2除以寄存器P1后的余数,并将结果存储在寄存器P3中。如果寄存器P1中的值为零,则结果为NULL。如果任一操作数为NULL,则结果为NULL。 |
ReopenIdx | ReopenIdx操作码的工作方式与ReadOpen完全相同,不同之处在于它首先检查P1上的光标是否已经以P2的根页面编号打开,并且该操作码是否为空操作。换句话说,如果光标已经打开,请不要重新打开它。ReopenIdx操作码只能与P5 == 0一起使用,而P4是P4_KEYINFO对象。此外,对于相同的游标编号,P3值必须与每隔一个ReopenIdx或OpenRead相同。请参阅OpenRead操作码文档以获取更多信息。 |
ResetCount | 更改计数器的值被复制到数据库句柄更改计数器(由对sqlite3_changes()的后续调用返回)。然后,VM内部更改计数器重置为0.触发程序使用此值。 |
ResetSorter | 删除光标P1上打开的临时表或分拣机中的所有内容。此操作码仅适用于用于排序并使用OpenEphemeral或SorterOpen打开的游标。 |
ResultRow | 寄存器P1到P1 + P2-1包含一行结果。此操作码会导致sqlite3_step()调用以SQLITE_ROW返回码终止,并设置sqlite3_stmt结构以提供对r(P1).. r(P1 + P2-1)值作为结果行的访问权限。 |
返回 | 跳转到寄存器P1中的地址之后的下一条指令。跳转后,寄存器P1变得不确定。 |
倒带 | P1的Rowid或Column或Next指令的下一次使用将引用数据库表或索引中的第一个条目。如果表或索引为空,则立即跳至P2。如果表格或索引不是空的,请参阅以下说明。该操作码将光标配置为从开始到结束以正向顺序移动。换句话说,游标被配置为使用Next,而不是Prev。 |
RowData | 在寄存器P2中写入光标P1当前指向的行的完整行内容。没有数据的解释。它只是被复制到P2寄存器,就像它在数据库文件中找到的一样。如果游标P1是索引,则内容是该行的关键字。如果游标P2是表格,则提取的内容是数据。如果P1游标必须指向真实表的有效行(不是NULL行),而不是伪表。如果P3!= 0,则允许此操作码在数据库页面中生成一个ephermeral指针。这意味着一旦光标移动,输出寄存器的内容就会失效 - 包括其他游标引起的移动,这些游标会“保存”当前游标的位置,以便它们可以写入同一个表。如果P3 == 0,则将数据的副本存入内存。P3!= 0更快,但P3 == 0更安全。如果P3!= 0,则P2寄存器的内容不适合在OP_Result中使用,任何OP_Result都将使P2寄存器内容无效。P2寄存器的内容被诸如Function之类的操作码或任何使用指向同一个表的另一个光标的操作无效。 |
ROWID | 在寄存器P2中存储一个整数,该整数是P1当前指向的表项的关键字。P1可以是普通表或虚拟表。过去有一个独立的OP_VRowid操作码用于虚拟表,但是这一个操作码现在适用于两种表类型。 |
RowSetAdd | 将寄存器P2保存的整数值插入保存在寄存器P1中的RowSet对象。如果P2不是整数,则断言失败。 |
RowSetRead | 从P1中的RowSet对象中提取最小值并将该值存入寄存器P3。或者,如果RowSet对象P1初始为空,则保持P3不变并跳转到指令P2。 |
RowSetTest | 假设寄存器P3保存64位整数值。如果寄存器P1包含RowSet对象并且RowSet对象包含P3中保存的值,则跳转到寄存器P2。否则,将P3中的整数插入RowSet并继续到下一个操作码。RowSet对象针对整数集插入不同阶段(每个集不包含重复项)的情况进行了优化。每组由一个唯一的P4值标识。第一组必须具有P4 == 0,最终组必须具有P4 == -1,而对于所有其他组必须具有P4> 0。这允许优化:(a)当P4 == 0时,不需要为P3测试RowSet对象,因为它保证不包含它,(b)当P4 == -1时,不需要插入值,因为它永远不会被测试,并且(c)当插入集合X的一部分的值被插入时, |
保存点 | 根据P1的值打开,释放或回滚由参数P4命名的保存点。要打开一个新的保存点,P1 == 0。释放(提交)现有保存点P1 == 1或回滚现有保存点P1 == 2。 |
SCOPY | 将寄存器P1的浅拷贝写入寄存器P2。这条指令创建了一个值的浅表副本。如果该值是一个字符串或blob,那么该副本只是一个指向原始的指针,因此如果原始副本更改的话。更糟糕的是,如果原件被重新分配,副本将变为无效。因此,程序必须保证原件在复制期间不会改变。使用复制来制作完整的副本。 |
SeekEnd | 将光标P1定位在btree的结尾处,以便将新条目附加到btree上。假定游标仅用于追加,因此如果游标有效,则游标必须已经指向btree的末尾,因此不会对游标进行任何更改。 |
SeekGE | 如果游标P1引用SQL表(使用整数键的B树),则使用寄存器P3中的值作为键。如果游标P1引用SQL索引,则P3是P4寄存器阵列中的第一个,用作未解压缩的索引键。重新定位光标P1,使其指向大于或等于键值的最小条目。如果没有记录大于或等于键并且P2不为零,则跳转到P2。如果使用OPFLAG_SEEKEQ标志打开游标P1,则该操作码将始终落在等于该键的记录上,否则立即跳转到P2。当游标是OPFLAG_SEEKEQ时,这个操作码必须后跟一个具有相同参数的IdxLE操作码。如果此操作码成功,则会跳过IdxLE操作码,但是IdxLE操作码将在随后的循环迭代中使用。该操作码将光标配置为从开始到结束以正向顺序移动。换句话说,游标被配置为使用Next,而不是Prev。另见:Found,NotFound,SeekLt,SeekGt,SeekLe |
SeekGT | 如果游标P1引用SQL表(使用整数键的B树),则使用寄存器P3中的值作为键。如果游标P1引用SQL索引,则P3是P4寄存器阵列中的第一个,用作未解压缩的索引键。重新定位光标P1,使其指向大于键值的最小条目。如果没有记录大于该键并且P2不为零,则跳转到P2。该操作码将光标配置为从开始到结束以正向顺序移动。换句话说,游标被配置为使用Next,而不是Prev。另见:Found,Not Found,SeekLt,SeekGe,SeekLe |
SeekLE | 如果游标P1引用SQL表(使用整数键的B树),则使用寄存器P3中的值作为键。如果游标P1引用SQL索引,则P3是P4寄存器阵列中的第一个,用作未解压缩的索引键。重新定位光标P1,使其指向小于或等于键值的最大条目。如果没有小于或等于该键的记录并且P2不为零,则跳转到P2。该操作码将光标配置为按照相反的顺序移动,从末端开始。换句话说,游标被配置为使用Prev,而不是Next。如果使用OPFLAG_SEEKEQ标志打开游标P1,则该操作码将始终落在等于该键的记录上,否则立即跳转到P2。当光标是OPFLAG_SEEKEQ时,这个操作码必须后跟一个带相同参数的IdxGE操作码。如果此操作码成功,则会跳过IdxGE操作码,但IdxGE操作码将用于后续循环迭代。另见:Found,NotFound,SeekGt,SeekGe,SeekLt |
SeekLT | 如果游标P1引用SQL表(使用整数键的B树),则使用寄存器P3中的值作为键。如果游标P1引用SQL索引,则P3是P4寄存器阵列中的第一个,用作未解压缩的索引键。重新定位光标P1,使其指向小于键值的最大条目。如果没有记录少于该键并且P2不为零,则跳转到P2。该操作码将光标配置为按照相反的顺序移动,从末端开始。换句话说,游标被配置为使用Prev,而不是Next。另见:Found,NotFound,SeekGt,SeekGe,SeekLe |
SeekRowid | P1是在SQL表btree(带整数键)上打开的游标的索引。如果寄存器P3不包含整数,或者P1没有包含rowid P3的记录,则立即跳转到P2。或者,如果P2为0,则引发SQLITE_CORRUPT错误。如果P1确实包含rowid P3的记录,则将光标指向该记录并落入下一条指令。NotExists操作码执行相同的操作,但对于NotExists,P3寄存器必须保证包含一个整数值。通过此操作码,寄存器P3可能不包含整数。NotFound操作码在索引btree上执行相同的操作(使用任意多值键)。该操作码将光标置于无法在任一方向上前进的状态。换句话说,在此操作码之后,Next和Prev操作码将不起作用。另见:发现, |
序列 | 找到光标P1的下一个可用序列号。将序列号写入寄存器P2。此指令后,光标上的序列号会增加。 |
SequenceTest | P1是分拣机光标。如果序列计数器当前为零,则跳转到P2。无论是否进行跳转,都会增加序列值。 |
setCookie方法 | 将整数值P3写入数据库P1的cookie号码P2。P2 == 1是模式版本。P2 == 2是数据库格式。P2 == 3是推荐的寻呼机高速缓存大小,等等。P1 == 0是主数据库文件,P1 == 1是用于存储临时表的数据库文件。在执行这个操作码之前必须开始一个事务。 |
ShiftLeft | 将寄存器P2中的整数值向左移动寄存器P1中整数指定的位数。将结果存储在寄存器P3中。如果任一输入为NULL,则结果为NULL。 |
ShiftRight | 将寄存器P2中的整数值向右移动由寄存器P1中的整数指定的位数。将结果存储在寄存器P3中。如果任一输入为NULL,则结果为NULL。 |
SoftNull | 通过MakeRecord指令设置寄存器P1的值为NULL,但不释放任何与寄存器相关联的字符串或Blob内存,以便如果该值是之前使用SCopy复制的字符串或Blob,则副本将继续有效。 |
分类 | 这个操作码和Rewind完全一样,只是它增加了一个用于测试的未公开的全局变量。排序是通过将记录写入排序索引,然后倒回该索引并从头到尾回放来完成的。我们使用排序操作码而不是倒回来执行倒带,以便全局变量增加,回归测试可以确定优化器是否正确地优化排序。 |
比较排序 | P1是分拣机光标。该指令将寄存器P3中记录块的前缀与分类器光标当前指向的项的前缀进行比较。只有rP3的第一个P4字段和分拣机记录进行比较。如果P3或分拣机在其重要字段之一中包含NULL(不包括末尾被忽略的P4字段),则假定比较相等。如果两个记录的比较相等,则转入下一条指令。如果它们不同,则跳到P2。 |
数据排序 | 将分类器光标P1的当前分拣机数据写入寄存器P2。然后清除光标P3上的列标题缓存。该操作码通常用于将记录移出分拣机并存入一个寄存器,该寄存器是使用OpenPseudo创建的伪表游标的源。该伪表格光标是由参数P3标识的光标。清除P3列缓存作为此操作码的一部分,使我们不必发出单独的NullRow指令来清除该缓存。 |
SorterInsert | 寄存器P2保存使用MakeRecord指令创建的SQL索引键。该操作码将该密钥写入分拣机P1。该条目的数据为零。 |
排序下一页 | 除了P1必须是SorterSort操作码已被调用的分拣机对象之外,该操作码与Next类似。此操作码将光标移至下一个排序记录,或者如果没有更多排序记录,则跳转至P2。 |
排序打开 | 此操作代码的工作方式与OpenEphemeral相同,只不过它会打开一个临时索引,它专门用于使用外部合并排序算法对大型表进行排序。如果参数P3不为零,则表明分拣机可以假定考虑到每个关键字的第一个P3字段的稳定排序足以产生所需的结果。 |
排序黑色 | 在所有记录都插入P1标识的Sorter对象后,调用这个操作码实际进行排序。如果没有要排序的记录,则跳转到P2。此操作码是用于Sorter对象的Sort和Rewind的别名。 |
SQLEXEC | 运行P4字符串中指定的SQL语句或语句。 |
串 | 长度P1(字节)的字符串值P4被存储在寄存器P2中。如果P3不为零且寄存器P3的内容等于P5,则寄存器P2的数据类型被转换为BLOB。内容是相同的字节序列,它只是被解释为一个BLOB而不是一个字符串,就好像它是CAST。换句话说:if(P3!= 0和regP3 == P5)regP2:= CAST(regP2为BLOB) |
String8 | P4指向一个nul终止的UTF-8字符串。这个操作码在第一次被执行之前被转换成一个字符串操作码。在此转换期间,字符串P4的长度被计算并存储为P1参数。 |
减去 | 从寄存器P2的值中减去寄存器P1中的值,并将结果存储到寄存器P3中。如果任一输入为NULL,则结果为NULL。 |
TableLock | 获取特定表格上的锁定。该指令仅在启用共享缓存功能时使用。P1是获取锁的数据库的sqlite3.aDb []中的数据库的索引。如果P3 == 0,则获得读锁,或者如果P3 == 1,则获得写锁。P2包含要锁定的表的根页面。P4包含一个指向被锁定表的名字的指针。如果无法获取锁,则仅用于生成错误消息。 |
交易 | 如果事务尚未处于活动状态,请在数据库P1上开始事务。如果P2不为零,则写入事务将启动,或者如果读取事务已处于活动状态,则会将其升级为写入事务。如果P2为零,则开始读取事务。P1是开始事务的数据库文件的索引。索引0是主数据库文件,索引1是用于临时表的文件。2个或更多的索引用于连接的数据库。如果写入事务开始并且Vdbe.usesStmtJournal标志为真(如果Vdbe可能修改多行并可能引发ABORT异常,则设置此标志),也可以打开语句事务。更具体地说,如果数据库连接当前不处于自动提交模式,或者存在其他活动语句,则会打开语句事务。语句事务允许在发生错误后回滚此VDBE所做的更改,而无需回滚整个事务。如果没有遇到错误,语句事务将在VDBE暂停时自动提交。如果P5!= 0,那么这个操作码也检查针对P3的模式cookie和针对P4的模式生成计数器。每当数据库模式更改时,Cookie都会更改其值。此操作用于检测cookie何时发生更改以及当前进程是否需要重新读取模式。如果P3中的模式cookie与数据库头中的模式cookie不同,或者P4中的模式生成计数器与当前生成计数器不同,则会引发SQLITE_SCHEMA错误并停止执行。 |
真空 | 抽真空整个数据库P1。对于“主”,P1为0,对于附加数据库,P1为2或更多。“临时”数据库可能不会被抽真空。 |
变量 | 将绑定参数P1的值传送到寄存器P2中。如果参数被命名,则其名称出现在P4中。P4值由sqlite3_bind_parameter_name()使用。 |
VBegin | P4可能是一个指向sqlite3_vtab结构的指针。如果是这样,请为该表调用xBegin方法。此外,无论P4是否已设置,请检查是否在回调到虚拟表xSync()方法时未调用此方法。如果是,则错误代码将设置为SQLITE_LOCKED。 |
V列 | 将P1光标指向的虚拟表行的第P2列的值存储到寄存器P3中。 |
VCreate | P2是保存数据库P1中的虚拟表名称的寄存器。调用该表的xCreate方法。 |
VDestroy | P4是数据库P1中虚拟表的名称。调用该表的xDestroy方法。 |
VFILTER | P1是使用VOpen打开的游标。如果过滤结果集为空,则P2是要跳转到的地址。P4是NULL或由模块的xBestIndex方法生成的字符串。P4字符串的解释留给模块实现。该操作码调用P1指定的虚拟表上的xFilter方法。xFilter的整数查询计划参数存储在寄存器P3中。寄存器P3 + 1存储要传递给xFilter方法的argc参数。寄存器P3 + 2..P3 + 1 + argc是作为argv传递给xFilter的argc附加参数。传递给xFilter时,寄存器P3 + 2变为argv0。如果过滤后的结果集为空,则跳转到P2。 |
VNext | 将虚拟表P1提前到结果集中的下一行并跳转到指令P2。或者,如果虚拟表达到其结果集的末尾,则转到下一条指令。 |
Vopen | P4是一个指向虚拟表对象的指针,一个sqlite3_vtab结构。P1是一个游标编号。该操作码将光标打开到虚拟表并将该光标存储在P1中。 |
VRename | P4是一个指向虚拟表对象的指针,一个sqlite3_vtab结构。这个操作码调用相应的xRename方法。寄存器P1中的值作为zName参数传递给xRename方法。 |
VUpdate | P4是一个指向虚拟表对象的指针,一个sqlite3_vtab结构。该操作码调用相应的xUpdate方法。P2值是从P3开始传递给xUpdate调用的连续内存单元。寄存器(P3 + P2-1)中的值对应于传递给xUpdate的argv数组的第p2个元素。xUpdate方法将执行DELETE或INSERT或两者。argv0元素(对应于内存单元P3)是要删除的行的rowid。如果argv0为NULL,则不会发生删除。argv1元素是新行的rowid。这可以为NULL,让虚拟表为自己选择新的rowid。数组中的后续元素是新行中列的值。如果P2 == 1,则不执行插入。argv0是要删除的行的rowid。P1是一个布尔标志。如果它设置为true并且xUpdate调用成功,那么sqlite3_last_insert_rowid()返回的值将被设置为刚刚插入的rowid的值。P5是在插入或更新约束失败的情况下应用的错误操作(OE_Replace,OE_Fail,OE_Ignore等)。 |
产量 | 使用寄存器P1中的值交换程序计数器。这具有产生协同程序的效果。如果此指令启动的协程以Yield或Return结束,则继续下一条指令。但是,如果此指令启动的协程以EndCoroutine结束,则跳转到P2而不是继续下一条指令。另请参阅:InitCoroutine |
- P2=='A' → BLOB
- P2=='B' → TEXT
- P2=='C' → NUMERIC
- P2=='D' → INTEGER
- P2=='E' → REAL
A NULL value is not changed by this routine. It remains NULL.
Checkpoint Checkpoint database P1. This is a no-op if P1 is not currently in WAL mode. Parameter P2 is one of SQLITE\_CHECKPOINT\_PASSIVE, FULL, RESTART, or TRUNCATE. Write 1 or 0 into mem[P3] if the checkpoint returns SQLITE\_BUSY or not, respectively. Write the number of pages in the WAL after the checkpoint into mem[P3+1] and the number of pages in the WAL that have been checkpointed after the checkpoint completes into mem[P3+2]. However on an error, mem[P3+1] and mem[P3+2] are initialized to -1. Clear Delete all contents of the database table or index whose root page in the database file is given by P1. But, unlike [Destroy](opcode#Destroy), do not remove the table or index from the database file. The table being clear is in the main database file if P2==0. If P2==1 then the table to be clear is in the auxiliary database file that is used to store tables create using CREATE TEMPORARY TABLE.
如果P3值不为零,那么引用的表必须是一个 intkey 表(一个 SQL 表,而不是一个索引)。在这种情况下,行更改计数会增加正在清除的表中的行数。如果 P3 大于零,则存储在寄存器 P3 中的值也会增加正在清除的表中的行数。
另见:Destroy
Close Close a cursor previously opened as P1. If P1 is not currently open, this instruction is a no-op. CollSeq P4 is a pointer to a CollSeq object. If the next call to a user function or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will be returned. This is used by the built-in min(), max() and nullif() functions. If P1 is not zero, then it is a register that a subsequent min() or max() aggregate will set to 1 if the current row is not the minimum or maximum. The P1 register is initialized to 0 by this instruction.
执行前述功能来检索由此操作码设置的归类序列所使用的接口不可公开获得。只有内置功能才能访问此功能。
Column Interpret the data that cursor P1 points to as a structure built using the [MakeRecord](opcode#MakeRecord) instruction. (See the [MakeRecord](opcode#MakeRecord) opcode for additional information about the format of the data.) Extract the P2-th column from this record. If there are less that (P2+1) values in the record, extract a NULL. The value extracted is stored in register P3.
如果记录包含少于 P2 字段,则提取一个 NULL。或者,如果P4参数是 P4_MEM,则使用P4参数的值作为结果。
如果在 P5 上设置了 OPFLAG_CLEARCACHE 位,并且 P1 是一个伪表游标,那么在提取列之前会重置游标的缓存。在内容寄存器的值发生变化之后,针对伪表的第一列应该设置该位。
如果在 P5 上设置 OPFLAG_LENGTHARG 和 OPFLAG_TYPEOFARG 位,则结果保证只能分别用作 length()或 typeof()函数的参数。加载大块可以跳过 length(),并且 typeof()可以跳过所有内容加载。
ColumnsUsed This opcode (which only exists if SQLite was compiled with SQLITE\_ENABLE\_COLUMN\_USED\_MASK) identifies which columns of the table or index for cursor P1 are used. P4 is a 64-bit integer (P4\_INT64) in which the first 63 bits are one for each of the first 63 columns of the table or index that are actually used by the cursor. The high-order bit is set if any column after the 64th is used. Compare Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of the comparison for use by the next [Jump](opcode#Jump) instruct. If P5 has the OPFLAG\_PERMUTE bit set, then the order of comparison is determined by the most recent [Permutation](opcode#Permutation) operator. If the OPFLAG\_PERMUTE bit is clear, then register are compared in sequential order.
P4 是一个 KeyInfo 结构,用于定义比较的整理顺序和排序顺序。该排列仅适用于寄存器。KeyInfo 元素按顺序使用。
比较是一种排序比较,所以 NULL 比较相等,NULL 小于数字,数字小于字符串,字符串小于 blob。
Concat Add the text in register P1 onto the end of the text in register P2 and store the result in register P3. If either the P1 or P2 text are NULL then store NULL in P3. P3 = P2 || P1
P1 和 P3 是相同的寄存器是非法的。有时,如果 P3与 P2的寄存器相同,则实现可以避免使用 memcpy()。
Copy Make a copy of registers P1..P1+P3 into registers P2..P2+P3. This instruction makes a deep copy of the value. A duplicate is made of any string or blob constant. See also [SCopy](opcode#SCopy).
Count Store the number of entries (an integer value) in the table or index opened by cursor P1 in register P2 CreateBtree Allocate a new b-tree in the main database file if P1==0 or in the TEMP database file if P1==1 or in an attached database if P1>1. The P3 argument must be 1 (BTREE\_INTKEY) for a rowid table it must be 2 (BTREE\_BLOBKEY) for a index or WITHOUT ROWID table. The root page number of the new b-tree is stored in register P2. CursorHint Provide a hint to cursor P1 that it only needs to return rows that satisfy the Expr in P4. TK\_REGISTER terms in the P4 expression refer to values currently held in registers. TK\_COLUMN terms in the P4 expression refer to columns in the b-tree to which cursor P1 is pointing. DecrJumpZero Register P1 must hold an integer. Decrement the value in P1 and jump to P2 if the new value is exactly zero. DeferredSeek P1 is an open index cursor and P3 is a cursor on the corresponding table. This opcode does a deferred seek of the P3 table cursor to the row that corresponds to the current row of P1. This is a deferred seek. Nothing actually happens until the cursor is used to read a record. That way, if no reads occur, no unnecessary I/O happens.
P4 可能是一个整数数组(P4_INTARRAY 类型),其中包含 P3表中每列的一个条目。如果数组条目a(i)非零,则从光标 P3读取 a(i)-1列相当于执行延迟查找,然后从 P1读取列i。这些信息存储在 P3中,用于将读取操作重定向到 P1,从而可能避免需要查找和读取光标 P3。
Delete Delete the record at which the P1 cursor is currently pointing. If the OPFLAG\_SAVEPOSITION bit of the P5 parameter is set, then the cursor will be left pointing at either the next or the previous record in the table. If it is left pointing at the next record, then the next [Next](opcode#Next) instruction will be a no-op. As a result, in this case it is ok to delete a record from within a [Next](opcode#Next) loop. If OPFLAG\_SAVEPOSITION bit of P5 is clear, then the cursor will be left in an undefined state.
如果在P5上设置 OPFLAG_AUXDELETE 位,则表示删除与删除表行及其所有相关索引条目相关的几个中的一个。其中的一个删除是“主要”删除。其他的都在 OPFLAG_FORDELETE 游标上,或者用 AUXDELETE 标志标记。
如果设置了 P2(NB:P2而不是P5)的 OPFLAG_NCHANGE 标志,则行更改计数递增(否则)。
P1不能是伪表。它必须是具有多行的真实表格。
如果 P4 不是 NULL,则它指向一个 Table 对象。在这种情况下,可能会调用更新或更新前的钩子或两者。在这种情况下,在调用此操作码之前,必须使用 NotFound 定位 P1游标。特别是,如果配置了一个,如果 P4不为 NULL,则会调用更新前的钩子。如果配置了更新挂钩,则会调用更新挂钩,P4 不为 NULL,并且在P2中设置 OPFLAG_NCHANGE 标志。
如果在 P2中设置了 OPFLAG_ISUPDATE 标志,则 P3包含存储单元的地址,该地址包含该行的 rowid 将被更新设置为的值。
Destroy Delete an entire database table or index whose root page in the database file is given by P1. The table being destroyed is in the main database file if P3==0. If P3==1 then the table to be clear is in the auxiliary database file that is used to store tables create using CREATE TEMPORARY TABLE.
如果启用 AUTOVACUUM,则可能会将另一个根页面移动到新删除的根页面中,以便将所有的根页面连接在数据库的开头。移动的根页面的前一个值(移动发生前的值)存储在寄存器P2中。如果不需要页面移动(因为被删除的表已经是数据库中的最后一个),则将零存储在寄存器 P2中。如果 AUTOVACUUM 被禁用,则零点被存储在寄存器 P2中。
如果有任何活动的读取器虚拟机被调用,此操作码会引发错误。这样做是为了避免当在 AUTOVACUUM 数据库中移动根页面时更新现有游标的困难。即使数据库不是 AUTOVACUUM 数据库,也会引发此错误,以避免在 autovacuum 和非 autovacuum 模式之间引入不兼容。
另请参阅: Clear
Divide Divide the value in register P1 by the value in register P2 and store the result in register P3 (P3=P2/P1). If the value in register P1 is zero, then the result is NULL. If either input is NULL, the result is NULL. DropIndex Remove the internal (in-memory) data structures that describe the index named P4 in database P1. This is called after an index is dropped from disk (using the [Destroy](opcode#Destroy) opcode) in order to keep the internal representation of the schema consistent with what is on disk. DropTable Remove the internal (in-memory) data structures that describe the table named P4 in database P1. This is called after a table is dropped from disk (using the [Destroy](opcode#Destroy) opcode) in order to keep the internal representation of the schema consistent with what is on disk. DropTrigger Remove the internal (in-memory) data structures that describe the trigger named P4 in database P1. This is called after a trigger is dropped from disk (using the [Destroy](opcode#Destroy) opcode) in order to keep the internal representation of the schema consistent with what is on disk. ElseNotEq This opcode must immediately follow an [Lt](opcode#Lt) or [Gt](opcode#Gt) comparison operator. If result of an [Eq](opcode#Eq) comparison on the same two operands would have be NULL or false (0), then then jump to P2. If the result of an [Eq](opcode#Eq) comparison on the two previous operands would have been true (1), then fall through. EndCoroutine The instruction at the address in register P1 is a [Yield](opcode#Yield). [Jump](opcode#Jump) to the P2 parameter of that [Yield](opcode#Yield). After the jump, register P1 becomes undefined. See also: [InitCoroutine](opcode#InitCoroutine)
Eq Compare the values in register P1 and P3. If reg(P3)==reg(P1) then jump to address P2. Or if the SQLITE\_STOREP2 flag is set in P5, then store the result of comparison in register P2. The SQLITE\_AFF\_MASK portion of P5 must be an affinity character - SQLITE\_AFF\_TEXT, SQLITE\_AFF\_INTEGER, and so forth. An attempt is made to coerce both inputs according to this affinity before the comparison is made. If the SQLITE\_AFF\_MASK is 0x00, then numeric affinity is used. Note that the affinity conversions are stored back into the input registers P1 and P3. So this opcode can cause persistent changes to registers P1 and P3.
一旦发生任何转换,并且两个值都不为 NULL,则会比较这些值。如果两个值都是斑点,则使用 memcmp()来确定比较结果。如果两个值均为文本,则使用 P4中指定的适当的整理函数进行比较。如果未指定 P4,则使用 memcmp()来比较文本字符串。如果两个值都是数字,则使用数字比较。如果这两个值的类型不同,则认为数字小于字符串,字符串被认为小于 blob。
如果 SQLITE_NULLEQ 在 P5中设置,那么比较结果总是为真或为假,并且从不为 NULL。如果两个操作数均为 NULL,则比较结果为 true。如果任一操作数为 NULL,则结果为 false。如果两个操作数都不为 NULL,则结果与从 P5中省略 SQLITE_NULLEQ标志的结果相同。
如果同时设置了 SQLITE_STOREP2 和 SQLITE_KEEPNULL 标志,则只有在新值为 NULL 或0(false)时才会更改 rP2 的内容。换句话说,先前的 rP2 值不会被1(真)覆盖。
Expire Cause precompiled statements to expire. When an expired statement is executed using sqlite3\_step() it will either automatically reprepare itself (if it was originally created using sqlite3\_prepare\_v2()) or it will fail with SQLITE\_SCHEMA. If P1 is 0, then all SQL statements become expired. If P1 is non-zero, then only the currently executing statement is expired.
FkCounter Increment a "constraint counter" by P2 (P2 may be negative or positive). If P1 is non-zero, the database constraint counter is incremented (deferred foreign key constraints). Otherwise, if P1 is zero, the statement counter is incremented (immediate foreign key constraints). FkIfZero This opcode tests if a foreign key constraint-counter is currently zero. If so, jump to instruction P2. Otherwise, fall through to the next instruction. If P1 is non-zero, then the jump is taken if the database constraint-counter is zero (the one that counts deferred constraint violations). If P1 is zero, the jump is taken if the statement constraint-counter is zero (immediate foreign key constraint violations).
Found If P4==0 then register P3 holds a blob constructed by [MakeRecord](opcode#MakeRecord). If P4>0 then register P3 is the first of P4 registers that form an unpacked record. Cursor P1 is on an index btree. If the record identified by P3 and P4 is a prefix of any entry in P1 then a jump is made to P2 and P1 is left pointing at the matching entry.
操作使光标处于可向前推进的状态。下一条指令将工作,但不是上一条指令。
另请参阅:NotFound,NoConflict,NotExists。SeekGe
Function Invoke a user function (P4 is a pointer to an sqlite3\_context object that contains a pointer to the function to be run) with P5 arguments taken from register P2 and successors. The result of the function is stored in register P3. Register P3 must not be one of the function inputs. P1 is a 32-bit bitmask indicating whether or not each argument to the function was determined to be constant at compile time. If the first argument was constant then bit 0 of P1 is set. This is used to determine whether meta data associated with a user function argument using the sqlite3\_set\_auxdata() API may be safely retained until the next invocation of this opcode.
SQL 函数最初编码为 Function0,P4 指向一个 FuncDef 对象。但在第一次评估时,P4操作数会自动转换为 sqlite3_context 对象,并将操作更改为此函数操作码。通过这种方式,sqlite3_context 对象的初始化只发生一次,而不是每次评估函数一次。
另请参阅:Function0, AggStep, AggFinal
Function0 Invoke a user function (P4 is a pointer to a FuncDef object that defines the function) with P5 arguments taken from register P2 and successors. The result of the function is stored in register P3. Register P3 must not be one of the function inputs. P1 is a 32-bit bitmask indicating whether or not each argument to the function was determined to be constant at compile time. If the first argument was constant then bit 0 of P1 is set. This is used to determine whether meta data associated with a user function argument using the sqlite3\_set\_auxdata() API may be safely retained until the next invocation of this opcode.
另请参阅:Function, AggStep, AggFinal
Ge This works just like the Lt opcode except that the jump is taken if the content of register P3 is greater than or equal to the content of register P1. See the Lt opcode for additional information. Gosub Write the current address onto register P1 and then jump to address P2. Goto An unconditional jump to address P2. The next instruction executed will be the one at index P2 from the beginning of the program. The P1 parameter is not actually used by this opcode. However, it is sometimes set to 1 instead of 0 as a hint to the command-line shell that this [Goto](opcode#Goto) is the bottom of a loop and that the lines from P2 down to the current line should be indented for EXPLAIN output.
Gt This works just like the Lt opcode except that the jump is taken if the content of register P3 is greater than the content of register P1. See the Lt opcode for additional information. Halt Exit immediately. All open cursors, etc are closed automatically. P1 is the result code returned by sqlite3\_exec(), sqlite3\_reset(), or sqlite3\_finalize(). For a normal halt, this should be SQLITE\_OK (0). For errors, it can be some other value. If P1!=0 then P2 will determine whether or not to rollback the current transaction. Do not rollback if P2==OE\_Fail. Do the rollback if P2==OE\_Rollback. If P2==OE\_Abort, then back out all changes that have occurred during this execution of the VDBE, but do not rollback the transaction.
If P4 is not null then it is an error message string.
P5是一个介于0和4之间(包括0和4)的值,用于修改 P4字符串。
0:(无变化)1:NOT NULL 约束失败:P4 2:UNIQUE 约束失败:P4 3:CHECK 约束失败:P4 4:FOREIGN KEY 约束失败:P4
如果 P5不为零且 P4为 NULL,则省略“:”后面的所有内容。
在每个程序的最后插入一个隐含的 “Halt 0 0 0” 指令。所以跳过程序的最后一条指令就像执行中止一样。
HaltIfNull Check the value in register P3. If it is NULL then [Halt](opcode#Halt) using parameter P1, P2, and P4 as if this were a [Halt](opcode#Halt) instruction. If the value in register P3 is not NULL, then this routine is a no-op. The P5 parameter should be 1. IdxDelete The content of P3 registers starting at register P2 form an unpacked index key. This opcode removes that entry from the index opened by cursor P1. IdxGE The P4 register values beginning with P3 form an unpacked index key that omits the PRIMARY KEY. [Compare](opcode#Compare) this key value against the index that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID fields at the end. If the P1 index entry is greater than or equal to the key value then jump to P2. Otherwise fall through to the next instruction.
IdxGT The P4 register values beginning with P3 form an unpacked index key that omits the PRIMARY KEY. [Compare](opcode#Compare) this key value against the index that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID fields at the end. If the P1 index entry is greater than the key value then jump to P2. Otherwise fall through to the next instruction.
IdxInsert Register P2 holds an SQL index key made using the [MakeRecord](opcode#MakeRecord) instructions. This opcode writes that key into the index P1. Data for the entry is nil. If P4 is not zero, then it is the number of values in the unpacked key of reg(P2). In that case, P3 is the index of the first register for the unpacked key. The availability of the unpacked key can sometimes be an optimization.
如果P5设置了 OPFLAG_APPEND 位,则这是向 b-tree 层提示该插入可能是附加的。
如果 P5 设置了 OPFLAG_NCHANGE 位,则更改计数器将按照该指令递增。如果 OPFLAG_NCHANGE 位清零,则更改计数器保持不变。
如果设置了 P5的 OPFLAG_USESEEKRESULT 标志,则通过避免在光标P1上进行不必要的查找,实现可能运行得更快。但是,只有在光标上没有事先查找的情况下,或者最近的查找使用的是与P2等价的键时,才能设置 OPFLAG_USESEEKRESULT 标志。
该指令仅适用于指数。表格的等效指令是 Insert。
IdxLE The P4 register values beginning with P3 form an unpacked index key that omits the PRIMARY KEY or ROWID. [Compare](opcode#Compare) this key value against the index that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID on the P1 index. If the P1 index entry is less than or equal to the key value then jump to P2. Otherwise fall through to the next instruction.
IdxLT The P4 register values beginning with P3 form an unpacked index key that omits the PRIMARY KEY or ROWID. [Compare](opcode#Compare) this key value against the index that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID on the P1 index. If the P1 index entry is less than the key value then jump to P2. Otherwise fall through to the next instruction.
IdxRowid Write into register P2 an integer which is the last entry in the record at the end of the index key pointed to by cursor P1. This integer should be the rowid of the table entry to which this index entry points. See also: [Rowid](opcode#Rowid), [MakeRecord](opcode#MakeRecord).
If Jump to P2 if the value in register P1 is true. The value is considered true if it is numeric and non-zero. If the value in P1 is NULL then take the jump if and only if P3 is non-zero. IfNot Jump to P2 if the value in register P1 is False. The value is considered false if it has a numeric value of zero. If the value in P1 is NULL then take the jump if and only if P3 is non-zero. IfNotZero Register P1 must contain an integer. If the content of register P1 is initially greater than zero, then decrement the value in register P1. If it is non-zero (negative or positive) and then also jump to P2. If register P1 is initially zero, leave it unchanged and fall through. IfNullRow Check the cursor P1 to see if it is currently pointing at a NULL row. If it is, then set register P3 to NULL and jump immediately to P2. If P1 is not on a NULL row, then fall through without making any changes. IfPos Register P1 must contain an integer. If the value of register P1 is 1 or greater, subtract P3 from the value in P1 and jump to P2. If the initial value of register P1 is less than 1, then the value is unchanged and control passes through to the next instruction.
IfSmaller Estimate the number of rows in the table P1. [Jump](opcode#Jump) to P2 if that estimate is less than approximately 2\*\*(0.1\*P3). IncrVacuum Perform a single step of the incremental vacuum procedure on the P1 database. If the vacuum has finished, jump to instruction P2. Otherwise, fall through to the next instruction. Init Programs contain a single instance of this opcode as the very first opcode. If tracing is enabled (by the sqlite3\_trace()) interface, then the UTF-8 string contained in P4 is emitted on the trace callback. Or if P4 is blank, use the string returned by sqlite3\_sql().
如果P2不为零,则跳转到指令 P2。
增加 P1的值,以便一次操作码在第一次对此运行进行评估时跳转。
如果 P3不为零,那么如果遇到 SQLITE_CORRUPT 错误,它就是要跳转到的地址。
InitCoroutine Set up register P1 so that it will [Yield](opcode#Yield) to the coroutine located at address P3. If P2!=0 then the coroutine implementation immediately follows this opcode. So jump over the coroutine implementation to address P2.
另请参阅:EndCoroutine
Insert Write an entry into the table of cursor P1. A new entry is created if it doesn't already exist or the data for an existing entry is overwritten. The data is the value MEM\_Blob stored in register number P2. The key is stored in register P3. The key must be a MEM\_Int. If the OPFLAG\_NCHANGE flag of P5 is set, then the row change count is incremented (otherwise not). If the OPFLAG\_LASTROWID flag of P5 is set, then rowid is stored for subsequent return by the sqlite3\_last\_insert\_rowid() function (otherwise it is unmodified).
如果设置了 P5的 OPFLAG_USESEEKRESULT 标志,则通过避免在光标P1上进行不必要的查找,实现可能运行得更快。但是,只有在光标上没有事先查询或者最近的查找使用的键等于P3时,才能设置 OPFLAG_USESEEKRESULT 标志。
如果 OPFLAG_ISUPDATE 标志被设置,那么这个操作码是 UPDATE 操作的一部分。否则(如果标志清除),那么这个操作码是 INSERT 操作的一部分。这个区别只对更新钩子很重要。
参数 P4可能指向一个 Table 结构,或者可能是 NULL。如果它不是 NULL,则在成功插入后调用 update-hook(sqlite3.xUpdateCallback)。
(WARNING / TODO:如果P1是伪游标并且P2是动态分配的,则P2的所有权转移到伪游标,并且寄存器P2变为短暂的,如果光标改变,则寄存器P2的值将改变。确保这不会导致任何问题。)
该指令仅适用于表格。索引的等价指令是 IdxInsert。
InsertInt This works exactly like [Insert](opcode#Insert) except that the key is the integer value P3, not the value of the integer stored in register P3. Int64 P4 is a pointer to a 64-bit integer value. Write that value into register P2. IntCopy Transfer the integer value held in register P1 into register P2. This is an optimized version of [SCopy](opcode#SCopy) that works only for integer values.
Integer The 32-bit integer value P1 is written into register P2. IntegrityCk Do an analysis of the currently open database. Store in register P1 the text of an error message describing any problems. If no problems are found, store a NULL in register P1. The register P3 contains one less than the maximum number of allowed errors. At most reg(P3) errors will be reported. In other words, the analysis stops as soon as reg(P1) errors are seen. Reg(P1) is updated with the number of errors remaining.
数据库中所有表的根页码是存储在 P4_INTARRAY 参数中的整数。
如果 P5不为零,则检查在辅助数据库文件上完成,而不是在主数据库文件上完成。
该操作码用于实现 integrity_check 编译指示。
IsNull Jump to P2 if the value in register P1 is NULL. JournalMode Change the journal mode of database P1 to P3. P3 must be one of the PAGER\_JOURNALMODE\_XXX values. If changing between the various rollback modes (delete, truncate, persist, off and memory), this is a simple operation. No IO is required. If changing into or out of WAL mode the procedure is more complicated.
写一个包含最终日志模式的字符串来注册P2。
Jump Jump to the instruction at address P1, P2, or P3 depending on whether in the most recent [Compare](opcode#Compare) instruction the P1 vector was less than equal to, or greater than the P2 vector, respectively. Last The next use of the [Rowid](opcode#Rowid) or [Column](opcode#Column) or [Prev](opcode#Prev) instruction for P1 will refer to the last entry in the database table or index. If the table or index is empty and P2>0, then jump immediately to P2. If P2 is 0 or if the table or index is not empty, fall through to the following instruction. This opcode leaves the cursor configured to move in reverse order, from the end toward the beginning. In other words, the cursor is configured to use [Prev](opcode#Prev), not [Next](opcode#Next).
Le This works just like the Lt opcode except that the jump is taken if the content of register P3 is less than or equal to the content of register P1. See the Lt opcode for additional information. LoadAnalysis Read the sqlite\_stat1 table for database P1 and load the content of that table into the internal index hash table. This will cause the analysis to be used when preparing all subsequent queries. Lt Compare the values in register P1 and P3. If reg(P3)<reg(P1) then jump to address P2. Or if the SQLITE\_STOREP2 flag is set in P5 store the result of comparison (0 or 1 or NULL) into register P2. If the SQLITE\_JUMPIFNULL bit of P5 is set and either reg(P1) or reg(P3) is NULL then the take the jump. If the SQLITE\_JUMPIFNULL bit is clear then fall through if either operand is NULL.
P5 的 SQLITE_AFF_MASK 部分必须是亲和性字符 - SQLITE_AFF_TEXT,SQLITE_AFF_INTEGER 等等。在进行比较之前,试图根据这种相似性强制两个输入。如果 SQLITE_AFF_MASK 是0x00,则使用数字亲缘关系。请注意,亲和转换被存回输入寄存器 P1和 P3。所以这个操作码可能会导致寄存器P1和P3的持续变化。
一旦发生任何转换,并且两个值都不为 NULL,则会比较这些值。如果两个值都是斑点,则使用 memcmp()来确定比较结果。如果两个值均为文本,则使用 P4中指定的适当的整理函数进行比较。如果未指定 P4,则使用 memcmp()来比较文本字符串。如果两个值都是数字,则使用数字比较。如果这两个值的类型不同,则认为数字小于字符串,字符串被认为小于 blob。
MakeRecord Convert P2 registers beginning with P1 into the [record format](fileformat2#record_format) use as a data record in a database table or as a key in an index. The [Column](opcode#Column) opcode can decode the record later. P4 may be a string that is P2 characters long. The N-th character of the string indicates the column affinity that should be used for the N-th field of the index key.
从字符到关联的映射由 sqliteInt.h 中定义的 SQLITE_AFF_ 宏给出。
如果 P4为 NULL,则所有索引字段都具有亲和性 BLOB。
MaxPgcnt Try to set the maximum page count for database P1 to the value in P3. Do not let the maximum page count fall below the current page count and do not change the maximum page count value if P3==0. Store the maximum page count after the change in register P2.
MemMax P1 is a register in the root frame of this VM (the root frame is different from the current frame if this instruction is being executed within a sub-program). Set the value of register P1 to the maximum of its current value and the value in register P2. This instruction throws an error if the memory cell is not initially an integer.
Move Move the P3 values in register P1..P1+P3-1 over into registers P2..P2+P3-1. Registers P1..P1+P3-1 are left holding a NULL. It is an error for register ranges P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error for P3 to be less than 1. Multiply Multiply the value in register P1 by the value in register P2 and store the result in register P3. If either input is NULL, the result is NULL. MustBeInt Force the value in register P1 to be an integer. If the value in P1 is not an integer and cannot be converted into an integer without data loss, then jump immediately to P2, or if P2==0 raise an SQLITE\_MISMATCH exception. Ne This works just like the Eq opcode except that the jump is taken if the operands in registers P1 and P3 are not equal. See the Eq opcode for additional information. If both SQLITE\_STOREP2 and SQLITE\_KEEPNULL flags are set then the content of r[P2] is only changed if the new value is NULL or 1 (true). In other words, a prior r[P2] value will not be overwritten by 0 (false).
NewRowid Get a new integer record number (a.k.a "rowid") used as the key to a table. The record number is not previously used as a key in the database table that cursor P1 points to. The new record number is written written to register P2. If P3>0 then P3 is a register in the root frame of this VDBE that holds the largest previously generated record number. No new record numbers are allowed to be less than this value. When this value reaches its maximum, an SQLITE\_FULL error is generated. The P3 register is updated with the ' generated record number. This P3 mechanism is used to help implement the AUTOINCREMENT feature.
Next Advance cursor P1 so that it points to the next key/data pair in its table or index. If there are no more key/value pairs then fall through to the following instruction. But if the cursor advance was successful, jump immediately to P2. The [Next](opcode#Next) opcode is only valid following an [SeekGT](opcode#SeekGT), [SeekGE](opcode#SeekGE), or [Rewind](opcode#Rewind) opcode used to position the cursor. [Next](opcode#Next) is not allowed to follow [SeekLT](opcode#SeekLT), [SeekLE](opcode#SeekLE), or [Last](opcode#Last).
P1游标必须用于真实表格,而不是伪表格。P1必须在这个操作码之前打开,否则程序会出现段错误。
P3 值是 btree 实现的提示。如果 P3 == 1,这意味着 P1是一个 SQL 索引,并且如果该索引是唯一的,则可以省略该指令。P3通常为0. P3 总是为0或1。
P4 始终是 P4_ADVANCE 类型。函数指针指向 sqlite3BtreeNext()。
如果 P5为正值并跳转,则准备语句中的事件计数器编号 P5-1将递增。
另请参阅:Prev,NextIfOpen
NextIfOpen This opcode works just like [Next](opcode#Next) except that if cursor P1 is not open it behaves a no-op. NoConflict If P4==0 then register P3 holds a blob constructed by [MakeRecord](opcode#MakeRecord). If P4>0 then register P3 is the first of P4 registers that form an unpacked record. Cursor P1 is on an index btree. If the record identified by P3 and P4 contains any NULL value, jump immediately to P2. If all terms of the record are not-NULL then a check is done to determine if any row in the P1 index btree has a matching key prefix. If there are no matches, jump immediately to P2. If there is a match, fall through and leave the P1 cursor pointing to the matching row.
这个操作码与 NotFound 相似,除了在搜索关键字输入的任何部分为 NULL 时总是采用分支。
该操作使光标处于无法向任一方向前进的状态。换句话说,在此操作之后,Next 和 Prev 操作码不起作用。
另请参阅:NotFound,Found,NotExists
Noop Do nothing. This instruction is often useful as a jump destination. Not Interpret the value in register P1 as a boolean value. Store the boolean complement in register P2. If the value in register P1 is NULL, then a NULL is stored in P2. NotExists P1 is the index of a cursor open on an SQL table btree (with integer keys). P3 is an integer rowid. If P1 does not contain a record with rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an SQLITE\_CORRUPT error. If P1 does contain a record with rowid P3 then leave the cursor pointing at that record and fall through to the next instruction. The [SeekRowid](opcode#SeekRowid) opcode performs the same operation but also allows the P3 register to contain a non-integer value, in which case the jump is always taken. This opcode requires that P3 always contain an integer.
NotFound 操作码对索引树(使用任意多值键)执行相同的操作。
该操作码将光标置于无法在任一方向上前进的状态。换句话说,在此操作码之后,Next 和 Prev 操作码将不起作用。
另见:Found,NotFound,NoConflict,SeekRowid
NotFound If P4==0 then register P3 holds a blob constructed by [MakeRecord](opcode#MakeRecord). If P4>0 then register P3 is the first of P4 registers that form an unpacked record. Cursor P1 is on an index btree. If the record identified by P3 and P4 is not the prefix of any entry in P1 then a jump is made to P2. If P1 does contain an entry whose prefix matches the P3/P4 record then control falls through to the next instruction and P1 is left pointing at the matching entry.
该操作使光标处于无法向任一方向前进的状态。换句话说,在此操作之后,Next 和 Prev 操作码不起作用。
另见:Found,NotExists,NoConflict
NotNull Jump to P2 if the value in register P1 is not NULL. Null Write a NULL into registers P2. If P3 greater than P2, then also write NULL into register P3 and every register in between P2 and P3. If P3 is less than P2 (typically P3 is zero) then only register P2 is set to NULL. If the P1 value is non-zero, then also set the MEM\_Cleared flag so that NULL values will not compare equal even if SQLITE\_NULLEQ is set on [Ne](opcode#Ne) or [Eq](opcode#Eq).
NullRow Move the cursor P1 to a null row. Any [Column](opcode#Column) operations that occur while the cursor is on the null row will always write a NULL. OffsetLimit This opcode performs a commonly used computation associated with LIMIT and OFFSET process. r[P1] holds the limit counter. r[P3] holds the offset counter. The opcode computes the combined value of the LIMIT and OFFSET and stores that value in r[P2]. The r[P2] value computed is the total number of rows that will need to be visited in order to complete the query. If r[P3] is zero or negative, that means there is no OFFSET and r[P2] is set to be the value of the LIMIT, r[P1].
如果 rP1 为零或负值,则表示没有 LIMIT 且 rP2 设置为-1。
否则,rP2 被设置为 rP1和 rP3之和。
Once Fall through to the next instruction the first time this opcode is encountered on each invocation of the byte-code program. [Jump](opcode#Jump) to P2 on the second and all subsequent encounters during the same invocation. Top-level programs determine first invocation by comparing the P1 operand against the P1 operand on the [Init](opcode#Init) opcode at the beginning of the program. If the P1 values differ, then fall through and make the P1 of this opcode equal to the P1 of [Init](opcode#Init). If P1 values are the same then take the jump.
对于子程序,VdbeFrame 中有一个位掩码,用于确定是否应该进行跳转。位掩码是必要的,因为自变更代码技巧不适用于递归触发器。
OpenAutoindex This opcode works the same as [OpenEphemeral](opcode#OpenEphemeral). It has a different name to distinguish its use. Tables created using by this opcode will be used for automatically created transient indices in joins. OpenDup Open a new cursor P1 that points to the same ephemeral table as cursor P2. The P2 cursor must have been opened by a prior [OpenEphemeral](opcode#OpenEphemeral) opcode. Only ephemeral cursors may be duplicated. Duplicate ephemeral cursors are used for self-joins of materialized views.
OpenEphemeral Open a new cursor P1 to a transient table. The cursor is always opened read/write even if the main database is read-only. The ephemeral table is deleted automatically when the cursor is closed. P2 is the number of columns in the ephemeral table. The cursor points to a BTree table if P4==0 and to a BTree index if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure that defines the format of keys in the index.
P5参数可以是 btree.h 中定义的 BTREE_ *标志的掩码。这些标志控制 btree 的操作方面。BTREE_OMIT_JOURNAL 和 BTREE_SINGLE 标志会自动添加。
OpenPseudo Open a new cursor that points to a fake table that contains a single row of data. The content of that one row is the content of memory register P2. In other words, cursor P1 becomes an alias for the MEM\_Blob content contained in register P2. A pseudo-table created by this opcode is used to hold a single row output from the sorter so that the row can be decomposed into individual columns using the [Column](opcode#Column) opcode. The [Column](opcode#Column) opcode is the only cursor opcode that works with a pseudo-table.
P3是将由伪表存储的记录中的字段数。
OpenRead Open a read-only cursor for the database table whose root page is P2 in a database file. The database file is determined by P3. P3==0 means the main database, P3==1 means the database used for temporary tables, and P3>1 means used the corresponding attached database. Give the new cursor an identifier of P1. The P1 values need not be contiguous but all P1 values should be small integers. It is an error for P1 to be negative. If P5!=0 then use the content of register P2 as the root page, not the value of P2 itself.
只要有一个打开的光标,数据库就会有一个读锁定。如果在该指令之前数据库被解锁,那么作为该指令的一部分获取读锁。读锁允许其他进程读取数据库,但禁止其他进程修改数据库。当所有游标关闭时,读锁定被释放。如果此指令尝试获取读取锁但失败,则脚本以 SQLITE_BUSY 错误代码终止。
P4值可以是整数(P4_INT32)或指向 KeyInf o结构的指针(P4_KEYINFO)。如果它是指向 KeyInfo 结构的指针,则所述结构定义打开的索引的内容和整理顺序。否则,如果P4是整数值,则将其设置为表中的列数。
另请参阅:OpenWrite,ReopenIdx
OpenWrite Open a read/write cursor named P1 on the table or index whose root page is P2. Or if P5!=0 use the content of register P2 to find the root page. The P4 value may be either an integer (P4\_INT32) or a pointer to a KeyInfo structure (P4\_KEYINFO). If it is a pointer to a KeyInfo structure, then said structure defines the content and collating sequence of the index being opened. Otherwise, if P4 is an integer value, it is set to the number of columns in the table, or to the largest index of any column of the table that is actually used.
该指令的工作原理与 OpenRead 类似,不同之处在于它以读/写模式打开光标。对于给定的表,可以有一个或多个只读游标或单个读/写游标,但不能同时包含两者。
另请参阅 OpenRead。
Or Take the logical OR of the values in register P1 and P2 and store the answer in register P3. If either P1 or P2 is nonzero (true) then the result is 1 (true) even if the other input is NULL. A NULL and false or two NULLs give a NULL output.
Pagecount Write the current number of pages in database P1 to memory cell P2. Param This opcode is only ever present in sub-programs called via the [Program](opcode#Program) instruction. [Copy](opcode#Copy) a value currently stored in a memory cell of the calling (parent) frame to cell P2 in the current frames address space. This is used by trigger programs to access the new.\* and old.\* values. The address of the cell in the parent frame is determined by adding the value of the P1 argument to the value of the P1 argument to the calling [Program](opcode#Program) instruction.
ParseSchema Read and parse all entries from the SQLITE\_MASTER table of database P1 that match the WHERE clause P4. This opcode invokes the parser to create a new virtual machine, then runs the new virtual machine. It is thus a re-entrant opcode.
Permutation Set the permutation used by the [Compare](opcode#Compare) operator in the next instruction. The permutation is stored in the P4 operand. The permutation is only valid until the next [Compare](opcode#Compare) that has the OPFLAG\_PERMUTE bit set in P5. Typically the [Permutation](opcode#Permutation) should occur immediately prior to the [Compare](opcode#Compare).
P4整数数组中的第一个整数是数组的长度,不会成为置换的一部分。
Prev Back up cursor P1 so that it points to the previous key/data pair in its table or index. If there is no previous key/value pairs then fall through to the following instruction. But if the cursor backup was successful, jump immediately to P2. The [Prev](opcode#Prev) opcode is only valid following an [SeekLT](opcode#SeekLT), [SeekLE](opcode#SeekLE), or [Last](opcode#Last) opcode used to position the cursor. [Prev](opcode#Prev) is not allowed to follow [SeekGT](opcode#SeekGT), [SeekGE](opcode#SeekGE), or [Rewind](opcode#Rewind).
P1游标必须用于真实表格,而不是伪表格。如果 P1未打开,则行为未定义。
P3值是 btree 实现的提示。如果 P3 == 1,这意味着 P1是一个 SQL 索引,并且如果该索引是唯一的,则可以省略该指令。P3 通常为 0. P3总是为0或1。
P4始终是 P4_ADVANCE类型。函数指针指向 sqlite3BtreePrevious()。
如果 P5为正值并跳转,则准备语句中的事件计数器编号 P5-1将递增。
PrevIfOpen This opcode works just like [Prev](opcode#Prev) except that if cursor P1 is not open it behaves a no-op. Program Execute the trigger program passed as P4 (type P4\_SUBPROGRAM). P1 contains the address of the memory cell that contains the first memory cell in an array of values used as arguments to the sub-program. P2 contains the address to jump to if the sub-program throws an IGNORE exception using the RAISE() function. Register P3 contains the address of a memory cell in this (the parent) VM that is used to allocate the memory required by the sub-vdbe at runtime.
P4是指向包含触发程序的虚拟机的指针。
如果 P5不为零,则启用递归程序调用。
ReadCookie Read cookie number P3 from database P1 and write it into register P2. P3==1 is the schema version. P3==2 is the database format. P3==3 is the recommended pager cache size, and so forth. P1==0 is the main database file and P1==1 is the database file used to store temporary tables. There must be a read-lock on the database (either a transaction must be started or there must be an open cursor) before executing this instruction.
Real P4 is a pointer to a 64-bit floating point value. Write that value into register P2. RealAffinity If register P1 holds an integer convert it to a real value. This opcode is used when extracting information from a column that has REAL affinity. Such column values may still be stored as integers, for space efficiency, but after extraction we want them to have only a real value.
Remainder Compute the remainder after integer register P2 is divided by register P1 and store the result in register P3. If the value in register P1 is zero the result is NULL. If either operand is NULL, the result is NULL. ReopenIdx The [ReopenIdx](opcode#ReopenIdx) opcode works exactly like ReadOpen except that it first checks to see if the cursor on P1 is already open with a root page number of P2 and if it is this opcode becomes a no-op. In other words, if the cursor is already open, do not reopen it. The [ReopenIdx](opcode#ReopenIdx) opcode may only be used with P5==0 and with P4 being a P4\_KEYINFO object. Furthermore, the P3 value must be the same as every other [ReopenIdx](opcode#ReopenIdx) or [OpenRead](opcode#OpenRead) for the same cursor number.
请参阅 OpenRead 操作码文档以获取更多信息。
ResetCount The value of the change counter is copied to the database handle change counter (returned by subsequent calls to sqlite3\_changes()). Then the VMs internal change counter resets to 0. This is used by trigger programs. ResetSorter Delete all contents from the ephemeral table or sorter that is open on cursor P1. This opcode only works for cursors used for sorting and opened with [OpenEphemeral](opcode#OpenEphemeral) or [SorterOpen](opcode#SorterOpen).
ResultRow The registers P1 through P1+P2-1 contain a single row of results. This opcode causes the sqlite3\_step() call to terminate with an SQLITE\_ROW return code and it sets up the sqlite3\_stmt structure to provide access to the r(P1)..r(P1+P2-1) values as the result row. Return Jump to the next instruction after the address in register P1. After the jump, register P1 becomes undefined. Rewind The next use of the [Rowid](opcode#Rowid) or [Column](opcode#Column) or [Next](opcode#Next) instruction for P1 will refer to the first entry in the database table or index. If the table or index is empty, jump immediately to P2. If the table or index is not empty, fall through to the following instruction. This opcode leaves the cursor configured to move in forward order, from the beginning toward the end. In other words, the cursor is configured to use [Next](opcode#Next), not [Prev](opcode#Prev).
RowData Write into register P2 the complete row content for the row at which cursor P1 is currently pointing. There is no interpretation of the data. It is just copied onto the P2 register exactly as it is found in the database file. If cursor P1 is an index, then the content is the key of the row. If cursor P2 is a table, then the content extracted is the data.
如果 P1游标必须指向真实表的有效行(不是 NULL 行),而不是伪表。
如果 P3!= 0,则允许此操作码在数据库页面中生成一个 ephermeral 指针。这意味着一旦光标移动,输出寄存器的内容就会失效 - 包括其他游标引起的移动,这些游标会“保存”当前游标的位置,以便它们可以写入同一个表。如果P3 == 0,则将数据的副本存入内存。P3!= 0更快,但 P3 == 0更安全。
如果 P3!= 0,则P2寄存器的内容不适合在 OP_Result 中使用,任何 OP_Result 都将使 P2寄存器内容无效。P2寄存器的内容被诸如 Function 之类的操作码或任何使用指向同一个表的另一个光标的操作无效化。
Rowid Store in register P2 an integer which is the key of the table entry that P1 is currently point to. P1 can be either an ordinary table or a virtual table. There used to be a separate OP\_VRowid opcode for use with virtual tables, but this one opcode now works for both table types.
RowSetAdd Insert the integer value held by register P2 into a RowSet object held in register P1. An assertion fails if P2 is not an integer.
RowSetRead Extract the smallest value from the RowSet object in P1 and put that value into register P3. Or, if RowSet object P1 is initially empty, leave P3 unchanged and jump to instruction P2. RowSetTest Register P3 is assumed to hold a 64-bit integer value. If register P1 contains a RowSet object and that RowSet object contains the value held in P3, jump to register P2. Otherwise, insert the integer in P3 into the RowSet and continue on to the next opcode. The RowSet object is optimized for the case where sets of integers are inserted in distinct phases, which each set contains no duplicates. Each set is identified by a unique P4 value. The first set must have P4==0, the final set must have P4==-1, and for all other sets must have P4>0.
这允许优化:(a)当 P4 == 0时,不需要为P3测试 RowSet 对象,因为它保证不包含它,(b)当 P4 == -1时,不需要插入值,因为它永远不会被测试,并且(c)当插入集合 X 的一部分的值被插入时,不需要搜索以查看是否先前插入了相同的值作为集合X的一部分(仅当它是先前插入作为一些其他集合的一部分)。
Savepoint Open, release or rollback the savepoint named by parameter P4, depending on the value of P1. To open a new savepoint, P1==0. To release (commit) an existing savepoint, P1==1, or to rollback an existing savepoint P1==2. SCopy Make a shallow copy of register P1 into register P2. This instruction makes a shallow copy of the value. If the value is a string or blob, then the copy is only a pointer to the original and hence if the original changes so will the copy. Worse, if the original is deallocated, the copy becomes invalid. Thus the program must guarantee that the original will not change during the lifetime of the copy. Use [Copy](opcode#Copy) to make a complete copy.
SeekEnd Position cursor P1 at the end of the btree for the purpose of appending a new entry onto the btree. It is assumed that the cursor is used only for appending and so if the cursor is valid, then the cursor must already be pointing at the end of the btree and so no changes are made to the cursor.
SeekGE If cursor P1 refers to an SQL table (B-Tree that uses integer keys), use the value in register P3 as the key. If cursor P1 refers to an SQL index, then P3 is the first in an array of P4 registers that are used as an unpacked index key. Reposition cursor P1 so that it points to the smallest entry that is greater than or equal to the key value. If there are no records greater than or equal to the key and P2 is not zero, then jump to P2.
如果使用 OPFLAG_SEEKEQ 标志打开游标P1,则该操作码将始终落在等于该键的记录上,否则立即跳转到 P2。当游标是 OPFLAG_SEEKEQ 时,这个操作码必须后跟一个具有相同参数的 IdxLE 操作码。如果此操作码成功,则会跳过 IdxLE 操作码,但是 IdxLE 操作码将在随后的循环迭代中使用。
该操作码将光标配置为从开始到结束以正向顺序移动。换句话说,游标被配置为使用 Next,而不是 Prev。
另见:Found,NotFound,SeekLt,SeekGt,SeekLe
SeekGT If cursor P1 refers to an SQL table (B-Tree that uses integer keys), use the value in register P3 as a key. If cursor P1 refers to an SQL index, then P3 is the first in an array of P4 registers that are used as an unpacked index key. Reposition cursor P1 so that it points to the smallest entry that is greater than the key value. If there are no records greater than the key and P2 is not zero, then jump to P2.
该操作码将光标配置为从开始到结束以正向顺序移动。换句话说,游标被配置为使用 Next,而不是 Prev。
另见:Found,Not Found,SeekLt,SeekGe,SeekLe
SeekLE If cursor P1 refers to an SQL table (B-Tree that uses integer keys), use the value in register P3 as a key. If cursor P1 refers to an SQL index, then P3 is the first in an array of P4 registers that are used as an unpacked index key. Reposition cursor P1 so that it points to the largest entry that is less than or equal to the key value. If there are no records less than or equal to the key and P2 is not zero, then jump to P2.
该操作码将光标配置为按照相反的顺序移动,从末端开始。换句话说,游标被配置为使用 Prev,而不是 Next。
如果使用 OPFLAG_SEEKEQ 标志打开游标 P1,则该操作码将始终落在等于该键的记录上,否则立即跳转到 P2。当光标是 OPFLAG_SEEKEQ 时,该操作码后面必须跟着一个具有相同参数的 IdxGE 操作码。如果此操作码成功,则会跳过 IdxGE 操作码,但 IdxGE 操作码将用于后续循环迭代。
另见:Found,NotFound,SeekGt,SeekGe,SeekLt
SeekLT If cursor P1 refers to an SQL table (B-Tree that uses integer keys), use the value in register P3 as a key. If cursor P1 refers to an SQL index, then P3 is the first in an array of P4 registers that are used as an unpacked index key. Reposition cursor P1 so that it points to the largest entry that is less than the key value. If there are no records less than the key and P2 is not zero, then jump to P2.
该操作码将光标配置为按照相反的顺序移动,从末端开始。换句话说,游标被配置为使用 Prev,而不是 Next。
另见:Found,NotFound,SeekGt,SeekGe,SeekLe
SeekRowid P1 is the index of a cursor open on an SQL table btree (with integer keys). If register P3 does not contain an integer or if P1 does not contain a record with rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an SQLITE\_CORRUPT error. If P1 does contain a record with rowid P3 then leave the cursor pointing at that record and fall through to the next instruction. The [NotExists](opcode#NotExists) opcode performs the same operation, but with [NotExists](opcode#NotExists) the P3 register must be guaranteed to contain an integer value. With this opcode, register P3 might not contain an integer.
NotFound 操作码对索引树(使用任意多值键)执行相同的操作。
该操作码将光标置于无法在任一方向上前进的状态。换句话说,在此操作码之后,Next 和 Prev 操作码将不起作用。
另见:Found,NotFound,NoConflict,SeekRowid
Sequence Find the next available sequence number for cursor P1. Write the sequence number into register P2. The sequence number on the cursor is incremented after this instruction. SequenceTest P1 is a sorter cursor. If the sequence counter is currently zero, jump to P2. Regardless of whether or not the jump is taken, increment the the sequence value. SetCookie Write the integer value P3 into cookie number P2 of database P1. P2==1 is the schema version. P2==2 is the database format. P2==3 is the recommended pager cache size, and so forth. P1==0 is the main database file and P1==1 is the database file used to store temporary tables. A transaction must be started before executing this opcode.
ShiftLeft Shift the integer value in register P2 to the left by the number of bits specified by the integer in register P1. Store the result in register P3. If either input is NULL, the result is NULL. ShiftRight Shift the integer value in register P2 to the right by the number of bits specified by the integer in register P1. Store the result in register P3. If either input is NULL, the result is NULL. SoftNull Set register P1 to have the value NULL as seen by the [MakeRecord](opcode#MakeRecord) instruction, but do not free any string or blob memory associated with the register, so that if the value was a string or blob that was previously copied using [SCopy](opcode#SCopy), the copies will continue to be valid. Sort This opcode does exactly the same thing as [Rewind](opcode#Rewind) except that it increments an undocumented global variable used for testing. Sorting is accomplished by writing records into a sorting index, then rewinding that index and playing it back from beginning to end. We use the [Sort](opcode#Sort) opcode instead of [Rewind](opcode#Rewind) to do the rewinding so that the global variable will be incremented and regression tests can determine whether or not the optimizer is correctly optimizing out sorts.
SorterCompare P1 is a sorter cursor. This instruction compares a prefix of the record blob in register P3 against a prefix of the entry that the sorter cursor currently points to. Only the first P4 fields of r[P3] and the sorter record are compared. If either P3 or the sorter contains a NULL in one of their significant fields (not counting the P4 fields at the end which are ignored) then the comparison is assumed to be equal.
如果两个记录的比较相等,则转入下一条指令。如果它们不同,则跳到P2。
SorterData Write into register P2 the current sorter data for sorter cursor P1. Then clear the column header cache on cursor P3. This opcode is normally use to move a record out of the sorter and into a register that is the source for a pseudo-table cursor created using [OpenPseudo](opcode#OpenPseudo). That pseudo-table cursor is the one that is identified by parameter P3. Clearing the P3 column cache as part of this opcode saves us from having to issue a separate [NullRow](opcode#NullRow) instruction to clear that cache.
SorterInsert Register P2 holds an SQL index key made using the [MakeRecord](opcode#MakeRecord) instructions. This opcode writes that key into the sorter P1. Data for the entry is nil. SorterNext This opcode works just like [Next](opcode#Next) except that P1 must be a sorter object for which the [SorterSort](opcode#SorterSort) opcode has been invoked. This opcode advances the cursor to the next sorted record, or jumps to P2 if there are no more sorted records. SorterOpen This opcode works like [OpenEphemeral](opcode#OpenEphemeral) except that it opens a transient index that is specifically designed to sort large tables using an external merge-sort algorithm. If argument P3 is non-zero, then it indicates that the sorter may assume that a stable sort considering the first P3 fields of each key is sufficient to produce the required results.
SorterSort After all records have been inserted into the Sorter object identified by P1, invoke this opcode to actually do the sorting. [Jump](opcode#Jump) to P2 if there are no records to be sorted. This opcode is an alias for [Sort](opcode#Sort) and [Rewind](opcode#Rewind) that is used for Sorter objects.
SqlExec Run the SQL statement or statements specified in the P4 string. String The string value P4 of length P1 (bytes) is stored in register P2. If P3 is not zero and the content of register P3 is equal to P5, then the datatype of the register P2 is converted to BLOB. The content is the same sequence of bytes, it is merely interpreted as a BLOB instead of a string, as if it had been CAST. In other words:
如果(P3!= 0和 regP3 == P5)regP2:= CAST(regP2为BLOB)
String8 P4 points to a nul terminated UTF-8 string. This opcode is transformed into a [String](opcode#String) opcode before it is executed for the first time. During this transformation, the length of string P4 is computed and stored as the P1 parameter. Subtract Subtract the value in register P1 from the value in register P2 and store the result in register P3. If either input is NULL, the result is NULL. TableLock Obtain a lock on a particular table. This instruction is only used when the shared-cache feature is enabled. P1 is the index of the database in sqlite3.aDb[] of the database on which the lock is acquired. A readlock is obtained if P3==0 or a write lock if P3==1.
P2包含要锁定的表的根页面。
P4包含一个指向被锁定表的名字的指针。如果无法获取锁,则仅用于生成错误消息。
Transaction Begin a transaction on database P1 if a transaction is not already active. If P2 is non-zero, then a write-transaction is started, or if a read-transaction is already active, it is upgraded to a write-transaction. If P2 is zero, then a read-transaction is started. P1 is the index of the database file on which the transaction is started. Index 0 is the main database file and index 1 is the file used for temporary tables. Indices of 2 or more are used for attached databases.
如果写入事务开始并且 Vdbe.usesStmtJournal 标志为真(如果Vdbe 可能修改多行并可能引发 ABORT 异常,则设置此标志),也可以打开语句事务。更具体地说,如果数据库连接当前不处于自动提交模式,或者存在其他活动语句,则会打开语句事务。语句事务允许在发生错误后回滚此 VDBE 所做的更改,而无需回滚整个事务。如果没有遇到错误,语句事务将在 VDBE 暂停时自动提交。
如果 P5!= 0,那么这个操作码也检查针对P3的模式 cookie 和针对 P4的模式生成计数器。每当数据库模式更改时,Cookie 都会更改其值。此操作用于检测 cookie 何时发生更改以及当前进程是否需要重新读取模式。如果P3中的模式 cookie 与数据库头中的模式 cookie 不同,或者P4中的模式生成计数器与当前生成计数器不同,则会引发 SQLITE_SCHEMA 错误并停止执行。然后,sqlite3_step()包装函数可以重新声明语句并从头开始重新运行它。
Vacuum Vacuum the entire database P1. P1 is 0 for "main", and 2 or more for an attached database. The "temp" database may not be vacuumed. Variable Transfer the values of bound parameter P1 into register P2 If the parameter is named, then its name appears in P4. The P4 value is used by sqlite3\_bind\_parameter\_name().
VBegin P4 may be a pointer to an sqlite3\_vtab structure. If so, call the xBegin method for that table. Also, whether or not P4 is set, check that this is not being called from within a callback to a virtual table xSync() method. If it is, the error code will be set to SQLITE\_LOCKED.
VColumn Store the value of the P2-th column of the row of the virtual-table that the P1 cursor is pointing to into register P3. VCreate P2 is a register that holds the name of a virtual table in database P1. Call the xCreate method for that table. VDestroy P4 is the name of a virtual table in database P1. Call the xDestroy method of that table. VFilter P1 is a cursor opened using [VOpen](opcode#VOpen). P2 is an address to jump to if the filtered result set is empty. P4 is either NULL or a string that was generated by the xBestIndex method of the module. The interpretation of the P4 string is left to the module implementation.
该操作码调用 P1指定的虚拟表上的 xFilter 方法。xFilter 的整数查询计划参数存储在寄存器P3中。寄存器 P3 + 1存储要传递给xFilter 方法的 argc 参数。寄存器 P3 + 2..P3 + 1 + argc 是作为argv传递给 xFilter 的 argc 附加参数。传递给xFilter时,寄存器P3 + 2变为 argv0。
如果过滤后的结果集为空,则跳转到 P2。
VNext Advance virtual table P1 to the next row in its result set and jump to instruction P2. Or, if the virtual table has reached the end of its result set, then fall through to the next instruction. VOpen P4 is a pointer to a virtual table object, an sqlite3\_vtab structure. P1 is a cursor number. This opcode opens a cursor to the virtual table and stores that cursor in P1. VRename P4 is a pointer to a virtual table object, an sqlite3\_vtab structure. This opcode invokes the corresponding xRename method. The value in register P1 is passed as the zName argument to the xRename method. VUpdate P4 is a pointer to a virtual table object, an sqlite3\_vtab structure. This opcode invokes the corresponding xUpdate method. P2 values are contiguous memory cells starting at P3 to pass to the xUpdate invocation. The value in register (P3+P2-1) corresponds to the p2th element of the argv array passed to xUpdate. The xUpdate method will do a DELETE or an INSERT or both. The argv[0] element (which corresponds to memory cell P3) is the rowid of a row to delete. If argv[0] is NULL then no deletion occurs. The argv[1] element is the rowid of the new row. This can be NULL to have the virtual table select the new rowid for itself. The subsequent elements in the array are the values of columns in the new row.
如果 P2 == 1,则不执行插入。argv0 是要删除的行的 rowid。
P1 是一个布尔标志。如果它设置为 true 并且 xUpdate 调用成功,则 sqlite3_last_insert_rowid()返回的值将设置为刚刚插入的行的 rowid 值。
P5 是在插入或更新约束失败的情况下应用的错误操作(OE_Replace,OE_Fail,OE_Ignore 等)。
Yield Swap the program counter with the value in register P1. This has the effect of yielding to a coroutine. If the coroutine that is launched by this instruction ends with [Yield](opcode#Yield) or [Return](opcode#Return) then continue to the next instruction. But if the coroutine launched by this instruction ends with [EndCoroutine](opcode#EndCoroutine), then jump to P2 rather than continuing with the next instruction.