PostgreSQL7.0手册-接口-54. libpq - C++ 绑定库
内容
控制和初始化
libpq++ 类
数据库联接函数
查询执行函数
异步通知
F与 COPY 命令Command
libpq++ 是 Postgres 的 C++ API (接口)。libpq++ 是一个 C++ 类的集合,这些类允许客户端程序与 Postgres 后端服务器进行联接。联接有两种形式:一个数据库类和一个大对象类。
数据库类用于操作数据库,你可以向 Postgres 后端服务器发送任何 SQL 查询并检索服务器的返回。
大对象类用于操作数据库中的大对象。尽管一个大对象实例可以给Postgres 后端发送正常的查询,但通常只是用于那些不返回任何数据的简单查询。一个大对象应该看作一个文件流。以后它应该显得更象 C++ 文件流 cin,cout 和 cerr。
本章基于 libpq C 库的文档。本章的末尾有三个短程序列出来作为 libpq++ 编程的例子(尽管不是很好的编程例子)。在 src/libpq++/examples 里有好几个 libpq++ 应用的例子,包括本章的三个例子的源码。
控制和初始化
环境变量
下面的环境变量可以在一个环境里设置缺省值以避免在应用程序里面把数据库名放到硬代码里:
注意:请参考 libpq - C 库 获取一个可用联接选项的完整列表。
下面的环境变量可以用于选择缺省的联接参数值,这些值将被 PQconnectdb 或 PQsetdbLogin 使用--如果调用代码没有直接声明相应值的话.这些(环境变量)可以避免把麻烦的数据库名强加入简单的应用程序的硬代码里面。
注意:libpq++ 只使用环境变量或者 PQconnectdb conninfo 风格的字串。
PGHOST 设置缺省的服务器名.如果声明了一个非零长的字符串,将使用 TCP/IP 通讯.如果没有主机名,libpq 将使用本地的Unix 域套接字.
PGPORT 设置与 Postgres 后端通讯的缺省端口号或本地 Unix 主控套接字的文件扩展(文件标识符).
PGDATABASE 设置缺省的 Postgres 数据库名.
PGUSER 设置用于与数据库联接和用于认证的用户名.
PGPASSWORD 如果后端要求口令认证,设置使用的口令.
PGREALM 设置与 Postgres 一起使用的 Kerberos --如果该域与本地域不同的话。如果设置了 PGREALM,Postgres 应用将试图用这个域(realm)与服务器进行认证并且使用独立的门票文件(ticket files)以避免与本地的门票文件冲突.只有在后端选择了 Kerberos 认证时才使用这个环境变量.(译注:门票文件是 Kerberos 认证协议中用于交换密钥的一个文件/服务器。)
PGOPTIONS 为 Postgres 设置附加的运行时选项.
PGTTY 设置后端调试信息显示输出的文件或者控制台(tty).
下面的环境变量可以用于为每个 Postgres 会话声明用户级别的缺省特性:
PGDATESTYLE 设置缺省的日期/时间表现形式.
PGTZ 设置缺省的时区.
下面的环境变量可以用于为每个 Postgres 会话声明缺省的内部特性:
PGGEQO 为基因优化器设置缺省模式.
参阅 SET SQL 命令获取这些环境变量的正确值的信息.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
libpq++ 类
联接类:PgConnection
联接类与数据库进行实际的联接,被所有的访问类继承。
数据库类:PgDatabase
数据库类提供与一个服务器后端已联接的 C++ 对象。要创建这样的一个对象,我们首先需要用于访问后端的环境。下面的构造器处理从 C++ 程序里面访问后端服务器的工作。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
数据库联接函数
PgConnection 与一个后端服务器建议一个新联接。
PgConnection::PgConnection(const char *conninfo)
尽管典型的是从一个访问类里面调用(此函数),与后端服务器的联接很有可能是通过创建一个 PgConnection 对象实现的。
ConnectionBad 返回与一个后端服务器的联接是否成功。
int PgConnection::ConnectionBad()
如果联接失败返回 TRUE (真)。
Status 返回与一个后端服务器的联接的状态。
ConnStatusType PgConnection::Status()
取决于联接的状态,返回 CONNECTION_OK 或 CONNECTION_BAD。
PgDatabase 与后端服务器建立一个新联接。
PgDatabase(const char *conninfo)
在创建一个 PgDatabase 后,我们在向对象发送查询前要通过检查来验证与数据库的联接是否成功。这一点很容易通过使用 Status 或 ConnectionBad 方法检索 PgDatabase 对象当前的状态来实现。
DBName 返回当前数据库的名称。
const char *PgConnection::DBName()
Notifies 返回一个从后端收到的未处理通知信息列表里的下一条通知。
PGnotify* PgConnection::Notifies()
参阅 PQnotifies() 获取细节。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
查询执行函数
Exec 向后端服务器发送一个查询。可能我们更愿意使用下面两个函数之一。
ExecStatusType PgConnection::Exec(const char* query)
返回查询的结果。可能的状态结果可以是下面的值:
PGRES_EMPTY_QUERY
PGRES_COMMAND_OK,如果查询是一条命令
PGRES_TUPLES_OK,如果查询成功返回记录
PGRES_COPY_OUT
PGRES_COPY_IN
PGRES_BAD_RESPONSE,如收到一个未知的响应
PGRES_NONFATAL_ERROR
PGRES_FATAL_ERROR
ExecCommandOk 向后端服务器发送一条命令查询。
int PgConnection::ExecCommandOk(const char *query)
如果命令查询成功返回 TRUE。
ExecTuplesOk 向后端服务器发送一条命令查询。
int PgConnection::ExecTuplesOk(const char *query)
如果命令查询成功返回 TRUE。
ErrorMessage 返回最后一条错误信息文本。
const char *PgConnection::ErrorMessage()
Tuples 返回查询结果里记录(实例)的条数。
int PgDatabase::Tuples()
CmdTuples 返回在一次 INSERT,UPDATE 或 DELETE 后涉及的行数.如果是其他命令,返回 -1.
int PgDatabase::CmdTuples()
Fields 返回查询结果里每条记录的数据域(字段)数。
int PgDatabase::Fields()
FieldName 返回与指定域索引相联的域(字段)名称。域索引从 0 开始计数。
const char *PgDatabase::FieldName(int field_num)
FieldNum 返回与指定域(字段)名称相联的域索引。
int PgDatabase::FieldNum(const char* field_name)
如果给出的名称无法与任何域匹配返回 -1。
FieldType 返回与给出域索引相联的域的类型。返回的整数是该类型的内部编码。域索引从 0 开始计数。
Oid PgDatabase::FieldType(int field_num)
FieldType 返回与给出域名称相联的域的类型。返回的整数是该类型的内部编码。域索引从 0 开始计数。
Oid PgDatabase::FieldType(const char* field_name)
FieldSize 返回与给出域索引相联的域的以字节计算的尺寸。域索引从 0 开始计数。
short PgDatabase::FieldSize(int field_num)
返回在数据库记录里面给该数据域分配的空间,换句话说就是该数据类型在服务器里的二进制形式的大小(尺寸).如果该数据域是可变尺寸,返回 -1.
FieldSize 返回与给出域名称相联的域的以字节计算的尺寸。域索引从 0 开始计数。
short PgDatabase::FieldSize(const char *field_name)
返回在数据库记录里面给该数据域分配的空间,换句话说就是该数据类型在服务器里的二进制形式的大小(尺寸).如果该数据域是可变尺寸,返回 -1.
GetValue 返回一个 PGresult 里面的一条记录的单独的一个数据域(字段)的值.记录和数据域索引从 0 开始.
const char *PgDatabase::GetValue(int tup_num, int field_num)
对大多数查询而言,GetValue 返回的值是一个表示字段值的空(NULL)结尾的 ASCII 字符串.但是如果 BinaryTuples() 为 TRUE, GetValue 返回的值就是该类型在后端服务器内部的二进制表现形式(但是不包括尺寸字--如果数据域是变长的).这样,把数据转换成对应的 C 类型就是程序员的责任了. GetValue 返回的指针指向一个本身是 PGresult 结构的一部分的存储区域.我们不能更改它,并且如果我们要在 PGresult 结构的生存期后还要使用它的话,我们必须显式的把该数值拷贝到其他存储器中.BinaryTuples() 还没有实现。
GetValue 返回一个 PGresult 里面的一条记录的单独的一个数据域(字段)的值.记录和数据域索引从 0 开始.
const char *PgDatabase::GetValue(int tup_num, const char *field_name)
对大多数查询而言,GetValue 返回的值是一个表示字段值的空(NULL)结尾的 ASCII 字符串.但是如果 BinaryTuples() 为 TRUE, GetValue 返回的值就是该类型在后端服务器内部的二进制表现形式(但是不包括尺寸字--如果数据域是变长的).这样,把数据转换成对应的 C 类型就是程序员的责任了. GetValue 返回的指针指向一个本身是 PGresult 结构的一部分的存储区域.我们不能更改它,并且如果我们要在 PGresult 结构的生存期后还要使用它的话,我们必须显式的把该数值拷贝到其他存储器中.BinaryTuples() 还没有实现。
GetLength 返回以字节计的数据域(字段)的长度.记录和数据域索引从 0 开始.
int PgDatabase::GetLength(int tup_num, int field_num)
这是某一特定数据值的实际数据长度,也就是由 GetValue 指向的对象的尺寸.注意,对于 ASCII 代表的数值,这个尺寸与 PQfsize 报告的二进制尺寸无关.
GetLength 返回以字节计的数据域(字段)的长度.记录和数据域索引从 0 开始.
int PgDatabase::GetLength(int tup_num, const char* field_name)
这是某一特定数据值的实际数据长度,也就是由 GetValue 指向的对象的尺寸.注意,对于 ASCII 代表的数值,这个尺寸与 PQfsize 报告的二进制尺寸无关.
DisplayTuples 向指定输出流打印所有记录和(可选的)字段名。
void PgDatabase::DisplayTuples(FILE *out = 0, int fillAlign = 1,
const char* fieldSep = "",int printHeader = 1, int quiet = 0)
PrintTuples 向指定输出流打印所有记录和(可选的)字段名。
void PgDatabase::PrintTuples(FILE *out = 0, int printAttName = 1,
int terseOutput = 0, int width = 0)
GetLine
int PgDatabase::GetLine(char* string, int length)
PutLine
void PgDatabase::PutLine(const char* string)
OidStatus
const char *PgDatabase::OidStatus()
EndCopy
int PgDatabase::EndCopy()
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
异步通知
Postgres 支持通过 LISTEN 和 NOTIFY 命令产生的异步通知.一个后端用 LISTEN 命令注册一个它感兴趣的信号灯.所有正在监听某一命名信号灯的后端在该条件名的 NOTIFY (通知)被另一个后端执行后都将被异步地通知.没有附加的信息从通知发出者传递到通知接收者.因此,很典型地,任何实际的需要被传递的数据都是通过一个数据库关系传递的.通常条件名是与相关联的关系同名,但是并不是一定要与某个关系相关才行.
注意:以前,本文档把用于异步通知的名称与关系或者表相联。但实际上在这两个概念的实现上没有任何直接的联系,因而实际上命名信号灯不需要象以前定义的那样与对应的关系相关联。
libpq++ 应用在与之相联的后端收到一个异步通知时将被通知。不过,从后端到前端的通讯不是异步的。libpq++ 应用必须轮询后端以便查找是否有待处理的信息。在一个查询执行完毕后,前端可以调用 PgDatabase::Notifies 来判断目前是否有从后端来的任何通知数据。PgDatabase::Notifies 从一个来自后端的未处理通知列表里返回一个通知。如果没有来自后端的待处理的通知,该函数返回 NULL。PgDatabase::Notifies 的表现想一个弹出栈。一旦从 PgDatabase::Notifies 返回了一个通知,该通知就被认为已处理并且被从通知列表里删除。
PgDatabase::Notifies 从服务器里检索待处理通知。
PGnotify* PgDatabase::Notifies()
第二个例子程序给出了一个使用异步通知的例子。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
与 COPY 命令向关联的函数
Postgres 里的 copy 命令里有用于 libpq++ 里从网络联接读出或者写入的选项.因此,这些函数有必要直接访问网络联接,以便应用可以充分利用这个功能.
PgDatabase::GetLine 读取一个以回车符(换行符)结尾的字符行中 length 字节的字符(由后端服务器传输)到一个字符串缓冲区 string 里.
int PgDatabase::GetLine(char* string, int length)
类似 Unix 系统过程 fgets(3),这个过程拷贝最多 length-1 个字符到字符串 string 里.但是它会象 gets(3) 那样把结尾的换行符转换成一个空字符(null)。
PgDatabase::GetLine 在碰到文件结束时返回 EOF,如果整行都被读取了返回 0,如果缓冲区填满了而还没有遇到结束的换行符则返回 1.
注意,应用程序必须检查新行是否包含单个句点("."),这表明后端服务器已经完成了 copy 命令结果的发送。因此,如果应用预计接收超过 length-1 字符长的行,应用就必须保证仔细地检查PgDatabase::GetLine 的返回值。
PgDatabase::PutLine 发送一个空结尾的 string 到后端服务器。
void PgDatabase::PutLine(char* string)
应用必须显式的发送一个句点字符(".")告诉后端它已经完成它的数据发送。
PgDatabase::EndCopy 与后端同步。
int PgDatabase::EndCopy()
这个函数等到后端完成 copy(才返回?).你可以在用 PgDatabase::PutLine 向后端发送完最后一个字符串后或者用 PgDatabase::GetLine 从后端获取最后一行字符串后调用它.我们必须调用这个函数,否则后端可能会和前端“丢失同步”。在这个函数返回后,后端就已经准备好接收下一个查询了。
成功时返回 0,否则返回非零值。
一个例子:
PgDatabase data;
data.Exec("create table foo (a int4, b char(16), d float8)");
data.Exec("copy foo from stdin");
data.PutLine("3\tHello World\t4.5\n");
data.PutLine("4\tGoodbye World\t7.11\n");
&...
data.PutLine("\\.\n");
data.EndCopy();
--------------------------------------------------------------------------------