GB | BIG5
|
| 首頁 > 數據庫 > 其它 > 正文 |
 |
| PostgreSQL7.0手冊-接口-53. libpq - C 庫 |
| 編譯:何偉平 laser@zhengmai.com.cn (2001-04-21 23:20:27) |
第五十三章. libpq - C 庫
內容
數據庫聯接函數
查詢執行函數
異步查詢處理
捷徑
異步通知
與 COPY 命令相關的函數
libpq 跟蹤函數
libpq 控制函數
環境變量
線程特性
例子程序
libpq 是 Postgres 的 C 應用程序員的接口.libpq 是一套允許客戶程序向 Postgres 端服務進程發送查詢並且獲得查詢返回的庫過程.libpq 同時也是其他幾個 Postgres 應用接口下面的引擎,包括 libpq++ (C++),libpgtcl (Tcl), perl5,和 ecpg.所以如果你使用這些軟件包,libpq 某些方面的特性會對你非常重要.
本節末尾有三個小程序顯示如何利用 libpq 書寫程序.在下面目錄裡面有幾個完整的 libpq 應用的例子:
../src/test/regress
../src/test/examples
../src/bin/psql
使用 libpq 的前端程序必須包括頭文件 libpq-fe.h 並且必須與 libpq 庫鏈接.
數據庫聯接函數
下面的過程處理與 Postgres 端服務器聯接的事情.一個應用程序一次可以與多個端建立聯接.(這做的原因之一是訪問多一個數據庫.)每個連接都是用一個從 PQconnectdb() 或 PQsetdbLogin()獲得的 PGconn 對象表示.注意,這些函數總是返回一個非空的對象指針,除非存儲器少得連個 PGconn 對象都分配不出來.在把查詢發送給聯接對象之前,可以調用 PQstatus 函數來檢查一下聯接是否成功.
PQconnectdb 與端數據庫服務器建立一個新的聯接.
PGconn *PQconnectdb(const char *conninfo)
這個過程用從一個字符串 conninfo 來的參數與數據庫打開一個新的聯接.與下面的 PQsetdbLogin() 不同的是,我們可以不必更換函數簽名(名字)就可以擴展參數集,所以我們建議應用程序中使用這個函數或者是它的非阻塞的相似函數 PQconnectStart / PQconnectPoll.傳入的參數可以為空,表明使用所有缺省的參數,或者可以包含一個或更多個用空白間隔的參數設置.
每個參數設置以 關鍵字=數值 keyword = value 的形式設置.(要寫一個空值或者一個包含空白的值,你可以用一對單引號包圍它們,例如,keyword = 'a value' .數值內部的單引號必須書寫為 \'.等號周圍的空白是可選的.)目前可識別的參數值是:
host
要聯接的主機(host ).如果聲明了一個非零長字符串,就將使用 TCP/IP 通訊.使用這個參數導致一個主機名的查找。參閱 hostaddr。
hostaddr
與之聯接的主機的 IP 地址。這個可以是標準的數字-點的形式,象在 BSD 函數 inet_aton 等裡面用的那樣。如果聲明了一個非零長的字符串,那使用 TCP/IP 通訊機制。
使用 hostaddr 取代 host 允許應用避免一次主機名查找,這一點對那些有時間約束的應用來說可能是非常重要的。不過,Kerberos 認証系統要求主機(host)名。因此,應用下面的規則。如果聲明了不帶 hostaddr 的 host 那就強制進行主機名查找。如果聲明中沒有 host,hostaddr 的值給出遠端的地址;如果使用了 Kerberos,將導致一次反向名字查詢。如果同時聲明了 host 和 hostaddr,除非使用了 Kerberos,否則將使用 hostaddr 的值作為遠端地址;host 的值將被忽略,如果使用了 Kerberos,host 的值用 Kerberos 認証。要注意如果傳遞給 libpq 的主機名(host)不是地址 hostaddr 處的機器名,那認証很有可能失敗。
如果主機名(host)和主機地址都沒有,那 libpq 將使用一個本地的 Unix 域套接字進行通訊。
port
主機服務器的端口號,或者在 Unix 主控套接字聯接時的套接字擴展文件名.
dbname
數據庫名.
user
要聯接的用戶名。
password
如果端要求口令認証,所用的口令.
options
發給端的跟蹤/調試選項.
tty
文件或控制台,用從端的可選調試輸出.
如果有任何沒有聲明的參數,那將檢查對應的環境變量(參閱"環境變量"章)。如果環境變量也沒有設置,那使用編譯時的硬代碼。返回的值是一個指向代表與端聯接的抽象結構的指針。
PQsetdbLogin 與端數據庫服務器建立一個新的聯接.
PGconn *PQsetdbLogin(const char *pghost,
const char *pgport,
const char *pgoptions,
const char *pgtty,
const char *dbName,
const char *login,
const char *pwd)
這個函數是 PQconnectdb 前身,它有固定個數的參數,但是有相同的功能。
PQsetdb 與端數據庫服務器建立一個新的聯接.
PGconn *PQsetdb(char *pghost,
char *pgport,
char *pgoptions,
char *pgtty,
char *dbName)
這是一個調用 PQsetdbLogin() 的宏,只是 login 和 pwd 參數用空(null )代替.提供這個函數主要是為了與老版本的程序兼容.
PQconnectStart PQconnectPoll 與數據庫服務器建立一次非阻塞的聯接。
PGconn *PQconnectStart(const char *conninfo)
PostgresPollingStatusType *PQconnectPoll(PQconn *conn)
著兩個過程用打開一個與數據庫服務器之間的非阻塞的聯接:你的應用的執行線索在運行的時候不會阻塞遠端的 I/O。
數據庫聯接是用從 conninfo 字符串裡取得的參數傳遞給 PQconnectStart 進行的。這個字符串的格式與上面 PQconnectdb 裡描述的一樣。
PQconnectStart 和 PQconnectPoll 都不會阻塞(進程),不過有一些限制:
必須正確提供 hostaddr 和 host 參數以確保不會發生正向或者反向的名字查找。參閱上面 PQconnectdb 裡的這些參數的文檔獲取細節。
如果你調用了 PQtrace,確保你跟蹤進入的流對象不會阻塞。
你必須在調用 PQconnectPoll 之前確保 socket 處正確的狀態,象下面描述的那樣。
要開始(聯接),調用 conn=PQconnectStart("")。如果 conn 是 NULL,表明 libpq 無法分配一個新的 PGconn 結構。否則,返回一個有效的 PGconn 指針(盡管還不一定代表一個與數據庫有效聯接)。PQconnectStart 一返回,調用 status=PQstatus(conn)。如果 status 等 CONNECTION_BAD,PQconnectStart 失敗。
如果 PQconnectStart 成功了,下一個階段是輪詢 libpq,這樣它就可以繼續進行繼的聯接動作。象這樣循環:認為一個聯接缺省時是'不活躍'的。如果 PQconnectPoll 的最一個返回是PGRES_POLLING_ACTIVE,則認為它是'活躍的'。如果 PQconnectPoll(conn) 的最一個返回是PGRES_POLLING_READING,執行一個對 PQsocket(conn) 的讀 select。如果最一個返回是PGRES_POLLING_WRITING,執行一個對 PQsocket(conn) 的寫 select。如果還沒(?)調用 PQconnectPoll,例如象在調用完 PQconnectStart 那樣,把它當作最返回PGRES_POLLING_WRITING 那樣對待。如果 select 顯示 socket 已經準備好,那認為它是'活躍的'。如果認為一個聯接是'活躍的',再次調用 PQconnectPoll(conn)。如果這次調用返回 PGRES_POLLING_FAILED,聯接過程失敗,如果這次調用返回 PGRES_POLLING_OK,聯接成功。
要注意上面用 select() 來確保一個 socket 準備好只是一個(近似)的例子;還可以用其他方法,比如一個 poll() 調用,來代替 select。
在聯接的任何時候,我們都可以通過調用 PQstatus 來檢查聯接的狀態。如果這是 CONNECTION_BAD,那聯接過程失敗;如果是 CONNECTION_OK,那聯接已經做好。著兩種狀態同樣也可以從上面的 PQconnectPoll 的返回值裡檢測到。其他狀態可能(也只能)在一次異步聯接過程中看到。這些標識聯接過程的當前狀態,因而可能對給用戶提供反饋有幫助。這些狀態可能包括:
CONNECTION_STARTED:等待進行聯接。
CONNECTION_MADE:聯接成功;等待發送。
CONNECTION_AWAITING_RESPONSE:等待來自 postmaster 的響應。
CONNECTION_AUTH_OK:已收到認証;等待端啟動。
CONNECTION_SETENV:協商環境。
注意,盡管這些常量將保持下去(為了維持兼容性),應用決不應該依賴這些常量的某種特定順序,或者是根本不應依賴這些常量,或者是不應該依賴這些狀態總是某個文檔聲明的值。一個應用可能象象下面這樣:
switch(PQstatus(conn))
{
case CONNECTION_STARTED:
feedback = "Connecting...";
break;
case CONNECTION_MADE:
feedback = "Connected to server...";
break;
.
.
.
default:
feedback = "Connecting...";
}
要注意如果 PQconnectStart 返回一個非空的指針,你必須在使用完它(指針)之調用 PQfinish,以處理那些結構和所有相關的存儲塊。甚至調用 PQconnectStart 或者 PQconnectPoll 失敗時也要這樣處理。
如果編譯 libpq 時定義了 USE_SSL 那目前的 PQconnectPoll 將阻塞住。這個限制可能在將來的版本移除。
除非編譯 libpq 時定義了 WIN32_NON_BLOCKING_CONNECTIONS,否則目前的 PQconnectPoll 將在 Windows 裡阻塞住。這些代碼還沒有在 Windows 裡測試過,因此目前缺省時是不帶這些代碼的。著一點以可能修改。
這些函數把 socket 置一個非阻塞的狀態,就好象調用了 PQsetnonblocking 一樣。
PQconndefaults 返回缺省的聯接選項。
PQconninfoOption *PQconndefaults(void)
struct PQconninfoOption
{
char *keyword; /* The keyword of the option */
char *envvar; /* Fallback environment variable name */
char *compiled; /* Fallback compiled in default value */
char *val; /* Option's current value, or NULL */
char *label; /* Label for field in connect dialog */
char *dispchar; /* Character to display for this field
in a connect dialog. Values are:
"" Display entered value as is
"*" Password field - hide value
"D" Debug option - don't show by default */
int dispsize; /* Field size in characters for dialog */
}
返回聯接選項結構的地址.可以用獲取所有可能的 PQconnectdb 選項和它們的當前缺省值.返回值指向一個 PQconninfoOption 結構數組,該數組以一個有 NULL 關鍵字指針的入口結束.注意缺省值("val" 域)將依賴環境變量和其他上下文.調用者必須把聯接選項當作只讀對待.
在處理完選項數組,把數組交給 PQconninfoFree() 釋放.如果沒有這做,每次調用 PQconndefaults() 都會有一小部分內存泄漏.
在 Postgres 7.0 以前的版本,PQconndefaults() 返回一個指向靜態數組的指針,而不是一個動態分配的數組.這樣做是線程不安全的,因此這個特點被修改了.
PQfinish 關閉與端的聯接.同時釋放被 PGconn 對象使用的存儲器.
void PQfinish(PGconn *conn)
注意,即使與端的聯接嘗試失敗(可由 PQstatus 判斷),應用也要調用 PQfinish 釋放被 PGconn 對象使用的存儲器.PGconn 指針不應該在調用 PQfinish 再使用.
PQreset 重置與端的通訊端口.
void PQreset(PGconn *conn)
此函數將關閉與端的聯接並且試圖與同一個 postmaster 重建新的聯接,使用所有前面使用過的參數.這在失去工作聯接進行故障恢復時很有用.
PQresetStart PQresetPoll 重置與端的非阻塞模式的通訊端口。
int PQresetStart(PGconn *conn);
PostgresPollingStatusType PQresetPoll(PGconn *conn);
此函數將關閉與端的聯接並且試圖與同一個 postmaster 重建新的聯接,使用所有前面使用過的參數.這在失去工作聯接進行故障恢復時很有用.它們和上面的 PQreset (above) 的區別是它們工作在非阻塞模式。這些函數的使用有與上面 PQconnectStart 和 PQconnectPoll 一樣的限制。
調用 PQresetStart。如果它返回 0,那重置失敗。如果返回 1,用與使用 PQconnectPoll 建立聯接的同樣的方法使用 PQresetPoll 重置聯接。
libpq 應用程序員應該仔細維護 PGconn 結構.使用下面的訪問函數來獲取 PGconn 的內容.避免直接引用 PGconn 結構裡的字段,因為這些字段在今可能被改變.(從PostgreSQL 版本 6.4 開始, 結構 PGconn 的定義甚至沒有放在 libpq-fe.h 裡.如果你有一些直接訪問 PGconn 數據域的舊代碼,你可以通過包含 libpq-int.h 來訪問它們,但我們鼓勵你趕快修改那些代碼.)
PQdb 返回聯接的數據庫名.
char *PQdb(const PGconn *conn)
PQdb 和下面幾個函數返回聯接建立起來的幾個值.這些值在 PGconn 對象的生存期內是固定的.
PQuser 返回聯接的用戶名.
char *PQuser(const PGconn *conn)
PQpass 返回聯接的口令.
char *PQpass(const PGconn *conn)
PQhost 返回聯接的服務器主機名.
char *PQhost(const PGconn *conn)
PQport 返回聯接的端口號.
char *PQport(const PGconn *conn)
PQtty 返回聯接的調試控制台( tty ).
char *PQtty(const PGconn *conn)
PQoptions 返回聯接中使用的端選項.
char *PQoptions(const PGconn *conn)
PQstatus 返回聯接的狀態.
ConnStatusType PQstatus(const PGconn *conn)
這個狀態可以是一些值之一。不過,在一次異步聯接過程以外的范圍裡只能看到其中的兩個 - CONNECTION_OK 或者 CONNECTION_BAD。一個與數據庫的成功的聯接返回狀態 CONNECTION_OK。一次失敗的企圖用狀態 CONNECTION_BAD 標識。通常,一個 OK 狀態保持到 PQfinish,但是一個通訊失敗可能會導致狀態永久的改變為 CONNECTION_BAD。這時應用可以試著調用 PQreset 來恢復.
參閱 PQconnectStart 和 PQconnectPoll 條目看看可能出現的其他的狀態碼。
PQerrorMessage 返回聯接中操作產生的最近的錯誤信息.
char *PQerrorMessage(const PGconn* conn);
幾乎所有 libpq 函數在失敗時都會設置 PQerrorMessage .注意 libpq 的傳統是,一個非空的 PQerrorMessage 將在結尾包含一個新行.
PQbackendPID 返回控制此聯接的端服務器的進程號(ID)。
int PQbackendPID(const PGconn *conn);
這個端 PID 在調試和對比 NOTIFY 信息(包含發出通知的端的 PID )時很有用.注意該 PID 屬運行數據庫服務器的主機的進程,而不是本地主機!
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
異步查詢處理
PQexec 函數對簡單的同步應用裡提交查詢已經是足夠用的了.但是它卻有幾個主要的缺陷:
PQexec 等待查詢結束.應用可能有其他工作要做(例如維護用戶界面),這時它可不希望阻塞在這裡等待返回.
因為控制是藏在 PQexec 內部,前端很難取消掉正進行著的查詢.(可以通過信號控制器進行,但沒有別的方法.)
PQexec 只能返回一個 PGresult 結構.如果提交的查詢字符串包含多個 SQL 命令,除了最一個 PGresult 以外都會被 PQexec 丟棄。
不想受到這些限制的應用可以改用下面的函數,這些函數也是構造 PQexec 的函數:PQsendQuery 和PQgetResult。
使用這些(異步)功能以及 PQputline 和 PQputnbytes 的老一些的程序可能在等待數據發送給端時阻塞住,要改變這樣的方式,增加了函數 PQsetnonblocking。
舊應用可以忽略 PQsetnonblocking 的使用,維持原有的阻塞特征。新的程序可以利用 PQsetnonblocking 獲得與端完全非阻塞的聯接。
PQsetnonblocking 把該聯接的狀態設置為非阻塞。
int PQsetnonblocking(PGconn *conn)
此函數將確保對 PQputline,PQputnbytes,PQsendQuery 和 PQendcopy 的調用不被阻塞,如果對它們的調用需要再次執行將是返回一個錯誤(而不是阻塞)。
當把一個數據庫的聯接設置為非阻塞的模式並且調用了 PQexec,它將暫時把聯接狀態設置為阻塞模式直到 PQexec 完成。
在不久的將來將有更多的 libpq 會設計成在 PQsetnonblocking 方式下是安全的。
PQisnonblocking 返回數據庫聯接的阻塞狀態。
int PQisnonblocking(const PGconn *conn)
如果聯接設置為非阻塞狀態,返回 TRUE,如果是阻塞狀態返回 FALSE。
PQsendQuery 向 Postgres 提交一個查詢而不等待結果.如果查詢成功發送則返回真(TRUE ),否則返回假(FALSE)(此時,可以用 PQerrorMessage 獲取關失敗的信息).
int PQsendQuery(PGconn *conn,
const char *query);
在成功調用 PQsendQuery ,調用 PQgetResult 一次或者多次獲取查詢結果.PQsendQuery 可以不再調用(在同一次聯接裡)直到 PQgetResult 返回 NULL,表明查詢完成.
PQgetResult 等待從前面 PQsendQuery 調用返回的下一個結果,然返回之.當查詢結束並且沒有更多結果返回 NULL.
PGresult *PQgetResult(PGconn *conn);
PQgetResult 必須重復的調用,直到它返回 NULL,表明該查詢結束.(如果在沒有激活查詢時調用, PQgetResult 將只是立即返回 NULL.)每個 PQgetResult返回的非空結果都應該用前面描述的 PGresult 訪問函數進行分析.不要忘了在結束分析用 PQclear 釋放每個結果對象.注意,PQgetResult 只是在有查詢激活而且必須的返回數據還沒有被 PQconsumeInput 讀取時阻塞.
使用 PQsendQuery 和 PQgetResult 解決了 PQexec 的一個問題:如果一個查詢字符串包含多個 SQL 命令,這些命令的結果可以獨立的獲得.(順便說一句:這樣就允許一種簡單的重疊處理模式,前端可以處理一個查詢的結果而端可以仍然在處理同一查詢字符串的面的查詢.)但是,調用 PQgetResult 將仍然導致前端被阻塞住直到端完成下一個SQL 命令.這一點可以通過合理的使用下面三個函數來避免:
PQconsumeInput 如果存在端來的輸入可用,則使用之.
int PQconsumeInput(PGconn *conn);
PQconsumeInput 通常返回 1 表明"沒有錯誤",而返回 0 表明有某種錯誤發生(同時設置 PQerrorMessage ).注意這個結果並不表明實際上是否收集了數據.在調用 PQconsumeInput 之,應用可以檢查 PQisBusy 和/或 PQnotifies 看一眼它們的狀態是否改變.
PQconsumeInput 可以在應用還沒有做好處理結果或通知的情況下被調用.這個過程將讀取可用的數據並且在一個緩沖區裡保存它,這樣導致一個 select(2) 讀準備好標識的生成.這樣應用就可以使用PQconsumeInput 立即清掉 select 條件,然在空閑的時候檢查結果.
PQisBusy 在查詢忙的時候返回 1 ,也就是說,PQgetResult 將阻塞住等待輸入.一個 0 的返回表明這時調用 PQgetResult 可以確保不阻塞.
int PQisBusy(PGconn *conn);
PQisBusy 本身將不會試圖從端讀取數據;所以必須先調用 PQconsumeInput ,否則忙狀態將永遠不會消除.
PQflush 試圖把任何正在排隊的數據沖刷到端,如果成功(或者發送隊列為空)返回 0,如果因某種原因失敗返回 EOF。
int PQflush(PGconn *conn);
在一個非阻塞的聯接調用 select 判斷是否有響應到達之前需要調用一個 PQflush。如果返回 0 則保証了與端的發送隊列裡面沒有待發送的數據。只有使用了 PQsetnonblocking 的應用需要這個。
PQsocket 獲取用端聯接套接字的文件描述符號.一個有效的描述符應該是 >= 0;一個 -1 表明當前沒有打開與端的聯接.
int PQsocket(const PGconn *conn);
PQsocket 應該用獲取準備調用 select(2) 的端套接字描述符.這就允許一個應用使用阻塞的聯接等待端的響應或者其他條件.如果 select(2) 的結果表明可以從端套接字讀取數據,那應該調用PQconsumeInput 讀取數據;之,PQisBusy,PQgetResult,和/或 PQnotifies 可用處理返回信息.
非阻塞的聯接(那些使用了 PQsetnonblocking 的聯接)在 PQflush 返回 0 之前,這表明沒有數據緩沖著等待發送給端,不應該使用 select。
一個使用這些函數的典型的前端將有一個主循環使用 select(2) 等待所有它必須處理的條件.其中一個條件將會是端來的數據已準備好,從 select 的角度來看就是 PQsocket 標識的文件描述符上已經有可讀取的數據.當主循環偵測到輸入準備好,它將調用 PQconsumeInput 讀取輸入.然可以調用 PQisBusy,如果 PQisBusy 返回 false(0)面可以跟著 PQgetResult。同樣它(用戶應用)可以調用 PQnotifies 測 NOTIFY 信息(參閱下面的 "異步通知").例子程序節裡面給出了一個例子程序.
一個使用 PQsendQuery/PQgetResult 的前端同樣也可以試圖取消一個正在被端處理的查詢.
PQrequestCancel 要求 Postgres 放棄處理當前查詢.
int PQrequestCancel(PGconn *conn);
如果取消的請求成功發送,返回值是 1,否則是 0.(如果為假,PQerrorMessage 會告之為什.)不過,取消請求的成功發送將不保証請求將產生作用.不管 PQrequestCancel 的返回值是什,應用都必須繼續使用 PQgetResult進行通常的續的結果讀取工作.如果取消動作生效,當前的查詢將提前退出並返回一個錯誤結果.如果取消動作失敗(也就是端已經處理完查詢了),那將沒有可見的結果.
注意:如果當前的查詢是事務的一部分,取消動作將退出整個事務.
PQrequestCancel 可以很好地從一個信號句柄裡調用.所以,如果取消動作可以從信號句柄裡發出的話,它也可以與簡單的 PQexec 一起使用.例如,psql 從一個 SIGINT 信號句柄裡調用 PQrequestCancel,因此允許交互地取消通過 PQexec 運行的查詢.注意,如果沒有與端建立聯接或者端當前沒有處理查詢, PQrequestCancel將不發生做用.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
查詢執行函數
一旦與數據庫服務器的聯接成功建立,便可用這裡描述的函數執行 SQL 查詢和命令。
PQexec 提交一個查詢給 Postgres 並且等待結果.
PGresult *PQexec(PGconn *conn,
const char *query);
返回一個 PGresult 指針或者也可能是一個 NULL 指針.通常返回一個非空(non-NULL)的指針,除非沒有內存或發生了象不能把查詢發送到端這樣的嚴重錯誤.如果返回的是 NULL,它應該被當作 PGRES_FATAL_ERROR 結果處理.用 PQerrorMessage 獲取有關錯誤的更多信息.
PGresult 結構封裝了端返回的查詢結果.libpq 應用程序員應該仔細維護 PGresult.用下面的訪問函數來獲取 PGresult 的內容.避免直接引用 PGresult 結構的數據域,因為這個結構可能會在未來被改變.(從 Postgres 版本 6.4 開始,結構 PGresult 的定義甚至都沒有放在 libpq-fe.h 裡.如果你有一些直接訪問 PGresult 數據域的老代碼,你可以通過包含 libpq-int.h 繼續使用它們,但是我們鼓勵你立刻修改代碼.)
PQresultStatus 返回查詢的結果狀態.
ExecStatusType PQresultStatus(const PGresult *res)
PQresultStatus 可以返回下面數值之一:
PGRES_EMPTY_QUERY -- 發送給端的字串是空的
PGRES_COMMAND_OK -- 成功完成一個沒有返回數據的命令
PGRES_TUPLES_OK -- 成功執行查詢
PGRES_COPY_OUT -- (從服務器)Copy Out (拷貝出)數據傳輸開始
PGRES_COPY_IN -- Copy In (拷貝入)(到服務器)數據傳輸開始
PGRES_BAD_RESPONSE -- 服務器的響應無法理解
PGRES_NONFATAL_ERROR
PGRES_FATAL_ERROR
如果結果狀態是 PGRES_TUPLES_OK,那下面的過程可以用從查詢的返回中抽取記錄信息.注意一個碰巧檢索了零條記錄的 SELECT 仍然顯示 PGRES_TUPLES_OK。PGRES_COMMAND_OK 用不返回記錄的命令(INSERT,UPDATE,等)。返回 PGRES_EMPTY_QUERY 的響應通常意味著客戶端軟件裡面的臭虫。
PQresStatus 把 PQresultStatus 返回的枚舉類型轉換成一個描述狀態碼的字符串常量。
char *PQresStatus(ExecStatusType status);
PQresultErrorMessage 返回與查詢關聯的錯誤信息,或在沒有錯誤時返回一個空字符串.
char *PQresultErrorMessage(const PGresult *res);
緊跟在一個 PQexec 或 PQgetResult 調用面,PQerrorMessage (對聯接)將返回與 PQresultErrorMessage (對結果)一樣的字符串.不過,一個 PGresult 將保有其錯誤信息直到被刪除,而連結的錯誤信息將在續的操作完成時被改變.當你想知道與某個 PGresult 相關聯的狀態時用 PQresultErrorMessage;當你想知道與聯接的最近一個操作相關聯的狀態時用 PQerrorMessage;
PQntuples 返回查詢結果裡的記錄(實例)個數.
int PQntuples(const PGresult *res);
PQnfields 返回查詢結果裡每個記錄的數據域(字段)的個數.
int PQnfields(const PGresult *res);
PQbinaryTuples 如果 PGresult 包含二進制記錄數據時返回 1,如果包含 ASCII 數據返回 0.
int PQbinaryTuples(const PGresult *res);
目前,二進制記錄數據只能從一個從 BINARY 遊標裡抽取數據的查詢返回.
PQfname 返回與給出的數據域索引相關聯的數據域(字段)的名稱.數據域索引從 0 開始
char *PQfname(const PGresult *res,
int field_index);
PQfnumber Returns the field (attribute) index associated with the given field name.
int PQfnumber(const PGresult *res,
const char *field_name);
-1 is returned if the given name does not match any field.
PQftype 返回與給定數據域索引關聯的數據域類型.整數返回值是一個該類型的內部編碼.數據域索引從 0 開始.
Oid PQftype(const PGresult *res,
int field_num);
你可以查詢系統表 pg_type 以獲取各種數據類型的名稱和屬性。內建的數據類型的OID 在源碼樹的 src/include/catalog/pg_type.h 文件裡定義。
PQfsize 返回與給定數據域索引關聯的數據域的大小.數據域索引從 0 開始.
int PQfsize(const PGresult *res,
int field_index);
PQfsize 返回在數據庫記錄裡面給該數據域分配的空間,換句話說就是該數據類型在服務器裡的二進制形式的大小(尺寸).如果該數據域是可變尺寸,返回 -1.
PQfmod 返回與給定數據域索引相關聯的類型相關的修正數據(??).數據域索引從 0 開始.
int PQfmod(const PGresult *res,
int field_index);
PQgetvalue 返回一個 PGresult 裡面的一條記錄的單獨的一個數據域(字段)的值.記錄和數據域索引從 0 開始.
char* PQgetvalue(const PGresult *res,
int tup_num,
int field_num);
對大多數查詢而言,PQgetvalue 返回的值是一個表示字段值的空(NULL)結尾的ASCII 字符串.但是如果 PQbinaryTuples() 為 1,PQgetvalue 返回的值就是該類型在端服務器內部的二進制表現形式(但是不包括尺寸字--如果數據域是變長的).這樣,把數據轉換成對應的 C 類型就是程序員的責任了.PQgetvalue 返回的指針指向一個本身是 PGresult 結構的一部分的存儲區域.我們不能更改它,並且如果我們要在 PGresult 結構的生存期還要使用它的話,我們必須顯式的把該數值拷貝到其他存儲器中.
PQgetlength 返回以字節計的數據域(字段)的長度.記錄和數據域索引從 0 開始.
int PQgetlength(const PGresult *res,
int tup_num,
int field_num);
這是某一特定數據值的實際數據長度,也就是由 PQgetvalue 指向的對象的尺寸.注意,對 ASCII 代表的數值,這個尺寸與 PQfsize 報告的二進制尺寸無關.
PQgetisnull 測試一個數據域是否為空(NULL).記錄和數據域索引從 0 開始.
int PQgetisnull(const PGresult *res,
int tup_num,
int field_num);
如果該域包含 NULL,函數返回 1,如果包含非空(non-null )值,返回 0.(注意,對一個 NULL 數據域,PQgetvalue 將返回一個空字符串,不是一個空指針.)
PQcmdStatus 返回產生 PGresult 的 SQL 命令的命令狀態字符串.
char * PQcmdStatus(const PGresult *res);
PQcmdTuples 返回被 SQL 命令影響的行的數量.
char * PQcmdTuples(const PGresult *res);
如果產生 PGresult 的 SQL 命令是 INSERT,UPDATE 或 DELETE,這裡返回涉及行的行數.如果是其他命令返回一個空字符串.
PQoidValue 返回一個插入的記錄的記錄對象標識(OID)如果SQL 命令是 INSERT.否則,返回 InvalidOid .
Oid PQoidValue(const PGresult *res);
如果你包含了 libpq 頭文件,那 Oid 和常量 InvalidOid 的類型將被定義。他們都是某種整型類型。
PQoidStatus 返回一個被插入的記錄的對象標識的字串,如果SQL 命令是 INSERT。否則. 返回一個空字串。
char * PQoidStatus(const PGresult *res);
因為有了 PQoidValue,我們不建議使用這個函數,而且它在線程裡使用也是不安全的。
PQprint 向指定的輸出流打印所有的記錄和(可選的)字段名稱.
void PQprint(FILE* fout, /* output stream */
const PGresult *res,
const PQprintOpt *po);
struct {
pqbool header; /* print output field headings and row count */
pqbool align; /* fill align the fields */
pqbool standard; /* old brain dead format */
pqbool html3; /* output html tables */
pqbool expanded; /* expand tables */
pqbool pager; /* use pager for output if needed */
char *fieldSep; /* field separator */
char *tableOpt; /* insert to HTML table ... */
char *caption; /* HTML caption */
char **fieldName; /* null terminated array of replacement field names */
} PQprintOpt;
這個函數以前被 psql 用打印查詢結果,但是現在已經不用這個函數了,並且此函數不再有活躍的支持。
PQclear 釋放與 PGresult 關聯的存儲器.當不再需要時,每個查詢結果都應該通過 PQclear 釋放.
void PQclear(PQresult *res);
你可以保留 PGresult 對象任意長的時間;當你提交新的查詢時它並不消失,甚至你斷開聯接也是這樣.要刪除它,你必須調用 PQclear.不這做將導致前端的存儲器泄漏.
PQmakeEmptyPGresult 構建一個給出狀態的空的 PGresult 對象.
PGresult* PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
這是 libpq 的內部過程,用分配和初始化一個空 PGresult 對象.它被輸出是因為一些應用需要自行生成結果對象(尤其是特定的帶有錯誤狀態的對象).如果 conn 非空(NULL)並且狀態指示一個錯誤,聯接當前的 errorMessage 被拷貝到 PGresult.注意最終對該對象要調用 PQclear,正如 libpq 本身返回的 PGresult 一樣.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
捷徑
PostgreSQL 提供一個發往端的函數調用的捷徑接口.這是一個通向系統內部的門,因而可能存在安全漏洞.大多數用戶應該不需要這個特性.
PQfn 通過捷徑接口執行請求的端函數.
PGresult* PQfn(PGconn* conn,
int fnid,
int *result_buf,
int *result_len,
int result_is_int,
const PQArgBlock *args,
int nargs);
fnid 參數是待執行的函數的對象標識(OID).result_buf 是放置返回值的緩沖區.調用者必須為返回值分配足夠的空間(這裡沒有檢查!).實際的返回值長度將被放在 result_len 指向的整數裡返回.如果預期返回值是 4-字節整數,把 result_is_int 設為 1;否則設為 0.(把 result_is_int 設為 1 告訴 libpq 必要時交換數值的字節序,這樣就可以正確地傳輸成客戶機上的整數值.當result_is_int 是 0 時,端發送回來的字節串不做修改.)args 和 nargs 聲明要傳入函數的參數.
typedef struct {
int len;
int isint;
union {
int *ptr;
int integer;
} u;
} PQArgBlock;
PQfn 總是返回一個有效的 PGresult*.在使用結果之前應該檢查 resultStatus.當結果不再使用,調用者有責任使用 PQclear 釋放 PGresult.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
異步通知
PostgreSQL 支持通過 LISTEN 和 NOTIFY 命令產生的異步通知.一個端用 LISTEN 命令注冊一個它感興趣的通知條件(也可以用 UNLISTEN 去掉這個注冊).所有正在監聽某一通知條件的端在該條件名的 NOTIFY (通知)被任何端執行都將被異步地通知.通知發出者不會傳遞附加的信息從到通知接收者.因此,很典型地是,任何實際的需要被傳遞的數據都是通過一個數據庫關系傳遞的.通常,條件名與相關聯的關系同名,但是並不是一定要與某個關系相關才行.
libpq 應用把 LISTEN 和 UNLISTEN 命令作為通常的 SQL 查詢提交.因此,通過調用 PQnotifies() 可以偵測到 NOTIFY 消息的到達.
PQnotifies 從一個來自端的未處理的通知信息列表中返回下一條通知.如果沒有未處理的信息則返回 NULL.一旦 PQnotifies 返回一條通知,該通知會被認為已處理並且將被從通知列表中刪除.
PGnotify* PQnotifies(PGconn *conn);
typedef struct pgNotify {
char relname[NAMEDATALEN]; /* name of relation
* containing data */
int be_pid; /* process id of backend */
} PGnotify;
在處理完 PQnotifies 返回的 PGnotify 對象,別忘了用 free() 把它釋放,以避免內存泄漏。
注意:在 PostgreSQL 6.4 和更高的版本裡,be_pid 是正在通知的端的 PID,而在早些的版本裡它總是你自己的端的PID。
第二個樣本程序給出一個使用異步通知的例子.
PQnotifies() 實際上不讀取端數據;它只是返回被前面的另一個libpq 函數吸收的信息.在以前的 libpq 的版本裡,周期性的收到通知(NOTIFY)信息的唯一方法是持續的提交查詢,即使是空查詢也可以,並且在每次 PQexec() 檢查 PQnotifies()。現在這個方法也能還工作,不過我們認為它太浪費處理器時間而廢棄了它。
在你沒有可用的查詢提交時檢查 NOTIFY 消息的更好的方法是調用 PQconsumeInput(),然檢查 PQnotifies().你可以使用 select(2) 來等待端數據的到達,這樣在沒有數據可處理時可以不浪費CPU 時間.注意這種方法不管你使用 PQsendQuery/ PQgetResult 還是簡單的 PQexec 來執行查詢都能工作.不過,你應該記住在每次 PQgetResult 或 PQexec 檢查 PQnotifies(),看看在處理查詢的過程中是否有通知到達.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
與 COPY 命令相關的函數
PostgreSQL 裡的 COPY 命令裡有用 libpq 裡從網絡聯接讀出或者寫入的選項.因此,這些函數有必要直接訪問網絡聯接,以便應用可以充分利用這個功能.
這些函數應該只在從 PQexec 或 PQgetResult 獲得了 PGRES_COPY_OUT 或 PGRES_COPY_IN 結果對象的情況下執行.
PQgetline 讀取一個以回車符(換行符)結尾的字符行中指定字節數的字符(由端服務器傳輸)到一個字符串緩沖區.
int PQgetline(PGconn *conn,
char *string,
int length)
類似 fgets(3),這個過程拷貝最多 length-1 個字符到字符串裡.但是它會象 gets(3) 那樣把結尾的換行符轉換成一個空字符(null).PQgetline 在碰到 EOF 時返回 EOF,如果整行都被讀取了返回 0,如果緩沖區填滿了而還沒有遇到結束的換行符則返回 1.
注意,應用程序必須檢查新行是否包含兩個字符 "\.",這表明端服務器已經完成了 copy 命令的結果集的發送.如果應用可能收到超過 length-1 字符長的字符,我們就應該確保正確識別"\."行(例如,不要把一個長的行的結束當作一個終止行).src/bin/psql/copy.c 裡的代碼包含正確控制 copy 協議的過程.
PQgetlineAsync 不做阻塞地讀取一行以換行符結尾的字符(由端服務器傳輸)到一個緩沖區中.
int PQgetlineAsync(PGconn *conn,
char *buffer,
int bufsize)
這個過程類似 PQgetline,但是可以用那些必須異步地讀取 COPY 數據的應用,因而是不阻塞的.在使用了 COPY 命令和獲取了 PGRES_COPY_OUT 響應之,應用應該調用 PQconsumeInput 和 PQgetlineAsync 直到收到數據結束的信號.不象 PQgetline,這個過程負責檢測數據結束.在每次調用時,如果 libpq 的輸入緩沖區內有可用的一個完整的換行符結尾的數據行或者調用者聲明的緩沖區小到來的數據行的長度,PQgetlineAsync 都將返回數據.否則,在其他數據到達之前不會返回數據.
如果見到了拷貝數據結束的信號,此過程返回 -1,如果沒有可用數據返回 0,或者是給出一個正數表明返回的數據的字節數.如果返回 -1,調用者下一步必須調用 PQendcopy,然回到正常處理.返回的數據將不會超出換行符的范圍.如果可能,每次將返回一個完整行.但如果調用者提供的緩沖區太小,無法容下端發出的整行,那將返回部分行.這個可以通過測試返回的最一個字節是否“\n” 來確認.返回的字符串不是空結尾的.(如果你想得到一個空結尾的字串,確保你傳遞了一個比實際大小少一字節的緩沖區.)
PQputline 向端服務器發送一個空結尾的字符串.成功時返回 0,如果不能發送字符串返回 EOF.
int PQputline(PGconn *conn,
const char *string);
注意,應用在最一行時必須顯式的發送兩個字符 "\.",通知端它已經完成數據發送.
PQputnbytes 向端服務器發送一個非空結尾的字符串.成功時返回 0,如果不能發送字符串返回 EOF.
int PQputnbytes(PGconn *conn,
const char *buffer,
int nbytes);
此函數類似 PQputline,除了數據緩沖區不需要是空結尾的,因為要發送的字節數是直接聲明的.
PQendcopy 與端同步.這個函數等到端完成拷貝(才返回?).你可以在用 PQputline 向端發送完最一個字符串或者用 PGgetline 從端獲取最一行字符串調用它.我們必須調用這個函數,否則端可能會和前端“同步丟失”。在這個函數返回,端就已經準備好接收下一個查詢了.成功時返回 0,否則返回非零值.
int PQendcopy(PGconn *conn);
一個例子:
PQexec(conn, "create table foo (a int4, b char(16), d float8)");
PQexec(conn, "copy foo from stdin");
PQputline(conn, "3\thello world\t4.5\n");
PQputline(conn,"4\tgoodbye world\t7.11\n");
...
PQputline(conn,"\\.\n");
PQendcopy(conn);
在使用 PQgetResult 時,應用應該對 PGRES_COPY_OUT 的結果做出反應:重復調用 PQgetline,並且在收到結束行時調用 PQendcopy.然應該返回到 PQgetResult 循環直到 PQgetResult 返回 NULL.類似的 PGRES_COPY_IN 結果是用一系列 PQputline 調用最跟著 PQendcopy,然返回到 PQgetResult 循環.這樣的排列將保証嵌入到一系列SQL 命令裡的 copy in 或 copy out 命令將被正確執行.
舊的應用大多通過 PQexec 提交一個 copy in 或 copy out 命令並且假設在 PQendcopy 事務完成.這樣只有在 copy in/out 是查詢字符串裡的唯一的 SQL 命令才能正確工作.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
libpq 跟蹤函數
PQtrace 打開對前端/端通訊的跟蹤,把調試信息輸出到一個文件流裡.
void PQtrace(PGconn *conn
FILE *debug_port)
PQuntrace 關閉 PQtrace 打開的跟蹤
void PQuntrace(PGconn *conn)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
libpq 控制函數
PQsetNoticeProcessor 控制 libpq 生成的通知和警告信息的匯報.
typedef void (*PQnoticeProcessor) (void *arg, const char *message);
PQnoticeProcessor
PQsetNoticeProcessor(PGconn *conn,
PQnoticeProcessor proc,
void *arg);
缺省時, libpq 在端往 stderr 上打印“通知”信息和一些它自身生成的錯誤信息.這個特性可以通過提供一個對信息進行某種加工的回叫函數來更改.我們向這個回叫函數傳遞錯誤信息的文本(包括文本結尾的換行符),和一個空(void)指針,該指針與傳遞給 PQsetNoticeProcessor 的完全一樣.(如果需要,這個指針可以用訪問應用相關的狀態.)缺省的通知處理器只是簡單的
static void
defaultNoticeProcessor(void * arg, const char * message)
{
fprintf(stderr, "%s", message);
}
要使用特殊的通知處理器,在創建完新的 PGconn 對象馬上調用 PQsetNoticeProcessor。
返回值是指向以前的通知處理器的指針。如果你提供了一個 NULL 做為回調指針,那不會發生任何動作,只是返回當前的指針。
一旦你設置了一個通知處理器,你就應該預料到該函數可能在 PGconn 對象或 PGresult 對象從開始存在時起就可能被調用.當創建一個 PGresult 時,PGconn 的當前的通知指針被拷貝到 PGresult 裡提供給可能需要的過程,如 PQgetvalue 使用.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
環境變量
下面的環境變量可以用選擇缺省的聯接參數值,這些值將被 PQconnectdb 或 PQsetdbLogin 使用--如果調用代碼沒有直接聲明相應值的話.這些(環境變量)可以避免把麻煩的數據庫名強加入簡單的應用程序的硬代碼裡面.The following environment variables can be used to select default connection parameter values, which will be used by PQconnectdb or PQsetdbLogin if no value is directly specified by the calling code. These are useful to avoid hard-coding database names into simple application programs.
PGHOST 設置缺省的服務器名.如果聲明了一個非零長的字符串,將使用 TCP/IP 通訊.如果沒有主機名,libpq 將使用本地的Unix 域套接字.
PGPORT 設置與 Postgres 端通訊的缺省端口號或本地 Unix 主控套接字的文件擴展(文件標識符).
PGDATABASE 設置缺省的 PostgreSQL 數據庫名.
PGUSER 設置用與數據庫聯接和用認証的用戶名.
PGPASSWORD 如果端要求口令認証,設置使用的口令.
PGREALM 設置與 Postgres 一起使用的 Kerberos --如果該域與本地域不同的話。如果設置了 PGREALM,Postgres 應用將試圖用這個域(realm)與服務器進行認証並且使用獨立的門票文件(ticket files)以避免與本地的門票文件沖突.只有在端選擇了 Kerberos 認証時才使用這個環境變量.(譯注:門票文件是 Kerberos 認証協議中用交換密鑰的一個文件/服務器。)
PGOPTIONS 為 Postgres 設置附加的運行時選項.
PGTTY 設置端調試信息顯示輸出的文件或者控制台(tty).
下面的環境變量可以用為每個 Postgres 會話聲明用戶級別的缺省特性:
PGDATESTYLE 設置缺省的日期/時間表現形式.
PGTZ 設置缺省的時區.
PGCLIENTENCODING 設置缺省的客戶端編碼(如果配制 Postgres 時選擇了 MULTIBYTE 支持).
下面的環境變量可以用為每個 Postgres 會話聲明缺省的內部特性:
PGGEQO 為基因優化器設置缺省模式.
參閱 SET SQL 命令獲取這些環境變量的正確值的信息.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
線程特性
到 Postgres 7.0 時 libpq 是線程安全的,只要不是兩個線程試圖同時操作同一個 PGconn 對象.實際上,你無法從不同的線程向同一個聯接對象發出並發的查詢.(如果你需要運行並行查詢,請啟動多個聯接.)
PGresult 對象在創建是只讀的,因此可以自由地在線程之間傳遞.
過時了的函數 PQoidStatus 和 fe_setauthsvc 都是線程不安全的,因此不應該在一個多線程的程序裡面使用.PQoidStatus 可以由 PQoidValue代替.而我們覺得根本沒有調用 fe_setauthsvc 的必要.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
例子程序
例子程序 1
/*
* testlibpq.c Test the C version of Libpq, the Postgres frontend
* library.
*
*
*/
#include
#include "libpq-fe.h"
void
exit_nicely(PGconn *conn)
{
PQfinish(conn);
exit(1);
}
main()
{
char *pghost,
*pgport,
*pgoptions,
*pgtty;
char *dbName;
int nFields;
int i,
j;
/* FILE *debug; */
PGconn *conn;
PGresult *res;
/*
* begin, by setting the parameters for a backend connection if the
* parameters are null, then the system will try to use reasonable
* defaults by looking up environment variables or, failing that,
* using hardwired constants
*/
pghost = NULL; /* host name of the backend server */
pgport = NULL; /* port of the backend server */
pgoptions = NULL; /* special options to start up the backend
* server */
pgtty = NULL; /* debugging tty for the backend server */
dbName = "template1";
/* make a connection to the database */
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
/*
* check to see that the backend connection was successfully made
*/
if (PQstatus(conn) == CONNECTION_BAD)
{
fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
fprintf(stderr, "%s", PQerrorMessage(conn));
exit_nicely(conn);
}
/* debug = fopen("/tmp/trace.out","w"); */
/* PQtrace(conn, debug); */
/* start a transaction block */
res = PQexec(conn, "BEGIN");
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "BEGIN command failed\n");
PQclear(res);
exit_nicely(conn);
}
/*
* should PQclear PGresult whenever it is no longer needed to avoid
* memory leaks
*/
PQclear(res);
/*
* fetch instances from the pg_database, the system catalog of
* databases
*/
res = PQexec(conn, "DECLARE mycursor CURSOR FOR select * from pg_database");
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "DECLARE CURSOR command failed\n");
PQclear(res);
exit_nicely(conn);
}
PQclear(res);
res = PQexec(conn, "FETCH ALL in mycursor");
if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, "FETCH ALL command didn't return tuples properly\n");
PQclear(res);
exit_nicely(conn);
}
/* first, print out the attribute names */
nFields = PQnfields(res);
for (i = 0; i < nFields; i++)
printf("%-15s", PQfname(res, i));
printf("\n\n");
/* next, print out the instances */
for (i = 0; i < PQntuples(res); i++)
{
for (j = 0; j < nFields; j++)
printf("%-15s", PQgetvalue(res, i, j));
printf("\n");
}
PQclear(res);
/* close the cursor */
res = PQexec(conn, "CLOSE mycursor");
PQclear(res);
/* commit the transaction */
res = PQexec(conn, "COMMIT");
PQclear(res);
/* close the connection to the database and cleanup */
PQfinish(conn);
/* fclose(debug); */
return 0;
}
例子程序 2
/*
* testlibpq2.c
* Test of the asynchronous notification interface
*
* Start this program, then from psql in another window do
* NOTIFY TBL2;
*
* Or, if you want to get fancy, try this:
* Populate a database with the following:
*
* CREATE TABLE TBL1 (i int4);
*
* CREATE TABLE TBL2 (i int4);
*
* CREATE RULE r1 AS ON INSERT TO TBL1 DO
* (INSERT INTO TBL2 values (new.i); NOTIFY TBL2);
*
* and do
*
* INSERT INTO TBL1 values (10);
*
*/
#include
#include "libpq-fe.h"
void
exit_nicely(PGconn *conn)
{
PQfinish(conn);
exit(1);
}
main()
{
char *pghost,
*pgport,
*pgoptions,
*pgtty;
char *dbName;
int nFields;
int i,
j;
PGconn *conn;
PGresult *res;
PGnotify *notify;
/*
* begin, by setting the parameters for a backend connection if the
* parameters are null, then the system will try to use reasonable
* defaults by looking up environment variables or, failing that,
* using hardwired constants
*/
pghost = NULL; /* host name of the backend server */
pgport = NULL; /* port of the backend server */
pgoptions = NULL; /* special options to start up the backend
* server */
pgtty = NULL; /* debugging tty for the backend server */
dbName = getenv("USER"); /* change this to the name of your test
* database */
/* make a connection to the database */
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
/*
* check to see that the backend connection was successfully made
*/
if (PQstatus(conn) == CONNECTION_BAD)
{
fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
fprintf(stderr, "%s", PQerrorMessage(conn));
exit_nicely(conn);
}
res = PQexec(conn, "LISTEN TBL2");
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "LISTEN command failed\n");
PQclear(res);
exit_nicely(conn);
}
/*
* should PQclear PGresult whenever it is no longer needed to avoid
* memory leaks
*/
PQclear(res);
while (1)
{
/*
* wait a little bit between checks; waiting with select()
* would be more efficient.
*/
sleep(1);
/* collect any asynchronous backend messages */
PQconsumeInput(conn);
/* check for asynchronous notify messages */
while ((notify = PQnotifies(conn)) != NULL)
{
fprintf(stderr,
"ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
notify->relname, notify->be_pid);
free(notify);
}
}
/* close the connection to the database and cleanup */
PQfinish(conn);
return 0;
}
例子程序 3
/*
* testlibpq3.c Test the C version of Libpq, the Postgres frontend
* library. tests the binary cursor interface
*
*
*
* populate a database by doing the following:
*
* CREATE TABLE test1 (i int4, d float4, p polygon);
*
* INSERT INTO test1 values (1, 3.567, '(3.0, 4.0, 1.0,
* 2.0)'::polygon);
*
* INSERT INTO test1 values (2, 89.05, '(4.0, 3.0, 2.0,
* 1.0)'::polygon);
*
* the expected output is:
*
* tuple 0: got i = (4 bytes) 1, d = (4 bytes) 3.567000, p = (4
* bytes) 2 points boundbox = (hi=3.000000/4.000000, lo =
* 1.000000,2.000000) tuple 1: got i = (4 bytes) 2, d = (4 bytes)
* 89.050003, p = (4 bytes) 2 points boundbox =
* (hi=4.000000/3.000000, lo = 2.000000,1.000000)
*
*
*/
#include
#include "libpq-fe.h"
#include "utils/geo-decls.h" /* for the POLYGON type */
void
exit_nicely(PGconn *conn)
{
PQfinish(conn);
exit(1);
}
main()
{
char *pghost,
*pgport,
*pgoptions,
*pgtty;
char *dbName;
int nFields;
int i,
j;
int i_fnum,
d_fnum,
p_fnum;
PGconn *conn;
PGresult *res;
/*
* begin, by setting the parameters for a backend connection if the
* parameters are null, then the system will try to use reasonable
* defaults by looking up environment variables or, failing that,
* using hardwired constants
*/
pghost = NULL; /* host name of the backend server */
pgport = NULL; /* port of the backend server */
pgoptions = NULL; /* special options to start up the backend
* server */
pgtty = NULL; /* debugging tty for the backend server */
dbName = getenv("USER"); /* change this to the name of your test
* database */
/* make a connection to the database */
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
/*
* check to see that the backend connection was successfully made
*/
if (PQstatus(conn) == CONNECTION_BAD)
{
fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
fprintf(stderr, "%s", PQerrorMessage(conn));
exit_nicely(conn);
}
/* start a transaction block */
res = PQexec(conn, "BEGIN");
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "BEGIN command failed\n");
PQclear(res);
exit_nicely(conn);
}
/*
* should PQclear PGresult whenever it is no longer needed to avoid
* memory leaks
*/
PQclear(res);
/*
* fetch instances from the pg_database, the system catalog of
* databases
*/
res = PQexec(conn, "DECLARE mycursor BINARY CURSOR FOR select * from test1");
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "DECLARE CURSOR command failed\n");
PQclear(res);
exit_nicely(conn);
}
PQclear(res);
res = PQexec(conn, "FETCH ALL in mycursor");
if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, "FETCH ALL command didn't return tuples properly\n");
PQclear(res);
exit_nicely(conn);
}
i_fnum = PQfnumber(res, "i");
d_fnum = PQfnumber(res, "d");
p_fnum = PQfnumber(res, "p");
for (i = 0; i < 3; i++)
{
printf("type[%d] = %d, size[%d] = %d\n",
i, PQftype(res, i),
i, PQfsize(res, i));
}
for (i = 0; i < PQntuples(res); i++)
{
int *ival;
float *dval;
int plen;
POLYGON *pval;
/* we hard-wire this to the 3 fields we know about */
ival = (int *) PQgetvalue(res, i, i_fnum);
dval = (float *) PQgetvalue(res, i, d_fnum);
plen = PQgetlength(res, i, p_fnum);
/*
* plen doesn't include the length field so need to
* increment by VARHDSZ
*/
pval = (POLYGON *) malloc(plen + VARHDRSZ);
pval->size = plen;
memmove((char *) &pval->npts, PQgetvalue(res, i, p_fnum), plen);
printf("tuple %d: got\n", i);
printf(" i = (%d bytes) %d,\n",
PQgetlength(res, i, i_fnum), *ival);
printf(" d = (%d bytes) %f,\n",
PQgetlength(res, i, d_fnum), *dval);
printf(" p = (%d bytes) %d points \tboundbox = (hi=%f/%f, lo = %f,%f)\n",
PQgetlength(res, i, d_fnum),
pval->npts,
pval->boundbox.xh,
pval->boundbox.yh,
pval->boundbox.xl,
pval->boundbox.yl);
}
PQclear(res);
/* close the cursor */
res = PQexec(conn, "CLOSE mycursor");
PQclear(res);
/* commit the transaction */
res = PQexec(conn, "COMMIT");
PQclear(res);
/* close the connection to the database and cleanup */
PQfinish(conn);
return 0;
}
--------------------------------------------------------------------------------
(http://www.fanqiang.com)
進入【UNIX論壇】
|
|
| 相關文章 |
PostgreSQL7.0手冊-附錄-文檔 (2001-04-21 23:50:44) PostgreSQL7.0手冊-附錄-日期/時間支持-CVS 倉庫 (2001-04-21 23:48:48) PostgreSQL7.0手冊-教程 -73. Postgres SQL 高級特性 (2001-04-21 23:45:36) PostgreSQL7.0手冊-教程 -72. 查詢語言 (2001-04-21 23:44:40) PostgreSQL7.0手冊-教程 -71. 開始 (2001-04-21 23:42:54) PostgreSQL7.0手冊-教程 -70. 體系結構 (2001-04-21 23:41:58) PostgreSQL7.0手冊-教程 -69. SQL (2001-04-21 23:41:23) PostgreSQL7.0手冊-開發者手冊 -68. 分頁文件 (2001-04-21 23:39:22) PostgreSQL7.0手冊-開發者手冊 -67. 端接口 (2001-04-21 23:38:34) PostgreSQL7.0手冊-開發者手冊 -66. gcc 缺省優化 (2001-04-21 23:37:20)
|
===更多相關=== |
|
|
 |
★ 樊強制作 歡迎分享 ★ |