首页 > 数据库 > PostgreSQL > 正文

PostgreSQL7.0手册-接口-53. libpq - C 库

2019-09-08 23:34:13
字体:
来源:转载
供稿:网友
第五十三章. libpq - C 库
内容 
数据库联接函数 
查询执行函数 
异步查询处理 
捷径 
异步通知 
与 COPY 命令相关的函数 
libpq 跟踪函数 
libpq 控制函数 
环境变量 
线程特性 
例子程序 
libpq 是 Postgres 的 C 应用程序员的接口.libpq 是一套允许客户程序向 Postgres 后端服务进程发送查询并且获得查询返回的库过程.libpq 同时也是其他几个 Postgres 应用接口下面的引擎,包括 libpq++ (C++),libpgtcl (Tcl), perl5,和 ecpg.所以如果你使用这些软件包,libpq 某些方面的特性会对你非常重要. 
本节末尾有三个小程序显示如何利用 libpq 书写程序.在下面目录里面有几个完整的 libpq 应用的例子: 
  

../src/test/regress
../src/test/examples
../src/bin/psql
使用 libpq 的前端程序必须包括头文件 libpq-fe.h 并且必须与 libpq 库链接. 
  
数据库联接函数
下面的过程处理与 Postgres 后端服务器联接的事情.一个应用程序一次可以与多个后端建立联接.(这么做的原因之一是访问多于一个数据库.)每个连接都是用一个从 PQconnectdb() 或 PQsetdbLogin()获得的 PGconn 对象表示.注意,这些函数总是返回一个非空的对象指针,除非存储器少得连个 PGconn 对象都分配不出来.在把查询发送给联接对象之前,可以调用 PQstatus 函数来检查一下联接是否成功. 
PQconnectdb 与后端数据库服务器建立一个新的联接. 
PGconn *PQconnectdb(const char *conninfo)
这个过程用从一个字符串 conninfo 来的参数与数据库打开一个新的联接.与下面的 PQsetdbLogin() 不同的是,我们可以不必更换函数签名(名字)就可以扩展参数集,所以我们建议应用程序中使用这个函数或者是它的非阻塞的相似函数 PQconnectStart / PQconnectPoll.传入的参数可以为空,表明使用所有缺省的参数,或者可以包含一个或更多个用空白间隔的参数设置. 
每个参数设置以 关键字=数值 keyword = value 的形式设置.(要写一个空值或者一个包含空白的值,你可以用一对单引号包围它们,例如,keyword = 'a value' .数值内部的单引号必须书写为 /'.等号周围的空白是可选的.)目前可识别的参数值是: 

host 
要联接的主机(host ).如果声明了一个非零长字符串,就将使用 TCP/IP 通讯.使用这个参数导致一个主机名的查找。参阅 hostaddr。 
hostaddr 
与之联接的主机的 IP 地址。这个可以是标准的数字-点的形式,象在 BSD 函数 inet_aton 等里面用的那样。如果声明了一个非零长的字符串,那么使用 TCP/IP 通讯机制。 
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

使用 hostaddr 取代 host 允许应用避免一次主机名查找,这一点对于那些有时间约束的应用来说可能是非常重要的。不过,Kerberos 认证系统要求主机(host)名。因此,应用下面的规则。如果声明了不带 hostaddr 的 host 那么就强制进行主机名查找。如果声明中没有 host,hostaddr 的值给出远端的地址;如果使用了 Kerberos,将导致一次反向名字查询。如果同时声明了 host 和 hostaddr,除非使用了 Kerberos,否则将使用 hostaddr 的值作为远端地址;host 的值将被忽略,如果使用了 Kerberos,host 的值用于 Kerberos 认证。要注意如果传递给 libpq 的主机名(host)不是地址 hostaddr 处的机器名,那么认证很有可能失败。 

如果主机名(host)和主机地址都没有,那么 libpq 将使用一个本地的 Unix 域套接字进行通讯。 

port 
主机服务器的端口号,或者在 Unix 主控套接字联接时的套接字扩展文件名. 
dbname 
数据库名. 
user 
要联接的用户名。 
password 
如果后端要求口令认证,所用的口令. 
options 
发给后端的跟踪/调试选项. 
tty 
文件或控制台,用于从后端的可选调试输出. 
如果有任何没有声明的参数,那么将检查对应的环境变量(参阅"环境变量"章)。如果环境变量也没有设置,那么使用编译时的硬代码。返回的值是一个指向代表与后端联接的抽象结构的指针。 
PQsetdbLogin 与后端数据库服务器建立一个新的联接. 

PGconn *PQsetdbLogin(const char *pghost,
                     const char *pgport,
                     const char *pgoptions,
                     const char *pgtty,
                     const char *dbName,
                     const char *login,
                     const char *pwd)
这个函数是 PQconnectdb 前身,它有固定个数的参数,但是有相同的功能。 
PQsetdb 与后端数据库服务器建立一个新的联接. 

PGconn *PQsetdb(char *pghost,
                char *pgport,
                char *pgoptions,
                char *pgtty,
                char *dbName)
这是一个调用 PQsetdbLogin() 的宏,只是 login 和 pwd 参数用空(null )代替.提供这个函数主要是为了与老版本的程序兼容. 
PQconnectStart PQconnectPoll 与数据库服务器建立一次非阻塞的联接。 

PGconn *PQconnectStart(const char *conninfo)
PostgresPollingStatusType *PQconnectPoll(PQconn *conn)
着两个过程用于打开一个与数据库服务器之间的非阻塞的联接:你的应用的执行线索在运行的时候不会阻塞远端的 I/O。 
数据库联接是用从 conninfo 字符串里取得的参数传递给 PQconnectStart 进行的。这个字符串的格式与上面 PQconnectdb 里描述的一样。 

PQconnectStart 和 PQconnectPoll 都不会阻塞(进程),不过有一些限制: 
  

必须正确提供 hostaddr 和 host 参数以确保不会发生正向或者反向的名字查找。参阅上面 PQconnectdb 里的这些参数的文档获取细节。 
如果你调用了 PQtrace,确保你跟踪进入的流对象不会阻塞。 

你必须在调用 PQconnectPoll 之前确保 socket 处于正确的状态,象下面描述的那样。

要开始(联接),调用 conn=PQconnectStart("")。如果 conn 是 NULL,表明 libpq 无法分配一个新的 PGconn 结构。否则,返回一个有效的 PGconn 指针(尽管还不一定代表一个与数据库有效联接)。PQconnectStart 一返回,调用 status=PQstatus(conn)。如果 status 等于 CONNECTION_BAD,PQconnectStart 失败。 
如果 PQconnectStart 成功了,下一个阶段是轮询 libpq,这样它就可以继续进行后继的联接动作。象这样循环:认为一个联接缺省时是'不活跃'的。如果 PQconnectPoll 的最后一个返回是PGRES_POLLING_ACTIVE,则认为它是'活跃的'。如果 PQconnectPoll(conn) 的最后一个返回是PGRES_POLLING_READING,执行一个对 PQsocket(conn) 的读 select。如果最后一个返回是PGRES_POLLING_WRITING,执行一个对 PQsocket(conn) 的写 select。如果还没(?)调用 PQconnectPoll,例如象在调用完 PQconnectStart 后那样,把它当作最后返回PGRES_POLLING_WRITING 那样对待。如果 select 显示 socket 已经准备好,那么认为它是'活跃的'。如果认为一个联接是'活跃的',再次调用 PQconnectPoll(conn)。如果这次调用返回 PGRES_POLLING_FAILED,联接过程失败,如果这次调用返回 PGRES_POLLING_OK,联接成功。 

要注意上面用 select() 来确保一个 socket 准备好只是一个(近似)的例子;还可以用其他方法,比如一个 poll() 调用,来代替 select。 

在联接的任何时候,我们都可以通过调用 PQstatus 来检查联接的状态。如果这是 CONNECTION_BAD,那么联接过程失败;如果是 CONNECTION_OK,那么联接已经做好。着两种状态同样也可以从上面的 PQconnectPoll 的返回值里检测到。其他状态可能(也只能)在一次异步联接过程中看到。这些标识联接过程的当前状态,因而可能对给用户提供反馈有帮助。这些状态可能包括: 

CONNECTION_STARTED:等待进行联接。
CONNECTION_MADE:联接成功;等待发送。 
CONNECTION_AWAITING_RESPONSE:等待来自 postmaster 的响应。 

CONNECTION_AUTH_OK:已收到认证;等待后端启动。 

CONNECTION_SETENV:协商环境。

注意,尽管这些常量将保持下去(为了维持兼容性),应用决不应该依赖于这些常量的某种特定顺序,或者是根本不应依赖于这些常量,或者是不应该依赖于这些状态总是某个文档声明的值。一个应用可能象象下面这样: 
    switch(PQstatus(conn))
    {
        case CONNECTION_STARTED:
            feedback = "Connecting...";
            break;

        case CONNECTION_MADE:
            feedback = "Connected to server...";
            break;
.
.
.
        default:
            feedback = "Connecting...";
    }
要注意如果 PQconnectStart 返回一个非空的指针,你必须在使用完它(指针)之后调用 PQfinish,以处理那些结构和所有相关的存储块。甚至调用 PQconnectStart 或者 PQconnectPoll 失败时也要这样处理。 
如果编译 libpq 时定义了 USE_SSL 那么目前的 PQconnectPoll 将阻塞住。这个限制可能在将来的版本移除。 

除非编译 libpq 时定义了 WIN32_NON_BLOCKING_CONNECTIONS,否则目前的 PQconnectPoll 将在 Windows 里阻塞住。这些代码还没有在 Windows 里测试过,因此目前缺省时是不带这些代码的。着一点以后可能修改。 

这些函数把 socket 置于一个非阻塞的状态,就好象调用了 PQsetnonblocking 一样。 

PQconndefaults 返回缺省的联接选项。 

PQconninfoOption *PQconndefaults(void)

struct PQconninfoOption
{
    char   *keyword;   /* The keyword of the option */
    char   *envvar;    /* Fallback environment variable name */
    char   *compiled;  /* Fallback compiled in default value */
    char   *val;       /* Option's current value, or NULL */
    char   *label;     /* Label for field in connect dialog */
    char   *dispchar;  /* Character to display for this field
                          in a connect dialog. Values are:
                          ""        Display entered value as is
                          "*"       Password field - hide value
                          "D"       Debug option - don't show by default */
    int     dispsize;  /* Field size in characters for dialog */
}
返回联接选项结构的地址.可以用于获取所有可能的 PQconnectdb 选项和它们的当前缺省值.返回值指向一个 PQconninfoOption 结构数组,该数组以一个有 NULL 关键字指针的入口结束.注意缺省值("val" 域)将依赖于环境变量和其他上下文.调用者必须把联接选项当作只读对待. 
在处理完选项数组后,把数组交给 PQconninfoFree() 释放.如果没有这么做,每次调用 PQconndefaults() 都会有一小部分内存泄漏. 

在 Postgres 7.0 以前的版本,PQconndefaults() 返回一个指向静态数组的指针,而不是一个动态分配的数组.这样做是线程不安全的,因此这个特点被修改了. 

PQfinish 关闭与后端的联接.同时释放被 PGconn 对象使用的存储器. 

void PQfinish(PGconn *conn)
注意,即使与后端的联接尝试失败(可由 PQstatus 判断),应用也要调用 PQfinish 释放被 PGconn 对象使用的存储器.PGconn 指针不应该在调用 PQfinish 后再使用. 
PQreset 重置与后端的通讯端口. 

void PQreset(PGconn *conn)
此函数将关闭与后端的联接并且试图与同一个 postmaster 重建新的联接,使用所有前面使用过的参数.这在失去工作联接后进行故障恢复时很有用. 
PQresetStart PQresetPoll 重置与后端的非阻塞模式的通讯端口。 

int PQresetStart(PGconn *conn);
PostgresPollingStatusType PQresetPoll(PGconn *conn);
此函数将关闭与后端的联接并且试图与同一个 postmaster 重建新的联接,使用所有前面使用过的参数.这在失去工作联接后进行故障恢复时很有用.它们和上面的 PQreset (above) 的区别是它们工作在非阻塞模式。这些函数的使用有与上面 PQconnectStart 和 PQconnectPoll 一样的限制。 
调用 PQresetStart。如果它返回 0,那么重置失败。如果返回 1,用与使用 PQconnectPoll 建立联接的同样的方法使用 PQresetPoll 重置联接。

libpq 应用程序员应该仔细维护 PGconn 结构.使用下面的访问函数来获取 PGconn 的内容.避免直接引用 PGconn 结构里的字段,因为这些字段在今后可能被改变.(从PostgreSQL 版本 6.4 开始, 结构 PGconn 的定义甚至没有放在 libpq-fe.h 里.如果你有一些直接访问 PGconn 数据域的旧代码,你可以通过包含 libpq-int.h 来访问它们,但我们鼓励你赶快修改那些代码.) 
PQdb 返回联接的数据库名. 
char *PQdb(const PGconn *conn)
PQdb 和下面几个函数返回联接后建立起来的几个值.这些值在 PGconn 对象的生存期内是固定的. 
PQuser 返回联接的用户名. 

char *PQuser(const PGconn *conn)
PQpass 返回联接的口令. 
char *PQpass(const PGconn *conn)
PQhost 返回联接的服务器主机名. 
char *PQhost(const PGconn *conn)
PQport 返回联接的端口号. 
char *PQport(const PGconn *conn)
PQtty 返回联接的调试控制台( tty ). 
char *PQtty(const PGconn *conn)
PQoptions 返回联接中使用的后端选项. 
char *PQoptions(const PGconn *conn)
PQstatus 返回联接的状态. 
ConnStatusType PQstatus(const PGconn *conn)
这个状态可以是一些值之一。不过,在一次异步联接过程以外的范围里只能看到其中的两个 - CONNECTION_OK 或者 CONNECTION_BAD。一个与数据库的成功的联接返回状态 CONNECTION_OK。一次失败的企图用状态 CONNECTION_BAD 标识。通常,一个 OK 状态保持到 PQfinish,但是一个通讯失败可能会导致状态永久的改变为 CONNECTION_BAD。这时应用可以试着调用 PQreset 来恢复. 
参阅 PQconnectStart 和 PQconnectPoll 条目看看可能出现的其他的状态码。 

PQerrorMessage 返回联接中操作产生的最近的错误信息. 

char *PQerrorMessage(const PGconn* conn);
几乎所有 libpq 函数在失败时都会设置 PQerrorMessage .注意 libpq 的传统是,一个非空的 PQerrorMessage 将在结尾包含一个新行. 
PQbackendPID 返回控制此联接的后端服务器的进程号(ID)。 

int PQbackendPID(const PGconn *conn);
这个后端 PID 在调试和对比 NOTIFY 信息(包含发出通知的后端的 PID )时很有用.注意该 PID 属于运行数据库服务器的主机的进程,而不是本地主机!

--------------------------------------------------------------------------------  --------------------------------------------------------------------------------

异步查询处理
PQexec 函数对简单的同步应用里提交查询已经是足够用的了.但是它却有几个主要的缺陷: 
  
PQexec 等待查询结束.应用可能有其他工作要做(例如维护用户界面),这时它可不希望阻塞在这里等待返回. 
因为控制是藏在 PQexec 内部,前端很难取消掉正进行着的查询.(可以通过信号控制器进行,但没有别的方法.) 

PQexec 只能返回一个 PGresult 结构.如果提交的查询字符串包含多个 SQL 命令,除了最后一个 PGresult 以外都会被 PQexec 丢弃。

不想受到这些限制的应用可以改用下面的函数,这些函数也是构造 PQexec 的函数:PQsendQuery 和PQgetResult。 
使用这些(异步)功能以及 PQputline 和 PQputnbytes 的老一些的程序可能在等待数据发送给后端时阻塞住,要改变这样的方式,增加了函数 PQsetnonblocking。 

旧应用可以忽略 PQsetnonblocking 的使用,维持原有的阻塞特征。新的程序可以利用 PQsetnonblocking 获得与后端完全非阻塞的联接。 

PQsetnonblocking 把该联接的状态设置为非阻塞。 
int PQsetnonblocking(PGconn *conn)
此函数将确保对 PQputline,PQputnbytes,PQsendQuery 和 PQendcopy 的调用不被阻塞,如果对它们的调用需要再次执行将是返回一个错误(而不是阻塞)。 
当把一个数据库的联接设置为非阻塞的模式并且调用了 PQexec,它将暂时把联接状态设置为阻塞模式直到 PQexec 完成。 

在不久的将来将有更多的 libpq 会设计成在 PQsetnonblocking 方式下是安全的。 

PQisnonblocking 返回数据库联接的阻塞状态。 

int PQisnonblocking(const PGconn *conn)
如果联接设置为非阻塞状态,返回 TRUE,如果是阻塞状态返回 FALSE。 
PQsendQuery 向 Postgres 提交一个查询而不等待结果.如果查询成功发送则返回真(TRUE ),否则返回假(FALSE)(此时,可以用 PQerrorMessage 获取关于失败的信息). 

int PQsendQuery(PGconn *conn,
                const char *query);
在成功调用 PQsendQuery 后,调用 PQgetResult 一次或者多次获取查询结果.PQsendQuery 可以不再调用(在同一次联接里)直到 PQgetResult 返回 NULL,表明查询完成. 
PQgetResult 等待从前面 PQsendQuery 调用返回的下一个结果,然后返回之.当查询结束并且没有更多结果后返回 NULL. 

PGresult *PQgetResult(PGconn *conn);
PQgetResult 必须重复的调用,直到它返回 NULL,表明该查询结束.(如果在没有激活查询时调用, PQgetResult 将只是立即返回 NULL.)每个 PQgetResult返回的非空结果都应该用前面描述的 PGresult 访问函数进行分析.不要忘了在结束分析后用 PQclear 释放每个结果对象.注意,PQgetResult 只是在有查询激活而且必须的返回数据还没有被 PQconsumeInput 读取时阻塞.
使用 PQsendQuery 和 PQgetResult 解决了 PQexec 的一个问题:如果一个查询字符串包含多个 SQL 命令,这些命令的结果可以独立的获得.(顺便说一句:这样就允许一种简单的重叠处理模式,前端可以处理一个查询的结果而后端可以仍然在处理同一查询字符串的后面的查询.)但是,调用 PQgetResult 将仍然导致前端被阻塞住直到后端完成下一个SQL 命令.这一点可以通过合理的使用下面三个函数来避免: 
PQconsumeInput 如果存在后端来的输入可用,则使用之. 
int PQconsumeInput(PGconn *conn);
PQconsumeInput 通常返回 1 表明"没有错误",而返回 0 表明有某种错误发生(同时设置 PQerrorMessage ).注意这个结果并不表明实际上是否收集了数据.在调用 PQconsumeInput 之后,应用可以检查 PQisBusy 和/或 PQnotifies 看一眼它们的状态是否改变. 
PQconsumeInput 可以在应用还没有做好处理结果或通知的情况下被调用.这个过程将读取可用的数据并且在一个缓冲区里保存它,这样导致一个 select(2) 读准备好标识的生成.这样应用就可以使用PQconsumeInput 立即清掉 select 条件,然后在空闲的时候检查结果. 

PQisBusy 在查询忙的时候返回 1 ,也就是说,PQgetResult 将阻塞住等待输入.一个 0 的返回表明这时调用 PQgetResult 可以确保不阻塞. 

int PQisBusy(PGconn *conn);
PQisBusy 本身将不会试图从后端读取数据;所以必须先调用 PQconsumeInput ,否则忙状态将永远不会消除. 
PQflush 试图把任何正在排队的数据冲刷到后端,如果成功(或者发送队列为空)返回 0,如果因某种原因失败返回 EOF。 

int PQflush(PGconn *conn);
在一个非阻塞的联接调用 select 判断是否有响应到达之前需要调用一个 PQflush。如果返回 0 则保证了与后端的发送队列里面没有待发送的数据。只有使用了 PQsetnonblocking 的应用需要这个。 
PQsocket 获取用于后端联接套接字的文件描述符号.一个有效的描述符应该是 >= 0;一个 -1 表明当前没有打开与后端的联接. 

int PQsocket(const PGconn *conn);
PQsocket 应该用于获取准备调用 select(2) 的后端套接字描述符.这就允许一个应用使用阻塞的联接等待后端的响应或者其他条件.如果 select(2) 的结果表明可以从后端套接字读取数据,那么应该调用PQconsumeInput 读取数据;之后,PQisBusy,PQgetResult,和/或 PQnotifies 可用于处理返回信息. 
非阻塞的联接(那些使用了 PQsetnonblocking 的联接)在 PQflush 返回 0 之前,这表明没有数据缓冲着等待发送给后端,不应该使用 select。

一个使用这些函数的典型的前端将有一个主循环使用 select(2) 等待所有它必须处理的条件.其中一个条件将会是后端来的数据已准备好,从 select 的角度来看就是 PQsocket 标识的文件描述符上已经有可读取的数据.当主循环侦测到输入准备好,它将调用 PQconsumeInput 读取输入.然后可以调用 PQisBusy,如果 PQisBusy 返回 false(0)后面可以跟着 PQgetResult。同样它(用户应用)可以调用 PQnotifies 测 NOTIFY 信息(参阅下面的 "异步通知").例子程序节里面给出了一个例子程序. 
一个使用 PQsendQuery/PQgetResult 的前端同样也可以试图取消一个正在被后端处理的查询. 
  

PQrequestCancel 要求 Postgres 放弃处理当前查询. 
int PQrequestCancel(PGconn *conn);
如果取消的请求成功发送,返回值是 1,否则是 0.(如果为假,PQerrorMessage 会告之为什么.)不过,取消请求的成功发送将不保证请求将产生作用.不管 PQrequestCancel 的返回值是什么,应用都必须继续使用 PQgetResult进行通常的后续的结果读取工作.如果取消动作生效,当前的查询将提前退出并返回一个错误结果.如果取消动作失败(也就是后端已经处理完查询了),那么将没有可见的结果.
注意:如果当前的查询是事务的一部分,取消动作将退出整个事务. 
PQrequestCancel 可以很好地从一个信号句柄里调用.所以,如果取消动作可以从信号句柄里发出的话,它也可以与简单的 PQexec 一起使用.例如,psql 从一个 SIGINT 信号句柄里调用 PQrequestCancel,因此允许交互地取消通过 PQexec 运行的查询.注意,如果没有与后端建立联接或者后端当前没有处理查询, PQrequestCancel将不发生做用.


--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

查询执行函数
一旦与数据库服务器的联接成功建立,便可用这里描述的函数执行 SQL 查询和命令。 
PQexec 提交一个查询给 Postgres 并且等待结果. 
PGresult *PQexec(PGconn *conn,
                 const char *query);
返回一个 PGresult 指针或者也可能是一个 NULL 指针.通常返回一个非空(non-NULL)的指针,除非没有内存或发生了象不能把查询发送到后端这样的严重错误.如果返回的是 NULL,它应该被当作 PGRES_FATAL_ERROR 结果处理.用 PQerrorMessage 获取有关错误的更多信息.
PGresult 结构封装了后端返回的查询结果.libpq 应用程序员应该仔细维护 PGresult.用下面的访问函数来获取 PGresult 的内容.避免直接引用 PGresult 结构的数据域,因为这个结构可能会在未来被改变.(从 Postgres 版本 6.4 开始,结构 PGresult 的定义甚至都没有放在 libpq-fe.h 里.如果你有一些直接访问 PGresult 数据域的老代码,你可以通过包含 libpq-int.h 继续使用它们,但是我们鼓励你立刻修改代码.) 
PQresultStatus 返回查询的结果状态. 
ExecStatusType PQresultStatus(const PGresult *res)
PQresultStatus 可以返回下面数值之一: 
PGRES_EMPTY_QUERY -- 发送给后端的字串是空的 
PGRES_COMMAND_OK -- 成功完成一个没有返回数据的命令 

PGRES_TUPLES_OK -- 成功执行查询 
 

PGRES_COPY_OUT -- (从服务器)Copy Out (拷贝出)数据传输开始 
PGRES_COPY_IN -- Copy In (拷贝入)(到服务器)数据传输开始 

PGRES_BAD_RESPONSE -- 服务器的响应无法理解 

PGRES_NONFATAL_ERROR 

PGRES_FATAL_ERROR

如果结果状态是 PGRES_TUPLES_OK,那么下面的过程可以用于从查询的返回中抽取记录信息.注意一个碰巧检索了零条记录的 SELECT 仍然显示 PGRES_TUPLES_OK。PGRES_COMMAND_OK 用于不返回记录的命令(INSERT,UPDATE,等)。返回 PGRES_EMPTY_QUERY 的响应通常意味着客户端软件里面的臭虫。 
PQresStatus 把 PQresultStatus 返回的枚举类型转换成一个描述状态码的字符串常量。 

char *PQresStatus(ExecStatusType status);
PQresultErrorMessage 返回与查询关联的错误信息,或在没有错误时返回一个空字符串. 
char *PQresultErrorMessage(const PGresult *res);
紧跟在一个 PQexec 或 PQgetResult 调用后面,PQerrorMessage (对联接)将返回与 PQresultErrorMessage (对结果)一样的字符串.不过,一个 PGresult 将保有其错误信息直到被删除,而连结的错误信息将在后续的操作完成时被改变.当你想知道与某个 PGresult 相关联的状态时用 PQresultErrorMessage;当你想知道与联接的最近一个操作相关联的状态时用 PQerrorMessage; 
PQntuples 返回查询结果里的记录(实例)个数. 

int PQntuples(const PGresult *res);
PQnfields 返回查询结果里每个记录的数据域(字段)的个数. 
int PQnfields(const PGresult *res);
PQbinaryTuples 如果 PGresult 包含二进制记录数据时返回 1,如果包含 ASCII 数据返回 0. 
int PQbinaryTuples(const PGresult *res);
目前,二进制记录数据只能从一个从 BINARY 游标里抽取数据的查询返回. 
PQfname 返回与给出的数据域索引相关联的数据域(字段)的名称.数据域索引从 0 开始 

char *PQfname(const PGresult *res,
                    int field_index);
PQfnumber Returns the field (attribute) index associated with the given field name. 
int PQfnumber(const PGresult *res,
              const char *field_name);
-1 is returned if the given name does not match any field. 
PQftype 返回与给定数据域索引关联的数据域类型.整数返回值是一个该类型的内部编码.数据域索引从 0 开始. 

Oid PQftype(const PGresult *res,
            int field_num);
你可以查询系统表 pg_type 以获取各种数据类型的名称和属性。内建的数据类型的OID 在源码树的 src/include/catalog/pg_type.h 文件里定义。 
PQfsize 返回与给定数据域索引关联的数据域的大小.数据域索引从 0 开始. 

int PQfsize(const PGresult *res,
            int field_index);
PQfsize 返回在数据库记录里面给该数据域分配的空间,换句话说就是该数据类型在服务器里的二进制形式的大小(尺寸).如果该数据域是可变尺寸,返回 -1. 
PQfmod 返回与给定数据域索引相关联的类型相关的修正数据(??).数据域索引从 0 开始. 

int PQfmod(const PGresult *res,
           int field_index);
PQgetvalue 返回一个 PGresult 里面的一条记录的单独的一个数据域(字段)的值.记录和数据域索引从 0 开始. 
char* PQgetvalue(const PGresult *res,
                 int tup_num,
                 int field_num);
对大多数查询而言,PQgetvalue 返回的值是一个表示字段值的空(NULL)结尾的ASCII 字符串.但是如果 PQbinaryTuples() 为 1,PQgetvalue 返回的值就是该类型在后端服务器内部的二进制表现形式(但是不包括尺寸字--如果数据域是变长的).这样,把数据转换成对应的 C 类型就是程序员的责任了.PQgetvalue 返回的指针指向一个本身是 PGresult 结构的一部分的存储区域.我们不能更改它,并且如果我们要在 PGresult 结构的生存期后还要使用它的话,我们必须显式的把该数值拷贝到其他存储器中. 
PQgetlength 返回以字节计的数据域(字段)的长度.记录和数据域索引从 0 开始. 

int PQgetlength(const PGresult *res,
                int tup_num,
                int field_num);
这是某一特定数据值的实际数据长度,也就是由 PQgetvalue 指向的对象的尺寸.注意,对于 ASCII 代表的数值,这个尺寸与 PQfsize 报告的二进制尺寸无关. 
PQgetisnull 测试一个数据域是否为空(NULL).记录和数据域索引从 0 开始. 

int PQgetisnull(const PGresult *res,
                int tup_num,
                int field_num);
如果该域包含 NULL,函数返回 1,如果包含非空(non-null )值,返回 0.(注意,对一个 NULL 数据域,PQgetvalue 将返回一个空字符串,不是一个空指针.) 
PQcmdStatus 返回产生 PGresult 的 SQL 命令的命令状态字符串. 

char * PQcmdStatus(const PGresult *res);
PQcmdTuples 返回被 SQL 命令影响的行的数量. 
char * PQcmdTuples(const PGresult *res);
如果产生 PGresult 的 SQL 命令是 INSERT,UPDATE 或 DELETE,这里返回涉及行的行数.如果是其他命令返回一个空字符串. 
PQoidValue 返回一个插入的记录的记录对象标识(OID)――如果SQL 命令是 INSERT.否则,返回 InvalidOid . 

Oid PQoidValue(const PGresult *res);
如果你包含了 libpq 头文件,那么 Oid 和常量 InvalidOid 的类型将被定义。他们都是某种整型类型。 
PQoidStatus 返回一个被插入的记录的对象标识的字串,如果SQL 命令是 INSERT。否则. 返回一个空字串。 

char * PQoidStatus(const PGresult *res);
因为有了 PQoidValue,我们不建议使用这个函数,而且它在线程里使用也是不安全的。
    PQprint 向指定的输出流打印所有的记录和(可选的)字段名称. 
void PQprint(FILE* fout,      /* output stream */
             const PGresult *res,
             const PQprintOpt *po);

struct {
    pqbool  header;      /* print output field headings and row count */
    pqbool  align;       /* fill align the fields */
    pqbool  standard;    /* old brain dead format */
    pqbool  html3;       /* output html tables */
    pqbool  expanded;    /* expand tables */
    pqbool  pager;       /* use pager for output if needed */
    char    *fieldSep;   /* field separator */
    char    *tableOpt;   /* insert to HTML table ... */
    char    *caption;    /* HTML caption */
    char    **fieldName; /* null terminated array of replacement field names */
} PQprintOpt;
这个函数以前被 psql 用于打印查询结果,但是现在已经不用这个函数了,并且此函数不再有活跃的支持。 
PQclear 释放与 PGresult 关联的存储器.当不再需要时,每个查询结果都应该通过 PQclear 释放. 

void PQclear(PQresult *res);
你可以保留 PGresult 对象任意长的时间;当你提交新的查询时它并不消失,甚至你断开联接后也是这样.要删除它,你必须调用 PQclear.不这么做将导致前端的存储器泄漏. 
PQmakeEmptyPGresult 构建一个给出状态的空的 PGresult 对象. 

PGresult* PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
这是 libpq 的内部过程,用于分配和初始化一个空 PGresult 对象.它被输出是因为一些应用需要自行生成结果对象(尤其是特定的带有错误状态的对象).如果 conn 非空(NULL)并且状态指示一个错误,联接当前的 errorMessage 被拷贝到 PGresult.注意最终对该对象要调用 PQclear,正如 libpq 本身返回的 PGresult 一样.

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

捷径
PostgreSQL 提供一个发往后端的函数调用的捷径接口.这是一个通向系统内部的后门,因而可能存在安全漏洞.大多数用户应该不需要这个特性. 
PQfn 通过捷径接口执行请求的后端函数. 
PGresult* PQfn(PGconn* conn,
               int fnid,
               int *result_buf,
               int *result_len,
               int result_is_int,
               const PQArgBlock *args,
               int nargs);
fnid 参数是待执行的函数的对象标识(OID).result_buf 是放置返回值的缓冲区.调用者必须为返回值分配足够的空间(这里没有检查!).实际的返回值长度将被放在 result_len 指向的整数里返回.如果预期返回值是 4-字节整数,把 result_is_int 设为 1;否则设为 0.(把 result_is_int 设为 1 告诉 libpq 必要时交换数值的字节序,这样就可以正确地传输成客户机上的整数值.当result_is_int 是 0 时,后端发送回来的字节串不做修改.)args 和 nargs 声明要传入函数的参数. 
typedef struct {
    int len;
    int isint;
    union {
        int *ptr;
        int integer;
    } u;
} PQArgBlock;
PQfn 总是返回一个有效的 PGresult*.在使用结果之前应该检查 resultStatus.当结果不再使用后,调用者有责任使用 PQclear 释放 PGresult.

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

异步通知
PostgreSQL 支持通过 LISTEN 和 NOTIFY 命令产生的异步通知.一个后端用 LISTEN 命令注册一个它感兴趣的通知条件(也可以用 UNLISTEN 去掉这个注册).所有正在监听某一通知条件的后端在该条件名的 NOTIFY (通知)被任何后端执行后都将被异步地通知.通知发出者不会传递附加的信息从到通知接收者.因此,很典型地是,任何实际的需要被传递的数据都是通过一个数据库关系传递的.通常,条件名与相关联的关系同名,但是并不是一定要与某个关系相关才行. 
libpq 应用把 LISTEN 和 UNLISTEN 命令作为通常的 SQL 查询提交.因此,通过调用 PQnotifies() 可以侦测到 NOTIFY 消息的到达. 

PQnotifies 从一个来自后端的未处理的通知信息列表中返回下一条通知.如果没有未处理的信息则返回 NULL.一旦 PQnotifies 返回一条通知,该通知会被认为已处理并且将被从通知列表中删除. 
PGnotify* PQnotifies(PGconn *conn);

typedef struct pgNotify {
    char relname[NAMEDATALEN];       /* name of relation
                                      * containing data */
    int  be_pid;                     /* process id of backend */
} PGnotify;
在处理完 PQnotifies 返回的 PGnotify 对象后,别忘了用 free() 把它释放,以避免内存泄漏。 
注意:在 PostgreSQL 6.4 和更高的版本里,be_pid 是正在通知的后端的 PID,而在早些的版本里它总是你自己的后端的PID。
第二个样本程序给出一个使用异步通知的例子. 
PQnotifies() 实际上不读取后端数据;它只是返回被前面的另一个libpq 函数吸收的信息.在以前的 libpq 的版本里,周期性的收到通知(NOTIFY)信息的唯一方法是持续的提交查询,即使是空查询也可以,并且在每次 PQexec() 后检查 PQnotifies()。现在这个方法也能还工作,不过我们认为它太浪费处理器时间而废弃了它。 

在你没有可用的查询提交时检查 NOTIFY 消息的更好的方法是调用 PQconsumeInput(),然后检查 PQnotifies().你可以使用 select(2) 来等待后端数据的到达,这样在没有数据可处理时可以不浪费CPU 时间.注意这种方法不管你使用 PQsendQuery/ PQgetResult 还是简单的 PQexec 来执行查询都能工作.不过,你应该记住在每次 PQgetResult 或 PQexec 后检查 PQnotifies(),看看在处理查询的过程中是否有通知到达.


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

与 COPY 命令相关的函数
PostgreSQL 里的 COPY 命令里有用于 libpq 里从网络联接读出或者写入的选项.因此,这些函数有必要直接访问网络联接,以便应用可以充分利用这个功能. 
这些函数应该只在从 PQexec 或 PQgetResult 获得了 PGRES_COPY_OUT 或 PGRES_COPY_IN 结果对象的情况下执行. 

PQgetline 读取一个以回车符(换行符)结尾的字符行中指定字节数的字符(由后端服务器传输)到一个字符串缓冲区. 
int PQgetline(PGconn *conn,
              char *string,
              int length)
类似 fgets(3),这个过程拷贝最多 length-1 个字符到字符串里.但是它会象 gets(3) 那样把结尾的换行符转换成一个空字符(null).PQgetline 在碰到 EOF 时返回 EOF,如果整行都被读取了返回 0,如果缓冲区填满了而还没有遇到结束的换行符则返回 1. 
注意,应用程序必须检查新行是否包含两个字符 "/.",这表明后端服务器已经完成了 copy 命令的结果集的发送.如果应用可能收到超过 length-1 字符长的字符,我们就应该确保正确识别"/."行(例如,不要把一个长的行的结束当作一个终止行).src/bin/psql/copy.c 里的代码包含正确控制 copy 协议的过程. 

PQgetlineAsync 不做阻塞地读取一行以换行符结尾的字符(由后端服务器传输)到一个缓冲区中. 

int PQgetlineAsync(PGconn *conn,
                   char *buffer,
                   int bufsize)
这个过程类似于 PQgetline,但是可以用于那些必须异步地读取 COPY 数据的应用,因而是不阻塞的.在使用了 COPY 命令和获取了 PGRES_COPY_OUT 响应之后,应用应该调用 PQconsumeInput 和 PQgetlineAsync 直到收到数据结束的信号.不象 PQgetline,这个过程负责检测数据结束.在每次调用时,如果 libpq 的输入缓冲区内有可用的一个完整的换行符结尾的数据行或者调用者声明的缓冲区小于到来的数据行的长度,PQgetlineAsync 都将返回数据.否则,在其他数据到达之前不会返回数据. 
如果见到了拷贝数据结束的信号,此过程返回 -1,如果没有可用数据返回 0,或者是给出一个正数表明返回的数据的字节数.如果返回 -1,调用者下一步必须调用 PQendcopy,然后回到正常处理.返回的数据将不会超出换行符的范围.如果可能,每次将返回一个完整行.但如果调用者提供的缓冲区太小,无法容下后端发出的整行,那么将返回部分行.这个可以通过测试返回的最后一个字节是否“/n” 来确认.返回的字符串不是空结尾的.(如果你想得到一个空结尾的字串,确保你传递了一个比实际大小少一字节的缓冲区.) 

PQputline 向后端服务器发送一个空结尾的字符串.成功时返回 0,如果不能发送字符串返回 EOF. 

int PQputline(PGconn *conn,
              const char *string);
注意,应用在最后一行时必须显式的发送两个字符 "/.",通知后端它已经完成数据发送. 
PQputnbytes 向后端服务器发送一个非空结尾的字符串.成功时返回 0,如果不能发送字符串返回 EOF. 

int PQputnbytes(PGconn *conn,
                const char *buffer,
                int nbytes);
此函数类似 PQputline,除了数据缓冲区不需要是空结尾的,因为要发送的字节数是直接声明的. 
PQendcopy 与后端同步.这个函数等到后端完成拷贝(才返回?).你可以在用 PQputline 向后端发送完最后一个字符串后或者用 PGgetline 从后端获取最后一行字符串后调用它.我们必须调用这个函数,否则后端可能会和前端“同步丢失”。在这个函数返回后,后端就已经准备好接收下一个查询了.成功时返回 0,否则返回非零值. 

int PQendcopy(PGconn *conn);
一个例子: 
PQexec(conn, "create table foo (a int4, b char(16), d float8)");
PQexec(conn, "copy foo from stdin");
PQputline(conn, "3/thello world/t4.5/n");
PQputline(conn,"4/tgoodbye world/t7.11/n");
...
PQputline(conn,"//./n");
PQendcopy(conn);
在使用 PQgetResult 时,应用应该对 PGRES_COPY_OUT 的结果做出反应:重复调用 PQgetline,并且在收到结束行时调用 PQendcopy.然后应该返回到 PQgetResult 循环直到 PQgetResult 返回 NULL.类似的 PGRES_COPY_IN 结果是用一系列 PQputline 调用最后跟着 PQendcopy,然后返回到 PQgetResult 循环.这样的排列将保证嵌入到一系列SQL 命令里的 copy in 或 copy out 命令将被正确执行. 
旧的应用大多通过 PQexec 提交一个 copy in 或 copy out 命令并且假设在 PQendcopy 后事务完成.这样只有在 copy in/out 是查询字符串里的唯一的 SQL 命令才能正确工作.


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

libpq 跟踪函数
PQtrace 打开对前端/后端通讯的跟踪,把调试信息输出到一个文件流里. 
void PQtrace(PGconn *conn
             FILE *debug_port)
PQuntrace 关闭 PQtrace 打开的跟踪 
void PQuntrace(PGconn *conn)

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

libpq 控制函数
PQsetNoticeProcessor 控制 libpq 生成的通知和警告信息的汇报. 
typedef void (*PQnoticeProcessor) (void *arg, const char *message);

PQnoticeProcessor
PQsetNoticeProcessor(PGconn *conn,
                     PQnoticeProcessor proc,
                     void *arg);
缺省时, libpq 在后端往 stderr 上打印“通知”信息和一些它自身生成的错误信息.这个特性可以通过提供一个对信息进行某种加工的回叫函数来更改.我们向这个回叫函数传递错误信息的文本(包括文本结尾的换行符),和一个空(void)指针,该指针与传递给 PQsetNoticeProcessor 的完全一样.(如果需要,这个指针可以用于访问应用相关的状态.)缺省的通知处理器只是简单的 
static void
defaultNoticeProcessor(void * arg, const char * message)
{
    fprintf(stderr, "%s", message);
}
要使用特殊的通知处理器,在创建完新的 PGconn 对象后马上调用 PQsetNoticeProcessor。 
返回值是指向以前的通知处理器的指针。如果你提供了一个 NULL 做为回调指针,那么不会发生任何动作,只是返回当前的指针。 

一旦你设置了一个通知处理器,你就应该预料到该函数可能在 PGconn 对象或 PGresult 对象从开始存在时起就可能被调用.当创建一个 PGresult 时,PGconn 的当前的通知指针被拷贝到 PGresult 里提供给可能需要的过程,如 PQgetvalue 使用.


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

环境变量
下面的环境变量可以用于选择缺省的联接参数值,这些值将被 PQconnectdb 或 PQsetdbLogin 使用--如果调用代码没有直接声明相应值的话.这些(环境变量)可以避免把麻烦的数据库名强加入简单的应用程序的硬代码里面.The following environment variables can be used to select default connection parameter values, which will be used by PQconnectdb or PQsetdbLogin if no value is directly specified by the calling code. These are useful to avoid hard-coding database names into simple application programs. 
PGHOST 设置缺省的服务器名.如果声明了一个非零长的字符串,将使用 TCP/IP 通讯.如果没有主机名,libpq 将使用本地的Unix 域套接字. 
PGPORT 设置与 Postgres 后端通讯的缺省端口号或本地 Unix 主控套接字的文件扩展(文件标识符). 

PGDATABASE 设置缺省的 PostgreSQL 数据库名. 

PGUSER 设置用于与数据库联接和用于认证的用户名. 

PGPASSWORD 如果后端要求口令认证,设置使用的口令. 

PGREALM 设置与 Postgres 一起使用的 Kerberos --如果该域与本地域不同的话。如果设置了 PGREALM,Postgres 应用将试图用这个域(realm)与服务器进行认证并且使用独立的门票文件(ticket files)以避免与本地的门票文件冲突.只有在后端选择了 Kerberos 认证时才使用这个环境变量.(译注:门票文件是 Kerberos 认证协议中用于交换密钥的一个文件/服务器。) 

PGOPTIONS 为 Postgres 设置附加的运行时选项. 

PGTTY 设置后端调试信息显示输出的文件或者控制台(tty).

下面的环境变量可以用于为每个 Postgres 会话声明用户级别的缺省特性: 
PGDATESTYLE 设置缺省的日期/时间表现形式. 
PGTZ 设置缺省的时区. 

PGCLIENTENCODING 设置缺省的客户端编码(如果配制 Postgres 时选择了 MULTIBYTE 支持).

下面的环境变量可以用于为每个 Postgres 会话声明缺省的内部特性: 
PGGEQO 为基因优化器设置缺省模式.
参阅 SET SQL 命令获取这些环境变量的正确值的信息. 

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

线程特性
到 Postgres 7.0 时 libpq 是线程安全的,只要不是两个线程试图同时操作同一个 PGconn 对象.实际上,你无法从不同的线程向同一个联接对象发出并发的查询.(如果你需要运行并行查询,请启动多个联接.) 
PGresult 对象在创建后是只读的,因此可以自由地在线程之间传递. 

过时了的函数 PQoidStatus 和 fe_setauthsvc 都是线程不安全的,因此不应该在一个多线程的程序里面使用.PQoidStatus 可以由 PQoidValue代替.而我们觉得根本没有调用 fe_setauthsvc 的必要.


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

例子程序
例子程序 1
/*
 * testlibpq.c Test the C version of Libpq, the Postgres frontend
 * library.
 *
 *
 */
#include 
#include "libpq-fe.h"

void
exit_nicely(PGconn *conn)
{
    PQfinish(conn);
    exit(1);
}

main()
{
    char       *pghost,
               *pgport,
               *pgoptions,
               *pgtty;
    char       *dbName;
    int         nFields;
    int         i,
                j;

    /* FILE *debug; */

    PGconn     *conn;
    PGresult   *res;

    /*
     * begin, by setting the parameters for a backend connection if the
     * parameters are null, then the system will try to use reasonable
     * defaults by looking up environment variables or, failing that,
     * using hardwired constants
     */
    pghost = NULL;              /* host name of the backend server */
    pgport = NULL;              /* port of the backend server */
    pgoptions = NULL;           /* special options to start up the backend
                                 * server */
    pgtty = NULL;               /* debugging tty for the backend server */
    dbName = "template1";

    /* make a connection to the database */
    conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);

    /*
     * check to see that the backend connection was successfully made
     */
    if (PQstatus(conn) == CONNECTION_BAD)
    {
        fprintf(stderr, "Connection to database '%s' failed./n", dbName);
        fprintf(stderr, "%s", PQerrorMessage(conn));
        exit_nicely(conn);
    }

    /* debug = fopen("/tmp/trace.out","w"); */
    /* PQtrace(conn, debug);  */

    /* start a transaction block */
    res = PQexec(conn, "BEGIN");
    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "BEGIN command failed/n");
        PQclear(res);
        exit_nicely(conn);
    }

    /*
     * should PQclear PGresult whenever it is no longer needed to avoid
     * memory leaks
     */
    PQclear(res);

    /*
     * fetch instances from the pg_database, the system catalog of
     * databases
     */
    res = PQexec(conn, "DECLARE mycursor CURSOR FOR select * from pg_database");
    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "DECLARE CURSOR command failed/n");
        PQclear(res);
        exit_nicely(conn);
    }
    PQclear(res);
    res = PQexec(conn, "FETCH ALL in mycursor");
    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
    {
        fprintf(stderr, "FETCH ALL command didn't return tuples properly/n");
        PQclear(res);
        exit_nicely(conn);
    }

    /* first, print out the attribute names */
    nFields = PQnfields(res);
    for (i = 0; i < nFields; i++)
        printf("%-15s", PQfname(res, i));
    printf("/n/n");

    /* next, print out the instances */
    for (i = 0; i < PQntuples(res); i++)
    {
        for (j = 0; j < nFields; j++)
            printf("%-15s", PQgetvalue(res, i, j));
        printf("/n");
    }
    PQclear(res);

    /* close the cursor */
    res = PQexec(conn, "CLOSE mycursor");
    PQclear(res);

    /* commit the transaction */
    res = PQexec(conn, "COMMIT");
    PQclear(res);

    /* close the connection to the database and cleanup */
    PQfinish(conn);

    /* fclose(debug); */
    return 0;

}
例子程序 2
/*
 * testlibpq2.c
 *  Test of the asynchronous notification interface
 *
 * Start this program, then from psql in another window do
 *   NOTIFY TBL2;
 *
 * Or, if you want to get fancy, try this:
 * Populate a database with the following:
 *
 *   CREATE TABLE TBL1 (i int4);
 *
 *   CREATE TABLE TBL2 (i int4);
 *
 *   CREATE RULE r1 AS ON INSERT TO TBL1 DO
 *     (INSERT INTO TBL2 values (new.i); NOTIFY TBL2);
 *
 * and do
 *
 *   INSERT INTO TBL1 values (10);
 *
 */
#include 
#include "libpq-fe.h"

void
exit_nicely(PGconn *conn)
{
    PQfinish(conn);
    exit(1);
}

main()
{
    char       *pghost,
               *pgport,
               *pgoptions,
               *pgtty;
    char       *dbName;
    int         nFields;
    int         i,
                j;

    PGconn     *conn;
    PGresult   *res;
    PGnotify   *notify;

    /*
     * begin, by setting the parameters for a backend connection if the
     * parameters are null, then the system will try to use reasonable
     * defaults by looking up environment variables or, failing that,
     * using hardwired constants
     */
    pghost = NULL;              /* host name of the backend server */
    pgport = NULL;              /* port of the backend server */
    pgoptions = NULL;           /* special options to start up the backend
                                 * server */
    pgtty = NULL;               /* debugging tty for the backend server */
    dbName = getenv("USER");    /* change this to the name of your test
                                 * database */

    /* make a connection to the database */
    conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);

    /*
     * check to see that the backend connection was successfully made
     */
    if (PQstatus(conn) == CONNECTION_BAD)
    {
        fprintf(stderr, "Connection to database '%s' failed./n", dbName);
        fprintf(stderr, "%s", PQerrorMessage(conn));
        exit_nicely(conn);
    }

    res = PQexec(conn, "LISTEN TBL2");
    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "LISTEN command failed/n");
        PQclear(res);
        exit_nicely(conn);
    }

    /*
     * should PQclear PGresult whenever it is no longer needed to avoid
     * memory leaks
     */
    PQclear(res);

    while (1)
    {

        /*
         * wait a little bit between checks; waiting with select()
         * would be more efficient.
         */
        sleep(1);
        /* collect any asynchronous backend messages */
        PQconsumeInput(conn);
        /* check for asynchronous notify messages */
        while ((notify = PQnotifies(conn)) != NULL)
        {
            fprintf(stderr,
                 "ASYNC NOTIFY of '%s' from backend pid '%d' received/n",
                    notify->relname, notify->be_pid);
            free(notify);
        }
    }

    /* close the connection to the database and cleanup */
    PQfinish(conn);

    return 0;
}
例子程序 3
/*
 * testlibpq3.c Test the C version of Libpq, the Postgres frontend
 * library. tests the binary cursor interface
 *
 *
 *
 * populate a database by doing the following:
 *
 * CREATE TABLE test1 (i int4, d float4, p polygon);
 *
 * INSERT INTO test1 values (1, 3.567, '(3.0, 4.0, 1.0,
 * 2.0)'::polygon);
 *
 * INSERT INTO test1 values (2, 89.05, '(4.0, 3.0, 2.0,
 * 1.0)'::polygon);
 *
 * the expected output is:
 *
 * tuple 0: got i = (4 bytes) 1, d = (4 bytes) 3.567000, p = (4
 * bytes) 2 points   boundbox = (hi=3.000000/4.000000, lo =
 * 1.000000,2.000000) tuple 1: got i = (4 bytes) 2, d = (4 bytes)
 * 89.050003, p = (4 bytes) 2 points   boundbox =
 * (hi=4.000000/3.000000, lo = 2.000000,1.000000)
 *
 *
 */
#include 
#include "libpq-fe.h"
#include "utils/geo-decls.h"    /* for the POLYGON type */

void
exit_nicely(PGconn *conn)
{
    PQfinish(conn);
    exit(1);
}

main()
{
    char       *pghost,
               *pgport,
               *pgoptions,
               *pgtty;
    char       *dbName;
    int         nFields;
    int         i,
                j;
    int         i_fnum,
                d_fnum,
                p_fnum;
    PGconn     *conn;
    PGresult   *res;

    /*
     * begin, by setting the parameters for a backend connection if the
     * parameters are null, then the system will try to use reasonable
     * defaults by looking up environment variables or, failing that,
     * using hardwired constants
     */
    pghost = NULL;              /* host name of the backend server */
    pgport = NULL;              /* port of the backend server */
    pgoptions = NULL;           /* special options to start up the backend
                                 * server */
    pgtty = NULL;               /* debugging tty for the backend server */

    dbName = getenv("USER");    /* change this to the name of your test
                                 * database */

    /* make a connection to the database */
    conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);

    /*
     * check to see that the backend connection was successfully made
     */
    if (PQstatus(conn) == CONNECTION_BAD)
    {
        fprintf(stderr, "Connection to database '%s' failed./n", dbName);
        fprintf(stderr, "%s", PQerrorMessage(conn));
        exit_nicely(conn);
    }

    /* start a transaction block */
    res = PQexec(conn, "BEGIN");
    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "BEGIN command failed/n");
        PQclear(res);
        exit_nicely(conn);
    }

    /*
     * should PQclear PGresult whenever it is no longer needed to avoid
     * memory leaks
     */
    PQclear(res);

    /*
     * fetch instances from the pg_database, the system catalog of
     * databases
     */
    res = PQexec(conn, "DECLARE mycursor BINARY CURSOR FOR select * from test1");
    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    {
        fprintf(stderr, "DECLARE CURSOR command failed/n");
        PQclear(res);
        exit_nicely(conn);
    }
    PQclear(res);

    res = PQexec(conn, "FETCH ALL in mycursor");
    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
    {
        fprintf(stderr, "FETCH ALL command didn't return tuples properly/n");
        PQclear(res);
        exit_nicely(conn);
    }

    i_fnum = PQfnumber(res, "i");
    d_fnum = PQfnumber(res, "d");
    p_fnum = PQfnumber(res, "p");

    for (i = 0; i < 3; i++)
    {
        printf("type[%d] = %d, size[%d] = %d/n",
               i, PQftype(res, i),
               i, PQfsize(res, i));
    }
    for (i = 0; i < PQntuples(res); i++)
    {
        int        *ival;
        float      *dval;
        int         plen;
        POLYGON    *pval;

        /* we hard-wire this to the 3 fields we know about */
        ival = (int *) PQgetvalue(res, i, i_fnum);
        dval = (float *) PQgetvalue(res, i, d_fnum);
        plen = PQgetlength(res, i, p_fnum);

        /*
         * plen doesn't include the length field so need to
         * increment by VARHDSZ
         */
        pval = (POLYGON *) malloc(plen + VARHDRSZ);
        pval->size = plen;
        memmove((char *) &pval->npts, PQgetvalue(res, i, p_fnum), plen);
        printf("tuple %d: got/n", i);
        printf(" i = (%d bytes) %d,/n",
               PQgetlength(res, i, i_fnum), *ival);
        printf(" d = (%d bytes) %f,/n",
               PQgetlength(res, i, d_fnum), *dval);
        printf(" p = (%d bytes) %d points /tboundbox = (hi=%f/%f, lo = %f,%f)/n",
               PQgetlength(res, i, d_fnum),
               pval->npts,
               pval->boundbox.xh,
               pval->boundbox.yh,
               pval->boundbox.xl,
               pval->boundbox.yl);
    }
    PQclear(res);

    /* close the cursor */
    res = PQexec(conn, "CLOSE mycursor");
    PQclear(res);

    /* commit the transaction */
    res = PQexec(conn, "COMMIT");
    PQclear(res);

    /* close the connection to the database and cleanup */
    PQfinish(conn);

    return 0;
}

--------------------------------------------------------------------------------
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选