Php pg_send_query():无法将连接设置为阻止模式?

Php pg_send_query():无法将连接设置为阻止模式?,php,postgresql,Php,Postgresql,我有一个长期运行的脚本,它似乎偶尔会报告以下通知级别的错误: pg_send_query():无法将连接设置为阻止模式 之后它似乎会继续发送查询,但不清楚它是否成功发送了生成错误的查询 这是什么症状 编辑:错误发生时,postgres日志中没有任何条目,这表明这仅仅是一个连接错误,而不是postgres方面的错误(例如,可能不是postgres崩溃和重新启动或其他原因造成的) 编辑:据我所知,当触发此错误时,我的INSERT语句以某种方式成功 编辑:看起来这可能在2013年6月得到了修复:听起来

我有一个长期运行的脚本,它似乎偶尔会报告以下通知级别的错误: pg_send_query():无法将连接设置为阻止模式

之后它似乎会继续发送查询,但不清楚它是否成功发送了生成错误的查询

这是什么症状

编辑:错误发生时,postgres日志中没有任何条目,这表明这仅仅是一个连接错误,而不是postgres方面的错误(例如,可能不是postgres崩溃和重新启动或其他原因造成的)

编辑:据我所知,当触发此错误时,我的INSERT语句以某种方式成功


编辑:看起来这可能在2013年6月得到了修复:

听起来您正试图使用
pg\u send\u query()
函数向PostgreSQL发送异步查询。此函数的目的是允许PHP脚本在等待PostgreSQL执行查询并准备好结果的同时继续执行其他代码

for
pg\u send\u query()
中给出的示例建议,如果PostgreSQL已经在处理另一个查询,则不应发送查询:

if (!pg_connection_busy($dbconn)) {
  pg_send_query($dbconn, "select * from authors; select count(*) from authors;");
}

您使用
pg\u send\u query()
而不是
pg\u query()
有什么原因吗?如果您可以允许脚本阻止等待查询执行,我猜(当然没有尝试过)您不会看到这些错误。

这是
pg\u send\u query()
无法成功地将连接切换回阻止模式的症状。查看PHPs pgsql.c中的源代码,您可以找到:

/* {{{ proto bool pg_send_query(resource connection, string query)
   Send asynchronous query */
PHP_FUNCTION(pg_send_query)
{

<... snipped function setup stuff ...>

 if (PQ_SETNONBLOCKING(pgsql, 1)) {
  php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
  RETURN_FALSE;
 }

<... snipped main function execution stuff ...>

 if (PQ_SETNONBLOCKING(pgsql, 0)) {
  php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
 }
 RETURN_TRUE;
}
如果arg为1,则将连接状态设置为非阻塞, 或在arg为0时阻塞。如果是,则返回0 好的,如果有错误,-1

在非阻塞状态下,调用 PQsendQuery、PQputline、PQputnbytes、, 和PQendcopy将不会阻止,但 如果需要,则返回一个错误 再次被召唤

请注意,PQexec不遵守 非阻塞模式;如果它被称为 不管怎么说,他都会采取封锁的方式

进一步查看PQsetnonblocking的来源(在PostgeSQLs fe exec.c中),调用失败可能有两个原因:

/* PQsetnonblocking:
 * sets the PGconn's database connection non-blocking if the arg is TRUE
 * or makes it non-blocking if the arg is FALSE, this will not protect
 * you from PQexec(), you'll only be safe when using the non-blocking API.
 * Needs to be called only on a connected database connection.
 */
int
PQsetnonblocking(PGconn *conn, int arg)
{
 bool  barg;

 if (!conn || conn->status == CONNECTION_BAD)
  return -1;

 barg = (arg ? TRUE : FALSE);

 /* early out if the socket is already in the state requested */
 if (barg == conn->nonblocking)
  return 0;

 /*
  * to guarantee constancy for flushing/query/result-polling behavior we
  * need to flush the send queue at this point in order to guarantee proper
  * behavior. this is ok because either they are making a transition _from_
  * or _to_ blocking mode, either way we can block them.
  */
 /* if we are going from blocking to non-blocking flush here */
 if (pqFlush(conn))
  return -1;

 conn->nonblocking = barg;

 return 0;
}
因此,要么连接不知何故丢失,要么pqFlush没有成功完成,这表明连接输出缓冲区中存在剩余内容

第一种情况是无害的,因为您的脚本肯定会在以后的调用中注意到丢失的连接,并对此做出反应(或者更明显地失败)


这就剩下了第二种情况,这意味着您的连接处于非默认、非阻塞状态。我不知道这是否会影响以后重用此连接的调用。如果您想安全起见,在这种情况下,您应该关闭连接并使用新的/另一个连接。

如果您使用线程,并且重新使用连接,则可能会发生这种情况。 如果是这种情况,您可以像这样使用
PGSQL\u CONNECT\u FORCE\u NEW

pg_connect("...", PGSQL_CONNECT_FORCE_NEW)

这将强制使用新的数据库连接资源,但请注意:您可能会耗尽客户端的连接,因此请小心地在线程内部使用此资源,以便不要忘记使用
pg_close()

我最近遇到了相同的问题,在Henrik Opels的帮助下,answer意识到PHP实际上不会等到缓冲区刷新后再将连接设置回阻塞模式

“无法将连接设置为阻塞模式”对于足够大的查询可以重复,以填充发送缓冲区(在末尾填充空格就足够了)。对于较小的查询,我认为它取决于负载,而且是断断续续的


如果您确实需要异步模式,请尝试在

上的补丁。我在PHP5.6.9中遇到了相同的错误消息

当pg_pconnect()建立的持久连接丢失且 pgsql.auto_reset_persistent设置为Off

在以下情况下,连接可能会丢失:

  • PHP会话过期
  • 连接到数据库超时
  • 重新启动Web服务器/DB服务器
  • 您可以检查PHP.ini中的pgsql.auto_reset_persistent并将其设置为On


    启用pgsql.auto_reset_persistent后,每次调用pg_pconnect()时,都会检查连接链接是否仍然有效。这需要一点开销,但会在连接丢失时修复错误消息。

    我也遇到了这个错误。我通过重新启动web服务器(Apache)来解决我的问题。

    +1-考虑到“长时间运行脚本”的说法,我假设他是故意异步执行的,但如果不是这样的话,这将是显而易见的解决方案:)需要使用
    pg\u send\u query()
    才能在查询失败时正确查询错误。否则,您需要使用
    pg\u last\u error()
    ,但实际效果并不理想。如果您使用
    pg\u send\u query()
    并与远程服务器对话,请注意错误。如果查询字符串太长(以字节为单位),
    pg\u send\u query()
    将因实现错误而失败(触摸连接前缺少刷新)。对于解决方法,请安装PgBouncer并使用pg_connect()连接到本地主机PgBouncer,而不是直接连接到远程服务器。+1用于确定真正的原因并提供实际的建议。做得好!我想我很不幸地用pg_query()和pg_pconnect()组合成功地重复了这个错误。不需要使用pg_send_query()。如果使用pg_pconnect()获取“新”连接时自动回滚上一个连接,则pg_查询似乎会随机生成此错误。在Ubuntu10.04 LTS x86-64上运行的PHP 5.3.2和Postgres 8.4存在问题。如果您遇到此问题,并且没有尝试使用
    pg_pconnect()
    可能的原因是PHP错误:您还可以在本地主机和
    pg_connect("...", PGSQL_CONNECT_FORCE_NEW)