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 использует байткод" для ознакомления с причинами, по которым SQLite предпочитает использовать байткод для реализации SQL.

2. Введение

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

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

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

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

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

Исходный код механизма байткода находится в файле исходного кода vdbe.c. Определения операционных кодов (opcodes) в этом документе получены из комментариев в этом файле. Комментарии к исходному коду — канонический источник информации о механизме байткода. В случае сомнений обратитесь к исходному коду.

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

Помните, что имена и значения операционных кодов (opcodes) часто меняются от одной версии SQLite к другой. Поэтому, если вы изучаете вывод EXPLAIN от SQLite, вы должны обратиться к версии этого документа (или исходного кода vdbe.c), соответствующей версии SQLite, которая выполнила EXPLAIN. В противном случае описание операционных кодов может быть неточным. Этот документ основан на версии SQLite 3.47.0, введённой в 03a9703e27c44 21 октября 2024 года.

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

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

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

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

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

2.3. Регистры

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

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

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

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

Количество регистров в одном подготовленном утверждении фиксируется во время компиляции. Содержимое всех регистров очищается, когда подготовленное утверждение (prepared statement) сбрасывается или завершается.

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

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

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

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

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

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

4.Коды команд

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

Обратите внимание: Коды команд VDBE не являются частью определения интерфейса для SQLite. Количество кодов команд, их имена и значения могут изменяться от одной версии SQLite к другой. Коды команд, показанные в таблице ниже, действительны для версии SQLite 3.47.0, коммит 03a9703e27c44, от 2024-10-21.

Имя кода операции Описание
Abortable Проверить возможность отмены. Утвердить, если отмена в этом месте может привести к повреждению базы данных. Эта кодовая операция появляется только в отладочных сборках.

Отмена безопасна, если либо не было записей, либо есть активный журнал транзакций.

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 (ложь), то результат равен 0, даже если другой входной параметр NULL. NULL и истина или два NULL дают на выходе NULL.

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

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

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

Этот механизм работает, загружая NULL в регистр P2. Когда регистр адреса возврата содержит NULL, инструкция Return — это пустая операция, которая просто переходит к следующей инструкции (при условии, что у кодовой операции Return значение P3 равно 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, то создать блок нулевых байт длиной P1 в P2.
Cast Принудительно изменить тип значения в регистре P1 на тип, определённый P2.

  • P2=='A' → BLOB
  • P2=='B' → TEXT
  • P2=='C' → NUMERIC
  • P2=='D' → INTEGER
  • P2=='E' → REAL

Значение NULL не изменяется этим механизмом. Оно остаётся NULL.

Checkpoint Проверка контрольной точки базы данных P1. Это пустая операция, если P1 в данный момент не в режиме WAL. Параметр P2 — один из SQLITE_CHECKPOINT_PASSIVE, FULL, RESTART или TRUNCATE. Записать 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 инициализируется нулём этой инструкцией.

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

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 бита равны 1 для каждого из первых 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 Сохранить количество записей (целое значение) в таблице или индексе, открытом курсором P1, в регистр P2.

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

CreateBtree Выделить новое b-дерево в основном файле базы данных, если P1==0, или в файле TEMP базы данных, если P1==1, или в присоединённой базе данных, если P1>1. Аргумент P3 должен быть 1 (BTREE_INTKEY) для таблицы строк, 2 (BTREE_BLOBKEY) для индекса или таблицы без строк. Номер страницы корня нового b-дерева сохраняется в регистре P2.
CursorHint Предоставить подсказку курсору P1 о том, что ему нужно вернуть только строки, удовлетворяющие выражению в P4. Термины TK_REGISTER в выражении P4 относятся к значениям, которые в данный момент хранятся в регистрах. Термины TK_COLUMN в выражении P4 относятся к столбцам в b-дереве, к которому указывает курсор P1.
CursorLock Заблокировать b-дерево, к которому указывает курсор P1, так, чтобы к нему не мог получить доступ для записи другой курсор.
CursorUnlock Разблокировать b-дерево, к которому указывает курсор 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.

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

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

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

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

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

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

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

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. Перейти к параметру P2 этого Yield. После перехода регистр значений P1 остаётся со значением таким, что последующие OP_Yields возвращаются к этой инструкции EndCoroutine.

См. также: InitCoroutine

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

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

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

Если в P5 установлен SQLITE_NULLEQ, то результат сравнения всегда либо истинный, либо ложный, и никогда не является NULL. Если оба операнда равны NULL, то результат сравнения — истинный. Если один из операндов равен NULL, то результат — ложный. Если ни один из операндов не равен 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, которое может ускорить выполнение инструкции, но не повлияет на корректность операции.

Объяснение Это то же самое, что Noop во время выполнения обычного запроса. Цель данного кода операции — хранить информацию о плане запроса для вывода EXPLAIN QUERY PLAN.

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

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

Для элементов цикла for, P3 — это предполагаемый код каждого вызова данного элемента.

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

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

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

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

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

Счётчик внешних ключей Увеличить "счётчик ограничений" на P2 (P2 может быть положительным или отрицательным). Если P1 не равно нулю, счётчик ограничений базы данных увеличивается (отложенные ограничения внешнего ключа). В противном случае, если P1 равно нулю, увеличивается счётчик оператора (немедленные ограничения внешнего ключа).
FkЕслиНоль Данный код операции проверяет, равен ли счётчик ограничений внешнего ключа нулю. Если да, то перейти к инструкции P2. В противном случае продолжить выполнение следующей инструкции.

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

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

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

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

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

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

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

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

>= Это работает так же, как код операции Lt, за исключением того, что переход выполняется, если содержимое регистра P3 больше или равно содержимому регистра P1. Дополнительную информацию см. в коде операции Lt.
Получить подтип Извлечь значение подтипа из регистра P1 и записать этот подтип в регистр P2. Если у P1 нет подтипа, то P1 получает значение NULL.
Подпрограмма Записать текущий адрес в регистр P1 и перейти к адресу P2.
Переход Безусловный переход к адресу P2. Следующей выполняемой инструкцией будет инструкция по индексу P2 с начала программы.

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

> Это работает так же, как код операции Lt, за исключением того, что переход выполняется, если содержимое регистра P3 больше содержимого регистра P1. Дополнительную информацию см. в коде операции Lt.
Остановка Немедленно выйти. Все открытые курсоры и т.д. закрываются автоматически.

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

Если 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.

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

Если P5 не равно нулю, то выдаётся ошибка SQLITE_CORRUPT_INDEX, если соответствующая запись в индексе не найдена. Это происходит при выполнении операторов UPDATE или DELETE, когда запись в индексе, подлежащая обновлению или удалению, не найдена. Для некоторых применений IdxDelete (например, оператор EXCEPT) не имеет значения, найдена ли соответствующая запись. В этих случаях P5 равно нулю. Также не следует генерировать эту (самоисправляющую и некритическую) ошибку в режиме writable_schema.

Idx>= Значения регистров P4, начиная с P3, образуют распакованный индексный ключ, который опускает PRIMARY KEY. Сравнить это значение ключа с индексом, на который в данный момент указывает P1, игнорируя поля PRIMARY KEY или ROWID в конце.

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

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

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

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

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

Если в P5 установлен бит OPFLAG_APPEND, это подсказка для слоя B-дерева о том, что эта вставка, вероятно, является добавлением.

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

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

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

Idx<= Значения регистров P4, начиная с P3, образуют распакованный индексный ключ, который опускает PRIMARY KEY или ROWID. Сравнить это значение ключа с индексом, на который в данный момент указывает P1, игнорируя поля PRIMARY KEY или ROWID в индексе P1.

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

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

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

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

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

If Перейти к P2, если значение в регистре P1 истинно. Значение считается истинным, если оно числовое и ненулевое. Если значение в P1 равно NULL, то переход выполняется только в том случае, если P3 ненулевое.
IfNoHope Регистр P3 является первым из регистров P4, образующих распакованную запись. Курсор P1 — это индексный b-дерево. 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 установлен, то идентификатор строки сохраняется для последующего возврата функцией sqlite3_last_insert_rowid() (иначе он не изменяется).

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Логика обобщается следующим образом:

  • Если P3==0 и P4==0, то r[P2] := r[P1] 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-дереве является одним из типов, указанных в маске P5.

P1 обычно является курсором на b-дереве, для которого кеш декодирования строки действителен по крайней мере для столбца P3. Другими словами, должен был быть предыдущий Column для столбца P3 или больше. Если курсор недействителен, то этот код операции может давать ложные результаты. Если строка b-дерева содержит меньше, чем 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. Если переключение между различными режимами отката (удаление, усечение, сохранение, выключение и память), это простая операция. Ввод/вывод не требуется.

Если переключение происходит в режим 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.

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

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

После любого преобразования, и ни одно из значений не равно NULL, значения сравниваются. Если оба значения являются BLOB, то для определения результатов сравнения используется memcmp(). Если оба значения являются текстом, то для сравнения используется соответствующая функция сортировки, указанная в P4. Если P4 не указан, то для сравнения строковых значений используется memcmp(). Если оба значения являются числовыми, то используется числовое сравнение. Если два значения имеют разные типы, то числа считаются меньше строк, а строки считаются меньше 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 — это индекс правой таблицы, которая может быть обнулена.

* Если SQLITE_ENABLE_NULL_TRIM не указан, то P5 имеет значение OPFLAG_NOCHNG_MAGIC, если оператор MakeRecord может принимать записи без изменений с типом последовательности 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 для позиционирования курсора. Next не допускается после операторов SeekLT, SeekLE или Last.

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

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

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

См. также: Prev

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

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

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

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

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

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

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

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

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

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

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

Курсор P1 находится на индексном дереве btree. Если запись, идентифицируемая 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 не сравнивались как равные, даже если SQLITE_NULLEQ установлен для операторов Ne или Eq.

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

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

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

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

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

Предел смещения Эта инструкция выполняет часто используемое вычисление, связанное с обработкой 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].

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Разрешенные биты P5:

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

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

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

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

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

Разрешенные биты P5:

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

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

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

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

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

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

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

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

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

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

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

Первое целое число в массиве целых чисел P4 — это длина массива и не становится частью перестановки.

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

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

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

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

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

Программа Выполнить программу триггера, переданную как 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 — рекомендуемый размер кэша пейджера и так далее. P1==0 — основной файл базы данных, а P1==1 — файл базы данных, используемый для хранения временных таблиц.

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

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

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

ReleaseReg Освобождение регистров от обслуживания. Любое содержимое, которое было в регистрах, становится ненадежным после завершения этой операции.

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

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

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

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

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

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

Операция ReopenIdx может использоваться только при P5==0 или P5==OPFLAG_SEEKEQ и P4 является объектом P4_KEYINFO. Кроме того, значение 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» в командной строке отступит все операции от операции P2 до текущего Return (не включая). P2 должен быть первой операцией в подпрограмме, из которой возвращается эта операция. Таким образом, значение P2 — подсказка для отступа байткода. См. тег-20220407a в wherecode.c и shell.c.

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

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

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

RowCell P1 и P2 — открытые курсоры. Оба должны быть открыты на одном типе таблицы — intkey или индекс. Данная операция используется в рамках копирования текущей строки из P2 в P1. Если курсоры открыты на таблицах intkey, регистр P3 содержит идентификатор строки для использования с новой записью в 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. Содержимое регистра P2 аннулируется операциями, такими как Function, или любым использованием другого курсора, указывающего на ту же таблицу.

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

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

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

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

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

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

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

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

Эта инструкция создает неглубокую копию значения. Если значение является строкой или блобом, то копия является только указателем на оригинал, и, следовательно, если оригинал изменяется, то изменяется и копия. Хуже того, если оригинал удаляется, копия становится недействительной. Таким образом, программа должна гарантировать, что оригинал не изменится в течение срока действия копии. Используйте Copy для создания полной копии.

SeekEnd Поместить курсор P1 в конец b-дерева для добавления новой записи в b-дерево.

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

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

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

Если курсор P1 был открыт с флагом OPFLAG_SEEKEQ, то эта операция либо попадет на запись, которая точно совпадает с ключом, либо вызовет переход к P2. Когда курсор имеет флаг OPFLAG_SEEKEQ, эта операция должна быть после операцией IdxLE с теми же аргументами. Операция IdxGT будет пропущена, если эта операция выполнится успешно, но операция 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-early-out.

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

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

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

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

Если курсор P1 был открыт с флагом OPFLAG_SEEKEQ, то эта операция либо попадет на запись, которая точно совпадает с ключом, либо вызовет переход к P2. Когда курсор имеет флаг OPFLAG_SEEKEQ, эта операция должна быть после операцией IdxLE с теми же аргументами. Операция IdxGE будет пропущена, если эта операция выполнится успешно, но операция 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 – индекс курсора, открытого в SQL табличном b-дереве (с целочисленными ключами). Если регистр 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 – ложь (0), то происходит переход к SeekGE.P2. Если This.P5 – истина (ненулевое значение), то происходит переход к 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 в куку с номером P2 базы данных P1. P2==1 — версия схемы. P2==2 — формат базы данных. P2==3 — рекомендуемый размер кэша страниц, и так далее. P1==0 — основной файл базы данных, а P1==1 — файл базы данных, используемый для хранения временных таблиц.

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

Если P2 — это кука SCHEMA_VERSION (номер 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 в конце, которые игнорируются), то сравнение считается равным.

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

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

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

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

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

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

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

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

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

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

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

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

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

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), также может быть открыта транзакция запроса. Более точно, транзакция запроса открывается, если подключение к базе данных в настоящее время не находится в режиме автоматического подтверждения или если существуют другие активные запросы. Транзакция запроса позволяет отменить изменения, внесенные этим VDBE, после ошибки, не прибегая к отмене всей транзакции. Если ошибка не возникла, транзакция запроса автоматически подтвердится, когда VDBE остановится.

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

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

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

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

Предпосылки:

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

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

Vacuum Сделать вакуум всей базы данных P1. P1 равно 0 для «основной» и 2 или более для присоединённой базы данных. База данных «временных» таблиц не может быть вакуумирована.

Если 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. Регистр P3+2 становится argv[0] при передаче в xFilter.

Переход выполняется в 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 передаётся в качестве аргумента zName методу xRename.
VUpdate P4 — указатель на объект виртуальной таблицы, структура sqlite3_vtab. Этот оператор вызывает соответствующий метод xUpdate. Значения P2 — смежные ячейки памяти, начинающиеся с P3, для передачи вызову xUpdate. Значение в регистре (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, то в регистр P2 записывается NULL.

Последнее изменение этой страницы: 03.05.2024 13:40:22 UTC

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

Spec-Zone.ru

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