32.3. 命令执行函数

32.3.1. 主要函数
32.3.2. 检索查询结果信息
32.3.3. 检索其他结果信息
32.3.4. 用于包含在 SQL 命令中的转移串

一旦到一个数据库服务器的连接被成功建立,这里描述的函数可以被用来执行 SQL 查询和命令。

32.3.1. 主要函数

PQexec

提交一个命令给服务器并且等待结果。

PGresult *PQexec(PGconn *conn, const char *command);

返回一个PGresult指针或者可能是一个空指针。 除了内存不足的情况或者由于严重错误无法将命令发送给服务器之外,一般都会返回一个非空指针。 PQresultStatus函数应当被调用来检查返回值是否代表错误(包括空指针的值,它会返回PGRES_FATAL_ERROR)。 用PQerrorMessage可得到关于那些错误的详细信息。

命令字符串可以包括多个 SQL 命令(用分号分隔)。 在一次PQexec调用中被发送的多个查询会在一个事务中处理,除非其中有显式的BEGIN/COMMIT命令将该查询字符串划分成多个事务(服务器如何处理多查询字符串的更多细节请参考Section 51.2.2.1)。 但是注意,返回的PGresult结构只描述该字符串中被执行的最后一个命令的结果。 如果一个命令失败,该字符串的处理会在它那里停止并且返回的PGresult会描述错误情况。

PQexecParams

提交一个命令给服务器并且等待结果,它可以在 SQL 命令文本之外独立地传递参数。

PGresult *PQexecParams(PGconn *conn,
                       const char *command,
                       int nParams,
                       const Oid *paramTypes,
                       const char * const *paramValues,
                       const int *paramLengths,
                       const int *paramFormats,
                       int resultFormat);

PQexecParamsPQexec相似,但是提供了额外的功能:参数值可以与命令字符串分开指定,并且可以以文本或二进制格式请求查询结果。 PQexecParams只在 3.0 协议及其后的连接中被支持,当使用 2.0 协议时它会失败。

该函数的参数是:

conn

要在其中发送命令的连接对象。

command

要执行的 SQL 命令字符串。如果使用了参数,它们在该命令字符串中被引用为$1$2等。

nParams

提供的参数数量。它是数组paramTypes[]paramValues[]paramLengths[]paramFormats[]的长度(当nParams为零时,数组指针可以是NULL)。

paramTypes[]

通过 OID 指定要赋予给参数符号的数据类型。如果paramTypesNULL或者该数组中任何特定元素为零,服务器会用对待未知类型文字串的方式为参数符号推测一种数据类型。

paramValues[]

指定参数的实际值。这个数组中的一个空指针表示对应的参数为空,否则该指针指向一个以零终止的文本字符串(用于文本格式)或者以服务器所期待格式的二进制数据(用于二进制格式)。

paramLengths[]

指定二进制格式参数的实际数据长度。它对空参数和文本格式参数被忽略。当没有二进制参数时,该数组指针可以为空。

paramFormats[]

指定参数是否为文本(在参数相应的数组项中放一个零)或二进制(在参数相应的数组项中放一个一)。如果该数组指针为空,那么所有参数都会被假定为文本串。

以二进制格式传递的值要求后端所期待的内部表示形式的知识。例如,整数必须以网络字节序被传递。传递numeric值要求关于服务器存储格式的知识,正如src/backend/utils/adt/numeric.c::numeric_send()以及src/backend/utils/adt/numeric.c::numeric_recv()中所实现的。

Lightdb 23.3引入了一个新的数据库级别GUC参数lightdb_ascii_zero_store_value。 此参数取值范围为0到32,包含0,32。 如果数据库兼容模式为Oracle或Mysql,并且 lightdb_ascii_zero_store_value为非零ASCII 码值,当参数类型为文本类型的时候,'\0' 被替换为ASCII码值 lightdb_ascii_zero_store_value

更多关于GUClightdb_ascii_zero_store_value的信息,请参考 lightdb_ascii_zero_store_value

resultFormat

指定零来得到文本格式的结果,或者指定一来得到二进制格式的结果(目前没有规定要求以不同格式得到不同的结果列,尽管在底层协议中这是可以实现的)。

PQexecParams相对于PQexec的主要优点是参数值可以从命令串中分离,因此避免了冗长的书写、容易发生错误的引用以及转义。

PQexec不同,PQexecParams至多允许在给定串中出现一个 SQL 命令(其中可以有分号,但是不能有超过一个非空命令)。这是底层协议的一个限制,但是有助于抵抗 SQL 注入攻击。

Tip

通过 OID 指定参数类型很罗嗦,特别是如果你不愿意将特定的 OID 值硬编码到你的程序中时。不过,即使服务器本身也无法确定参数的类型,你可以避免这样做,或者选择一种与你想要的不同的类型。在 SQL 命令文本中,附加一个显式造型给参数符号来表示你将发送什么样的数据类型。例如:

SELECT * FROM mytable WHERE x = $1::bigint;

这强制参数$1被当作bigint,而默认情况下它将被赋予与x相同的类型。当以二进制格式发送参数值时,我们强烈推荐以这种方式或通过指定一个数字类型的 OID 来强制参数类型决定。因为二进制格式比文本格式具有更少的冗余,并且因此服务器将不会有更多机会为你检测一个类型匹配错误。

PQprepare

提交一个请求用给定参数创建一个预备语句并且等待完成。

PGresult *PQprepare(PGconn *conn,
                    const char *stmtName,
                    const char *query,
                    int nParams,
                    const Oid *paramTypes);

PQprepare创建一个后面会由PQexecPrepared执行的预备语句。 这个特性允许命令被反复执行而无需每次都进行解析和规划,详见PREPAREPQprepare只在协议 3.0 及之后的连接中被支持,当使用协议 2.0 时它将失败。

该函数从query串创建一个名为stmtName的预备语句,该串必须包含一个单一 SQL 命令。 stmtName可以是""来创建一个未命名语句,在这种情况下任何已存在未命名语句将被自动替换。 如果语句名称已经在当前会话中被定义,则是一种错误。如果使用了任何参数,它们在查询中以$1$2等引用。 nParams是参数的个数,其类型在数组paramTypes[]中被预先指定(当nParams为零时,该数组指针可以是NULL)。 paramTypes[]通过 OID 指定要赋予给参数符号的数据类型。 如果paramTypesNULL或者该数组中任何特定元素为零,服务器会用对待未知类型文字串的方式为参数符号推测一种数据类型。 还有,查询能够使用编号高于nParams的参数符号,它们的数据类型也会被自动推测(找出推测出的数据类型的方法见PQdescribePrepared)。

正如PQexec一样,结果通常是一个PGresult对象,其内容代表服务器端成功或失败。 一个空结果表示内存不足或者根本无法发送命令。关于错误的更多信息请见PQerrorMessage

用于PQexecPrepared的预备语句也能通过执行 SQL PREPARE语句来创建。 还有,尽管没有libpq函数来删除一个预备语句,SQL DEALLOCATE语句可被用于此目的。

PQexecPrepared

发送一个请求来用给定参数执行一个预备语句,并且等待结果。

PGresult *PQexecPrepared(PGconn *conn,
                         const char *stmtName,
                         int nParams,
                         const char * const *paramValues,
                         const int *paramLengths,
                         const int *paramFormats,
                         int resultFormat);

PQexecPreparedPQexecParams,但是要被执行的命令是用之前准备的语句的名字指定,而不是指定一个查询串。 这个特性允许将被重复使用的命令只被解析和规划一次,而不是在每次被执行时都被解析和规划。这个语句必须之前在当前会话中已经被准备好。 PQexecPrepared仅被协议 3.0 及之后的连接支持,当使用协议 2.0 时它会失败。

参数和PQexecParams相同,除了给定的是一个预备语句的名称而不是一个查询语句,以及不存在paramTypes[]参数(因为预备语句的参数类型已经在它被创建时决定好了)。

PQdescribePrepared

提交一个请求来获得有关指定预备语句的信息,并且等待完成。

PGresult *PQdescribePrepared(PGconn *conn, const char *stmtName);

PQdescribePrepared允许一个应用获得有关一个之前预备好的语句的信息。PQdescribePrepared仅被协议 3.0 及之后的连接支持,当使用协议 2.0 时它会失败。

stmtName可以用""或者NULL来引用未命名语句,否则它必须是一个现有预备语句的名字。 如果成功,一个PGresult以及状态PGRES_COMMAND_OK会被返回。 函数PQnparamsPQparamtype可以被应用到这个PGresult来得到关于该预备语句参数的额信息, 而函数PQnfields, PQfname,PQftype等提供该语句结果列(如果有)的信息。

PQdescribePortal

提交一个请求来得到有关指定入口的信息,并且等待完成。

PGresult *PQdescribePortal(PGconn *conn, const char *portalName);

PQdescribePortal允许一个应用获得有关一个之前被创建的入口的信息(libpq不提供对入口任何直接的访问,但是你可以使用这个函数来观察一个通过DECLARE CURSOR SQL 命令创建的游标的属性)。 PQdescribePortal仅被协议 3.0 及之后的连接支持,当使用协议 2.0 时它会失败。

portalName可以用""或者NULL来引用未命名入口,否则它必须是一个现有入口的名字。 如果陈功,一个PGresult和状态PGRES_COMMAND_OK会被返回。 函数PQnfields, PQfname, PQftype等可以被应用到PGresult来获得有关该入口结果列(如果有)的信息。

PGresult结构封装了由服务器返回的结果。libpq应用程序员应该小心地维护PGresult的抽象。使用下面的存储器函数来得到PGresult的内容。避免直接引用PGresult结构的域,因为它们可能在未来更改。

PQresultStatus

返回该命令的结果状态。

ExecStatusType PQresultStatus(const PGresult *res);

PQresultStatus能返回下列值之一:

PGRES_EMPTY_QUERY

发送给服务器的字符串为空。

PGRES_COMMAND_OK

一个不返回数据的命令成功完成。

PGRES_TUPLES_OK

一个返回数据的命令(例如SELECT或者SHOW)成功完成。

PGRES_COPY_OUT

从服务器复制出数据的传输开始。

PGRES_COPY_IN

复制数据到服务器的传输开始。

PGRES_BAD_RESPONSE

无法理解服务器的响应。

PGRES_NONFATAL_ERROR

发生了一次非致命错误(一个提示或警告)。

PGRES_FATAL_ERROR

发生了一次致命错误。

PGRES_COPY_BOTH

向服务器复制数据/从服务器复制数据的传输开始。这个特性当前只被用于流复制,因此这个状态应该不会在普通应用中出现。

PGRES_SINGLE_TUPLE

PGresult包含来自于当前命令的一个单一结果元组。这个状态只在查询选择了单一行模式时发生(见Section 32.5)。

如果结果状态是PGRES_TUPLES_OK或者PGRES_SINGLE_TUPLE,那么下面所描述的函数能被用来检索该查询所返回的行。注意,一个恰好检索零行的SELECT命令仍然会显示PGRES_TUPLES_OKPGRES_COMMAND_OK用于从不返回行的命令(不带RETURNING子句的INSERT或者UPDATE等)。一个PGRES_EMPTY_QUERY可能表示客户端软件中的一个缺陷。

一个状态为PGRES_NONFATAL_ERROR的结果将不会被PQexec或者其他查询执行函数直接返回,这类结果将被传递给提示处理器(见 Section 32.12)。

PQresStatus

PQresultStatus返回的枚举转换成描述状态编码的字符串常量。调用者不应该释放结果。

char *PQresStatus(ExecStatusType status);

PQresultErrorMessage

返回与该命令相关的错误消息,如果有错误则会返回一个空字符串。

char *PQresultErrorMessage(const PGresult *res);

如果有一个错误,被返回的字符串将包含一个收尾的新行。调用者不应该直接释放结果。它将在相关的PGresult句柄被传递给PQclear之后被释放。

紧跟着一个PQexecPQgetResult调用,PQerrorMessage(在连接上)将返回与PQresultErrorMessage相同的字符串(在结果上)。 不过,一个PGresult将保持它的错误消息直到被销毁,而连接的错误消息将在后续操作被执行时被更改。 当你想要知道与一个特定PGresult相关的状态,使用PQresultErrorMessage。 而当你想要知道连接上最后一个操作的状态,使用PQerrorMessage

PQresultVerboseErrorMessage

返回与PGresult对象相关的错误消息的重新格式化的版本。

char *PQresultVerboseErrorMessage(const PGresult *res,
                                  PGVerbosity verbosity,
                                  PGContextVisibility show_context);

在有些情况下,客户端可能希望得到之前报告过的错误的更加详尽的版本。 如果在产生给定PGresult的连接上 verbosity 设置有效,PQresultVerboseErrorMessage会通过计算已经被PQresultErrorMessage产生过的消息来满足这种需求。 如果PGresult不是一个错误结果,则会报告PGresult is not an error result。返回的字符串包括一个新行作为结尾。

和大部分从PGresult中提取数据的其他函数不同,这个函数的结果是一个全新分配的字符串。调用者在不需要这个字符串以后,必须使用PQfreemem()释放它。

如果内存不足,可能会返回 NULL。

PQresultErrorField

返回一个错误报告的一个域。

char *PQresultErrorField(const PGresult *res, int fieldcode);

fieldcode是一个错误域标识符,见下列符号。 如果PGresult不是一个错误或者警告结果或者不包括指定域,会返回NULL。 域通常不包括一个收尾的新行。调用者不应该直接释放结果。 它将在相关的PGresult句柄被传递给PQclear之后被释放。

下列域代码可用:

PG_DIAG_SEVERITY

严重性。域的内容是ERRORFATALPANIC(在一个错误消息中)。或者是WARNINGNOTICEDEBUGINFOLOG(在一个提示消息中)。或者是其中之一的一个本地化翻译。总是存在。

PG_DIAG_SEVERITY_NONLOCALIZED

域的内容是ERRORFATALPANIC(在一个错误消息中)。或者是WARNINGNOTICEDEBUGINFOLOG(在一个提示消息中)。这和PG_DIAG_SEVERITY域相同,不过内容不会被本地化。只存在于LightDB 9.6 版本以后产生的报告中。

PG_DIAG_SQLSTATE

用于错误的 SQLSTATE 代码。SQLSTATE 代码标识了已经发生的错误的类型,它可以被前端应用用来执行特定操作(例如错误处理)来响应一个特定数据库错误。一个可能的 SQLSTATE 代码列表可见Appendix A。这个域无法被本地化,并且总是存在。

PG_DIAG_MESSAGE_PRIMARY

主要的人类可读的错误消息(通常是一行)。总是存在。

PG_DIAG_MESSAGE_DETAIL

细节:一个可选的次级错误消息,它携带了关于问题的等多细节。可能有多行。

PG_DIAG_MESSAGE_HINT

提示:一个关于如何处理该问题的可选建议。它与细节的区别在于它提供了建议(可能不合适)而不是铁的事实。可能有多行。

PG_DIAG_STATEMENT_POSITION

包含一个十进制整数的字符串,它表示一个错误游标位置,该位置是原始语句字符串的索引。第一个字符的索引是 1,位置以字符计算而不是以及字节计算。

PG_DIAG_INTERNAL_POSITION

这被定义为与PG_DIAG_STATEMENT_POSITION域相同,但是它被用在游标位置引用一个内部产生的命令而不是客户端提交的命令时。当这个域出现时,PG_DIAG_INTERNAL_QUERY域将总是出现。

PG_DIAG_INTERNAL_QUERY

一个失败的内部产生的命令的文本。例如,这可能是由一个 PL/pgSQL 函数发出的 SQL 查询。

PG_DIAG_CONTEXT

指示错误发生的环境。当前这包括活动过程语言函数的调用栈追踪以及内部生成的查询。追踪是每行一项,最近的排在最前面。

PG_DIAG_SCHEMA_NAME

如果错误与某个特定的数据库对象相关,这里是包含该对象的模式名(如果有)。

PG_DIAG_TABLE_NAME

如果错误与某个特定表相关,这里是该表的名字(该表的模式参考模式名域)。

PG_DIAG_COLUMN_NAME

如果错误与一个特定表列相关,这里是该表列的名字(参考模式和表名域来标识该表)。

PG_DIAG_DATATYPE_NAME

如果错误与一个特定数据类型相关,这里是该数据了行的名字(该数据类型的模式名参考模式名域)。

PG_DIAG_CONSTRAINT_NAME

如果错误与一个特定约束相关,这里是该约束的名字。相关的表或域参考上面列出的域(为了这个目的,索引也被视作约束,即使它们不是用约束语法创建的)。

PG_DIAG_SOURCE_FILE

报告错误的源代码所在的文件名。

PG_DIAG_SOURCE_LINE

报告错误的源代码行号。

PG_DIAG_SOURCE_FUNCTION

报告错误的源代码函数的名字。

Note

用于模式名、表名、列名、数据类型名和约束名的域只提供给有限的错误类型,见Appendix A。不要假定任何这些域的存在保证另一个域的存在。核心错误源会遵守上面提到的内在联系,但是用户定义的函数可能以其他方式使用这些域。同样地,不要假定这些域代表当前数据库中同类的对象。

客户端负责格式化显示信息来迎合它的需要,特别是根据需要打断长的行。出现在错误消息域中的新行字符应该被当作分段而不是换行。

libpq内部产生的错误将有严重和主要消息,但是通常没有其他域。3.0 协议之前的服务器返回的错误将包括严重和主要消息,并且有时候还有细节消息,但是没有其他域。

注意错误与只从PGresult对象中有效,对PGconn对象无效。没有PQerrorField函数。

PQclear

Frees the storage associated with a 释放与一个PGresult相关的存储。每一个命令结果不再需要时应该用PQclear释放。

void PQclear(PGresult *res);

你可以按照需要保留PGresult对象,当你发出一个新命令时它也不会消失,甚至关闭连接时也不会消失。 要去掉它,你必须调用PQclear。没有这样做将会导致在应用中的内存泄露。

32.3.2. 检索查询结果信息

这些函数被用来从一个代表成功查询结果(也就是状态为PGRES_TUPLES_OK或者PGRES_SINGLE_TUPLE)的PGresult对象中抽取信息。它们也可以被用来从一个成功的 Describe 操作中抽取信息:一个 Describe 的结果具有和该查询被实际执行所提供的完全相同的列信息,但是它没有行。对于其他状态值的对象,这些函数会认为结果具有零行和零列。

PQntuples

返回查询结果中的行(元组)数(注意,PGresult对象被限制为不超过INT_MAX行,因此一个int结果就足够了)。

int PQntuples(const PGresult *res);

PQnfields

返回查询结果中每一行的列(域)数。

int PQnfields(const PGresult *res);

PQfname

返回与给定列号相关联的列名。列号从 0 开始。调用者不应该直接释放该结果。它将在相关的PGresult句柄被传递给PQclear之后被释放。

char *PQfname(const PGresult *res,
              int column_number);

如果列号超出范围,将返回NULL

PQfnumber

返回与给定列名相关联的列号。

int PQfnumber(const PGresult *res,
              const char *column_name);

如果给定的名字不匹配任何列,将返回 -1。

给定的名称被视作一个 SQL 命令中的一个标识符,也就是说,除非被双引号引用,它是小写形式的。例如,给定一个 SQL 命令:

SELECT 1 AS FOO, 2 AS "BAR";

我们将得到结果:

PQfname(res, 0)              foo
PQfname(res, 1)              BAR
PQfnumber(res, "FOO")        0
PQfnumber(res, "foo")        0
PQfnumber(res, "BAR")        -1
PQfnumber(res, "\"BAR\"")    1

PQftable

返回给定列从中取出的表的 OID。列号从 0 开始。

Oid PQftable(const PGresult *res,
             int column_number);

如果列号超出范围或者指定的列不是对一个表列的简单引用或者在使用 3.0 协议时,返回InvalidOid。你可以查询系统表pg_class来确定究竟是哪个表被引用。

当你包括libpq头文件,类型oid以及常数InvalidOid将被定义。它们将都是某种整数类型。

PQftablecol

返回构成指定查询结果列的列(在其表中)的列号。查询结果列号从 0 开始,但是表列具有非零编号。

int PQftablecol(const PGresult *res,
                int column_number);

如果列号超出范围或者指定的列不是对一个表列的简单引用或者在使用 3.0 协议时,返回零。

PQfformat

返回指示给定列格式的格式编码。列号从 0 开始。

int PQfformat(const PGresult *res,
              int column_number);

格式代码零指示文本数据表示,而格式代码一表示二进制表示(其他代码被保留用于未来的定义)。

PQftype

返回与给定列号相关联的数据类型。被返回的整数是该类型的内部 OID 号。列号从 0 开始。

Oid PQftype(const PGresult *res,
            int column_number);

你可以查询系统表pg_type来得到多个数据类型的名字和属性。内建数据类型的OID被定义在源代码树中的文件src/include/catalog/pg_type_d.h中。

PQfmod

返回与给定列号相关联的列的修饰符类型。列号从 0 开始。

int PQfmod(const PGresult *res,
           int column_number);

修饰符值的解释是与类型相关的,它们通常指示精度或尺寸限制。值 -1 被用来指示没有信息可用。大部分的数据类型不适用修饰符,在那种情况中值总是 -1。

PQfsize

返回与给定列号相关的列的尺寸(以字节计)。列号从 0 开始。

int PQfsize(const PGresult *res,
            int column_number);

PQfsize返回在一个数据库行中为这个列分配的空间,换句话说是服务器对该数据类型的内部表示的尺寸(因此,它对客户端并不是真地非常有用)。一个负值指示该数据类型是变长的。

PQbinaryTuples

如果PGresult包含二进制数据,返回 1。如果包含的是文本数据,返回 0。

int PQbinaryTuples(const PGresult *res);

这个函数已经被废弃(除了与COPY一起使用),因为一个单一PGresult可以在某些列中包含文本数据而且在另一些列中包含二进制数据。 PQfformat要更好。只有结果的所有列是二进制(格式 1)时PQbinaryTuples才返回 1。

PQgetvalue

返回一个PGresult的一行的单一域值。行和列号从 0 开始。调用者不应该直接释放该结果。 它将在相关的PGresult句柄被传递给PQclear之后被释放。

char *PQgetvalue(const PGresult *res,
                 int row_number,
                 int column_number);

对于文本格式的数据,PQgetvalue返回的值是该域值的一种空值结束的字符串表示。对于二进制格式的数据,该值是由该数据类型的typsendtypreceive函数决定的二进制表示(在这种情况下该值实际上也跟随着一个零字节,但是这通常没有用处,因为该值很可能包含嵌入的空)。

如果该域值为空,则返回一个空串。关于区分空值和空字符串值请见PQgetisnull

PQgetvalue返回的指针指向作为PGresult结构一部分的存储。我们不应该修改它指向的数据,并且如果要在超过PGresult结构本身的生命期之外使用它,我们必须显式地把该数据拷贝到其他存储中。

PQgetisnull

测试一个域是否为空值。行号和列号从 0 开始。

int PQgetisnull(const PGresult *res,
                int row_number,
                int column_number);

如果该域是空,这个函数返回 1。如果它包含一个非空值,则返回 0(注意PQgetvalue将为一个空域返回一个空串,不是一个空指针)。

PQgetlength

返回一个域值的真实长度,以字节计。行号和列号从 0 开始。

int PQgetlength(const PGresult *res,
                int row_number,
                int column_number);

这是特定数据值的真实数据长度,也就是PQgetvalue指向的对象的尺寸。 对于文本数据格式,这和strlen()相同。对于二进制格式这是基本信息。 注意我们应该依赖于PQfsize来得到真值的数据长度。

PQnparams

返回一个预备语句的参数数量。

int PQnparams(const PGresult *res);

只有在查看PQdescribePrepared的结果时,这个函数才有用。对于其他类型的查询,它将返回零。

PQparamtype

返回所指示的语句参数的数据类型。参数号从 0 开始。

Oid PQparamtype(const PGresult *res, int param_number);

只有在查看PQdescribePrepared的结果时,这个函数才有用。对于其他类型的查询,它将返回零。

PQprint

将所有的行打印到指定的输出流,以及有选择地将列名打印到指定的输出流。

void PQprint(FILE *fout,      /* 输出流 */
             const PGresult *res,
             const PQprintOpt *po);
typedef struct
{
    pqbool  header;      /* 打印输出域标题和行计数 */
    pqbool  align;       /* 填充对齐域 */
    pqbool  standard;    /* 旧的格式 */
    pqbool  html3;       /* 输出 HTML 表格 */
    pqbool  expanded;    /* 扩展表格 */
    pqbool  pager;       /* 如果必要为输出使用页 */
    char    *fieldSep;   /* 域分隔符 */
    char    *tableOpt;   /* 用于 HTML 表格元素的属性 */
    char    *caption;    /* HTML 表格标题 */
    char    **fieldName; /* 替换域名称的空终止数组 */
} PQprintOpt;

这个函数以前被ltsql用来打印查询结果,但是现在不是这样了。注意它假定所有的数据都是文本格式。

32.3.3. 检索其他结果信息

这些函数被用来从PGresult对象中抽取其他信息。

PQcmdStatus

返回来自于产生PGresult的 SQL 命令的命令状态标签。

char *PQcmdStatus(PGresult *res);

通常这就是该命令的名称,但是它可能包括额外数据,例如已被处理的行数。调用者不应该直接释放该结果。它将在相关的PGresult句柄被传递给PQclear之后被释放。

PQcmdTuples

返回受该 SQL 命令影响的行数。

char *PQcmdTuples(PGresult *res);

这个函数返回一个字符串,其中包含着产生PGresultSQL语句影响的行数。 这个只能被用于下列情况:执行一个SELECTCREATE TABLE ASINSERTUPDATEDELETEMOVEFETCHCOPY语句,或者一个包含INSERTUPDATEDELETE语句的预备查询的EXECUTE。 如果产生PGresult的命令是其他什么东西,PQcmdTuples会返回一个空串。 调用者不应该直接释放该结果。它将在相关的PGresult句柄被传递给PQclear之后被释放。

PQoidValue

如果该SQL命令是一个正好将一行插入到具有 OID 的表的INSERT,或者是一个包含合适INSERT语句的预备查询的EXECUTE,这个函数返回被插入行的 OID。否则,这个函数返回InvalidOid。如果被INSERT语句影响的表不包含 OID,这个函数也将返回InvalidOid

Oid PQoidValue(const PGresult *res);

PQoidStatus

这个函数已经被PQoidValue取代,并且不是线程安全的。它返回包含被插入行的 OID 的一个字符串,而PQoidValue返回 OID 值。

char *PQoidStatus(const PGresult *res);

32.3.4. 用于包含在 SQL 命令中的转移串

PQescapeLiteral

char *PQescapeLiteral(PGconn *conn, const char *str, size_t length);

为了让一个串能用在 SQL 命令中,PQescapeLiteral可对它进行转义。 当在 SQL 命令中插入一个数据值作为文字常量时,这个函数很有用。一些字符(例如引号和反斜线)必须被转义以防止它们被 SQL 解析器解释成特殊的意思。 PQescapeLiteral执行这种操作。

PQescapeLiteral返回一个str参数的已被转义版本,该版本被放在用malloc()分配的内存中。 当该结果不再被需要时,这个内存应该用PQfreemem()释放。 一个终止的零字节不是必须的,并且不应该被计入length(如果在length字节被处理之前找到一个终止字节,PQescapeLiteral会停止在零,该行为更像strncpy)。 返回串中的所有特殊字符都被替换掉,这样它们能被LightDB字符串解析器正确地处理。 还会加上一个终止零字节。包括在结果串中的LightDB字符串必须用单引号包围。

发生错误时,PQescapeLiteral返回NULL并且一个合适的消息会被存储在conn对象中。

Tip

在处理从一个非可信源接收到的串时,做正确的转义特别重要。否则就会有安全性风险:你容易受到SQL 注入攻击,其中可能会有预期之外的 SQL 语句会被喂给你的数据库。

注意,当一个数据值被作为PQexecParams或其兄弟例程中的一个独立参数传递时,没有必要做转义而且做转义也不正确。

PQescapeIdentifier

char *PQescapeIdentifier(PGconn *conn, const char *str, size_t length);

PQescapeIdentifier转义一个要用作 SQL 标识符的字符串,例如表名、列名或函数名。当一个用户提供的标识符可能包含被 SQL 解析器解释为标识符一部分的特殊字符时,或者当该标识符可能包含大小写形式应该被保留的大写字符时,这个函数很有用。

PQescapeIdentifier返回一个str参数的已被转义为 SQL 标识符的版本,该版本被放在用malloc()分配的内存中。 当该结果不再被需要时,这个内存应该用PQfreemem()释放。 一个终止的零字节不是必须的,并且不应该被计入length(如果在length字节被处理之前找到一个终止字节,PQescapeIdentifier会停止在零,该行为更像strncpy)。 返回串中的所有特殊字符都被替换掉,这样它们能被作为一个 SQL 标识符正确地处理。还会加上一个终止零字节。返回串也将被双引号包围。

发生错误时,PQescapeIdentifier返回NULL并且一个合适的消息会被存储在conn对象中。

Tip

与字符串一样,要阻止 SQL 注入攻击,当从一个不可信的来源接收到 SQL 标识符时,它们必须被转义。

PQescapeStringConn

size_t PQescapeStringConn(PGconn *conn,
                          char *to, const char *from, size_t length,
                          int *error);

PQescapeStringConn转义字符串,它很像PQescapeLiteral。 与PQescapeLiteral不一样的是,调用者负责提供一个合适尺寸的缓冲区。 此外,PQescapeStringConn不产生必须包围LightDB字符串的单引号。 它们应该在结果要插入的 SQL 命令中提供。参数from指向要被转义的串的第一个字符,并且length参数给出了这个串中的字节数。 一个终止的零字节不是必须的,并且不应该被计入length(如果在length字节被处理之前找到一个终止字节,PQescapeStringConn会停止在零,该行为更像strncpy)。 to应当指向一个缓冲区,它能够保持至少比length值的两倍还要多至少一个字节,否则该行为是未被定义的。 如果tofrom串重叠,行为也是未被定义的。

如果error参数不是NULL,那么成功时*error被设置为零,错误时设置为非零。当前唯一可能的错误情况涉及源串中非法的多字节编码。错误时仍然会产生输出串,但是可以预期服务器将认为它是畸形的并且拒绝它。在发生错误时,一个合适的消息被存储在conn对象中,不管error是不是NULL

PQescapeStringConn返回写到to的字节数,不包括终止的零字节。

PQescapeString

PQescapeString是一个更老的被废弃的PQescapeStringConn版本。

size_t PQescapeString (char *to, const char *from, size_t length);

PQescapeStringConnPQescapeString之间的唯一区别是不需要PGconnerror参数。 正因为如此,它不能基于连接属性(例如字符编码)调整它的行为并且因此它可能给出错误的结果。还有,它没有方法报告错误情况。

PQescapeString可以在一次只使用一个LightDB连接的客户端程序中安全地使用(在这种情况下它可以在现象后面找出它需要知道的东西)。 在其他环境中它是一个安全性灾难并且应该用PQescapeStringConn来避免。

PQescapeByteaConn

把要用于一个 SQL 命令的二进制数据用类型bytea转义。和PQescapeStringConn一样,只有在将数据直接插入到一个 SQL 命令串时才使用它。

unsigned char *PQescapeByteaConn(PGconn *conn,
                                 const unsigned char *from,
                                 size_t from_length,
                                 size_t *to_length);

当某些字节值被用作一个SQL语句中的bytea文字的一部分时,它们必须被转义。 PQescapeByteaConn转义使用十六进制编码或反斜线转义的字节。详见Section 9.4

from参数指向要被转义的串的第一个字节,并且from_length参数给出这个二进制串中的字节数(一个终止的零字节是不需要的也是不被计算的)。to_length参数指向一个将保持生成的已转义串长度的变量。这个结果串长度包括结果的终止零字节。

PQescapeByteaConn返回一个from参数的已被转义为二进制串的版本,该版本被放在用malloc()分配的内存中。 当该结果不再被需要时,这个内存应该用PQfreemem()释放。 返回串中的所有特殊字符都被替换掉,这样它们能被LightDB的字符串解析器以及bytea输入函数正确地处理。 还会加上一个终止零字节。不是结果串一部分的LightDB字符串必须被单引号包围。

在发生错误时,将返回一个空指针,并且一个合适的错误消息被存储在conn对象中。当前,唯一可能的错误是没有足够的内存用于结果串。

PQescapeBytea

PQescapeBytea是一个更老的被废弃的PQescapeByteaConn版本。

unsigned char *PQescapeBytea(const unsigned char *from,
                             size_t from_length,
                             size_t *to_length);

PQescapeByteaConn的唯一区别是PQescapeBytea不用一个PGconn参数。 正因为这样,PQescapeBytea只能在一次只使用一个LightDB连接的客户端程序中安全地使用(在这种情况下它可以在现象后面找出它需要知道的东西)。 如果在有多个数据库连接的程序中使用,它可能给出错误的结果(在那种情况下使用PQescapeByteaConn)。

PQunescapeBytea

将二进制数据的一个字符串表示转换成二进制数据 — 它是PQescapeBytea的逆向函数。当检索文本格式的bytea数据时,需要这个函数,但检索二进制个事时则不需要它。

unsigned char *PQunescapeBytea(const unsigned char *from, size_t *to_length);

from参数指向一个字符串,例如PQgetvalue被应用到一个bytea列上所返回的。 PQunescapeBytea把这个串表示转换成它的二进制表示。 它返回一个指向用malloc()分配的缓冲区的指针,在错误时返回NULL,并且把缓冲区的尺寸放在to_length中。 当结果不再需要时,它必须使用PQfreemem释放。

这种转换并不完全是PQescapeBytea的逆函数,因为当从PQgetvalue接收到字符串时,我们并不能期待它被转义。特别地这意味着不需要考虑字符串引用,并且因此也不需要一个参数。