postgresql 數據庫的 c 語言接口libpq簡介
libpq 是 postgresql 數據庫的 c 語言接口,在 c 程序中通過 libpq 庫訪問 postgresql 數據庫并進行數據庫操作
數據庫連接控制函數
下面的函數處理到 PostgreSQL 后端服務器的連接。一個應用程序可以同時打開多個后端連接。(其中一個原因是訪問多個數據庫。)每個連接由一個 PGconn 對象表示,該對象可以通過 PQconnectdb, PQconnectdbParams, 或者 PQsetdbLogin 函數獲得。注意這些函數總是返回一個非空對象指針,除非內存不足以分配 PGconn 對象。在通過該連接對象發送查詢請求之前應該先調用 PQstatus 函數檢查連接是否成功。
- PQconnectdbParams
創建一個連接到數據庫服務器。
PGconn *PQconnectdbParams(const char * const *keywords, const char * const *values, int expand_dbname);
該函數使用兩個 NULL 結尾的數組作為參數打開一個新的數據庫連接。第一個 keywords 是一個字符串數組,每個值是一個關鍵字。第二個 values 給定每個關鍵字的值。
當前識別的關鍵字在關鍵字列表中列出。
傳入的數組可以為空,這樣它就會使用默認值,或者包括一個或多個參數設置。兩個數組的長度應該相同。程序識別到 keywords 數組最后一個非空元素時停止參數解析。
一般來說按照數組索引順序處理關鍵字。結果是如果某個關鍵字重復了,就會使用最后的那一個值,因此要特別注意參數的順序,尤其是 dbname,很可能會被 conninfo 字符串覆蓋。
創建一個連接到數據庫服務器。
PGconn *PQconnectdb(const char *conninfo);
該函數使用從 conninfo 字符串獲得的參數打開一個新的連接到數據庫。
傳遞的字符串可以為空,這樣就會使用默認值。也可以包括一個或多個由空格分隔的參數設置,還可以是一個 URI。關于合法的 URI,可以查看
URI章節。
</div>創建一個連接到數據庫服務器。
PGconn *PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pgtty, const char *dbName, const char *login, const char *pwd);
這是 PQconnectdb 之前的版本,只支持后者的部分參數。它們有相同的功能,除了前者將不支持的參數都使用默認值。
如果 dbName 包括 ‘=’ 符號或者有一個有效的 URI 前綴,會被作為一個傳入 PQconnectdb 的 conninfo,其余的參數會像為 PQconnectdbParams 那樣處理。
關閉到服務器的連接。同時釋放 PGconn 對象使用的內存。
void PQfinish(PGconn *conn);
注意即使服務器連接嘗試失敗了,應用程序也應該調用 PQfinish 釋放 PGconn 對象占用的內存。調用 PGfinish 之后不能再使用該 PGconn 指針。
重置到服務器的連接。
void PQreset(PGconn *conn);
該函數會關閉到服務器的連接,然后嘗試再次使用和之前完全相同的參數建立一個新的連接。這在連接丟失進行錯誤恢復的時候非常有用。
</ul>連接字符串
- keyword/value 連接字符串
- URI
- host
- hostaddr
- port
- dbname
- user
- password
- connect_timeout
- PQdb
- PQuser
- PQpass
- PQhost
- PQport
- PQstatus
- PQparameterStatus
- PQerrorMessage
- PQexec
- PQexecParams
- PQprepare
- PQexecPrepared
第一種方式是每個參數設置都是 keyword = value 的形式,其中等號兩邊的空格是可選的。要設置一個空值或者包括空格的值,應該用單引號括起來。值中的單引號或者反斜杠必須使用一個反斜杠進行轉義。
事例:
host=localhost port=5432 dbname=mydb connect_timeout=10
URI 的一般形式是:
postgresql://[user[:password]@][netlocation][:port][/dbname][?param1=value1&...]
URI 模式可以是 postgresql:// 或者 postgres://。URI 的每個部分都是可選的。下面是一些有效 URI 的例子:
postgresql:// postgresql://localhost postgresql://localhost:5433 postgresql://localhost/mydb postgresql://user@localhost postgresql://user:secret@localhost postgresql://other@localhost/otherdb?connect_timeout=10&application_name=myapp
URI 中的成員也可以作為參數指定值,例如:
postgresql:///mydb?host=localhost&port=5433
對于關鍵字部分沒有列出的參數都會被忽視,而且會發送一個相關的 warning 到 stderr。
</ol>關鍵字
當前能識別的關鍵字包括:
連接到的主機名。如果用一個斜杠開頭,則表示 Unix-域 連接,而不是 TCP/IP 連接,值是保存 socket 文件的目錄。
主機的 IP 地址。值應該是一個標準的 IPv4 或 IPv6 地址,例如 172.28.40.9。
服務器主機的連接端口,或 socket 文件名擴展。
要連接的數據庫名稱,默認和用戶名相同。
PostgreSQL 用戶名,默認和運行程序的系統用戶名相同。
用戶名對應的密碼。
最大等待時間,單位為秒。0 或者不指定表示無窮大。不推薦使用低于2秒的超時。
</ul>這里只介紹了部分常用的關鍵字,關于完整的支持關鍵字,可以查看 官方文檔 。
連接狀態函數
以下這些函數可以獲得現有數據庫連接對象的信息,這些值在 PGconn 對象的生命周期內有效。
返回連接的數據庫名稱。
char* PQdb(const PGconn *conn);
返回連接的用戶名稱。
char* PQuser(const PGconn *conn);
返回連接的用戶名密碼。
char* PQpass(const PGconn *conn);
返回連接的服務器主機名。
char* PQhost(const PGconn *conn);
返回連接的端口。
char* PQport(const PGconn *conn);
返回連接的狀態。
ConnStatusType PQstatus(const PGconn *conn);
查看當前連接的某個參數設置。
const char *PQparameterStatus(const PGconn *conn, const char *paramName);
返回最近連接操作產生的錯誤信息。
har *PQerrorMessage(const PGconn *conn);</ul>
更完整的可用連接狀態函數介紹,可以查看 官方文檔 。
命令執行函數
主要函數
提交一個命令到服務器并等待結果。
PGresult *PQexec(PGconn *conn, const char *command);
返回一個 PGresult 指針或者空指針。除非內存不夠或者發生重大錯誤,例如無法發送命令到服務器,都會返回一個非空指針。然后應該調用 PQresultStatus 函數檢查返回值看是否有錯誤(包括空指針,此時會返回 PGRES_FATAL_ERROR),要獲得關于錯誤的詳細信息,可以調用 PQerrorMessage 函數。
command 字符串可以包括多個 SQL 命令(用分號分隔)。在一個 PQexec 中發送的多個查詢會作為一個事務處理,除非查詢中包括顯式的 BEGIN/COMMIT 命令,此時會被作為多個事務處理。注意返回的 PGresult 結構體只是最后一個命令的執行結果。
提交一個命令到服務器并等待結果,可以傳遞參數。
PGresult *PQexecParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char * const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat);
PQexecParams 和 PQexec 類似,但提供了更多的功能:參數的值可以和命令字符串隔離,可以以二進制或者文本形式返回結果。
函數的參數包括:
conn 命令發送到的連接 command 要執行的命令。如果使用了參數,在命令字符串中通過 $1,$2... 使用。 nParams 提供的參數的數目,即 paramTypes[], paramValues[], paramLengths[], 和 paramFormats[] 數組的長度。nParam 為 0 的時候數組可以為空。 paramTypes[] 參數符號數據類型的 OID 值,可以在 postgresql 中通過 select typname, oid from pg_type 查看數據類型對應的 oid。如果 paramTypes 為空 或者其中的某一個值為 0,服務器會像無類型字面字符串那樣為參數符號推斷數據類型。 paramValues[] 指定參數的實際值。數組中的空指針表示對應的參數值為空;否則指針指向以0結尾的文本字符串(text 格式)或者二進制數據(二進制格式)。 paramLengths[] 指定二進制格式參數的實際數據長度(字節數)。空參數或者 text 格式參數會忽視這個值。沒有二進制參數的時候該數組可為空。 paramFormats[] 指定參數是 text(對應參數位置值置為 0)還是binary 格式(對應參數位置置為 1)。如果數組為空,認為所有參數都是 text 字符串。 以二進制格式傳遞的值要求了解后端的內部表示。例如 integer 必須以網絡字節序傳遞(大端法)。如果主機是小端(大部分機器都是小端的),則需要手動進行字節序轉換。 resultFormat 0 表示以 text 格式返回結果,1 表示二進制格式。
PQexecParams 和 PQexec 相比最大的好處是參數值可以和命令字符串分離,從而避免冗長而又容易出錯的引號和轉義。
不像 PQexec,PQexecParams 的命令字符串中只允許一個查詢。
提交一個請求用于根據指定的參數創建 prepared 語句并等待執行結果。
PGresult *PQprepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes);
PQprepare 創建一個 prepared 語句用于后面 PQexecPrepared 的執行。這個功能使得要重復執行的命令只需要進行一次語法解析和計劃生成。而不是每次執行的時候都要進行。
該函數為 query 字符串創建一個名為 stmtName 的 prepared 語句,其中 query 只包括一個 SQL 命令。stmtName 可以為空 “” 用于創建一個無命名語句,這種情況下任何之前的無命名語句都會被自動替換;否則如果在當前會話中已經定義了該 stmtName 就會產生錯誤。如果使用了參數,在查詢中通過 $1,$2…引用。這里的 nParams, paramTypes 和 之前介紹的相同。
發送一個請求用于根據指定的參數執行 prepared 語句并等待執行結果。
PGresult *PQexecPrepared(PGconn *conn, const char *stmtName, int nParams, const char * const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat);
該函數和 PQexecParams 類似,不過要執行的命令通過指定之前定義的 prepared 語句指定,而不是一個 query 字符串。
</ul>關于其它執行命令的介紹可以查看 官方文檔 。
關于獲取查詢結果的函數介紹,可以查看 官方文檔。
一個完整事例程序
#include <libpq-fe.h>include <stdint.h>
include <arpa/inet.h>
include <iostream>
int main() { const char conninfo[] = "postgresql://postgres@localhost:5432/dbtest"; // const char conninfo[] = "postgresql://postgres@localhost?port=5432&dbname=dbtest"; PGconn conn = PQconnectdb(conninfo); / Check to see that the backend connection was successfully made / if (PQstatus(conn) != CONNECTION_OK) { std::cout << "Connection to database failed: " << PQerrorMessage(conn) << std::endl; } PGresult res = PQexec(conn, "create table tb0927 (id integer, name char(20), age int);"); if(PQresultStatus(res) != PGRES_COMMAND_OK) { std::cout << "Create table failed: " << PQresultErrorMessage(res) << std::endl; return 1; } PQclear(res); res = PQexec(conn, "insert into tb0927 values(1, 'helloworld', 23);"); if(PQresultStatus(res) != PGRES_COMMAND_OK) { std::cout << "Insert into table failed: " << PQresultErrorMessage(res) << std::endl; return 1; } PQclear(res); const char command[] = "insert into tb0927 values($1, $2, $3);"; int id = htobe32(2); char name[20] = "helloworld2"; int age= htobe32(24); int nParams = 3; const char const paramValues[] = { (char)&id, name, (char)&age }; const int paramLengths[] = { sizeof(id), sizeof(name), sizeof(age) }; const int paramFormats[] = { 1 ,0 ,1 }; int resultFormat = 0; res = PQexecParams(conn, command, nParams, NULL, paramValues, paramLengths, paramFormats, resultFormat ); if(PQresultStatus(res) != PGRES_COMMAND_OK) { std::cout << "PQexecParams failed: " << PQresultErrorMessage(res) << std::endl; return 1; } PQclear(res); res = PQprepare(conn, "insertStmt", command, nParams, NULL ); if(PQresultStatus(res) != PGRES_COMMAND_OK) { std::cout << "PQprepare failed:" << PQresultErrorMessage(res) << std::endl; return 1; } PQclear(res); res = PQexecPrepared(conn, "insertStmt", nParams, paramValues, paramLengths, paramFormats, resultFormat ); if(PQresultStatus(res) != PGRES_COMMAND_OK) { std::cout << "PQexecPrepared failed: " << PQresultErrorMessage(res) << std::endl; return 1; } PQclear(res); res = PQexec(conn, "select from tb0927;"); if(PQresultStatus(res) != PGRES_TUPLES_OK) { std::cout << "Select failed: " << PQresultErrorMessage(res) << std::endl; return 1; } std::cout << "Get " << PQntuples(res) << "tuples, each tuple has " << PQnfields(res) << "fields" << std::endl; for(int i = 0; i < PQnfields(res); i++) { std::cout << PQfname(res, i) << " " ; } std::cout << std::endl; for(int i = 0; i < PQntuples(res); i++) { for(int j = 0; j < PQnfields(res); j++) { std::cout << PQgetvalue(res,i ,j ) << " "; } std::cout << std::endl; } PQclear(res); PQfinish(conn); return 0; }</pre>
編譯:g++ libpq.cc -o libpq -lpq -std=c++0x
運行:./libqp
運行結果截圖如下:
![]()
![]()
Reference:
PostgreSQL Documentation Libpq