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

首頁 > 數據庫 > PostgreSQL > 正文

PostgreSQL7.0手冊-接口-53. libpq - C 庫

2019-09-08 23:34:13
字體:
來源:轉載
供稿:網友
第五十三章. 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,"http://./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;
}

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

圖片精選

主站蜘蛛池模板: 视频一区二区在线观看 | 国产午夜精品一区二区三区四区 | 夜间福利网站 | 精品1 | 在线成人看片 | 国产精选91 | 中文字幕在线观看91 | 宅男噜噜噜66国产免费观看 | 亚洲国产网址 | 色中色激情影院 | 亚洲精品午夜在线 | 日本在线不卡一区二区 | 欧洲成人一区 | 久久激情免费视频 | a网站在线 | 全黄性性激高免费视频 | 精品国产一区二区三区久久久蜜月 | 99日韩精品视频 | 欧美偷拍一区二区 | 日本成人在线播放 | a黄网站| 激情九九| 欧美精品一区自拍a毛片在线视频 | 国产一区二区午夜 | 成人福利在线播放 | 成人做爰高潮片免费视频韩国 | 成人一区二区三区在线 | 午夜精品老牛av一区二区三区 | 欧美激情精品久久久久久黑人 | 成人性爱视频在线观看 | 麻豆视频在线观看免费网站 | 黄色男女视频 | 精品国产乱码久久久久久久 | 一区二区三区四区高清视频 | 国产男女 爽爽爽爽视频 | 日韩精品一区二区三区中文 | 中国洗澡偷拍在线播放 | 一级观看免费完整版视频 | 国产精品一区二区免费在线观看 | 日本网站一区 | 成人午夜激情视频 |