Таблицы-обманки
1. Введение
Таблица-обманка — это таблица, которая прикреплена к тому же B-дереву, что и индекс. Таблица-обманка позволяет выполнять запросы и изменять содержимое индекса так, как будто индекс — это обычная таблица.
Таблицы-обманки предназначены только для анализа и отладки. Это не функция, которую большинство разработчиков приложений должны понимать или даже знать. Таблицы-обманки — только для экспертов.
Неправильное использование таблиц-обманок может привести к повреждению индекса, хотя любое возникшее таким образом повреждение можно исправить, выполнив REINDEX.
2. Подробности
Каждая таблица и каждый индекс в SQLite хранятся в отдельном B-дереве в файле базы данных. Каждое B-дерево идентифицируется своим номером корневой страницы. Номер корневой страницы любого индекса или таблицы можно найти, обратившись к столбцу "rootpage" в таблице sqlite_schema. Дополнительную информацию об этой структуре можно найти в учебнике по индексации и документации по формату файла.
Обычно B-деревья для таблиц и индексов немного отличаются. B-дерево таблицы содержит 64-битное целое число в качестве ключа и произвольные данные. 64-битное целое число — это ROWID. 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.
Можно записывать данные в таблицу "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" включает механизм таблицы-обманки. "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
По состоянию на SQLite 3.16.0 (2017-01-02), командная строка оболочки содержит команду ".imposter", которая выполняет всю работу по настройке временной таблицы-обманки. Вместо нескольких вызовов sqlite3_test_control() и определения и вызова совместимого оператора CREATE TABLE, временная таблица-обманка может быть создана следующим образом:
.imposter t1bc t2
Конечно, замените нужные имена индекса и таблицы-обманки на "t1bc" и "t2" в примере. Команда ".imposter" считывает схему индекса "t1bc", использует эту информацию для построения совместимого оператора CREATE TABLE для таблицы-обманки, а затем автоматически выполняет все необходимые вызовы для создания временной таблицы-обманки.
3. Заключение и последнее предупреждение
Механизм таблицы-обманки — это мощный инструмент анализа и отладки для SQLite. Но, как и все острые инструменты, он может быть опасным и может привести к повреждению файлов базы данных при неправильном использовании. Не пытайтесь использовать таблицы-обманки в приложении. Таблицы-обманки предназначены для использования в лабораторных условиях экспертами.
Эта страница была в последний раз изменена 08.01.2022 05:02:57 UTC
SQLite is in the Public Domain.
https://sqlite.org/imposter.html