开发环境
- PostgreSQL以后简称PG
程序目录:C:\pgsql
数据目录:E:/pgdata
- Visual Studio 2015,以后简称VS
特别注意:
-
Windows下安装的PG没法用VS调试,因此不需要Debug版本,如果自己编译另说
-
调试使用PG自带函数elog,用法和C语言的printf一样,就像最早的js一样,调试用alter(xxx)
-
PG插件一般用C语言开发,不是C++,非要用也行,不过不建议
-
**数据库程序一般是重度内存使用者,现在一般都是64位的,因此只需要x64的版本 **
-
PG插件内存分配不建议使用malloc和free,一定要用也行
-
PG插件内存分配使用palloc或palloc0,不需要检查是否返回是否成功,分配完成后直接使用,分配失败函数内部已经检查
-
PG插件palloc或palloc0分配的内存可以不释放(当前会话断开时会自动释放).但是还是建议除函数返回值外使用完成后调用PG函数pfree释放分配的内存
#1 创建项目
创建一个空项目,创建成功选择项目属性,修改以下配置: -
修改配置为Release
-
修改平台为X64
-
将常规-配置类型更改为"动态库(.dll)"
#2 设置包含目录
C:\pgsql\include\server\port\win32_msvc
C:\pgsql\include\server\port\win32
C:\pgsql\include
C:\pgsql\include\server
#3 设置附加库目录
C:\pgsql\lib
附加依赖项
postgres.lib
ws2_32.lib
ws2_32.lib是因为使用了gethostname函数才需要的,你可以根据自己的需求设置
#4 创建扩展
PG插件可以C/C++混编,担是入口函数必须是C风格的函数,如果使用cpp也要注意修改Makefile
现在示例创建一个简单和扩展,只有一个获取服务器主机名的函数hostname.博主设置的项目名称为pg_kmcb.
新建一个名称为pg_function.c文件,内容为
#include "postgres.h"
#include "fmgr.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
/*获取主机名函数*/
PGDLLEXPORT Datum hostname(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(hostname);
/*获取主机名*/
Datum hostname(PG_FUNCTION_ARGS) {
text *result;
size_t len;
char buf[MAX_HOST_SIZE + sizeof(char)];
gethostname(buf, MAX_HOST_SIZE);
len = strlen(buf);
//elog(NOTICE, "hostname=%s\n",buf);
result = (text *)palloc(len + VARHDRSZ);
SET_VARSIZE(result, len + VARHDRSZ);
memcpy(VARDATA(result), buf, len);
PG_RETURN_TEXT_P(PointerGetDatum(result));
}
注意看elog的用法
新建一个名称为pg_kmcb.control的控制文件,内容为
comment = '自定义C风格的函数'
default_version = '1.0'
module_pathname = '$libdir/pg_kmcb'
relocatable = true
pg_kmcb为项目名称 ,也是编译好的dll文件名.
新建一个名称为pg_kmcb–1.0.sql的sql文件,用于在pg中创建函数hostname
/*获取主机名*/
create function hostname()
returns text
as 'pg_kmcb', 'hostname'
language C immutable strict;
新建Makefile文件,在linux中才使用,Windows不需要
MODULE_big = pg_kmcb
OBJS = pg_function.o
--如果有多个C文件,可以在OBJS里写多个,用空格分开
VRESION=1.0
EXTENSION = pg_kmcb
DATA = pg_kmcb--1.0.sql
ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/pg_kmcb
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
好了,现在一个简单的扩展就完成了.
#5 其它
每次修改并生成成功后,要停止PG,然后做以下操作
copy pg_kmcb.dll “C:\pgsql\lib”
copy pg_kmcb.control “C:\pgsql\share\extension”
copy pg_kmcb–1.0.sql “C:\pgsql\share\extension”
为方便使用,可以在VS项目属性-生成事件-后期生成事件-命令行中填写以下内容实现自动部署
if exist "E:\pgdata\postmaster.pid" "C:\pgsql\bin\pg_ctl.exe" -m fast -D "E:\pgdata" stop
copy "D:\MyWork\2017C++\x64\Release\pg_kmcb.dll" "C:\pgsql\lib"
copy "D:\MyWork\2017C++\pg_kmcb\pg_kmcb.control" "C:\pgsql\share\extension\"
copy "D:\MyWork\2017C++\pg_kmcb\pg_kmcb--1.0.sql" "C:\pgsql\share\extension\"
细心的同学可能已经看到没有数据库启动命令,在VS中启动数据会导致VS无法编译,因此启动数据库用一个cmd手动启动,每次编译完成后,在cmd里执行
C:\pgsql\bin\pg_ctl.exe -D E:/pgdata start
第一次使用要在需要的数据库中创建扩展,以后除非新加函数,否则不需要再次创建扩展.
drop extension if exists pg_kmcb;
create extension pg_kmcb;