支持的版本:当前17)/ 16 / 15 / 14 / 13
开发版本:devel
不支持的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

32.10. 与 COPY 命令关联的函数 #

PostgreSQL 中的 COPY 命令具有从 libpq 使用的网络连接读取或写入的选项。本节中描述的函数允许应用程序通过提供或使用复制的数据来利用此功能。

整个过程是应用程序首先通过 PQexec 或等效函数之一发出 SQL COPY 命令。对此的响应(如果命令中没有错误)将是一个 PGresult 对象,其状态代码为 PGRES_COPY_OUTPGRES_COPY_IN(取决于指定的复制方向)。然后,应用程序应使用本节中的函数来接收或传输数据行。当数据传输完成时,将返回另一个 PGresult 对象以指示传输的成功或失败。其状态对于成功将为 PGRES_COMMAND_OK,如果遇到某些问题,则为 PGRES_FATAL_ERROR。此时,可以通过 PQexec 发出进一步的 SQL 命令。(在 COPY 操作正在进行时,无法使用同一连接执行其他 SQL 命令。)

如果通过 PQexec 在可能包含其他命令的字符串中发出 COPY 命令,则应用程序必须在完成 COPY 序列后继续通过 PQgetResult 获取结果。只有当 PQgetResult 返回 NULL 时,才能确定 PQexec 命令字符串已完成,并且可以安全地发出更多命令。

只有从 PQexecPQgetResult 获得 PGRES_COPY_OUTPGRES_COPY_IN 的结果状态后,才应执行本节中的函数。

带有这些状态值之一的 PGresult 对象携带有关正在启动的 COPY 操作的一些其他数据。可以使用也用于查询结果的函数来访问此附加数据

PQnfields #

返回要复制的列(字段)数。

PQbinaryTuples #

0 表示整体复制格式是文本格式(行由换行符分隔,列由分隔符分隔,等等)。1 表示整体复制格式是二进制格式。有关更多信息,请参见 COPY

PQfformat #

返回与复制操作的每一列关联的格式代码(文本为 0,二进制为 1)。当整体复制格式为文本时,每列的格式代码将始终为零,但二进制格式可以同时支持文本列和二进制列。(但是,根据当前 COPY 的实现,二进制复制中仅出现二进制列;因此,目前每列格式始终与整体格式匹配。)

32.10.1. 用于发送 COPY 数据的函数 #

这些函数用于在 COPY FROM STDIN 期间发送数据。如果在连接未处于 COPY_IN 状态时调用它们,则它们将失败。

PQputCopyData #

COPY_IN 状态期间将数据发送到服务器。

int PQputCopyData(PGconn *conn,
                  const char *buffer,
                  int nbytes);

将指定 buffer 中长度为 nbytesCOPY 数据传输到服务器。如果数据已排队,则结果为 1;如果由于缓冲区已满而未排队(这仅在非阻塞模式下发生),则结果为零;如果发生错误,则结果为 -1。(如果返回值为 -1,请使用 PQerrorMessage 来检索详细信息。如果值为零,请等待写就绪并重试。)

应用程序可以将 COPY 数据流划分为任何方便大小的缓冲区负载。在发送时,缓冲区负载边界没有任何语义意义。数据流的内容必须与 COPY 命令期望的数据格式匹配;有关详细信息,请参见 COPY

PQputCopyEnd #

COPY_IN 状态期间向服务器发送数据结束指示。

int PQputCopyEnd(PGconn *conn,
                 const char *errormsg);

如果 errormsgNULL,则成功结束 COPY_IN 操作。如果 errormsg 不为 NULL,则强制 COPY 失败,并且将 errormsg 指向的字符串用作错误消息。(但是,不应假设此确切的错误消息会从服务器返回,因为服务器可能已经出于自身原因而使 COPY 失败。)

如果发送了终止消息,则结果为 1;或者在非阻塞模式下,这可能仅指示终止消息已成功排队。(在非阻塞模式下,要确定数据已发送,您应该接下来等待写就绪并调用 PQflush,重复直到它返回零。)零表示该函数由于缓冲区已满而无法使终止消息排队;这仅在非阻塞模式下发生。(在这种情况下,请等待写就绪并再次尝试 PQputCopyEnd 调用。)如果发生严重错误,则返回 -1;您可以使用 PQerrorMessage 来检索详细信息。

成功调用 PQputCopyEnd 后,调用 PQgetResult 以获取 COPY 命令的最终结果状态。可以使用通常的方式等待此结果可用。然后返回正常操作。

32.10.2. 用于接收 COPY 数据的函数 #

这些函数用于在 COPY TO STDOUT 期间接收数据。如果在连接未处于 COPY_OUT 状态时调用它们,则它们将失败。

PQgetCopyData #

COPY_OUT 状态期间从服务器接收数据。

int PQgetCopyData(PGconn *conn,
                  char **buffer,
                  int async);

尝试在 COPY 期间从服务器获取另一行数据。始终一次返回一行数据;如果只有部分行可用,则不会返回。成功返回数据行涉及分配一块内存来保存数据。buffer 参数必须为非 NULL*buffer 设置为指向已分配的内存,或者在不返回缓冲区的情况下设置为 NULL。不再需要时,应使用 PQfreemem 释放非 NULL 结果缓冲区。

当成功返回一行数据时,返回值是该行数据的字节数(总是大于零)。返回的字符串总是以 null 结尾,尽管这可能只对文本 COPY 有用。返回零表示 COPY 仍在进行中,但尚无可用行(仅当 async 为 true 时才可能发生)。返回 -1 表示 COPY 已完成。返回 -2 表示发生错误(请查阅 PQerrorMessage 以了解原因)。

async 为 true(非零)时,PQgetCopyData 不会阻塞等待输入;如果 COPY 仍在进行中但没有完整的行可用,它将返回零。(在这种情况下,请等待读取就绪,然后在再次调用 PQgetCopyData 之前调用 PQconsumeInput。)当 async 为 false(零)时,PQgetCopyData 将阻塞,直到有数据可用或操作完成。

PQgetCopyData 返回 -1 后,调用 PQgetResult 以获取 COPY 命令的最终结果状态。可以以通常的方式等待此结果可用。然后返回正常操作。

32.10.3. COPY 的过时函数 #

这些函数代表了处理 COPY 的较旧方法。尽管它们仍然有效,但由于错误处理不佳、检测数据结束的方法不方便以及缺乏对二进制或非阻塞传输的支持而被弃用。

PQgetline #

将服务器发送的以换行符结尾的一行字符读取到大小为 length 的缓冲区字符串中。

int PQgetline(PGconn *conn,
              char *buffer,
              int length);

此函数将最多 length-1 个字符复制到缓冲区中,并将结尾的换行符转换为零字节。PQgetline 在输入结束时返回 EOF,如果已读取整行则返回 0,如果缓冲区已满但尚未读取结尾的换行符则返回 1。

请注意,应用程序必须检查新行是否由两个字符 \. 组成,这表示服务器已完成发送 COPY 命令的结果。如果应用程序可能会接收到超过 length-1 个字符长的行,则需要小心确保它能正确识别 \. 行(并且不会例如将长数据行的结尾误认为终止行)。

PQgetlineAsync #

将一行 COPY 数据(由服务器发送)读取到缓冲区中,而不会阻塞。

int PQgetlineAsync(PGconn *conn,
                   char *buffer,
                   int bufsize);

此函数类似于 PQgetline,但它可以被必须异步读取 COPY 数据的应用程序使用,即不阻塞。在发出 COPY 命令并获得 PGRES_COPY_OUT 响应后,应用程序应调用 PQconsumeInputPQgetlineAsync,直到检测到数据结束信号。

PQgetline 不同,此函数负责检测数据结束。

在每次调用时,如果 libpq 的输入缓冲区中有一个完整的数据行可用,PQgetlineAsync 将返回数据。否则,直到行的其余部分到达才会返回数据。如果已识别出复制数据结束标记,则该函数返回 -1;如果没有数据可用,则返回 0;或返回一个正数,表示返回的数据字节数。如果返回 -1,则调用者必须接下来调用 PQendcopy,然后返回正常处理。

返回的数据不会超出数据行边界。如果可能,将一次返回整行。但是,如果调用者提供的缓冲区太小而无法容纳服务器发送的行,则将返回部分数据行。对于文本数据,可以通过测试最后返回的字节是否为 \n 来检测到这一点。(在二进制 COPY 中,需要实际解析 COPY 数据格式才能做出等效的判断。)返回的字符串不是以 null 结尾的。(如果要添加结尾 null,请确保传递的 bufsize 比实际可用的空间小 1。)

PQputline #

将以 null 结尾的字符串发送到服务器。如果正常则返回 0,如果无法发送字符串则返回 EOF

int PQputline(PGconn *conn,
              const char *string);

通过一系列调用 PQputline 发送的 COPY 数据流的格式与 PQgetlineAsync 返回的格式相同,但应用程序不必每次调用 PQputline 都发送完全一个数据行;每次调用发送部分行或多行都可以。

注意

PostgreSQL 协议 3.0 之前,应用程序必须显式发送两个字符 \. 作为最后一行,以向服务器指示它已完成发送 COPY 数据。虽然这仍然有效,但它已被弃用,并且可以预期在未来的版本中删除 \. 的特殊含义。在发送实际数据后调用 PQendcopy 就足够了。

PQputnbytes #

将非 null 结尾的字符串发送到服务器。如果正常则返回 0,如果无法发送字符串则返回 EOF

int PQputnbytes(PGconn *conn,
                const char *buffer,
                int nbytes);

这与 PQputline 完全相同,只是数据缓冲区不必以 null 结尾,因为要发送的字节数是直接指定的。在发送二进制数据时使用此过程。

PQendcopy #

与服务器同步。

int PQendcopy(PGconn *conn);

此函数等待服务器完成复制。它应该在通过 PQputline 将最后一个字符串发送到服务器时,或在使用 PQgetline 从服务器接收到最后一个字符串时发出。必须发出此命令,否则服务器将与客户端“失去同步”。从此函数返回后,服务器已准备好接收下一个 SQL 命令。成功完成时返回值 0,否则返回值非零。(如果返回值为非零,请使用 PQerrorMessage 来检索详细信息。)

当使用 PQgetResult 时,应用程序应通过重复执行 PQgetline 来响应 PGRES_COPY_OUT 结果,然后在看到终止行后执行 PQendcopy。然后,它应该返回到 PQgetResult 循环,直到 PQgetResult 返回空指针。类似地,通过一系列 PQputline 调用处理 PGRES_COPY_IN 结果,然后是 PQendcopy,然后返回到 PQgetResult 循环。此安排将确保正确执行嵌入在一系列SQL命令中的 COPY 命令。

较旧的应用程序可能会通过 PQexec 提交 COPY,并假设在 PQendcopy 之后事务已完成。只有当 COPY 是命令字符串中的唯一SQL命令时,此操作才能正确运行。

提交更正

如果您在文档中发现任何不正确、与您使用特定功能的体验不符或需要进一步澄清的内容,请使用 此表格 报告文档问题。