PostgreSQL7.0手册-程序员手册 -48. 服务器编程接口
-------------------
SPI_getrelname
名称
SPI_getrelname — 返回指明关系的名称
语法
SPI_getrelname(rel)
输入
Relation rel
输入的关系
输出
char *
指定的关系的名称
描述
SPI_getrelname 返回指明关系的名称.
用法
TBD
算法
把关系名称拷贝到新的存储器中去.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SPI_palloc
名称
SPI_palloc — 在上层执行器环境中分配存储器
语法
SPI_palloc(size)
输入
Size size
八进制的待分配存储空间大小
输出
void *
指明大小的新存储区
描述
SPI_palloc 在执行器上层环境分配存储器.参阅存储器管理章节.
用法
TBD
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SPI_repalloc
名称
SPI_repalloc — 重新在执行器上层环境中分配存储器
语法
SPI_repalloc(pointer, size)
输入
void * pointer
指向现有存储器
Size size
八进制的要分配的存储空间尺寸
输出
void *
新分配的存储空间, 带有从现存区域拷贝来的内容.
描述
SPI_repalloc 在上层执行器环境中重新分配存储器.参考存储器管理章节.
用法
TBD
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SPI_pfree
名称
SPI_pfree — 从上层执行器环境中释放存储器
语法
SPI_pfree(pointer)
输入
void * pointer
指向现有存储器(区)的指针
输出
无
描述
SPI_pfree 释放在上层执行器环境中的存储器.参考存储器管理章节.
用法
TBD
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
存储器管理
服务器在存储器环境按这样的方法分配存储器:在某个环境分配的存储器可以被环境析构器释放而不会影响其他环境中分配的存储器.所有存储器分配(通过 palloc 等)都被当作在当前环境的区域中分配存储器.如果你试图释放(或再分配)不在当前环境的存储器,你将得到不可预料的结果.
创建存储器环境和切换存储器环境是 SPI 管理器中存储器管理器的任务.
SPI 过程处理两种存储器环境:上层执行器存储器环境和过程存储器环境(如果已联接).
在一个过程与 SPI 管理器联接之前,当前存储器环境是上层执行器环境,所以所有由过程自身通过 palloc/repalloc 或通过 SPI 工具函数在联接到 SPI 管理器之前分配的存储器都在这个环境里.
在进行 SPI_connect 调用之后,当前环境是过程自身所有的.通过 palloc/repalloc 或通过 SPI 应用函数分配的存储器(除了 SPI_copytuple,SPI_modifytuple,SPI_palloc 和 SPI_repalloc 以外)都在这个环境中分配.
当进程与 SPI 管理器断开(通过调用 SPI_finish)后,当前环境恢复为上层执行器环境并且所有在过程存储器环境分配的存储器都被释放,并且不可继续使用!
如果你想返回一些东西给上层执行器,那么你必须为此在上层环境分配一片存储器!
SPI 不能自动释放在上层执行器环境里分配的存储器!
SPI 在查询完成后自动释放查询执行期间分配的存储器!
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
数据改变的可视性
Postgres 数据修改的可视性规则:在查询执行过程中,由查询本身造成的数据修改(通过 SQL-函数, SPI-函数,触发器)对查询扫描而言是不可见的.例如,在查询 INSERT INTO a SELECT * FROM a 里,插入的记录对 SELECT 的扫描是不可见的.实际上,这么做在数据库内部形成非递归的数据库表的复制品(当然是要受到唯一索引规则的制约的喽)。
由查询 Q 造成的改变可以为查询 Q 以后运行的查询可见,不管这些查询是在查询 Q 内部开始运行(在 Q 运行期间)的还是Q运行完毕后开始运行的.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
例子
这个 SPI 使用的样例演示了可视性规则.在 src/test/regress/regress.c 和 contrib/spi 里有更复杂的例子.
这是一个非常简单的 SPI 使用的例子.过程 execq 在其第一个参数里接收一个 SQL 查询,第二个参数接收一个 tcount(译注:记录个数),用 SPI_exec 执行这个查询并且返回查询执行过的记录个数:
#include "executor/spi.h" /* this is what you need to work with SPI(这个是你用SPI所要用的头文件) */
int execq(text *sql, int cnt);
int
execq(text *sql, int cnt)
{
int ret;
int proc = 0;
SPI_connect();
ret = SPI_exec(textout(sql), cnt);
proc = SPI_processed;
/*
* If this is SELECT and some tuple(s) fetched -
* returns tuples to the caller via elog (NOTICE).
*/
if ( ret == SPI_OK_SELECT && SPI_processed > 0 )
{
TupleDesc tupdesc = SPI_tuptable->tupdesc;
SPITupleTable *tuptable = SPI_tuptable;
char buf[8192];
int i;
SPI_getrelname
名称
SPI_getrelname — 返回指明关系的名称
语法
SPI_getrelname(rel)
输入
Relation rel
输入的关系
输出
char *
指定的关系的名称
描述
SPI_getrelname 返回指明关系的名称.
用法
TBD
算法
把关系名称拷贝到新的存储器中去.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SPI_palloc
名称
SPI_palloc — 在上层执行器环境中分配存储器
语法
SPI_palloc(size)
输入
Size size
八进制的待分配存储空间大小
输出
void *
指明大小的新存储区
描述
SPI_palloc 在执行器上层环境分配存储器.参阅存储器管理章节.
用法
TBD
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SPI_repalloc
名称
SPI_repalloc — 重新在执行器上层环境中分配存储器
语法
SPI_repalloc(pointer, size)
输入
void * pointer
指向现有存储器
Size size
八进制的要分配的存储空间尺寸
输出
void *
新分配的存储空间, 带有从现存区域拷贝来的内容.
描述
SPI_repalloc 在上层执行器环境中重新分配存储器.参考存储器管理章节.
用法
TBD
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SPI_pfree
名称
SPI_pfree — 从上层执行器环境中释放存储器
语法
SPI_pfree(pointer)
输入
void * pointer
指向现有存储器(区)的指针
输出
无
描述
SPI_pfree 释放在上层执行器环境中的存储器.参考存储器管理章节.
用法
TBD
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
存储器管理
服务器在存储器环境按这样的方法分配存储器:在某个环境分配的存储器可以被环境析构器释放而不会影响其他环境中分配的存储器.所有存储器分配(通过 palloc 等)都被当作在当前环境的区域中分配存储器.如果你试图释放(或再分配)不在当前环境的存储器,你将得到不可预料的结果.
创建存储器环境和切换存储器环境是 SPI 管理器中存储器管理器的任务.
SPI 过程处理两种存储器环境:上层执行器存储器环境和过程存储器环境(如果已联接).
在一个过程与 SPI 管理器联接之前,当前存储器环境是上层执行器环境,所以所有由过程自身通过 palloc/repalloc 或通过 SPI 工具函数在联接到 SPI 管理器之前分配的存储器都在这个环境里.
在进行 SPI_connect 调用之后,当前环境是过程自身所有的.通过 palloc/repalloc 或通过 SPI 应用函数分配的存储器(除了 SPI_copytuple,SPI_modifytuple,SPI_palloc 和 SPI_repalloc 以外)都在这个环境中分配.
当进程与 SPI 管理器断开(通过调用 SPI_finish)后,当前环境恢复为上层执行器环境并且所有在过程存储器环境分配的存储器都被释放,并且不可继续使用!
如果你想返回一些东西给上层执行器,那么你必须为此在上层环境分配一片存储器!
SPI 不能自动释放在上层执行器环境里分配的存储器!
SPI 在查询完成后自动释放查询执行期间分配的存储器!
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
数据改变的可视性
Postgres 数据修改的可视性规则:在查询执行过程中,由查询本身造成的数据修改(通过 SQL-函数, SPI-函数,触发器)对查询扫描而言是不可见的.例如,在查询 INSERT INTO a SELECT * FROM a 里,插入的记录对 SELECT 的扫描是不可见的.实际上,这么做在数据库内部形成非递归的数据库表的复制品(当然是要受到唯一索引规则的制约的喽)。
由查询 Q 造成的改变可以为查询 Q 以后运行的查询可见,不管这些查询是在查询 Q 内部开始运行(在 Q 运行期间)的还是Q运行完毕后开始运行的.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
例子
这个 SPI 使用的样例演示了可视性规则.在 src/test/regress/regress.c 和 contrib/spi 里有更复杂的例子.
这是一个非常简单的 SPI 使用的例子.过程 execq 在其第一个参数里接收一个 SQL 查询,第二个参数接收一个 tcount(译注:记录个数),用 SPI_exec 执行这个查询并且返回查询执行过的记录个数:
#include "executor/spi.h" /* this is what you need to work with SPI(这个是你用SPI所要用的头文件) */
int execq(text *sql, int cnt);
int
execq(text *sql, int cnt)
{
int ret;
int proc = 0;
SPI_connect();
ret = SPI_exec(textout(sql), cnt);
proc = SPI_processed;
/*
* If this is SELECT and some tuple(s) fetched -
* returns tuples to the caller via elog (NOTICE).
*/
if ( ret == SPI_OK_SELECT && SPI_processed > 0 )
{
TupleDesc tupdesc = SPI_tuptable->tupdesc;
SPITupleTable *tuptable = SPI_tuptable;
char buf[8192];
int i;

