更新时间:2024-11-12 GMT+08:00
绑定参数并返回二进制结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
/* * testlibpq3.c * 测试PQexecParams * PQexecParams: 执行一个绑定参数的命令,并以二进制格式请求查询结果。 * 在运行这个例子之前,用下面的命令填充一个数据库 * * * CREATE TABLE test1 (i int4, t text); * * INSERT INTO test1 values (2, 'ho there'); * * 期望的输出如下 * * * tuple 0: got * i = (4 bytes) 2 * t = (8 bytes) 'ho there' * */ #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); } /* * 这个函数打印查询结果,这些结果是二进制格式,从上面的 * 注释里面创建的表中抓取出来的 */ static void show_binary_results(PGresult *res) { int i; int i_fnum, t_fnum; /* 使用 PQfnumber 来避免对结果中的字段顺序进行假设 */ i_fnum = PQfnumber(res, "i"); t_fnum = PQfnumber(res, "t"); for (i = 0; i < PQntuples(res); i++) { char *iptr; char *tptr; int ival; /* 获取字段值(忽略可能为空的可能) */ iptr = PQgetvalue(res, i, i_fnum); tptr = PQgetvalue(res, i, t_fnum); /* * INT4 的二进制表现形式是网络字节序 * 建议转换成本地字节序 */ ival = ntohl(*((uint32_t *) iptr)); /* * TEXT 的二进制表现形式是文本,因此libpq能够给它附加一个字节零 * 把它看做 C 字符串 * */ 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("\n\n"); } } int main(int argc, char **argv) { /* 此处user、passwd等变量应从环境变量或配置文件读取,环境变量需用户自己按需配置;非环境变量情况下可直接赋值字符串 */ const char conninfo[1024]; PGconn *conn; PGresult *res; const char *paramValues[1]; int paramLengths[1]; int paramFormats[1]; uint32_t binaryIntVal; char *passwd = getenv("EXAMPLE_PASSWD_ENV"); char *port = getenv("EXAMPLE_PORT_ENV"); char *hostaddr = getenv("EXAMPLE_HOST_ENV"); char *username = getenv("EXAMPLE_USERNAME_ENV"); char *dbname = getenv("EXAMPLE_DBNAME_ENV"); /* * 如果用户在命令行上提供了参数, * 那么使用该值为conninfo 字符串;否则 * 使用环境变量或者缺省值。 */ if (argc > 1) strcpy(conninfo, argv[1]); else sprintf(conninfo, "dbname=%s port=%s host=%s application_name=test connect_timeout=5 sslmode=allow user=%s password=%s", dbname, port, hostaddr, username, passwd); /* 和数据库建立连接 */ conn = PQconnectdb(conninfo); /* 检查与服务器的连接是否成功建立 */ if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn)); exit_nicely(conn); } res = PQexec(conn, "drop table if exists test1;CREATE TABLE test1 (i int4, t text);"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "command failed: %s", PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } PQclear(res); res = PQexec(conn, "INSERT INTO test1 values (2, 'ho there');"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "command failed: %s", PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } PQclear(res); /* 把整数值 "2" 转换成网络字节序 */ binaryIntVal = htonl((uint32_t) 2); /* 为 PQexecParams 设置参数数组 */ paramValues[0] = (char *) &binaryIntVal; paramLengths[0] = sizeof(binaryIntVal); paramFormats[0] = 1; /* 二进制 */ /* PQexecParams执行一个绑定参数的命令 */ res = PQexecParams(conn, "SELECT * FROM test1 WHERE i = $1::int4", 1, /* 一个参数 */ NULL, /* 让后端推导参数类型 */ paramValues, paramLengths, paramFormats, 1); /* 要求二进制结果 */ if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn)); PQclear(res); exit_nicely(conn); } /* 显示二进制结果 */ show_binary_results(res); PQclear(res); /* 关闭与数据库的连接并清理 */ PQfinish(conn); return 0; } |
示例运行结果如下:
tuple 0: got i = (4 bytes) 2 t = (8 bytes) 'ho there'
父主题: 典型应用开发示例