丹尼尔·维里特:使用 coproc 进行高级 psql 脚本编写

丹尼尔·维里特:使用 coproc 进行高级 psql 脚本编写

💡 原文英文,约1400词,阅读约需5分钟。
📝

内容提要

本文介绍了如何使用bash中的coproc功能来控制psql。通过将psql作为coprocess启动,可以将命令发送到psql并获取结果。此外,还介绍了如何使用coprocess来实现更高级的错误处理和与其他进程的同步。

🔎

延伸解读

coproc 与传统 psql 调用方式的对比

文章指出,不使用 coproc 时,可以通过 psql 的 -c 选项执行单条命令,或用 -f 选项运行脚本文件,也可以利用 here-document 将 SQL 嵌入 shell 脚本,或动态生成命令并通过管道传给 psql。这些方式虽然灵活,但一旦命令块确定,就难以根据中间结果调整后续操作,也无法与外部事件同步。coproc 则通过双向管道实现了与 psql 的实时交互,为需要精细控制的场景提供了可能。

利用结束标记获取每条命令的结果

将 psql 作为协进程启动后,脚本可以向其标准输入写入命令,并从标准输出读取结果。但直接读取会面临阻塞问题:当没有更多输出时,读取操作会挂起。为此,文章采用了一种实用技巧:在每条命令后追加一条输出随机结束标记的命令,该标记包含 UUID 以降低冲突概率。脚本逐行读取输出,直到遇到该标记才停止,从而准确获取每条命令的完整结果。

基于 SQLSTATE 的细粒度错误处理与重试

通过访问 psql 的 SQLSTATE 变量,脚本可以实现更精细的错误处理。文章展示了一个 retriable_transaction 函数,它在事务中执行一系列语句,并检查每条语句后的 SQLSTATE。对于语句超时(57014)、序列化失败(40001)或死锁(40P01)等可重试错误,函数会回滚并重新开始整个事务;对于其他错误,则输出错误信息并回滚退出。这种模式提升了脚本的健壮性。

与外部进程同步:流式导入压缩归档

文章还介绍了一个实际用例:从压缩的 tar 归档中导入文件到数据库,且要求整个导入在单个事务中完成。由于磁盘空间可能不足,无法先解压文件。解决方案是利用 GNU tar 的 --to-command 选项将文件内容流式传输到命名管道,同时将 psql 作为协进程,根据管道中出现的文件名动态发送 \copy 命令。这样既避免了中间磁盘存储,又保证了所有导入操作在同一个事务中执行。

❓

Q&A

什么是bash中的coproc功能?

coproc是一个在子进程中异步执行的shell命令,允许在shell和coprocess之间建立双向管道。

如何使用coproc与psql进行交互?

可以通过向${PSQL[1]}写入命令并从${PSQL[0]}读取结果来与psql交互。

使用coproc有什么优势?

使用coproc可以实现更高级的错误处理和与其他进程的同步,提供更好的控制。

如何在psql中实现细粒度的错误处理?

可以通过访问SQLSTATE来实现细粒度的错误处理,处理可重试的事务。

如何在bash脚本中嵌入SQL命令?

可以使用here-document语法将SQL命令嵌入到shell脚本中。

如何使用GNU tar与psql同步命令?

可以通过将psql作为coprocess启动,并使用named pipes来同步命令和数据流。

🏷️

标签

➡️

继续阅读