VastbaseG100

基于openGauss内核开发的企业级关系型数据库。

Menu

同步命令处理

数据库服务器的连接被成功建立后,这里描述的函数可以被用来执行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;
}