Реализация функций на языке СИ для PostgreSQL на MS Visual Studio
В этой статье я попытаюсь осветить основные аспекты создания dll библиотек с функциями для PostgreSQL с использованием Microsoft VS. Функции можно использовать для определения собственных типов данных, обработки и индексирования данных и т.д. Для всего этого дела я использовал платформу Windows (после отладки вы без особого труда можете перекомпилировать свои творения на любую платформу, немного изменив код), PostgreSQL версии 9.0 (можно 8.4) и Microsoft Visual Studio 2010.
Для начала создадим новый проект в VS. В заготовках проектов для C++ выбираем «Win32 Project». Далее, в опциях мастера создания новых проектов, в типе приложения (Application Type) переключаем radio button на «DLL», а в дополнительных опциях ставим галочку на пункте «Пустой проект» (Empty Project). Затем создаём в папочке с исходниками(Source files) новый файлик «main.c». Вообще с давних пор в VS создаётся впечатление, что чистого Си в нём нет, и добавление Си файлов просходит путём создания файлов с разширением "*.cpp" и перемеинованием расширения в ".c".
Сейчас нам нужно подключить несколько библиотек к проекту. Сначала VS будет упорно ругаться на отсутствие данных файлов, но обращать на это внимание не стоит, т.к. чуть позже мы это победим. Добавляем следующий код в наш «main.c».
// Следующие два хидера принадлежат PostgreSQL и по умолчанию располагаются в {PostgreSQL_dir}\9.0\include\server
#include «postgres.h»
#include «fmgr.h»
// Так же нам понадобится «libintl.h», который можно найти в интернете. А можно и не искать, далее объясню почему.
#include «libintl.h»
Содержимое файла «libintl.h» в нашем проекте использоваться не будет, поэтому можно создать файл заглушку. Для этого в хидерах нашего проекта(Header Files) создаём файл заглушку с именем «libintl.h» и добавляем в него следующее:
#ifndef _LIBINTL_H
#define _LIBINTL_H
#endif
Теперь нам нужно объяснить VS в каких директориях ей следует искать наши библиотеки. Я буду приводить те пути, которые указаны у меня, вам же следует переделать их на свои. Для добавления директорий к библиотекам необходимо в пункте меню выбрать свойства проекта(Project\Properties). В открывшемся окне заходим в свойста директорий VS++ (VS++ directories) и добавляем в Include Directories следующее:
C:\Program Files\PostgreSQL\9.0\include\server\port\Win32
C:\Program Files\PostgreSQL\9.0\include\server\port
C:\Program Files\PostgreSQL\9.0\include\server
C:\Program Files\PostgreSQL\9.0\Include\internal
Для того чтобы PostgreSQL смог загрузить точки входа в функции, необходимо их экспортировать из dll и дополнительно сделать магический постгрес-define. Для этого пишем:
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
#if defined(_WIN32)
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif
Для того чтобы ускорить компиляцию можно добавить ещё пару дефайнов:
#define WIN32_LEAN_AND_MEAN
#define NOCOMM
Теперь нам необходимо подружить линковщик с библиотеками PostgreSQL. Для этого опять заходим в свойства проекта -> свойства линковщика(Linker) и добавляем ему следующую директорию с библиотеками(Additional Library Directories):
C:\Program Files\PostgreSQL\9.0\lib
Тут же выставляем Link Library Dependencies в «Yes». Затем заходим в свойства линковщика(Linker)-> Input и в поле Additional Dependencies вписываем «Postgres.lib». На этом с кучей ни разу не очевидных не сложных настроек VS покончено. Создадим наконец-то простую функцию в файле «main.c» для тестирования в PostgreSQL:
DLLEXPORT
int add_one (int arg) {
return arg + 1;
}
В этом месте всё должно скомпилироваться. Теперь копируем в C:\Program Files\PostgreSQL\9.0\lib\ получившуюся dll и переходим к PostgreSQL. Командуем ему:
CREATE or replace FUNCTION add_one(integer) RETURNS integer
AS '$libdir/mycool.dll', 'add_one'
LANGUAGE C STRICT;
SELECT add_one(99)
Если по непонятным причинам PostgreSQL скажет, что не нашёл dll, то следует заменить одинарный слеш, двойным. Если всё сделано правильно, то PostgreSQL выдаст нам число «100».
Для удобства можно переназначить путь создаваемой dll прямо в директорию с dll библиотеками PostgreSQL. Также следует помнить, что для замены нашей dll необходимо будет постоянно перезагружать сервер баз данных. Лично я, для удобства использовал бесплатную утилиту Unlocker для разблокировки dll, и после этого без проблем заменял её.
Для начала создадим новый проект в VS. В заготовках проектов для C++ выбираем «Win32 Project». Далее, в опциях мастера создания новых проектов, в типе приложения (Application Type) переключаем radio button на «DLL», а в дополнительных опциях ставим галочку на пункте «Пустой проект» (Empty Project). Затем создаём в папочке с исходниками(Source files) новый файлик «main.c». Вообще с давних пор в VS создаётся впечатление, что чистого Си в нём нет, и добавление Си файлов просходит путём создания файлов с разширением "*.cpp" и перемеинованием расширения в ".c".
Сейчас нам нужно подключить несколько библиотек к проекту. Сначала VS будет упорно ругаться на отсутствие данных файлов, но обращать на это внимание не стоит, т.к. чуть позже мы это победим. Добавляем следующий код в наш «main.c».
// Следующие два хидера принадлежат PostgreSQL и по умолчанию располагаются в {PostgreSQL_dir}\9.0\include\server
#include «postgres.h»
#include «fmgr.h»
// Так же нам понадобится «libintl.h», который можно найти в интернете. А можно и не искать, далее объясню почему.
#include «libintl.h»
Содержимое файла «libintl.h» в нашем проекте использоваться не будет, поэтому можно создать файл заглушку. Для этого в хидерах нашего проекта(Header Files) создаём файл заглушку с именем «libintl.h» и добавляем в него следующее:
#ifndef _LIBINTL_H
#define _LIBINTL_H
#endif
Теперь нам нужно объяснить VS в каких директориях ей следует искать наши библиотеки. Я буду приводить те пути, которые указаны у меня, вам же следует переделать их на свои. Для добавления директорий к библиотекам необходимо в пункте меню выбрать свойства проекта(Project\Properties). В открывшемся окне заходим в свойста директорий VS++ (VS++ directories) и добавляем в Include Directories следующее:
C:\Program Files\PostgreSQL\9.0\include\server\port\Win32
C:\Program Files\PostgreSQL\9.0\include\server\port
C:\Program Files\PostgreSQL\9.0\include\server
C:\Program Files\PostgreSQL\9.0\Include\internal
Для того чтобы PostgreSQL смог загрузить точки входа в функции, необходимо их экспортировать из dll и дополнительно сделать магический постгрес-define. Для этого пишем:
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
#if defined(_WIN32)
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif
Для того чтобы ускорить компиляцию можно добавить ещё пару дефайнов:
#define WIN32_LEAN_AND_MEAN
#define NOCOMM
Теперь нам необходимо подружить линковщик с библиотеками PostgreSQL. Для этого опять заходим в свойства проекта -> свойства линковщика(Linker) и добавляем ему следующую директорию с библиотеками(Additional Library Directories):
C:\Program Files\PostgreSQL\9.0\lib
Тут же выставляем Link Library Dependencies в «Yes». Затем заходим в свойства линковщика(Linker)-> Input и в поле Additional Dependencies вписываем «Postgres.lib». На этом с кучей ни разу не очевидных не сложных настроек VS покончено. Создадим наконец-то простую функцию в файле «main.c» для тестирования в PostgreSQL:
DLLEXPORT
int add_one (int arg) {
return arg + 1;
}
В этом месте всё должно скомпилироваться. Теперь копируем в C:\Program Files\PostgreSQL\9.0\lib\ получившуюся dll и переходим к PostgreSQL. Командуем ему:
CREATE or replace FUNCTION add_one(integer) RETURNS integer
AS '$libdir/mycool.dll', 'add_one'
LANGUAGE C STRICT;
SELECT add_one(99)
Если по непонятным причинам PostgreSQL скажет, что не нашёл dll, то следует заменить одинарный слеш, двойным. Если всё сделано правильно, то PostgreSQL выдаст нам число «100».
Для удобства можно переназначить путь создаваемой dll прямо в директорию с dll библиотеками PostgreSQL. Также следует помнить, что для замены нашей dll необходимо будет постоянно перезагружать сервер баз данных. Лично я, для удобства использовал бесплатную утилиту Unlocker для разблокировки dll, и после этого без проблем заменял её.
0 комментариев