暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL libpq 客户端接口(一)

晟数学院 2021-04-16
527

点击“蓝字”关注我们


前言


Libpq 是为 C 语言开发这提供的关于 PostgreSQL 的接口。Libpq 由相关库函数组成,可以允许客户端程序通过将查询传递给 PostgreSQL 后台服务器并接收这些查询返回的结果。同时,libpq 也是其它几个 PostgreSQL 应用程序接口的基础引擎,包括 C++,Perl,Python,Tcl和ECPGC编程的嵌入式 SQL。


连接字符串


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


函数介绍如下:

PQconnectdbParams 

该参数用来创建连接到数据库服务器的新的连接。如下:

    PGconn *PQconnectdbParams(const char * const *keywords,
    const char * const *values,
                              int expand_dbname);
    复制


    该函数使用传入的两个 NULL 终止的数组中打开一个新的连接,首先,keywords 用来定义一个字符串数组,每一个都是一个关键字。其次,values,为每个关键字给定一个值。当前可识别的关键字有 host、hostaddr、port、dbname、user、password、passfile、connect_timeout、client_encoding、options、application_name、fallback_application_name,keepalives 等信息。常用的通常有 host、hostaddr、port、dbname、user、password 这五个。


    当 expand_dbname 是非零时,该 dbname 关键字的值可以允许作为一个连接字符串。

    而关于 PGconn 的定义,PGconn 属于封装到后端的连接,应用程序不需要关心该结构的定义,此处给出该结构的定义:

      typedef struct pg_conn PGconn;
      复制


      可以看出 PGconn 的数据类型为 pg_conn,而在 pg_conn 中自定义的数据类型的结构为如下(此处只描述了常用的几个):

        struct pg_conn 
        {
        /* Saved values of connection options */
        char *pghost; /* 服务器运行的主机
        * 或者是一个UNIX套接字,或者是
        * 逗号分隔的主机列表,或者是路径
        * 如果为NULL,使用 DEFAULT_PGSOCKET_DIR定义的套接字目录
        */
        char *pghostaddr; /* 服务器运行主机的数值IP地址或者主机列表
        *优先于pghost
        */
        char *pgport; /*服务器通信端口 */


        char *connect_timeout; /* 指定连接超时 */
        char *pgtcp_user_timeout; /* tcp用户超时*/
        char *client_encoding_initial; /* 客户端使用的编码 */
        char *dbName; /* 数据库名称 */
        char *pguser; /* 用户名 */
        char *pgpass; /* 用户密码 */
        };
        复制


        • PQconnectdb

        该函数和 PQconnectdbParams 类似,只不过该函数使用的并非一个 key-value 的值,而是一个字符串数组常量。如下:

          PGconn * PQconnectdb(const char * conninfo);
          复制


          上述中,字符串数组常量为 conninfo,是一个指针常量。传入的字符串可以为空,为空时,使用默认 uninx 套接字进行连接,或者包含一个或者多个用空格分隔的参数设置。或者可以包含 URI。使用的 URI 格式如下:

            postgresql://
            postgresql://localhost
            postgresql://localhost:5433
            postgresql://localhost/mydb
            postgresql://user@localhost
            postgresql://user:secret@localhost
            postgresql://other@localhost/otherdb?connect_timeout=10&application_name=myapp
            postgresql://host1:123,host2:456/somedb?target_session_attrs=any&application_name=myapp
            复制


            • PQsetdbLogin

            该函数用来使用指定的数据库信息进行连接,其实 PQconnectdb 执行时省略了这一步而已。该函数与 PQconnectdb 具有相同的功能,都时用来创建一个新的服务器连接,只不过 PQsetdbLogin 指定了相关的数据库信息,而 PQconnectdb 使用 URI 来连接。如果该参数缺少参数,也将采用默认值,即 UNIX 套接字。

              PGconn *PQsetdbLogin(const char *pghost,
              const char *pgport,
              const char *pgoptions,
              const char *pgtty,
              const char *dbName,
              const char *login,
                                   const char *pwd);
              复制


              • PQsetdb

              该函数使用指定的数据库信息进行连接。主要用来和以前版本的服务器进行兼容,忽略。


              连接状态函数


              • PQstatus

                ConnStatusType PQstatus(const PGconn *conn);
                复制


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


                • PQerrorMessage

                该函数返回最近连接时出现的错误信息。

                  char *PQerrorMessage(const PGconn *conn);
                  复制


                  • PQconnectionNeedsPassword

                  该函数返回采用密码加密方式认证时需要请求的密码。如果需要密码但密码错误返回1,如果没有则返回 0。

                    int PQconnectionNeedsPassword(const PGconn *conn);
                    复制


                    • PQparameterStatus

                    返回当前已连接服务器的参数信息

                      const char *PQparameterStatus(const PGconn *conn, const char *paramName);
                      复制


                      该函数的状态可能是多个值中的一个值。但是,这些值中仅有两种状态在异步连接处理之外可见:CONNECTION_OK 和 CONNECTION_BAD。正常连接到数据库服务器的状态是 CONNECTION_OK。未连接到数据库服务器的状态为 CONNECTION_BAD。通常,服务器连接成功的状态会在 PQfinish 执行结束前一直保留,但服务器连接通讯失败可能会过早使状态变更为 CONNECTION_BAD。在这种情况下,应用程序可能会通过调用 PQreset 尝试恢复。


                      • PQtransactionStatus

                      返回当前处于事务当中服务器状态。

                        PGTransactionStatusType PQtransactionStatus(const PGconn *conn);
                        复制


                        这个状态可能是 PQTRANS_IDLE(当前空闲),PQTRANS_ACTIVE(事务中有正在执行的命令),PQTRANS_INTRANS(表示在一个有效的事务块中状态空闲),或者 PQTRANS_INERROR(表示在一个失败的事务块中空闲)。如果服务器连接失败,将会提示 PQTRANS_UNKNOWN 状态。只有当一个在事务中的查询被发送到服务器并且没有完成的时候,事务中的服务器状态为 PQTRANS_ACTIVE。


                        • PQerrorMessage

                        该函数返回在一个已连接到服务器上生成的最近操作错误的信息。

                          char *PQerrorMessage(const PGconn *conn);
                          复制


                          • PQbackendPID

                          该函数返回一个已连接到服务器的后台进程 ID。

                            int PQbackendPID(const PGconn *conn);
                            复制


                            通常,对于出于 debugging 目的和比较 NOTIFY 信息的连接来说,后台 PID 非常有用。


                            • PQconnectionNeedsPassword

                            如果连接认证方式请求一个密码,那么该函数返回 1,如果没有密码请求,则返回 0。

                              int PQconnectionNeedsPassword(const PGconn *conn);
                              复制


                              该函数被应用于在连接失败后尝试决定是否需要提示用户密码。


                              • PQconnectionUsedPassword

                              如果一个连接认证方式使用密码则返回 1,否则返回 0。

                                int PQconnectionUsedPassword(const PGconn *conn);
                                复制


                                示例

                                  #创建源码文件存放目录
                                  mkdir home/postgres/libpqtest
                                  #编写源码文件 test.c
                                  #include <stdio.h>
                                  #include <stdlib.h>
                                  #include "libpq-fe.h"


                                  int main(int argc,char **argv)
                                  {
                                  const char *conninfo; 定义传入连接参数常量
                                  PGconn *conn; 定义连接字符串
                                  if (argc > 1)
                                  {
                                  conninfo = argv[1];
                                  }else
                                  {
                                  conninfo = "dbname = postgres";
                                  }
                                  创建一个新的连接
                                  conn = PQconnectdb(conninfo);
                                  检查连接状态
                                  if (PQstatus(conn) != CONNECTION_OK)
                                  {
                                  打印连接字符串信息
                                  fprintf(stderr,"错误的连接字符串信息: %s",PQerrorMessage(conn));
                                  }else
                                  {
                                  打印连接的字符串信息
                                  printf("OK\n");
                                  }


                                  }


                                  #编写Makefile 文件
                                  [postgres@sungsasong libpqtest]$ cat Makefile
                                  #
                                  # Makefile for example programs
                                  #


                                  subdir = ~/libpqtest
                                  top_builddir = /home/postgres/pack/postgresql-12.3
                                  include $(top_builddir)/src/Makefile.global


                                  ifeq ($(PORTNAME), win32)
                                  LDFLAGS += -lws2_32
                                  endif


                                  override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
                                  LDFLAGS_INTERNAL += $(libpq_pgport)




                                  PROGS = test


                                  all: $(PROGS)


                                  clean distclean maintainer-clean:
                                  rm -f $(PROGS) *.o




                                  #执行 make 编译
                                  [postgres@sungsasong libpqtest]$ make
                                  make -C /home/postgres/pack/postgresql-12.3/src/backend generated-headers
                                  make[1]: Entering directory `/home/postgres/pack/postgresql-12.3/src/backend'
                                  make -C catalog distprep generated-header-symlinks
                                  make[2]: Entering directory `/home/postgres/pack/postgresql-12.3/src/backend/catalog'
                                  make[2]: Nothing to be done for `distprep'.
                                  make[2]: Nothing to be done for `generated-header-symlinks'.
                                  make[2]: Leaving directory `/home/postgres/pack/postgresql-12.3/src/backend/catalog'
                                  make -C utils distprep generated-header-symlinks
                                  make[2]: Entering directory `/home/postgres/pack/postgresql-12.3/src/backend/utils'
                                  make[2]: Nothing to be done for `distprep'.
                                  make[2]: Nothing to be done for `generated-header-symlinks'.
                                  make[2]: Leaving directory `/home/postgres/pack/postgresql-12.3/src/backend/utils'
                                  make[1]: Leaving directory `/home/postgres/pack/postgresql-12.3/src/backend'
                                  gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -I/home/postgres/pack/postgresql-12.3/src/interfaces/libpq -I/home/postgres/pack/postgresql-12.3/src/include -D_GNU_SOURCE -I/usr/include/libxml2 -c -o test.o test.c
                                  gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 test.o -L/home/postgres/pack/postgresql-12.3/src/port -L/home/postgres/pack/postgresql-12.3/src/common -L/home/postgres/pack/postgresql-12.3/src/common -lpgcommon -L/home/postgres/pack/postgresql-12.3/src/port -lpgport -L/home/postgres/pack/postgresql-12.3/src/interfaces/libpq -lpq -Wl,--as-needed -Wl,-rpath,'/data/pg12/lib',--enable-new-dtags -lpgcommon -lpgport -lpthread -lxslt -lxml2 -lpam -lssl -lcrypto -lz -lreadline -lrt -lcrypt -ldl -lm -o test




                                  #执行程序
                                  [postgres@sungsasong libpqtest]$ ./test
                                  OK
                                  [postgres@sungsasong libpqtest]$ ./test "postgresql://localhost"
                                  OK
                                  [postgres@sungsasong libpqtest]$ ./test "postgresql://10.10.20.50:5404"
                                  错误的连接字符串信息: could not connect to server: Connection refused
                                  Is the server running on host "10.10.20.50" and accepting
                                  TCP/IP connections on port 5404?
                                  [postgres@sungsasong libpqtest]$ vi $PGDATA/postgresql.conf
                                  [postgres@sungsasong libpqtest]$ vi $PGDATA/pg_hba.conf
                                  [postgres@sungsasong libpqtest]$ pg_ctl restart -D $PGDATA -l /tmp/logfile
                                  waiting for server to shut down.... done
                                  server stopped
                                  waiting for server to start.... done
                                  server started
                                  [postgres@sungsasong libpqtest]$ ./test "postgresql://10.10.20.50:5404"
                                  OK
                                  复制


                                  作者:宋少华


                                  PostgreSQL分会培训认证委员会委员、晟数科技首席技术专家、晟数学院金牌讲师、oracle 11g OCM、PostgreSQL首批PGCE。


                                  曾服务于国家电网冀北电力有限公司建设大数据平台,为人社局和北京市卫计委构建IT基础服务,为多家银行和证券公司构建web服务器,系统及数据库维护;具有对税务局、国家电网、银行等政府行业和民营企业的IT培训经验;为相关安全行业设计DW数据仓库模型,使用PostgreSQL,Greenplum,HUAWEIGaussDB,Vertica和Clickhouse做数据基础服务,开发TB级数据落地程序及百TB级别数据迁移程序。



                                  推荐阅读

                                  PostgreSQL JDBC客户端接口介绍

                                  2020-9-23

                                  PostgreSQL 中的 shared buffer

                                  2020-8-28



                                  点击“阅读原文”

                                  文章转载自晟数学院,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                  评论