当前位置: 首页 > news >正文

[PostgreSQL的 SPI_接口函数]

Server Programming Interface(SPI)是PostgreSQL内核中的一个模块,这个模块让内核开发者可以在C函数中执行SQL语句,并具备管理事务的能力。通过它我们可以用C语言去调用数据库里的各种SQL。

这个SPI_比较便利的一点在于,我们可以在自定义的Extension中也可以使用它,去用C调用SQL执行,也就是说,如果我们想的话,我们可以在Extension里用C语言定义一个函数,在函数里拼接出我们想要执行的SQL,并调用SPI_的相关接口函数,在数据库里实际执行该SQL。因为是以Extension的形式去做的,所以,不想使用了,直接drop extension就可以了。

在spi.h里我们可以看到有很多的SPI_的函数。具体的可以参考官方文档PostgreSQL: Documentation: 14: Chapter 47. Server Programming Interface

因为此前发过自定义PostgreSQL的extension的文章,在此就不做赘述了,直接放链接:如何为PostgreSQL创建自定义Extension

下面,我将举个小例子,在Extension里使用这些SPI_接口函数,来实现一个数据库里的函数,在PostgreSQL里执行SQL。关键的部分如下,通过逻辑,其实可以看出来,我这里做了一个巨鸡肋的功能————通过函数输入一个表名和一个路径文件,函数拼接了一个COPY的SQL来实现copy to拷贝表的功能,但是为了演示SPI_的接口函数已经足够了。

PG_FUNCTION_INFO_V1(pg_copy_plugin_out);

Datum pg_copy_plugin_out(PG_FUNCTION_ARGS)
{
  int SPI_connect(void);
  int SPI_exec(const char * command, long count);
  int SPI_finish(void);
  char *plugintableName = text_to_cstring(PG_GETARG_TEXT_PP(0));
  char *filepath = text_to_cstring(PG_GETARG_TEXT_PP(1));
  char command[128];
        
 sprintf(command,"copy  %s to  \'%s\';", plugintableName,filepath);
 SPI_connect();
 SPI_exec(command, 0); 
 SPI_finish();

SPI_connect的主要作用是连接一个C函数到 SPI 管理器 。
SPI_exec的作用是执行一个读/写命令。
SPI_finish的作用是将一个C函数从 SPI 管理器断开。

我这里是拼接后直接执行了,因此只用到这几个,如果想获取prepare语句,但不执行等,可以去使用其他类型的SPI_接口函数,具体可以参考手册。

其实在后边返回值那里,我遇到了点障碍,所以,我加了一个 ereport(ERROR,去抛出一个报错,但却能让我的功能正常完成。

[postgres@localhost pg_copy_plugin]$ ll
total 16
-rw-r--r-- 1 postgres dba  217 Jun 15 05:13 Makefile
-rw-r--r-- 1 postgres dba  642 Aug  1 15:26 pg_copy_plugin--1.0.sql
-rw-r--r-- 1 postgres dba 1013 Aug  1 17:29 pg_copy_plugin.c
-rw-r--r-- 1 postgres dba  137 Jun 15 05:12 pg_copy_plugin.control

[postgres@localhost pg_copy_plugin]$ make
gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -fPIC -I. -I./ -I/home/postgres/soft/include/server -I/home/postgres/soft/include/internal  -D_GNU_SOURCE   -c -o pg_copy_plugin.o pg_copy_plugin.c
gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -fPIC pg_copy_plugin.o -L/home/postgres/soft/lib   -Wl,--as-needed -Wl,-rpath,'/home/postgres/soft/lib',--enable-new-dtags  -shared -o pg_copy_plugin.so

[postgres@localhost pg_copy_plugin]$ make install
/bin/mkdir -p '/home/postgres/soft/share/extension'
/bin/mkdir -p '/home/postgres/soft/share/extension'
/bin/mkdir -p '/home/postgres/soft/lib'
/bin/install -c -m 644 .//pg_copy_plugin.control '/home/postgres/soft/share/extension/'
/bin/install -c -m 644 .//pg_copy_plugin--1.0.sql  '/home/postgres/soft/share/extension/'
/bin/install -c -m 755  pg_copy_plugin.so '/home/postgres/soft/lib/'

依次的编译安装,make阶段产生了.so的文件,make install阶段,把.control和.sql文件拷贝到share路径下,将.so文件拷贝到lib路径下。

我们到数据库里去安装这个自定义的插件,下边的这个pg_copy_plugin_out 就是我们刚才定义的那个函数。

[postgres@localhost pg_copy_plugin]$ psql
psql (15beta1)
Type "help" for help.

postgres=# \df
                       List of functions
 Schema | Name | Result data type | Argument data types | Type 
--------+------+------------------+---------------------+------
(0 rows)

postgres=# create extension pg_copy_plugin;
CREATE EXTENSION
postgres=# \df
                                         List of functions
 Schema |        Name        | Result data type |            Argument data types             | Type 
--------+--------------------+------------------+--------------------------------------------+------
 public | pg_bak_tab         | text             | ta character varying, fa character varying | func
 public | pg_copy_plugin_out | text             | plugintablename text, filename text        | func
(2 rows)

来验证一下这个函数的功能,可以看到,他是使用c实现的,输入的两个参数是两个text类型,返回值也是text。

可以看到,这个函数通过使用SPI_的接口函数,实现了在C语言层面根据输入值拼接SQL并在数据库执行的功能。(…其实在数据库里用plpgsql写一个函数就可以达到同样的效果,所以我说很鸡肋。但是本文主要就是展示SPI_接口函数在Extension里的一个大致使用)

postgres=# \! ls -l /home/postgres/ysl.sql
ls: cannot access /home/postgres/ysl.sql: No such file or directory
postgres=# select pg_copy_plugin_out('t1','/home/postgres/ysl.sql');
ERROR:  copy  t1 to  '/home/postgres/ysl.sql';
postgres=# \! ls -l /home/postgres/ysl.sql
-rw-r--r-- 1 postgres dba 11679 Aug  1 17:55 /home/postgres/ysl.sql
postgres=# \! head -10 /home/postgres/ysl.sql
1
2
3
4
5
6
7
8
9
10

到此,这个演示结束了。感兴趣的也可以去尝试使用这些SPI_的接口函数,去实现一些功能。

相关文章:

  • 系统结构设计原则、聚合与耦合
  • 启动命令,项目文件介绍,简单配置项介绍,url处理和视图函数
  • Double Q-learning
  • 【前端】HTTP相关知识总结
  • csp202206
  • Hive中的数据倾斜优化
  • SpringMvc(二、请求传参
  • [如何编译openGauss对应版本的wal2json.so]
  • 计算方法/数值分析 期末复习整理
  • makefile(详细讲解)
  • Java递归实现迷宫问题和八皇后
  • 软件测试面试题及答案,2022最强版
  • 2.采药-01背包
  • 语法基础(函数)
  • 这几个小插件助你快速提升工作效率
  • (三)从jvm层面了解线程的启动和停止
  • Android开源项目规范总结
  • Angular4 模板式表单用法以及验证
  • codis proxy处理流程
  • CSS中外联样式表代表的含义
  • JavaScript/HTML5图表开发工具JavaScript Charts v3.19.6发布【附下载】
  • js算法-归并排序(merge_sort)
  • leetcode46 Permutation 排列组合
  • leetcode98. Validate Binary Search Tree
  • MD5加密原理解析及OC版原理实现
  • text-decoration与color属性
  • Vue 重置组件到初始状态
  • Web设计流程优化:网页效果图设计新思路
  • 番外篇1:在Windows环境下安装JDK
  • 一个完整Java Web项目背后的密码
  • Nginx实现动静分离
  • puppet连载22:define用法
  • 带你开发类似Pokemon Go的AR游戏
  • #QT(智能家居界面-界面切换)
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • ${factoryList }后面有空格不影响
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (Oracle)SQL优化技巧(一):分页查询
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (新)网络工程师考点串讲与真题详解
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • .NET Core Web APi类库如何内嵌运行?
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .net core 源码_ASP.NET Core之Identity源码学习
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉
  • .NET成年了,然后呢?
  • .Net接口调试与案例
  • .NET文档生成工具ADB使用图文教程
  • .sh
  • [ Algorithm ] N次方算法 N Square 动态规划解决
  • [ C++ ] STL_vector -- 迭代器失效问题
  • [2018/11/18] Java数据结构(2) 简单排序 冒泡排序 选择排序 插入排序
  • [383] 赎金信 js
  • [Android] Upload package to device fails #2720