同步命令处理
数据库服务器的连接被成功建立后,这里描述的函数可以被用来执行SQL查询和命令。这里的函数均为同步函数,在返回结果之前会阻塞。
执行查询
使用PQnfields、PQfname等函数,程序将一次性获取查询的所有结果。开发者可以通过使用游标,配合fetch命令逐条数据取出结果。也可通过libpq提供的接口来逐行获取数据。本例中采用pqexec的方式简单的使用游标,并采用Fetch all命令一次性获取所有的结果。并调用PQfname函数获取所有字段的名称,调用PQntuples函数获取元组的数量,并最终循环调用PQgetvalue函数得到每个元组的数据。
#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;
/*
* 如果用户在命令行上提供了一个参数,将它用作连接信息串。
* 否则默认用设置 dbname=vastbase并且为所有其他链接参数使用环境变量或默认值。
*/
if (argc > 1)
conninfo = argv[1];
else
conninfo = "dbname = vastbase";
/* 建立到数据库的一个连接 */
conn = PQconnectdb(conninfo);
/* 检查看后端连接是否成功建立 */
if (PQstatus(conn) != CONNECTION_OK)
{
fprintf(stderr, "Connection to database failed: %s",
PQerrorMessage(conn));
exit_nicely(conn);
}
/*
* 我们的测试案例这里涉及使用一个游标,对它我们必须用在一个事务块内。
* 我们可以在一个单一的 "select * from pg_database" 的 PQexec() 中做整个事情,
*/
/* 开始一个事务块 */
res = PQexec(conn, "BEGIN");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "BEGIN command failed: %s", PQerrorMessage(conn));
PQclear(res);
exit_nicely(conn);
}
PQclear(res);
/*
* 从 pg_database 取得行,它是数据库的系统目录
*/
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);
/* 关闭入口,我们不需要考虑检查错误 */
res = PQexec(conn, "CLOSE myportal");
PQclear(res);
/* 结束事务 */
res = PQexec(conn, "END");
PQclear(res);
/* 关闭到数据库的连接并且清理 */
PQfinish(conn);
return 0;
}
使用PQprepare接口
PQprepare创建一个后面会由PQexecPrepared执行的预备语句,这个特性允许命令被反复执行而无需每次都进行解析和规划,各函数的使用方式及必要的参数使用举例说明请参考代码注释。
#include <stdio.h>
#include <stdlib.h>
#include "libpq-fe.h"
static void
exit_nicely(PGconn *conn)
{
PQfinish(conn);
exit(EXIT_SUCCESS);
}
int
main(int argc, char **argv)
{
int nFields;
int i,j;
const char *conninfo;
PGconn *conn;
PGresult *res;
if (argc > 1)
conninfo = argv[1];
else
conninfo = "dbname = vastbase";
/* 建立到数据库的一个连接 */
conn = PQconnectdb(conninfo);
/* 查看连接是否成功 */
if (PQstatus(conn) == CONNECTION_BAD)
{
fprintf(stderr, "Connection to database failed.\n");
fprintf(stderr, "%s", PQerrorMessage(conn));
exit_nicely(conn);
}
/* 开启事务块 */
res = PQexec(conn, "BEGIN");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "BEGIN command failed\n");
PQclear(res);
exit_nicely(conn);
}
PQclear(res);
const char *stmt_name = "test_stmt";
/* 注意若存在参数,则以$1, $2来表示 */
const char *stmt = "select * from pg_class where relname=$1";
Oid param_types[1];
param_types[0] = 0; //自动推测参数类型
/* 提交一个请求创建一个预备语句并且等待完成,当前stmt语句只有1个参数。 */
res = PQprepare(conn, stmt_name, stmt, 1, param_types);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "PQprepare failed\n");
PQclear(res);
exit_nicely(conn);
}
PQclear(res);
const char* theRelname= "pg_type";
const char* param_values[1];
param_values[0] = theRelname;
int param_lengths[1];
param_lengths[0] = 1;
int param_formats[1];
param_formats[0] = 0;
/* 使用PQexecPrepared发送一个请求来用给定参数执行一个预备语句,并且等待结果。 */
res = PQexecPrepared(conn, stmt_name, 1, param_values, param_lengths,
param_formats, 0);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, "PQexecPrepared statement didn't return tuples properly\n");
PQclear(res);
exit_nicely(conn);
}
/* 这里依然采用PQnfields获取字段数,采用PQfname获取各字段名 */
nFields = PQnfields(res);
for (i = 0; i < nFields; i++)
printf("%-15s", PQfname(res, i));
printf("\n\n");
/* 采用PQntuples获取元组数量,采用PQgetvalue获取各行元组数据 */
for (i = 0; i < PQntuples(res); i++)
{
for (j = 0; j < nFields; j++)
printf("%-15s", PQgetvalue(res, i, j));
printf("\n");
}
PQclear(res);
/* 结束事务 */
res = PQexec(conn, "END");
PQclear(res);
/* 关闭连接,清理 */
PQfinish(conn);
return 0;
}