Postgresql扩展Sql-源码添加系统函数

PostgreSql 源码增添新的系统函数

  • 基于Postgresql 10.4
  • 基于 psql (PostgreSQL) 11beta2

函数实现:

  • 第一种: 添加于 backend/utils/adt/pgstatfuncs.c;

    1
    2
    3
    4
    5
    6
    // 函数实现;  
    Datum
    return_pid(PG_FUNCTION_ARGS)
    {  
    PG_RETURN_INT32(MyProcPid);
    }
  • 第二种: 新建 .c 文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include "postgres.h"

    #include <sys/file.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <dirent.h>

    #include "access/heapam.h"
    #include "catalog/pg_type.h"
    #include "funcapi.h"
    #include "miscadmin.h"
    #include "postmaster/syslogger.h"
    #include "storage/fd.h"
    #include "utils/builtins.h"

    Datum
    return_pid(PG_FUNCTION_ARGS)
    {  
    PG_RETURN_INT32(MyProcPid);
    }

    需要在Makefile文件中增加对其.c文件的编译引用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # keep this list arranged alphabetically or it gets to be a mess
    OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
    array_typanalyze.o array_userfuncs.o arrayutils.o ascii.o \
    bool.o cash.o char.o cryptohashes.o \
    date.o datetime.o datum.o dbsize.o domains.o \
    encode.o enum.o expandeddatum.o expandedrecord.o \
    float.o format_type.o formatting.o genfile.o \
    geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
    int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
    jsonfuncs.o like.o lockfuncs.o mac.o mac8.o misc.o nabstime.o name.o \
    network.o network_gist.o network_selfuncs.o network_spgist.o \
    numeric.o numutils.o oid.o oracle_compat.o \
    orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
    pgstatfuncs.o \
    pseudotypes.o quote.o rangetypes.o rangetypes_gist.o \
    rangetypes_selfuncs.o rangetypes_spgist.o rangetypes_typanalyze.o \
    regexp.o regproc.o ri_triggers.o rowtypes.o ruleutils.o \
    selfuncs.o tid.o timestamp.o trigfuncs.o \
    tsginidx.o tsgistidx.o tsquery.o tsquery_cleanup.o tsquery_gist.o \
    tsquery_op.o tsquery_rewrite.o tsquery_util.o tsrank.o \
    tsvector.o tsvector_op.o tsvector_parser.o \
    txid.o uuid.o varbit.o varchar.o varlena.o version.o \
    windowfuncs.o xid.o xml.o <page_mr.o> ##新增;

支持外部访问

  • 增加外部调用声明 backend/utils/fmgrprotos.h

    1
    extern Datum return_pid(PG_FUNCTION_ARGS);

参数

1
2
3
4
5
//定义 OID
backend/utils/fmgroids.h:2588: #define F_RETURN_PID 54336

//定义参数;
backend/utils/fmgrtab.c:2833: { 54336, "return_pid", 0, true, false, return_pid }
  • 关于OID添加: 参考后文补充;

注册到命令空间

PostgreSQL 11beta2
  • 用于生成注册信息, 注册到命令空间 include/catalog/pg_proc.dat
1
2
3
4
//用于生成pg_proc 表信息;   -- 注册到命令空间
{ oid => '54336', descr => 'statistics: current backend PID',
proname => 'return_pid', provolatile => 's', proparallel => 'r',
prorettype => 'int4', proargtypes => '', prosrc => 'return_pid' },
Postgresql 10.4
  • include/catalog/pg_proc.h
    1
    DATA(insert OID = 2026 (  pg_backend_pid				PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_backend_pid _null_ _null_ _null_ ));
  • 在pg_proc.h中插入的记录是什么含义?

    以第一行为例详细说明如下:
    DATA(insert OID = 13624 ( sys_read_page PGNSP 0 PGUID 12 t f f f t f v 2 17 17 i f i f f “25 20 20” null null null null null null sys_read_page 2D null ));

    13624–OID使用内核中未使用的OID即可(src/include/catalog下unused_oids,可以显示未使用的oid) postgres内部预留了1W多个oid给系统用,选一个没有的就行,如果不知道哪些可用,在\src\include\catalog\ 下有个脚本文件unused_oids,运行一下就能找出哪些oid可用,但要这是一个linux脚本,需要在linux下运行。

    PGNSP–函数所属的名字空间的OID,PGNSP即pg_catalog(oid=11),内置函数添加此值固定

    PGUID–函数的拥有者OID,PGUID及initdb时指定用户(oid=10),内置函数添加此值固定

    12–实现语言或该函数的调用接口,内置函数使用12(internal),SQL用14

    t–函数是否为一个聚集函数
    f–函数是否为一个窗口函数
    f–函数是一个安全性定义者(即,一个”setuid”函数)
    f–该函数没有副作用。除了通过返回值,没有关于参数的信息被传播。任何会抛出基于其参数值的错误信息的函数都不是泄露验证的。
    t–当任意调用函数为空时,函数是否会返回空值。在那种情况下函数实际上根本不会被调用。非”strict”函数必须准备好处理空值输入。
    f–函数是否返回一个集合(即,指定数据类型的多个值)
    v–未知

    2–输入参数的个数,对应后面的”“25 20 20”“两个参数,明显我们这里写错了,找到了原因,我们修改为我们对应的参数个数和类型:

    17–具有默认值的参数个数
    17–返回值的数据类型

    “25 20 20”–函数参数的数据类型的数组,这只包括输入参数(含INOUT和VARIADIC参数),因此也表现了函数的调用特征 重载函数也凭这区别,如果有多个,参数肯定不同,这个不同即可以是数量不同,也可以是类型不同,25 20 20 就是代表类型,如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    TEST=# select oid,typname from pg_type where oid in (1082,23,1114,1184,17,25);
    OID | TYPNAME
    ------+-------------
    17 | BYTEA
    23 | INT4
    25 | TEXT
    1082 | DATE
    1114 | TIMESTAMP
    1184 | TIMESTAMPTZ

    null–函数参数的数据类型的数组,这包括所有参数(含OUT和INOUT参数)。但是,如果所有参数都是IN参数,这个域将为空。注意下标是从1开始 ,然而由于历史原因proargtypes的下标是从0开始

    null–函数参数的模式的数组。编码为: i表示IN参数 , o表示OUT参数, b表示INOUT参数, v表示VARIADIC参数, t表示TABLE参数。 如果所有的参数都是IN参数,这个域为空。注意这里的下标对应着proallargtypes而不是proargtypes中的位置

    null–函数参数的名字的数组。没有名字的参数在数组中设置为空字符串。如果没有一个参数有名字,这个域为空。注意这里的下标对应着proallargtypes而不是proargtypes中的位置

    null–默认值的表达式树(按照nodeToString()的表现方式)。这是一个pronargdefaults元素的列表,对应于最后N个input参数(即最后N个proargtypes位置)。如果没有一个参数具有默认值,这个域为空

    null–数据类型OID为了应用转换

验证

  1. 关闭Pg服务 pg_ctl
  2. 重新编译源代码 ; make && make install
  3. 重新创建新的数据集簇 initdb -D test; createdb test
  4. pg_ctl start -D test
  5. 登陆psql 进行验证select return_pid();

补充:

关于OID:

  1. OID不能重复,但是可以自己任意YY
  2. 如果不知道哪些可用,在src/include/catalog 下有个脚本文件 unused_oids,运行一下就能找出哪些oid可用,但要这是一个linux脚本,需要在linux下运行。
欣赏此文? 求鼓励,求支持!