COPY
命令相关的函数 #PostgreSQL 中的 COPY
命令具有从 libpq 使用的网络连接中读取或写入数据的选项。本节描述的功能允许应用程序通过提供或使用已复制的数据来利用此功能。
整个过程是应用程序首先通过 PQexec
或等效函数之一发布 SQL COPY
命令。对此的响应(如果命令中没有错误)将是状态代码为 PGRES_COPY_OUT
或 PGRES_COPY_IN
(取决于指定的复制方向)的 PGresult
对象。然后应用程序应该使用本节中的函数来接收或传输数据行。当数据传输完成时,将返回另一个 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;如果由于缓冲区已满而没有对其排队(这仅在非阻塞模式下发生),则结果为零;如果发生错误,则结果为 -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
。当不再需要非 NULL
结果缓冲区时,应该使用 PQfreemem
释放它。
当一行成功返回时,返回值为行中的数据字节数(这将始终大于零)。返回的字符串始终以 null 结尾,尽管这可能仅对文本 COPY
有用。如果值为零,则表示 COPY
仍处于进行中状态,但尚未有可用的行(只有在 async
为 true 时才可能出现这种情况)。如果值为 -1,则表示 COPY
完成。如果值为 -2,则表示出错(请参阅 PQerrorMessage
了解原因)。
当 async
为 true(不为零)时,PQgetCopyData
不会阻塞等待输入,如果 COPY
仍处于进行中但没有完整可用的行,则会返回 0。(在这种情况下,请等待读取就绪,然后调用 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
不同,此函数负责检测数据结束。
每次调用时,PQgetlineAsync
如果在 libpq 的输入缓冲区中有完整的数据行可用,它将返回数据。否则,在该行的其余部分到达之前,不会返回数据。此函数如果已识别出复制数据结束标记,则返回 -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
并重复执行,然后在看到终止符行后执行 PQendcopy
,对 PGRES_COPY_OUT
结果做出响应。然后,它应该返回到 PQgetResult
循环,直到 PQgetResult
返回空指针。同样,通过一系列 PQputline
调用以及后跟 PQendcopy
处理 PGRES_COPY_IN
结果,然后返回到 PQgetResult
循环。该设置能确保正确执行嵌入在系列SQL命令中的 COPY
命令。
较旧的应用程序可能会通过 PQexec
提交 COPY
,并认为在 PQendcopy
之后完成事务。只有在 COPY
是命令字符串中SQL唯一命令时,此功能才能正常工作。