2024 年 9 月 26 日: PostgreSQL 17 发布!
支持的版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不支持的版本: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;如果由于缓冲区已满而未排队(这仅在非阻塞模式下才会发生),则结果为 0;如果发生错误,则结果为 -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 为真时才有可能)。结果为 -1 表示 COPY 已完成。结果为 -2 表示发生了错误(请参阅 PQerrorMessage 获取原因)。

async 为真(非零)时,PQgetCopyData 不会阻塞等待输入;如果 COPY 仍在进行中但没有完整的行可用,它将返回零。(在这种情况下,请等待读就绪,然后调用 PQconsumeInput,然后再再次调用 PQgetCopyData。)当 async 为假(零)时,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 不同,此函数负责检测数据结尾。

在每次调用中,PQgetlineAsync 将在 libpq 的输入缓冲区中存在完整的DataRow 时返回数据。否则,在DataRow 的其余部分到达之前不会返回任何数据。如果识别出数据结尾标记,则该函数返回 -1;如果无数据可用,则返回 0;如果返回正数,则表示返回的数据字节数。如果返回 -1,则调用者必须接下来调用 PQendcopy,然后恢复正常处理。

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

PQputline #

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

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

通过一系列对 PQputline 的调用发送的 COPY 数据流与 PQgetlineAsync 返回的格式相同,只是应用程序不必在每次 PQputline 调用中发送正好一个DataRow;可以每次调用发送部分行或多行。

注意

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 调用,后跟 PQendcopy 处理 PGRES_COPY_IN 结果,然后返回到 PQgetResult 循环。这种安排将确保嵌入在 SQL 命令系列中的 COPY 命令被正确执行。SQL命令将被正确执行。

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

提交更正

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