Spec-Zone.ru › SQLite

Байткодовый движок SQLite

Содержание
1. Краткое описание
2. Введение
2.1. Исходный код VDBE
2.2. Формат инструкций
2.3. Регистры
2.4. Курсоры B-дерева
2.5. Подпрограммы, сопрограммы и подпрограммы триггеров
2.6. Самоизменяющийся код
3. Просмотр байткода
4. Коды операций

1. Краткое описание

SQLite работает, преобразуя инструкции SQL в байткод, а затем выполняя этот байткод на виртуальной машине. В этом документе описано, как работает байткодовый движок.

В этом документе описано внутреннее устройство SQLite. Приведённая здесь информация не требуется для повседневной разработки приложений с использованием SQLite. Документ предназначен для тех, кто хочет глубже разобраться во внутренней работе SQLite.

Байткодовый движок не является API SQLite. Детали устройства байткодового движка меняются от одного выпуска SQLite к следующему. Приложения, использующие SQLite, не должны зависеть от каких-либо сведений, приведённых в этом документе.

О причинах, по которым SQLite предпочитает использовать байткод для реализации SQL, см. документ «Почему SQLite использует байткод».

2. Введение

SQLite работает, преобразуя каждую инструкцию SQL в байткод, а затем выполняя этот байткод. Подготовленная инструкция в SQLite — это в основном байткод, необходимый для реализации соответствующей инструкции SQL. Интерфейс sqlite3_prepare_v2() представляет собой компилятор, который преобразует SQL в байткод. Интерфейс sqlite3_step() представляет собой виртуальную машину, которая выполняет байткод, содержащийся в подготовленной инструкции.

Виртуальная машина байткода — сердце SQLite. Программистам, желающим понять, как SQLite работает внутри, необходимо разбираться в байткодовом движке.

Исторически байткодовый движок SQLite называется «Virtual DataBase Engine», или «VDBE». На этом сайте термины «байткодовый движок», «VDBE», «виртуальная машина» и «виртуальная машина байткода» используются как взаимозаменяемые, поскольку означают одно и то же.

В этой статье термины «байткодовая программа» и «подготовленная инструкция» также используются как взаимозаменяемые, поскольку в основном означают одно и то же.

2.1. Исходный код VDBE

Исходный код байткодового движка находится в файле vdbe.c. Определения кодов операций в этом документе составлены на основе комментариев в этом файле. Комментарии в исходном коде являются авторитетным источником сведений о байткодовом движке. Если возникнут сомнения, обращайтесь к исходному коду.

Помимо основного файла исходного кода vdbe.c, в дереве исходного кода есть и другие вспомогательные файлы, все названия которых начинаются с «vdbe» — сокращения от «Virtual DataBase Engine».

Помните, что названия и значения кодов операций часто меняются от одного выпуска SQLite к следующему. Поэтому, если вы изучаете вывод EXPLAIN в SQLite, следует обратиться к версии этого документа (или исходного кода vdbe.c), соответствующей версии SQLite, в которой выполнялся EXPLAIN. В противном случае описание кодов операций может оказаться неточным. Этот документ составлен на основе версии SQLite 3.53.0, зафиксированной в ревизии 4525003a53a7f от 2026-04-09.

2.2. Формат инструкций

Программа на байткоде SQLite состоит из одной или нескольких инструкций. У каждой инструкции есть код операции и пять операндов с именами P1, P2, P3, P4 и P5. Операнды P1, P2 и P3 — это 32-разрядные целые числа со знаком. Эти операнды часто ссылаются на регистры. В инструкциях, работающих с курсорами B-дерева, операнд P1 обычно задаёт номер курсора. В инструкциях перехода P2 обычно задаёт адрес перехода. P4 может быть 32-разрядным целым числом со знаком, 64-разрядным целым числом со знаком, 64-разрядным числом с плавающей точкой, строковым литералом, литералом Blob, указателем на функцию сравнения последовательности сортировки, указателем на реализацию определённой приложением функции SQL или иметь другое значение. P5 — это 16-разрядное беззнаковое целое число, обычно используемое для хранения флагов. Биты флага P5 иногда могут тонко влиять на работу кода операции. Например, если для кода операции Eq установлен бит SQLITE_NULLEQ (0x0080) операнда P5, значения NULL считаются равными друг другу. В противном случае значения NULL считаются различными.

Некоторые коды операций используют все пять операндов. Другие — один или два. Некоторые коды операций не используют ни одного операнда.

Байткодовый движок начинает выполнение с инструкции номер 0. Выполнение продолжается, пока не встретится инструкция Halt, счётчик команд не станет больше адреса последней инструкции или не произойдёт ошибка. Когда байткодовый движок останавливается, освобождается вся выделенная им память и закрываются все открытые курсоры базы данных. Если выполнение остановилось из-за ошибки, все ожидающие транзакции прерываются, а изменения базы данных откатываются.

Код операции ResultRow приостанавливает работу байткодового движка, и соответствующий вызов sqlite3_step() возвращает SQLITE_ROW. Перед вызовом ResultRow байткодовая программа загружает результаты одной строки запроса в последовательность регистров. Результаты запроса извлекаются из этих регистров с помощью API на языке C, например sqlite3_column_int() или sqlite3_column_text(). При следующем вызове sqlite3_step() байткодовый движок продолжает выполнение со следующей после ResultRow инструкции.

2.3. Регистры

В каждой байткодовой программе имеется фиксированное (но потенциально большое) число регистров. Один регистр может хранить объекты разных типов:

  • Значение NULL
  • 64-разрядное целое число со знаком
  • Число с плавающей точкой двойной точности IEEE (64-разрядное)
  • Строку произвольной длины
  • BLOB произвольной длины
  • Объект RowSet (см. коды операций RowSetAdd, RowSetRead и RowSetTest)
  • Объект Frame (используется подпрограммами — см. Program)

Регистр также может быть «неопределённым», то есть вообще не содержать значения. Неопределённое значение отличается от NULL. В зависимости от параметров компиляции попытка прочитать неопределённый регистр обычно приводит к ошибке во время выполнения. Если генератор кода (sqlite3_prepare_v2()) создаёт подготовленную инструкцию, которая читает неопределённый регистр, это означает, что в генераторе кода есть ошибка.

Регистры нумеруются начиная с 0. Большинство кодов операций обращаются как минимум к одному регистру.

Число регистров в одной подготовленной инструкции фиксируется во время компиляции. Содержимое всех регистров очищается при сбросе или завершении подготовленной инструкции.

Внутренний объект Mem хранит значение одного регистра. Абстрактный объект sqlite3_value, доступный через API, на самом деле представляет собой объект Mem, то есть регистр.

2.4. Курсоры B-дерева

У подготовленной инструкции может быть ноль или несколько открытых курсоров. Каждый курсор обозначается небольшим целым числом, которое обычно передаётся как параметр P1 кода операции, использующего этот курсор. На одном и том же индексе или таблице могут быть открыты несколько курсоров. Все курсоры работают независимо, в том числе курсоры, указывающие на одни и те же индексы или таблицы. Виртуальная машина может взаимодействовать с файлом базы данных только через курсор. Инструкции виртуальной машины могут создавать курсор (например, OpenRead или OpenWrite), считывать данные из курсора (Column), перемещать курсор к следующей записи таблицы (например, Next или Prev) и выполнять другие действия. Все курсоры автоматически закрываются при сбросе или завершении подготовленной инструкции.

2.5. Подпрограммы, сопрограммы и подпрограммы триггеров

В байткодовом движке нет стека для хранения адреса возврата из подпрограммы. Адреса возврата необходимо хранить в регистрах. Поэтому байткодовые подпрограммы не являются реентерабельными.

Код операции Gosub сохраняет текущий счётчик команд в регистр P1, а затем переходит по адресу P2. Код операции Return выполняет переход по адресу P1+1. Таким образом, каждая подпрограмма связана с двумя целыми числами: адресом точки входа в подпрограмму и номером регистра, используемого для хранения адреса возврата.

Код операции Yield меняет местами значение счётчика команд и целое значение в регистре P1. Этот код операции используется для реализации сопрограмм. Сопрограммы часто используются для реализации подзапросов, содержимое которых извлекается по мере необходимости.

Триггеры должны быть реентерабельными. Поскольку байткодовые подпрограммы не являются реентерабельными, для реализации триггеров используется другой механизм. Каждый триггер реализуется отдельной байткодовой программой с собственными кодами операций, счётчиком команд и набором регистров. Код операции Program вызывает подпрограмму триггера. Инструкция Program выделяет и инициализирует новый набор регистров при каждом вызове подпрограммы, поэтому подпрограммы могут быть реентерабельными и рекурсивными. Код операции Param используется подпрограммами для доступа к содержимому регистров вызывающей байткодовой программы.

2.6. Самоизменяющийся код

Некоторые коды операций изменяют сами себя. Например, код операции Init (всегда являющийся первым кодом операции в каждой байткодовой программе) увеличивает значение своего операнда P1. Последующие коды операций Once сравнивают свои операнды P1 со значением P1 кода операции Init, чтобы определить, следует ли пропустить следующий за ними код однократной инициализации. Другой пример — код операции String8, который преобразует свой операнд P4 из UTF-8 в правильную кодировку строк базы данных, а затем заменяет себя кодом операции String.

3. Просмотр байткода

Каждая инструкция SQL, обрабатываемая SQLite, преобразуется в программу для виртуальной машины. Но если инструкция 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. В командной оболочке есть дополнительная логика для расстановки отступов в циклах. Кроме того, столбец «comment» в выводе EXPLAIN предоставляется только в том случае, если SQLite скомпилирован с параметром -DSQLITE_ENABLE_EXPLAIN_COMMENTS.

При компиляции SQLite с параметром SQLITE_DEBUG становятся доступны дополнительные команды PRAGMA, полезные для отладки и изучения работы VDBE. Например, включение pragma vdbe_trace приводит к тому, что при выполнении каждого кода операции VDBE его дизассемблированное представление выводится в стандартный поток вывода. К этим отладочным pragma относятся:

  • PRAGMA parser_trace
  • PRAGMA vdbe_addoptrace
  • PRAGMA vdbe_debug
  • PRAGMA vdbe_listing
  • PRAGMA vdbe_trace

4. Коды операций

В настоящее время виртуальная машина определяет 192 кода операции. Все определённые на данный момент коды операций описаны в таблице ниже. Эта таблица автоматически создана путём сканирования исходного кода файла vdbe.c.

Помните: коды операций VDBE не являются частью определения интерфейса SQLite. Число кодов операций, их названия и значения меняются от одного выпуска SQLite к следующему. Коды операций, приведённые в таблице ниже, соответствуют версии SQLite 3.53.0, зафиксированной в ревизии 4525003a53a7f от 2026-04-09.

Название опкода Описание
Abortable Проверяет, может ли произойти Abort. Вызывает утверждение, если Abort на этом этапе может привести к повреждению базы данных. Этот опкод встречается только в отладочных сборках.

Abort безопасен, если записей ещё не было или если активен журнал операторов.

Add Складывает значение в регистре P1 со значением в регистре P2 и сохраняет результат в регистре P3. Если любой из операндов равен NULL, результат равен NULL.
AddImm Прибавляет константу P2 к значению в регистре P1. Результат всегда является целым числом.

Чтобы принудительно преобразовать любой регистр в целое число, достаточно прибавить 0.

Affinity Применяет типы аффинности к диапазону из P2 регистров, начиная с P1.

P4 — это строка длиной P2 символов. N-й символ строки указывает аффинность столбца, которую следует использовать для N-й ячейки памяти в диапазоне.

AggFinal P1 — это ячейка памяти, служащая аккумулятором для агрегатной или оконной функции. Выполняет функцию-завершитель агрегата и сохраняет результат в P1.

P2 — количество аргументов функции шага, а P4 — указатель на FuncDef этой функции. Аргумент P2 этим опкодом не используется. Он нужен только для различения функций, принимающих разное количество аргументов. Аргумент 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. При первом выполнении FuncDef, хранящийся в P4, преобразуется в sqlite3_context, а опкод изменяется. Благодаря этому инициализация sqlite3_context выполняется только один раз, а не при каждом вызове функции шага.

AggValue Вызывает функцию xValue() и сохраняет результат в регистре P3.

P2 — количество аргументов функции шага, а P4 — указатель на FuncDef этой функции. Аргумент P2 этим опкодом не используется. Он нужен только для различения функций, принимающих разное количество аргументов. Аргумент P4 требуется лишь в том случае, если функция шага ранее не вызывалась.

And Выполняет логическое И над значениями в регистрах P1 и P2 и записывает результат в регистр P3.

Если P1 или P2 равен 0 (false), результат равен 0, даже если другой операнд — NULL. Значение NULL при операции И с true, а также два значения NULL дают результат NULL.

AutoCommit Устанавливает флаг автоматической фиксации базы данных в значение P1 (1 или 0). Если P2 имеет значение true, выполняет откат всех активных транзакций btree. Если имеются активные виртуальные машины (кроме этой), ROLLBACK завершается ошибкой. COMMIT завершается ошибкой, если есть активные виртуальные машины, выполняющие запись, или активные виртуальные машины, использующие общий кэш.

Эта инструкция останавливает виртуальную машину.

BeginSubrtn Помечает начало подпрограммы, в которую можно перейти напрямую или вызвать с помощью Gosub. Подпрограмма должна завершаться инструкцией Return, у которой операнд P1 совпадает с операндом P2 этого опкода, а P3 равен 1. Если подпрограмма выполняется напрямую, инструкция Return просто передаст управление следующей инструкции. Если же подпрограмма вызвана с помощью Gosub, инструкция Return вернёт управление к первой инструкции после Gosub.

Эта процедура загружает NULL в регистр P2. Когда регистр адреса возврата содержит NULL, инструкция Return ничего не делает и просто передаёт управление следующей инструкции (при условии, что значение P3 опкода Return равно 1). Поэтому при прямом выполнении подпрограммы Return продолжит выполнение следующих за ней инструкций. Если же подпрограмма вызвана через Gosub, инструкция Return вернёт управление по адресу, следующему за Gosub.

Этот опкод идентичен Null. У него другое имя только для упрощения чтения и проверки байт-кода.

BitAnd Выполняет побитовое И над значениями в регистрах P1 и P2 и сохраняет результат в регистре P3. Если любой из операндов равен NULL, результат равен NULL.
BitNot Интерпретирует содержимое регистра P1 как целое число. Сохраняет побитовое дополнение значения P1 в регистре P2. Если P1 содержит NULL, сохраняет NULL в P2.
BitOr Выполняет побитовое ИЛИ над значениями в регистрах P1 и P2 и сохраняет результат в регистре P3. Если любой из операндов равен NULL, результат равен NULL.
Blob P4 указывает на блоб данных длиной P1 байт. Сохраняет этот блоб в регистре P2. Если P4 — указатель NULL, создаёт в P2 блоб длиной P1 байт, заполненный нулями.
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. Записывает 1 или 0 в mem[P3] в зависимости от того, вернула ли контрольная точка SQLITE_BUSY. Записывает количество страниц в WAL после контрольной точки в mem[P3+1], а количество страниц в WAL, для которых контрольная точка завершилась, — в mem[P3+2]. Однако при ошибке mem[P3+1] и mem[P3+2] инициализируются значением -1.
Clear Удаляет всё содержимое таблицы или индекса базы данных, корневая страница которого в файле базы данных задана значением P1. Однако, в отличие от Destroy, не удаляет таблицу или индекс из файла базы данных.

Если P2==0, очищаемая таблица находится в основном файле базы данных. Если P2==1, таблица находится во вспомогательном файле базы данных, используемом для хранения таблиц, созданных с помощью CREATE TEMPORARY TABLE.

Если значение P3 не равно нулю, счётчик изменений строк увеличивается на количество строк в очищаемой таблице. Если P3 больше нуля, значение в регистре P3 также увеличивается на количество строк в очищаемой таблице.

См. также: Destroy

Close Закрывает курсор, ранее открытый как P1. Если P1 в данный момент не открыт, инструкция ничего не делает.
ClrSubtype Очищает подтип регистра 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_LENGTHARG, гарантируется, что результат будет использоваться только функцией length() или её эквивалентом. Содержимое больших блобов не загружается, что позволяет сэкономить циклы ЦП. Если установлен бит OPFLAG_TYPEOFARG, результат будет использоваться только функцией typeof(), операторами IS NULL или IS NOT NULL либо их эквивалентами. В этом случае загрузку всего содержимого можно пропустить.

ColumnsUsed Этот опкод (который существует только в сборках SQLite с SQLITE_ENABLE_COLUMN_USED_MASK) указывает, какие столбцы таблицы или индекса для курсора P1 используются. P4 — 64-разрядное целое число (P4_INT64), в котором каждый из первых 63 битов установлен для соответствующего столбца из первых 63 столбцов таблицы или индекса, фактически используемого курсором. Старший бит устанавливается, если используется какой-либо столбец после 64-го.
Compare Сравнивает два вектора регистров: reg(P1)..reg(P1+P3-1) (обозначим этот вектор «A») и reg(P2)..reg(P2+P3-1) («B»). Сохраняет результат сравнения для использования следующей инструкцией Jump.

Если в P5 установлен бит OPFLAG_PERMUTE, порядок сравнения определяется последним оператором Permutation. Если бит OPFLAG_PERMUTE сброшен, регистры сравниваются последовательно.

P4 — структура KeyInfo, задающая последовательности сортировки и порядок сортировки для сравнения. Перестановка применяется только к регистрам. Элементы KeyInfo используются последовательно.

Сравнение выполняется в порядке сортировки: значения NULL равны друг другу, NULL меньше чисел, числа меньше строк, а строки меньше блобов.

Сразу за этим опкодом должен следовать опкод Jump.

Concat Добавляет текст из регистра P1 в конец текста в регистре P2 и сохраняет результат в регистре P3. Если текст в P1 или P2 равен NULL, сохраняет NULL в P3.

P3 = P2 || P1

Регистры P1 и P3 не должны совпадать. Иногда, если P3 совпадает с P2, реализация может избежать вызова memcpy().

Copy Копирует регистры P1..P1+P3 в регистры P2..P2+P3.

Если установлен бит 0x0002 параметра P5, в назначении также сбрасывается флаг MEM_Subtype. Бит 0x0001 параметра P5 указывает, что этот опкод Copy нельзя объединять с другими. Бит 0x0001 используется планировщиком запросов и не влияет на выполнение запроса.

Эта инструкция создаёт глубокую копию значения. Для любой строковой или блоб-константы создаётся дубликат. См. также SCopy.

Count Сохраняет в регистре P2 количество записей (целое число) в таблице или индексе, открытом курсором P1.

Если P3==0, получается точное количество, для чего требуется просмотреть каждую страницу btree таблицы. Если P3 не равен нулю, возвращается оценка, основанная на текущем положении курсора.

CreateBtree Выделяет новое дерево b-tree в основном файле базы данных, если P1==0, во временном файле базы данных, если P1==1, или в подключённой базе данных, если P1>1. Для таблицы с rowid аргумент P3 должен быть равен 1 (BTREE_INTKEY), а для индекса или таблицы WITHOUT ROWID — 2 (BTREE_BLOBKEY). Номер корневой страницы нового дерева b-tree сохраняется в регистре P2.
CursorHint Передаёт курсору P1 подсказку о том, что ему нужно возвращать только строки, удовлетворяющие выражению Expr в P4. Термы TK_REGISTER в выражении P4 ссылаются на значения, хранящиеся в данный момент в регистрах. Термы TK_COLUMN в выражении P4 ссылаются на столбцы дерева b-tree, на которое указывает курсор P1.
CursorLock Блокирует дерево btree, на которое указывает курсор P1, чтобы другой курсор не мог выполнять запись в это дерево.
CursorUnlock Снимает блокировку с дерева btree, на которое указывает курсор P1, чтобы другие курсоры могли выполнять запись в это дерево.
DecrJumpZero В регистре P1 должно находиться целое число. Уменьшает значение в P1 и переходит к P2, если новое значение равно нулю.
DeferredSeek P1 — открытый курсор индекса, а P3 — курсор соответствующей таблицы. Этот опкод выполняет отложенный поиск курсора таблицы P3 по строке, соответствующей текущей строке P1.

Поиск выполняется отложенно. Фактически ничего не происходит, пока курсор не используется для чтения записи. Таким образом, если чтение не выполняется, не происходит и лишнего ввода-вывода.

P4 может быть массивом целых чисел (тип P4_INTARRAY), содержащим по одной записи для каждого столбца таблицы P3. Если элемент массива a(i) не равен нулю, чтение столбца a(i)-1 курсором P3 эквивалентно выполнению отложенного поиска, а затем чтению столбца i из P1. Эта информация хранится в P3 и используется для перенаправления чтения из P3 в P1, что может избавить от необходимости искать и читать данные курсором P3.

Delete Удаляет запись, на которую в данный момент указывает курсор P1.

Если в параметре P5 установлен бит OPFLAG_SAVEPOSITION, курсор останется указывать на следующую или предыдущую запись таблицы. Если он останется указывать на следующую запись, следующая инструкция Next ничего не сделает. Поэтому в этом случае запись можно удалять внутри цикла Next. Если бит OPFLAG_SAVEPOSITION параметра P5 сброшен, курсор останется в неопределённом состоянии.

Если в P5 установлен бит OPFLAG_AUXDELETE, это означает, что данное удаление является одним из нескольких удалений, связанных с удалением строки таблицы и всех соответствующих ей записей индекса. Ровно одно из этих удалений является «основным». Остальные выполняются курсорами OPFLAG_FORDELETE или помечены флагом AUXDELETE.

Если установлен флаг OPFLAG_NCHANGE (0x01) параметра P2 (обратите внимание: P2, а не P5), счётчик изменений строк увеличивается (иначе он не изменяется).

Если установлен флаг OPFLAG_ISNOOP (0x40) параметра P2 (не P5!), запускается pre-update-hook для удаления, но дерево btree в остальном не изменяется. Это происходит, когда за Delete вскоре следует Insert с тем же ключом, в результате чего запись дерева btree перезаписывается.

P1 не должен быть псевдотаблицей. Это должна быть настоящая таблица с несколькими строками.

Если P4 не равен NULL, он указывает на объект Table. В этом случае может быть вызван обработчик обновления, pre-update-hook или оба обработчика. Перед вызовом этого опкода курсор P1 в таком случае должен быть позиционирован с помощью NotFound. В частности, если pre-update-hook настроен, он вызывается, когда P4 не равен NULL. Обработчик обновления вызывается, если он настроен, P4 не равен NULL и в P2 установлен флаг OPFLAG_NCHANGE.

Если в P2 установлен флаг OPFLAG_ISUPDATE, P3 содержит адрес ячейки памяти со значением, которое операция обновления присвоит rowid строки.

Destroy Удаляет всю таблицу или индекс базы данных, корневая страница которого в файле базы данных задана значением P1.

Если P3==0, уничтожаемая таблица находится в основном файле базы данных. Если P3==1, таблица находится во вспомогательном файле базы данных, используемом для хранения таблиц, созданных с помощью CREATE TEMPORARY TABLE.

Если включён AUTOVACUUM, другая корневая страница может быть перемещена на место только что удалённой корневой страницы, чтобы сохранить непрерывность расположения всех корневых страниц в начале базы данных. Прежнее значение перемещённой корневой страницы — до перемещения — сохраняется в регистре P2. Если перемещение страницы не потребовалось (поскольку удаляемая таблица уже была последней в базе данных), в регистр P2 записывается ноль. Если AUTOVACUUM отключён, в регистр P2 также записывается ноль.

Этот опкод вызывает ошибку, если во время его выполнения работают какие-либо виртуальные машины-читатели. Это сделано, чтобы избежать сложностей с обновлением существующих курсоров при перемещении корневой страницы в базе данных с AUTOVACUUM. Ошибка вызывается, даже если база данных не использует AUTOVACUUM, чтобы избежать несовместимости между режимами с автоочисткой и без неё.

См. также: Clear

Divide Делит значение в регистре P1 на значение в регистре P2 и сохраняет результат в регистре P3 (P3=P2/P1). Если значение в регистре P1 равно нулю, результат равен NULL. Если любой из операндов равен NULL, результат равен NULL.
DropIndex Удаляет внутренние структуры данных (в памяти), описывающие индекс с именем P4 в базе данных P1. Этот опкод вызывается после удаления индекса с диска (с помощью опкода Destroy), чтобы внутреннее представление схемы соответствовало данным на диске.
DropTable Удаляет внутренние структуры данных (в памяти), описывающие таблицу с именем P4 в базе данных P1. Этот опкод вызывается после удаления таблицы с диска (с помощью опкода Destroy), чтобы внутреннее представление схемы соответствовало данным на диске.
DropTrigger Удаляет внутренние структуры данных (в памяти), описывающие триггер с именем P4 в базе данных P1. Этот опкод вызывается после удаления триггера с диска (с помощью опкода Destroy), чтобы внутреннее представление схемы соответствовало данным на диске.
ElseEq Этот опкод должен следовать за оператором сравнения Lt или Gt. Между ними может находиться ноль или более опкодов OP_ReleaseReg, но никаких других опкодов между этой инструкцией и предыдущей инструкцией Lt или Gt быть не должно.

Если результат сравнения Eq тех же двух операндов, что и у предыдущего Lt или Gt, был бы истинным, выполняется переход к P2. Если результат сравнения Eq двух предыдущих операндов был бы ложным или NULL, выполнение продолжается со следующей инструкции.

EndCoroutine Инструкция по адресу в регистре P1 — это Yield. Выполняет Jump к параметру P2 этой инструкции Yield. После перехода в регистре P1 остаётся значение, при котором последующие OP_Yields возвращают управление к той же инструкции EndCoroutine.

См. также: InitCoroutine

Eq Сравнивает значения в регистрах P1 и P3. Если reg(P3)==reg(P1), выполняет переход по адресу P2.

Часть SQLITE_AFF_MASK параметра P5 должна содержать символ аффинности — SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER и т. д. Перед сравнением выполняется попытка преобразовать оба операнда согласно этой аффинности. Если SQLITE_AFF_MASK равен 0x00, используется числовая аффинность. Обратите внимание, что результаты преобразования аффинности записываются обратно во входные регистры P1 и P3. Таким образом, этот опкод может вносить постоянные изменения в регистры P1 и P3.

После выполнения преобразований, если ни одно из значений не равно NULL, значения сравниваются. Если оба значения являются блобами, для определения результата сравнения используется memcmp(). Если оба значения являются текстом, для сравнения используется соответствующая функция сортировки, заданная в P4. Если P4 не задан, строки сравниваются с помощью memcmp(). Если оба значения числовые, используется числовое сравнение. Если значения имеют разные типы, числа считаются меньше строк, а строки — меньше блобов.

Если в P5 установлен SQLITE_NULLEQ, результат сравнения всегда будет истинным или ложным и никогда не будет NULL. Если оба операнда равны NULL, результат сравнения — true. Если один из операндов равен NULL, результат — false. Если ни один из операндов не равен NULL, результат будет таким же, как если бы флаг SQLITE_NULLEQ отсутствовал в P5.

Этот опкод сохраняет результат сравнения для использования новой инструкцией Jump.

Expire Помечает предварительно скомпилированные операторы как устаревшие. При выполнении устаревшего оператора с помощью sqlite3_step() он либо автоматически подготовится заново (если изначально был создан с помощью sqlite3_prepare_v2()), либо завершится ошибкой SQLITE_SCHEMA.

Если P1 равен 0, устаревшими становятся все операторы SQL. Если P1 не равен нулю, устаревшим становится только выполняемый в данный момент оператор.

Если P2 равен 0, операторы SQL устаревают немедленно. Если P2 равен 1, выполняющимся операторам SQL разрешается завершить работу. Случай P2==1 возникает при создании индекса CREATE INDEX или другом аналогичном изменении схемы, которое может ускорить выполнение оператора, не влияя на его корректность.

Explain При обычном выполнении запроса эта инструкция эквивалентна Noop. Назначение этого опкода — хранить сведения о плане запроса для вывода EXPLAIN QUERY PLAN.

Значение P4 — понятный человеку текст, описывающий элемент плана запроса. Например, «SCAN t1» или «SEARCH t2 USING INDEX t2x1».

Значение P1 — идентификатор текущего элемента, а P2 — родительский элемент для вложенных элементов плана запроса. Если P2 равен нулю, этот элемент является элементом верхнего уровня.

Для элементов цикла P3 — оценочная стоимость каждого вызова этого элемента.

Как и значения параметров всех опкодов, значения параметров Explain могут меняться от выпуска к выпуску. Приложениям не следует пытаться интерпретировать или использовать какую-либо информацию из опкода Explain. Информация, предоставляемая этим опкодом, предназначена только для тестирования и отладки.

Filter Вычисляет хеш ключа, содержащегося в регистрах P4, начиная с r[P3]. Проверяет, присутствует ли этот хеш в фильтре Блума, хранящемся в регистре P1. Если хеш отсутствует, возможно, выполняется переход к P2. В противном случае выполнение продолжается со следующей инструкции.

Ложноотрицательные результаты безвредны. Продолжить выполнение безопасно всегда, даже если значение присутствует в фильтре Блума. Ложноотрицательный результат приводит к лишним циклам ЦП, но правильный ответ всё равно будет получен. Однако ложноположительный результат вполне может привести к неправильному ответу — если переход выполняется, хотя следовало продолжить выполнение.

FilterAdd Вычисляет хеш регистров P4, начиная с r[P3], и добавляет этот хеш в фильтр Блума, содержащийся в r[P1].
FinishSeek Если ранее курсор P1 был перемещён с помощью DeferredSeek, немедленно завершает эту операцию поиска. Если поиск курсора уже выполнен, инструкция ничего не делает.
FkCheck Останавливает выполнение с ошибкой SQLITE_CONSTRAINT, если имеются неразрешённые нарушения ограничений внешнего ключа. Если нарушений ограничений внешнего ключа нет, инструкция ничего не делает.

Нарушения ограничений внешнего ключа также проверяются при завершении подготовленного оператора. Этот опкод используется для вызова ошибок ограничений внешнего ключа до возврата таких результатов, как счётчик изменений строк или результат предложения RETURNING.

FkCounter Увеличивает «счётчик ограничений» на P2 (P2 может быть положительным или отрицательным). Если P1 не равен нулю, увеличивается счётчик ограничений базы данных (отложенные ограничения внешнего ключа). Если P1 равен нулю, увеличивается счётчик оператора (немедленные ограничения внешнего ключа).
FkIfZero Этот опкод проверяет, равен ли в данный момент нулю счётчик ограничений внешнего ключа. Если да, выполняется переход к инструкции P2. В противном случае выполнение продолжается со следующей инструкцией.

Если P1 не равен нулю, переход выполняется, когда счётчик ограничений базы данных равен нулю (счётчик, учитывающий отложенные нарушения ограничений). Если P1 равен нулю, переход выполняется, когда счётчик ограничений оператора равен нулю (немедленные нарушения ограничений внешнего ключа).

Found Если P4==0, в регистре P3 находится блоб, созданный с помощью MakeRecord. Если P4>0, регистр P3 — первый из P4 регистров, образующих распакованную запись.

Курсор P1 установлен на индексе btree. Если запись, заданная P3 и P4, является префиксом какой-либо записи в P1, выполняется переход к P2, а P1 остаётся указывать на соответствующую запись.

После этой операции курсор остаётся в состоянии, допускающем перемещение вперёд. Инструкция Next будет работать, а инструкция Prev — нет.

См. также: NotFound, NoConflict, NotExists. SeekGe

Function Вызывает пользовательскую функцию (P4 — указатель на объект sqlite3_context, содержащий указатель на вызываемую функцию) с аргументами из регистра P2 и следующих за ним регистров. Количество аргументов указано в объекте sqlite3_context, на который указывает P4. Результат функции сохраняется в регистре P3. Регистр P3 не должен совпадать ни с одним из входных регистров функции.

P1 — 32-разрядная битовая маска, указывающая, были ли аргументы функции определены как константы во время компиляции. Если первый аргумент был константой, устанавливается бит 0 в P1. Это используется для определения того, можно ли безопасно сохранять метаданные, связанные с аргументом пользовательской функции с помощью API sqlite3_set_auxdata(), до следующего вызова этого опкода.

См. также: AggStep, AggFinal, PureFunc

Ge Работает так же, как опкод Lt, за исключением того, что переход выполняется, если содержимое регистра P3 больше или равно содержимому регистра P1. Дополнительные сведения см. в описании опкода Lt.
GetSubtype Извлекает значение подтипа из регистра P1 и записывает его в регистр P2. Если у P1 нет подтипа, в P1 записывается NULL.
Gosub Записывает текущий адрес в регистр P1, а затем выполняет переход по адресу P2.
Goto Безусловный переход по адресу P2. Следующей будет выполнена инструкция с индексом P2 от начала программы.

Параметр P1 фактически не используется этим опкодом. Однако иногда ему задают значение 1 вместо 0, чтобы сообщить командной оболочке, что этот Goto завершает цикл и строки от P2 до текущей строки следует выделить отступом в выводе EXPLAIN.

Gt Работает так же, как опкод Lt, за исключением того, что переход выполняется, если содержимое регистра P3 больше содержимого регистра P1. Дополнительные сведения см. в описании опкода Lt.
Halt Немедленно завершает выполнение. Все открытые курсоры и прочие объекты закрываются автоматически.

P1 — код результата, возвращаемый sqlite3_exec(), sqlite3_reset() или sqlite3_finalize(). При обычном завершении это должно быть SQLITE_OK (0). При ошибке может возвращаться другое значение. Если P1!=0, параметр P2 определяет, следует ли откатить текущую транзакцию. Откат не выполняется, если P2==OE_Fail. Откат выполняется, если P2==OE_Rollback. Если P2==OE_Abort, отменяются все изменения, выполненные за время этого запуска VDBE, но сама транзакция не откатывается.

Если P3 не равен нулю, а P4 равен NULL, в P3 находится регистр с текстом сообщения об ошибке.

Если P3 равен нулю, а P4 не равен NULL, строка сообщения об ошибке содержится в P4.

Если P5 имеет значение от 1 до 4 включительно, строка сообщения об ошибке из P4 изменяется следующим образом:

1: нарушено ограничение NOT NULL: P4 2: нарушено ограничение UNIQUE: P4 3: нарушено ограничение CHECK: P4 4: нарушено ограничение FOREIGN KEY: P4

Если P3 равен нулю, P5 не равен нулю, а P4 равен NULL, всё после символа «:» опускается.

В самом конце каждой программы неявно добавляется инструкция «Halt 0 0 0». Поэтому переход за пределы последней инструкции программы эквивалентен выполнению Halt.

HaltIfNull Проверяет значение в регистре P3. Если оно равно NULL, выполняет Halt с параметрами P1, P2 и P4, как если бы это была инструкция Halt. Если значение в регистре P3 не равно NULL, процедура ничего не делает. Параметр P5 должен быть равен 1.
IdxDelete Содержимое регистров P3, начиная с регистра P2, образует распакованный ключ индекса. Этот опкод удаляет соответствующую запись из индекса, открытого курсором P1.

P4 — указатель на структуру Index.

Если соответствующая запись индекса не найдена и не включён режим writable_schema, возникает ошибка SQLITE_CORRUPT_INDEX.

IdxGE Значения регистров P4, начиная с P3, образуют распакованный ключ индекса, не содержащий PRIMARY KEY. Compare это значение ключа с индексом, на который в данный момент указывает P1, игнорируя поля PRIMARY KEY или ROWID в конце.

Если запись индекса P1 больше или равна значению ключа, перейти к P2. В противном случае перейти к следующей инструкции.

IdxGT Значения регистров P4, начиная с P3, образуют распакованный ключ индекса, не содержащий PRIMARY KEY. Compare это значение ключа с индексом, на который в данный момент указывает P1, игнорируя поля PRIMARY KEY или ROWID в конце.

Если запись индекса P1 больше значения ключа, перейти к P2. В противном случае перейти к следующей инструкции.

IdxInsert В регистре P2 хранится ключ индекса SQL, созданный инструкциями MakeRecord. Эта операция записывает ключ в индекс P1. Данные записи равны nil.

Если P4 не равен нулю, то он задаёт количество значений в распакованном ключе reg(P2). В этом случае P3 — индекс первого регистра распакованного ключа. Наличие распакованного ключа иногда позволяет выполнить оптимизацию.

Если в P5 установлен бит OPFLAG_APPEND, это служит подсказкой для уровня b-tree о том, что, вероятно, выполняется добавление в конец.

Если в P5 установлен бит OPFLAG_NCHANGE, эта инструкция увеличивает счётчик изменений. Если бит OPFLAG_NCHANGE не установлен, счётчик изменений не изменяется.

Если установлен флаг OPFLAG_USESEEKRESULT в P5, реализация может работать быстрее, избегая ненужного поиска по курсору P1. Однако флаг OPFLAG_USESEEKRESULT следует устанавливать только в том случае, если до этого по курсору не выполнялось поиск либо если при последнем поиске использовался ключ, эквивалентный P2.

Эта инструкция работает только с индексами. Эквивалентная инструкция для таблиц — Insert.

IdxLE Значения регистров P4, начиная с P3, образуют распакованный ключ индекса, не содержащий PRIMARY KEY или ROWID. Compare это значение ключа с индексом, на который в данный момент указывает P1, игнорируя PRIMARY KEY или ROWID в индексе P1.

Если запись индекса P1 меньше или равна значению ключа, перейти к P2. В противном случае перейти к следующей инструкции.

IdxLT Значения регистров P4, начиная с P3, образуют распакованный ключ индекса, не содержащий PRIMARY KEY или ROWID. Compare это значение ключа с индексом, на который в данный момент указывает P1, игнорируя PRIMARY KEY или ROWID в индексе P1.

Если запись индекса P1 меньше значения ключа, перейти к P2. В противном случае перейти к следующей инструкции.

IdxRowid Записать в регистр P2 целое число, являющееся последней записью в записи в конце ключа индекса, на который указывает курсор P1. Это число должно быть rowid записи таблицы, на которую указывает эта запись индекса.

См. также: Rowid, MakeRecord.

If Перейти к P2, если значение в регистре P1 истинно. Значение считается истинным, если оно числовое и не равно нулю. Если значение в P1 равно NULL, выполнить переход тогда и только тогда, когда P3 не равен нулю.
IfEmpty Проверить, пуста ли таблица b-tree, на которую ссылается курсор P1, и перейти к P2, если она пуста.
IFindKey Эта инструкция всегда следует за инструкцией Found с такими же значениями P1, P2 и P3, как у этой инструкции, и ненулевым значением P4. Значение P4 этой операции имеет тип P4_INDEX и содержит указатель на объект Index для искомого индекса.

Эта операция использует sqlite3VdbeFindIndexKey() для поиска рядом с текущей позицией курсора ключа индекса, который точно совпадает по всем полям, не являющимся индексируемыми выражениями или ссылками на виртуальные генерируемые столбцы, а по остальным полям либо точно совпадает, либо содержит вещественные числа, отличающиеся не более чем на 2 ULP.

Иными словами, эта операция ищет рядом записи индекса, очень близкие к ключу поиска, но имеющие небольшие различия в значениях с плавающей точкой, полученных в результате вычисления выражения.

Если в курсоре P1 не найдено близкой альтернативной записи, перейти к P2. Если найдено близкое совпадение, перейти к следующей инструкции.

Эта операция используется командой PRAGMA integrity_check, чтобы помочь отличить действительно повреждённые индексы от индексов по выражениям, содержащих значения с плавающей точкой, отличающиеся на один или два ULP.

IfNoHope Регистр P3 — первый из P4 регистров, образующих распакованную запись. Курсор P1 указывает на индекс b-tree. P2 — адрес перехода. Иными словами, операнды этой операции совпадают с операндами NotFound и IdxGT.

Эта операция предназначена только для оптимизации. Если она всегда переходит к следующей инструкции, правильный результат всё равно будет получен, но потребуется дополнительная работа.

Значение N во флаге seekHit курсора P1 означает, что существует ключ P3:N, совпадающий с некоторой записью в индексе. Нужно выяснить, может ли запись P3:P4 совпасть с какой-либо записью в индексе. Если это невозможно, часть работы можно пропустить. Поэтому, если seekHit меньше P4, попытаться выяснить, возможно ли совпадение, выполнив NotFound.

Эта операция используется при обработке предложения IN для ключа из нескольких столбцов. Если предложение IN связано с элементом ключа, отличным от самого левого, и при последнем поиске по всему ключу совпадений не найдено, возможно, совпадению препятствует один из элементов ключа слева. Следовательно, «надежды» на совпадение нет независимо от того, сколько элементов предложения IN будет проверено. В этом случае поиск по предложению IN досрочно прекращается с помощью этой операции. Название операции связано с тем, что переход выполняется, если «надежды» на совпадение нет.

См. также: NotFound, SeekHit

IfNot Перейти к P2, если значение в регистре P1 ложно. Значение считается ложным, если его числовое значение равно нулю. Если значение в P1 равно NULL, выполнить переход тогда и только тогда, когда P3 не равен нулю.
IfNotOpen Если курсор P1 не открыт или для P1 установлена строка NULL с помощью операции NullRow, перейти к инструкции P2. В противном случае перейти к следующей инструкции.
IfNotZero Регистр P1 должен содержать целое число. Если исходное содержимое регистра P1 больше нуля, уменьшить значение в регистре P1. Если после этого оно не равно нулю (положительное или отрицательное), перейти к P2. Если изначально регистр P1 равен нулю, оставить его без изменений и перейти к следующей инструкции.
IfNullRow Проверить, указывает ли курсор P1 в данный момент на строку NULL. Если да, установить в регистре P3 значение NULL и немедленно перейти к P2. Если P1 не указывает на строку NULL, перейти к следующей инструкции, не внося изменений.

Если P1 не является открытым курсором, эта операция ничего не делает.

IfPos Регистр P1 должен содержать целое число. Если значение регистра P1 равно 1 или больше, вычесть P3 из значения в P1 и перейти к P2.

Если исходное значение регистра P1 меньше 1, оно не изменяется, и управление передаётся следующей инструкции.

IfSizeBetween Пусть N — приблизительное количество строк в таблице или индексе, на который указывает курсор P1, а X равно 10*log2(N), если N положительно, или -1, если N равно нулю.

Перейти к P2, если X находится в диапазоне от P3 до P4 включительно.

IncrVacuum Выполнить один шаг процедуры инкрементной очистки базы данных P1. Если очистка завершена, перейти к инструкции P2. В противном случае перейти к следующей инструкции.
Init В программах эта операция встречается один раз и является самой первой операцией.

Если трассировка включена с помощью интерфейса sqlite3_trace(), строка UTF-8 из P4 передаётся в функцию обратного вызова трассировки. Если P4 пуст, используется строка, возвращаемая sqlite3_sql().

Если P2 не равен нулю, перейти к инструкции P2.

Увеличить значение P1, чтобы операции Once при первом выполнении в этом запуске выполняли переход.

Если P3 не равен нулю, он задаёт адрес перехода при возникновении ошибки SQLITE_CORRUPT.

InitCoroutine Настроить регистр P1 так, чтобы он выполнял Yield для сопрограммы, расположенной по адресу P3.

Если P2!=0, реализация сопрограммы находится сразу после этой операции. Поэтому следует перейти через реализацию сопрограммы к адресу P2.

См. также: EndCoroutine

Insert Записать запись в таблицу курсора P1. Если такой записи ещё нет, она создаётся; в противном случае данные существующей записи перезаписываются. Данные — это значение MEM_Blob, хранящееся в регистре P2. Ключ хранится в регистре P3. Ключ должен иметь тип MEM_Int.

Если установлен флаг OPFLAG_NCHANGE в P5, счётчик изменений строк увеличивается (иначе он не изменяется). Если установлен флаг OPFLAG_LASTROWID в P5, rowid сохраняется для последующего возврата функцией sqlite3_last_insert_rowid() (иначе он не изменяется).

Если установлен флаг OPFLAG_USESEEKRESULT в P5, реализация может работать быстрее, избегая ненужного поиска по курсору P1. Однако флаг OPFLAG_USESEEKRESULT следует устанавливать только в том случае, если до этого по курсору не выполнялось поиск либо если при последнем поиске использовался ключ, равный P3.

Если установлен флаг OPFLAG_ISUPDATE, эта операция является частью операции UPDATE. В противном случае (если флаг не установлен) эта операция является частью операции INSERT. Это различие важно только для хука обновления.

Параметр P4 может указывать на структуру Table или иметь значение NULL. Если он не равен NULL, после успешной вставки вызывается хук обновления (sqlite3.xUpdateCallback).

(ПРЕДУПРЕЖДЕНИЕ/ПЛАН: если P1 — псевдокурсор, а P2 выделен динамически, владение P2 передаётся псевдокурсору, а регистр P2 становится временным. Если курсор изменится, значение регистра P2 также изменится. Убедитесь, что это не вызывает проблем.)

Эта инструкция работает только с таблицами. Эквивалентная инструкция для индексов — IdxInsert.

Int64 P4 — указатель на 64-разрядное целое значение. Записать это значение в регистр P2.
IntCopy Перенести целое значение из регистра P1 в регистр P2.

Это оптимизированная версия SCopy, работающая только с целыми значениями.

Integer Записать 32-разрядное целое значение P1 в регистр P2.
IntegrityCk Выполнить анализ открытой в данный момент базы данных. Записать в регистр (P1+1) текст сообщения об ошибке с описанием найденных проблем. Если проблем не обнаружено, записать в регистр (P1+1) значение NULL.

Регистр (P1) содержит число, на единицу меньше максимального допустимого количества ошибок. Будет выведено не более reg(P1) ошибок. Иными словами, анализ прекращается сразу после обнаружения reg(P1) ошибок. Значение reg(P1) обновляется и содержит оставшееся количество ошибок.

Номера корневых страниц всех таблиц базы данных — это целые числа, хранящиеся в аргументе P4_INTARRAY.

Если P5 не равен нулю, проверка выполняется для вспомогательного файла базы данных, а не для основного.

Эта операция используется для реализации pragma integrity_check.

IsNull Перейти к P2, если значение в регистре P1 равно NULL.
IsTrue Эта операция реализует операторы IS TRUE, IS FALSE, IS NOT TRUE и IS NOT FALSE.

Интерпретировать значение в регистре P1 как логическое. Записать это логическое значение (0 или 1) в регистр P2. Если значение в регистре P1 равно NULL, записать в регистр P2 значение P3. Если P4 равно 1, инвертировать результат.

Логика кратко представлена ниже:

  • Если P3==0 и P4==0, то r[P2] := r[P1] IS TRUE
  • Если P3==1 и P4==1, то r[P2] := r[P1] IS FALSE
  • Если P3==0 и P4==1, то r[P2] := r[P1] IS NOT TRUE
  • Если P3==1 и P4==0, то r[P2] := r[P1] IS NOT FALSE
IsType Перейти к P2, если тип столбца в b-tree соответствует одному из типов, указанных битовой маской P5.

Обычно P1 — это курсор на b-tree, для которого кэш декодирования строки действителен как минимум до столбца P3. Иными словами, ранее должна была выполняться операция Column для столбца P3 или более позднего. Если курсор недействителен, эта операция может дать ошибочные результаты. Если строка b-tree содержит меньше столбцов, чем P3, использовать P4 в качестве типа данных.

Если P1 равен -1, P3 задаёт номер регистра, а тип данных определяется по значению в этом регистре.

P5 — битовая маска типов данных. SQLITE_INTEGER соответствует младшему биту (0x01). SQLITE_FLOAT — биту 0x02. SQLITE_TEXT — 0x04. SQLITE_BLOB — 0x08. SQLITE_NULL — 0x10.

ПРЕДУПРЕЖДЕНИЕ: эта операция не позволяет надёжно отличить NULL от REAL, если P1>=0. Если база данных содержит значение NaN, эта операция определит тип данных как REAL, хотя он должен быть NULL. Если P1<0 и значение уже сохранено в регистре P3, операция надёжно различает NULL и REAL. Проблема возникает только при P1>=0.

Перейти по адресу P2 тогда и только тогда, когда тип данных значения, определяемого P1 и P3, соответствует одному из битов битовой маски P5.

JournalMode Изменить режим журнала базы данных P1 на P3. P3 должен быть одним из значений PAGER_JOURNALMODE_XXX. При переключении между различными режимами отката (delete, truncate, persist, off и memory) это простая операция. Операции ввода-вывода не требуются.

Переключение в режим WAL или из него выполняется сложнее.

Записать в регистр P2 строку с итоговым режимом журнала.

Jump Перейти к инструкции по адресу P1, P2 или P3 в зависимости от того, был ли в последней инструкции Compare вектор P1 меньше, равен или больше вектора P2 соответственно.

Эта операция должна непосредственно следовать за операцией Compare.

Last При следующем использовании инструкции Rowid, Column или Prev для P1 будет использоваться последняя запись таблицы или индекса базы данных. Если таблица или индекс пусты и P2>0, немедленно перейти к P2. Если P2 равен 0 или таблица либо индекс не пусты, перейти к следующей инструкции.

Эта операция настраивает курсор для перемещения в обратном порядке — от конца к началу. Иными словами, курсор настроен на использование Prev, а не Next.

Le Работает так же, как операция Lt, но переход выполняется, если содержимое регистра P3 меньше или равно содержимому регистра P1. Дополнительные сведения см. в описании операции Lt.
LoadAnalysis Прочитать таблицу sqlite_stat1 базы данных P1 и загрузить её содержимое во внутреннюю хеш-таблицу индексов. Благодаря этому результаты анализа будут использоваться при подготовке всех последующих запросов.
Lt Сравнить значения в регистрах P1 и P3. Если reg(P3)<reg(P1), перейти по адресу P2.

Если в P5 установлен бит SQLITE_JUMPIFNULL и reg(P1) или reg(P3) равен NULL, выполнить переход. Если бит SQLITE_JUMPIFNULL не установлен, перейти к следующей инструкции, если хотя бы один из операндов равен NULL.

Часть SQLITE_AFF_MASK параметра P5 должна содержать символ аффинности — SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER и т. д. Перед сравнением предпринимается попытка преобразовать оба входных значения согласно этой аффинности. Если SQLITE_AFF_MASK равен 0x00, используется числовая аффинность. Обратите внимание: результаты преобразования аффинности записываются обратно во входные регистры P1 и P3. Поэтому эта операция может привести к постоянному изменению регистров P1 и P3.

После выполнения преобразований, если ни одно из значений не равно NULL, значения сравниваются. Если оба значения являются blob, для определения результата сравнения используется memcmp(). Если оба значения являются текстом, для сравнения используется соответствующая функция сортировки, указанная в P4. Если P4 не задан, для сравнения текстовых строк используется memcmp(). Если оба значения числовые, выполняется числовое сравнение. Если значения имеют разные типы, числа считаются меньше строк, а строки — меньше blob.

Эта операция сохраняет результат сравнения для использования новой операцией Jump.

MakeRecord Преобразовать P2 регистров, начиная с P1, в формат записи, используемый для хранения записи данных в таблице базы данных или ключа в индексе. Позже операция Column может декодировать эту запись.

P4 может быть строкой длиной P2 символов. N-й символ строки задаёт аффинность столбца, которую следует использовать для N-го поля ключа индекса.

Соответствие символов аффинностям задаётся макросами SQLITE_AFF_, определёнными в sqliteInt.h.

Если P4 равен NULL, для всех полей индекса используется аффинность BLOB.

Значение P5 зависит от того, включён ли параметр компиляции SQLITE_ENABLE_NULL_TRIM:

* Если SQLITE_ENABLE_NULL_TRIM включён, P5 задаёт индекс самого правого столбца таблицы, для которого можно удалить завершающие значения NULL.

* Если SQLITE_ENABLE_NULL_TRIM не задан, P5 имеет значение OPFLAG_NOCHNG_MAGIC, если операции MakeRecord разрешено принимать записи без изменений с serial_type 10. Это значение используется только внутри assert() и не влияет на итоговый результат.

MaxPgcnt Попытаться установить максимальное количество страниц базы данных P1 равным значению в P3. Не допускать, чтобы максимальное количество страниц было меньше текущего, и не изменять его значение, если P3==0.

Записать максимальное количество страниц после изменения в регистр P2.

MemMax P1 — регистр в корневом кадре этой виртуальной машины (корневой кадр отличается от текущего, если эта инструкция выполняется в подпрограмме). Установить в регистре P1 максимальное из его текущего значения и значения в регистре P2.

Эта инструкция вызывает ошибку, если ячейка памяти изначально не содержит целое число.

Move Переместить P3 значений из регистров P1..P1+P3-1 в регистры P2..P2+P3-1. В регистрах P1..P1+P3-1 после этого останется NULL. Диапазоны регистров P1..P1+P3-1 и P2..P2+P3-1 не должны пересекаться. Значение P3 должно быть не меньше 1.
Multiply Умножить значение в регистре P1 на значение в регистре P2 и сохранить результат в регистре P3. Если один из входных операндов равен NULL, результатом будет NULL.
MustBeInt Принудительно преобразовать значение в регистре P1 в целое число. Если значение в P1 не является целым числом и его нельзя преобразовать в целое без потери данных, немедленно перейти к P2 или, если P2==0, вызвать исключение SQLITE_MISMATCH.
Ne Работает так же, как операция Eq, но переход выполняется, если операнды в регистрах P1 и P3 не равны. Дополнительные сведения см. в описании операции Eq.
NewRowid Получить новый номер записи (также называемый «rowid»), используемый в качестве ключа таблицы. Этот номер записи ранее не использовался в качестве ключа в таблице базы данных, на которую указывает курсор P1. Новый номер записи записывается в регистр P2.

Если P3>0, P3 — это регистр в корневом кадре данного VDBE, в котором хранится наибольший ранее сгенерированный номер записи. Новые номера записей не могут быть меньше этого значения. Когда это значение достигает максимума, возникает ошибка SQLITE_FULL. Регистр P3 обновляется сгенерированным номером записи. Этот механизм с P3 используется для реализации функции AUTOINCREMENT.

Next Переместить курсор P1 так, чтобы он указывал на следующую пару ключ/данные в таблице или индексе. Если пар ключ/значение больше нет, перейти к следующей инструкции. Если перемещение курсора выполнено успешно, немедленно перейти к P2.

Операция Next допустима только после операций SeekGT, SeekGE или Rewind, используемых для позиционирования курсора. За операциями SeekLT, SeekLE или Last операция Next следовать не может.

Курсор P1 должен указывать на настоящую таблицу, а не на псевдотаблицу. P1 должен быть открыт до этой операции, иначе программа завершится с ошибкой сегментации.

Значение P3 служит подсказкой для реализации b-tree. Если P3==1, это означает, что P1 — индекс SQL, а эту инструкцию можно было бы исключить, если бы индекс был уникальным. Обычно P3 равен 0. P3 всегда равен либо 0, либо 1.

Если P5 положителен и выполняется переход, увеличивается счётчик событий с номером P5-1 в подготовленной инструкции.

См. также: Prev

NoConflict Если P4==0, в регистре P3 хранится blob, созданный операцией MakeRecord. Если P4>0, регистр P3 — первый из P4 регистров, образующих распакованную запись.

Курсор P1 указывает на индекс b-tree. Если запись, определяемая P3 и P4, содержит значение NULL, немедленно перейти к P2. Если все поля записи не равны NULL, проверить, есть ли в индексе b-tree P1 строка с совпадающим префиксом ключа. Если совпадений нет, немедленно перейти к P2. Если совпадение есть, перейти к следующей инструкции, оставив курсор P1 указывающим на соответствующую строку.

Эта операция похожа на NotFound, за исключением того, что переход всегда выполняется, если какая-либо часть входного ключа поиска равна NULL.

После этой операции курсор переходит в состояние, в котором его нельзя перемещать ни в одном направлении. Иными словами, после неё операции Next и Prev не работают.

См. также: NotFound, Found, NotExists

Noop Ничего не делать. Перейти к следующей операции.
Not Интерпретировать значение в регистре P1 как логическое. Записать логическое дополнение в регистр P2. Если значение в регистре P1 равно NULL, записать NULL в P2.
NotExists P1 — индекс курсора, открытого на b-tree таблицы SQL (с целочисленными ключами). P3 — целочисленный rowid. Если в P1 нет записи с rowid P3, немедленно перейти к P2. Если P2 равен 0, вызвать ошибку SQLITE_CORRUPT. Если в P1 есть запись с rowid P3, оставить курсор указывающим на эту запись и перейти к следующей инструкции.

Операция SeekRowid выполняет то же действие, но также допускает нецелое значение в регистре P3; в этом случае переход выполняется всегда. Эта операция требует, чтобы P3 всегда содержал целое число.

Операция NotFound выполняет то же действие для индексных b-tree (с ключами из произвольного количества значений).

После этой операции курсор переходит в состояние, в котором его нельзя перемещать ни в одном направлении. Иными словами, после этой операции не работают операции Next и Prev.

См. также: Found, NotFound, NoConflict, SeekRowid

NotFound Если P4==0, в регистре P3 хранится blob, созданный операцией MakeRecord. Если P4>0, регистр P3 — первый из P4 регистров, образующих распакованную запись.

Курсор P1 указывает на индекс b-tree. Если запись, определяемая P3 и P4, не является префиксом ни одной записи в P1, выполняется переход к P2. Если в P1 есть запись с префиксом, совпадающим с записью P3/P4, управление переходит к следующей инструкции, а P1 остаётся указывать на соответствующую запись.

После этой операции курсор переходит в состояние, в котором его нельзя перемещать ни в одном направлении. Иными словами, после неё операции Next и Prev не работают.

См. также: Found, NotExists, NoConflict, IfNoHope

NotNull Перейти к P2, если значение в регистре P1 не равно NULL.
Null Записать NULL в регистр P2. Если P3 больше P2, также записать NULL в регистр P3 и во все регистры между P2 и P3. Если P3 меньше P2 (обычно P3 равен нулю), установить NULL только в регистре P2.

Если значение P1 не равно нулю, также установить флаг MEM_Cleared, чтобы значения NULL не считались равными, даже если для Ne или Eq установлен SQLITE_NULLEQ.

NullRow Переместить курсор P1 на строку NULL. Любые операции Column, выполняемые, когда курсор находится на строке NULL, всегда записывают NULL.

Если курсор P1 ранее не был открыт, открыть его сейчас как специальный псевдокурсор, который всегда возвращает NULL для каждого столбца.

Offset Сохранить в регистре r[P3] байтовое смещение в файле базы данных, соответствующее началу полезной нагрузки записи, на которую в данный момент указывает курсор P1.

P2 — номер столбца для аргумента функции sqlite_offset(). Эта операция не использует P2 напрямую, но значение P2 используется генератором кода. Операнды P1, P2 и P3 этой операции совпадают с операндами Column.

Эта операция доступна только в том случае, если SQLite скомпилирована с параметром -DSQLITE_ENABLE_OFFSET_SQL_FUNC.

OffsetLimit Эта операция выполняет часто используемое вычисление, связанное с обработкой LIMIT и OFFSET. В r[P1] хранится счётчик ограничения. В r[P3] хранится счётчик смещения. Операция вычисляет суммарное значение LIMIT и OFFSET и сохраняет его в r[P2]. Вычисленное значение r[P2] — это общее количество строк, которые потребуется просмотреть для выполнения запроса.

Если r[P3] равен нулю или отрицателен, это означает, что OFFSET отсутствует, и r[P2] устанавливается равным значению LIMIT — r[P1].

Если r[P1] равен нулю или отрицателен, это означает, что LIMIT отсутствует, и r[P2] устанавливается в -1.

В остальных случаях r[P2] устанавливается в сумму r[P1] и r[P3].

Once При первом выполнении этой операции за каждый запуск программы байт-кода перейти к следующей инструкции. При втором и всех последующих выполнениях в рамках того же запуска выполнить Jump к P2.

Программы верхнего уровня определяют первый запуск, сравнивая операнд P1 со значением операнда P1 в операции Init в начале программы. Если значения P1 различаются, перейти к следующей инструкции и присвоить P1 этой операции значение P1 из Init. Если значения P1 совпадают, выполнить переход.

Для подпрограмм в VdbeFrame имеется битовая маска, определяющая, следует ли выполнять переход. Битовая маска необходима, поскольку при рекурсивных триггерах не работает приём с самомодифицирующимся кодом.

Операнд P3 напрямую этой операцией не используется. Однако генератор кода использует P3 следующим образом: если эта операция является началом подпрограммы, использующей фильтр Блума, P3 будет регистром, в котором хранится этот фильтр Блума. Подробности реализации см. в исходном коде под меткой tag-202407032019.

OpenAutoindex Эта операция работает так же, как OpenEphemeral. Ей присвоено другое имя, чтобы отличать её назначение. Таблицы, созданные этой операцией, используются для автоматически создаваемых временных индексов при соединениях.
OpenDup Открыть новый курсор P1, указывающий на ту же временную таблицу, что и курсор P2. Курсор P2 должен быть открыт предшествующей операцией OpenEphemeral. Дублировать можно только временные курсоры.

Дублирующиеся временные курсоры используются для самосоединений материализованных представлений.

OpenEphemeral Открыть новый курсор P1 для временной таблицы. Курсор всегда открывается для чтения и записи, даже если основная база данных доступна только для чтения. Временная таблица автоматически удаляется при закрытии курсора.

Если курсор P1 уже открыт для временной таблицы, таблица очищается (всё содержимое удаляется).

P2 — количество столбцов во временной таблице. Если P4==0, курсор указывает на таблицу BTree, а если P4 не равен 0 — на индекс BTree. Если P4 не равен NULL, он указывает на структуру KeyInfo, определяющую формат ключей в индексе.

Параметр P5 может быть маской флагов BTREE_*, определённых в btree.h. Эти флаги управляют работой b-tree. Флаги BTREE_OMIT_JOURNAL и BTREE_SINGLE добавляются автоматически.

Если P3 положителен, значение reg[P3] слегка изменяется, чтобы его можно было использовать в качестве данных нулевой длины для Insert. Эта оптимизация позволяет избежать дополнительной операции Blob для инициализации этого регистра.

OpenPseudo Открыть новый курсор, указывающий на фиктивную таблицу, содержащую одну строку данных. Содержимое этой строки — содержимое регистра памяти P2. Иными словами, курсор P1 становится псевдонимом содержимого MEM_Blob, находящегося в регистре P2.

Псевдотаблица, созданная этой операцией, используется для хранения одной строки, выданной сортировщиком, чтобы строку можно было разделить на отдельные столбцы с помощью операции Column. Операция Column — единственная операция курсора, работающая с псевдотаблицей.

P3 — количество полей в записях, которые будут храниться в псевдотаблице. Если P2 равен 0 или отрицателен, псевдокурсор будет возвращать NULL для каждого столбца.

OpenRead Открыть курсор только для чтения для таблицы базы данных, корневая страница которой в файле базы данных имеет номер P2. Файл базы данных определяется значением P3. P3==0 означает основную базу данных, P3==1 — базу данных, используемую для временных таблиц, а P3>1 — соответствующую подключённую базу данных. Назначить новому курсору идентификатор P1. Значения P1 не обязаны быть последовательными, но все они должны быть небольшими целыми числами. Отрицательное значение P1 является ошибкой.

Допустимые биты P5:

  • 0x02 OPFLAG_SEEKEQ: этот курсор будет использоваться только для поиска на равенство (реализованного парой операций SeekGE/IdxGT или SeekLE/IdxLT)

Значение P4 может быть целым числом (P4_INT32) или указателем на структуру KeyInfo (P4_KEYINFO). Если это указатель на объект KeyInfo, открываемая таблица должна быть индексным B-деревом, содержимое и последовательность сортировки которого определяются объектом KeyInfo. В противном случае, если P4 — целочисленное значение, открываемая таблица должна быть табличным B-деревом с количеством столбцов не меньше значения P4.

См. также: OpenWrite, ReopenIdx

OpenWrite Открыть курсор для чтения и записи с именем P1 для таблицы или индекса, корневая страница которого имеет номер P2 (или номер корневой страницы хранится в регистре P2, если в P5 установлен бит OPFLAG_P2ISREG — см. ниже).

Значение P4 может быть целым числом (P4_INT32) или указателем на структуру KeyInfo (P4_KEYINFO). Если это указатель на объект KeyInfo, открываемая таблица должна быть индексным B-деревом, содержимое и последовательность сортировки которого определяются объектом KeyInfo. В противном случае, если P4 — целочисленное значение, открываемая таблица должна быть табличным B-деревом с количеством столбцов не меньше значения P4.

Допустимые биты P5:

  • 0x02 OPFLAG_SEEKEQ: этот курсор будет использоваться только для поиска на равенство (реализованного парой операций SeekGE/IdxGT или SeekLE/IdxLT)
  • 0x08 OPFLAG_FORDELETE: этот курсор используется только для поиска и последующего удаления записей в индексном B-дереве. Это подсказка для подсистемы хранения, которую она может игнорировать. Официальная подсистема хранения SQLite на основе B-дерева не использует эту подсказку, но её использует COMDB2.
  • 0x10 OPFLAG_P2ISREG: использовать содержимое регистра P2 в качестве корневой страницы, а не само значение P2.

Эта инструкция работает как OpenRead, но открывает курсор в режиме чтения и записи.

См. также: OpenRead, ReopenIdx

Or Вычислить логическое ИЛИ значений в регистрах P1 и P2 и сохранить результат в регистре P3.

Если P1 или P2 не равен нулю (истина), результатом будет 1 (истина), даже если другое входное значение равно NULL. NULL и ложь, а также два значения NULL дают результат NULL.

Pagecount Записать текущее количество страниц базы данных P1 в ячейку памяти P2.
Param Эта операция присутствует только во вложенных программах, вызываемых инструкцией Program. Скопировать значение, находящееся в ячейке памяти вызывающего (родительского) фрейма, в ячейку P2 адресного пространства текущего фрейма. Это используется триггерными программами для доступа к значениям new.* и old.*.

Адрес ячейки в родительском фрейме определяется сложением значения аргумента P1 этой операции со значением аргумента P1 вызывающей инструкции Program.

ParseSchema Прочитать и разобрать все записи из таблицы схемы базы данных P1, соответствующие предложению WHERE в P4. Если P4 — нулевой указатель, схема P1 разбирается заново целиком.

Эта операция вызывает анализатор для создания новой виртуальной машины, а затем запускает её. Таким образом, это реентерабельная операция.

Permutation Задать перестановку, используемую оператором Compare в следующей инструкции. Перестановка хранится в операнде P4.

Перестановка действительна только для следующей операции, которой должна быть Compare с установленным битом OPFLAG_PERMUTE в P5.

Первое целое число в массиве целых чисел P4 задаёт длину массива и не входит в перестановку.

Prev Переместить курсор P1 назад, чтобы он указывал на предыдущую пару ключ/данные в своей таблице или индексе. Если предыдущей пары ключ/значение нет, перейти к следующей инструкции. Если же перемещение курсора назад выполнено успешно, немедленно перейти к P2.

Операция Prev допустима только после операций SeekLT, SeekLE или Last, используемых для позиционирования курсора. За SeekGT, SeekGE или Rewind операция Prev следовать не может.

Курсор P1 должен относиться к настоящей таблице, а не к псевдотаблице. Если P1 не открыт, поведение не определено.

Значение P3 является подсказкой для реализации B-дерева. Если P3==1, это означает, что P1 — индекс SQL, и эту инструкцию можно было бы опустить, если бы индекс был уникальным. Обычно P3 равен 0. P3 всегда равен либо 0, либо 1.

Если P5 положителен и выполняется переход, счётчик событий с номером P5-1 в подготовленной инструкции увеличивается.

Program Выполнить программу триггера, переданную в P4 (тип P4_SUBPROGRAM).

P1 содержит адрес ячейки памяти, в которой находится первая ячейка массива значений, используемого как аргументы вложенной программы. P2 содержит адрес перехода, если вложенная программа выдаёт исключение IGNORE с помощью функции RAISE(). P2 может быть равен нулю, если исключение IGNORE возникнуть не может. Регистр P3 содержит адрес ячейки памяти в этой (родительской) виртуальной машине, используемой для выделения памяти, необходимой вложенной виртуальной машине во время выполнения.

P4 — указатель на виртуальную машину, содержащую программу триггера.

Если P5 не равен нулю, рекурсивный вызов программы разрешён.

PureFunc Вызвать пользовательскую функцию (P4 — указатель на объект sqlite3_context, содержащий указатель на вызываемую функцию) с аргументами из регистра P2 и следующих за ним регистров. Количество аргументов указано в объекте sqlite3_context, на который указывает P4. Результат функции сохраняется в регистре P3. Регистр P3 не должен совпадать с одним из входных регистров функции.

P1 — 32-разрядная битовая маска, указывающая, какие аргументы функции были определены как константы во время компиляции. Если первый аргумент является константой, устанавливается бит 0 в P1. Это используется для определения того, можно ли безопасно сохранять метаданные, связанные с аргументом пользовательской функции через API sqlite3_set_auxdata(), до следующего вызова этой операции.

Эта операция работает точно так же, как Function. Отличается только её имя. Она используется в случаях, когда функция должна быть чисто недетерминированной. Некоторые встроенные функции даты и времени могут быть детерминированными или недетерминированными в зависимости от аргументов. При недетерминированном использовании такие функции проверяют, были ли они вызваны с помощью PureFunc, а не Function, и в этом случае выдают ошибку.

См. также: AggStep, AggFinal, Function

ReadCookie Прочитать cookie с номером P3 из базы данных P1 и записать его в регистр P2. P3==1 — версия схемы. P3==2 — формат базы данных. P3==3 — рекомендуемый размер кеша pager и так далее. P1==0 — файл основной базы данных, а P1==1 — файл базы данных, используемый для хранения временных таблиц.

Перед выполнением этой инструкции для базы данных должна быть установлена блокировка чтения (должна быть начата транзакция или открыт курсор).

Real P4 — указатель на 64-разрядное число с плавающей точкой. Записать это значение в регистр P2.
RealAffinity Если в регистре P1 хранится целое число, преобразовать его в вещественное.

Эта операция используется при извлечении данных из столбца с аффинностью REAL. Для экономии места такие значения столбца могут храниться как целые числа, но после извлечения они должны иметь вещественный тип.

ReleaseReg Освободить регистры. Содержимое регистров после завершения этой операции становится ненадёжным.

Освобождаются P2 регистров, начиная с P1, за исключением регистра P1+ii, если установлен бит ii в P3. Иными словами, P3 — маска регистров, которые следует сохранить.

Освобождение регистра очищает указатель Mem.pScopyFrom. Это означает, что если содержимое освобождённого регистра было задано с помощью SCopy, изменение значения исходного регистра для SCopy больше не будет вызывать ошибку assert в sqlite3VdbeMemAboutToChange().

Если установлен P5, тип всех освобождённых регистров устанавливается в MEM_Undefined, поэтому любая последующая попытка прочитать освобождённый регистр (до его повторной инициализации) вызовет ошибку assert.

P5 следует устанавливать при каждом вызове этой операции. Однако генератор кода в некоторых местах освобождает регистры до их использования, исходя из (верного) предположения, что регистры не будут переназначены для других целей до использования и поэтому их безопасно освободить.

Эта операция доступна только в сборках для тестирования и отладки. В релизных сборках она не генерируется. Назначение этой операции — помочь проверить сгенерированный байт-код. Она фактически не участвует в вычислении результата.

Remainder Вычислить остаток от деления целого числа в регистре P2 на значение в регистре P1 и сохранить результат в регистре P3. Если значение в регистре P1 равно нулю, результат — NULL. Если любой из операндов равен NULL, результат — NULL.
ReopenIdx Операция ReopenIdx работает как OpenRead, но сначала проверяет, открыт ли уже курсор P1 для того же B-дерева; если открыт, эта операция ничего не делает. Иными словами, если курсор уже открыт, повторно открывать его не нужно.

Операцию ReopenIdx можно использовать только с P5==0 или P5==OPFLAG_SEEKEQ и объектом P4 типа P4_KEYINFO. Кроме того, значение P3 должно совпадать со значением P3 во всех остальных операциях ReopenIdx или OpenRead для того же номера курсора.

Допустимые биты P5:

  • 0x02 OPFLAG_SEEKEQ: этот курсор будет использоваться только для поиска на равенство (реализованного парой операций SeekGE/IdxGT или SeekLE/IdxLT)

См. также: OpenRead, OpenWrite

ResetCount Значение счётчика изменений копируется в счётчик изменений дескриптора базы данных (возвращаемый последующими вызовами sqlite3_changes()). Затем внутренний счётчик изменений виртуальной машины сбрасывается в 0. Это используется триггерными программами.
ResetSorter Удалить всё содержимое из временной таблицы или сортировщика, открытого на курсоре P1.

Эта операция работает только с курсорами, используемыми для сортировки и открытыми с помощью OpenEphemeral или SorterOpen.

ResultRow Регистры P1—P1+P2-1 содержат одну строку результатов. Эта операция приводит к завершению вызова sqlite3_step() с кодом возврата SQLITE_ROW и настраивает структуру sqlite3_stmt для доступа к значениям r(P1)..r(P1+P2-1) как к строке результата.
Return Перейти по адресу, хранящемуся в регистре P1. Если P1 — регистр адреса возврата, это приводит к возврату из подпрограммы.

Если P3 равен 1, переход выполняется только в том случае, если в регистре P1 хранится целочисленное значение; в противном случае выполнение продолжается со следующей операции, а Return ничего не делает. Если P3 равен 0, в регистре P1 должно храниться целое число, иначе возникает ошибка assert(). Для этой операции следует задавать P3 равным 1 при использовании вместе с BeginSubrtn и равным 0 во всех остальных случаях.

Значение в регистре P1 этой операцией не изменяется.

Движок байт-кода не использует P2. Однако, если P2 положителен и меньше текущего адреса, форматтер вывода "EXPLAIN" в CLI добавит отступ для всех операций от операции P2 до текущей Return, не включая её. P2 должен указывать на первую операцию подпрограммы, из которой выполняется возврат. Таким образом, значение P2 служит подсказкой для отступов в байт-коде. См. tag-20220407a в wherecode.c и shell.c.

Rewind При следующем использовании инструкции Rowid, Column или Next для P1 будет обработана первая запись таблицы или индекса базы данных. Если таблица или индекс пусты, немедленно перейти к P2. Если таблица или индекс не пусты, перейти к следующей инструкции.

Если P2 равен нулю, это утверждение о том, что таблица P1 никогда не бывает пустой, а значит, переход никогда не будет выполнен.

Эта операция настраивает курсор для перемещения вперёд, от начала к концу. Иными словами, курсор настроен на использование Next, а не Prev.

RowCell P1 и P2 — открытые курсоры. Оба должны быть открыты для таблиц одного типа — intkey или index. Эта операция используется при копировании текущей строки из P2 в P1. Если курсоры открыты для таблиц intkey, регистр P3 содержит rowid, который нужно использовать для новой записи в P1. Если курсоры открыты для индексных таблиц, P3 не используется.

За этой операцией должна следовать операция Insert или InsertIdx с установленным флагом OPFLAG_PREFORMAT, чтобы завершить вставку.

RowData Записать в регистр P2 полное содержимое строки, на которую в данный момент указывает курсор P1. Данные не интерпретируются. Они просто копируются в регистр P2 точно в том виде, в каком хранятся в файле базы данных.

Если курсор P1 указывает на индекс, содержимым является ключ строки. Если курсор P2 указывает на таблицу, извлекается содержимое строки.

Курсор P1 должен указывать на допустимую строку (не на строку NULL) настоящей таблицы, а не псевдотаблицы.

Если P3!=0, эта операция может создать временный указатель на страницу базы данных. Это означает, что содержимое выходного регистра станет недействительным при любом перемещении курсора, включая перемещения других курсоров, которые «сохраняют» текущую позицию курсора, чтобы записать данные в ту же таблицу. Если P3==0, данные копируются в память. P3!=0 быстрее, но P3==0 безопаснее.

Если P3!=0, содержимое регистра P2 нельзя использовать в OP_Result, и любая операция OP_Result сделает его недействительным. Содержимое регистра P2 также становится недействительным при выполнении таких операций, как Function, или при любом использовании другого курсора, указывающего на ту же таблицу.

Rowid Сохранить в регистре P2 целое число — ключ записи таблицы, на которую в данный момент указывает P1.

P1 может быть обычной таблицей или виртуальной таблицей. Раньше для виртуальных таблиц использовалась отдельная операция OP_VRowid, но теперь эта операция работает с таблицами обоих типов.

RowSetAdd Вставить целочисленное значение из регистра P2 в объект RowSet, хранящийся в регистре P1.

Если P2 не является целым числом, возникает ошибка assert.

RowSetRead Извлечь наименьшее значение из объекта RowSet в P1 и поместить его в регистр P3. Если объект RowSet P1 изначально пуст, оставить P3 без изменений и перейти к инструкции P2.
RowSetTest Предполагается, что в регистре P3 хранится 64-разрядное целочисленное значение. Если регистр P1 содержит объект RowSet и этот объект содержит значение из P3, перейти к P2. В противном случае вставить целое число из P3 в RowSet и перейти к следующей операции.

Объект RowSet оптимизирован для случая, когда наборы целых чисел добавляются отдельными этапами, причём в каждом наборе нет дубликатов. Каждый набор идентифицируется уникальным значением P4. Для первого набора должно выполняться P4==0, для последнего — P4==-1, а для всех остальных — P4>0.

Это позволяет выполнять оптимизации: (a) при P4==0 проверять наличие P3 в RowSet не нужно, поскольку гарантируется, что такого значения там нет; (b) при P4==-1 вставлять значение не нужно, поскольку оно никогда не будет проверяться; (c) при вставке значения из набора X не нужно искать, не было ли это же значение уже вставлено в рамках набора X (проверять нужно только, не было ли оно ранее вставлено в рамках другого набора).

Savepoint Открыть точку сохранения с именем, заданным параметром P4, освободить её или выполнить откат к ней — в зависимости от значения P1. Чтобы открыть новую точку сохранения, задать P1==0 (SAVEPOINT_BEGIN). Чтобы освободить (зафиксировать) существующую точку сохранения, задать P1==1 (SAVEPOINT_RELEASE). Чтобы выполнить откат к существующей точке сохранения, задать P1==2 (SAVEPOINT_ROLLBACK).
SCopy Создать поверхностную копию регистра P1 в регистр P2.

Эта инструкция создаёт поверхностную копию значения. Если значение является строкой или BLOB-объектом, копия содержит только указатель на исходное значение, поэтому при изменении исходного значения изменится и копия. Более того, если исходное значение освобождено, копия становится недействительной. Следовательно, программа должна гарантировать, что исходное значение не изменится в течение срока существования копии. Для создания полной копии используйте Copy.

SeekEnd Расположить курсор P1 в конце B-дерева, чтобы добавить в него новую запись.

Предполагается, что курсор используется только для добавления записей, поэтому, если он действителен, он уже должен указывать на конец B-дерева и перемещать его не нужно.

SeekGE Если курсор P1 указывает на таблицу SQL (B-дерево с целочисленными ключами), использовать значение в регистре P3 в качестве ключа. Если курсор P1 указывает на индекс SQL, P3 — первый регистр в массиве из P4 регистров, используемых как распакованный ключ индекса.

Переместить курсор P1 так, чтобы он указывал на наименьшую запись, значение которой больше или равно значению ключа. Если записей со значением больше или равным ключу нет и P2 не равен нулю, перейти к P2.

Если курсор P1 был открыт с флагом OPFLAG_SEEKEQ, эта операция либо установит его на запись, точно соответствующую ключу, либо выполнит переход к P2. При курсоре с флагом OPFLAG_SEEKEQ за этой операцией должна следовать операция IdxLE с теми же аргументами. Если эта операция выполнена успешно, операция IdxGT будет пропущена, но в последующих итерациях цикла она будет использоваться. Флаг OPFLAG_SEEKEQ служит подсказкой для уровня B-дерева о том, что выполняется поиск на равенство.

Эта операция настраивает курсор для перемещения вперёд, от начала к концу. Иными словами, курсор настроен на использование Next, а не Prev.

См. также: Found, NotFound, SeekLt, SeekGt, SeekLe

SeekGT Если курсор P1 указывает на таблицу SQL (B-дерево с целочисленными ключами), использовать значение в регистре P3 в качестве ключа. Если курсор P1 указывает на индекс SQL, P3 — первый регистр в массиве из P4 регистров, используемых как распакованный ключ индекса.

Переместить курсор P1 так, чтобы он указывал на наименьшую запись, значение которой больше значения ключа. Если записей со значением больше ключа нет и P2 не равен нулю, перейти к P2.

Эта операция настраивает курсор для перемещения вперёд, от начала к концу. Иными словами, курсор настроен на использование Next, а не Prev.

См. также: Found, NotFound, SeekLt, SeekGe, SeekLe

SeekHit При необходимости увеличить или уменьшить значение seekHit для курсора P1 так, чтобы оно было не меньше P2 и не больше P3.

Целое число seekHit обозначает максимальное количество терминов индекса, для которых известно, что есть хотя бы одно совпадение. Если значение seekHit меньше общего числа терминов равенства при поиске по индексу, может выполниться операция IfNoHope, чтобы проверить, можно ли досрочно прервать цикл IN и тем самым избежать лишней работы. Это часть оптимизации досрочного завершения IN.

P1 должен быть допустимым курсором B-дерева.

SeekLE Если курсор P1 указывает на таблицу SQL (B-дерево с целочисленными ключами), использовать значение в регистре P3 в качестве ключа. Если курсор P1 указывает на индекс SQL, P3 — первый регистр в массиве из P4 регистров, используемых как распакованный ключ индекса.

Переместить курсор P1 так, чтобы он указывал на наибольшую запись, значение которой меньше или равно значению ключа. Если записей со значением меньше или равным ключу нет и P2 не равен нулю, перейти к P2.

Эта операция настраивает курсор для перемещения в обратном порядке, от конца к началу. Иными словами, курсор настроен на использование Prev, а не Next.

Если курсор P1 был открыт с флагом OPFLAG_SEEKEQ, эта операция либо установит его на запись, точно соответствующую ключу, либо выполнит переход к P2. При курсоре с флагом OPFLAG_SEEKEQ за этой операцией должна следовать операция IdxLE с теми же аргументами. Если эта операция выполнена успешно, операция IdxGE будет пропущена, но в последующих итерациях цикла она будет использоваться. Флаг OPFLAG_SEEKEQ служит подсказкой для уровня B-дерева о том, что выполняется поиск на равенство.

См. также: 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 — индекс курсора, открытого для B-дерева таблицы SQL (с целочисленными ключами). Если в регистре P3 не содержится целое число или в P1 нет записи с rowid P3, немедленно перейти к P2. Если P2 равен 0, выдать ошибку SQLITE_CORRUPT. Если в P1 есть запись с rowid P3, оставить курсор указывающим на эту запись и перейти к следующей инструкции.

Операция NotExists выполняет ту же задачу, но для NotExists гарантируется, что в регистре P3 содержится целочисленное значение. При использовании этой операции в регистре P3 может не быть целого числа.

Операция NotFound выполняет ту же задачу для индексных B-деревьев (с произвольными составными ключами).

Эта операция оставляет курсор в состоянии, в котором его нельзя перемещать ни в одном направлении. Иными словами, после этой операции не будут работать операции Next и Prev.

См. также: Found, NotFound, NoConflict, SeekRowid

SeekScan Эта операция является префиксной операцией для SeekGE. Иными словами, за ней должна непосредственно следовать SeekGE. Это ограничение проверяется инструкциями assert().

Эта операция использует операнды P1—P4 следующей операции SeekGE. Далее операнды следующей операции SeekGE обозначаются как SeekOP.P1—SeekOP.P4. Также используются только операнды P1, P2 и P5 этой операции, обозначаемые как This.P1, This.P2 и This.P5.

Эта операция помогает оптимизировать операторы IN по многоколоночному индексу, когда оператор IN применяется к более поздним терминам индекса: она позволяет избежать лишних поисков в B-дереве, заменяя их переходами к следующей строке B-дерева. Правильный результат будет получен и в том случае, если эту операцию опустить или если она ничего не делает.

Операнды SeekGE.P3 и SeekGE.P4 задают распакованный ключ — требуемую запись, на которую должен указывать курсор SeekGE.P1. Назовём эту строку SeekGE.P3/P4 «целевой».

Если курсор SeekGE.P1 в данный момент не указывает на допустимую строку, эта операция ничего не делает и управление переходит к SeekGE.

Если курсор SeekGE.P1 указывает на допустимую строку, эта строка может быть целевой, находиться рядом и немного перед целевой строкой или располагаться после неё. Если курсор находится перед целевой строкой, эта операция пытается переместить его на целевую строку или за неё, вызывая sqlite3BtreeStep() для курсора от 1 до This.P1 раз.

Параметр This.P5 — это флаг, указывающий, что делать, если курсор укажет на допустимую строку, расположенную после целевой. Если This.P5 равен false (0), выполняется переход к SeekGE.P2. Если This.P5 равен true (не нулю), выполняется переход к This.P2. Случай P5==0 возникает, когда справа от ограничения IN нет ограничений неравенства. Переход к SeekGE.P2 завершает цикл. Случай P5!=0 возникает, когда справа от оператора IN есть ограничения неравенства. В таком случае This.P2 указывает либо непосредственно на операцию IdxGT или IdxGE, либо на подготовительный код перед ней; эта операция проверяет завершение цикла.

Возможные результаты выполнения этой операции:

  1. Если изначально курсор не указывает ни на одну допустимую строку, перейти к следующей операции SeekGE.

  2. Если после выполнения до This.P1 вызовов sqlite3BtreeNext() курсор по-прежнему указывает на строку перед целевой, также перейти к SeekGE.

  3. Если курсор указывает на целевую строку — изначально или после одного либо нескольких вызовов sqlite3BtreeNext(), — перейти к This.P2..,

  4. Если курсор изначально находился перед целевой строкой, а вызов sqlite3BtreeNext() переместил его за конец индекса (что указывает на то, что целевой строки определённо нет в B-дереве), перейти к SeekGE.P2 и завершить цикл.

  5. Если курсор указывает на допустимую строку, расположенную после целевой (что указывает на отсутствие целевой строки в B-дереве), перейти к SeekOP.P2, если This.P5==0, или к This.P2, если This.P5>0.
Sequence Найти следующий доступный номер последовательности для курсора P1. Записать этот номер в регистр P2. После выполнения этой инструкции номер последовательности курсора увеличивается.
SequenceTest P1 — курсор сортировщика. Если счётчик последовательности в данный момент равен нулю, перейти к P2. Независимо от того, выполнен переход или нет, увеличить значение последовательности.
SetCookie Записывает целочисленное значение P3 в cookie с номером P2 базы данных P1. P2==1 — версия схемы. P2==2 — формат базы данных. P2==3 — рекомендуемый размер кэша pager и так далее. P1==0 — основной файл базы данных, а P1==1 — файл базы данных, используемый для хранения временных таблиц.

Перед выполнением этого опкода необходимо начать транзакцию.

Если P2 — это cookie SCHEMA_VERSION (cookie с номером 1), внутренняя версия схемы устанавливается в P3-P5. В инструкции "PRAGMA schema_version=N" для P5 задано значение 1, поэтому внутренняя версия схемы будет отличаться от версии схемы базы данных, что приведёт к сбросу схемы.

SetSubtype Устанавливает для подтипа регистра P2 целочисленное значение из регистра P1. Если P1 равен NULL, очищает подтип в p2.
ShiftLeft Сдвигает целочисленное значение в регистре P2 влево на количество битов, заданное целым числом в регистре P1. Сохраняет результат в регистре P3. Если любой из входных аргументов равен NULL, результат равен NULL.
ShiftRight Сдвигает целочисленное значение в регистре P2 вправо на количество битов, заданное целым числом в регистре P1. Сохраняет результат в регистре P3. Если любой из входных аргументов равен NULL, результат равен NULL.
SoftNull Устанавливает для регистра P1 значение NULL, как его видит инструкция MakeRecord, но не освобождает память строк или blob-объектов, связанную с регистром, поэтому, если значение было строкой или blob-объектом, ранее скопированным с помощью SCopy, копии останутся действительными.
Sort Этот опкод выполняет ровно то же действие, что и Rewind, за исключением того, что он увеличивает недокументированную глобальную переменную, используемую для тестирования.

Сортировка выполняется путём записи записей в индекс сортировки, последующего перемещения к его началу и чтения записей от начала до конца. Для перемещения к началу мы используем опкод Sort вместо Rewind, чтобы увеличить глобальную переменную и дать регрессионным тестам возможность определить, правильно ли оптимизатор исключает сортировки.

SorterCompare P1 — курсор сортировщика. Эта инструкция сравнивает префикс blob-записи в регистре P3 с префиксом записи, на которую в данный момент указывает курсор сортировщика. Сравниваются только первые P4 полей r[P3] и записи сортировщика.

Если в P3 или сортировщике одно из значимых полей содержит NULL (не считая последних P4 полей, которые игнорируются), сравнение считается равным.

Если записи равны, перейти к следующей инструкции. Если они различаются, выполнить переход к P2 с помощью Jump.

SorterData Записывает текущие данные сортировщика для курсора сортировщика P1 в регистр P2. Затем очищает кэш заголовков столбцов курсора P3.

Этот опкод обычно используется для перемещения записи из сортировщика в регистр, который служит источником для курсора псевдотаблицы, созданного с помощью OpenPseudo. Этот курсор псевдотаблицы идентифицируется параметром P3. Очистка кэша столбцов P3 в рамках этого опкода избавляет от необходимости выполнять отдельную инструкцию NullRow для очистки этого кэша.

SorterInsert В регистре P2 находится ключ индекса SQL, созданный с помощью инструкций MakeRecord. Этот опкод записывает ключ в сортировщик P1. Данные записи отсутствуют.
SorterNext Этот опкод работает так же, как Next, за исключением того, что P1 должен быть объектом сортировщика, для которого был вызван опкод SorterSort. Этот опкод перемещает курсор к следующей отсортированной записи или выполняет переход к P2, если отсортированных записей больше нет.
SorterOpen Этот опкод работает как OpenEphemeral, но открывает временный индекс, специально предназначенный для сортировки больших таблиц с помощью алгоритма внешней сортировки слиянием.

Если аргумент P3 не равен нулю, это означает, что сортировщик может считать достаточной стабильную сортировку по первым P3 полям каждого ключа для получения требуемых результатов.

SorterSort После вставки всех записей в объект Sorter, идентифицируемый P1, вызовите этот опкод для выполнения сортировки. Если записей для сортировки нет, выполните переход к P2 с помощью Jump.

Этот опкод является псевдонимом Sort и Rewind, используемым для объектов Sorter.

SqlExec Выполняет инструкцию или инструкции SQL, указанные в строке P4.

Параметр P1 — это битовая маска параметров:

0x0001 Отключает обратные вызовы Auth и Trace на время выполнения инструкций из P4.

0x0002 Устанавливает db->nAnalysisLimit в P2 на время выполнения инструкций из P4.

String Строковое значение P4 длиной P1 (в байтах) сохраняется в регистре P2.

Если P3 не равен нулю и содержимое регистра P3 равно P5, тип данных регистра P2 преобразуется в BLOB. Содержимое представляет собой ту же последовательность байтов, которая лишь интерпретируется как BLOB, а не как строка, как если бы было выполнено приведение типа CAST. Иными словами:

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

String8 P4 указывает на строку UTF-8, завершённую нулевым символом. Перед первым выполнением этот опкод преобразуется в опкод String. Во время преобразования вычисляется длина строки P4 и сохраняется в параметре P1.
Subtract Вычитает значение в регистре P1 из значения в регистре P2 и сохраняет результат в регистре P3. Если любой из входных аргументов равен NULL, результат равен NULL.
TableLock Получает блокировку определённой таблицы. Эта инструкция используется только при включённой функции общего кэша.

P1 — индекс базы данных в sqlite3.aDb[], для которой приобретается блокировка. Если P3==0, устанавливается блокировка на чтение, а если P3==1 — блокировка на запись.

P2 содержит корневую страницу блокируемой таблицы.

P4 содержит указатель на имя блокируемой таблицы. Оно используется только для формирования сообщения об ошибке, если получить блокировку не удаётся.

Trace Записывает P4 в вывод трассировки инструкции, если трассировка инструкций включена.

Операнд P1 должен быть равен 0x7fffffff, а P2 должен быть положительным.

Transaction Начинает транзакцию для базы данных P1, если транзакция ещё не активна. Если P2 не равен нулю, начинается транзакция на запись или, если транзакция на чтение уже активна, она преобразуется в транзакцию на запись. Если P2 равен нулю, начинается транзакция на чтение. Если P2 равен 2 или больше, начинается эксклюзивная транзакция.

P1 — индекс файла базы данных, для которого начинается транзакция. Индекс 0 соответствует основному файлу базы данных, а индекс 1 — файлу, используемому для временных таблиц. Индексы 2 и выше используются для присоединённых баз данных.

Если начинается транзакция на запись и флаг Vdbe.usesStmtJournal имеет значение true (этот флаг устанавливается, если Vdbe может изменить более одной строки и вызвать исключение ABORT), также может быть открыта транзакция инструкции. Точнее, транзакция инструкции открывается тогда и только тогда, когда соединение с базой данных в данный момент не находится в режиме autocommit или имеются другие активные инструкции. Транзакция инструкции позволяет отменить изменения, внесённые этим VDBE, после ошибки, не отменяя всю транзакцию. Если ошибки не возникнет, транзакция инструкции будет автоматически зафиксирована при остановке VDBE.

Если P5!=0, этот опкод также проверяет cookie схемы по значению P3, а счётчик поколений схемы — по значению P4. Значение cookie меняется при каждом изменении схемы базы данных. Эта операция позволяет обнаружить изменение cookie и необходимость повторного чтения схемы текущим процессом. Если cookie схемы в P3 отличается от cookie схемы в заголовке базы данных или счётчик поколений схемы в P4 отличается от текущего счётчика поколений, возникает ошибка SQLITE_SCHEMA и выполнение останавливается. Затем функция-обёртка sqlite3_step() может заново подготовить инструкцию и выполнить её повторно с самого начала.

TypeCheck Применяет affinity к диапазону из P2 регистров, начиная с P1. Значения affinity берутся из объекта Table в P4. Если какое-либо значение нельзя привести к нужному типу, возникает ошибка.

Если P3==0, проверка столбцов VIRTUAL пропускается.

Если P3==1, пропускается проверка всех генерируемых столбцов — как VIRTUAL, так и STORED.

Если P3>=2, проверяется только столбец с номером P3-2 в таблице (это будет столбец VIRTUAL) на соответствие значению в reg[P1]. В этом случае P2 будет равен 1.

Этот опкод похож на Affinity, но принудительно задаёт тип регистра в соответствии с типом столбца Table. Это используется для реализации «строгой affinity».

Столбцы GENERATED ALWAYS AS ... STATIC проверяются, только если P3 равен нулю. Если P3 не равен нулю, проверка типов для статических генерируемых столбцов не выполняется. Виртуальные столбцы вычисляются во время выполнения запроса, поэтому они никогда не проверяются.

Предварительные условия:

  • P2 должно быть равно количеству невиртуальных столбцов в таблице P4, если только P3>1; в этом случае P2 будет равно 1.
  • Таблица P4 является таблицей STRICT.

Если какое-либо предварительное условие не выполнено, возникает ошибка утверждения.

Vacuum Выполняет вакуумирование всей базы данных P1. P1 равен 0 для "main" и 2 или больше для присоединённой базы данных. Базу данных "temp" вакуумировать нельзя.

Если P2 не равен нулю, это регистр, содержащий строку с именем файла, в который следует записать результат вакуумирования. Если P2 равен нулю, вакуумирование перезаписывает исходную базу данных.

Variable Переносит значения связанного параметра P1 в регистр P2
VBegin P4 может быть указателем на структуру sqlite3_vtab. Если это так, вызывается метод xBegin этой таблицы.

Кроме того, независимо от того, задан ли P4, проверяется, не вызван ли этот опкод из обратного вызова метода xSync() виртуальной таблицы. Если это так, код ошибки устанавливается в SQLITE_LOCKED.

VCheck P4 — указатель на объект Table, представляющий виртуальную таблицу в схеме P1, которая поддерживает метод xIntegrity(). Этот опкод запускает метод xIntegrity() для этой виртуальной таблицы, используя P3 в качестве целочисленного аргумента. Если метод сообщает об ошибке, к сообщению об ошибке добавляется в начало имя таблицы, а затем сообщение сохраняется в P2. Если ошибок не обнаружено, для регистра P2 устанавливается значение NULL.
VColumn Сохраняет в регистре P3 значение столбца с номером P2 текущей строки виртуальной таблицы курсора P1.

Если опкод VColumn используется для получения значения неизменяемого столбца во время операции UPDATE, значение P5 равно OPFLAG_NOCHNG. В результате функция sqlite3_vtab_nochange() вернёт true внутри метода xColumn реализации виртуальной таблицы. Столбец P5 также может содержать другие биты (OPFLAG_LENGTHARG или OPFLAG_TYPEOFARG), но опкод VColumn их не использует.

VCreate P2 — регистр, содержащий имя виртуальной таблицы в базе данных P1. Вызывает метод xCreate этой таблицы.
VDestroy P4 — имя виртуальной таблицы в базе данных P1. Вызывает метод xDestroy этой таблицы.
VFilter P1 — курсор, открытый с помощью VOpen. P2 — адрес, на который следует перейти, если отфильтрованный набор результатов пуст.

P4 имеет значение NULL или содержит строку, сформированную методом xBestIndex модуля. Интерпретация строки P4 определяется реализацией модуля.

Этот опкод вызывает метод xFilter виртуальной таблицы, указанной в P1. Целочисленный параметр плана запроса для xFilter хранится в регистре P3. В регистре P3+1 хранится параметр argc, передаваемый методу xFilter. Регистры P3+2..P3+1+argc содержат argc дополнительных параметров, передаваемых в xFilter как argv. При передаче в xFilter регистр P3+2 становится argv[0].

Если после фильтрации набор результатов окажется пустым, выполняется переход к P2.

VInitIn Устанавливает в регистре P2 указатель на объект ValueList для курсора P1 с регистром кэша P3 и выходным регистром P3+1. Этот объект ValueList можно использовать в качестве первого аргумента для sqlite3_vtab_in_first() и sqlite3_vtab_in_next(), чтобы извлечь все значения, хранящиеся в курсоре P1. Регистр P3 используется для хранения значений, возвращаемых sqlite3_vtab_in_first() и sqlite3_vtab_in_next().
VNext Перемещает виртуальную таблицу P1 к следующей строке набора результатов и выполняет переход к инструкции P2. Если виртуальная таблица достигла конца набора результатов, выполнение продолжается со следующей инструкции.
VOpen P4 — указатель на объект виртуальной таблицы, структуру sqlite3_vtab. P1 — номер курсора. Этот опкод открывает курсор виртуальной таблицы и сохраняет его в P1.
VRename P4 — указатель на объект виртуальной таблицы, структуру sqlite3_vtab. Этот опкод вызывает соответствующий метод xRename. Значение в регистре P1 передаётся методу xRename как аргумент zName.
VUpdate P4 — указатель на объект виртуальной таблицы, структуру sqlite3_vtab. Этот опкод вызывает соответствующий метод xUpdate. Для вызова xUpdate значения P2 передаются в смежных ячейках памяти, начиная с P3. Значение в регистре (P3+P2-1) соответствует элементу p2 массива argv, передаваемого в xUpdate.

Метод 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 и т. д.), применяемые при нарушении ограничения во время вставки или обновления.

Yield Меняет местами счётчик команд и значение в регистре P1. Это приводит к передаче управления сопрограмме.

Если сопрограмма, запущенная этой инструкцией, завершается с помощью Yield или Return, выполнение продолжается со следующей инструкции. Если же сопрограмма, запущенная этой инструкцией, завершается с помощью EndCoroutine, выполняется переход к P2, а не к следующей инструкции.

См. также: InitCoroutine

ZeroOrNull Если оба регистра P1 и P3 НЕ равны NULL, записывает ноль в регистр P2. Если один из регистров P1 или P3 равен NULL, записывает NULL в регистр P2.

Эта страница в последний раз обновлялась 2025-04-16 13:13:29Z

SQLite is in the Public Domain.
https://sqlite.org/opcode.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API