Đó là một triệu chứng của pg_send_query()
không thể chuyển thành công kết nối trở lại chế độ chặn. Nhìn vào mã nguồn trong PHP pgsql.c, bạn có thể tìm thấy:
/* {{{ 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;
}
Vì vậy, lỗi được nêu ra ở cuối hàm, sau khi hoàn thành công việc chính. Điều này phù hợp với quan sát của bạn rằng các câu lệnh INSERT của bạn được thực hiện.
Toàn bộ mục đích của hai cuộc gọi PQ_SETNONBLOCKING
là đặt kết nối ở chế độ không chặn để cho phép thực thi không đồng bộ và đưa nó trở lại hành vi chặn mặc định sau đó. Từ documentation of PQsetnonblocking: (PQ_SETNONBLOCKING chỉ là một bí danh được xác định cho chức năng đó):
Sets the nonblocking status of the connection.
int PQsetnonblocking(PGconn *conn, int arg);
Sets the state of the connection to nonblocking if arg is 1, or blocking if arg is 0. Returns 0 if OK, -1 if error.
In the nonblocking state, calls to PQsendQuery, PQputline, PQputnbytes, and PQendcopy will not block but instead return an error if they need to be called again.
Note that PQexec does not honor nonblocking mode; if it is called, it will act in blocking fashion anyway.
Nhìn xa hơn vào nguồn gốc của PQsetnonblocking (trong PostgeSQLs fe-exec.c), có hai lý do khiến các cuộc gọi có thể thất bại :
/* 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;
}
Vì vậy, kết nối bị mất bằng cách nào đó hoặc pqFlush không kết thúc thành công, cho biết công cụ còn lại trong bộ đệm đầu ra kết nối.
Trường hợp đầu tiên sẽ vô hại, vì tập lệnh của bạn chắc chắn sẽ thông báo kết nối bị mất cho các cuộc gọi sau đó và phản ứng lại (hoặc không thể nhận thấy rõ hơn).
Điều này để lại trường hợp thứ hai, điều đó có nghĩa là bạn có kết nối ở trạng thái không mặc định, không chặn. Tôi không biết nếu điều này có thể ảnh hưởng đến các cuộc gọi sau đó sẽ tái sử dụng kết nối này. Nếu bạn muốn chơi nó an toàn, bạn sẽ đóng kết nối trong trường hợp này và sử dụng một kết nối mới/khác.
+1 để đi thẳng đến nguồn –
+1 để xác định nguyên nhân thực sự và đưa ra các đề xuất thực tế về việc cần làm. Làm tốt! –
Tôi nghĩ rằng tôi đã không may thành công trong việc lặp lại lỗi này với pg_query() kết hợp với pg_pconnect(). Sử dụng pg_send_query() là không cần thiết. Các pg_query dường như ngẫu nhiên tạo ra lỗi này nếu kết nối trước đó được tự động cuộn lại khi kết nối "mới" được mua với pg_pconnect(). Sự cố được hiển thị với PHP 5.3.2 và Postgres 8.4 chạy trên Ubuntu 10.04 LTS x86-64. –