279
![]() |
|
|||
WebMoney: WMZ Z294115950220 WMR R409981405661 WME E134003968233 |
Visa 4274 3200 2453 6495 |
У SQLite есть способность загрузить расширения (включая новые
определенные применением функции SQL,
последовательности сопоставления,
виртуальные таблицы и VFS)
во время выполнения. Эта особенность позволяет коду
расширений быть разработанным и проверенным отдельно от применения и
затем загруженным по мере необходимости. Расширения могут также быть статически связаны с применением.
Кодовый шаблон, показанный ниже, будет работать точно так же как статически
связанное расширение, как загружаемое расширение во время выполнения за
исключением того, что необходимо дать функцию точке входа
("sqlite3_extension_init") другое имя, чтобы избежать столкновений имени,
если приложение содержит два или больше расширения. Расширение SQLite это общая библиотека или DLL.
Чтобы загрузить его, необходимо поставлять SQLite название
файла, содержащего общую библиотеку или DLL и точку входа, чтобы
инициализировать расширение. В коде C эта информация предоставляется,
используя sqlite3_load_extension()
API. Обратите внимание на то, что различные операционные системы используют
различные суффиксы имени файла для своих общих библиотек. Windows использует
".dll", Mac ".dylib" и большинство unix ".so". Если вы хотите сделать свой
код портативным, можно опустить суффикс от общего имени файла библиотеки, и
соответствующий суффикс будет добавлен автоматически
sqlite3_load_extension(). Есть также функция SQL, которая может использоваться, чтобы загрузить
расширения: load_extension(X,Y)
. Это работает точно так же, как
sqlite3_load_extension(). Оба метода для загрузки расширения позволяют вам определять название точки
входа для расширения. Можно оставить этот незаполненный аргумент передав
NULL в sqlite3_load_extension()
или опустив второй аргумент в
load_extension(),
и дополнительная логика загрузчика попытается выяснить точку входа
самостоятельно. Это сначала попробует универсальное дополнительное имя
"sqlite3_extension_init". Если это не работает, это строит точку входа,
используя шаблон "sqlite3_X_init", где X заменяются строчным эквивалентом
каждого символа ASCII в имени файла после последнего "/" и перед
первым следующим "." за исключением первых трех знаков, если они,
"lib". Так, например, если имя файла "/usr/lib/libmathfunc-4.8.so",
имя точки входа было бы "sqlite3_mathfunc_init".
Или если бы имя файла "./SpellFixExt.dll", точку входа назвали бы
"sqlite3_spellfixext_init". Из соображений безопасности загрузка выключена по умолчанию. Чтобы
использовать функции загрузки расширения SQL, нужно сначала позволить
загрузку расширения, используя
sqlite3_db_config(db,
SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION,1,NULL)
C API в вашем приложении. Из оболочки командной строки расширения могут быть
загружены, используя команду ".load": Обратите внимание на то, что программная оболочка командной строки уже
позволила загрузку расширения для вас (вызвав
sqlite3_enable_load_extension()
как часть его установки), так команда выше работает без любых
специальных выключателей, установки или других осложнений. Команда ".load" с одним аргументом вызывает sqlite3_load_extension() с
zProc = NULL, заставляя SQLite сначала искать точку входа, названную
"sqlite3_extension_init", а затем "sqlite3_X_init", где "X"
получен из имени файла. Если у вашего расширения есть точка входа с другим
именем, просто поставляйте то имя как второй аргумент. Например: Загружаемые расширения это код на C. Чтобы собрать их на большинстве
подобных Unix операционных систем, обычная команда что-то вроде этого: Mac подобны unix, но они не следуют обычным общим соглашениям библиотеки.
Чтобы собрать общую библиотеку на Mac, используйте команду: Если, когда вы пытаетесь загрузить свою библиотеку, вы возвращаете
сообщение об ошибке, в котором говорится "mach-o, but wrong architecture",
вы, возможно, должны были бы добавить параметры командной строки
"-arch i386" или "arch x86_64" для gcc, в зависимости от того, как
ваше приложение создается. Чтобы собрать на Windows, используя MSVC, команда, подобная следующей,
будет обычно работать: Чтобы собрать для использования Windows MinGW, командная строка
точно так же, как для Unix за исключением того, что суффикс выходного файла
меняется на ".dll" и не нужен параметр -fPIC: Шаблон загружаемого расширения содержит следующие три элемента: Используйте "#include <sqlite3ext.h>" в начале
своих файлов исходного кода вместо "#include <sqlite3.h>
". Поместите макрос "SQLITE_EXTENSION_INIT1" на строку
прямо после "#include <sqlite3ext.h>". Добавьте расширение, загружающее установленный код
точки входа, который похож на что-то следующее: Желательно настроить название вашей точки входа, чтобы соответствовать
названию общей библиотеки, которую вы будете производить, вместо того, чтобы
использовать универсальное имя "sqlite3_extension_init".
Предоставление расширению своей точки входа позволит вам статически связать
два или больше расширения в ту же самую программу без конфликта компоновщика,
если вы позже решите использовать статическое подключение, а не динамическое.
Если ваша общая библиотека была названа "YourCode.so", "YourCode.dll" или
"YourCode.dylib", как показано в примерах компилятора выше, то правильное имя
точки входа было бы "sqlite3_yourcode_init". Вот полный шаблон расширения, что вы можете
скопировать/вставить, чтобы начать: Много примеров полных и рабочих загружаемых расширений могут быть
найдены в исходном дереве SQLite в подкаталоге
ext/misc.
Каждый файл в том каталоге это отдельное расширение.
Документация предоставлена заголовком, комментирующим файл.
Вот краткие обзоры на нескольких расширений в
ext/misc:
carray.c — реализует табличную функцию
carray.
compress.c — реализует определенные
приложением функции SQL compress() и uncompress(), которые делают
zLib-сжатие содержания text или blob. json1.c
— реализует JSON-функции SQL и
табличные функции.
Это большее и более сложное расширение.
memvfs.c — реализует новую VFS,
которая хранит все содержание в памяти. rot13.c
— реализует SQL-функцию
rot13(). Это очень простой пример дополнительной функции и полезно как
шаблон для создания новых расширений. series.c
— реализует generate_series виртуальной
таблицы и табличной функции.
Это относительно простой пример виртуального внедрения таблицы, которое может
служить шаблоном для написания новых виртуальных таблиц. Другие и более сложные расширения могут быть найдены в подпапках под
каталогом ext/
кроме ext/misc/.
Поведение по умолчанию для загружаемого расширения состоит в том, что оно
выгружено из памяти процесса, когда соединение с базой данных, которое
первоначально вызвало
sqlite3_load_extension(), закрыто. Другими словами, метод xDlClose
объекта sqlite3_vfs вызывают для всех
расширений, когда соединение с базой данных закрывается.
Однако, если процедура инициализации возвратит
SQLITE_OK_LOAD_PERMANENTLY
вместо SQLITE_OK, то расширение не будет выгружено (xDlClose не будет вызван)
и расширение останется в памяти процесса неопределенно долго.
Возвращаемое значение SQLITE_OK_LOAD_PERMANENTLY полезно для расширений,
которые хотят зарегистрировать новую VFS. Расширение, для которого функция инициализации возвращает
SQLITE_OK_LOAD_PERMANENTLY, продолжает существовать в памяти после того, как
соединение с базой данных закрывается. Однако, расширение
автоматически не зарегистрировано в последующих соединениях с базой
данных. Это позволяет загрузить расширения, которые осуществляют новые
VFS. Чтобы постоянно загрузить и зарегистрировать
расширение, которое осуществляет новые функции SQL, сопоставляя
последовательности и/или виртуальные таблицы, чтобы те добавленные
возможности были доступны всем последующим соединениям с базой данных, код
инициализации должен также вызвать
sqlite3_auto_extension()
в подфункции, которая зарегистрирует те услуги. vfsstat.c
показывает пример загружаемого расширения, которое постоянно регистрирует
новую VFS и новый виртуальную таблицу.
sqlite3_vfsstat_init(). Код инициализации в том расширении вызывают
только однажды, когда расширение сначала загружается. Это регистрирует новую
VFS "vfslog" и возвращает SQLITE_OK_LOAD_PERMANENTLY так, чтобы код
, используемый, чтобы осуществить "vfslog" VFS, остался в памяти.
Установленный порядок инициализации также вызывает
sqlite3_auto_extension()
на указателе на функцию "vstatRegister()", чтобы все последующие соединения
с базой данных вызвали функцию "vstatRegister()", когда запускаются
и следовательно зарегистрировали виртуальную таблицу "vfsstat".
Тот же самый исходный код может использоваться и для загружаемой общей
библиотеки во время выполнения или DLL и как модуль, который статически
связан с вашим приложением. Это обеспечивает гибкость и позволяет вам снова
использовать тот же самый код по-разному. Чтобы статически связать ваше расширение, просто добавьте опцию компиляции
-DSQLITE_CORE. Макрос SQLITE_CORE заставляет SQLITE_EXTENSION_INIT1 и макрос
SQLITE_EXTENSION_INIT2 ничего не делать. Тогда измените свое приложение,
чтобы вызвать точку входа непосредственно, передавая NULL как третий
параметр "pApi". Особенно важно использовать имя точки входа, которое основано на
дополнительном имени файла, а не универсальное
"sqlite3_extension_init", если вы будете статически связывать два или больше
расширения. Если вы будете использовать родовое название, будут повторные
определения того же самого символа, и связь потерпит неудачу. Если вы будете открывать многократные соединения с базой данных в своем
приложении вместо того, чтобы вызвать дополнительные точки входа для каждого
соединения с базой данных отдельно, вы могли бы хотеть рассмотреть
использование sqlite3_auto_extension()
, чтобы зарегистрировать ваши расширения и заставить их быть
автоматически начатыми, когда каждое соединение с базой данных открыто.
Только необходимо зарегистрировать каждое расширение однажды, и можно сделать
так около начала функции main(). Применение
sqlite3_auto_extension(),
чтобы зарегистрировать ваши расширения заставляет ваши расширения работать,
как будто они были встроены в основной SQLite:
они автоматически существуют каждый раз, когда вы открываете новое соединение
с базой данных, дополнительно инициализировать ничего не надо.
Просто обязательно закончите любую конфигурацию
sqlite3_config() прежде, чем зарегистрировать расширения.
sqlite3_auto_extension()
неявно называет sqlite3_initialize(). SQLite осуществляет загрузку расширения во время выполнения, используя
методы xDlOpen(), xDlError(), xDlSym() и xDlClose() объекта
sqlite3_vfs.
Эти методы осуществляются, используя библиотеку
dlopen() в unix (это объясняет, почему SQLite обычно должен связываться
с библиотекой "-ldl" в unix) или LoadLibrary() API в Windows.
В своей VFS для необычных систем эти методы могут все
быть опущены, в этом случае механизм загрузки расширения во время выполнения
не будет работать (хотя вы все еще будете в состоянии статически связать
дополнительный код, предполагая, что указатели входа имеют уникальные
имена). SQLite может быть собран с
SQLITE_OMIT_LOAD_EXTENSION,
чтобы опустить код загрузки расширения.
Choose any three.
1. Обзор
2. Загрузка расширения
.load ./YourCode
.load ./YourCode nonstandard_entry_point
3.
Компилирование загружаемого расширения
gcc -g -fPIC -shared YourCode.c -o YourCode.so
gcc -g -fPIC -dynamiclib YourCode.c -o YourCode.dylib
cl YourCode.c -link -dll -out:YourCode.dll
gcc -g -shared YourCode.c -o YourCode.dll
4.
Программирование загружаемых расширений
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_extension_init( /* <== Change this name, maybe */
sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi)
{
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
/* insert code to initialize your extension here */
return rc;
}
/* Add your header comment here */
#include <sqlite3ext.h> /* Do not use <sqlite3.h>! */
SQLITE_EXTENSION_INIT1
/* Insert your extension code here */
#ifdef _WIN32
__declspec(dllexport)
#endif
/* TODO: Change the entry point name so that "extension" is replaced by
** text derived from the shared library filename as follows: Copy every
** ASCII alphabetic character from the filename after the last "/" through
** the next following ".", converting each character to lowercase, and
** discarding the first three characters if they are "lib".
*/
int sqlite3_extension_init(sqlite3 *db, char **pzErrMsg,
const sqlite3_api_routines *pApi)
{
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
/* Insert here calls to
** sqlite3_create_function_v2(),
** sqlite3_create_collation_v2(),
** sqlite3_create_module_v2(), and/or
** sqlite3_vfs_register()
** to register the new features that your extension adds.
*/
return rc;
}
4.1. Пример расширения/h2>
5.
Постоянные загружаемые расширения
6. Статически связывая загружаемое расширение во время выполнения
7. Детали внедрения