我还没想好
发布于

OushuDB编程接口 - libpq

编程接口 - libpq

libpq 是 PostgreSQL 的 C 应用程序接口。Libpq 由相关库函数组成,可以允许客户端程序通过将查询传递给 PostgreSQL 后台服务器并接收这些查询返回的结果。同时,libpq 也是其它几个 PostgreSQL 应用程序接口的基础引擎,包括 C++,Perl,Python,Tcl 和 ECPGC 编程的嵌入式 SQL。OushuDB 与 PostgreSQL 兼容,同样可以通过 libpq 来进行数据库连接和数据操纵。

获取连接

一个应用程序同时可以有多个打开的连接,这也是 PostgreSQL 服务器能够同时访问多个库的原因。每一个连接都通过 PGconn 对象表示,该对象可以从函数 PQconnectdb,PQconnectdbParams 中或者 PQsetdbLogin 获取信息。需要注意的是,这些对象通常返回一个非空的对象指针。除非由于内存太小导致无法分配 PGconn 对象。PQstatus 函数用来检查在执行查询前连接是否成功的状态。

在要使用 libpq 连接 OushuDB 数据库之前,首先要引用 libpq 的头文件 libpq-fe.h。

然后创建连接字符串和 PGconn 结构体,设定连接字符串后就可以通过连接字符串获取连接了,例如:

const char *conninfo;
PGconn     *conn;
conninfo = "host=127.0.0.1 port=5433 dbname=postgres user=oushu";
conn = PQconnectdb(conninfo);

这里使用了 PQconnectdb 函数来创建一个连接到数据库服务器的新连接

注意如果这里缺省连接关键字的话,libpq 将使用缺省关键字的默认值进行连接,连接关键字的默认值可以参考官方手册。

在连接过程中,在 libpq 中也提供了判断连接是否成功建立的接口:连接状态函数 PQstatus

ConnStatusType PQstatus(const PGconn *conn);

这个函数返回一个连接的状态,在异步连接过程之外可以返回两个状态:CONNECTION_OK 和 CONNECTION_BAD。若连接到数据库正常则返回 CONNECTION_OK,否则返回 CONNECTION_BAD。通常一个 OK 的状态将会持续到执行 PQfinish。

于是,我们可以通过下面的语句来进行连接状态的查询和处理,并通过 PQerrorMessage()函数来返回最近连接时出现的错误信息:

 if (PQstatus(conn) != CONNECTION_OK)
 {
        fprintf(stderr, "Connection to database failed: %s",
                PQerrorMessage(conn));
        exit_nicely(conn);//关闭连接并执行清理操作
 }

这里如果连接不成功的话会返回服务端返回的错误 message,如果成功的话后面就可以通过 conn 操作数据库了。

数据查询和数据操纵

在获取到 PGconn 实例后,我们就可利用 PGconn 实例进行对数据库的操作了,Libpq 执行 SQL 命令的核心函数为 PQexec(PGconn *conn, const char *command);其中第一个参数为连接。第二个为执行的命令,其中 command 字符串可以包含多条执行命令,如果不加入 begin 或者 commit 的关键字,command 字符串中的所有命令将在一个事务中执行,并且只要其中一条失败,就会导致整个 command 执行失败。

PGresult PQexec(PGconn *conn*, const** char *query);

PQexec 函数的返回类型为 PGresult,如果返回值为 null,说明执行失败,也可以通过 PQerrorMessage()方法查看错误消息。

在 libpg 中,查询语句和更新语句都是通过 PQexec 函数执行,但是很明显对于这两种语句我们需要的返回值肯定不同,所以在解析 PGresult 时,libpq 提供了不同的解析函数,这部分先说说解析查询结果用到的几个函数

  • PQnfields(PGresult *res):用于获取结果集中列的数目
  • PQfname(PGresult *res,int i):用于获取结果集中列的名称
  • PQntuples(PGresult *res):用于获取结果集中行的数目
  • PQgetvalue(PGresult *res,int i,int j):用于获取结果集中 i 行 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);
}
//这里需要注意不再使用的PGresult需要及时释放,否则可能会造成内存泄漏
PQclear(res);

res = PQexec(conn, "FETCH ALL in myportal");//FETCH ALL表示从结果中取回全部数据
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);

对于 select 语句,我们在解析 PGresult 时需要的是结果集,所以在上面调用了以上几个函数,但是在插入、删除和修改语句时我们更关心的受影响的行数,这时我们可以通过 PQntuples(const PGresult *res)来获取受影响函数,其中对于 PGresult 而言它的成员中包含了所有执行的结果,不同的解析函数只是用来取得 PGresult 中相应的成员而已,更多的关于 PGresult 的实现,大家可以参考官方文档。

res = PQexec(conn, "delete from department where d_id=101;");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
    fprintf(stderr, "delete failed: %s", PQerrorMessage(conn));
    PQclear(res);
    exit_nicely(conn);
}
printf("updatelin:%s",PQcmdTuples(res));//解析并打印受影响行数
PQclear(res);

执行 命令,可以完成 libpq 程序。c 文件的编译,生成可执行文件

gcc -L $libpath -I $includepath -lpq -o testlipq testlipq.c

终止连接

在我们完成操作后,可以选择通过 PQfinish()函数终止连接以释放资源:

void PQfinish(PGconn *conn);
评论
    test