Интернет, компьютеры, софт и прочий Hi-Tech

Подписаться через RSS2Email.ru

Загружаемые расширения SQLite

SQLite

Начиная с версии 3.3.6 SQLite позволяет загружать новые функции SQL и сортирующие последовательности из разделяемых библиотек и DLL. Это означает, что вам больше ненужно перекомпилировать SQLite, чтобы добавлять в него новые функции и сортировки.

Это новое экспериментальное API включает в себя функцию sqlite3_load_extension(), которая и выполняет загрузку. Экспериментальность этого API заключается в том, что его дальнейшая поддержка для обеспечения обратной совместимости не гарантируется в будущих релизах. Мы оставляем за собой право вносить изменения в данный интерфейс. После получения некоторого опыта с этим интерфейсом мы, возможно, избавим его от ярлыка "экспериментальный".

Новый API доступен из командной строки с использованием команды ".load":

.load имя_файла  ?точка_входа?

Новое API может быть использовано также и из SQL с помощью функции load_extension():

SELECT load_extension('имя_файла');
SELECT load_extension('имя_файла','точка_входа');

Здесь имя_файла — имя разделяемой библиотеки или DLL, а точка_входа — имя инициализирующей функции в этой разделяемой библиотеке. Если точка входа не указана, то по умолчанию будет вызвана функция sqlite3_extension_init. Рекомендуется использовать именно умолчальную точку входа.

Точка входа должная быть функцией, соответствующей следующему прототипу:

int sqlite3_extension_init(
  sqlite3 *db,          /* Коннект к базе данных */
  char **pzErrMsg,      /* Сюда вписывается сообщение об ошибке */
  const sqlite3_api_routines *pApi  /* Методы API */
);

Параметр db — это указатель на коннект к базе данных, возвращаемый функцией sqlite3_open(). Расширение может использовать этот аргумент только в таких функциях как sqlite3_create_function() и sqlite3_create_collation(). Если параметр pzErrMsg не является NULL, то расширение должно использовать sqlite3_mprintf() для генерации сообщения об ошибке и сохранить это сообщение в *pzErrMsg. Аргумент pApi содержит указатели на все API в вызываемой библиотеке. Расширения должны ссылаться на API SQLite с помощью этих указателей.

Соображения безопасности

Некоторые программы позволяют пользователям вводить SQL-запросы, которые затем проверяются с помощью sqlite3_set_authorizer() для предотвращения атак через программу. Новая SQL-функция load_extension(), описанная выше, позволяет обойти эту защиту и создает уязвимость в обсуждаемых приложениях. Во избежание этого весь механизм загрузки расширений отключён по умолчанию. Для включения механизма загрузки расширений используется следующий API:

int sqlite3_enable_load_extension(sqlite3 *db, int onoff);

Параметр onoff должен быть TRUE при загрузке расширения и FALSE при его отключении. Это позволяет программам, запускающим введённый пользователями SQL, обезопаситься от загрузки расширений. По умолчанию загружаемые расширения отключены на тот случай, если старые программы линкуются с новой версией SQLite. Это позволяет избежать потенциальных эксплойтов.

Пример расширения

Следующий код демонстрирует, как создавать загружаемое расширение:

#include <sqlite3ext.h>
SQLITE_EXTENSION_INIT1

/*
** SQL-функция half() возвращает половину от введённого значения.
*/
static void halfFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  sqlite3_result_double(context, 0.5*sqlite3_value_double(argv[0]));
}

/* SQLite выполняет эту программу только один раз в момент загрузки расширения.
** Можете создавать здесь новые функции, сортирующие последовательности и модули
** виртуальных таблиц. Обычно они экспортируются в разделяемую библиотеку.
*/
int sqlite3_extension_init(
  sqlite3 *db,
  char **pzErrMsg,
  const sqlite3_api_routines *pApi
){
  SQLITE_EXTENSION_INIT2(pApi)
  sqlite3_create_function(db, "half", 1, SQLITE_ANY, 0, halfFunc, 0, 0);
  return 0;
}

В приведённом выше примере зелёным цветом подсвечен тот код, который должен присутствовать в каждом загружаемом расширении. Код, подсвеченный синим цветом, реализует ваше расширение. В примере реализована единственная функция SQL, которая умножает введённый параметр на 0.5. Реальное загружаемое расширение может быть гораздо более полезным.

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

Заметьте, что расширение использует заголовочный файл "sqlite3ext.h" вместо "sqlite3.h". Это является важной особенностью. Динамически загружаемые расширения должны всегда использовать "sqlite3ext.h", в то время как статически линкуемые дополнения всегда используют "sqlite3.h". Если ваш код должен использоваться как в статической линковке, так и в качестве динамически загружаемого модуля, то необходимо использовать #ifdef, чтобы выполнить #include нужного заголовочного файла.

Символы SQLITE_EXTENSION_INIT1 и SQLITE3_EXTENSION_INIT2 являются макросами препроцессора C, которые переключают программный API на указатели функций в структуре "sqlite3_api_routines". Если вам это необходимо, вы можете посмотреть определения этих макросов в заголовочном файле "sqlite3ext.h", чтобы точно знать что они делают. В простейшем же случае, вы можете просто использовать их, как показано выше.

Как собрать загружаемое расширение в разделяемую библиотеку

Вам нужен заголовочный файл sqlite3ext.h, доступный в вашей системе. Если он еще не инсталлирован, вы можете найти его скачав амальгамацию SQLite (amalgamation). Будем считать, что он находится в директории sqlite3. Он должен быть той-же версии (или более старшей) что и sqlite3.h.

Имя файла расширения может быть любым на ваш выбор с традиционным расширением файла .so/.dll или чем-то более специфичным. Мы будем собирать half.sqlext из исходного кода half.c.

Использование GCC/MinGW под Windows и Linux
gcc -shared -fPIC -Isqlite3 -o half.sqlext half.c
Использование GCC под Mac OSX
gcc -bundle -fPIC -Isqlite3 -o half.sqlext half.c
Microsoft Tools под Windows
cl /Gd half.c /I sqlite3 /DDLL /LD /link /export:sqlite3_extension_init /out:half.sqlext

Запуск из командной строки

SQLite version 3.3.17
Enter ".help" for instructions
sqlite> .load half.sqlext
sqlite> select half(7);
3.5

Чего хотелось бы

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

Список разделяемых библиотек, которые должны быть загружены при открытии данной базы данных, можно хранить в специальной таблице SQLite. Эти разделяемые библиотеки расширений не должны иметь путей или суффиксов имен файлов (.dll или .so).

Пользователь должен иметь возможность установить эти библиотеки таким способом, как это предусмотрено в его ОС с использованием соответствующих механизмов загрузки (PATH, LD_LIBRARY_PATH и т.п.). Соответственно суффикс имени файла должен определяться при компиляции sqlite3 под конкретную платформу и может быть .dll, .so или чем-то еще.

Планируемая таблица может быть такой:

  create table sqlite_extensions (
    load INT,  -- Порядок, в котором должны загружаться/инициализироваться
               -- расширения. Сопоставленные меньшим числам должны загружаться
               -- первыми. Если эти числа равны, то загрузка происходит в
               -- алфавитном порядке по имени.

    name TEXT, -- Имя разделяемой библиотеки с расширением.
               -- ЗАМЕЧАНИЕ: путь и суффикс НЕ включаются в имя.

    init TEXT, -- Имя инициализирующей функции, входящей в разделяемую
               -- библиотеку. Необязательное поле, может быть NULL. В последнем
               -- случае функция точки входа должна быть сконструирована из
               -- имени.

    fini TEXT  -- Имя функции - точки входа в разделяемой библиотеке для
               -- выгрузки расширения. Расширения должны выгружаться в обратном
               -- порядке к их загрузке. Необязательное поле, может быть NULL.
  );

Перевод: Дмитрий Скоробогатов, 31.08.2011.
Оригинальный текст может быть найден по адресу http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions.


Предыдущие публикации:

Биржа долевых инвестиций SIMEX.

Последнее редактирование: 2011-08-31 06:35:15

Метки материала: sqlite, загружаемые расширения, расширения sqlite, базы данных, ит, по, программа, программы, it, приложение, софт, программирование, software, soft, программное обеспечение, db, разработка по, информационные технологии, c, спо, программное обеспечение по


2 комментария

02.09.2011 01:26:33 #
Mozilla Firefox dima
Пожалуйста Well
01.09.2011 02:34:23 #
Opera Гость Олег
Дмитрий,
Спасибо, будем изучать.

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

Представиться как     Антибот:
   

Просьба не постить мусор. Если вы хотите потестить xBB, воспользуйтесь кнопкой предварительного просмотра на панели инструментов xBBEditor-а.


© 2007-2017, Дмитрий Скоробогатов.
Разрешается воспроизводить, распространять и/или изменять материалы сайта
в соответствии с условиями GNU Free Documentation License,
версии 1.2 или любой более поздней версии, опубликованной FSF,
если только иное не указано в самих материалах.