上一期讲了一些如何通过jdbc连接postgresql数据库,这一期准备说一说如何通过libpq连接postgresql数据库。
上一期的jdbc是postgresql的java语言应用程序接口,这一期的libpq对应的是postgresql的C语言应用程序接口。

这里依旧分为三个模块来讲:
一.获取连接
二.执行select语句
三.执行insert,delete,update语句

第一部分:获取连接
要使用libpq连接postgresql数据库首先要引用libpq的头文件libpq-fe.h

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

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

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

在jdbc中,我们可以通过try catch的方式进行连接错误捕获,在libpq中也提供了判断连接是否成功建立的接口:

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

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

第二部分:执行select语句
在获取到PGconn实例后,我们就可利用PGconn实例进行对数据库的操作了,和jdbc不同,jdbc中查询语句和更新语句会分别调用executeQuery()和executeUpdate(),而libpq中使用的是同一个接口。

Lipq执行sql命令的核心函数为PQexec(PGconn *conn, const char *command);其中第一个参数为连接。第二个为执行的命令,其中command字符串可以包含多条执行命令,需要注意的是如果不加入begin或者commit的关键字,command字符串中的所有命令将在一个事务中执行,并且只要其中一条失败,就会导致整个command执行失败。

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);

第三部分:执行insert,delete,update语句
对于select语句,我们在解析PGresult时需要的是结果集,所以在上面调用了以上几个函数,但是修改语句我们更关心的受影响的行数,所以对于修改语句可以通过PQntuples(const PGresult *res)获取受影响函数,其中对于PGresult而言它的成员中包含了所有执行的结果,不同的解析函数只是用来取得PGresult中相应的成员而已,有兴趣的同学可以去看一看PGresult结构体的实现,里面对于所有的成员都有比较清楚的描述。
下面贴一段执行插入语句的例子:

res = PQexec(conn, "delete from student where sid=4;");
    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