?
このドキュメントでは、 php中國(guó)語(yǔ)ネットマニュアル リリース
這些例子和其他的可以在字典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; /* * 如果用戶在命令行上提供了一個(gè)參數(shù),則拿它當(dāng)作 conninfo 字串使用; * 否則缺省為 dbname=postgres 并且使用環(huán)境變量或者所有其它連接參數(shù) * 都使用缺省值。 */ if (argc >1) conninfo = argv[1]; else conninfo = "dbname = postgres"; /*連接數(shù)據(jù)庫(kù)*/ conn = PQconnectdb(conninfo); /* 檢查后端連接成功建立*/ if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr,"Connection to database failed: %s", PQerrorMessage(conn)); exit_nicely(conn); } /* * 我們的測(cè)試實(shí)例涉及游標(biāo)的使用,這個(gè)時(shí)候我們必須使用事務(wù)塊 * 我們可以把全部事情放在一個(gè) "select * from pg_database" * PQexec() 里,不過(guò)那樣太簡(jiǎn)單了,不是個(gè)好例子。 */ /* 開(kāi)始一個(gè)事務(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é)果不需要的時(shí)候 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) ... 我們不用檢查錯(cuò)誤 ... */ res = PQexec(conn,"CLOSE myportal"); PQclear(res); /*結(jié)束事務(wù)*/ res = PQexec(conn,"END"); PQclear(res); /* 關(guān)閉數(shù)據(jù)庫(kù)連接并清理 */ PQfinish(conn); return 0; }
Example 31-2. libpq例子程序 2
/* * testlibpq2.c * * * * 測(cè)試異步通知接口 * * 運(yùn)行此程序,然后從另外一個(gè)窗口的 psql 里運(yùn)行 * NOTIFY TBL2; * 重復(fù)四次,直到程序退出 * * 或者,如果你想好玩一點(diǎn),用下面命令填充數(shù)據(jù)庫(kù)∶ * (在 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 * 并且對(duì)其它連接使用環(huán)境變量或者缺省值。 * */ if (argc >1) conninfo = argv[1]; else conninfo = "dbname = postgres"; /* 和數(shù)據(jù)庫(kù)建立鏈接 */ conn = PQconnectdb(conninfo); /* 檢查一下與服務(wù)器的連接是否成功建立*/ if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr,"Connection to database failed: %s", PQerrorMessage(conn)); exit_nicely(conn); } /* * 發(fā)出 LISTEN 命令打開(kāi)來(lái)自規(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 * 測(cè)試線外參數(shù)和二進(jìn)制I/O。 * * 在運(yùn)行這個(gè)例子之前,用下面的命令填充一個(gè)數(shù)據(jù)庫(kù) * (在 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); } /* * 這個(gè)函數(shù)打印查詢結(jié)果,這些結(jié)果是二進(jìn)制格式,從上面的 * 注釋里面創(chuàng)建的表中抓取出來(lái)的。我們把這個(gè)函數(shù)單獨(dú)拆出來(lái) * 是因?yàn)?main() 函數(shù)用了它兩次。 */ static void show_binary_results(PGresult *res) { int i, j; int i_fnum, t_fnum, b_fnum; /* 使用 PQfnumber 來(lái)避免對(duì)結(jié)果中的字段順序進(jìn)行假設(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; /* 獲取字段值(我們忽略了它們可能為空的這個(gè)可能?。?/ iptr = PQgetvalue(res,i,i_fnum); tptr = PQgetvalue(res,i,t_fnum); bptr = PQgetvalue(res,i,b_fnum); /* * INT4 的二進(jìn)制表現(xiàn)形式是網(wǎng)絡(luò)字節(jié)序, * 我們最好轉(zhuǎn)換成本地字節(jié)序。 */ ival = ntohl(*((uint32_t *) iptr)); /* * TEXT 的二進(jìn)制表現(xiàn)形式是,嗯,文本,因?yàn)?libpq 好的會(huì)給它附加一個(gè)字節(jié)零, * 因此把它看做 C 字串就挺好。 * * BYTEA 的二進(jìn)制表現(xiàn)形式是一堆字節(jié),里面可能包含嵌入的空值, * 因此我們必須注意字段長(zhǎng)度。 */ 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 * 并且對(duì)其它連接使用環(huán)境變量或者缺省值。 * */ if (argc >1) conninfo = argv[1]; else conninfo = "dbname = postgres"; /* 和數(shù)據(jù)庫(kù)建立鏈接 */ conn = PQconnectdb(conninfo); /* * 檢查一下與服務(wù)器的連接是否成功建立 */ if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr,"Connection to database failed: %s", PQerrorMessage(conn)); exit_nicely(conn); } /* * 這個(gè)程序是用來(lái)演示使用線外參數(shù)的 PQexecParams(), * 以及結(jié)果集的二進(jìn)制傳輸。第一個(gè)例子使用文本傳輸參數(shù), * 但是用二進(jìn)制格式檢索結(jié)果。通過(guò)使用線外參數(shù),我們可以避免大量 * 枯燥的字串的引起和逃逸。請(qǐng)注意我們這里不需要對(duì)參數(shù)值里的引號(hào) * 做任何特殊的處理 */ /* 這里是我們的線外數(shù)據(jù)*/ paramValues[0] = "joe's place"; res = PQexecParams(conn, "SELECT * FROM test1 WHERE t = $1", 1,/* 一個(gè)參數(shù)*/ NULL,/* 讓后端推出參數(shù)類型*/ paramValues, NULL,/* 因?yàn)槭俏谋?,所以必須要參?shù)長(zhǎng)度 */ NULL,/* 缺省是全部文本參數(shù) */ 1); /* 要求二進(jìn)制結(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); /* * 在這個(gè)第二個(gè)例子里,我們以二進(jìn)制格式傳輸一個(gè)整數(shù)參數(shù), * 然后還是以二進(jìn)制格式檢索結(jié)果。 * * 盡管我們告訴 PQexecParams,我們讓后端推導(dǎo)參數(shù)類型, * 實(shí)際上我們通過(guò)在查詢字串里轉(zhuǎn)換參數(shù)符號(hào)的方法強(qiáng)制了決定的做出。 * 在發(fā)送二進(jìn)制參數(shù)的時(shí)候,這是一個(gè)很好的安全檢查。 */ /* 把整數(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; /*二進(jìn)制 */ res = PQexecParams(conn, "SELECT * FROM test1 WHERE i = $1::int4", 1,/*一個(gè)參數(shù)*/ NULL,/* 讓后端推導(dǎo)參數(shù)類型*/ paramValues, paramLengths, paramFormats, 1); /* 要求二進(jìn)制結(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ù)庫(kù)的連接并清理 */ PQfinish(conn); return 0; }