![]() |
|
|||
WebMoney: WMZ Z294115950220 WMR R409981405661 WME E134003968233 |
Visa 4274 3200 2453 6495 |
Виртуальная таблица это объект, который зарегистрирован в открытом
соединении с базой данных SQLite.
С точки зрения SQL-оператора виртуальный объект таблицы похож на любую другую
таблицу или представление. Но негласно, запросы и обновления на виртуальной
таблице зывают методы отзыва виртуального объекта таблицы вместо того, чтобы
читать и писать файл базы данных. Виртуальный механизм таблицы позволяет
издать интерфейсы, которые доступны от SQL-операторов, как будто они были
таблицами. SQL-операторы могут сделать с виртуальной таблицей почти все,
что с реальной за следующими исключениями: Отдельные виртуальные внедрения таблицы могли бы наложить дополнительные
ограничения. Например, некоторые виртуальные внедрения могли бы обеспечить
таблицы только для чтения. Или некоторые виртуальные внедрения таблицы могли
бы позволить INSERT или
DELETE, но не
UPDATE.
Или некоторые виртуальные внедрения таблицы могли бы ограничить виды UPDATE,
которые могут быть сделаны. Виртуальная таблица могла бы представлять структуры в данных оперативной
памяти. Или это могло бы представлять представление о данных на диске,
которые не находится в формате SQLite. Или применение могло бы вычислить
содержание виртуальной таблицы по требованию. Вот некоторое существующее и постулируемое использование
для виртуальных таблиц: См. здесь
для более длинного списка фактических виртуальных внедрений таблицы. Виртуальная таблица составлена, используя
CREATE VIRTUAL TABLE.
CREATE VIRTUAL TABLE составляет новую таблицу, названную
table-name , полученную из
module-name.
Здесь module-name это
имя, которое зарегистрировано для виртуальной таблицы через
sqlite3_create_module(). Можно также обеспечить отделенные
запятой аргументы модулю после имени модуля: Формат аргументов модуля очень общий. Каждый
module-argument
может содержать ключевые слова, строковые литералы, идентификаторы, числа и
пунктуацию. Каждый module-argument передан
как написано (как текст) в
метод constructor виртуального внедрения
таблицы, когда виртуальная таблица составлена, и тот конструктор ответственен
за парсинг и интерпретацию аргументов. Синтаксис аргумента достаточно общий,
так что виртуальное внедрение таблицы, если это хочет, может интерпретировать
свои аргументы как определения
столбца в обычном запросе CREATE TABLE
. Внедрение могло также наложить некоторую другую
интерпретацию на аргументы. Как только виртуальная таблица была составлена, она может использоваться
как любая другая за исключениями, отмеченными выше, и наложенными
определенными виртуальными внедрениями таблицы.
Виртуальная таблица ликвидируется, используя обычный синтаксис
DROP TABLE. Нет команды "CREATE TEMP VIRTUAL TABLE".
Чтобы составить временную виртуальную таблицу, добавьте схему "temp"
перед именем таблицы. Некоторые виртуальные таблицы существуют автоматически в схеме "main"
каждого соединения с базой данных, в котором их модуль зарегистрирован, даже
без CREATE VIRTUAL TABLE.
Такие виртуальные таблицы называют "одноименными виртуальными
таблицами". Чтобы использовать одноименную виртуальную таблицу,
просто используйте имя модуля, как будто это была таблица.
Одноименные виртуальные таблицы существуют только в схеме "main",
таким образом, они не будут работать, если указано другое имя схемы. Пример одноименной виртуальной таблицы это таблица
dbstat. Чтобы использовать dbstat
в качестве одноименной виртуальной таблицы, просто запросите имя модуля
"dbstat", как будто это была обычная таблица (обратите внимание на то, что
SQLite должен быть собран с выбором
SQLITE_ENABLE_DBSTAT_VTAB,
чтобы включать dbstat). Виртуальная таблица одноименна, если метод
xCreate это та же самая функция, как
метод xConnect или если метод
xCreate = NULL. Метод
xCreate вызывают, когда виртуальная
таблица сначала составлена, используя
CREATE VIRTUAL TABLE.
Метод xConnect
вызван каждый раз, когда соединение с базой данных создано или
повторно разбирают схему. Когда эти два метода то же самое, это
указывает, что у виртуальной таблицы нет постоянного состояния, которое
должно быть создано и разрушено.
Если метод xCreate = NULL,
CREATE VIRTUAL TABLE запрещаются для той
виртуальной таблицы и виртуальные таблицы являются
"одноименно-единственными". Одноименно-единственные виртуальные
таблицы полезны как табличные функции. Обратите внимание на то, что до version
3.9.0 (2015-10-14) SQLite не проверял xCreate метод на NULL прежде, чем
вызвать его. Таким образом, если одноименно-единственная виртуальная таблица
зарегистрирована в SQLite
version 3.8.11.1 (2015-07-29) или ранее и
CREATE VIRTUAL TABLE
предпринята для того виртуального модуля таблицы, произойдет переход на
NULL, приводя к сбою. Несколько новых объектов C-уровня используются
виртуальным внедрением таблицы: Структура sqlite3_module
определяет объект модуля, используемый, чтобы осуществить виртуальную
таблицу. Думайте о модуле как о классе, из которого можно построить
многократные виртуальные таблицы, имеющие подобные свойства.
Например, можно было бы иметь модуль, который обеспечивает доступ только
для чтения к файлам comma-separated-value (CSV). Тот модуль может тогда
использоваться, чтобы составить несколько виртуальных таблиц, где каждая
виртуальная таблица обращается к различному файлу CSV. Структура модуля содержит методы, которые вызваны SQLite, чтобы выполнить
различные действия на виртуальной таблице, такие как создание новых копий
или разрушение старых, чтения и написания данных, поиска и удаления,
обновления или вставки строк. Структура модуля объяснена
более подробно ниже. Каждый виртуальный экземпляр таблицы представляется структурой
sqlite3_vtab. Структура sqlite3_vtab
похожа на это: Виртуальные внедрения таблицы будут обычно подклассифицировать эту
структуру, чтобы добавить дополнительные частные и определенные для внедрения
области. nRef используется внутренне ядром SQLite и не должна быть изменена
виртуальным внедрением таблицы. Виртуальное внедрение таблицы может передать
текст сообщения об ошибке ядру, поместив последовательность сообщения об
ошибке в zErrMsg. Пространство, чтобы содержать эту последовательность
сообщения об ошибке, должно быть получено из функции выделения памяти SQLite,
такой как sqlite3_mprintf() или
sqlite3_malloc().
До назначения нового значения zErrMsg виртуальное внедрение таблицы должно
освободить любое существующее ранее содержание zErrMsg, используя
sqlite3_free().
Отказ сделать это приведет к утечке памяти. Ядро SQLite освободит и обнулит
содержание zErrMsg, когда это поставит текст сообщения об ошибке клиентскому
приложению или когда это разрушит таблицу. Виртуальное внедрение таблицы
должно волноваться об освобождении содержания zErrMsg, только когда это
переписывает содержание новым сообщением об ошибке. Структура sqlite3_vtab_cursor
представляет указатель на определенную строку таблицы.
Это то, на что похожа sqlite3_vtab_cursor: Еще раз, практические внедрения, вероятно, подклассифицируют эту
структуру, чтобы добавить дополнительные частные области. sqlite3_index_info
используется, чтобы передать информацию в и из метода xBestIndex
модуля, который осуществляет таблицу. Перед выполнением CREATE VIRTUAL TABLE
модуль, определенный в том запросе, должен быть зарегистрирован в соединении
с базой данных. Это достигается, используя любой из
sqlite3_create_module() или
sqlite3_create_module_v2(): sqlite3_create_module() и
sqlite3_create_module_v2()
связывает имя модуля со структурой
sqlite3_module
и отдельными данными клиента, которые являются определенными для каждого
модуля. Единственная разница между двумя методами create_module в том, что
_v2-метод включает дополнительный параметр, который определяет деструктор
для указателя данных клиента. Структура модуля определяет поведение
виртуальной таблицы. Структура модуля похожа на это: Структура модуля определяет все методы для каждого виртуального объекта
таблицы. Структура модуля также содержит поле iVersion, которое определяет
конкретный выпуск структуры таблицы модуля. В настоящее время iVersion всегда
равняется 4 или меньше, но в будущих выпусках SQLite определение структуры
модуля могло бы быть расширено с дополнительными методами, и в этом случае
максимум значения iVersion будет увеличен. Остальная часть структуры модуля состоит из методов, используемых, чтобы
реализовать различные опции виртуальной таблицы. Подробная информация о том,
что делает каждый из этих методов, предоставлена в продолжении. До SQLite version 3.6.17
(2009-08-10) виртуальный механизм таблицы предполагает, что каждое
соединение с базой данных содержит свою
собственную копию схемы базы данных. Следовательно, виртуальный механизм
таблицы не мог использоваться в базе данных, которая использует
режим общего кэширования.
sqlite3_create_module()
возвратил бы ошибку, если
режим общего кэширования включен.
Это ограничение было ослаблено в SQLite
version 3.6.17.
Выполните эти шаги, чтобы составить вашу
собственную виртуальную таблицу: Единственная действительно сложная часть это шаг 1. Вы могли бы хотеть
начать с существующего виртуального внедрения таблицы и изменить его, чтобы
удовлетворить вашим потребностям.
Исходное дерево SQLite содержит много виртуальных внедрений таблицы,
которые подходят для копирования, включая: Есть много других виртуальных внедрений таблицы
в исходном дереве SQLite, которые могут использоваться в качестве
примеров. Определите местонахождение этих других виртуальных внедрений
таблицы, ища "sqlite3_create_module". Вы могли бы также хотеть осуществить свой новую виртуальную таблицу как
загружаемое расширение. Метод xCreate вызывают, чтобы создать новый экземпляр виртуальной таблицы
в ответ на CREATE VIRTUAL TABLE. Если
метод xCreate тот же самый указатель, как метод
xConnect, виртуальная таблица это
одноименная виртуальная таблица.
Если метод xCreate опущен (если это NULL), виртуальная таблица это
одноименно-единственная виртуальная
таблица. db это указатель на SQLite
соединение с базой данных, которое выполняет
CREATE VIRTUAL TABLE.
pAux это копия указателя данных клиента, который был четвертым аргументом
sqlite3_create_module() или
sqlite3_create_module_v2(),
который зарегистрировал виртуальный модуль
таблицы. argv это множество argc указателей на законченные null
последовательности. Первая последовательность, argv[0], является названием
вызываемого модуля. Имя модуля это имя, обеспеченное как второй аргумент
sqlite3_create_module()
и как аргумент пункта USING в CREATE VIRTUAL
TABLE. Второй, argv[1], название базы данных, в которой составляется
новая виртуальная таблица. Имя базы данных "main"
для основной базы данных, "temp" для БД TEMP или имя, данное в
команде ATTACH.
Третий элемент множества, argv[2], является названием новой виртуальной
таблицы, как определено после ключевого слова TABLE в
CREATE VIRTUAL TABLE.
Если существуют, четвертая и последующие последовательности в множестве
argv[] сообщают об аргументах модуля в
CREATE VIRTUAL TABLE. Работа по этому методу состоит в том, чтобы построить новый виртуальный
объект таблицы (объект sqlite3_vtab)
и возвратить указатель на него в *ppVTab. Как часть задачи создания новой структуры
sqlite3_vtab, этот метод ДОЛЖЕН вызвать
sqlite3_declare_vtab(),
чтобы сказать ядру SQLite о колонках и типах данных в виртуальной таблице.
sqlite3_declare_vtab() API
имеет следующий прототип: Первым аргументом
sqlite3_declare_vtab()
должен быть тот же самый указатель
соединения с базой данных как первый
параметр к этому методу. Второй аргумент
sqlite3_declare_vtab() должен быть законченной нолем строкой UTF-8,
которая содержит правильно построенный запрос
CREATE TABLE,
который определяет колонки в виртуальной таблице и их типы данных.
Название таблицы в этом CREATE TABLE проигнорировано, как все ограничения.
Только имена столбцов и типы данных важны. Строка CREATE TABLE
не должна быть проведена в постоянной памяти. Последовательность может быть
освобождена и/или снова использована, как только вернется
sqlite3_declare_vtab(). Метод xConnect может также произвольно вызвать специальные функции для
виртуальной таблицы, сделав одно или несколько обращений к
sqlite3_vtab_config(): Вызов sqlite3_vtab_config() опционален.
Но для максимальной безопасности, рекомендуется, чтобы виртуальные внедрения
таблицы вызвали "sqlite3_vtab_config(db,
SQLITE_VTAB_DIRECTONLY)", если виртуальная таблица не будет
использоваться изнутри триггеров или обзоров. Метод xCreate не должен инициализировать поля pModule, nRef и zErrMsg
объекта sqlite3_vtab.
Ядро SQLite будет заботиться об этом. xCreate должен возвратить SQLITE_OK,
если это успешно в составлении новой виртуальной таблицы или
SQLITE_ERROR,
если это не успешно. Если не успешно, структура
sqlite3_vtab
не должна быть ассигнована. Сообщение об ошибке может произвольно быть
возвращено в *pzErr. Место, чтобы содержать последовательность сообщения об
ошибке должно быть выделено, используя функцию выделения памяти SQLite
sqlite3_malloc() или
sqlite3_mprintf(), поскольку ядро SQLite
попытается освободить пространство, используя
sqlite3_free()
после того, как об ошибке сообщили. Если метод xCreate = NULL, виртуальная таблица это
одноименно-единственный виртуальная таблица
. Новые экземпляры виртуальной таблицы не могут быть созданы, используя
CREATE VIRTUAL TABLE
и виртуальная таблица может использоваться только через имя модуля.
Обратите внимание на то, что версии SQLite до 3.9.0 (2015-10-14) не понимают
одноименно-единственные виртуальные таблицы, и будет segfault, если будет
предпринята попытка CREATE VIRTUAL TABLE
на одноименно-единственном виртуальной таблице, потому что метод xCreate
не был проверен на пустой указатель. Если метод xCreate это тот же самый указатель, как
xConnect,
это указывает, что виртуальная таблица не должна инициализировать
запоминающее устройство. Такая виртуальная таблица может использоваться в
качестве одноименной виртуальной таблицы, в
качестве названной виртуальной таблицы, используя
CREATE VIRTUAL TABLE, или обеих.
Если тип данных колонки содержит специальное ключевое слово "HIDDEN"
(в какой-либо комбинации прописных и строчных букв), ключевое слово опущено
от имени типа данных колонки, а колонка отмечена как скрытый столбец
внутренне. Скрытый столбец отличается от нормальной
колонки в трех отношениях: Например, если следующий SQL передается к
sqlite3_declare_vtab(): виртуальная таблица была бы составлена с двумя скрытыми столбцами, и с
типами данных "VARCHAR(12)" и "INTEGER". Использование в качестве примера скрытых столбцов может быть замечено в
виртуальном внедрении таблицы FTS3,
где каждая виртуальная таблица FTS содержит
скрытый столбец FTS,
который используется, чтобы передать информацию от виртуальной таблицы в
вспомогательные функции FTS и оператор
FTS MATCH.
Виртуальная таблица, которая содержит
скрытые столбцы, может использоваться как
табличная функция в пункте FROM в SELECT.
Аргументы табличной функции становятся ограничениями на скрытые
столбцы виртуальной таблицы. Например, расширение "generate_series" (находится в файле
ext/misc/series.c
в исходном дереве)
реализует одноименную виртуальную таблицу
со следующей схемой: Метод sqlite3_module.xBestIndex
во внедрении этой таблицы проверяет на ограничения равенства против
скрытых столбцов и использует те как входные параметры, чтобы определить
диапазон вывода integer "value", чтобы произвести. Разумные умолчания
используются для любых неограниченных столбцов.
Например, чтобы перечислить все целые числа между 5 и 50: Предыдущий запрос эквивалентен следующему:
Аргументы на виртуальном имени таблицы соответствуют
скрытым столбцам.
Количество аргументов может быть меньше, чем количество скрытых столбцов, в
этом случае последние скрытые столбцы не ограничены.
Однако, будет ошибка, если есть больше аргументов, чем в виртуальной
таблице есть скрытых столбцов.
С SQLite version 3.14.0
(2016-08-08) CREATE TABLE, который передается в
sqlite3_declare_vtab(), может содержать
WITHOUT ROWID.
Это полезно для случаев, где виртуальные строки таблицы не могут легко быть
отображены в уникальные целые числа. CREATE TABLE, который включает WITHOUT
ROWID, должен определить одну или более колонок как PRIMARY KEY.
Каждая колонка PRIMARY KEY должна индивидуально быть NOT NULL, и все колонки
для каждой строки должны быть коллективно уникальными. Обратите внимание на то, что SQLite не проводит в жизнь PRIMARY KEY для
виртуальной таблицы WITHOUT ROWID. Осуществление это ответственность
основного виртуального внедрения таблицы. Но SQLite предполагает, что
ограничение PRIMARY KEY действительно, что определенные колонки действительно
UNIQUE и NOT NULL и использует это предположение, чтобы оптимизировать
запросы для виртуальной таблицы. rowid недоступна на виртуальной таблице WITHOUT ROWID (конечно). Метод xUpdate
был первоначально разработан вокруг наличия
ROWID
как единственное значение. Метод xUpdate
был расширен, чтобы приспособить произвольный PRIMARY KEY вместо ROWID, но
PRIMARY KEY должен все еще быть только одной колонкой.
Поэтому SQLite отклонит любую таблицу WITHOUT ROWID, у которой есть больше,
чем одна колонка PRIMARY KEY и не-NULL метод xUpdate.
Метод xConnect очень похож на
xCreate. Он имеет те же самые параметры и
строит новую структуру
sqlite3_vtab подобно xCreate.
И это должно также вызвать
sqlite3_declare_vtab(), как xCreate.
Это должно также сделать все те же самые вызовы
sqlite3_vtab_config(), как xCreate. Различие в том, что xConnect вызывают, чтобы установить новую связь с
существующей виртуальной таблицей, тогда как xCreate, чтобы составить новую
виртуальную таблицу с нуля. xCreate и xConnect отличаются, когда у виртуальной таблицы есть некоторое
запоминающее устройство, которое должно быть инициализировано в первый раз,
когда виртуальная таблица составлена. xCreate создает и инициализирует
запоминающее устройство. xConnect просто соединяется с существующим
запоминающим устройством. Когда xCreate и xConnect то же самое, таблица это
одноименная виртуальная таблица. Как пример, рассмотрите виртуальное внедрение таблицы, которое
обеспечивает доступ только для чтения к существующим файлам
comma-separated-value (CSV) на диске. Нет никакого запоминающего устройства,
которое должно быть создано или инициализировано для такого виртуальной
таблицы (так как файлы CSV уже существуют на диске), так что xCreate и
xConnect будут идентичны для этого модуля. Другой пример: виртуальная таблица, который осуществляет полнотекстовый
индекс. xCreate должен создать и инициализировать структуры данных, чтобы
содержать словарь и отправляющие списки для того индекса.
xConnect, с другой стороны, должен только определить местонахождение и
использовать существующий словарь и списки, которые были созданы
предшествующим вызовом xCreate. xConnect должен вернуть SQLITE_OK,
если это успешно в составлении новой виртуальной таблицы, или
SQLITE_ERROR иначе.
Если неуспешно, структура sqlite3_vtab
не должна быть ассигнована. Сообщение об ошибке может произвольно быть
возвращено в *pzErr, если была неудача. Место, чтобы содержать
последовательность сообщения об ошибке должно быть выделено, используя
функцию выделения памяти SQLite
sqlite3_malloc() или
sqlite3_mprintf(), поскольку ядро SQLite
попытается освободить пространство, используя
sqlite3_free()
после того, как об ошибке сообщили. xConnect требуется для каждого виртуального внедрения таблицы, хотя
указатели xCreate и xConnect объекта
sqlite3_module
могут указать на ту же самую функцию, если
виртуальная таблица не должна инициализировать запоминающее устройство.
SQLite применяет xBestIndex виртуального модуля таблицы, чтобы определить
лучший способ получить доступ к виртуальной таблице.
У метода xBestIndex есть такой прототип: Ядро SQLite общается с xBestIndex, заполняя определенные области
структуры sqlite3_index_info
и передавая указатель на ту структуру в xBestIndex как второй параметр.
Метод xBestIndex заполняет другие области этой структуры,
которая формирует ответ. Структура
sqlite3_index_info похожа на это: Отметьте предупреждения на "estimatedRows", "idxFlags" и colUsed.
Эти области были добавлены с версий 3.8.2, 3.9.0 и 3.10.0, соответственно.
Любое расширение, которое читает или пишет эти области, должно сначала
проверить, что версия библиотеки SQLite в использовании больше или равна
соответствующей версии, возможно, сравнение значения, возвращенные из
sqlite3_libversion_number(), с
константами 3008002, 3009000 и/или 3010000.
Результат попытки получить доступ к этим областям в структуре
sqlite3_index_info, созданной более старой версией SQLite, не определен. Кроме того, есть некоторые определенные константы: Используйте
sqlite3_vtab_collation(), чтобы найти название
последовательности сопоставления,
которая должна использоваться, оценивая i-е ограничение: Ядро SQLite вызывает xBestIndex, когда это собирает запрос, который
включает виртуальную таблицу. Другими словами, SQLite вызывает этот метод,
когда это управляет sqlite3_prepare()
или эквивалент. Вызывая этот метод, ядро SQLite говорит виртуальной таблице,
что должно получить доступ к некоторому подмножеству строк в виртуальной
таблице, и хочет знать самый эффективный способ сделать это.
xBestIndex отвечает информацией, что именно ядро SQLite может использовать,
чтобы провести эффективный поиск в виртуальной таблице. Собирая единственный SQL-запрос, ядро SQLite могло бы вызвать
xBestIndex неоднократно с различными параметрами настройки в
sqlite3_index_info.
Ядро SQLite тогда выберет комбинацию, которая, кажется,
дает лучшую производительность. Прежде, чем вызвать этот метод, ядро SQLite инициализирует экземпляр
структуры sqlite3_index_info
с информацией о запросе, который это в настоящее время пытается обработать.
Эта информация происходит, главным образом, из оператора Where и пунктов
ORDER BY или GROUP BY запроса, но также и от любого пункта ON или USING,
если запрос это соединение. Информация, которую ядро SQLite предоставляет
методу xBestIndex, содержится в части структуры, которая отмечена как
"Inputs". Секция "Outputs" инициализируется к нолю. p>Информация в структуре
sqlite3_index_info эфемерна и может быть переписана или освобождена,
как только метод xBestIndex возвращается. Если xBestIndex должен помнить
какую-либо часть структуры
sqlite3_index_info, это должно сделать
копию. Важно сохранить копию в месте, где это будет освобождено, например, в
области idxStr с needToFreeIdxStr = 1. Обратите внимание на то, что xBestIndex будут всегда вызывать прежде
xFilter,
так как выводы idxNum и idxStr из xBestIndex требуют вход в xFilter.
Однако, нет никакой гарантии, что xFilter вызовут
после успешного xBestIndex. Метод xBestIndex требуется для каждого виртуального внедрения таблицы. Главным, что ядро SQLite пытается сообщить виртуальной таблице, являются
ограничения, которые доступны, чтобы ограничить количество строк, которые
должны быть просмотрены. Массив aConstraint[] содержит один вход для каждого
ограничения. Будет точно nConstraint записей в этом множестве. Каждое ограничение будет обычно соответствовать термину в операторе Where,
в пункте USING или ON, который имеет форму: Здесь "column" это колонка в виртуальной таблице, OP оператор вроде
"=" или "<", EXPR произвольное выражение. Так, например, если оператор
Where содержал такой термин: Тогда одно из ограничений было бы на колонке "a" с оператором
"=" и выражение "5". У ограничений не должно быть буквального
представления оператора Where. Оптимизатор запросов мог бы сделать
преобразования к оператору Where, чтобы извлечь столько ограничений, сколько
сможет. Так, например, если оператор Where содержал что-то вроде этого: Оптимизатор запросов мог бы перевести это в три отдельных ограничения: Для каждого такого ограничения поле aConstraint[].iColumn
указывает, какая колонка появляется на левой стороне ограничения.
Первая колонка виртуальной таблицы это колонка 0. rowid виртуальной таблицы
это колонка -1. Поле aConstraint[].op указывает, какой оператор используется.
Константы SQLITE_INDEX_CONSTRAINT_* отображают константы целого числа в
значения оператора. Колонки происходят в порядке, в котором они были
определены в вызове
sqlite3_declare_vtab() в методе xCreate
или xConnect.
Скрытые столбцы посчитаны, определяя индекс столбца. Если метод xFindFunction()
для виртуальной таблицы определяется, и если xFindFunction() иногда
возвращает
SQLITE_INDEX_CONSTRAINT_FUNCTION
или больше, то ограничения могли бы также иметь форму: В этом случае значение aConstraint[].op
совпадает со значениею, возвращенным
xFindFunction() для FUNCTION. Массив aConstraint[] содержит информацию обо всех ограничениях, которые
относятся к виртуальной таблице. Но некоторые ограничения не могли бы быть
применимыми из-за способа, которым таблицы упорядочены в соединении.
xBestIndex должен поэтому рассмотреть только ограничения, у которых есть
флаг aConstraint[].usable = true. В дополнение к ограничениям оператора Where ядро SQLite также говорит
методу xBestIndex о пункте ORDER BY. В агрегатном запросе ядро SQLite могло
бы вставить информацию о пункте GROUP BY вместо информации о пункте ORDER
BY, но этот факт не должен иметь никакого значения для метода xBestIndex.
Если все условия пункта ORDER BY будут колонками в виртуальной таблице, то
nOrderBy будет количеством условий в пункте ORDER BY и массив aOrderBy[]
определит колонку для каждого термина в порядке пункта и является ли та
колонка ASC или DESC.
В SQLite version 3.10.0 (2016-01-06)
и позже есть поле colUsed, чтобы указать, какие области виртуальной таблицы
на самом деле используются подготовленным запросом.
Если младший бит colUsed установлен, это означает, что первая колонка
используется. Второй бит соответствует второй колонке. И т. д.
Если старший бит colUsed установлен, это означает, что используются одна или
более колонок кроме первых 63 колонок. Если информация об использовании
колонки необходима методу xFilter,
то необходимые биты должны быть закодированы в выводе поля
idxNum или idxStr. Для операторов LIKE, GLOB, REGEXP и MATCH значение aConstraint[].iColumn
является виртуальным столбцом таблицы, который является левым операндом
оператора. Однако, если эти операторы выражаются как вызовы функции вместо
операторов, то значение aConstraint[].iColumn ссылается на столбец
виртуальной таблицы, который является вторым аргументом той функции: Следовательно, до вызова метода xBestIndex()
следующие две формы эквивалентны: Это специальное поведение рассмотрения второго аргумента функции
происходит только для функций LIKE, GLOB, REGEXP и MATCH. Для всех других
функций значение aConstraint[].iColumn ссылается на
первый аргумент функции. Эта специальная функция LIKE, GLOB, REGEXP и MATCH не относится
к методу xFindFunction().
xFindFunction()
всегда выключает левый операнд операторов LIKE, GLOB, REGEXP или MATCH. Когда aConstraint[].op = SQLITE_INDEX_CONSTRAINT_LIMIT или
SQLITE_INDEX_CONSTRAINT_OFFSET, это
указывает, что есть пункт LIMIT или OFFSET в запросе SQL, который использует
виртуальную таблица. У операторов LIMIT и OFFSET нет левого операнда, поэтому
когда aConstraint[].op = SQLITE_INDEX_CONSTRAINT_LIMIT или
SQLITE_INDEX_CONSTRAINT_OFFSET, значение
aConstraint[].iColumn бессмысленно и не должно использоваться. sqlite3_vtab_rhs_value()
может использоваться, чтобы попытаться получить доступ к правому операнду
ограничения. Однако, значение правого оператора не могло быть известно в то
время, когда работает метод xBestIndex, таким образом,
sqlite3_vtab_rhs_value() не мог бы быть успешным. Обычно правый операнд
ограничения доступен только xBestIndex, если это закодировано как литеральное
значение во входе SQL. Если правильный операнд будет закодирован как
выражение или параметр хоста,
это, вероятно, не будет доступно для xBestIndex. У некоторых операторов,
таких как
SQLITE_INDEX_CONSTRAINT_ISNULL и
SQLITE_INDEX_CONSTRAINT_ISNOTNULL, нет правого операнда.
sqlite3_vtab_rhs_value() для них всегда вернет
SQLITE_NOTFOUND. Учитывая всю информацию выше, работа с методом xBestIndex
нужна, чтобы выяснить лучший способ искать в виртуальной таблице. Метод xBestIndex передает стратегию индексации
xFilter через idxNum и idxStr.
Значение idxNum и содержание строки idxStr произвольны, насколько ядро SQLite
затронуто и могут иметь любое значение.
Ядро SQLite просто копирует информацию от xBestIndex в
xFilter, предполагая только, что
последовательность работы, на которую ссылаются через
idxStr, закончена NUL. Значение idxStr может быть последовательностью, полученной из функции
выделения памяти SQLite, такой как
sqlite3_mprintf(). Если это верно, тогда флаг needToFreeIdxStr
должен быть установлен в true так, чтобы ядро SQLite знало, что надо вызвать
sqlite3_free()
на той последовательности, когда это закончит с ней, и таким образом избегает
утечки памяти. Значение idxStr может также быть статической постоянной
строкой, в этом случае needToFreeIdxStr должен быть false. Поле estimatedCost должно быть установлено в предполагаемое количество
операций по доступу к диску, требуемых, чтобы выполнить этот запрос для
виртуальной таблицы. Ядро SQLite будет часто вызывать xBestIndex многократно
с различными ограничениями, получать многократные сметы, затем выбирать план
запросов, который дает самую низкую оценку. Ядро SQLite инициализирует
estimatedCost к очень большому значению до вызова xBestIndex, поэтому если
xBestIndex решает, что текущая комбинация параметров нежелательна, это может
оставить estimatedCost без изменений, чтобы
препятствовать ее использованию. Если текущая версия SQLite 3.8.2 или больше, estimatedRows
может быть установлена в оценку количества строк, возвращенных предложенным
планом запросов. Если это значение явно не установлено, используется оценка
по умолчанию 25 строк. Если текущая версия SQLite 3.9.0 или больше, idxFlags
может указать в SQLITE_INDEX_SCAN_UNIQUE, что виртуальная таблица возвратит
только ноль или одну строки, данную входными ограничениями.
Дополнительные биты idxFlags могли бы быть использованы в
более поздних версиях SQLite. Массив aConstraintUsage[] содержит один элемент для каждого из
ограничений nConstraint во входном разделе структуры
sqlite3_index_info.
aConstraintUsage[] применяется xBestIndex, чтобы сказать ядро, как
это использует ограничения. xBestIndex может установить записи aConstraintUsage[].argvIndex
в значения, больше, чем ноль. Точно один вход должен быть установлен в 1,
другой к 2, третий 3 и т. д., столько, как метод xBestIndex хочет.
EXPR соответствующих ограничений будет тогда передан как параметры
argv[] в xFilter. Например, если aConstraint[3].argvIndex = 1,
то, когда xFilter вызывают, argv[0], переданный xFilter,
будет иметь значение EXPR ограничения aConstraint[3]. По умолчанию SQLite производит bytecode,
который будет проверять все ограничения дважды на каждую строку
виртуальной таблицы, чтобы проверить, что они удовлетворены.
Если виртуальная таблица может гарантировать, что ограничение будет всегда
удовлетворяться, это может попытаться подавить ту перепроверку, установив
aConstraintUsage[].omit. Однако, за некоторыми исключениями, это только намек
и нет никакой гарантии, что избыточная проверка ограничения будет
подавлена. Ключевые пункты: Флаг omit соблюдают только, если значение argvIndex для
ограничения больше 0 и меньше или равно 16.
Ограничительная проверка никогда не подавляется для ограничений, которые
не передают их правый операнд в метод xFilter.
Текущее внедрение в состоянии подавить избыточную ограничительную проверку
только первых 16 значений, переданных xFilter,
хотя это ограничение могло бы быть увеличено в будущих выпусках. Флаг omit всегда соблюдают для ограничений
SQLITE_INDEX_CONSTRAINT_OFFSET
пока argvIndex больше 0. Урегулирование флага omit на ограничении
SQLITE_INDEX_CONSTRAINT_OFFSET указывает SQLite, что виртуальная таблица
самостоятельно подавит первые N строк вывода, где N это
правый операнд оператора OFFSET. Если реализация установит omit на
ограничении SQLITE_INDEX_CONSTRAINT_OFFSET, но не подавляет первые N строк
вывода, неправильный ответ будет следовать из полного запроса. Если виртуальная таблица произведет строки в порядке, определенном пунктом
ORDER BY, то флаг orderByConsumed может быть установлен в true.
Если вывод не автоматически в правильном порядке, тогда orderByConsumed
должен быть оставлен в значение по умолчанию false.
Это укажет ядру SQLite, что оно должно будет сделать отдельную сортировку
после того, как оно выходит из виртуальной таблицы.
Урегулирование orderByConsumed является оптимизацией.
Запрос будет всегда получать правильный ответ, если orderByConsumed оставят в
его значении по умолчанию (0). Ненужных операций по сортировке
можно было бы избежать, приведя к более быстрому запросу, если
orderByConsumed установлен, но неправильная установка orderByConsumed может
привести к неправильному ответу.
Предложено, чтобы новые виртуальные внедрения таблицы оставили
значение orderByConsumed первоначальным, а затем после того, как все
остальное, как известно, работает правильно, вернулись и попытались
оптимизировать, установив orderByConsumed в соответствующих случаях. Иногда флаг orderByConsumed может быть безопасно установлен, даже если
вывод виртуальной таблицы не находится строго в порядке, определенном
nOrderBy и aOrderBy. Если
sqlite3_vtab_distinct() вернет
1 или 2, это указывает, что порядок может быть смягчен.
См. документацию относительно
sqlite3_vtab_distinct(). xBestIndex должен возвратить SQLITE_OK на успехе. Если какой-либо вид
фатальной ошибки происходит, соответствующий код ошибки (например,
SQLITE_NOMEM)
должен быть возвращен вместо этого. Если xBestIndex вернет
SQLITE_CONSTRAINT, это не указывает на ошибку. Скорее SQLITE_CONSTRAINT
указывает, что конкретная комбинация входных определенных параметров
недостаточна для виртуальной таблицы, чтобы выполнить ее работу.
Это логически то же самое, как урегулирование estimatedCost к бесконечности.
Если каждое обращение к xBestIndex для конкретного плана запросов возвратит
SQLITE_CONSTRAINT, это означает, что нет никакого пути к виртуальной
таблице, который будет безопасно использоваться, и
sqlite3_prepare()
не потерпит неудачу с ошибкой "no query solution". Возврат SQLITE_CONSTRAINT из xBestIndex полезен для
табличных функций, у которых есть
обязательные параметры. Если aConstraint[].usable = false
для одного из обязательных параметров, то метод xBestIndex должен возвратить
SQLITE_CONSTRAINT. Если обязательное поле не появляется в aConstraint[]
вообще, это означает, что соответствующий параметр пропущен во входе SQL.
В этом случае xBestIndex должен установить сообщение об ошибке в
pVTab->zErrMsg и возвращать SQLITE_ERROR. В итоге: aConstraint[].usable для обязательного параметра является
false → вернуть SQLITE_CONSTRAINT. Обязательный параметр не появляется где угодно в
aConstraint[] → установить сообщение об ошибке в
pVTab->zErrMsg и вернуть SQLITE_ERROR. Следующий пример лучше иллюстрирует использование SQLITE_CONSTRAINT как
возвращаемое значение от xBestIndex: Предполагая, что первый скрытый столбец "tablevaluedfunc" это "param1",
запрос выше семантически эквивалентен этому: Планировщик запроса должен выбрать между многими возможными внедрениями
этого запроса, но два плана в особенности знамениты: Просмотрите все строки realtab и для каждой
найдите строки в tablevaluedfunc, где param1 = realtab.x Просмотрите все строки табличной функции и для каждой
строки найдите строки в realtab, где x = tablevaluedfunc.param1.
Метод xBestIndex будет вызван однажды для каждого из потенциальных планов
выше. Для плана 1 aConstraint[].usable для ограничений
SQLITE_CONSTRAINT_EQ столбца param1 будет true,
потому что значение правой стороны для ограничения "param1 = ?"
будет известно, так как оно определяется внешним циклом realtab.
Но для плана 2 aConstraint[].usable для "param1 = ?" будет false,
потому что значение правой стороны определяется внутренним циклом и является
таким образом неизвестным количеством. Поскольку param1 это
необходимый вход к табличным функциям, метод xBestIndex
должен возвратить SQLITE_CONSTRAINT, когда представлен план 2,
указав, что необходимый вход отсутствует. Это вынуждает планировщик
запроса выбрать план 1.
Этот метод освобождает связь с виртуальной таблицей. Только объект
sqlite3_vtab ликвидирован.
Виртуальная таблица не разрушена и любое запоминающее устройство, связанное с
виртуальной таблицей, сохраняется. Этот метод отменяет работу
xConnect. Этот метод это деструктор для связи с виртуальной таблицей.
Противопоставьте этот метод
xDestroy. xDestroy это деструктор для всей виртуальной таблицы. xDisconnect требуется для каждого виртуального внедрения таблицы, хотя
приемлемо для методов xDisconnect быть и той же самой функцией, если это
имеет смысл для конкретной виртуальной таблицы.
Этот метод освобождает связь с виртуальной таблицей, точно так же, как
xDisconnect,
и это также разрушает внедрение базовой таблицы. Этот метод отменяет работу
xCreate. xDisconnect
вызывают каждый раз, когда соединение с базой данных, которое использует
виртуальная таблица, закрывается. Метод xDestroy вызывают только когда запрос
DROP TABLE
выполняется для виртуальной таблицы. xDestroy требуется для каждого виртуального внедрения таблицы, хотя
приемлемо для методов
xDisconnect и xDestroy быть той же самой
функцией, если это имеет смысл для конкретной виртуальной таблицы.
xOpen создает новый курсор, используемый для доступа (чтения и/или записи)
виртуальной таблицы. Успешный вызов этого метода ассигнует память для
sqlite3_vtab_cursor (или подкласса),
инициализирует новый объект и делает *ppCursor указателем на новый объект.
Успешный вызов тогда возвращает SQLITE_OK. Для каждого успешного вызова этого метода ядро SQLite позже вызовет
xClose, чтобы
разрушить ассигнованный курсор. xOpen не должен инициализировать поле pVtab структуры
sqlite3_vtab_cursor.
Ядро SQLite будет заботиться об этом автоматически. Виртуальное внедрение таблицы должно быть в состоянии поддержать
произвольное число одновременно открытых курсоров. Когда первоначально открыто, курсор находится в неопределенном
состоянии. Ядро SQLite вызовет xFilter
на курсоре до любой попытки позиционировать или читать из курсора. xOpen требуется для каждого виртуального внедрения таблицы. xClose закрывает курсор, ранее открытый
xOpen.
Ядро SQLite будет всегда вызывать xClose однажды для каждого курсора,
открытого, используя xOpen. Этот метод должен высвободить все средства, ассигнованные соответствующим
xOpen. Установленный порядок не вызовут снова, даже если он возвратит ошибку.
Ядро SQLite не будет использовать
sqlite3_vtab_cursor
снова после того, как это будет закрыто. xClose требуется для каждого виртуального внедрения таблицы.
xEof должен возвратить false (0), если указанный курсор в настоящее
время указывает на действительную строку данных, или true (не 0) иначе.
Этот метод немедленно вызывает движок SQL после каждого
xFilter и
xNext. xEof требуется для каждого виртуального внедрения таблицы.
Этот метод начинает поиск в виртуальной таблице. Первый аргумент это
курсор, открытый xOpen.
Следующие два аргумента определяют конкретный индекс поиска, ранее выбранный
xBestIndex.
Определенные значения idxNum и idxStr неважны, xFilter и xBestIndex
договариваются, каково то значение. xBestIndex, возможно, просил значения определенных выражений, используя
значения aConstraintUsage[].argvIndex values
структуры sqlite3_index_info.
Те значения передаются к xFilter с использованием argc и argv. Если виртуальная таблица содержит одну или несколько строк, которые
соответствуют критериям поиска, то курсор должен быть левой точкой в первой
строке. Последующие обращения к xEof должны
вернуть false (0). Если нет никакого совпадения строк, то курсор нужно
оставить в состоянии, которое заставит xEof
вернуть true (не 0). Движок SQLite будет использовать
xColumn и
xRowid,
чтобы получить доступ к тому содержанию строки.
xNext будет использоваться, чтобы
продвинуться к следующей строке. Этот метод должен возвратить SQLITE_OK
в случае успеха или код ошибки sqlite иначе. Метод xFilter требуется для каждого виртуального внедрения таблицы.
xNext двигает
виртуальный курсор таблицы к следующей строке
набора результатов, инициализированного
xFilter.
Если курсор уже указывает на последнюю строку, когда этот установленный
порядок вызывают, то курсор больше не указывает на действительные данные и
последующее обращение к xEof
должно возвратить true (не 0). Если курсор успешно продвинут к другой
строке содержания, то последующие вызовы xEof
должны возвратить false (0). Этот метод должен возвратить SQLITE_OK
в случае успеха или
код ошибки sqlite иначе. Метод xNext требуется для каждого виртуального внедрения таблицы.
Ядро SQLite вызывает этот метод, чтобы найти значение для энной колонки
текущей строки. N основан на ноле, таким образом, первая колонка
пронумерована как 0. Метод xColumn может возвратить свой результат назад к
SQLite с использованием одного из следующего интерфейсов: Если реализация метода xColumn не вызывает ни одну из функций выше, то
значение колонки по умолчанию SQL NULL. Чтобы поднять ошибку, xColumn должен использовать один из методов
result_text(), чтобы установить текст сообщения об ошибке, затем возвратить
соответствующий код ошибки.
xColumn должен возвратить SQLITE_OK
при успехе. Метод xColumn требуется для каждого
виртуального внедрения таблицы.
Успешный вызов этого метода заставит *pRowid быть заполненным
rowid строки, на которую в
настоящее время указывает
виртуальный курсор таблицы pCur.
Этот метод возвращает SQLITE_OK
при успехе. Это возвращает соответствующий
код ошибки при неудаче. xRowid требуется для каждого виртуального внедрения таблицы.
Все изменения виртуальной таблицы внесены, используя метод xUpdate.
Этот метод может использоваться, чтобы вставить, удалить или обновить. Параметр argc определяет количество записей во множестве argv. Значение
argc будет 1 для чистого удаления, N+2 для вставки, замены или обновления,
где N это количество колонок в таблице. В предыдущем предложении N включает
любые скрытые столбцы. Каждый вход argv будет иметь ненулевое значение в C, но может содержать
значение SQL NULL. Другими словами, всегда верно, что
argv[i]!=0 для i от 0 до argc-1.
Однако, могло бы иметь место, что
sqlite3_value_type(argv[i])==SQLITE_NULL. argv[0] это rowid строки
в виртуальной таблице, которая будет удалена. Если argv[0] является NULL SQL,
то никакое удаление не происходит. argv[1] это rowid новой строки, которая будет вставлена в виртуальную
таблицу. Если argv[1] это SQL NULL, то внедрение должно выбрать rowid для
недавно вставленной строки. Последующие записи argv[] содержат значения
колонок виртуальной таблицы в порядке, в котором были объявлены колонки.
Количество колонок будет соответствовать декларации таблицы, что
xConnect или
xCreate сделали при вызове
sqlite3_declare_vtab().
Все скрытые столбцы включены. Делая вставку без rowid (argc>1, argv[1] = SQL NULL),
на виртуальной таблице, которая использует ROWID (но не на
виртуальной таблице WITHOUT ROWID),
внедрение должно установить *pRowid в rowid недавно вставленной строки,
это станет значением, возвращенным
sqlite3_last_insert_rowid().
Установка этого значения во всех других случаях является безопасной, но не
делает ничего, SQLite игнорирует возвращаемое значение *pRowid, если
argc==1 или argv[1] не SQL NULL. Каждый вызов xUpdate попадет в один из случаев, показанных ниже.
Ссылки на argv[i] указывают на значение SQL в пределах
объекта argv[i], но не сам объект argv[i]. DELETE: единственная строка с rowid или PRIMARY KEY = argv[0]
удалена. Никакая вставка не происходит. INSERT: новая строка вставляется со значениями столбцов, взятыми от
argv[2] и после. В rowid виртуальной таблице, если argv[1] это SQL NULL,
то новый уникальный rowid произведен автоматически. argv[1] будет NULL для
виртуальной таблицы WITHOUT ROWID,
в этом случае внедрение должно взять значение PRIMARY KEY из соответствующей
колонки в argv[2] и после. UPDATE: строка с rowid или PRIMARY KEY argv[0] обновляется с новыми
значениями в argv[2] и после. UPDATE с изменением rowid или PRIMARY KEY:
строка с rowid или PRIMARY KEY argv[0] обновлена с rowid или PRIMARY KEY в
argv[1] и новыми значениями в argv[2] и далее.
Это произойдет, когда SQL-оператор обновит rowid, как в запросе: xUpdate должен возвратить
SQLITE_OK
если и только если это успешно. Если неудача происходит, xUpdate должен
возвратить соответствующий
код ошибки. При неудаче элемент pVTab->zErrMsg
может произвольно быть заменен текстом сообщения об ошибке, сохраненным в
памяти, ассигнованной от SQLite, используя функции, такие как
sqlite3_mprintf() или
sqlite3_malloc(). Если xUpdate нарушает некоторое ограничение виртуальной таблицы
(включая, но не ограничиваясь попыткой сохранить значение
неверного типа данных, пытаясь сохранить значение, которое слишком велико
или слишком маленькое, или пытающийся изменить значение только для чтения),
тогда xUpdate должен потерпеть неудачу с соответствующим
кодом ошибки. Если xUpdate выполняет UPDATE, то
sqlite3_value_nochange(X)
может использоваться, чтобы обнаружить, какие колонки виртуальной таблицы
были на самом деле изменены UPDATE.
sqlite3_value_nochange(X)
вернет true для колонок, которые не изменяются. На каждом UPDATE SQLite
сначала вызовет xColumn
отдельно для каждой неизменной колонки в таблице, чтобы получить значение
для той колонки. xColumn
может проверить, чтобы видеть, неизменна ли колонка на уровне SQL
sqlite3_vtab_nochange().
Если xColumn
видит, что колонка не изменяется, это должно возвратиться, не устанавливая
результат, используя один из
sqlite3_result_xxxxx().
Только в этом случае
sqlite3_value_nochange() будет true в
xUpdate. Если xColumn
действительно вызывает один или несколько
sqlite3_result_xxxxx(),
SQLite понимает, что есть изменение в значения колонки, и вызов
sqlite3_value_nochange()
для той колонки в xUpdate возвратит false. Могли бы быть один или несколько открытых объектов
sqlite3_vtab_cursor
в использовании на виртуальной таблице и возможно даже на строке
виртуальной таблицы, когда метод xUpdate вызван. Внедрение xUpdate должно
быть подготовлено к попыткам удалить или изменить строки таблицы из других
существующих курсоров. Если виртуальная таблица не может приспособить такие
изменения, xUpdate должен возвратить
код ошибки. xUpdate дополнительный. Если указатель xUpdate в
sqlite3_module для виртуальной таблицы это
NULL, то виртуальная таблица только для чтения.
Этот метод вызывают во время
sqlite3_prepare(),
чтобы дать виртуальному внедрению таблицы возможность перегрузить функции.
Этот метод может быть установлен в NULL, в этом случае, никакая
перегрузка не происходит. Когда функция использует колонку от виртуальной таблицы как
первый аргумент, этот метод вызывают, чтобы видеть, хотела ли виртуальная
таблица перегрузить функцию. Первые три параметра это входы:
виртуальная таблица, количество аргументов функции и название функции.
Если никакая перегрузка не желаема, этот метод возвращает 0.
Чтобы перегрузить функцию, этот метод вписывает в новую реализацию функции
*pxFunc, в пользовательские данные *ppArg и возвращает 1
или число между
SQLITE_INDEX_CONSTRAINT_FUNCTION и 255. Исторически, возвращаемое значение от xFindFunction() было 0 или 1.
Ноль означает, что функция не перегружена, 1 означает перегрузку.
Способность к возвращаемым значениям
SQLITE_INDEX_CONSTRAINT_FUNCTION
или больше была добавлена в версии 3.25.0 (2018-09-15).
Если xFindFunction вернет
SQLITE_INDEX_CONSTRAINT_FUNCTION
или больше, это значит, что функция берет два аргумента, и функция может
использоваться в качестве boolean в WHERE запроса (и что виртуальная таблица
в состоянии эксплуатировать ту функцию, чтобы ускорить результат запроса).
Когда xFindFunction возвращает
SQLITE_INDEX_CONSTRAINT_FUNCTION
или больше, возвращенное значение становится значением
sqlite3_index_info.aConstraint.op
для одного из ограничений, переданных в
xBestIndex().
Первый аргумент функции это колонка, определенная полем
aConstraint[].iColumn ограничения, второй аргумент функции это значение,
которое будет передано в xFilter() (если
значение aConstraintUsage[].argvIndex установлено) или значение, возвращенное
из sqlite3_vtab_rhs_value(). Geopoly module это пример
виртуальной таблицы, который использует
SQLITE_INDEX_CONSTRAINT_FUNCTION, чтобы улучшить работу.
xFindFunction() для Geopoly возвращает
SQLITE_INDEX_CONSTRAINT_FUNCTION для SQL-функции
geopoly_overlap() и это возвращает
SQLITE_INDEX_CONSTRAINT_FUNCTION+1 для SQL-функции
geopoly_within().
Это разрешает оптимизации поиска для таких запросов, как: Обратите внимание на то, что инфикс функций
(LIKE,
GLOB,
REGEXP и
MATCH) полностью изменяет порядок
их аргументов. Так "like(A,B)" обычно работал бы как
"B like A". Но xFindFunction() всегда смотрит на крайний левый аргумент, а не
на первый логический аргумент. Следовательно, для формы "B like A" SQLite
смотрит на левый операнд "B" и если тот операнд столбец виртуальной таблицы,
он вызывает xFindFunction() на той виртуальной таблице. Но если форма
"like(A,B)" используется вместо этого, то SQLite проверяет термин, чтобы
видеть, является ли это колонкой виртуальной таблицы, и если так это вызывает
xFindFunction() для виртуальной таблицы колонки A. Указатель функции, возвращенный этим установленным порядком, должен быть
действительным для целой жизни объекта
sqlite3_vtab, данного в первом параметре.
Этот метод начинает транзакцию на виртуальной таблице.
Этот метод дополнительный. Указатель xBegin в
sqlite3_module может быть NULL. Этот метод всегда сопровождается одним обращением к
xCommit или
xRollback.
Транзакции в виртуальной таблице не вкладываются, таким образом, xBegin
не будет вызван несколько раз на единственной виртуальной таблице без
обращения к xCommit или
xRollback.
Множественные вызовы других методов могут и вероятно будут происходить
между xBegin и соответствующим xCommit (или
xRollback).
Этот метод сигнализирует о начале двухфазной передачи на виртуальной
таблице. Это дополнительный метод, указатель xSync в
sqlite3_module может быть NULL. Этот метод вызван только после
xBegin, но до
xCommit или
xRollback.
Чтобы осуществить двухфазную передачу, xSync
на всех виртуальных таблицах вызван до
xCommit
на любой виртуальной таблице. Если какой-либо из xSync терпит неудачу, вся
транзакция отменена до прежнего уровня.
Этот метод заставляет транзакцию виртуальной таблицы выполнить commit.
Это дополнительный метод, указатель xCommit в
sqlite3_module может быть NULL. Обращение к этому методу всегда следует за предшествующим
xBegin и xSync.
Этот метод вызывает отмену транзакции виртуальной таблицы.
Это дополнительный метод, указатель xRollback в
sqlite3_module может быть NULL. Обращение к этому методу всегда следует за предшествующим
xBegin.
Этот метод предоставляет уведомление виртуальному внедрению таблицы, что
виртуальной таблице дадут новое имя. Если этот метод возвращает
SQLITE_OK,
тогда SQLite переименовывает таблицу. Если этот метод возвращает
код ошибки, переименования не происходит. xRename опционален. Если опущен, то виртуальная таблица не может быть
переименована, используя ALTER TABLE RENAME.
PRAGMA legacy_alter_table позволено до вызова
этого метода, и значение для legacy_alter_table восстановлено
после того, как этот метод заканчивает работу.
Это необходимо для правильной обработки виртуальных таблиц, которые
используют теневые таблицы, где теневые
таблицы должны быть переименованы, чтобы соответствовать новому виртуальному
имени таблицы. Если legacy_alter_format = off, xConnect будет вызван
для виртуальной таблицы каждый раз, когда xRename пытается изменить
название теневой таблицы.
Эти методы предоставляют виртуальному внедрению таблицы возможность
осуществить вложенные транзакции. Они всегда дополнительные и будут вызваны
только в SQLite version 3.7.7
(2011-06-23) и позже. При вызове xSavepoint(X,N) это является сигналом
виртуальной таблице X, что это должно сохранить свое текущее состояние как
точку сохранения N. Последующее обращение к xRollbackTo(X,R)
означает, что статус виртуальной таблицы должен возвратиться к тому, каким
это было, когда был вызван xSavepoint(X,R). Обращение к xRollbackTo(X,R)
лишит законной силы все точки сохранения с N>R,
ни одна из этих точек сохранения не будет отменена или освобождена,
не будучи повторно инициализированной через xSavepoint().
xRelease(X,M) лишает законной силы все точки сохранения, где N>=M. Методы xSavepoint(), xRelease() или xRollbackTo() никогда не будут
вызваны между обращениями к xBegin() и xCommit() или xRollback(). Некоторые виртуальные внедрения таблицы (например,
FTS3, FTS5 и
RTREE) используют реальные (невиртуальные) таблицы
базы данных, чтобы сохранить содержание. Например, когда содержание
вставляется в виртуальную таблицу FTS3, данные в конечном счете хранятся в
реальных таблицах, названных "%_content", "%_segdir", "%_segments", "%_stat"
и "%_docsize", где "%" это название оригинальной виртуальной таблицы.
Эти вспомогательные реальные таблицы, которые хранят содержание для
виртуальной таблицы, называют "теневыми таблицами". См.
(1),
(2) и
(3). Метод xShadowName существует, чтобы позволить SQLite определять,
является ли определенная реальная таблица на самом деле теневой
таблицей для виртуальной таблицы. SQLite понимает реальную таблицу как теневую, если
все следующее верно: Если SQLite признает таблицу теневой и если установлен флаг
SQLITE_DBCONFIG_DEFENSIVE, то теневая таблица
только для чтения для обычных SQL-операторов. Теневая таблица может все еще
быть написана, но только SQL, который вызван из одного из методов некоторого
виртуального внедрения таблицы. Метод xShadowName должен защитить содержание теневых таблиц от того, чтобы
быть испорченным враждебным SQL. Каждое виртуальное внедрение таблицы,
которое использует теневые таблицы, должно быть в состоянии обнаружить и
справиться с испорченным теневым содержанием таблицы.
Однако, ошибки в виртуальных таблицах могли бы позволить сознательно
испорченной теневой таблице вызывать сбой. Механизм xShadowName стремится
избежать деяний нулевого дня, предотвращая обычные SQL-операторы от
преднамеренного повреждения теневых таблиц. Теневые таблицы допускают чтение-запись по умолчанию. Теневые таблицы
становятся только только для чтения, когда установлен флаг
SQLITE_DBCONFIG_DEFENSIVE через
sqlite3_db_config().
Теневые таблицы должны быть чтением-записью по умолчанию, чтобы поддержать
обратную совместимость. Например, текст SQL, произведенный командой
.dump в CLI пишет
непосредственно в теневые таблицы.
Если iVersion для sqlite3_module будет равняться 4 или больше, и метод
xIntegrity не NULL, то
PRAGMA integrity_check и
PRAGMA quick_check
выизовут xIntegrity как часть его обработки. Если xIntegrity напишет
последовательность сообщения об ошибке в пятый параметр, то PRAGMA
integrity_check сообщит об ошибке как часть вывода.
Так, другими словами метод xIntegrity позволяет
PRAGMA integrity_check
проверять целостность содержания, сохраненного в виртуальной таблице. Метод xIntegrity вызывают с пятью параметрами: xIntegrity должен обычно возвращать SQLITE_OK
даже если это находит проблемы в содержании виртуальной таблицы.
Любой другой код ошибки означает что сам xIntegrity имеет
проблемы, пытаясь оценить виртуальное содержание таблицы. Так, например, если
инвертированный индекс для FTS5
внутренне непоследователен, то xIntegrity
должен написать соответствующее сообщение об ошибке в параметр pzErr и
возвратить SQLITE_OK. Но если xIntegrity неспособен закончить свою оценку
виртуального содержания таблицы из-за исчерпывания памяти, то это должно
возвратить SQLITE_NOMEM. Если сообщение об ошибке произведено, место для него
должно быть получено из sqlite3_malloc64()
или аналога. Собственность последовательности сообщения об ошибке перейдет к
ядру SQLite, когда xIntegrity возвратится. Ядро удостоверится, что
sqlite3_free() вызван, чтобы освободить память.
PRAGMA integrity_check, которая вызывает xIntegrity, не изменяет возвращенное
сообщение об ошибке. Сам xIntegrity должен включать название виртуальной
таблицы как часть сообщения. zSchema и zName обеспечиваются, чтобы
сделать это легче. mFlags в настоящее время boolean (0 или 1), которое указывает, вызвали ли
xIntegrity для PRAGMA
integrity_check (mFlags==0) или
PRAGMA quick_check (mFlags==1).
Будущие версии SQLite могли бы использовать старшие биты mFlags,
чтобы указать на дополнительные варианты обработки. Поддержка метода xIntegrity была добавлена в SQLite version 3.44.0
(2023-11-01). В том же самом выпуске xIntegrity
был добавлен ко многим встроенным виртуальным таблицам, таким как
FTS3, FTS5 и
RTREE так, чтобы содержание тех таблиц было впредь
автоматически проверено на последовательность, когда выполняется
PRAGMA integrity_check.
Choose any three.
1. Введение
1.1. Применение
CREATE VIRTUAL TABLE tablename USING modulename;
CREATE VIRTUAL TABLE tablename USING modulename(arg1, arg2, ...);
1.1.1.
Временные виртуальные таблицы
CREATE VIRTUAL TABLE temp.tablename USING module(arg1, ...);
1.1.2.
Одноименные виртуальные таблицы
SELECT * FROM dbstat;
1.1.3.
Одноименно-единственные виртуальные таблицы
1.2. Реализация
typedef struct sqlite3_vtab sqlite3_vtab;
typedef struct sqlite3_index_info sqlite3_index_info;
typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor;
typedef struct sqlite3_module sqlite3_module;
struct sqlite3_vtab {
const sqlite3_module *pModule;
int nRef;
char *zErrMsg;
};
struct sqlite3_vtab_cursor {
sqlite3_vtab *pVtab;
};
int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *, /* Methods for the module */
void * /* Client data for xCreate/xConnect */
);
int sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *, /* Methods for the module */
void *, /* Client data for xCreate/xConnect */
void(*xDestroy)(void*) /* Client data destructor function */
);
struct sqlite3_module {
int iVersion;
int (*xCreate)(sqlite3*, void *pAux, int argc, char *const*argv,
sqlite3_vtab **ppVTab, char **pzErr);
int (*xConnect)(sqlite3*, void *pAux, int argc, char *const*argv,
sqlite3_vtab **ppVTab, char **pzErr);
int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
int (*xDisconnect)(sqlite3_vtab *pVTab);
int (*xDestroy)(sqlite3_vtab *pVTab);
int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
int (*xClose)(sqlite3_vtab_cursor*);
int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
int argc, sqlite3_value **argv);
int (*xNext)(sqlite3_vtab_cursor*);
int (*xEof)(sqlite3_vtab_cursor*);
int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);
int (*xRowid)(sqlite3_vtab_cursor*, sqlite_int64 *pRowid);
int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite_int64 *);
int (*xBegin)(sqlite3_vtab *pVTab);
int (*xSync)(sqlite3_vtab *pVTab);
int (*xCommit)(sqlite3_vtab *pVTab);
int (*xRollback)(sqlite3_vtab *pVTab);
int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg);
int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
/* The methods above are in version 1 of the sqlite_module object. Those
** below are for version 2 and greater. */
int (*xSavepoint)(sqlite3_vtab *pVTab, int);
int (*xRelease)(sqlite3_vtab *pVTab, int);
int (*xRollbackTo)(sqlite3_vtab *pVTab, int);
/* The methods above are in versions 1 and 2 of the sqlite_module object.
** Those below are for version 3 and greater. */
int (*xShadowName)(const char*);
/* The methods above are in versions 1 through 3 of the sqlite_module object.
** Those below are for version 4 and greater. */
int (*xIntegrity)(sqlite3_vtab *pVTab, const char *zSchema,
const char *zTabName, int mFlags, char **pzErr);
};
1.3. Виртуальные таблицы и общий кэш
1.4. Создание новых виртуальных внедрений таблицы
2. Виртуальные методы таблицы
2.1. Метод xCreate
int (*xCreate)(sqlite3 *db, void *pAux, int argc, char *const*argv,
sqlite3_vtab **ppVTab, char **pzErr);
int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable)
int sqlite3_vtab_config(sqlite3 *db, int op, ...);
2.1.1. Скрытые столбцы в виртуальных таблицах
CREATE TABLE x(a HIDDEN VARCHAR(12), b INTEGER, c INTEGER Hidden);
2.1.2. Табличные функции
CREATE TABLE generate_series(value, start HIDDEN, stop HIDDEN, step HIDDEN);
SELECT value FROM generate_series(5,50);
SELECT value FROM generate_series WHERE start=5 AND stop=50;
2.1.3. Виртуальные таблицы WITHOUT ROWID
2.2. Метод xConnect
int (*xConnect)(sqlite3*, void *pAux, int argc, char *const*argv,
sqlite3_vtab **ppVTab, char **pzErr);
2.3. Метод xBestIndex
int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
struct sqlite3_index_info {
/* Inputs */
const int nConstraint; /* Number of entries in aConstraint */
const struct sqlite3_index_constraint {
int iColumn; /* Column constrained. -1 for ROWID */
unsigned char op; /* Constraint operator */
unsigned char usable; /* True if this constraint is usable */
int iTermOffset; /* Used internally - xBestIndex should ignore */
} *const aConstraint; /* Table of WHERE clause constraints */
const int nOrderBy; /* Number of terms in the ORDER BY clause */
const struct sqlite3_index_orderby {
int iColumn; /* Column number */
unsigned char desc; /* True for DESC. False for ASC. */
} *const aOrderBy; /* The ORDER BY clause */
/* Outputs */
struct sqlite3_index_constraint_usage {
int argvIndex; /* if >0, constraint is part of argv to xFilter */
unsigned char omit; /* Do not code a test for this constraint */
} *const aConstraintUsage;
int idxNum; /* Number used to identify the index */
char *idxStr; /* String, possibly obtained from sqlite3_malloc */
int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
int orderByConsumed; /* True if output is already ordered */
double estimatedCost; /* Estimated cost of using this index */
/* Fields below are only available in SQLite 3.8.2 and later */
sqlite3_int64 estimatedRows; /* Estimated number of rows returned */
/* Fields below are only available in SQLite 3.9.0 and later */
int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */
/* Fields below are only available in SQLite 3.10.0 and later */
sqlite3_uint64 colUsed; /* Input: Mask of columns used by statement */
};
#define SQLITE_INDEX_CONSTRAINT_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4
#define SQLITE_INDEX_CONSTRAINT_LE 8
#define SQLITE_INDEX_CONSTRAINT_LT 16
#define SQLITE_INDEX_CONSTRAINT_GE 32
#define SQLITE_INDEX_CONSTRAINT_MATCH 64
#define SQLITE_INDEX_CONSTRAINT_LIKE 65 /* 3.10.0 and later */
#define SQLITE_INDEX_CONSTRAINT_GLOB 66 /* 3.10.0 and later */
#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 /* 3.10.0 and later */
#define SQLITE_INDEX_CONSTRAINT_NE 68 /* 3.21.0 and later */
#define SQLITE_INDEX_CONSTRAINT_ISNOT 69 /* 3.21.0 and later */
#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 /* 3.21.0 and later */
#define SQLITE_INDEX_CONSTRAINT_ISNULL 71 /* 3.21.0 and later */
#define SQLITE_INDEX_CONSTRAINT_IS 72 /* 3.21.0 and later */
#define SQLITE_INDEX_CONSTRAINT_LIMIT 73 /* 3.38.0 and later */
#define SQLITE_INDEX_CONSTRAINT_OFFSET 74 /* 3.38.0 and later */
#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 /* 3.25.0 and later */
#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
const char *sqlite3_vtab_collation(sqlite3_index_info*, int i);
2.3.1. Входы
column OP EXPR
a = 5
x BETWEEN 10 AND 100 AND 999>y
x >= 10
x <= 100
y < 999
FUNCTION(column, EXPR)
2.3.1.1. LIKE, GLOB, REGEXP и MATCH
LIKE(EXPR, column)
GLOB(EXPR, column)
REGEXP(EXPR, column)
MATCH(EXPR, column)
column LIKE EXPR
LIKE(EXPR,column)
2.3.1.2. LIMIT и OFFSET
2.3.1.3. Правые значения стороны ограничений
2.3.2. Вывод
2.3.2.1. Опустите проверку ограничений в bytecode
2.3.2.2. ORDER BY и orderByConsumed
2.3.3. Возвращаемое значение
2.3.4. Предписание обязательных параметров на табличных функциях
SELECT * FROM realtab, tablevaluedfunc(realtab.x);
SELECT * FROM realtab, tablevaluedfunc
WHERE tablevaluedfunc.param1 = realtab.x;
2.4. Метод xDisconnect
int (*xDisconnect)(sqlite3_vtab *pVTab);
2.5. Метод xDestroy
int (*xDestroy)(sqlite3_vtab *pVTab);
2.6. Метод xOpen
int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
2.7. Метод xClose
int (*xClose)(sqlite3_vtab_cursor*);
2.8. Метод xEof
int (*xEof)(sqlite3_vtab_cursor*);
2.9. Метод xFilter
int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
int argc, sqlite3_value **argv);
2.10. Метод xNext
int (*xNext)(sqlite3_vtab_cursor*);
2.11. Метод xColumn
int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int N);
2.12. Метод xRowid
int (*xRowid)(sqlite3_vtab_cursor *pCur, sqlite_int64 *pRowid);
2.13. Метод xUpdate
int (*xUpdate)(sqlite3_vtab *pVTab, int argc, sqlite3_value **argv,
sqlite_int64 *pRowid);
argv[0] ≠ NULL
argv[0] = NULL
argv[0] ≠ NULL
argv[0] = argv[1]
argv[0] ≠ NULL
argv[0] ≠ argv[1]
UPDATE table SET rowid=rowid+1 WHERE ...;
2.14. Метод xFindFunction
int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg);
SELECT * FROM geopolytab WHERE geopoly_overlap(_shape, $query_polygon);
SELECT * FROM geopolytab WHERE geopoly_within(_shape, $query_polygon);
2.15. Метод xBegin
int (*xBegin)(sqlite3_vtab *pVTab);
2.16. Метод xSync
int (*xSync)(sqlite3_vtab *pVTab);
2.17. Метод xCommit
int (*xCommit)(sqlite3_vtab *pVTab);
2.18. Метод xRollback
int (*xRollback)(sqlite3_vtab *pVTab);
2.19. The xRename Method
int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
2.20. Методы xSavepoint, xRelease и xRollbackTo
int (*xSavepoint)(sqlite3_vtab *pVtab, int);
int (*xRelease)(sqlite3_vtab *pVtab, int);
int (*xRollbackTo)(sqlite3_vtab *pVtab, int);
2.21. Метод xShadowName
2.22. Метод xIntegrity