## 34.10. Functions Associated with the`COPY`Command [34.10.1. Functions for Sending`COPY`Data](libpq-copy.html#LIBPQ-COPY-SEND) [34.10.2. Functions for Receiving`COPY`Data](libpq-copy.html#LIBPQ-COPY-RECEIVE) [34.10.3. Obsolete Functions for`COPY`](libpq-copy.html#LIBPQ-COPY-DEPRECATED) [](<>) The`COPY`command in PostgreSQL has options to read from or write to the network connection used by libpq. The functions described in this section allow applications to take advantage of this capability by supplying or consuming copied data. The overall process is that the application first issues the SQL`COPY`command via[`PQexec`](libpq-exec.html#LIBPQ-PQEXEC)or one of the equivalent functions. The response to this (if there is no error in the command) will be a`PGresult`object bearing a status code of`PGRES_COPY_OUT`or`PGRES_COPY_IN`(depending on the specified copy direction). The application should then use the functions of this section to receive or transmit data rows. When the data transfer is complete, another`PGresult`object is returned to indicate success or failure of the transfer. Its status will be`PGRES_COMMAND_OK`for success or`PGRES_FATAL_ERROR`如果遇到一些问题。此时可以通过以下方式发出进一步的 SQL 命令[`执行程序`](libpq-exec.html#LIBPQ-PQEXEC).(不能使用同一连接执行其他 SQL 命令,而`复制`操作正在进行中。) 如果一个`复制`命令是通过发出的[`执行程序`](libpq-exec.html#LIBPQ-PQEXEC)在可能包含其他命令的字符串中,应用程序必须继续通过以下方式获取结果[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)完成后`复制`顺序。只有当[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)返回`空值`是否确定[`执行程序`](libpq-exec.html#LIBPQ-PQEXEC)命令字符串已完成,可以安全地发出更多命令。 本节的功能只有在获得结果状态后才能执行`PGRES_COPY_OUT`要么`PGRES_COPY_IN`从[`执行程序`](libpq-exec.html#LIBPQ-PQEXEC)要么[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT). 一种`PGresult`object bearing one of these status values carries some additional data about the`COPY`operation that is starting. This additional data is available using functions that are also used in connection with query results: `PQnfields`[](<>) Returns the number of columns (fields) to be copied. `PQbinaryTuples`[](<>) 0 indicates the overall copy format is textual (rows separated by newlines, columns separated by separator characters, etc). 1 indicates the overall copy format is binary. See[COPY](sql-copy.html)for more information. `PQfformat`[](<>) Returns the format code (0 for text, 1 for binary) associated with each column of the copy operation. The per-column format codes will always be zero when the overall copy format is textual, but the binary format can support both text and binary columns. (However, as of the current implementation of`COPY`, only binary columns appear in a binary copy; so the per-column formats always match the overall format at present.) ### 34.10.1. Functions for Sending`COPY`Data These functions are used to send data during`COPY FROM STDIN`. They will fail if called when the connection is not in`COPY_IN`state. `PQputCopyData`[](<>) Sends data to the server during`COPY_IN`state. ``` int PQputCopyData(PGconn *conn, const char *buffer, int nbytes); ``` Transmits the`COPY`data in the specified*`buffer`*, 长度*`nbytes`*, 到服务器。如果数据已排队,则结果为 1,如果由于缓冲区已满而未排队,则结果为 0(这只会在非阻塞模式下发生),如果发生错误,则结果为 -1。(采用[`PQerrorMessage`](libpq-status.html#LIBPQ-PQERRORMESSAGE)如果返回值为 -1,则检索详细信息。如果值为零,请等待写入就绪,然后重试。) 该应用程序可以划分`复制`数据流到任何方便大小的缓冲区加载中。缓冲区加载边界在发送时没有语义意义。数据流的内容必须与预期的数据格式相匹配`复制`命令;看[复制](sql-copy.html)详情。 `PQputCopyEnd`[](<>) 在期间向服务器发送数据结束指示`COPY_IN`状态。 ``` int PQputCopyEnd(PGconn *conn, const char *errormsg); ``` 结束`COPY_IN`如果操作成功*`错误消息`*是`空值`.如果*`错误消息`*不是`空值`然后`复制`被迫失败,字符串指向*`错误消息`*用作错误消息。(但是,我们不应该假设这个确切的错误消息会从服务器返回,因为服务器可能已经失败了。)`复制`因为它自己的原因。) 如果发送了终止消息,则结果为1;或者在非阻塞模式下,这可能仅表明终止消息已成功排队。(在非阻塞模式下,为了确保数据已经发送,接下来应该等待write ready并调用[`PQflush`](libpq-async.html#LIBPQ-PQFLUSH),重复,直到返回零。)零表示由于缓冲区已满,函数无法对终止消息排队;这只会在非阻塞模式下发生。(在这种情况下,请等待write ready并尝试[`PQputCopyEnd`](libpq-copy.html#LIBPQ-PQPUTCOPYEND)再打一次。)如果出现硬错误,则返回-1;你可以用[`PQerrorMessage`](libpq-status.html#LIBPQ-PQERRORMESSAGE)检索详细信息。 成功呼叫后[`PQputCopyEnd`](libpq-copy.html#LIBPQ-PQPUTCOPYEND)呼叫[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)以获取`复制`命令人们可以等待这个结果以通常的方式出现。然后恢复正常操作。 ### 34.10.2.接收功能`复制`数据 这些函数用于在运行期间接收数据`复制到标准输出`。如果在连接不在时调用,它们将失败`抄写`状态 `PQgetCopyData`[](<>) 在运行期间从服务器接收数据`抄写`状态 ``` int PQgetCopyData(PGconn *conn, char **buffer, int async); ``` 尝试在中断期间从服务器获取另一行数据`复制`.数据总是一次返回一个数据行;如果只有部分行可用,则不返回。数据行的成功返回涉及分配一块内存来保存数据。这*`缓冲`*参数必须是非`空值`.*\`*缓冲`* 设置为指向分配的内存,或者指向`空值`在没有返回缓冲区的情况下。一个非`空值`应使用 [ 释放结果缓冲区`PQfreemem\`](libpq-misc.html#LIBPQ-PQFREEMEM) 不再需要时。 当成功返回一行时,返回值为该行中的数据字节数(这将始终大于零)。返回的字符串始终以 null 结尾,尽管这可能仅对文本有用`复制`.结果为零表示`复制`仍在进行中,但还没有可用的行(这只有在*`异步`*是真的)。-1 的结果表明`复制`已经完成了。结果 -2 表示发生了错误(请参阅[`PQerrorMessage`](libpq-status.html#LIBPQ-PQERRORMESSAGE)由于这个原因)。 什么时候*`异步`*为真(非零),[`PQgetCopyData`](libpq-copy.html#LIBPQ-PQGETCOPYDATA)不会阻塞等待输入;如果`COPY`is still in progress but no complete row is available. (In this case wait for read-ready and then call[`PQconsumeInput` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT)before calling[`PQgetCopyData`](libpq-copy.html#LIBPQ-PQGETCOPYDATA)again.) When*`async`*is false (zero),[`PQgetCopyData`](libpq-copy.html#LIBPQ-PQGETCOPYDATA)will block until data is available or the operation completes. After[`PQgetCopyData`](libpq-copy.html#LIBPQ-PQGETCOPYDATA)returns -1, call[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)to obtain the final result status of the`COPY`command. One can wait for this result to be available in the usual way. Then return to normal operation. ### 34.10.3. Obsolete Functions for`COPY` These functions represent older methods of handling`COPY`. Although they still work, they are deprecated due to poor error handling, inconvenient methods of detecting end-of-data, and lack of support for binary or nonblocking transfers. `PQgetline`[](<>) Reads a newline-terminated line of characters (transmitted by the server) into a buffer string of size*`length`*. ``` int PQgetline(PGconn *conn, char *buffer, int length); ``` This function copies up to*`length`*-1 characters into the buffer and converts the terminating newline into a zero byte.[`PQgetline`](libpq-copy.html#LIBPQ-PQGETLINE)返回`EOF`在输入结束时,如果已读取整行,则为 0,如果缓冲区已满但尚未读取终止的换行符,则为 1。 请注意,应用程序必须检查新行是否包含两个字符`\。`,表示服务器已经完成发送结果`复制`命令。如果应用程序可能收到超过*`长度`*-1 个字符长,需要注意确保它能够识别`\。`线正确(例如,不会将长数据线的末端误认为是终止线)。 `PQgetlineAsync`[](<>) 读取一行`复制`数据(由服务器传输)进入缓冲区而不阻塞。 ``` int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize); ``` 这个功能类似于[`PQgetline`](libpq-copy.html#LIBPQ-PQGETLINE),但它可以被必须阅读的应用程序使用`复制`数据异步,即不阻塞。发出了`复制`命令并得到一个`PGRES_COPY_OUT`响应,应用程序应该调用[`PQconsume输入` ](libpq-async.html#LIBPQ-PQCONSUMEINPUT)和[`PQgetlineAsync`](libpq-copy.html#LIBPQ-PQGETLINEASYNC)直到检测到数据结束信号。 不像[`PQgetline`](libpq-copy.html#LIBPQ-PQGETLINE),这个函数负责检测数据结束。 在每次通话中,[`PQgetlineAsync`](libpq-copy.html#LIBPQ-PQGETLINEASYNC)如果在 libpq 的输入缓冲区中有完整的数据行,将返回数据。否则,在行的其余部分到达之前,不会返回任何数据。如果已识别出复制数据结束标记,则该函数返回 -1,如果没有数据可用,则返回 0,或者返回一个正数,表示返回的数据字节数。如果返回 -1,调用者必须下一次调用[`PQendcopy`](libpq-copy.html#LIBPQ-PQENDCOPY),然后返回正常处理。 返回的数据不会超出数据行边界。如果可能,将一次返回一整行。但是如果调用者提供的缓冲区太小而无法容纳服务器发送的行,则将返回部分数据行。对于文本数据,可以通过测试最后返回的字节是否为`\n`或不。(在二进制`复制`, 实际解析`复制`将需要数据格式来进行等效确定。)返回的字符串不是以空值结尾的。(如果要添加终止空值,请务必传递一个*`缓冲区大小`*比实际可用的房间小一个。) `PQputline`[](<>) 向服务器发送一个以 null 结尾的字符串。如果 OK 并且返回 0`EOF`如果无法发送字符串。 ``` int PQputline(PGconn *conn, const char *string); ``` 这`复制`通过一系列调用发送的数据流[`PQputline`](libpq-copy.html#LIBPQ-PQPUTLINE)与返回的格式相同[`PQgetlineAsync`](libpq-copy.html#LIBPQ-PQGETLINEASYNC),除了应用程序没有义务每次只发送一个数据行[`PQputline`](libpq-copy.html#LIBPQ-PQPUTLINE)称呼;每次通话可以发送部分线路或多条线路。 ### 笔记 在 PostgreSQL 协议 3.0 之前,应用程序需要显式发送这两个字符`\。`作为最后一行,向服务器表明它已完成发送`复制`数据。虽然这仍然有效,但它已被弃用,并且它的特殊含义`\。`预计将在未来的版本中删除。打电话就够了[`PQendcopy`](libpq-copy.html#LIBPQ-PQENDCOPY)在发送了实际数据之后。 `PQputnbytes`[](<>) 向服务器发送一个非空终止的字符串。如果 OK 并且返回 0`EOF`如果无法发送字符串。 ``` int PQputnbytes(PGconn *conn, const char *buffer, int nbytes); ``` 这就像[`PQputline`](libpq-copy.html#LIBPQ-PQPUTLINE),除了数据缓冲区不需要以空值结尾,因为要发送的字节数是直接指定的。发送二进制数据时使用此过程。 `PQendcopy`[](<>) 与服务器同步。 ``` int PQendcopy(PGconn *conn); ``` 该函数一直等到服务器完成复制。它应该在最后一个字符串被发送到服务器时使用[`PQputline`](libpq-copy.html#LIBPQ-PQPUTLINE)或者当从服务器接收到最后一个字符串时,使用`PQgetline`.必须发出它,否则服务器将与客户端“不同步”。从这个函数返回后,服务器准备好接收下一个 SQL 命令。成功完成时返回值为 0,否则为非零。(采用[`PQerrorMessage`](libpq-status.html#LIBPQ-PQERRORMESSAGE)如果返回值非零,则检索详细信息。) 使用时[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT),应用程序应响应`PGRES_COPY_OUT`结果通过执行[`PQgetline`](libpq-copy.html#LIBPQ-PQGETLINE)反复,接着[`PQendcopy`](libpq-copy.html#LIBPQ-PQENDCOPY)在看到终结符线之后。然后它应该返回到[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)循环直到[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)返回一个空指针。同样一个`PGRES_COPY_IN`结果由一系列处理[`PQputline`](libpq-copy.html#LIBPQ-PQPUTLINE)电话随后[`PQendcopy`](libpq-copy.html#LIBPQ-PQENDCOPY),然后返回[`PQgetResult`](libpq-async.html#LIBPQ-PQGETRESULT)环形。这种安排将确保一个`复制`嵌入在一系列 SQL 命令中的命令将被正确执行。 较早的申请可能会提交`复制`通过[`执行程序`](libpq-exec.html#LIBPQ-PQEXEC)并假设交易完成后[`PQendcopy`](libpq-copy.html#LIBPQ-PQENDCOPY).只有当`复制`是命令字符串中唯一的 SQL 命令。