Small. Fast. Reliable.
Choose any three.
SQLite字节码引擎

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”开头-“ vdbe”是“ Virtual DataBase Engine”的缩写。

请记住,操作码的名称和含义通常会从一个版本的SQLite更改为下一个版本。因此,如果您正在研究 SQLite的EXPLAIN输出,则应参考与运行EXPLAIN的SQLite版本相对应的本文档版本(或vdbe.c源代码)。否则,操作码的描述可能不准确。这份文件是从SQLite的版本3.35.5衍生入住手续 1b256d97b553a日期2021年4月19日。

2.2。指令格式

SQLite中的字节编码程序由一个或多个指令组成。每个指令都有一个操作码和五个名为P1,P2,P3,P4和P5的操作数。P1,P2和P3操作数是32位带符号整数。这些操作数通常引用寄存器。对于对b树游标进行操作的指令,P1操作数通常是游标编号。对于跳转指令,P2通常是跳转目标。P4可以是32位有符号整数,64位有符号整数,64位浮点值,字符串文字,Blob文字,指向整理序列比较功能的指针或指向实现的指针。应用程序定义的SQL函数或其他各种东西。P5是16位无符号整数,通常用于保存标志。P5标志的位有时会以微妙的方式影响操作码。例如,操作码,则NULL值比较彼此相等。否则,NULL值彼此比较不同。

一些操作码使用所有五个操作数。一些操作码使用一两个。某些操作码不使用任何操作数。

字节码引擎从0号指令开始执行。执行将继续,直到看到Halt指令,或者直到程序计数器大于最后一条指令的地址为止,或者直到出现错误为止。当字节码引擎暂停时,将释放其分配的所有内存,并关闭可能已打开的所有数据库游标。如果执行由于错误而停止,则所有挂起的事务都将终止,并且对数据库所做的更改将回滚。

ResultRow操作码能够使字节码引擎暂停和相应的sqlite3_step() 来调用返回SQLITE_ROW。在调用ResultRow之前 ,字节码程序将查询的单行结果加载到一系列寄存器中。诸如sqlite3_column_int()sqlite3_column_text()之类的C语言API从这些寄存器中提取查询结果。字节码引擎在下一次调用sqlite3_step()时ResultRow之后的下一条指令恢复。

2.3。登记册

每个字节码程序都有固定数量(但可能很大)的寄存器。一个寄存器可以容纳各种对象:

寄存器也可以是“未定义”的,这意味着它根本不保存任何值。未定义与NULL不同。根据编译时选项,尝试读取未定义的寄存器通常会导致运行时错误。如果代码生成器(sqlite3_prepare_v2())生成了一条准备就绪的语句来读取未定义的寄存器,则这是代码生成器中的错误。

寄存器从0开始编号。大多数操作码都引用至少一个寄存器。

单个准备好的语句中的寄存器数量在编译时是固定的。当重置结束准备好的语句时,将清除所有寄存器的内容。

内部Mem对象存储单个寄存器的值。API中公开的抽象sqlite3_value对象实际上只是一个Mem对象或寄存器。

2.4。B树光标

一个准备好的语句可以有零个或多个打开的游标。每个游标都由一个小整数标识,该整数通常是使用游标的操作码的P1参数。在同一索引或表上可以有多个游标。所有游标都独立运行,即使游标指向相同的索引或表也是如此。虚拟机与数据库文件交互的唯一方法是通过游标。虚拟机中的指令可以创建一个新的游标(例如:OpenReadOpenWrite),从游标中读取数据(Column),将游标前进到表中的下一个条目(例如:NextPrev),依此类推。重置准备好的语句后,所有游标都会自动关闭或已 定稿

2.5。子例程,协程和子程序

字节码引擎没有用于存储子例程的返回地址的堆栈。返回地址必须存储在寄存器中。因此,字节码子例程不可重入。

GOSUB操作码存储当前程序计数器到寄存器P1,然后跳转到地址P2。在返回操作码跳转到地址P1 + 1。因此,每个子例程都与两个整数相关联:子例程中入口点的地址和用于保存返回地址的寄存器号。

产率操作码交换与在寄存器P1中的整数值的程序计数器的值。此操作码用于实现协程。协程通常用于实现子查询,根据需要从这些子查询中提取内容。

触发器需要重新进入。由于字节码子例程不可重入,因此必须使用不同的机制来实现触发器。每个触发器都是使用单独的字节码程序实现的,该程序具有自己的操作码,程序计数器和寄存器集。该 方案操作码调用子程序触发。该程序指令分配和初始化的子程序的每次调用一个新的寄存器组,所以子程序可以递进和回归。所述 帕拉姆操作码所使用的子程序来访问内容在主叫字节码程序的寄存器。

2.6。自行更改代码

有些操作码会自动更改。例如,Init操作码(始终是每个字节码程序中的第一个操作码)都会递增其P1操作数。随后的 一次操作码将其P1操作数与Init操作码的P1值进行比较,以确定是否应跳过后面的一次性初始化代码。另一个示例是String8操作码,它将其P4操作数从UTF-8转换为正确的数据库字符串编码,然后将自身转换为String操作码。

3.查看字节码

SQLite解释的每个SQL语句都会为虚拟机生成一个程序。但是,如果SQL语句以关键字EXPLAIN开头,则虚拟机将不会执行该程序。而是返回程序的指令,每行一条指令,如查询结果。此功能对于调试和了解虚拟机的运行方式很有用。例如:

sqlite3 ex1.db 
sqlite> 解释从tbl1删除的内容,其中two <20;
addr操作码p1 p2 p3 p4 p5注释      
---------- -------
0初始化0 12 0 00从12开始  
1空0 1 0 00 r [1] = NULL    
2 OpenWrite 0 2 0 3 00 root = 2 iDb = 0; tbl1
3倒带0 10 0 00               
4列0 1 2 00 r [2] = tbl1.two
5 Ge 3 9 2(BINARY)51如果r [2]> = r [3]转到9
6 Rowid 0 4 0 00 r [4] = rowid   
7一次0 8 0 00               
8删除0 1 0 tbl1 02               
9下一个0 4 0 01               
10 Noop 0 0 0 00               
11暂停0 0 0 00               
12交易0 1 1 0 01 useStmtJournal = 0
13 TableLock 0 2 1 tbl1 00 iDb = 0根= 2写= 1
14整数20 3 0 00 r [3] = 20      
15转到0 1 0 00

任何应用程序都可以运行EXPLAIN查询以获取与上述类似的输出。但是,显示循环结构的缩进不是SQLite核心生成的。在命令行shell包含缩进循环额外的逻辑。另外,仅当使用-DSQLITE_ENABLE_EXPLAIN_COMMENTS选项编译SQLite时,才提供EXPLAIN输出中 的“注释”列。

当使用SQLITE_DEBUG编译时选项编译SQLite时,将提供额外的PRAGMA命令,这些命令对于调试和探索VDBE的操作很有用。例如, 可以启用vdbe_trace编译指示,以使每个VDBE操作码的反汇编在执行操作码时打印在标准输出上。这些调试实用程序包括:

4.操作码

虚拟机当前定义了178个操作码。下表描述了所有当前定义的操作码。该表是通过扫描文件vdbe.c中的源代码自动生成的 。

切记:VDBE操作码不是SQLite接口定义的一部分。操作码的数量及其名称和含义从一个SQLite版本更改为另一个版本。下表中显示的操作码对日期为2021-04-19的SQLite版本3.35.5签入 1b256d97b553a有效。

操作码名称描述
可终止 验证是否可能发生中止。断言此时是否中止可能导致数据库损坏。该操作码仅出现在调试版本中。

如果没有写操作,或者有活动的语句日志,则中止是安全的。

添加 将寄存器P1中的值加到寄存器P2中的值,并将结果存储在寄存器P3中。如果任一输入为NULL,则结果为NULL。
AddImm 将常数P2加到寄存器P1中的值。结果始终是整数。

要将任何寄存器强制为整数,只需加0。

亲和力 对从P1开始的一系列P2寄存器应用亲和力。

P4是一个字符串,长度为P2个字符。字符串的第N个字符表示该范围内第N个存储单元应使用的列亲和力。

总决赛 P1是存储位置,是聚合或窗口函数的累加器。对汇总执行finalizer函数,并将结果存储在P1中。

P2是步进函数采用的参数数量,P4是指向该函数的FuncDef的指针。该操作码不使用P2参数。只有在这里才能消除可以采用不同数量参数的函数的歧义。仅在先前未调用step函数的情况下才需要P4参数。

AggInverse 对集合执行xInverse函数。该函数具有P5参数。P4是指向指定函数的FuncDef结构的指针。寄存器P3是累加器。

P5自变量取自寄存器P2及其后续寄存器。

AggStep 对集合执行xStep函数。该函数具有P5参数。P4是指向指定函数的FuncDef结构的指针。寄存器P3是累加器。

P5自变量取自寄存器P2及其后续寄存器。

AggStep1 对聚合执行xStep(如果P1 == 0)或xInverse(如果P1!= 0)功能。该函数具有P5参数。P4是指向指定函数的FuncDef结构的指针。寄存器P3是累加器。

P5自变量取自寄存器P2及其后续寄存器。

该操作码最初被编码为OP_AggStep0。第一次评估时,将存储在P4中的FuncDef转换为sqlite3_context并更改操作码。这样,sqlite3_context的初始化仅发生一次,而不是在每次调用step函数时进行。

AggValue 调用xValue()函数并将结果存储在寄存器P3中。

P2是步进函数采用的参数数量,P4是指向该函数的FuncDef的指针。该操作码不使用P2参数。只有在这里才能消除可以采用不同数量参数的函数的歧义。仅在先前未调用step函数的情况下才需要P4参数。

对寄存器P1和P2中的值进行逻辑与,并将结果写入寄存器P3中。

如果P1或P2为0(否),那么即使另一个输入为NULL,结果也为0。NULL和true或两个NULL给出NULL输出。

自动提交 将数据库自动提交标志设置为P1(1或0)。如果P2为true,则回滚任何当前活动的btree事务。如果有活动的VM(除此VM外),则ROLLBACK失败。如果存在活动的写入VM或使用共享缓存的活动VM,则COMMIT会失败。

该指令导致VM停止。

比特与 对寄存器P1和P2中的值进行按位与运算,并将结果存储在寄存器P3中。如果任一输入为NULL,则结果为NULL。
位不 将寄存器P1的内容解释为整数。将P1值的1补码存储到寄存器P2中。如果P1保留NULL,则将NULL存储在P2中。
比特或 对寄存器P1和P2中的值进行按位“或”运算,并将结果存储在寄存器P3中。如果任一输入为NULL,则结果为NULL。
斑点 P4指向数据B1字节长的blob。将该Blob存储在寄存器P2中。
强制将寄存器P1中的值设置为P2定义的类型。

  • P2 =='A'→BLOB
  • P2 =='B'→文本
  • P2 =='C'→数值
  • P2 =='D'→整数
  • P2 =='E'→实数

此例程不会更改NULL值。它保持为空。

检查站 检查点数据库P1。如果P1当前不在WAL模式下,则此操作为空操作。参数P2是SQLITE_CHECKPOINT_PASSIVE,FULL,RESTART或TRUNCATE之一。如果检查点是否分别返回SQLITE_BUSY,则分别将1或0写入mem [P3]。将检查点之后的WAL中的页数写入mem [P3 + 1],并将检查点完成之后的WAL中已被检查点的页数写入mem [P3 + 2]。但是,发生错误时,会将mem [P3 + 1]和mem [P3 + 2]初始化为-1。
中文行 由于设置了“ PRAGMA count_changes = ON”,因此将寄存器P1中的输出值作为DML语句的机会计数。或者,如果语句中有外键错误,请立即触发该错误。

此操作码是ResultRow的变体,它检查外键立即约束计数,如果计数不为零,则抛出错误。P2操作码必须为1。

清除 删除数据库表或索引的所有内容,这些表或索引的数据库文件在根文件中由P1指定。但是,与Destroy不同,请不要从数据库文件中删除表或索引。

如果P2 == 0,则要清除的表位于主数据库文件中。如果P2 == 1,则要清除的表位于辅助数据库文件中,该文件用于存储使用CREATE TEMPORARY TABLE创建的表。

如果P3值不为零,则所引用的表必须是intkey表(SQL表,而不是索引)。在这种情况下,行更改计数将增加要清除的表中的行数。如果P3大于零,则存储在寄存器P3中的值也会增加要清除的表中的行数。

另请参阅:销毁

关闭 关闭先前以P1打开的游标。如果P1当前未打开,则该指令为无操作。
CollSeq P4是指向CollSeq对象的指针。如果下一次调用用户函数或聚合调用sqlite3GetFuncCollSeq(),则将返回此整理序列。内置的min(),max()和nullif()函数使用此函数。

如果P1不为零,则它是一个寄存器,如果当前行不是最小值或最大值,则随后的min()或max()聚合将设置为1。通过该指令将P1寄存器初始化为0。

前述功能的实现所使用的用于检索此操作码设置的排序规则序列的接口不是公开可用的。只有内置功能可以访问此功能。

柱子 将光标P1指向的数据解释为使用MakeRecord指令构建的结构。(有关数据格式的其他信息,请参见MakeRecord操作码。)从该记录中提取第P2列。如果记录中的值少于(P2 + 1),则提取NULL。

提取的值存储在寄存器P3中。

如果记录包含少于P2字段,则提取NULL。或者,如果P4参数是P4_MEM,则使用P4参数的值作为结果。

如果在P5上将OPFLAG_LENGTHARG和OPFLAG_TYPEOFARG位置1,则保证结果仅分别用作length()或typeof()函数的参数。可以跳过length()的大blob的加载,而对于typeof()的所有内容的加载都可以跳过。

使用的列 该操作码(仅当使用SQLITE_ENABLE_COLUMN_USED_MASK编译SQLite时才存在)标识使用游标P1的表或索引的哪些列。P4是一个64位整数(P4_INT64),其中对于表或索引实际使用的表或索引的前63列中的每一列,前63位是一个。如果使用第64位之后的任何列,则设置高位。
比较 比较reg(P1).. reg(P1 + P3-1)中的两个寄存器向量(将此向量称为“ A”)和reg(P2).. reg(P2 + P3-1)中的寄存器(“ B”)。保存比较结果,以供下一个Jump指令使用。

如果P5的OPFLAG_PERMUTE位置1,则比较顺序由最新的置换运算符确定。如果OPFLAG_PERMUTE位清零,则按顺序比较寄存器。

P4是KeyInfo结构,用于定义比较序列和排序顺序以进行比较。排列仅适用于寄存器。KeyInfo元素按顺序使用。

比较是一种排序比较,因此NULL比较相等,NULL小于数字,数字小于字符串,并且字符串小于Blob。

康卡特 将寄存器P1中的文本添加到寄存器P2中文本的末尾,并将结果存储在寄存器P3中。如果P1或P2文本为NULL,则将NULL存储在P3中。

P3 = P2 || P1

P1和P3是同一寄存器是非法的。有时,如果P3与P2是同一寄存器,则实现可以避免使用memcpy()。

复制 将寄存器P1..P1 + P3复制到寄存器P2..P2 + P3。

该指令对值进行了深层复制。任何字符串或blob常量均构成重复项。另请参见SCopy

数数 将由光标P1打开的表或索引中的条目数(整数值)存储在寄存器P2中。

如果P3 == 0,则获得一个精确的计数,该计数涉及访问表的每个btree页。但是,如果P3不为零,则根据当前光标位置返回一个估计值。

创建树 如果P1 == 0,则在主数据库文件中分配新的b树;如果P1 == 1,则在TEMP数据库文件中分配新树;如果P1> 1,则在附加数据库中分配新树。对于rowid表,P3参数必须为1(BTREE_INTKEY),对于索引或WITHOUT ROWID表,P3参数必须为2(BTREE_BLOBKEY)。新b树的根页号存储在寄存器P2中。
光标提示 向游标P1提供提示,提示它仅需要返回满足P4中Expr的行。P4表达式中的TK_REGISTER术语是指当前保存在寄存器中的值。P4表达式中的TK_COLUMN术语指的是光标P1指向的b树中的列。
光标锁定 锁定光标P1指向的btree,以便其他光标无法写入btree。
光标解锁 解锁光标P1指向的btree,以便其他光标可以写入它。
减零 寄存器P1必须包含一个整数。减小P1中的值,如果新值恰好为零,则跳至P2。
延期寻求 P1是开放索引游标,P3是相应表上的游标。此操作码将P3表光标推迟到与P1当前行相对应的行。

这是一个延迟的寻求。在使用光标读取记录之前,实际上什么也没有发生。这样,如果没有读取发生,则不会发生不必要的I / O。

P4可以是整数数组(类型P4_INTARRAY),其中包含P3表中每一列的一个条目。如果数组项a(i)不为零,则从游标P3读取列a(i)-1等效于执行延迟搜索,然后从P1读取列i。此信息存储在P3中,并用于将对P3的读取重定向到P1,因此可能避免了寻找和读取游标P3的需要。

删除 删除P1光标当前指向的记录。

如果将P5参数的OPFLAG_SAVEPOSITION位置1,则光标将指向表中的下一个或上一个记录。如果它指向下一条记录,则下一条Next指令将是空操作。结果,在这种情况下,可以从Next循环中删除记录。如果P5的OPFLAG_SAVEPOSITION位清零,则光标将处于未定义状态。

如果在P5上将OPFLAG_AUXDELETE位置1,则表明此删除操作与删除表行及其所有相关的索引条目相关联,是其中之一。这些删除的确切之一是“主要”删除。其他的都在OPFLAG_FORDELETE游标上,或者标有AUXDELETE标志。

如果设置了P2的OPFLAG_NCHANGE标志(NB:P2而不是P5),则行更改计数增加(否则不增加)。

P1一定不能是伪表。它必须是具有多行的真实表。

如果P4不为NULL,则它指向一个Table对象。在这种情况下,可以调用更新钩子或更新前钩子,或两者都被调用。在这种情况下,在调用此操作码之前,必须已使用NotFound定位了P1光标。具体来说,如果配置了一个,则如果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中。

如果在调用该操作码时有活动的读取器VM,则此操作码将引发错误。这样做是为了避免在AUTOVACUUM数据库中移动根页时与更新现有游标相关的困难。即使数据库不是AUTOVACUUM db,也会抛出此错误,以避免在autovacuum和非autovacuum模式之间引入不兼容性。

另请参阅:清除

划分 将寄存器P1中的值除以寄存器P2中的值,然后将结果存储在寄存器P3中(P3 = P2 / P1)。如果寄存器P1中的值为零,则结果为NULL。如果任一输入为NULL,则结果为NULL。
DropIndex 删除描述数据库P1中名为P4的索引的内部(内存中)数据结构。从磁盘上删除索引(使用Destroy操作码)后,将调用此方法,以使模式的内部表示与磁盘上的内容保持一致。
删除表 删除描述数据库P1中名为P4的表的内部(内存中)数据结构。在将表从磁盘上删除(使用Destroy操作码)后,将调用此方法,以使模式的内部表示与磁盘上的内容保持一致。
DropTrigger 删除描述数据库P1中名为P4的触发器的内部(内存中)数据结构。在触发器从磁盘上删除(使用Destroy操作码)之后,将调用此命令,以使模式的内部表示与磁盘上的内容保持一致。
ElseNotEq 该操作码必须遵循LtGt比较运算符。可能有零个或多个OP_ReleaseReg操作码,但此指令与先前的LtGt之间不允许出现其他操作码 。此外,先前的LtGt必须在P5字段中设置SQLITE_STOREP2位。

如果对与先前LtGt相同的两个操作数进行Eq比较的结果为NULL或false(0),则跳至P2。如果对前两个操作数进行Eq比较的结果为true(1),则失败。

协程 寄存器P1中地址处的指令为Yield跳至收益率的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,则将比较这些值。如果两个值都是blob,则使用memcmp()确定比较结果。如果两个值都是文本,则使用P4中指定的适当整理函数进行比较。如果未指定P4,则使用memcmp()比较文本字符串。如果两个值都是数字,则使用数字比较。如果两个值的类型不同,则数字被认为小于字符串,而字符串被认为小于斑点。

如果在P5中设置了SQLITE_NULLEQ,则比较结果始终为true或false,并且永远不会为NULL。如果两个操作数均为NULL,则比较结果为true。如果任一操作数为NULL,则结果为false。如果两个操作数都不为NULL,则结果与从P5省略SQLITE_NULLEQ标志的结果相同。

如果同时设置了SQLITE_STOREP2和SQLITE_KEEPNULL标志,则仅当新值为NULL或0(假)时,才更改r [P2]的内容。换句话说,先前的r [P2]值不会被1(true)覆盖。

到期 使预编译的语句到期。当使用sqlite3_step()执行过期的语句时,它将自动自动重复(如果它最初是使用sqlite3_prepare_v2()创建的),否则将失败,并使用SQLITE_SCHEMA失败。

如果P1为0,则所有SQL语句都将过期。如果P1不为零,则仅当前正在执行的语句到期。

如果P2为0,则SQL语句立即过期。如果P2为1,则允许正在运行的SQL语句继续运行以完成操作。当发生CREATE INDEX或类似的模式更改时,会发生P2 == 1的情况,这可能有助于语句更快地运行,但不影响操作的正确性。

完成搜索 如果光标P1先前已通过DeferredSeek进行了移动,请立即完成该搜索操作,而不会造成进一步延迟。如果光标搜索已经发生,则该指令为无操作。
FkCounter 将“约束计数器”增加P2(P2可以为负或正)。如果P1不为零,则数据库约束计数器增加(延迟的外键约束)。否则,如果P1为零​​,则语句计数器递增(立即外键约束)。
零零 此操作码测试外键约束计数器当前是否为零。如果是这样,请跳至指令P2。否则,请继续执行下一条指令。

如果P1不为零,则在数据库约束计数器为零(对延迟约束违规进行计数的计数器)为零时进行跳转。如果P1为零​​,则在语句constraint-counter为零(立即违反外键约束)的情况下进行跳转。

成立 如果P4 == 0,则寄存器P3包含由MakeRecord构造的blob。如果P4> 0,则寄存器P3是构成未打包记录的P4寄存器中的第一个。

光标P1在索引btree上。如果由P3和P4标识的记录是P1中任何条目的前缀,则跳转到P2,并且P1指向匹配的条目。

该操作使光标处于可以向前移动的状态。在接下来的指令将工作,但不是上一个指令。

另请参见:NotFoundNoConflictNotExists。寻求

功能 使用从寄存器P2和后续函数中获取的参数调用用户函数(P4是指向sqlite3_context对象的指针,该对象包含要运行的函数的指针)。参数的数量在P4指向的sqlite3_context对象中。功能的结果存储在寄存器P3中。寄存器P3不得为功能输入之一。

P1是一个32位的位掩码,指示该函数的每个参数在编译时是否确定为常量。如果第一个参数是常量,则设置P1的位0。这用于确定是否可以安全保留与使用sqlite3_set_auxdata()API的用户功能参数关联的元数据,直到下一次调用此操作码为止。

另请参阅:AggStepAggFinalPureFunc

通用电器 除了寄存器P3的内容大于或等于寄存器P1的内容会发生跳转之外,这与Lt操作码的工作原理相同。有关其他信息,请参见Lt操作码。
Gosub 将当前地址写入寄存器P1,然后跳转到地址P2。
无条件跳转到地址P2。从程序开始,下一条执行的指令将是索引P2处的指令。

该操作码实际上未使用P1参数。但是,有时会将其设置为1而不是0,以提示命令行外壳程序此Goto是循环的底部,并且应该缩进从P2到当前行的行以进行EXPLAIN输出。

t 除了寄存器P3的内容大于寄存器P1的内容会进行跳转之外,这与Lt操作码的工作原理相同。有关其他信息,请参见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不为null,则为错误消息字符串。

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”指令。因此,跳过程序的最后一条指令与执行Halt相同。

HaltIfNull 检查寄存器P3中的值。如果是NULL,则暂停使用参数P1,P2和P4仿佛这是一个暂停指令。如果寄存器P3中的值不为NULL,则该例程为空操作。P5参数应为1。
IdxDelete 从寄存器P2开始的P3寄存器的内容形成一个未打包的索引键。该操作码从光标P1打开的索引中删除该条目。

如果P5不为零,则在找不到匹配的索引条目的情况下引发SQLITE_CORRUPT_INDEX错误。当运行UPDATE或DELETE语句并且找不到要更新或删除的索引条目时,会发生这种情况。对于IdxDelete的某些用法 (例如:EXCEPT运算符),没有匹配的条目都没关系。对于这些情况,P5为零。

标识号 以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树层此插入可能是附加项。

如果P5的OPFLAG_NCHANGE位置1,则更改计数器由该指令递增。如果OPFLAG_NCHANGE位清零,则更改计数器不变。

如果设置了P5的OPFLAG_USESEEKRESULT标志,则通过避免在游标P1上进行不必要的查找,实现可能会运行得更快。但是,仅当游标上没有在先搜索或最近的搜索使用等效于P2的键时,才必须设置OPFLAG_USESEEKRESULT标志。

该指令仅适用于索引。表的等效指令是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。

另请参见:RowidMakeRecord

如果 如果寄存器P1中的值为true,则跳转到P2。如果该值为数字且非零,则认为该值为true。如果P1中的值为NULL,则仅当P3为非零时才进行跳转。
如果没有希望 寄存器P3是构成未包装记录的P4寄存器中的第一个。光标P1是索引btree。P2是跳转目标。换句话说,此操作码的操作数与NotFoundIdxGT的操作数相同。

此操作码仅是一种优化尝试。如果此操作码始终失败,则仍会获得正确的答案,但会执行额外的工作。

游标P1的seekHit标志中的N值表示存在与索引中的某些记录匹配的键P3:N。我们想知道记录P3:P4是否有可能与索引中的某些记录匹配。如果不可能,我们可以跳过一些工作。因此,如果seekHit小于P4,请尝试通过运行NotFound找出是否可以匹配 。

此操作码用于多列键的IN子句处理。如果将IN子句附加到除最左侧元素以外的其他键元素上,并且在对整个键的最近搜索中没有匹配项,则可能是左侧的键元素之一是禁止匹配,因此无论检查了多少IN子句元素,都“没有希望”进行任何匹配。在这种情况下,我们将使用此操作码尽早放弃I​​N子句搜索。操作码名称来自以下事实:如果“没有希望”实现匹配,则执行跳转。

另请参阅:NotFoundSeekHit

如果不 如果寄存器P1中的值为False,则跳至P2。如果该值的数字值为零,则将其视为false。如果P1中的值为NULL,则仅当P3为非零时才进行跳转。
IfNotOpen 如果光标P1没有打开,则跳转到指令P2。否则,跌倒。
如果不是零 寄存器P1必须包含一个整数。如果寄存器P1的内容最初大于零,则减小寄存器P1中的值。如果它不为零(负或正),则也跳到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。
真空吸尘器 在P1数据库上执行增量真空过程的单个步骤。如果抽真空完成,则跳至指令P2。否则,请继续执行下一条指令。
在里面 程序包含此操作码的单个实例作为第一个操作码。

如果通过sqlite3_trace()接口启用了跟踪,则P4中包含的UTF-8字符串将在跟踪回调中发出。或者,如果P4为空,请使用sqlite3_sql()返回的字符串。

如果P2不为零,则跳转到指令P2。

递增P1的值,以便一旦操作码在第一次运行时就跳转。

如果P3不为零,则它是遇到SQLITE_CORRUPT错误时要跳转到的地址。

初始化协程 设置寄存器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可以指向表结构,也可以为NULL。如果它不是NULL,则在成功插入之后将调用更新挂钩(sqlite3.xUpdateCallback)。

(警告/待办事项:如果P1是伪光标,并且P2是动态分配的,则P2的所有权将转移到伪光标,并且寄存器P2变为临时寄存器。如果更改了光标,则寄存器P2的值将随之更改。确保这不会引起任何问题。)

该指令仅适用于表。索引的等效指令是IdxInsert

整数64 P4是指向64位整数值的指针。将该值写入寄存器P2。
IntCopy 将寄存器P1中保存的整数值传送到寄存器P2中。

这是SCopy的优化版本,仅适用于整数值。

整数 将32位整数值P1写入寄存器P2。
诚信度 对当前打开的数据库进行分析。将描述任何问题的错误消息的文本存储在寄存器P1中。如果未发现问题,则将NULL存储在寄存器P1中。

寄存器P3包含比允许错误的最大数量少一的寄存器。最多会报告reg(P3)错误。换句话说,一旦看到reg(P1)错误,分析就会立即停止。Reg(P1)用剩余的错误数进行更新。

数据库中所有表的根页号是存储在P4_INTARRAY参数中的整数。

如果P5不为零,则检查是在辅助数据库文件而不是主数据库文件上进行的。

此操作码用于实现integrity_check编译指示。

一片空白 如果寄存器P1中的值为NULL,则跳至P2。
是真的 此操作码实现IS TRUE,IS FALSE,IS NOT TRUE和IS NOT FALSE运算符。

将寄存器P1中的值解释为布尔值。将该布尔值(0或1)存储在寄存器P2中。或者,如果寄存器P1中的值为NULL,则P3将存储在寄存器P2中。如果P4为1,则求反。

逻辑总结如下:

  • 如果P3 == 0且P4 == 0,则r [P2]:= r [P1]为TRUE
  • 如果P3 == 1且P4 == 1,则r [P2]:= r [P1]为假
  • 如果P3 == 0且P4 == 1,则r [P2]:= r [P1]不正确
  • 如果P3 == 1且P4 == 0,则r [P2]:= r [P1]不成立
日志模式 将数据库P1的日志模式更改为P3。P3必须是PAGER_JOURNALMODE_XXX值之一。如果在各种回滚模式(删除,截断,持久,关闭和内存)之间切换,这是一个简单的操作。不需要IO。

如果更改为WAL模式或退出WAL模式,则过程将更为复杂。

编写一个包含最终日志模式的字符串以注册P2。

取决于在最近的比较指令中P1向量分别小于等于还是大于P2向量,跳转到地址P1,P2或P3处的指令。
最后的 P1的RowidColumnPrev指令的下一次使用将引用数据库表或索引中的最后一个条目。如果表或索引为空并且P2> 0,则立即跳转到P2。如果P2为0,或者表或索引不为空,请执行以下指令。

此操作码使光标配置为从末尾到开头以相反的顺序移动。换句话说,游标被配置为使用Prev,而不是Next

除了寄存器P3的内容小于或等于寄存器P1的内容会发生跳转之外,这与Lt操作码的工作原理相同。有关其他信息,请参见Lt操作码。
负载分析 读取数据库P1的sqlite_stat1表,并将该表的内容加载到内部索引哈希表中。这将导致在准备所有后续查询时使用分析。
Lt 比较寄存器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,则将比较这些值。如果两个值都是blob,则使用memcmp()确定比较结果。如果两个值都是文本,则使用P4中指定的适当整理函数进行比较。如果未指定P4,则使用memcmp()比较文本字符串。如果两个值都是数字,则使用数字比较。如果两个值的类型不同,则数字被认为小于字符串,而字符串被认为小于斑点。

制作记录 将以P1开头的P2寄存器转换为记录格式, 用作数据库表中的数据记录或索引中的键。该码后可以解码记录。

P4可以是一个长度为P2个字符的字符串。字符串的第N个字符表示应用于索引键的第N个字段的列亲和力。

从字符到相似性的映射由sqliteInt.h中定义的SQLITE_AFF_宏给出。

如果P4为NULL,则所有索引字段都具有亲和力BLOB。

P5的含义取决于是否启用了SQLITE_ENABLE_NULL_TRIM编译时选项:

*如果启用了SQLITE_ENABLE_NULL_TRIM,则P5是可以进行空修剪的最右边表的索引。

*如果省略了SQLITE_ENABLE_NULL_TRIM,那么如果允许MakeRecord操作码接受serial_type 10的不变记录,则P5的值为OPFLAG_NOCHNG_MAGIC 。该值仅在assert()内部使用,不会影响最终结果。

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异常。
NE 这与Eq操作码的工作原理相同,不同之处在于,如果寄存器P1和P3中的操作数不相等,则会进行跳转。有关更多信息,请参见Eq操作码。

如果同时设置了SQLITE_STOREP2和SQLITE_KEEPNULL标志,则仅当新值为NULL或1(真)时,才更改r [P2]的内容。换句话说,先前的r [P2]值不会被0(假)覆盖。

NewRowid 获取一个新的整数记录号(又名“ rowid”)用作表的键。记录编号以前没有用作光标P1指向的数据库表中的键。新记录号被写入寄存器P2。

如果P3> 0,则P3是此VDBE根帧中的一个寄存器,其中包含最大的先前生成的记录号。不允许任何新的记录号小于该值。当该值达到最大值时,将生成一个SQLITE_FULL错误。用生成的记录号更新P3寄存器。此P3机制用于帮助实现AUTOINCREMENT功能。

下一个 前进游标P1,使其指向其表或索引中的下一个键/数据对。如果没有更多的键/值对,请遵循以下说明。但是,如果光标前进成功,请立即跳至P2。

下一步操作码之后的是唯一有效的SeekGTSeekGE,或 倒带用来定位光标的操作码。 Next不允许跟随SeekLTSeekLELast

P1游标必须用于真实表,而不是伪表。在此操作码之前,必须先打开P1,否则程序将出现段错误。

P3值是对btree实现的提示。如果P3 == 1,则表示P1是SQL索引,并且如果该索引是唯一的,则可以省略此指令。P3通常为0。P3始终为0或1。

P4始终为P4_ADVANCE类型。函数指针指向sqlite3BtreeNext()。

如果P5为正且已执行跳转,则准备好的语句中的事件计数器编号P5-1会增加。

另请参阅:上一页

无冲突 如果P4 == 0,则寄存器P3包含由MakeRecord构造的blob。如果P4> 0,则寄存器P3是构成未打包记录的P4寄存器中的第一个。

光标P1在索引btree上。如果由P3和P4标识的记录包含任何NULL值,请立即跳转到P2。如果记录的所有项都不为NULL,则进行检查以确定P1索引btree中的任何行是否具有匹配的键前缀。如果没有匹配项,请立即跳至P2。如果存在匹配项,则进入并保留指向匹配行的P1光标。

此操作码与NotFound相似,不同之处在于,如果搜索键输入的任何部分为NULL,则始终采用分支。

此操作使光标处于无法向任一方向前进的状态。换句话说,NextPrev 操作码在此操作后不起作用。

另请参见:NotFoundFoundNotExists

op 没做什么。该指令通常用作跳转目标。
不是 将寄存器P1中的值解释为布尔值。将布尔补码存储在寄存器P2中。如果寄存器P1中的值为NULL,则将NULL存储在P2中。
不存在 P1是在SQL表btree(带有整数键)上打开的游标的索引。P3是整数rowid。如果P1不包含行号为P3的记录,则立即跳转到P2。或者,如果P2为0,则引发SQLITE_CORRUPT错误。如果P1确实包含具有行号P3的记录,则使光标指向该记录并进入下一条指令。

所述SeekRowid操作码进行同样的动作,但也可以让P3寄存器包含一个非整数值,在这种情况下,跳转总是采取。此操作码要求P3始终包含一个整数。

所述NOTFOUND操作码执行对索引B树相同的操作(具有任意多值的键)。

此操作码使光标处于无法向任一方向前进的状态。换句话说,下一个和上一个操作码在该操作码之后将不起作用。

另请参阅:FoundNotFoundNoConflictSeekRowid

未找到 如果P4 == 0,则寄存器P3包含由MakeRecord构造的blob。如果P4> 0,则寄存器P3是构成未打包记录的P4寄存器中的第一个。

光标P1在索引btree上。如果由P3和P4标识的记录不是P1中任何条目的前缀,则跳转到P2。如果P1确实包含一个前缀与P3 / P4记录匹配的条目,则控制权转到下一条指令,并且P1指向匹配的条目。

此操作使光标处于无法向任一方向前进的状态。换句话说,NextPrev 操作码在此操作后不起作用。

另请参阅:FoundNotExistsNoConflictIfNoHope

不为空 如果寄存器P1中的值不为NULL,则跳至P2。
空值 将NULL写入寄存器P2。如果P3大于P2,则还将NULL写入寄存器P3以及P2和P3之间的每个寄存器。如果P3小于P2(通常P3为零),则仅寄存器P2设置为NULL。

如果P1的值不为零,则还应设置MEM_Cleared标志,以使即使在NeEq上设置了SQLITE_NULLEQ,NULL值也不会相等 。

空行 将光标P1移动到空行。当光标在空行上时发生的任何操作都将始终写入NULL。
抵消 将字节偏移量存储到寄存器r [P3]中,该偏移量是数据库文件的字节偏移量,该偏移量是该游标P1当前指向的记录的有效载荷的起点。

P2是sqlite_offset()函数的参数的列号。该操作码本身不使用P2,但是代码生成器使用P2值。此操作码的P1,P2和P3操作数与Column相同。

仅当使用-DSQLITE_ENABLE_OFFSET_SQL_FUNC选项编译SQLite时,此操作码才可用。

偏移限制 该操作码执行与LIMIT和OFFSET处理关联的常用计算。r [P1]保存极限计数器。r [P3]保留偏移计数器。操作码计算LIMIT和OFFSET的组合值,并将该值存储在r [P2]中。计算的r [P2]值是完成查询将需要访问的总行数。

如果r [P3]为零或负,则表示不存在偏移,并且将r [P2]设置为LIMIT r [P1]的值。

如果r [P1]为零或负,则表示没有LIMIT,并且r [P2]设置为-1。

否则,将r [P2]设置为r [P1]和r [P3]之和。

一次 在每次调用字节码程序时第一次遇到此操作码时,请转到下一条指令。 在同一调用期间的第二次以及所有后续相遇时跳转到P2。

顶级程序通过将P1操作数与程序开始时Init操作码上的P1操作数进行比较来确定首次调用。如果P1值不同,则掉落并使该操作码的P1等于Init的P1 。如果P1值相同,则进行跳转。

对于子程序,VdbeFrame中有一个位掩码,用于确定是否应执行跳转。位掩码是必需的,因为自更改代码技巧不适用于递归触发器。

打开自动索引 此操作码的作用与OpenEphemeral相同。它具有不同的名称以区分其用途。使用此操作码创建的表将用于在联接中自动创建的瞬态索引。
的OpenDup 打开一个新的光标P1,该光标指向与光标P2相同的临时表。P2游标必须已由先前的OpenEphemeral 操作码打开。仅临时光标可以重复。

重复的临时光标用于实例化视图的自联接。

开放星历 打开一个新的光标P1到瞬态表。即使主数据库是只读的,游标也始终以读/写方式打开。临时表在关闭游标时会自动删除。

如果在临时表上已经打开了光标P1,则清除该表(删除所有内容)。

P2是临时表中的列数。如果P4 == 0,则光标指向BTree表,如果P4不为0,则指向BTree索引。如果P4不为NULL,则它指向定义索引中键格式的KeyInfo结构。

P5参数可以是btree.h中定义的BTREE_ *标志的掩码。这些标志控制btree操作的各个方面。BTREE_OMIT_JOURNAL和BTREE_SINGLE标志是自动添加的。

如果P3为正,则对reg [P3]进行一些修改,以便可以将其用作Insert的零长度数据。这种优化避免了额外的Blob操作码来初始化该寄存器。

OpenPseudo 打开一个新游标,该游标指向包含单行数据的伪造表。该行的内容是存储器寄存器P2的内容。换句话说,游标P1成为寄存器P2中包含的MEM_Blob内容的别名。

此操作码创建的伪表用于保存排序器的单行输出,以便可以使用“列”操作码将行分解为单独的列。该码是唯一的光标操作码与伪表的作品。

P3是伪表将存储的记录中的字段数。

打开阅读 在数据库文件中为根表为P2的数据库表打开一个只读游标。数据库文件由P3确定。P3 == 0表示主数据库,P3 == 1表示用于临时表的数据库,P3> 1表示使用相应的附加数据库。给新光标一个标识符P1。P1值不必是连续的,但所有P1值都应该是小整数。P1为负是一个错误。

允许的P5位:

  • 0x02 OPFLAG_SEEKEQ:此游标将仅用于相等查找(实现为SeekLE / IdxLT 的一对操作码SeekGE / IdxGT

P4值可以是整数(P4_INT32),也可以是指向KeyInfo结构的指针(P4_KEYINFO)。如果它是指向KeyInfo对象的指针,则打开的表必须是索引b树,其中KeyInfo对象定义该索引b树的内容和整理顺序。否则,如果P4是整数值,则打开的表必须是表b树,其列数不少于P4的值。

另请参见:OpenWriteReopenIdx

打开写 在根页为P2的表或索引上打开一个名为P1的读/写游标(或者如果P5中的OPFLAG_P2ISREG位置1,则其根页保留在寄存器P2中-参见下文)。

P4值可以是整数(P4_INT32),也可以是指向KeyInfo结构的指针(P4_KEYINFO)。如果它是指向KeyInfo对象的指针,则打开的表必须是索引b树,其中KeyInfo对象定义该索引b树的内容和整理顺序。否则,如果P4是整数值,则打开的表必须是表b树,其列数不少于P4的值。

允许的P5位:

  • 0x02 OPFLAG_SEEKEQ:此游标将仅用于相等查找(实现为SeekLE / IdxLT 的一对操作码SeekGE / IdxGT
  • 0x08 OPFLAG_FORDELETE:此光标仅用于查找和随后删除索引btree中的条目。这是对存储引擎的提示,表明可以忽略该存储引擎。提示未由官方SQLite b * tree存储引擎使用,但由COMDB2使用。
  • 0x10 OPFLAG_P2ISREG:将寄存器P2的内容用作根页,而不是P2本身的值。

该指令的工作方式与OpenRead相似,只是它以读/写模式打开游标。

另请参见:OpenReadReopenIdx

或者 对寄存器P1和P2中的值进行逻辑或,并将答案存储在寄存器P3中。

如果P1或P2都不为零(真),那么即使另一个输入为NULL,结果也为1(真)。NULL和false或两个NULL给出NULL输出。

页数 将数据库P1中的当前页数写入存储单元P2。
参数 该操作码仅存在于通过“程序”指令调用的子程序中 。当前存储在调用(父)帧的存储单元中的值复制到当前帧地址空间中的单元P2。触发程序使用它来访问new。*和old。*值。

通过将P1自变量的值与调用程序指令的P1自变量的值相加,可以确定父帧中单元的地址。

解析模式 从数据库P1的模式表中读取和解析与WHERE子句P4匹配的所有条目。如果P4是NULL指针,则将重新解析P1的整个架构。

此操作码调用解析器以创建新的虚拟机,然后运行新的虚拟机。因此,它是可重入的操作码。

排列 设置使用的置换比较中的下一个指令操作。排列存储在P4操作数中。

该排列仅在下一个在P5中将OPFLAG_PERMUTE位置1的比较之前有效。通常,排列应该在Compare之前立即进行

P4整数数组中的第一个整数是数组的长度,并且不成为置换的一部分。

上一个 备份游标P1,使其指向其表或索引中的上一个键/数据对。如果没有先前的键/值对,则遵循以下说明。但是,如果光标备份成功,请立即跳至P2。

上一个操作码之后的是唯一有效的SeekLTSeekLE,或 最后操作码用来定位光标。 Prev不允许关注SeekGTSeekGERewind

P1游标必须用于真实表,而不是伪表。如果P1未打开,则行为是不确定的。

P3值是对btree实现的提示。如果P3 == 1,则表示P1是SQL索引,并且如果该索引是唯一的,则可以省略此指令。P3通常为0。P3始终为0或1。

P4始终为P4_ADVANCE类型。函数指针指向sqlite3BtreePrevious()。

如果P5为正且已执行跳转,则准备好的语句中的事件计数器编号P5-1会增加。

程序 执行作为P4(类型P4_SUBPROGRAM)传递的触发程序。

P1包含存储单元的地址,该存储单元包含作为子程序参数的值数组中的第一个存储单元。如果子程序使用RAISE()函数引发IGNORE异常,则P2包含要跳转到的地址。寄存器P3包含此(父)VM中存储单元的地址,该存储单元用于在运行时分配sub-vdbe所需的内存。

P4是指向包含触发程序的VM的指针。

如果P5不为零,则启用递归程序调用。

PureFunc 使用从寄存器P2和后续函数中获取的参数调用用户函数(P4是指向sqlite3_context对象的指针,该对象包含要运行的函数的指针)。参数的数量在P4指向的sqlite3_context对象中。功能的结果存储在寄存器P3中。寄存器P3不得为功能输入之一。

P1是一个32位的位掩码,指示该函数的每个参数在编译时是否确定为常量。如果第一个参数是常量,则设置P1的位0。这用于确定是否可以安全保留与使用sqlite3_set_auxdata()API的用户功能参数关联的元数据,直到下一次调用此操作码为止。

此操作码的工作方式与Function完全相同。唯一的区别在于名称。此操作码用于功能必须完全不确定的地方。根据其参数,某些内置的日期/时间函数可以是确定性的,也可以是不确定性的。当以不确定性方式使用这些函数时,它们将检查是否使用PureFunc而不是Function调用了它们,如果使用了,则会引发错误。

另请参见:AggStepAggFinal函数

ReadCookie 从数据库P1读取cookie编号P3,并将其写入寄存器P2。P3 == 1是架构版本。P3 == 2是数据库格式。P3 == 3是推荐的寻呼机缓存大小,依此类推。P1 == 0是主数据库文件,P1 == 1是用于存储临时表的数据库文件。

在执行该指令之前,数据库上必须有一个读锁(必须启动一个事务或必须有一个打开的游标)。

真实的 P4是指向64位浮点值的指针。将该值写入寄存器P2。
真实亲和力 如果寄存器P1保留一个整数,则将其转换为实数值。

从具有REAL亲和力的列中提取信息时,将使用此操作码。为了节省空间,此类列值仍可以存储为整数,但是在提取之后,我们希望它们仅具有实值。

ReleaseReg 从服务中释放寄存器。此操作码完成后,寄存器中的任何内容都不可靠。

释放的寄存器将是从P1开始的P2寄存器,除非P3的位ii置位,则不要释放寄存器P1 + ii。换句话说,P3是要保留的寄存器的掩码。

释放寄存器将清除Mem.pScopyFrom指针。这意味着,如果已释放的寄存器的内容是使用SCopy设置的,则对SCopy的源寄存器的值进行更改将不再在sqlite3VdbeMemAboutToChange()中产生断言错误。

如果设置了P5,则所有释放的寄存器的类型都将设置为MEM_Undefined,以便任何随后的尝试读取释放的寄存器(在重新初始化之前)都将产生断言错误。

每次调用此操作码时都应设置P5。但是,在(合法的)假设下,代码生成器中的某些地方会在使用寄存器之前释放寄存器,在使用之前不会为其他目的而重新分配寄存器,因此可以安全释放它们。

此操作码仅在测试和调试版本中可用。它不是为发行版本生成的。此操作码的目的是帮助验证生成的字节码。该操作码实际上对计算答案没有帮助。

计算整数寄存器P2除以寄存器P1之后的余数,并将结果存储在寄存器P3中。如果寄存器P1中的值为零,则结果为NULL。如果任一操作数为NULL,则结果为NULL。
重新打开Idx ReopenIdx码就像打开读取区别在于它首先检查是否在P1上的光标已在同一B树开放的,如果是这样变成码无操作。换句话说,如果游标已经打开,则不要重新打开它。

所述ReopenIdx操作码只能与P5 == 0或P5 == OPFLAG_SEEKEQ并用P4是一个P4_KEYINFO对象使用。此外,对于相同的光标编号,P3值必须与其他所有ReopenIdxOpenRead相同。

允许的P5位:

  • 0x02 OPFLAG_SEEKEQ:此游标将仅用于相等查找(实现为SeekLE / IdxLT 的一对操作码SeekGE / IdxGT

另请参阅:OpenReadOpenWrite

重置计数 更改计数器的值将复制到数据库句柄更改计数器(由对sqlite3_changes()的后续调用返回)。然后,VM内部更改计数器重置为0。这由触发器程序使用。
ResetSorter 从临时表或在光标P1上打开的排序器中删除所有内容。

该操作码仅适用于用于排序并使用OpenEphemeralSorterOpen打开的游标。

结果行 寄存器P1至P1 + P2-1包含一行结果。此操作码使sqlite3_step()调用以SQLITE_ROW返回代码终止,并设置sqlite3_stmt结构以提供对r(P1).. r(P1 + P2-1)值的访问,作为结果行。
返回 跳转到寄存器P1中地址之后的下一条指令。跳转后,寄存器P1变为未定义。
倒带 P1的RowidColumnNext指令的下一次使用将引用数据库表或索引中的第一个条目。如果表或索引为空,请立即跳至P2。如果表或索引不为空,请执行以下指令。

此操作码使光标配置为从头到尾向前移动。换句话说,游标被配置为使用Next,而不是Prev

行单元 P1和P2都是打开的游标。两者都必须在相同类型的表(intkey或索引)上打开。此操作码用作将当前行从P2复制到P1的一部分。如果在intkey表上打开了游标,则寄存器P3包含要与P1中的新记录一起使用的行ID。如果在索引表上打开它们,则不使用P3。

必须在此操作码后面插入一个具有OPFLAG_PREFORMAT标志的Insert或InsertIdx操作码,才能完成插入操作。

行数据 将光标P1当前指向的行的完整行内容写入寄存器P2。没有数据解释。它将被完全复制到数据库文件中找到的P2寄存器中。

如果游标P1是索引,则内容是该行的键。如果光标P2是一个表,则提取的内容是数据。

如果P1游标必须指向实际表的有效行(而不是NULL行),则不是伪表。

如果P3!= 0,则允许该操作码向数据库页面创建临时指针。这意味着一旦光标移动,输出寄存器的内容就会失效-包括由其他光标“保存”当前光标位置以使其可以写入同一表的其他光标引起的移动。如果P3 == 0,则将数据副本复制到内存中。P3!= 0更快,但是P3 == 0更安全。

如果P3!= 0,则P2寄存器的内容不适合在OP_Result中使用,任何OP_Result都会使P2寄存器的内容无效。P2寄存器的内容将被功能(如Function)之类的操作码或指向该表的另一个游标的任何使用所无效。

罗威德 在寄存器P2中存储一个整数,该整数是P1当前指向的表条目的关键字。

P1可以是普通表也可以是虚拟表。曾经有一个单独的OP_VRowid操作码用于虚拟表,但是现在这个操作码适用于两种表类型。

行集添加 将寄存器P2所保存的整数值插入到寄存器P1中所保存的RowSet对象中。

如果P2不是整数,则断言失败。

行集读取 从P1中的RowSet对象中提取最小值,然后将该值放入寄存器P3中。或者,如果RowSet对象P1最初为空,则使P3保持不变,并跳转到指令P2。
行集测试 假定寄存器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的一部分的值时,无需搜索以查看先前是否已将相同的值作为集合X的一部分插入(仅当它是以前作为其他集合的一部分插入)。

保存点 根据P1的值,打开,释放或回滚由参数P4命名的保存点。要打开新的保存点,请设置P1 == 0(SAVEPOINT_BEGIN)。要释放(提交)现有保存点集P1 == 1(SAVEPOINT_RELEASE)。要回滚现有保存点,请设置P1 == 2(SAVEPOINT_ROLLBACK)。
复制 将寄存器P1的浅表副本复制到寄存器P2中。

该指令对值进行了浅表复制。如果值是字符串或Blob,则副本仅是指向原始对象的指针,因此,如果原始对象发生更改,则副本也将变为指向原始对象的指针。更糟糕的是,如果原件被重新分配,则该副本将无效。因此,程序必须保证原件在复印期间不会更改。使用“复制”进行完整复制。

搜寻结束 将光标P1定位在btree的末尾,以便将新条目附加到btree上。

假定游标仅用于追加,因此,如果游标有效,则游标必须已经指向btree的末尾,因此不会对游标进行任何更改。

寻求GE 如果游标P1引用SQL表(使用整数键的B树),则将寄存器P3中的值用作键。如果游标P1引用SQL索引,则P3是用作解压缩索引键的P4寄存器数组中的第一个。

重新定位光标P1,使其指向大于或等于键值的最小条目。如果没有大于或等于键的记录,并且P2不为零,则跳转到P2。

如果使用OPFLAG_SEEKEQ标志打开了光标P1,则此操作码将落在与键完全匹配的记录上,否则将导致跳转到P2。当游标为OPFLAG_SEEKEQ时,此操作码后必须跟具有相同参数的IdxLE操作码。该IdxGT如果这个操作码成功操作码会被跳过,但 IdxGT操作码将在后续的循环迭代中使用。OPFLAG_SEEKEQ标志是对btree层的提示,表明这是一个相等搜索。

此操作码使光标配置为从头到尾向前移动。换句话说,游标被配置为使用Next,而不是Prev

另请参阅:FoundNotFound,SeekLt,SeekGt,SeekLe

寻求GT 如果游标P1引用SQL表(使用整数键的B树),则将寄存器P3中的值用作键。如果游标P1引用SQL索引,则P3是用作解压缩索引键的P4寄存器数组中的第一个。

重新定位光标P1,使其指向大于键值的最小条目。如果没有大于键的记录并且P2不为零,则跳转到P2。

此操作码使光标配置为从头到尾向前移动。换句话说,游标被配置为使用Next,而不是Prev

另请参阅:FoundNotFound,SeekLt,SeekGe,SeekLe

寻求命中 如有必要,增大或减小游标P1的seekHit值,以使其不小于P2且不大于P3。

seekHit整数表示已知存在至少一个匹配项的索引中的最大项。如果seekHit值小于索引查找中相等项的总数,则 IfNoHope操作码可能会运行以查看是否可以尽早放弃I​​N循环,从而节省了工作。这是IN-early-out优化的一部分。

P1必须是有效的b树游标。

寻求 如果游标P1引用SQL表(使用整数键的B树),则将寄存器P3中的值用作键。如果游标P1引用SQL索引,则P3是用作解压缩索引键的P4寄存器数组中的第一个。

重新定位光标P1,使其指向小于或等于键值的最大条目。如果没有小于或等于键的记录,并且P2不为零,则跳转到P2。

此操作码使光标配置为从末尾到开头以相反的顺序移动。换句话说,游标被配置为使用Prev,而不是Next

如果使用OPFLAG_SEEKEQ标志打开了光标P1,则此操作码将落在与键完全匹配的记录上,否则将导致跳转到P2。当游标为OPFLAG_SEEKEQ时,此操作码后必须跟具有相同参数的IdxLE操作码。该IdxGE如果这个操作码成功操作码会被跳过,但 IdxGE操作码将在后续的循环迭代中使用。OPFLAG_SEEKEQ标志是对btree层的提示,表明这是一个相等搜索。

另请参阅:FoundNotFound,SeekGt,SeekGe,SeekLt

寻求 如果游标P1引用SQL表(使用整数键的B树),则将寄存器P3中的值用作键。如果游标P1引用SQL索引,则P3是用作解压缩索引键的P4寄存器数组中的第一个。

重新定位光标P1,使其指向小于键值的最大条目。如果没有少于键的记录,并且P2不为零,则跳转到P2。

此操作码使光标配置为从末尾到开头以相反的顺序移动。换句话说,游标被配置为使用Prev,而不是Next

另请参阅:FoundNotFound,SeekGt,SeekGe,SeekLe

搜寻行 P1是在SQL表btree(带有整数键)上打开的游标的索引。如果寄存器P3不包含整数,或者如果P1不包含行号为P3的记录,则立即跳转到P2。或者,如果P2为0,则引发SQLITE_CORRUPT错误。如果P1确实包含具有行号P3的记录,则使光标指向该记录并进入下一条指令。

所述NotExists码执行相同的操作,但与NotExists P3寄存器必须保证包含的整数值。使用此操作码,寄存器P3可能不包含整数。

所述NOTFOUND操作码执行对索引B树相同的操作(具有任意多值的键)。

此操作码使光标处于无法向任一方向前进的状态。换句话说,下一个和上一个操作码在该操作码之后将不起作用。

另请参阅:FoundNotFoundNoConflictSeekRowid

搜索扫描 该操作码是SeekGE的前缀操作码。换句话说,该操作码必须紧跟在SeekGE之后。此约束由assert()语句检查。

该操作码使用后续SeekGE的P1至P4操作数 。在随后的文本中,后续SeekGE操作码的操作数 表示为SeekOP.P1至SeekOP.P4。也仅使用此操作码的P1和P2操作数,它们被称为This.P1和This.P2。

该操作码通过避免在btree上进行不必要的查找,而代之以将步骤替换为b树的下一行,从而有助于优化IN运算符在索引的较后各项上的多列索引上的IN运算符。如果此操作码被忽略或为空操作,则将获得正确的答案。

SeekGE .P3和SeekGE .P4操作数确定一个解压的关键是,我们希望光标所需的条目SeekGE .P1是指向。将此SeekGE .P4 / P5行称为“目标”。

如果SeekGE .P1光标当前未指向有效行,则此操作码为无操作,并且控制权传递到SeekGE中

如果SeekGE .P1光标指向有效行,则该行可能是目标行,或者可能在目标行附近且稍早于目标行。此操作码可能尝试通过在0到This.P1之间调用光标上的sqlite3BtreeStep()来将光标定位在目标行上。

此操作码可能产生三种结果:

  1. 如果在This.P1步骤之后,光标仍指向btree中比目标行更早的位置,则进入SeekGE操作码的子顺序

  2. 如果通过0次或多次sqlite3BtreeNext()调用成功将光标移动到目标行,则跳至This.P2,它将登陆到SeekGE之后的IdxGTIdxGE操作码之后

  3. 如果光标结束超过目标行(指示目标行在btree中不存在),则跳至SeekOP.P2。
顺序 查找光标P1的下一个可用序列号。将序列号写入寄存器P2。该指令后,光标上的序列号递增。
序列测试 P1是分类光标。如果序列计数器当前为零,则跳至P2。无论是否进行跳转,都增加顺序值。
SetCookie 将整数P3写入数据库P1的cookie编号P2中。P2 == 1是架构版本。P2 == 2是数据库格式。P2 == 3是推荐的寻呼机缓存大小,依此类推。P1 == 0是主数据库文件,P1 == 1是用于存储临时表的数据库文件。

在执行此操作码之前,必须启动事务。

如果P2是SCHEMA_VERSION cookie(cookie号1),则内部模式版本将设置为P3-P5。“ PRAGMA schema_version = N”语句将P5设置为1,因此内部架构版本将与数据库架构版本不同,从而导致架构重置。

ShiftLeft 将寄存器P2中的整数值向左移动寄存器P1中整数所指定的位数。将结果存储在寄存器P3中。如果任一输入为NULL,则结果为NULL。
右移 将寄存器P2中的整数值向右移动寄存器P1中整数指定的位数。将结果存储在寄存器P3中。如果任一输入为NULL,则结果为NULL。
软零 MakeRecord 指令所示,将寄存器P1的值设置为NULL ,但不要释放与该寄存器关联的任何字符串或Blob内存,因此,如果该值是先前使用SCopy复制的字符串或Blob,则复制将继续是有效的。
种类 该操作码的作用与Rewind完全相同,不同之处在于它增加了用于测试的未记录的全局变量。

排序是通过将记录写入排序索引中,然后倒回该索引并从头到尾播放来完成的。我们使用Sort操作码而不是Rewind进行倒带,以便全局变量将递增,并且回归测试可以确定优化器是否正确地优化了排序。

分选机比较 P1是分类光标。该指令将寄存器P3中的记录blob的前缀与排序光标当前指向的条目的前缀进行比较。仅比较r [P3]的前P4字段和排序记录。

如果P3或分类器在它们的有效字段之一中包含NULL(不计算最后忽略的P4字段),则假定比较是相等的。

如果两个记录彼此相等,则转到下一条指令。 如果它们不同,则跳到P2。

分类数据 将分类器光标P1的当前分类器数据写入寄存器P2。然后清除游标P3上的列标题缓存。

此操作码通常用于将记录移出排序器,并移入寄存器,该寄存器是使用OpenPseudo创建的伪表游标的源 。该伪表游标是由参数P3标识的那个。作为该操作码的一部分,清除P3列高速缓存使我们不必发出单独的NullRow指令来清除该高速缓存。

排序器插入 寄存器P2包含使用MakeRecord指令创建的SQL索引键 。该操作码将该密钥写入分类器P1。条目的数据为零。
下一个 该操作码与Next一样工作,除了P1必须是已为其调用SorterSort操作码的排序器对象。该操作码使光标前进到下一个已排序的记录,如果没有更多已排序的记录,则跳转到P2。
分选机打开 此操作码的工作方式与OpenEphemeral相似,不同之处在于它打开了一个临时索引,该索引专门设计用于使用外部合并排序算法对大型表进行排序。

如果参数P3不为零,则表明排序器可以假定考虑每个键的前P3字段的稳定排序足以产生所需的结果。

分拣机排序 在将所有记录插入到由P1标识的Sorter对象中之后,调用此操作码以实际进行排序。 如果没有要排序的记录,请跳至P2。

此操作码是用于Sorter对象的Sort and Rewind的别名。

SqlExec 运行SQL语句或P4字符串中指定的语句。
细绳 长度为P1(字节)的字符串值P4存储在寄存器P2中。

如果P3不为零且寄存器P3的内容等于P5,则寄存器P2的数据类型将转换为BLOB。内容是相同的字节序列,它仅被解释为BLOB而不是字符串,就好像它是CAST一样。换句话说:

if(P3!= 0和reg [P3] == P5)reg [P2]:= CAST(reg [P2] as BLOB)

弦8 P4指向以nul终止的UTF-8字符串。该操作码在首次执行之前会转换为String操作码。在此转换过程中,将计算字符串P4的长度并将其存储为P1参数。
减去 从寄存器P2中的值减去寄存器P1中的值,并将结果存储在寄存器P3中。如果任一输入为NULL,则结果为NULL。
桌锁 获取特定表上的锁。仅当启用了共享缓存功能时,才使用此指令。

P1是在获取锁的数据库的sqlite3.aDb []中数据库的索引。如果P3 == 0,则获得一个读锁,如果P3 == 1,则获得一个写锁。

P2包含要锁定的表的根页面。

P4包含一个指向被锁定表名称的指针。如果无法获得锁,则仅用于生成错误消息。

痕迹 如果启用了语句跟踪,请在语句跟踪输出上写P4。

操作数P1必须为0x7fffffff,P2必须为正。

交易 如果事务尚未激活,则在数据库P1上开始事务。如果P2不为零,则启动写事务,或者如果读事务已经处于活动状态,则将其升级为写事务。如果P2为零,则开始读取事务。如果P2为2或更大,则开始排他事务。

P1是在其上启动事务的数据库文件的索引。索引0是主数据库文件,索引1是用于临时表的文件。2或更大的索引用于附加数据库。

如果启动了写入事务并且Vdbe.usesStmtJournal标志为true(如果Vdbe可以修改多行并可能引发ABORT异常,则设置此标志),也可以打开语句事务。更具体地说,如果数据库连接当前未处于自动提交模式,或者如果存在其他活动语句,则打开语句事务。语句事务允许在发生错误后回滚此VDBE所做的更改,而不必回滚整个事务。如果没有遇到错误,则在VDBE暂停时,语句事务将自动提交。

如果P5!= 0,则此操作码还将针对P3检查模式cookie,并针对P4检查模式生成计数器。每当数据库架构更改时,cookie都会更改其值。此操作用于检测cookie何时已更改以及当前进程需要重新读取架构。如果P3中的模式cookie与数据库头中的模式cookie不同,或者P4中的模式生成计数器与当前的生成计数器不同,则将引发SQLITE_SCHEMA错误,并暂停执行。然后,sqlite3_step()包装函数可能会重新声明该语句并从头开始重新运行它。

真空 清理整个数据库P1。对于“ main”,P1为0,对于连接的数据库,P1为2或更大。“临时”数据库可能没有被清除。

如果P2不为零,则它是一个包含字符串的寄存器,该字符串是应将真空结果写入其中的文件。当P2为零时,真空将覆盖原始数据库。

多变的 将绑定参数P1的值传输到寄存器P2中

如果参数已命名,则其名称将出现在P4中。P4值由sqlite3_bind_parameter_name()使用。

VBegin P4可以是指向sqlite3_vtab结构的指针。如果是这样,请为该表调用xBegin方法。

另外,是否设置了P4,请检查是否未从虚拟表xSync()方法的回调中调用此函数。如果是这样,错误代码将设置为SQLITE_LOCKED。

纵列 将游标P1虚拟表当前行的第P2列的值存储在寄存器P3中。

如果在UPDATE操作期间使用VColumn操作码来获取不变列的值,则P5值为OPFLAG_NOCHNG。这将导致sqlite3_vtab_nochange()函数在虚拟表实现的xColumn方法内部返回true。P5列可能还包含其他位(OPFLAG_LENGTHARG或OPFLAG_TYPEOFARG),但VColumn未使用那些位。

创建 P2是一个寄存器,用于保存数据库P1中虚拟表的名称。调用该表的xCreate方法。
销毁 P4是数据库P1中虚拟表的名称。调用该表的xDestroy方法。
VFilter P1是使用VOpen打开的游标。如果过滤的结果集为空,则P2是要跳转到的地址。

P4是NULL或由模块的xBestIndex方法生成的字符串。P4字符串的解释留给模块实现。

该操作码在P1指定的虚拟表上调用xFilter方法。xFilter的整数查询计划参数存储在寄存器P3中。寄存器P3 + 1存储要传递给xFilter方法的argc参数。寄存器P3 + 2..P3 + 1 + argc是argc附加参数,它们作为argv传递给xFilter。传递给xFilter时,寄存器P3 + 2变为argv [0]。

如果过滤后的结果集为空,则跳转到P2。

VNext 将虚拟表P1前进到其结果集中的下一行,并跳转到指令P2。或者,如果虚拟表已到达其结果集的末尾,则进入下一条指令。
威Open P4是指向虚拟表对象sqlite3_vtab结构的指针。P1是光标编号。此操作码将游标打开到虚拟表,并将该游标存储在P1中。
V重命名 P4是指向虚拟表对象sqlite3_vtab结构的指针。此操作码调用相应的xRename方法。寄存器P1中的值作为zName参数传递给xRename方法。
V更新 P4是指向虚拟表对象sqlite3_vtab结构的指针。此操作码调用相应的xUpdate方法。P2值是从P3开始的连续内存单元,以传递到xUpdate调用。寄存器(P3 + P2-1)中的值对应于传递给xUpdate的argv数组的第p2个元素。

xUpdate方法将执行DELETE或INSERT或两者都执行。argv [0]元素(对应于存储单元P3)是要删除的行的rowid。如果argv [0]为NULL,则不会发生删除。argv [1]元素是新行的rowid。该值可以为NULL,以使虚拟表为其自身选择新的rowid。数组中的后续元素是新行中列的值。

如果P2 == 1,则不执行插入操作。argv [0]是要删除的行的rowid。

P1是一个布尔标志。如果将其设置为true并且xUpdate调用成功,则sqlite3_last_insert_rowid()返回的值将设置为刚插入的行的rowid的值。

P5是在插入或更新约束失败的情况下要应用的错误操作(OE_Replace,OE_Fail,OE_Ignore等)。

屈服 用寄存器P1中的值交换程序计数器。这具有屈服于协程的作用。

如果此指令启动的协程以YieldReturn结尾, 则继续执行下一条指令。但是,如果此指令启动的协程以 EndCoroutine结尾,则跳至P2而不是继续执行下一条指令。

另请参阅:InitCoroutine