1. 簡介
習慣了c++來開發的人,可能更傾向於使用c++庫來訪問PG。libpqxx很早以前就推出了。目前已經到了4.0版。本文就簡單的介紹如何使用它,linux平台編譯相對簡單,這裡就介紹一下windows平台下的使用。
libpqxx的:直接上這裡http://pqxx.org/development/libpqxx/wiki/DownloadPage
由於libpqxx對libpq的C-API進行了很好的封裝,從而可以節省大量的編碼時間。
有關協助文檔,可以直接參考: libpqxx的手冊http://pqxx.org/devprojects/libpqxx/doc/4.0/html/Tutorial
libpqxx的類庫協助:http://pqxx.org/devprojects/libpqxx/doc/4.0/html/Reference/
2. 編譯過程
將libpqxx解壓到一固定目錄。你需要提前編譯好或安裝好的用戶端庫,通常為了方便,這裡假定你已經有一個PG的安裝版或者解壓縮版,在c:\pgsql裡頭。以PG9.x為例。
1. 進入libpqxx源碼目錄,備份並修改win32\common檔案,將PGSQLSRC的值指向正確的地方:
這裡是PGSQLSRC="c:\pgsql"
後邊還有很多目錄位置需要調整,針對我們這種情況,通常都是保留安裝版本的設定,如:LIBPQINC=$(PGSQLSRC)\include, 而注釋掉#LIBPQINC=$(PGSQLSRC)\interfaces\libpq, 其它幾個值都如此類推。
2. 拷貝一些編譯相關的標頭檔
針對具體版本,9.0的,將config\sample-headers\libpq\9.0\pqxx複製到include下邊
針對VS2008的,將config\sample-headers\compiler\VisualStudio2008\pqxx複製到include目錄下邊, 如果是VS2005,以此類推。
3. 編譯
program files->VS2008-->Visual studio tools->Visual Studio 2008 Command Prompt, 進入命令列, 在此進入libpqxx的原始碼根目錄,執行:
nmake /f win32\vc-libpqxx.mak ALL,
得到如下中間過程:
link.exe kernel32.lib ws2_32.lib advapi32.lib /nologo /dll /machine:I386 shell32.lib secur32.lib wldap32.lib /libpath:"C:\hisql-x86-2.0.1"\lib libpq.lib "ObjDllRelease\binarystring.obj" "ObjDllRelease\connection.obj" "ObjDllRelease\connection_base.obj" "ObjDllRelease\cursor.obj" "ObjDllRelease\dbtransaction.obj" "ObjDllRelease\errorhandler.obj" "ObjDllRelease\except.obj" "ObjDllRelease\field.obj" "ObjDllRelease\largeobject.obj" "ObjDllRelease\nontransaction.obj" "ObjDllRelease\notification.obj" "ObjDllRelease\notify-listen.obj" "ObjDllRelease\pipeline.obj" "ObjDllRelease\prepared_statement.obj" "ObjDllRelease\result.obj" "ObjDllRelease\robusttransaction.obj" "ObjDllRelease\statement_parameters.obj" "ObjDllRelease\strconv.obj" "ObjDllRelease\subtransaction.obj" "ObjDllRelease\tablereader.obj" "ObjDllRelease\tablestream.obj" "ObjDllRelease\tablewriter.obj" "ObjDllRelease\transaction.obj" "ObjDllRelease\transaction_base.obj" "ObjDllRelease\tuple.obj" "ObjDllRelease\util.obj" "ObjDllRelease\libpqxx.obj" /out:"lib\libpqxx.dll" /implib:"lib\libpqxx.lib" Creating library lib\libpqxx.lib and object lib\libpqxx.exp
最終會在lib目錄下產生:
D:\Projects\hisql.svn\trunk\learning\libpqxx-4.0>dir/b/s libD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpq.dllD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpq.libD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpqxx.dllD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpqxx.dll.manifestD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpqxx.expD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpqxx.libD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpqxxD.dllD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpqxxD.dll.manifestD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpqxxD.expD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpqxxD.ilkD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpqxxD.libD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpqxxD.pdbD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpqxx_static.libD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\libpqxx_staticD.libD:\Projects\hisql.svn\trunk\learning\libpqxx-4.0\lib\msdia80.dll
3. 簡單樣本
下邊來看看最簡單的樣本, 我們先建立樣本使用者foo, 密碼為foo1, 並建立一個簡單的表t (id, col), 插入一條包含中文的記錄,編碼,可以看出,用戶端為gbk。
iihero=# create user foo password 'foo1';
CREATE ROLE
iihero=> create table t(id int primary key, col2 varchar(32));注意: CREATE TABLE / PRIMARY KEY 將要為表 "t" 建立隱含索引 "t_pkey"CREATE TABLEiihero=> \encodingGBKiihero=> insert into t values(1 ,'不同類型的列表');INSERT 0 1iihero=> select * from t; id | col2----+---------------- 1 | 不同類型的列表(1 行記錄)
將編譯出來後的include, lib目錄提取到固定的目錄,與你原來的postgresql的include和lib目錄,可以合到一起。給開發使用。
下邊是一個最簡單的範例程式碼,只為體會一下串連及取一行最簡單的結果(1):
#include <iostream>#include <pqxx/pqxx>int main(){pqxx::connection conn("dbname=iihero hostaddr=127.0.0.1 user=foo password=foo1" );if(conn.is_open()){std::cout << "Connection succesful!" << std::endl;std::cout << conn.options()<<std::endl;}else{std::cout << "Something went wrong... oops" << std::endl;}pqxx::work w(conn); pqxx::result res = w.exec("SELECT 1"); w.commit();std::cout << res[0][0].as<int>() << std::endl;}
需要注意的是,要將libpq.lib, libpqxx.lib, 以及標頭檔都設定上。如果動態庫連結方式出現問題,可以嘗試使用libpqxx的靜態庫。
上邊的pqxx::connection對象, 要傳入一個字串作為串連串,這個串連串要求以空格將關鍵字串隔開,這與libpq的串連串是一致的。
dbname=<database> hostaddr=<IP地址或主機名稱> user=<usrename> password=<password>
關鍵字不能弄錯。否則會報異常。當然,上邊的代碼寫的非常不規範,只是作為示範。正常情況下,需要加入異常處理。
好,下邊我們將代碼稍改進一下。
4. 改進的代碼#include <iostream>#include <pqxx/pqxx>int main(){try {pqxx::connection conn("dbname=iihero hostaddr=127.0.0.1 user=foo password=foo1" );if(conn.is_open()){std::cout << "Connection succesful!" << std::endl;std::cout << conn.options()<<std::endl;}else{std::cout << "Something went wrong... oops" << std::endl;}pqxx::work w(conn);pqxx::result res = w.exec("SELECT 1");// w.commit();std::cout << res[0][0].as<int>() << std::endl;// 接著樣本 訪問表t中的資料, 先設定client端的字元集編碼, 否則會出現亂碼conn.set_client_encoding("GBK");pqxx::result r = w.exec("SELECT * FROM t");for (pqxx::result::const_iterator row = r.begin(); row != r.end(); ++row){ for (pqxx::tuple::const_iterator field = row->begin();field != row->end();++field)std::cout << field->c_str() << '\t';std::cout << std::endl;}}catch (std::exception& e) {std::cerr << e.what() << std::endl;return 1;}return 0;}
上邊,我們看到,需要設定用戶端的編碼。通過一個迭代器來訪問一個查詢中的資料。
需要說明的是,libpqxx的線上文檔寫的非常的爛,範例程式碼居然是錯誤的。裡邊,
pqxx::result::tuple::const_iterator
壓根就不能編譯。應該是pqxx::tuple.