PostgreSql扩展Sql-动态加载共享库(C函数)
- 基于 psql (PostgreSQL) 10.4
pg_language表定义了函数实现所使用的语言。主要支持了C语言和SQL语句。一些可选的语言包括pl/pgsql、tcl和perl。
ligang=# select lanname, lanispl, lanpltrusted, lanplcallfoid, laninline, lanvalidator from pg_language;
lanname | lanispl | lanpltrusted | lanplcallfoid | laninline | lanvalidator
----------+---------+--------------+---------------+-----------+--------------
internal | f | f | 0 | 0 | 2246
c | f | f | 0 | 0 | 2247
sql | f | t | 0 | 0 | 2248
plpgsql | t | t | 13198 | 13199 | 13200
pg_proc表对函数进行了定义。每一个函数在该表中都对应一个元组,包含函数名。输入参数类型,返回类型以及对函数的定义(可能是文本,可能是一段编译型语句,也可能是对可执行代码的引用)。编译过的函数可以静态地链接到服务器上,或者在存储在共享库内,当第一次使用该库时动态的载入。
ligang=# select proname,prolang, prorettype,proargtypes, prosrc,probin from pg_proc where proname like '%square%';
proname | prolang | prorettype | proargtypes | prosrc | probin
---------+---------+------------+-------------+----------------------------+--------------------
square | 13201 | 23 | 23 | begin return $1 * $1; end; |
squares | 13 | 23 | 23 | squares_return_int | $libdir/squares.so
查看其数据类型
ligang=# select oid , typname from pg_type where oid = 23;
oid | typname
-----+---------
23 | int4
(1 row)
以下是示例函数:
C: 与内建SQL类型等效的C类型
int
square_int (int x)
{
return x * x;
}
把上面的函数编译成共享库文件,这样声明:
CREATE FUNCTION square(int) RETURNS int
AS '/path/to/square.so', 'square_int'
LANGUAGE 'C';
PL/PGSQL:
ligang=# create function square(int) returns int as 'begin return $1 * $1; end;' LANGUAGE 'plpgsql';
CREATE FUNCTION
ligang=#
ligang=#
ligang=# select square(4);
square
--------
16
建立用户函数动态库
新建代码
#include "postgres.h"
#include "fmgr.h"int
square_int(int x)
{
return x * x;
}
编译 - 添加共享库
[ligang@yfslcentos71 include]$ gcc -I`pg_config --includedir-server` -c squares.c
[ligang@yfslcentos71 include]$ gcc -shared squares.o -o squares.so
[ligang@yfslcentos71 include]$ cp squares.so `pg_config --libdir`/
Pg数据库装载
ligang=# create function squares(int) returns int as '$libdir/squares.so', 'square_int' LANGUAGE 'c' STRICT;
关于PG_MODULE_MAGIC
为了确保不会错误加载共享库文件,从PostgreSQL 开始将检查那个文件的"magic block",这允许服务器以检查明显的不兼容性。
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
如果不打算兼容8.2 PostgreSQL之前的版本, #ifdef测试也可以省略
源码修改为:
#include "postgres.h"
#include "fmgr.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
int
square_int(int x)
{
return x * x;
}
版本约定
版本0约定
版本-0方法中,此风格 C 函数的参数和结果用普通 C 风格声明, 但是要小心使用上面显示的 SQL 数据类型的 C 表现形式。 (以前版本;)
#include "postgres.h"
#include "fmgr.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
int
square_int(int x)
{
return x * x;
}
版本1约定 (应当使用该版本)
版本-1调用约定使用宏消除大多数传递参数和结果的复杂性。版本-1风格函数的C定义总是下面这样:
Datum funcname(PG_FUNCTION_ARGS);
另外,宏调用:
PG_FUNCTION_INFO_V1(funcname);
也必须出现在同一个源文件里(通常就可以写在函数自身前面)。 对那些internal语言函数而言,不需要调用这个宏, 因为PostgreSQL目前假设内部函数都是版本-1。不过,对于动态加载的函数, 它是必须的。
每个实际参数都是用一个对应该参数的数据类型的 PG_GETARG_xxx()宏抓取的, 用返回类型的PG_RETURN_xxx()宏返回结果。 PG_GETARG_xxx()接受要抓取的函数参数的编号 (从 0 开始)作为其参数。PG_RETURN_xxx() 接受实际要返回的数值为自身的参数。
关于PG_GETARG_XXX 定义于 src/include/fmgr.h
/* Macros for fetching arguments of standard types */
#define PG_GETARG_DATUM(n) (fcinfo->arg[n])
#define PG_GETARG_INT32(n) DatumGetInt32(PG_GETARG_DATUM(n))
#define PG_GETARG_UINT32(n) DatumGetUInt32(PG_GETARG_DATUM(n))
#define PG_GETARG_INT16(n) DatumGetInt16(PG_GETARG_DATUM(n))
#define PG_GETARG_UINT16(n) DatumGetUInt16(PG_GETARG_DATUM(n))
#define PG_GETARG_CHAR(n) DatumGetChar(PG_GETARG_DATUM(n))
#define PG_GETARG_BOOL(n) DatumGetBool(PG_GETARG_DATUM(n))
#define PG_GETARG_OID(n) DatumGetObjectId(PG_GETARG_DATUM(n))
#define PG_GETARG_POINTER(n) DatumGetPointer(PG_GETARG_DATUM(n))
#define PG_GETARG_CSTRING(n) DatumGetCString(PG_GETARG_DATUM(n))
#define PG_GETARG_NAME(n) DatumGetName(PG_GETARG_DATUM(n))
/* these macros hide the pass-by-reference-ness of the datatype: */
#define PG_GETARG_FLOAT4(n) DatumGetFloat4(PG_GETARG_DATUM(n))
#define PG_GETARG_FLOAT8(n) DatumGetFloat8(PG_GETARG_DATUM(n))
#define PG_GETARG_INT64(n) DatumGetInt64(PG_GETARG_DATUM(n))
/* use this if you want the raw, possibly-toasted input datum: */
#define PG_GETARG_RAW_VARLENA_P(n) ((struct varlena *) PG_GETARG_POINTER(n))
/* use this if you want the input datum de-toasted: */
#define PG_GETARG_VARLENA_P(n) PG_DETOAST_DATUM(PG_GETARG_DATUM(n))
/* and this if you can handle 1-byte-header datums: */
#define PG_GETARG_VARLENA_PP(n) PG_DETOAST_DATUM_PACKED(PG_GETARG_DATUM(n))
代码
#include "postgres.h"
#include "fmgr.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(squares_return_int);
Datum squares_return_int(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);
PG_RETURN_INT32(arg * arg);
}
编译
[ligang@yfslcentos71 include]$ gcc -I`pg_config --includedir-server` -c squares.c
[ligang@yfslcentos71 include]$ gcc -shared squares.o -o squares.so
/usr/bin/ld: squares.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
squares.o: could not read symbols: Bad value
[ligang@yfslcentos71 include]$ gcc -I`pg_config --includedir-server` -fPIC -c squares.c
[ligang@yfslcentos71 include]$ gcc -shared squares.o -o squares.so
[ligang@yfslcentos71 include]$
[ligang@yfslcentos71 include]$ cp squares.so `pg_config --libdir`/
SQL声明函数
ligang=# create function squares(int) returns int as '$libdir/squares.so', 'squares_return_int' LANGUAGE 'c' STRICT;
CREATE FUNCTION
补充
- 函数声明为"strict"(严格),意思是说如果任何输入值为NULL, 那么系统应该自动假设一个NULL的结果。这样处理可以让我们避免在函数代码里面检查 NULL输入。如果不这样处理,我们就得明确检查NULL, 比如为每个传递引用的参数检查空指针。对于传值类型的参数,我们甚至没有办法检查!
参考Postgresql 9.4手册
PostgreSql扩展Sql-动态加载共享库(C函数)的更多相关文章
- Linux 动态加载共享库
- C++ ACE 动态加载链接库
添加头文件 #include <ace/DLL.h> #include <ace/DLL_Manager.h> 定义函数接口 typedef long (*PFN_TEST)( ...
- QTP动态加载对象库
Public Function AddObjectRepository(path) On Error Resume Next Dim pos, repath If instr(path,". ...
- windows/Linux动态加载链接库问题
windows: LoadLibraryA 指定的可执行模块映射到调用进程的地址空间并返回该 DLL 的句柄 HMODULE LoadLibraryA( LPCTSTR lpLibFileName// ...
- 谈谈动态地加载Jquery库文件的方法
有时候,我们可能不会在网页中<script src="jquery.min.js" 来加载 Jquery 库,可能在用户点击某个按钮后,才去加载 Jquery 库. 好处不用 ...
- Ext JS学习第十天 Ext基础之动态加载JS文件(补充)
此文用来记录学习笔记: •Ext4.x版本提供的一大亮点就是Ext.Loader这个类的动态加载机制!只要遵循路径规范,即可动态加载js文件,方便把自己扩展组件动态加载进来,并且减轻浏览器的压力. • ...
- GDB调试工具、动态加载、内存管理(day04)
一.程序中的错误处理 在系统中定义了一个全局变量errno.在这个全局变量中存放着系统调用或者库函数出错的信息(错误编号).然后根据错误编号获取错误信息. 举例说明: 打开一个文件,如果这个文件不存在 ...
- [转] c++加载外部库文件探究
首先介绍:用#import导入dll和用#pragma comment导入lib还有在程序中LoadLibrary加载dll有什么区别 (1) #import导入的dll是com组建的dll,主要用来 ...
- Qt动态连接库/静态连接库创建与使用,QLibrary动态加载库
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt动态连接库/静态连接库创建与使用,QLibrary动态加载库 本文地址:https ...
随机推荐
- C# 如何更改Word语言设置
一般在创建或者打开一个Word文档时,如果没有进行过特殊设置的话,系统默认的输入语言的是英语输入,但是为适应不同的办公环境,我们其实是需要对文字嵌入的语言进行切换的,因此,本文将介绍如何使用免费版组件 ...
- Spring Boot使用AOP在控制台打印请求、响应信息
AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等. AOP简介 AOP全称Aspect Oriented Programming,面向切面,AOP主要实现的 ...
- Java 学习笔记 二维数组和对象数组
定义二维数组 int[][] a = new int[4][5]; 可以不指定列数 int[][] a = new int[4][]; 获取行 int i = a.length(); 如果使用第一个例 ...
- Maven(十二)Maven 依赖详解
依赖的传递性 注意1:在Eclipise创建的Maven项目,若依赖eclipse空间中其他自己创建的 的项目时,此时并不会报错,但是当执行mvn compile命令时还是会显示缺失败.所以依赖的其他 ...
- LeetCode 176. 第二高的薪水(MySQL版)
0.前言 最近刷LeetCode 刷数据库题目 由于数据库课上的是SQL,而MySQL有许多自己的函数的,怕把刚学会的函数忘记 特在此记录! 1.题目 编写一个 SQL 查询,获取 Employee ...
- FragmentActivity + Fragment + Fragment使用过程中出现的bug
FragmentActivity + Fragment(通过hide和show来显示fragment) + Fragment(通过viewpager来显示fragment) 在Activity中 // ...
- C# 类如何声明索引器以提供对类的类似数组的访问的代码
研发期间,将内容过程中比较常用的内容段做个收藏,如下内容内容是关于 C# 类如何声明索引器以提供对类的类似数组的访问.的内容,希望能对各位有用处. using System;using System. ...
- 设计模式系列之单例模式(Singleton Pattern)
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.这种模式涉及到一个单一的类,该类负责创建自己的对象 ...
- SQL Server 数据库部分常用语句小结(一)
1. 查询某存储过程的访问情况 SELECT TOP 1000 db_name(d.database_id) as DBName, s.name as 存储名字, s.type_desc as 存储类 ...
- C# 反射的例子
通过字符串变量访问控件 string t = "textbox1"; TextBox tb = (TextBox)this.GetType().GetField(t, System ...