?
This document uses PHP Chinese website manual Release
這些例子和其他的可以在字典src/test/examples的源代碼分布中。
Example 31-1. libpq例子程序 1
/* * testlibpq.c * * Test the C version of libpq,the PostgreSQL frontend library. */ #include<stdio.h> #include<stdlib.h> #include<libpq-fe.h> static void exit_nicely(PGconn *conn) { PQfinish(conn); exit(1); } int main(int argc,char **argv) { const char *conninfo; PGconn *conn; PGresult *res; int nFields; int i, j; /* * 如果用戶在命令行上提供了一個參數(shù),則拿它當(dāng)作 conninfo 字串使用; * 否則缺省為 dbname=postgres 并且使用環(huán)境變量或者所有其它連接參數(shù) * 都使用缺省值。 */ if (argc >1) conninfo = argv[1]; else conninfo = "dbname = postgres"; /*連接數(shù)據(jù)庫*/ conn = PQconnectdb(conninfo); /* 檢查后端連接成功建立*/ if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr,"Connection to database failed: %s", PQerrorMessage(conn)); exit_nicely(conn); } /* * 我們的測試實例涉及游標(biāo)的使用,這個時候我們必須使用事務(wù)塊 * 我們可以把全部事情放在一個 "select * from pg_database" * PQexec() 里,不過那樣太簡單了,不是個好例子。 */ /* 開始一個事務(wù)塊*/ res = PQexec(conn,"BEGIN"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr,"BEGIN command failed: %s",PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } /* * leaks 應(yīng)該在結(jié)果不需要的時候 PQclear PGresult,以避免內(nèi)存泄漏 */ PQclear(res); /* * 從系統(tǒng)表 pg_database 里抓取數(shù)據(jù) */ res = PQexec(conn,"DECLARE myportal CURSOR FOR select * from pg_database"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr,"DECLARE CURSOR failed: %s",PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } PQclear(res); res = PQexec(conn,"FETCH ALL in myportal"); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr,"FETCH ALL failed: %s",PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } /* 首先,打印屬性名稱*/ nFields = PQnfields(res); for (i = 0; i< nFields; i++) printf("%-15s",PQfname(res,i)); printf("\n\n"); /* 然后打印行*/ for (i = 0; i< PQntuples(res); i++) { for (j = 0; j< nFields; j++) printf("%-15s",PQgetvalue(res,i,j)); printf("\n"); } PQclear(res); /* 關(guān)閉游標(biāo) ... 我們不用檢查錯誤 ... */ res = PQexec(conn,"CLOSE myportal"); PQclear(res); /*結(jié)束事務(wù)*/ res = PQexec(conn,"END"); PQclear(res); /* 關(guān)閉數(shù)據(jù)庫連接并清理 */ PQfinish(conn); return 0; }
Example 31-2. libpq例子程序 2
/* * testlibpq2.c * * * * 測試異步通知接口 * * 運行此程序,然后從另外一個窗口的 psql 里運行 * NOTIFY TBL2; * 重復(fù)四次,直到程序退出 * * 或者,如果你想好玩一點,用下面命令填充數(shù)據(jù)庫∶ * (在 src/test/examples/testlibpq2.sql 里提供) * * 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); * * 然后做四次∶ * * INSERT INTO TBL1 values (10); */ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/time.h> #include<libpq-fe.h> static void exit_nicely(PGconn *conn) { PQfinish(conn); exit(1); } int main(int argc,char **argv) { const char *conninfo; PGconn *conn; PGresult *res; PGnotify *notify; int nnotifies; /* * 如果用戶在命令行上提供了參數(shù), * 那么拿它當(dāng)作 conninfo 字串;否則缺省設(shè)置是 dbname=postgres * 并且對其它連接使用環(huán)境變量或者缺省值。 * */ if (argc >1) conninfo = argv[1]; else conninfo = "dbname = postgres"; /* 和數(shù)據(jù)庫建立鏈接 */ conn = PQconnectdb(conninfo); /* 檢查一下與服務(wù)器的連接是否成功建立*/ if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr,"Connection to database failed: %s", PQerrorMessage(conn)); exit_nicely(conn); } /* * 發(fā)出 LISTEN 命令打開來自規(guī)則 NOTIFY 的通知 */ res = PQexec(conn,"LISTEN TBL2"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr,"LISTEN command failed: %s",PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } /* * 如果不再需要 PGresult 了,我們應(yīng)該 PQclear,以避免內(nèi)存泄漏 */ PQclear(res); /* 收到四次通知之后退出。*/ nnotifies = 0; while (nnotifies< 4) { /* * 睡眠,直到某些事件發(fā)生。我們使用 select(2) 等待輸入, * 但是也可以用 poll() 或者類似的設(shè)施 */ int sock; fd_set input_mask; sock = PQsocket(conn); if (sock< 0) break; /* 不應(yīng)該發(fā)生*/ FD_ZERO(&input_mask); FD_SET(sock,&input_mask); if (select(sock + 1,&input_mask,NULL,NULL,NULL)< 0) { fprintf(stderr,"select() failed: %s\n",strerror(errno)); exit_nicely(conn); } /* 現(xiàn)在檢查輸入 */ PQconsumeInput(conn); while ((notify = PQnotifies(conn)) != NULL) { fprintf(stderr, "ASYNC NOTIFY of '%s' received from backend pid %d\n", notify->relname,notify->be_pid); PQfreemem(notify); nnotifies++; } } fprintf(stderr,"Done.\n"); /* 關(guān)閉數(shù)據(jù)連接并清理*/ PQfinish(conn); return 0; }
Example 31-3. libpq例子程序3
/* * testlibpq3.c * Test out-of-line parameters and binary I/O. * * Before running this,populate a database with the following commands * (provided in src/test/examples/testlibpq3.sql): * * CREATE TABLE test1 (i int4,t text,b bytea); * * INSERT INTO test1 values (1,'joe''s place','\\000\\001\\002\\003\\004'); * INSERT INTO test1 values (2,'ho there','\\004\\003\\002\\001\\000'); * * The expected output is: * * tuple 0: got * i = (4 bytes) 1 * t = (11 bytes) 'joe's place' * b = (5 bytes) \000\001\002\003\004 * * tuple 0: got * i = (4 bytes) 2 * t = (8 bytes) 'ho there' * b = (5 bytes) \004\003\002\001\000 */ /* * testlibpq3.c * 測試線外參數(shù)和二進制I/O。 * * 在運行這個例子之前,用下面的命令填充一個數(shù)據(jù)庫 * (在 src/test/examples/testlibpq3.sql 里提供): * * CREATE TABLE test1 (i int4,t text,b bytea); * * INSERT INTO test1 values (1,'joe''s place','\\000\\001\\002\\003\\004'); * INSERT INTO test1 values (2,'ho there','\\004\\003\\002\\001\\000'); * * 期望的輸出是: * * tuple 0: got * i = (4 bytes) 1 * t = (11 bytes) 'joe's place' * b = (5 bytes) \000\001\002\003\004 * * tuple 0: got * i = (4 bytes) 2 * t = (8 bytes) 'ho there' * b = (5 bytes) \004\003\002\001\000 */ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<libpq-fe.h> /* for ntohl/htonl */ #include<netinet/in.h> #include<arpa/inet.h> static void exit_nicely(PGconn *conn) { PQfinish(conn); exit(1); } /* * 這個函數(shù)打印查詢結(jié)果,這些結(jié)果是二進制格式,從上面的 * 注釋里面創(chuàng)建的表中抓取出來的。我們把這個函數(shù)單獨拆出來 * 是因為 main() 函數(shù)用了它兩次。 */ static void show_binary_results(PGresult *res) { int i, j; int i_fnum, t_fnum, b_fnum; /* 使用 PQfnumber 來避免對結(jié)果中的字段順序進行假設(shè) */ i_fnum = PQfnumber(res,"i"); t_fnum = PQfnumber(res,"t"); b_fnum = PQfnumber(res,"b"); for (i = 0; i< PQntuples(res); i++) { char *iptr; char *tptr; char *bptr; int blen; int ival; /* 獲取字段值(我們忽略了它們可能為空的這個可能?。?/ iptr = PQgetvalue(res,i,i_fnum); tptr = PQgetvalue(res,i,t_fnum); bptr = PQgetvalue(res,i,b_fnum); /* * INT4 的二進制表現(xiàn)形式是網(wǎng)絡(luò)字節(jié)序, * 我們最好轉(zhuǎn)換成本地字節(jié)序。 */ ival = ntohl(*((uint32_t *) iptr)); /* * TEXT 的二進制表現(xiàn)形式是,嗯,文本,因為 libpq 好的會給它附加一個字節(jié)零, * 因此把它看做 C 字串就挺好。 * * BYTEA 的二進制表現(xiàn)形式是一堆字節(jié),里面可能包含嵌入的空值, * 因此我們必須注意字段長度。 */ blen = PQgetlength(res,i,b_fnum); printf("tuple %d: got\n",i); printf(" i = (%d bytes) %d\n", PQgetlength(res,i,i_fnum),ival); printf(" t = (%d bytes) '%s'\n", PQgetlength(res,i,t_fnum),tptr); printf(" b = (%d bytes) ",blen); for (j = 0; j< blen; j++) printf("\\%03o",bptr[j]); printf("\n\n"); } } int main(int argc,char **argv) { const char *conninfo; PGconn *conn; PGresult *res; const char *paramValues[1]; int paramLengths[1]; int paramFormats[1]; uint32_t binaryIntVal; /* * 如果用戶在命令行上提供了參數(shù), * 那么拿它當(dāng)作 conninfo 字串;否則缺省設(shè)置是 dbname=postgres * 并且對其它連接使用環(huán)境變量或者缺省值。 * */ if (argc >1) conninfo = argv[1]; else conninfo = "dbname = postgres"; /* 和數(shù)據(jù)庫建立鏈接 */ conn = PQconnectdb(conninfo); /* * 檢查一下與服務(wù)器的連接是否成功建立 */ if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr,"Connection to database failed: %s", PQerrorMessage(conn)); exit_nicely(conn); } /* * 這個程序是用來演示使用線外參數(shù)的 PQexecParams(), * 以及結(jié)果集的二進制傳輸。第一個例子使用文本傳輸參數(shù), * 但是用二進制格式檢索結(jié)果。通過使用線外參數(shù),我們可以避免大量 * 枯燥的字串的引起和逃逸。請注意我們這里不需要對參數(shù)值里的引號 * 做任何特殊的處理 */ /* 這里是我們的線外數(shù)據(jù)*/ paramValues[0] = "joe's place"; res = PQexecParams(conn, "SELECT * FROM test1 WHERE t = $1", 1,/* 一個參數(shù)*/ NULL,/* 讓后端推出參數(shù)類型*/ paramValues, NULL,/* 因為是文本,所以必須要參數(shù)長度 */ NULL,/* 缺省是全部文本參數(shù) */ 1); /* 要求二進制結(jié)果*/ if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr,"SELECT failed: %s",PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } show_binary_results(res); PQclear(res); /* * 在這個第二個例子里,我們以二進制格式傳輸一個整數(shù)參數(shù), * 然后還是以二進制格式檢索結(jié)果。 * * 盡管我們告訴 PQexecParams,我們讓后端推導(dǎo)參數(shù)類型, * 實際上我們通過在查詢字串里轉(zhuǎn)換參數(shù)符號的方法強制了決定的做出。 * 在發(fā)送二進制參數(shù)的時候,這是一個很好的安全檢查。 */ /* 把整數(shù)值 "2" 轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序 */ binaryIntVal = htonl((uint32_t) 2); /* 為 PQexecParams 設(shè)置參數(shù)數(shù)組 */ paramValues[0] = (char *) &binaryIntVal; paramLengths[0] = sizeof(binaryIntVal); paramFormats[0] = 1; /*二進制 */ res = PQexecParams(conn, "SELECT * FROM test1 WHERE i = $1::int4", 1,/*一個參數(shù)*/ NULL,/* 讓后端推導(dǎo)參數(shù)類型*/ paramValues, paramLengths, paramFormats, 1); /* 要求二進制結(jié)果 */ if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr,"SELECT failed: %s",PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } show_binary_results(res); PQclear(res); /* 關(guān)閉與數(shù)據(jù)庫的連接并清理 */ PQfinish(conn); return 0; }