麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 數(shù)據(jù)庫 > PostgreSQL > 正文

PostgreSQL7.0手冊-程序員手冊 -48. 服務(wù)器編程接口

2019-09-08 23:34:17
字體:
供稿:網(wǎng)友
第四十八章.服務(wù)器編程接口
內(nèi)容 
接口函數(shù) 
接口支持函數(shù) 
存儲器管理 
數(shù)據(jù)改變的可視性 
例子 
服務(wù)器編程接口(Server Programming Interface) (SPI)給我們在用戶定義的 C 函數(shù)里面運行 SQL查詢的能力.可用的過程語言(PL)給我們一個實現(xiàn)這些功能的可選的手段. 
實際上,SPI 只是一套用于訪問分析器,規(guī)劃器,優(yōu)化器和執(zhí)行器(Parser,Planner,Optimizer and Executor)的本機接口函數(shù).SPI 同樣做一些存儲器管理工作. 

為了避免混淆,我們將使用 函數(shù)(function) 來代表 SPI 接口函數(shù),用 過程(procedure) 代表用戶用 SPI定義 C 函數(shù). 

SPI 過程總是被一些(上層)執(zhí)行器和 SPI 管理器用執(zhí)行器調(diào)用來運行你的查詢.其他過程可以通過執(zhí)行器從你的過程里運行查詢來調(diào)用. 

注意,如果在你的過程里執(zhí)行查詢時,事務(wù)退出了,那么控制不會返回到你的過程中.相反,所有工作都將回卷并且服務(wù)器將等待客戶端的另一個命令.這一點將在以后的版本中修正. 

其他限制是不能執(zhí)行 BEGIN,END 和 ABORT (交易控制語句)和游標(biāo)操作.這些同樣在將來的版本中要被修改. 

如果執(zhí)行成功了,SPI 函數(shù)返回一個非負(fù)結(jié)果(或者通過返回一個整數(shù)值或放在 SPI_result 全局變量,象下面描述的那樣).出錯時,返回一個負(fù)數(shù)或 NULL 結(jié)果. 

接口函數(shù)

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_connect
名稱
SPI_connect ― 把你的過程與 SPI 管理器連接起來. 

語法
int SPI_connect(void)
輸入
無 

輸出
int 
  
返回狀態(tài) 
SPI_OK_CONNECT 
如果聯(lián)接成功 
SPI_ERROR_CONNECT 
如果聯(lián)接失敗 

描述SPI_connect 打開一個與 Postgres 后端的聯(lián)接.如果你需要執(zhí)行查詢你就要調(diào)用這個函數(shù).有些使用 SPI 函數(shù)的應(yīng)用可以從非聯(lián)接的過程調(diào)用. 
如果試圖對一個已經(jīng)聯(lián)接的過程調(diào)用 SPI_connect 你可能得到一個 SPI_ERROR_CONNECT 錯誤信息 - 例如,如果你直接從另一個已聯(lián)接的過程里調(diào)用一個過程.實際上,因為子進(jìn)程可能使用 SPI,子進(jìn)程返回后你的父進(jìn)程將不能繼續(xù)使用 SPI (如果子進(jìn)程調(diào)用了 SPI_finish).這是一個糟糕的方面.

用法
算法
SPI_connect 執(zhí)行下面操作: 
• 
初始化 SPI 用于查詢執(zhí)行和存儲器管理的內(nèi)部結(jié)構(gòu). 

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_finish
名稱
SPI_finish ― 把你的過程與 SPI 管理器斷開. 

語法
SPI_finish(void)
輸入
無 

輸出
int 
   
 SPI_OK_FINISH 如果正常斷開,返回此信息 
SPI_ERROR_UNCONNECTED 如果從一個未聯(lián)接過程調(diào)用,返回此信息 

描述
SPI_finish 關(guān)閉一個現(xiàn)有的與 Postgres 后端的聯(lián)接.你應(yīng)該在結(jié)束通過 SPI 管理器的操作后調(diào)用此函數(shù). 
如果 SPI_finish 是在當(dāng)前沒有有效聯(lián)接的情況下被調(diào)用的,你可能會得到一個 SPI_ERROR_UNCONNECTED 的返回.這樣做沒有什么根本性的錯誤,這意味著 SPI 管理器不做任何事情.

用法
SPI_finish 必須 作為一個已聯(lián)接的過程的最后一步被調(diào)用,否則你可能得到不可預(yù)料的結(jié)果!注意:如果你從事務(wù)退出(通過 elog(ERROR)),你可以安全的忽略對 SPI_finish 的調(diào)用.
算法
SPI_finish 執(zhí)行下列操作: 
• 
斷開你的過程與 SPI 管理器的連接并且釋放所有你的過程自 SPI_connect 起通過 palloc 分配的存儲器.這些存儲器不能再利用!請參考存儲器管理. 

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_exec
名稱
SPI_exec ― 創(chuàng)建一個執(zhí)行規(guī)劃 (分析器+規(guī)劃器+優(yōu)化器)并且執(zhí)行一個查詢.
語法
SPI_exec(query, tcount)
輸入
char *query 
包含查詢規(guī)劃的字符串 
int tcount 
返回的最大記錄數(shù) 

輸出
int 
   
 SPI_OK_EXEC 如果正確斷開,返回此值 
SPI_ERROR_UNCONNECTED 如果從一個未聯(lián)接的過程調(diào)用,返回此值 
SPI_ERROR_ARGUMENT 如果查詢是 NULL(空)或 tcount < 0,返回此值 
SPI_ERROR_UNCONNECTED 如果過程未聯(lián)接,返回此值. 
SPI_ERROR_COPY 如果 COPY TO/FROM stdin(標(biāo)準(zhǔn)輸入),返回此值. 
SPI_ERROR_CURSOR 如果 DECLARE/CLOSE CURSOR,F(xiàn)ETCH,返回此值 
SPI_ERROR_TRANSACTION 如果 BEGIN/ABORT/END,返回此值. 
SPI_ERROR_OPUNKNOWN 如果查詢類型未知(這種情況不應(yīng)發(fā)生). 

如果你的查詢執(zhí)行成功,那么將返回下列非負(fù)數(shù)值之一: 
  
   
 SPI_OK_UTILITY 如果執(zhí)行了某些應(yīng)用(例如 CREATE TABLE ...) 
SPI_OK_SELECT 如果執(zhí)行了 SELECT (但不是 SELECT ... INTO!) 
SPI_OK_SELINTO 如果執(zhí)行了 SELECT ... INTO 
SPI_OK_INSERT 如果執(zhí)行了 INSERT(或 INSERT ... SELECT) 
SPI_OK_DELETE 如果執(zhí)行了 DELETE 
SPI_OK_UPDATE 如果執(zhí)行了 UPDATE 


描述
SPI_exec 創(chuàng)建一個執(zhí)行規(guī)劃(分析器+規(guī)劃器+優(yōu)化器)并且執(zhí)行查詢以獲取 tcount 條記錄.
用法
這個(函數(shù))只能從一個以聯(lián)接的過程中調(diào)用.如果 tcount 是零則對查詢掃描返回的所有記錄都執(zhí)行查詢.使用 tcount > 0 你可以限制查詢執(zhí)行的記錄數(shù).例如, 
SPI_exec ("insert into table select * from table", 5);
將最多允許 5 條記錄插入表中.如果你的查詢執(zhí)行成功則返回一個非負(fù)數(shù). 
注意:你可能在一個字符串里傳遞許多查詢或一個查詢字符串可能被 RULE (規(guī)則)重寫.SPI_exec 返回最后一個執(zhí)行的查詢的結(jié)果.
最后一個被執(zhí)行的查詢的實際記錄數(shù)放在全局變量 SPI_processed 里返回(如果不是 SPI_OK_UTILITY).如果返回了SPI_OK_SELECT 而且 SPI_processed > 0 那么你可以通過全局指針 SPITupleTable *SPI_tuptable 來訪問這些選擇了的記錄:同樣要注意,SPI_finish 將釋放所有 SPITupleTable 并令所有 SPITupleTable 不可用!(參閱存儲器管理). 
SPI_exec 可能返回下面的(本地)值: 
   
 SPI_ERROR_ARGUMENT 如果查詢是 NULL (空)或 tcount < 0,返回此值. 
SPI_ERROR_UNCONNECTED 如果過程沒有聯(lián)接,返回此值. 
SPI_ERROR_COPY如果是 COPY TO/FROM stdin(標(biāo)準(zhǔn)輸入),返回此值. 
SPI_ERROR_CURSOR 如果是 DECLARE/CLOSE CURSOR,F(xiàn)ETCH,返回此值. 
SPI_ERROR_TRANSACTION 如果 BEGIN/ABORT/END,返回此值. 
SPI_ERROR_OPUNKNOWN 如果查詢類型未知(不應(yīng)發(fā)生這種情況),返回此值. 


算法
SPI_exec 執(zhí)行下面操作: 
  
• 
斷開你的過程與 SPI 管理器的連接并且釋放所有你的過程自 SPI_connect 起通過 palloc 分配的存儲器.這些存儲器不能再利用!請參考存儲器管理。 

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_prepare
名稱
SPI_prepare ― 將你的過程與 SPI 管理器連接. 

語法
SPI_prepare(query, nargs, argtypes)
輸入
query 
查詢字符串 
nargs 
輸入的參數(shù)個數(shù)($1 ... $nargs -象 SQL-函數(shù)里一樣) 
argtypes 
指向輸入?yún)?shù)的類型為 OID 的指針數(shù)組 

輸出
void * 
指向一個執(zhí)行規(guī)劃的指針(分析器+規(guī)劃器+優(yōu)化器) 

描述
SPI_prepare 創(chuàng)建和返回一個執(zhí)行規(guī)劃(分析器+規(guī)劃器+優(yōu)化器)但是不執(zhí)行查詢.應(yīng)該只從一個已聯(lián)接的過程內(nèi)部調(diào)用.
用法
nargs 是參數(shù)個數(shù)($1 ... $nargs - 象 SQL-函數(shù)里一樣),并且 nargs 可以是 0 --只有在查詢里沒有任何 $1 時是這樣. 
準(zhǔn)備好的執(zhí)行規(guī)劃的執(zhí)行速度有時快很多,所以如果某個查詢會被執(zhí)行多次時這個特性可能會很有用. 

SPI_prepare 返回的規(guī)劃可能只能被用于目前的過程,因為 SPI_finish 將釋放為規(guī)劃分配的存儲器.參考 SPI_saveplan. 

如果成功,將返回一個非空的指針.否則,你會得到一個 NULL(空)的規(guī)劃.不管那種情況 SPI_result 都將象 SPI_exec 返回的值那樣被設(shè)置,除非它被設(shè)置為 SPI_ERROR_ARGUMENT --因為查詢是 NULL 或 nargs < 0 或 nargs > 0 && argtypes 是 NULL.


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_saveplan
名稱
SPI_saveplan ― 保存?zhèn)鬟f進(jìn)來的分析器規(guī)劃 

語法
SPI_saveplan(plan)
輸入
void *query 
傳入的規(guī)劃 

輸出
void * 
執(zhí)行規(guī)劃定位.如果成功返回 NULL. 
SPI_result 
   
 SPI_ERROR_ARGUMENT 如果規(guī)劃是 NULL,返回此值 
SPI_ERROR_UNCONNECTED 如果過程沒有聯(lián)接,返回此值 

描述
SPI_saveplan 把一個由 SPI_prepare 準(zhǔn)備的規(guī)劃存儲在安全的存儲器中,以避免被 SPI_finish 或事務(wù)管理器釋放. 
目前的 Postgres 版本不能把計劃好的規(guī)劃存儲在系統(tǒng)表里并從中獲取它們執(zhí)行.這個(特性)將在未來的版本中實現(xiàn).做為可選的方法,目前的版本可以在當(dāng)前會話中隨后擊活的過程中重新使用準(zhǔn)備好的規(guī)劃.用 SPI_execp 執(zhí)行這些保存了的規(guī)劃.

用法
SPI_saveplan 把一個傳入的規(guī)劃(由 SPI_prepare 準(zhǔn)備)保存在存儲器中防止被 SPI_finish 和事務(wù)管理器釋放并且返回一個指向被保存的規(guī)劃的指針.你可以把返回的指針保存在一個局部變量里.在準(zhǔn)備一個規(guī)劃或在 SPI_execp (見下面)中使用已準(zhǔn)備的規(guī)劃時,注意檢查這個指針是否為 NULL(空). 
注意:如果已準(zhǔn)備的規(guī)劃參考的對象之一 (一個關(guān)系,函數(shù),等.)在你的會話過程中被刪除(被你的后端或其他過程)那么對此規(guī)劃的 SPI_execp 執(zhí)行結(jié)果將不可預(yù)料.

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_execp
名稱
SPI_execp ― 執(zhí)行一個從 SPI_saveplan 來的規(guī)劃 

語法
SPI_execp(plan,
values,
nulls,
tcount)
輸入
void *plan 
執(zhí)行規(guī)劃 
Datum *values 
實際參數(shù)值 
char *nulls 
  
  
  
  

描述哪個參數(shù)獲得 NULL 值的數(shù)組  
 'n' 表明允許 NULL  
' ' 表示不允許 NULL  


int tcount 
將被執(zhí)行的規(guī)劃的記錄數(shù) 

輸出
int 
返回與 SPI_exec 一樣的值以及  
 SPI_ERROR_ARGUMENT 如果 plan 是 NULL 或 tcount < 0,返回此值 
SPI_ERROR_PARAM 如果 values 是 NULL 并且所準(zhǔn)備的 plan 帶有一些參數(shù). 

SPI_tuptable 
如果成功,則象 SPI_exec 一樣初始化 
SPI_processed 
如果成功,則象 SPI_exec 一樣初始化 

描述
SPI_execp 把一個由 SPI_prepare 準(zhǔn)備的規(guī)劃存儲在安全存儲器中,以免被 SPI_finish 或事務(wù)管理器釋放. 
目前的 Postgres 版本不能把計劃好的規(guī)劃存儲在系統(tǒng)表里并從中獲取它們執(zhí)行.這個(特性)將在未來的版本中實現(xiàn).做為繞開的方法,目前的版本可以在當(dāng)前會話中隨后擊活的過程中重新使用準(zhǔn)備好的規(guī)劃.用 SPI_execp 執(zhí)行這些保存了的規(guī)劃.

用法
如果 nulls 是 NULL 那么 SPI_execp 假設(shè)所有值(如果有的話)都是 NOT NULL. 
注意:如果已準(zhǔn)備的規(guī)劃參考的對象之一(一個關(guān)系,函數(shù),等.)在你的會話過程中被刪除(被你的后端或其他過程)那么對此規(guī)劃的 SPI_execp 執(zhí)行結(jié)果將不可預(yù)料.

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

接口支持函數(shù)
所有后面描述的函數(shù)都可被聯(lián)接或未聯(lián)接的過程使用.

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_copytuple
名稱
SPI_copytuple ― 把記錄的拷貝放到上層執(zhí)行器環(huán)境 

語法
SPI_copytuple(tuple)
輸入
HeapTuple tuple 
  
  
  
  

Input tuple to be copied

Outputs
HeapTuple 
輸入被拷貝的記錄 
   
 non-NULL 如果 tuple 為非空(not NULL)并且拷貝成功 
NULL 只有 tuple 是 NULL 

描述
SPI_copytuple 把一個記錄的拷貝放到上層高級執(zhí)行器環(huán)境.參考存儲器管理章節(jié).
用法
TBD

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_modifytuple
名稱
SPI_modifytuple ― 修改關(guān)系的記錄 

語法
SPI_modifytuple(rel, tuple , nattrs
, attnum , Values , Nulls)
輸入
Relation rel 
HeapTuple tuple 
要修改的輸入記錄 
int nattrs 
attnum 里字段號的個數(shù) 
int * attnum 
將要修改的字段號的數(shù)組 
Datum * Values 
給聲明的屬性的新值 
char * Nulls 
若存在,哪個字段是 NULL. 

輸出
HeapTuple 

修改后的新記錄  
 non-NULL 如果 tuple 為非空(not NULL)并且修改成功 
NULL 只有當(dāng) tuple 為 NULL(空) 


SPI_result 
   
 SPI_ERROR_ARGUMENT 如果 rel 是 NULL 或 tuple 是 NULL 或 natts &le(小于)0 或 attnum 是 NULL 或 Values 是 NULL. 
SPI_ERROR_NOATTRIBUTE 如果在 attnum 里有一個非法的數(shù)字 (attnum &le(小于)0 或 > 記錄中字段數(shù)) 

 
描述
SPI_modifytuple 修改一個上層執(zhí)行器環(huán)境的記錄.參考存儲器管理章節(jié). 
 
用法
如果成功,返回一個指向新記錄的指針.新記錄在執(zhí)行器上層環(huán)境分配(參見 存儲器管理).傳入的記錄沒有改變.

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_fnumber
名稱
SPI_fnumber ― 查找聲明的字段的字段號 

語法
SPI_fnumber(tupdesc, fname)
輸入
TupleDesc tupdesc 
輸入記錄的描述 
char * fname 
字段名 

輸出
int 

字段號  
 有效的以1為基的字段索引號 
SPI_ERROR_NOATTRIBUTE 如果命名的字段沒有找到 

 

描述
SPI_fnumber 返回 fname 指明的字段的字段號. 

用法
字段號是以1為基的. 

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_fname
名稱
SPI_fname ― 找出指明的字段的字段名 

語法
SPI_fname(tupdesc, fname)
輸入
TupleDesc tupdesc 
輸入的記錄描述 
char * fnumber 
字段號 

輸出
char * 

字段名  
 NULL -- 如果 fnumber 超出范圍 
出錯時,SPI_result 設(shè)置為 SPI_ERROR_NOATTRIBUTE 

 

描述
SPI_fname 返回指明的字段的字段名. 

用法
字段號是以 1 為基的. 

算法
返回一個新分配的字段名的拷貝. 

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_getvalue
名稱
SPI_getvalue ― 返回指明的字段的字符串值 

語法
SPI_getvalue(tuple, tupdesc, fnumber)
輸入
HeapTuple tuple 
輸入的待檢查的字段 
TupleDesc tupdesc 
輸入字段描述 
int fnumber 
字段號 

輸出
char * 

字段值或 NULL(空),如果 
   
 字段為 NULL(空) 
fnumber 超出范圍(這時 SPI_result 設(shè)置為 SPI_ERROR_NOATTRIBUTE) 
沒有可用的輸出函數(shù)(這時 SPI_result 設(shè)置為 SPI_ERROR_NOOUTFUNC) 

 

描述
SPI_getvalue 返回指明字段的一個外部(字符串)形式的值. 

用法
字段號是以 1 為基的. 

算法
根據(jù)數(shù)值的要求分配存儲器. 

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_getbinval
名稱
SPI_getbinval ― 返回指明的字段的二進(jìn)制數(shù)值 

語法
SPI_getbinval(tuple, tupdesc, fnumber, isnull)
輸入
HeapTuple tuple 
要檢查的輸入記錄 
TupleDesc tupdesc 
輸入記錄描述 
int fnumber 
字段號 

輸出
Datum 
字段二進(jìn)制數(shù)值 
bool * isnull 
字段是否為空的標(biāo)志 
SPI_result 
   
 SPI_ERROR_NOATTRIBUTE 

 
描述
SPI_getbinval 返回指明字段的二進(jìn)制數(shù)值 

用法
字段號是以1為基的. 

算法
不為二進(jìn)制數(shù)值分配新空間. 

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_gettype
名稱
SPI_gettype ― 返回指明字段的類型名 

語法
SPI_gettype(tupdesc, fnumber)
輸入
TupleDesc tupdesc 
輸入字段描述 
int fnumber 
字段號 

輸出
char * 
指明字段號的類型名稱 
SPI_result 
   
 SPI_ERROR_NOATTRIBUTE 

 
描述
SPI_gettype 返回一個指明字段的類型名的拷貝. 

用法
字段號是以1為基的. 

算法
不為二進(jìn)制數(shù)值分配新空間. 

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_gettypeid
名稱
SPI_gettypeid ― 返回指明字段的類型 OID 

語法
SPI_gettypeid(tupdesc, fnumber)
輸入
TupleDesc tupdesc 
輸入字段的描述 
int fnumber 
字段號 

輸出
OID 
指明字段號的類型 OID. 
SPI_result 
   
 SPI_ERROR_NOATTRIBUTE 

 
描述
SPI_gettypeid 返回指明的字段的類型 OID. 

用法
字段號是以 1 為基的. 

算法
TBD

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_getrelname
名稱
SPI_getrelname ― 返回指明關(guān)系的名稱 

語法
SPI_getrelname(rel)
輸入
Relation rel 
輸入的關(guān)系 

輸出
char * 
指定的關(guān)系的名稱 

描述
SPI_getrelname 返回指明關(guān)系的名稱. 

用法
TBD
算法
把關(guān)系名稱拷貝到新的存儲器中去. 

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_palloc
名稱
SPI_palloc ― 在上層執(zhí)行器環(huán)境中分配存儲器 

語法
SPI_palloc(size)
輸入
Size size 
八進(jìn)制的待分配存儲空間大小 

輸出
void * 
指明大小的新存儲區(qū) 

描述
SPI_palloc 在執(zhí)行器上層環(huán)境分配存儲器.參閱存儲器管理章節(jié). 

用法
TBD

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_repalloc
名稱
SPI_repalloc ― 重新在執(zhí)行器上層環(huán)境中分配存儲器 

語法
SPI_repalloc(pointer, size)
輸入
void * pointer 
指向現(xiàn)有存儲器 
Size size 
八進(jìn)制的要分配的存儲空間尺寸 

輸出
void * 
新分配的存儲空間, 帶有從現(xiàn)存區(qū)域拷貝來的內(nèi)容. 

描述
SPI_repalloc 在上層執(zhí)行器環(huán)境中重新分配存儲器.參考存儲器管理章節(jié). 

用法
TBD

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

SPI_pfree
名稱
SPI_pfree ― 從上層執(zhí)行器環(huán)境中釋放存儲器 

語法
SPI_pfree(pointer)
輸入
void * pointer 
指向現(xiàn)有存儲器(區(qū))的指針 

輸出
無 
描述
SPI_pfree 釋放在上層執(zhí)行器環(huán)境中的存儲器.參考存儲器管理章節(jié). 

用法
TBD

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

存儲器管理
服務(wù)器在存儲器環(huán)境按這樣的方法分配存儲器:在某個環(huán)境分配的存儲器可以被環(huán)境析構(gòu)器釋放而不會影響其他環(huán)境中分配的存儲器.所有存儲器分配(通過 palloc 等)都被當(dāng)作在當(dāng)前環(huán)境的區(qū)域中分配存儲器.如果你試圖釋放(或再分配)不在當(dāng)前環(huán)境的存儲器,你將得到不可預(yù)料的結(jié)果. 
創(chuàng)建存儲器環(huán)境和切換存儲器環(huán)境是 SPI 管理器中存儲器管理器的任務(wù). 

SPI 過程處理兩種存儲器環(huán)境:上層執(zhí)行器存儲器環(huán)境和過程存儲器環(huán)境(如果已聯(lián)接). 

在一個過程與 SPI 管理器聯(lián)接之前,當(dāng)前存儲器環(huán)境是上層執(zhí)行器環(huán)境,所以所有由過程自身通過 palloc/repalloc 或通過 SPI 工具函數(shù)在聯(lián)接到 SPI 管理器之前分配的存儲器都在這個環(huán)境里. 

在進(jìn)行 SPI_connect 調(diào)用之后,當(dāng)前環(huán)境是過程自身所有的.通過 palloc/repalloc 或通過 SPI 應(yīng)用函數(shù)分配的存儲器(除了 SPI_copytuple,SPI_modifytuple,SPI_palloc 和 SPI_repalloc 以外)都在這個環(huán)境中分配. 

當(dāng)進(jìn)程與 SPI 管理器斷開(通過調(diào)用 SPI_finish)后,當(dāng)前環(huán)境恢復(fù)為上層執(zhí)行器環(huán)境并且所有在過程存儲器環(huán)境分配的存儲器都被釋放,并且不可繼續(xù)使用! 

如果你想返回一些東西給上層執(zhí)行器,那么你必須為此在上層環(huán)境分配一片存儲器! 

SPI 不能自動釋放在上層執(zhí)行器環(huán)境里分配的存儲器! 

SPI 在查詢完成后自動釋放查詢執(zhí)行期間分配的存儲器!


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

數(shù)據(jù)改變的可視性
Postgres 數(shù)據(jù)修改的可視性規(guī)則:在查詢執(zhí)行過程中,由查詢本身造成的數(shù)據(jù)修改(通過 SQL-函數(shù), SPI-函數(shù),觸發(fā)器)對查詢掃描而言是不可見的.例如,在查詢 INSERT INTO a SELECT * FROM a 里,插入的記錄對 SELECT 的掃描是不可見的.實際上,這么做在數(shù)據(jù)庫內(nèi)部形成非遞歸的數(shù)據(jù)庫表的復(fù)制品(當(dāng)然是要受到唯一索引規(guī)則的制約的嘍)。 
由查詢 Q 造成的改變可以為查詢 Q 以后運行的查詢可見,不管這些查詢是在查詢 Q 內(nèi)部開始運行(在 Q 運行期間)的還是Q運行完畢后開始運行的.


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

例子
這個 SPI 使用的樣例演示了可視性規(guī)則.在 src/test/regress/regress.c 和 contrib/spi 里有更復(fù)雜的例子. 
這是一個非常簡單的 SPI 使用的例子.過程 execq 在其第一個參數(shù)里接收一個 SQL 查詢,第二個參數(shù)接收一個 tcount(譯注:記錄個數(shù)),用 SPI_exec 執(zhí)行這個查詢并且返回查詢執(zhí)行過的記錄個數(shù): 

#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;
                
                for (ret = 0; ret < proc; ret++)
                {
                        HeapTuple tuple = tuptable->vals[ret];
                        
                        for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++)
                                sprintf(buf + strlen (buf), " %s%s",
                                        SPI_getvalue(tuple, tupdesc, i),
                                        (i == tupdesc->natts) ? " " : " |");
                        elog (NOTICE, "EXECQ: %s", buf);
                }
        }

        SPI_finish();

        return (proc);
}
然后,編譯并創(chuàng)建函數(shù): 
create function execq (text, int4) returns int4 as '...path_to_so' language 'c';
vac=> select execq('create table a (x int4)', 0);
execq
-----
    0
(1 row)

vac=> insert into a values (execq('insert into a values (0)',0));
INSERT 167631 1
vac=> select execq('select * from a',0);
NOTICE:EXECQ:  0 <<< inserted by execq

NOTICE:EXECQ:  1 <<< value returned by execq and inserted by upper INSERT

execq
-----
    2
(1 row)

vac=> select execq('insert into a select x + 2 from a',1);
execq
-----
    1
(1 row)

vac=> select execq('select * from a', 10);
NOTICE:EXECQ:  0 

NOTICE:EXECQ:  1 

NOTICE:EXECQ:  2 <<< 0 + 2, only one tuple inserted - as specified

execq
-----
    3            <<< 10 is max value only, 3 is real # of tuples
(1 row)

vac=> delete from a;
DELETE 3
vac=> insert into a values (execq('select * from a', 0) + 1);
INSERT 167712 1
vac=> select * from a;
x
-
1                <<< no tuples in a (0) + 1
(1 row)

vac=> insert into a values (execq('select * from a', 0) + 1);
NOTICE:EXECQ:  0 
INSERT 167713 1
vac=> select * from a;
x
-
1
2                <<< there was single tuple in a + 1
(2 rows)

--   This demonstrates data changes visibility rule:

vac=> insert into a select execq('select * from a', 0) * x from a;
NOTICE:EXECQ:  1 
NOTICE:EXECQ:  2 
NOTICE:EXECQ:  1 
NOTICE:EXECQ:  2 
NOTICE:EXECQ:  2 
INSERT 0 2
vac=> select * from a;
x
-
1
2
2                <<< 2 tuples * 1 (x in first tuple)
6                <<< 3 tuples (2 + 1 just inserted) * 2 (x in second tuple)
(4 rows)             ^^^^^^^^ 
                     tuples visible to execq() in different invocations

--------------------------------------------------------------------------------
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 免费毛片在线 | 黄色久 | 国产一级一片免费播放 | 一级大片在线观看 | 日韩一级片黄色 | 91精品免费在线 | 性高跟鞋xxxxhd4kvideos | 日本在线一区二区 | 亚洲性生活免费视频 | 九九精品视频观看 | 国产噜噜噜噜久久久久久久久 | 视频一区二区国产 | 国产亚洲美女精品久久久2020 | 亚洲αv | 亚洲精品久久久久www | 久久久久久久午夜 | 国产精品99免费视频 | 国产精品亚洲一区二区三区久久 | 国产精品视频成人 | 黄色免费高清网站 | 天天躁狠狠躁夜躁2020挡不住 | 日本欧美一区二区三区在线观看 | 日日爱夜夜操 | 做爰xxxⅹ性护士hd在线 | 成人一级黄色 | 精品一区二区三区在线播放 | 亚洲第一页夜 | 国产午夜精品久久久久婷 | 黄色影院av | 毛片在哪里看 | 一级做a爱片性色毛片 | 日本中文字幕电影在线观看 | 国产亚洲欧美在线视频 | 成人资源在线 | 欧美成人做爰高潮片免费视频 | 精品一区二区三区在线观看国产 | 极品销魂一区二区三区 | 成人免费网站在线观看 | 中文字幕涩涩久久乱小说 | va视频在线 | 一本精品999爽爽久久久 |