COPY
命令相关的函数 #PostgreSQL 中的 COPY
命令具有从 libpq 使用的网络连接读取或写入数据的选项。本节介绍的函数允许应用程序通过提供或消耗复制的数据来利用此功能。
整个过程是,应用程序首先通过 PQexec
或其中一个等效函数发出 SQL COPY
命令。对此的响应(如果命令没有错误)将是一个 PGresult
对象,其状态码为 PGRES_COPY_OUT
或 PGRES_COPY_IN
(取决于指定的复制方向)。然后,应用程序应使用本节中的函数来接收或传输数据行。数据传输完成后,将返回另一个 PGresult
对象来指示传输的成功或失败。其状态将为 PGRES_COMMAND_OK
表示成功,或 PGRES_FATAL_ERROR
表示遇到问题。此时可以通过 PQexec
发出更多 SQL 命令。(在 COPY
操作进行期间,无法使用同一连接执行其他 SQL 命令。)
如果在可能包含其他命令的字符串中通过 PQexec
发出 COPY
命令,则在完成 COPY
序列后,应用程序必须继续通过 PQgetResult
获取结果。只有当 PQgetResult
返回 NULL
时,才能确定 PQexec
命令字符串已完成,并且可以安全地发出更多命令。
本节中的函数应仅在从 PQexec
或 PQgetResult
获得 PGRES_COPY_OUT
或 PGRES_COPY_IN
的结果状态后执行。
带有这些状态值之一的 PGresult
对象会携带有关即将开始的 COPY
操作的一些额外数据。这些额外数据可以使用与查询结果相关的函数来访问。
COPY
数据的函数 #这些函数用于在 COPY FROM STDIN
期间发送数据。如果在连接不在 COPY_IN
状态时调用它们,它们将失败。
PQputCopyData
#在 COPY_IN
状态期间将数据发送到服务器。
int PQputCopyData(PGconn *conn, const char *buffer, int nbytes);
将指定 buffer
中的 COPY
数据(长度为 nbytes
)传输到服务器。结果是 1 表示数据已排队,0 表示由于缓冲区已满未排队(这仅发生在非阻塞模式下),或 -1 表示发生错误。(如果返回值是 -1,请使用 PQerrorMessage
检索详细信息。如果值为零,则等待数据可写并重试。)
应用程序可以将 COPY
数据流分成任意方便大小的缓冲区加载。发送时,缓冲区加载边界没有语义意义。数据流的内容必须与 COPY
命令期望的数据格式匹配;有关详细信息,请参阅 COPY。
PQputCopyEnd
#在 COPY_IN
状态期间将数据结束指示发送到服务器。
int PQputCopyEnd(PGconn *conn, const char *errormsg);
如果 errormsg
是 NULL
,则成功结束 COPY_IN
操作。如果 errormsg
不是 NULL
,则强制 COPY
失败,并将 errormsg
指向的字符串用作错误消息。(但是,不应假设服务器会返回此精确的错误消息,因为服务器可能已因自身原因导致 COPY
失败。)
结果是 1 表示终止消息已发送;或在非阻塞模式下,这可能仅表示终止消息已成功排队。(在非阻塞模式下,要确保数据已发送,您应该接下来等待数据可写并调用 PQflush
,重复调用直到其返回零。)零表示由于缓冲区已满,该函数无法排队终止消息;这仅发生在非阻塞模式下。(在这种情况下,等待数据可写并再次尝试 PQputCopyEnd
调用。)如果发生硬错误,则返回 -1;您可以使用 PQerrorMessage
检索详细信息。
成功调用 PQputCopyEnd
后,调用 PQgetResult
以获取 COPY
命令的最终结果状态。可以按常规方式等待此结果可用。然后返回到正常操作。
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
有用。返回 0 表示 COPY
仍在进行中,但尚未准备好行(仅当 async
为 true 时才可能)。返回 -1 表示 COPY
已完成。返回 -2 表示发生错误(请参阅 PQerrorMessage
获取原因)。
当 async
为 true(非零)时,PQgetCopyData
不会阻塞等待输入;如果 COPY
仍在进行中但尚未准备好完整行,它将返回零。(在这种情况下,等待数据可读,然后调用 PQconsumeInput
,然后再调用 PQgetCopyData
。)当 async
为 false(零)时,PQgetCopyData
将阻塞直到有数据可用或操作完成。
在 PQgetCopyData
返回 -1 后,调用 PQgetResult
以获取 COPY
命令的最终结果状态。可以按常规方式等待此结果可用。然后返回到正常操作。
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
响应后,应用程序应调用 PQconsumeInput
和 PQgetlineAsync
,直到检测到数据结束信号。
与 PQgetline
不同,此函数负责检测数据结束。
每次调用时,如果 libpq 的输入缓冲区中有完整的数据行可用,PQgetlineAsync
就会返回数据。否则,直到行的其余部分到达才会返回数据。如果识别到复制数据结束标记,则函数返回 -1;如果没有数据可用,则返回 0;否则返回一个正数,表示返回的数据字节数。如果返回 -1,调用者随后必须调用 PQendcopy
,然后返回到正常处理。
返回的数据不会超出数据行的边界。如果可能,将一次返回一整行。但是,如果调用者提供的缓冲区太小而无法容纳服务器发送的一行,则将返回部分数据行。对于文本数据,可以通过测试最后一个返回的字节是否为 \n
来检测。(在二进制 COPY
中,需要实际解析 COPY
数据格式才能做出等效的判断。)返回的字符串不是 null 结尾的。(如果要添加终止 null,请确保将 bufsize
设置为比实际可用空间小一。)
PQputline
#将一个 null 结尾的字符串发送到服务器。如果成功则返回 0,如果无法发送字符串则返回 EOF
。
int PQputline(PGconn *conn, const char *string);
通过一系列 PQputline
调用发送的 COPY
数据流的格式与 PQgetlineAsync
返回的格式相同,不同之处在于应用程序不必每调用一次 PQputline
就发送正好一个数据行;每次调用发送部分行或多行是允许的。
在 PostgreSQL 协议 3.0 之前,应用程序必须显式发送两个字符 \.
作为最后一行,以向服务器指示其已完成发送 COPY
数据。虽然这仍然有效,但已弃用,并且 \.
的特殊含义预计将在未来版本中被移除。(它在 CSV
模式下可能已出现问题。)在发送实际数据后调用 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
时,应用程序应响应 PGRES_COPY_OUT
结果,通过反复执行 PQgetline
,然后在看到终止符行后执行 PQendcopy
。然后应返回到 PQgetResult
循环,直到 PQgetResult
返回 null 指针。类似地,PGRES_COPY_IN
结果通过一系列 PQputline
调用,然后执行 PQendcopy
来处理,然后返回到 PQgetResult
循环。这种安排将确保一系列命令中嵌入的 COPY
命令SQL能够正确执行。
旧的应用程序很可能会通过 PQexec
提交 COPY
,并在 PQendcopy
之后假设事务已完成。只有当 COPY
是命令字符串中的唯一SQL命令时,这才会正常工作。
如果您在文档中发现任何不正确、与您对特定功能的使用经验不符或需要进一步说明的内容,请使用 此表格 报告文档问题。