在postgresql有线协议中,我怎样才能从部分执行的select到达ReadyForQuery?

我正在尝试使用node.js中的node-pg-cursor模块针对postgresql服务器(版本9.3)

这个模块允许顺序读取一个select中的N行,并通过发送来工作

cur.read(N): 'Execute' on portal=unnamed, rows=N 

这个命令最多可以读取N行,我们可以继续递增地读取行,直到我们接收到的结束

 CommandComplete ReadyForQuery 

现在我的问题是,我想退出扩展命令之前获取所有的行,并达到执行序列的结束:我想增量获取N行,N行,N行,..在一个点决定我有足够的。

当我这样做(通过执行停止获取),查询似乎永远不会达到CommandComplete或ReadyForQuery。 这似乎是正常的,因为没有任何事情告诉扩展查询,我永远不会再问它的行。

除了closures连接之外,还有一个命令可以访问CommandComplete或ReadyForQuery,而不是从门户获取所有行?

我试图发送closures并收到CloseComplete,但它没有去ReadyForQuery。

如果我通过在协议上发送垃圾强制ErrorResponse,我达到ReadyForQuery,但似乎不是很干净…

我想你在文档中是指这个:

如果Execute在完成门户Execute之前终止(由于达到非零结果行数),它将发送一个PortalSuspended消息; 这个消息的出现告诉前端应该对同一个门户发出另一个执行来完成操作。 表示完成源SQL命令的CommandComplete消息在门户执行完成之前不会发送。 因此, Execute阶段总是以这些消息之一的出现而终止: CommandCompleteEmptyQueryResponse (如果门户从空查询string创build), ErrorResponsePortalSuspended

据推测,你得到了PortalSuspended ,你想放弃门户,不执行任何更多或消耗任何更多的结果。

如果是这样,我想你可以发送一个Sync消息:

在完成每一系列扩展查询消息时,前端应该发出一个同步消息。 如果不在BEGIN / COMMIT事务块内(“close”意思是在没有错误的情况下提交,或者如果错误,则回滚),这个无参数消息会导致后端closures当前事务。 然后发出ReadyForQuery响应。

您可能希望首先针对门户网站发布Close

closures消息closures现有的准备好的语句或门户并释放资源。

所以我认为你需要做的是,从消息stream的angular度来看:

  • Parse
  • Bind一个命名的门户
  • Describe
  • 循环:
    • 用行数限制Execute以获取一些行
    • 如果没有更多的行需要; 然后
      • Close门户
      • 打破循环
    • 如果CommandComplete收到:
      • 打破循环
  • Sync
  • 等待ReadyForQuery

这听起来像你可能想要使用asynchronous查询处理API ,如果你的驱动程序是一个libpq包装。 如果是本地实现, libpq的源代码可能会为您提供线索。

总的来说,看起来您需要使用新连接取消查询,然后继续使用input,直到缓冲区为空。 您会收到很多结果数据被缓冲,然后一个错误消息指出查询被取消(如果它没有caching所有的输出,然后取消它),最后是一个ReadyForQuery。

我引用libpq手册 :

使用PQsendQuery / PQgetResult的客户端也可以尝试取消服务器正在处理的命令; 见第31.6节 。 但不pipePQcancel的返回值如何,应用程序都必须使用PQgetResult继续正常的结果读取序列。 一个成功的取消只会导致命令比其他方式更快地终止。

系统通常具有相当大的TCP发送缓冲区,并且通常是dynamic的。 请参阅Linux的tcp(7)setsockopt(2)SO_SNDBUF选项等。因此,在PostgreSQL服务器写入套接字之前,可能会缓冲很多数据。 PostgreSQL不提供对发送缓冲区大小的连接控制,甚至不提供全局configuration选项; 您必须在操作系统级别执行此操作。 (也就是说,如果你想修补PostgreSQL来设置发送缓冲区的大小和setsockoptSO_SENDBUF是微不足道的)。

PostgreSQL不能在取消查询时刷新输出缓冲区。 即使这样做是安全的,并且平台也支持它,但Pg并不确定缓冲区是否已经清空了之前的查询和其他相关消息的结果,因为您可能已经对多个查询进行了piplined操作。

所以你所能做的就是减lessTCP输出缓冲区的最大大小。 这将减less必须读取和丢弃的数据量,但可能会影响发送批量数据的其他查询的性能。

当你看到足够多的时候,不是试图运行查询并取消它,而是build议阅读批量行,当你消耗当前行时请求一个新的批量。 您可以使用协议级别的游标来完成此操作。 这样你就可以控制服务器排队多less数据,而且你不必乱用缓冲区大小。 您可能已经这样做了 – 使用一个指定的门户,并发送一个最大行数的Execute ,等待PortalSuspended说有更多的行要读取。