diff --git a/UPGRADING b/UPGRADING index b1600aa0dd550..2ba242d811e2a 100644 --- a/UPGRADING +++ b/UPGRADING @@ -432,6 +432,7 @@ PHP 8.3 UPGRADE NOTES in error messages (with libpq >= 9.6). . Added pg_enter_pipeline_mode(). . Added pg_exit_pipeline_mode(). + . Added pg_send_flush_request(). . Added pg_pipeline_sync(). . Added pg_pipeline_status(). diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 31f15cbe6acab..165342edcc51c 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -3595,6 +3595,9 @@ PHP_FUNCTION(pg_send_query) char *query; size_t len; PGconn *pgsql; +#ifdef LIBPQ_HAS_PIPELINING + bool is_pipeline_mode; +#endif int is_non_blocking; int ret; @@ -3606,23 +3609,40 @@ PHP_FUNCTION(pg_send_query) CHECK_PGSQL_LINK(link); pgsql = link->conn; - is_non_blocking = PQisnonblocking(pgsql); +#ifdef LIBPQ_HAS_PIPELINING + is_pipeline_mode = (PQpipelineStatus(pgsql) == PQ_PIPELINE_ON); + if (is_pipeline_mode) { + is_non_blocking = 1; + } else { +#endif + is_non_blocking = PQisnonblocking(pgsql); - if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) { - php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode"); - RETURN_FALSE; - } + if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) { + php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode"); + RETURN_FALSE; + } - if (_php_pgsql_link_has_results(pgsql)) { - php_error_docref(NULL, E_NOTICE, - "There are results on this connection. Call pg_get_result() until it returns FALSE"); + if (_php_pgsql_link_has_results(pgsql)) { + php_error_docref(NULL, E_NOTICE, + "There are results on this connection. Call pg_get_result() until it returns FALSE"); + } +#ifdef LIBPQ_HAS_PIPELINING } +#endif if (is_non_blocking) { if (!PQsendQuery(pgsql, query)) { RETURN_FALSE; } - ret = PQflush(pgsql); +#ifdef LIBPQ_HAS_PIPELINING + if (is_pipeline_mode) { + ret = 0; + } else { +#endif + ret = PQflush(pgsql); +#ifdef LIBPQ_HAS_PIPELINING + } +#endif } else { if (!PQsendQuery(pgsql, query)) { if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { @@ -3667,6 +3687,9 @@ PHP_FUNCTION(pg_send_query_params) char *query; size_t query_len; PGconn *pgsql; +#ifdef LIBPQ_HAS_PIPELINING + bool is_pipeline_mode; +#endif int is_non_blocking; int ret; @@ -3678,17 +3701,26 @@ PHP_FUNCTION(pg_send_query_params) CHECK_PGSQL_LINK(link); pgsql = link->conn; - is_non_blocking = PQisnonblocking(pgsql); +#ifdef LIBPQ_HAS_PIPELINING + is_pipeline_mode = (PQpipelineStatus(pgsql) == PQ_PIPELINE_ON); + if (is_pipeline_mode) { + is_non_blocking = 1; + } else { +#endif + is_non_blocking = PQisnonblocking(pgsql); - if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) { - php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode"); - RETURN_FALSE; - } + if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) { + php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode"); + RETURN_FALSE; + } - if (_php_pgsql_link_has_results(pgsql)) { - php_error_docref(NULL, E_NOTICE, - "There are results on this connection. Call pg_get_result() until it returns FALSE"); + if (_php_pgsql_link_has_results(pgsql)) { + php_error_docref(NULL, E_NOTICE, + "There are results on this connection. Call pg_get_result() until it returns FALSE"); + } +#ifdef LIBPQ_HAS_PIPELINING } +#endif num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr)); if (num_params > 0) { @@ -3727,7 +3759,15 @@ PHP_FUNCTION(pg_send_query_params) } if (is_non_blocking) { - ret = PQflush(pgsql); +#ifdef LIBPQ_HAS_PIPELINING + if (is_pipeline_mode) { + ret = 0; + } else { +#endif + ret = PQflush(pgsql); +#ifdef LIBPQ_HAS_PIPELINING + } +#endif } else { /* Wait to finish sending buffer */ while ((ret = PQflush(pgsql))) { @@ -3761,6 +3801,9 @@ PHP_FUNCTION(pg_send_prepare) char *query, *stmtname; size_t stmtname_len, query_len; PGconn *pgsql; +#ifdef LIBPQ_HAS_PIPELINING + bool is_pipeline_mode; +#endif int is_non_blocking; int ret; @@ -3772,17 +3815,26 @@ PHP_FUNCTION(pg_send_prepare) CHECK_PGSQL_LINK(link); pgsql = link->conn; - is_non_blocking = PQisnonblocking(pgsql); +#ifdef LIBPQ_HAS_PIPELINING + is_pipeline_mode = (PQpipelineStatus(pgsql) == PQ_PIPELINE_ON); + if (is_pipeline_mode) { + is_non_blocking = 1; + } else { +#endif + is_non_blocking = PQisnonblocking(pgsql); - if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) { - php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode"); - RETURN_FALSE; - } + if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) { + php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode"); + RETURN_FALSE; + } - if (_php_pgsql_link_has_results(pgsql)) { - php_error_docref(NULL, E_NOTICE, - "There are results on this connection. Call pg_get_result() until it returns FALSE"); + if (_php_pgsql_link_has_results(pgsql)) { + php_error_docref(NULL, E_NOTICE, + "There are results on this connection. Call pg_get_result() until it returns FALSE"); + } +#ifdef LIBPQ_HAS_PIPELINING } +#endif if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) { if (is_non_blocking) { @@ -3798,7 +3850,15 @@ PHP_FUNCTION(pg_send_prepare) } if (is_non_blocking) { - ret = PQflush(pgsql); +#ifdef LIBPQ_HAS_PIPELINING + if (is_pipeline_mode) { + ret = 0; + } else { +#endif + ret = PQflush(pgsql); +#ifdef LIBPQ_HAS_PIPELINING + } +#endif } else { /* Wait to finish sending buffer */ while ((ret = PQflush(pgsql))) { @@ -3834,6 +3894,9 @@ PHP_FUNCTION(pg_send_execute) char *stmtname; size_t stmtname_len; PGconn *pgsql; +#ifdef LIBPQ_HAS_PIPELINING + bool is_pipeline_mode; +#endif int is_non_blocking; int ret; @@ -3845,17 +3908,26 @@ PHP_FUNCTION(pg_send_execute) CHECK_PGSQL_LINK(link); pgsql = link->conn; - is_non_blocking = PQisnonblocking(pgsql); +#ifdef LIBPQ_HAS_PIPELINING + is_pipeline_mode = (PQpipelineStatus(pgsql) == PQ_PIPELINE_ON); + if (is_pipeline_mode) { + is_non_blocking = 1; + } else { +#endif + is_non_blocking = PQisnonblocking(pgsql); - if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) { - php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode"); - RETURN_FALSE; - } + if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) { + php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode"); + RETURN_FALSE; + } - if (_php_pgsql_link_has_results(pgsql)) { - php_error_docref(NULL, E_NOTICE, - "There are results on this connection. Call pg_get_result() until it returns FALSE"); + if (_php_pgsql_link_has_results(pgsql)) { + php_error_docref(NULL, E_NOTICE, + "There are results on this connection. Call pg_get_result() until it returns FALSE"); + } +#ifdef LIBPQ_HAS_PIPELINING } +#endif num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr)); if (num_params > 0) { @@ -3896,7 +3968,15 @@ PHP_FUNCTION(pg_send_execute) } if (is_non_blocking) { - ret = PQflush(pgsql); +#ifdef LIBPQ_HAS_PIPELINING + if (is_pipeline_mode) { + ret = 0; + } else { +#endif + ret = PQflush(pgsql); +#ifdef LIBPQ_HAS_PIPELINING + } +#endif } else { /* Wait to finish sending buffer */ while ((ret = PQflush(pgsql))) { @@ -5891,6 +5971,8 @@ PHP_FUNCTION(pg_enter_pipeline_mode) pgsql_handle = Z_PGSQL_LINK_P(pgsql_link); CHECK_PGSQL_LINK(pgsql_handle); + PQsetnonblocking(pgsql_handle->conn, 1); + RETURN_BOOL(PQenterPipelineMode(pgsql_handle->conn)); } @@ -5906,9 +5988,26 @@ PHP_FUNCTION(pg_exit_pipeline_mode) pgsql_handle = Z_PGSQL_LINK_P(pgsql_link); CHECK_PGSQL_LINK(pgsql_handle); + PQsetnonblocking(pgsql_handle->conn, 0); + RETURN_BOOL(PQexitPipelineMode(pgsql_handle->conn)); } +PHP_FUNCTION(pg_send_flush_request) +{ + zval *pgsql_link; + pgsql_link_handle *pgsql_handle; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) { + RETURN_THROWS(); + } + + pgsql_handle = Z_PGSQL_LINK_P(pgsql_link); + CHECK_PGSQL_LINK(pgsql_handle); + + RETURN_BOOL(PQsendFlushRequest(pgsql_handle->conn)); +} + PHP_FUNCTION(pg_pipeline_sync) { zval *pgsql_link; diff --git a/ext/pgsql/pgsql.stub.php b/ext/pgsql/pgsql.stub.php index 7ce709d17e2d8..082f72fa00d69 100644 --- a/ext/pgsql/pgsql.stub.php +++ b/ext/pgsql/pgsql.stub.php @@ -966,6 +966,7 @@ function pg_select(PgSql\Connection $connection, string $table_name, array $cond #ifdef LIBPQ_HAS_PIPELINING function pg_enter_pipeline_mode(PgSql\Connection $connection): bool {} function pg_exit_pipeline_mode(PgSql\Connection $connection): bool {} + function pg_send_flush_request(PgSql\Connection $connection): bool {} function pg_pipeline_sync(PgSql\Connection $connection): bool {} function pg_pipeline_status(PgSql\Connection $connection): int {} #endif diff --git a/ext/pgsql/pgsql_arginfo.h b/ext/pgsql/pgsql_arginfo.h index 6f035f19246cf..53627f2f73ef6 100644 --- a/ext/pgsql/pgsql_arginfo.h +++ b/ext/pgsql/pgsql_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0d6ef9904082180bf9205d61c2f45c0752be8f7b */ + * Stub hash: 25badfac7b1d807202b80fd544e6db234fd726fd */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pg_connect, 0, 1, PgSql\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, connection_string, IS_STRING, 0) @@ -462,6 +462,10 @@ ZEND_END_ARG_INFO() #define arginfo_pg_exit_pipeline_mode arginfo_pg_enter_pipeline_mode #endif +#if defined(LIBPQ_HAS_PIPELINING) +#define arginfo_pg_send_flush_request arginfo_pg_enter_pipeline_mode +#endif + #if defined(LIBPQ_HAS_PIPELINING) #define arginfo_pg_pipeline_sync arginfo_pg_enter_pipeline_mode #endif @@ -578,6 +582,9 @@ ZEND_FUNCTION(pg_enter_pipeline_mode); ZEND_FUNCTION(pg_exit_pipeline_mode); #endif #if defined(LIBPQ_HAS_PIPELINING) +ZEND_FUNCTION(pg_send_flush_request); +#endif +#if defined(LIBPQ_HAS_PIPELINING) ZEND_FUNCTION(pg_pipeline_sync); #endif #if defined(LIBPQ_HAS_PIPELINING) @@ -709,6 +716,9 @@ static const zend_function_entry ext_functions[] = { #if defined(LIBPQ_HAS_PIPELINING) ZEND_FE(pg_exit_pipeline_mode, arginfo_pg_exit_pipeline_mode) #endif +#if defined(LIBPQ_HAS_PIPELINING) + ZEND_FE(pg_send_flush_request, arginfo_pg_send_flush_request) +#endif #if defined(LIBPQ_HAS_PIPELINING) ZEND_FE(pg_pipeline_sync, arginfo_pg_pipeline_sync) #endif diff --git a/ext/pgsql/tests/pg_pipeline_sync.phpt b/ext/pgsql/tests/pg_pipeline_sync.phpt index 38366a025483b..f72c8cd87940f 100644 --- a/ext/pgsql/tests/pg_pipeline_sync.phpt +++ b/ext/pgsql/tests/pg_pipeline_sync.phpt @@ -50,6 +50,26 @@ if (!pg_send_query_params($db, "select $1 as index, now() + ($1||' day')::interv die('pg_send_query_params failed'); } +if (!pg_flush($db)) { + die('pg_flush failed'); +} + +for ($i = 2; $i < 50; ++$i) { + if (!pg_send_query_params($db, "select $1 as index, now() + ($1||' day')::interval as time", array($i))) { + die('pg_send_query_params failed'); + } +} + +if (!pg_send_flush_request($db)) { + die('pg_send_flush_request failed'); +} + +for ($i = 50; $i < 99; ++$i) { + if (!pg_send_query_params($db, "select $1 as index, now() + ($1||' day')::interval as time", array($i))) { + die('pg_send_query_params failed'); + } +} + if (!pg_pipeline_sync($db)) { die('pg_pipeline_sync failed'); } @@ -58,26 +78,37 @@ if (pg_pipeline_status($db) !== PGSQL_PIPELINE_ON) { die('pg_pipeline_status failed'); } -if (!($result = pg_get_result($db))) { - die('pg_get_result'); +if (!($stream = pg_socket($db))) { + die('pg_socket'); } -if (pg_result_status($result) !== PGSQL_TUPLES_OK) { - die('pg_result_status failed'); +if (pg_connection_busy($db)) { + $read = [$stream]; $write = $ex = []; + while (!stream_select($read, $write, $ex, null, null)) { } } -if (pg_num_rows($result) == -1) { - die('pg_num_rows failed'); -} +for ($i = 1; $i < 99; ++$i) { + if (!($result = pg_get_result($db))) { + die('pg_get_result'); + } -if (!pg_fetch_row($result, null)) { - die('pg_fetch_row failed'); -} + if (pg_result_status($result) !== PGSQL_TUPLES_OK) { + die('pg_result_status failed'); + } -pg_free_result($result); + if (pg_num_rows($result) == -1) { + die('pg_num_rows failed'); + } -if (pg_get_result($db) !== false) { - die('pg_get_result failed'); + if (!($row = pg_fetch_row($result, null))) { + die('pg_fetch_row failed'); + } + + pg_free_result($result); + + if (pg_get_result($db) !== false) { + die('pg_get_result failed'); + } } if (($result = pg_get_result($db)) !== false) {