pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
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 命令。)
如果一个COPY命令是通过PQexec在一个可能包含额外命令的字符串中发出的,那么应用在完成COPY序列之后必须继续用PQgetResult取得结果。 只有在PQgetResult返回NULL时,我们才能确信PQexec的命令字符串已经处理完毕, 并且可以安全地发出更多命令。
只有从 PQexec 或 PQgetResult 获得 PGRES_COPY_OUT 或 PGRES_COPY_IN 结果状态后,才应调用本节函数。
带有上述某个状态值的 PGresult 对象,还会携带关于即将开始的 COPY 操作的附加数据。这些数据可以通过下列函数获取,这些函数也用于查询结果:
这些附加数据值仅在使用协议 3.0 时可用。使用协议 2.0 时,这些函数都返回 0。
COPY数据的函数 #这些函数用于在 COPY FROM STDIN 期间发送数据。如果连接不处于 COPY_IN 状态,调用它们会失败。
PQputCopyData #在COPY_IN状态中向服务器发送数据。
int PQputCopyData(PGconn *conn,
const char *buffer,
int nbytes);
将指定 buffer 中长度为 nbytes 的 COPY 数据传输到服务器。数据成功加入队列时返回 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 失败。还要注意,在使用 3.0 之前协议的连接上,强制失败选项不起作用。)
终止消息已发送时返回 1;在非阻塞模式下,返回 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 释放。
成功返回一行时,返回值是该行的数据字节数,始终大于零。返回的字符串总是以零字节结尾,不过这可能仅对文本 COPY 有用。返回零表示 COPY 仍在进行,但尚无可用行(仅在 async 为真时可能发生)。返回 -1 表示 COPY 已完成;返回 -2 表示发生了错误(可用 PQerrorMessage 查看原因)。
当 async 为真(非零)时,PQgetCopyData 不会阻塞等待输入;如果 COPY 仍在进行,但没有完整行可用,则返回零。(此时,应等待读就绪,先调用 PQconsumeInput,再调用 PQgetCopyData。)当 async 为假(零)时,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 数据格式才能作出相同判断。)返回的字符串不以零字节结尾。(如果要自行添加末尾的零字节,务必将传入的 bufsize 设置为比实际可用空间少一字节。)
PQputline #向服务器发送以零字节结尾的字符串。成功时返回 0,无法发送字符串时返回 EOF。
int PQputline(PGconn *conn,
const char *string);
连续调用 PQputline 发送的 COPY 数据流,与 PQgetlineAsync 返回的数据格式相同。不过,应用程序不必在每次 PQputline 调用中恰好发送一个数据行;每次发送部分行或多行也可以。
在 PostgreSQL 协议 3.0 之前,应用程序必须显式发送由 \. 两个字符组成的最后一行,告知服务器应用程序已发送完 COPY 数据。虽然这种方式仍然有效,但已被弃用,\. 的特殊含义预计会在未来版本中移除。发送完实际数据后,调用 PQendcopy 即可。
PQputnbytes #向服务器发送不以零字节结尾的字符串。成功时返回 0,无法发送字符串时返回 EOF。
int PQputnbytes(PGconn *conn,
const char *buffer,
int nbytes);
此函数与 PQputline 完全相同,只是直接指定了要发送的字节数,因此数据缓冲区不必以零字节结尾。发送二进制数据时可使用此函数。
PQendcopy #与服务器同步。
int PQendcopy(PGconn *conn);
此函数会等待服务器完成复制。应在使用 PQputline 向服务器发送最后一个字符串后,或使用 PQgetline 从服务器接收最后一个字符串后调用它。必须调用此函数,否则服务器与客户端会“失去同步”。函数返回后,服务器便准备好接收下一条 SQL 命令。成功完成时返回 0,否则返回非零值。(返回非零值时,可用 PQerrorMessage 获取详细信息。)
使用 PQgetResult 时,收到 PGRES_COPY_OUT 结果后,应用程序应反复调用 PQgetline,并在看到终止行后调用 PQendcopy。随后应回到 PQgetResult 循环,直到 PQgetResult 返回空指针。类似地,收到 PGRES_COPY_IN 结果后,应连续调用 PQputline,再调用 PQendcopy,然后回到 PQgetResult 循环。这样可以保证嵌在一系列 SQL 命令中的 COPY 命令正确执行。
旧的应用很可能会通过PQexec提交一个COPY命令并且假定事务在PQendcopy之后完成。 只有在COPY是命令字符串中唯一的SQL命令时才能正确工作。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。