跳至主要內容

KlustronDB大约 30 分钟

34.3. 命令执行函数

34.3.1. 主要函数

34.3.2. 检索查询结果信息

34.3.3. 检索其他结果信息

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

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

34.3.1. 主要函数

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

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

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

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

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

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

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

该函数的参数是:

**`conn`**
:   要在其中发送命令的连接对象。

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

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

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

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

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

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

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

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

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

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

提示

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```synopsis
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 : 返回该命令的结果状态。

```synopsis
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`包含来自于当前命令的一个单一结果元组。这个状态只在查询选择了单一行模式时发生(见[第 34.5 节](libpq-single-row-mode.md "34.5. 一行一行地检索查询结果"))。

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

一个状态为`PGRES_NONFATAL_ERROR`的结果将不会被`PQexec`或者其他查询执行函数直接返回,这类结果将被传递给提示处理器(见 [第 34.12 节](libpq-notice-processing.md "34.12. 通知处理"))。

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

```synopsis
char *PQresStatus(ExecStatusType status);
```

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

```synopsis
char *PQresultErrorMessage(const PGresult *res);
```

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

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

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

```synopsis
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 : 返回一个错误报告的一个域。

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

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

下列域代码可用:

`PG_DIAG_SEVERITY`
:   严重性。域的内容是`ERROR`、`FATAL`或`PANIC`(在一个错误消息中)。或者是`WARNING`、`NOTICE`、`DEBUG`、`INFO`或`LOG`(在一个提示消息中)。或者是其中之一的一个本地化翻译。总是存在。

`PG_DIAG_SEVERITY_NONLOCALIZED`
:   域的内容是`ERROR`、`FATAL`或`PANIC`(在一个错误消息中)。或者是`WARNING`、`NOTICE`、`DEBUG`、`INFO`或`LOG`(在一个提示消息中)。这和`PG_DIAG_SEVERITY`域相同,不过内容不会被本地化。只存在于PostgreSQL 9.6 版本以后产生的报告中。

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

`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`
:   报告错误的源代码函数的名字。

### 注意

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

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

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

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

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

```synopsis
void PQclear(PGresult *res);
```

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

34.3.2. 检索查询结果信息

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

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

```synopsis
int PQntuples(const PGresult *res);
```

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

```synopsis
int PQnfields(const PGresult *res);
```

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

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

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

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

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

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

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

```programlisting
SELECT 1 AS FOO, 2 AS "BAR";
```

我们将得到结果:

```programlisting
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 开始。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```synopsis
int PQbinaryTuples(const PGresult *res);
```

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

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

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

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

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

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

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

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

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

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

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

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

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

```synopsis
int PQnparams(const PGresult *res);
```

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

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

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

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

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

```synopsis
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;
```

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

34.3.3. 检索其他结果信息

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

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

```synopsis
char *PQcmdStatus(PGresult *res);
```

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

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

```synopsis
char *PQcmdTuples(PGresult *res);
```

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

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

```synopsis
Oid PQoidValue(const PGresult *res);
```

PQoidStatus : 由于PQoidValue和不是线程安全的,这个函数已经被废弃。它返回包含被插入行的 OID 的一个字符串,而PQoidValue返回 OID 值。

```synopsis
char *PQoidStatus(const PGresult *res);
```

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

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

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

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

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

### 提示

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

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

PQescapeIdentifier : synopsis 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`**对象中。

### 提示

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

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

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

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

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

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

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

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

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

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

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

当某些字节值被用作一个SQL语句中的`bytea`文字的一部分时,它们必须被转义。`PQescapeByteaConn`转义使用十六进制编码或反斜线转义的字节。详见[第 8.4 节](datatype-binary.md "8.4. 二进制数据类型")。

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

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

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

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

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

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

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

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

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

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