接口篇 – C连接Greenplum

C语言是比较偏基础的语言,现在大多数开发人员可能不怎么会用C语言进行开发。但是在2020年1月份发布的2019年度编程语言中,C语言战胜众多对手,王者归来,足见C语言的地位。

也确实如上所说,C语言可能影响到软件开发的方方面面,但并不一定为你我所熟知。在PostgreSQL/Greenplum领域中,libpq是PostgreSQL/Greenplum的 C应用程序接口,这个C接口同时也是C++、Perl、Python、Tcl 和ECPG应用接口的驱动引擎。今天就来简单看看这个C接口是如何使用的。

示例

可以将如下代码编辑到gpadmin用户下的testlibpq.c文件中,下面会介绍简单的编译和使用

/*
 * src/test/examples/testlibpq.c
 * testlibpq.c
 *      注意:下面需要引入libpq-fe.h头文件
 */
#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;

    /* 
     * 如果用户在命令行定义了参数,那么这里解析为conninfo,作为连接参数;
     * 如果没有定义,则会选用环境变量定义的连接参数或采用默认值。
     */
    if (argc > 1)
        conninfo = argv[1];
    else
        conninfo = "dbname = postgres";

    /* 创建一个数据库连接 */
    conn = PQconnectdb(conninfo);

    /* 检查连接是否成功开启 */
    if (PQstatus(conn) != CONNECTION_OK)
    {
        fprintf(stderr, "Connection to database failed: %s",
                PQerrorMessage(conn));
        exit_nicely(conn);
    }

    /* Set always-secure search path, so malicious users can't take control. */
    res = PQexec(conn,
                 "SELECT pg_catalog.set_config('search_path', '', false)");
    if (PQresultStatus(res) != PGRES_TUPLES_OK)
    {
        fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
        PQclear(res);
        exit_nicely(conn);
    }

    /*
     * 当完成操作后,执行清理操作,避免内存泄漏。
     */
    PQclear(res);

    /*
     * Our test case here involves using a cursor, for which we must be inside
     * a transaction block.  We could do the whole thing with a single
     * PQexec() of "select * from pg_database", but that's too trivial to make
     * a good example.
     */

    /* 开始一个事务块 */
    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);

    /* 关闭上面定义的cursor */
    res = PQexec(conn, "CLOSE myportal");
    PQclear(res);

    /* end the transaction */
    res = PQexec(conn, "END");
    PQclear(res);

    /* 关闭数据库连接 */
    PQfinish(conn);

    return 0;
}

编译

[gpadmin@gp1 ~]$ gcc -I /usr/local/greenplum-db/include/ -L /usr/local/greenplum-db/lib -lpq testlibpq.c -o testlibpq

这里采用gcc编译器,指定头文件(-I)和库文件(-L),编译完成后,会生成二进制可执行文件testlibpq。

运行

此时可以执行该文件,查看是否能正常访问数据库。

[gpadmin@gp1 ~]$ ./testlibpq
datname        datdba         encoding       datcollate     datctype       datistemplate  datallowconn   datconnlimit   datlastsysoid  datfrozenxid   datminmxid     dattablespace  datacl

template1      10             6              en_US.utf8     en_US.utf8     t              t              -1             12813          725            1              1663           {=c/gpadmin,gpadmin=CTc/gpadmin}
template0      10             6              en_US.utf8     en_US.utf8     t              f              -1             12813          725            1              1663           {=c/gpadmin,gpadmin=CTc/gpadmin}
postgres       10             6              en_US.utf8     en_US.utf8     t              t              -1             12813          725            1              1663

上面代码采用默认的连接信息,如果要特别指定,可以通过定义如下字符串信息来访问数据库。

[gpadmin@gp1 ~]$ ./testlibpq "host=172.16.142.191 port=5432 user=gpadmin dbname=postgres"
datname        datdba         encoding       datcollate     datctype       datistemplate  datallowconn   datconnlimit   datlastsysoid  datfrozenxid   datminmxid     dattablespace  datacl

template1      10             6              en_US.utf8     en_US.utf8     t              t              -1             12813          725            1              1663           {=c/gpadmin,gpadmin=CTc/gpadmin}
template0      10             6              en_US.utf8     en_US.utf8     t              f              -1             12813          725            1              1663           {=c/gpadmin,gpadmin=CTc/gpadmin}
postgres       10             6              en_US.utf8     en_US.utf8     t              t              -1             12813          725            1              1663

在尝试连接过程中,可能会报如下错误,此时需要修改pg_hba.conf文件并gpstop -u生效即可。

[gpadmin@gp1 ~]$ ./testlibpq
Connection to database failed: FATAL:  no pg_hba.conf entry for host "[local]", user "gpadmin", database "postgres", SSL off

参考文章

https://www.postgresql.org/docs/current/libpq-example.html

End~

发表评论

电子邮件地址不会被公开。 必填项已用*标注