Spec-Zone.ru › SQLite

Таблицы-имитаторы

1. Введение

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

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

По умолчанию таблицы-имитаторы доступны только для чтения. Пока они доступны только для чтения, они безвредны. Однако при включении PRAGMA writable_schema=ON в таблицу-имитатор можно записывать данные. Это может привести к повреждению индекса, хотя любое такое повреждение можно устранить, выполнив REINDEX.

2. Подробности

Каждая таблица и каждый индекс в SQLite хранятся в отдельном B-дереве в файле базы данных. Каждое B-дерево идентифицируется номером корневой страницы. Номер корневой страницы любого индекса или таблицы можно найти, запросив столбец "rootpage" таблицы sqlite_schema. Дополнительные сведения об этой структуре см. в руководстве по индексированию и документации по формату файла.

Обычно B-деревья таблиц и индексов немного различаются. B-дерево таблицы содержит 64-битный целочисленный ключ и произвольные данные. 64-битный целочисленный ключ — это ROWID. B-деревья индексов содержат произвольный двоичный ключ и не содержат данных. Поэтому B-деревья таблиц и B-деревья индексов несовместимы напрямую.

Однако B-дерево таблицы WITHOUT ROWID имеет тот же формат, что и B-дерево индекса. Таким образом, к B-дереву индекса можно обращаться так, как если бы оно было таблицей WITHOUT ROWID.

2.1. Таблицы-имитаторы, созданные вручную

Один из способов создать таблицу-имитатор — напрямую отредактировать таблицу sqlite_schema, вставив новую строку с описанием таблицы. Например, предположим, что схема выглядит так:

CREATE TABLE t1(a INTEGER PRIMARY KEY,b TEXT,c INT, d INT);
CREATE INDEX t1bc ON t1(b,c);

Таблица WITHOUT ROWID с той же структурой, что и индекс t1bc, будет выглядеть так:

CREATE TABLE t2(b TEXT,c INT,a INT, PRIMARY KEY(b,c,a)) WITHOUT ROWID;

Чтобы создать постоянную таблицу-имитатор "t2" для индекса "t1bc", сначала следует разрешить редактирование таблицы sqlite_schema, выполнив "PRAGMA writable_schema=ON". (Обязательно ознакомьтесь с предупреждениями, сопровождающими эту PRAGMA. Ошибка может привести к серьёзному повреждению базы данных.) Затем вставьте новую запись в таблицу sqlite_schema, как показано ниже:

INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)
 SELECT 'table','t2','t2',rootpage,
   'CREATE TABLE t2(b,c,a,PRIMARY KEY(b,c,a))WITHOUT ROWID'
   FROM sqlite_schema
  WHERE name='t1bc';

Приведённая выше инструкция INSERT добавляет в таблицу sqlite_schema новую строку, которая определяет таблицу "t2" с тем же форматом на диске, что и индекс "t1bc", и указывает на то же B-дерево. После добавления этой записи в таблицу sqlite_schema необходимо закрыть и снова открыть базу данных, чтобы SQLite перечитала схему. Затем можно запрашивать таблицу "t2", чтобы просмотреть содержимое индекса "t1bc".

2.1.1. Повреждённая база данных

Серьёзная проблема описанного выше способа создания таблицы-имитатора вручную состоит в том, что после добавления новой записи "t2" в таблицу "sqlite_schema" файл базы данных формально будет повреждён. И индекс "t1bc", и таблица "t2" будут указывать на одно и то же B-дерево. Это не вызовет немедленных проблем, однако следует избегать выполнения VACUUM.

Если включена PRAGMA writable_schema, в таблицу "t2" можно записывать данные, изменяя тем самым содержимое индекса. Это приведёт к рассинхронизации индекса "t1bc" с родительской таблицей "t1". Рассинхронизированный индекс может приводить к неверным результатам запросов.

Поскольку таблица-имитатор "t2" представляет собой разновидность повреждения базы данных, ручной способ создания таблиц-имитаторов не рекомендуется. Вообще, использование таблиц-имитаторов не рекомендуется никому, кроме опытных разработчиков, но от таблиц-имитаторов, созданных вручную, следует отказаться в особенности, поскольку они являются постоянными.

2.2. Временные таблицы-имитаторы

Другой (более безопасный) способ создать таблицу-имитатор — добавить запись о ней во внутреннюю таблицу символов SQLite, не обновляя таблицу "sqlite_schema" на диске. В этом случае таблица-имитатор существует только в одном подключении к базе данных и автоматически удаляется при каждой повторной загрузке схемы.

Для создания временной таблицы-имитатора требуется специальный вызов sqlite3_test_control(). В отличие от всех остальных API SQLite, интерфейс sqlite3_test_control() может изменяться несовместимым образом от одного выпуска к следующему, поэтому описанный ниже механизм не гарантированно будет работать в будущих выпусках SQLite. Разработчики SQLite не считают это проблемой, поскольку таблицы-имитаторы не следует использовать в приложениях. Они предназначены только для анализа и тестирования.

Чтобы создать временную таблицу-имитатор, сначала вызовите sqlite3_test_control() следующим образом:

sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 1, tnum);

Параметр "db" — это указатель на подключение к базе данных. Аргумент "main" — это имя схемы, в которой нужно создать таблицу-имитатор. Аргумент "1" включает механизм таблиц-имитаторов. Если вместо "1" указать "2", будет создана таблица-имитатор, доступная только для чтения. "tnum" — это корневая страница индекса, которому должна соответствовать таблица-имитатор.

После приведённого выше вызова sqlite3_test_control() выполните инструкцию CREATE TABLE, определяющую таблицу-имитатор. При включённом механизме таблиц-имитаторов эта инструкция CREATE TABLE не создаёт настоящую таблицу, а лишь добавляет запись во внутреннюю таблицу символов SQLite. Обратите внимание: инструкция CREATE TABLE должна иметь правильный формат для данного индекса. Если в таблице-имитаторе неверное число столбцов, если она не является таблицей WITHOUT ROWID или если она иным образом несовместима с B-деревом индекса, при использовании таблицы-имитатора возникнут ошибки SQLITE_CORRUPT.

После выполнения инструкции CREATE TABLE отключите механизм таблиц-имитаторов следующим образом:

sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 0, 0);

Иными словами, выполните тот же вызов sqlite3_test_control(), изменив два последних параметра на ноль.

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

2.3. Команда оболочки .imposter

Оболочка командной строки содержит dot-команду ".imposter", которая выполняет всю работу по настройке временной таблицы-имитатора. Вместо нескольких вызовов sqlite3_test_control() и самостоятельного составления и выполнения совместимой инструкции CREATE TABLE временную таблицу-имитатор можно создать следующим образом:

.imposter t1bc t2

Разумеется, замените имена индекса и таблицы-имитатора "t1bc" и "t2" из примера на нужные вам. Команда ".imposter" считывает схему индекса "t1bc", использует эти сведения для составления совместимой инструкции CREATE TABLE для таблицы-имитатора, а затем автоматически выполняет все необходимые вызовы для создания временной таблицы-имитатора.

По умолчанию команда ".imposter" работает в SQLite версии 3.51.0 (2025-11-04) и более поздних версиях, однако созданная таблица-имитатор доступна только для чтения. Используйте параметр командной строки --unsafe-testing, чтобы включить команду ".imposter" в более ранних версиях CLI или создать таблицу-имитатор с возможностью чтения и записи.

3. Итоги и последнее предупреждение

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

Последнее обновление этой страницы: 2025-11-13 07:12:58Z

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

Spec-Zone.ru

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