1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

ext/pgsql: adding pg_socket_poll.

Using PQSocketPoll to poll on a connection's socket.
Returns immediatly is there no event expected on read and write.
Other than that, it is a thin wrapper on top of poll, thus reflecting
 its return value.

close GH-14366
This commit is contained in:
David Carlier
2024-05-29 19:55:13 +01:00
parent 3096c71594
commit e69bccd7c7
7 changed files with 132 additions and 1 deletions

1
NEWS
View File

@@ -197,6 +197,7 @@ PHP NEWS
. Added pg_change_password to alter an user's password. (David Carlier)
. Added pg_put_copy_data/pg_put_copy_end to send COPY commands and signal
the end of the COPY. (David Carlier)
. Added pg_socket_poll to poll on the connection. (David Carlier)
- Phar:
. Fixed bug GH-12532 (PharData created from zip has incorrect timestamp).

View File

@@ -549,6 +549,8 @@ PHP 8.4 UPGRADE NOTES
transparently the password encryption from the database settings.
. Added pg_put_copy_data to send COPY commands and pg_put_copy_end to send
end-of-data to the server.
. Added pg_socket_poll to check if there is any read and/or write events
with an optional timeout.
- Sodium:
. Added the sodium_crypto_aead_aegis128l_*() and sodium_crypto_aead_aegis256l_*()

View File

@@ -68,6 +68,7 @@ if test "$PHP_PGSQL" != "no"; then
AC_CHECK_LIB(pq, PQsetErrorContextVisibility, AC_DEFINE(HAVE_PG_CONTEXT_VISIBILITY,1,[PostgreSQL 9.6 or later]))
AC_CHECK_LIB(pq, PQresultMemorySize, AC_DEFINE(HAVE_PG_RESULT_MEMORY_SIZE,1,[PostgreSQL 12 or later]))
AC_CHECK_LIB(pq, PQchangePassword, AC_DEFINE(HAVE_PG_CHANGE_PASSWORD,1,[PostgreSQL 17 or later]))
AC_CHECK_LIB(pq, PQsocketPoll, AC_DEFINE(HAVE_PG_SOCKET_POLL,1,[PostgreSQL 17 or later]))
LIBS=$old_LIBS
LDFLAGS=$old_LDFLAGS

View File

@@ -40,6 +40,9 @@
#include "php_globals.h"
#include "zend_exceptions.h"
#include "zend_attributes.h"
#if !defined(HAVE_PG_SOCKET_POLL)
#include "php_network.h"
#endif
#ifdef HAVE_PGSQL
@@ -443,6 +446,41 @@ static PGresult *PQchangePassword(PGconn *conn, const char *user, const char *pa
}
#endif
#if !defined(HAVE_PG_SOCKET_POLL)
static int PQsocketPoll(int socket, int read, int write, time_t timeout)
{
if (!read && !write)
return 0;
php_pollfd fd;
int ts = -1;
fd.fd = socket;
fd.events = POLLERR;
fd.revents = 0;
if (read) {
fd.events |= POLLIN;
}
if (write) {
fd.events |= POLLOUT;
}
if (timeout != (time_t)ts) {
time_t cur = time(NULL);
if (timeout > cur) {
ts = (timeout - cur) * 1000;
} else {
ts = 0;
}
}
return php_poll2(&fd, 1, ts);
}
#endif
/* {{{ PHP_INI */
PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN( "pgsql.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_persistent, zend_pgsql_globals, pgsql_globals)
@@ -6165,3 +6203,29 @@ PHP_FUNCTION(pg_put_copy_end)
RETURN_LONG((zend_long)PQputCopyEnd(link->conn, err));
}
PHP_FUNCTION(pg_socket_poll)
{
zval *z_socket;
php_stream *stream;
php_socket_t socket;
zend_long read, write;
zend_long ts = -1;
ZEND_PARSE_PARAMETERS_START(3, 4)
Z_PARAM_RESOURCE(z_socket)
Z_PARAM_LONG(read)
Z_PARAM_LONG(write)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(ts)
ZEND_PARSE_PARAMETERS_END();
php_stream_from_zval(stream, z_socket);
if (php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void **)&socket, 0)) {
zend_argument_type_error(1, "invalid resource socket");
RETURN_THROWS();
}
RETURN_LONG((zend_long)PQsocketPoll(socket, (int)read, (int)write, (int)ts));
}

View File

@@ -952,6 +952,11 @@ namespace {
function pg_put_copy_data(PgSql\Connection $connection, string $cmd): int {}
function pg_put_copy_end(PgSql\Connection $connection, ?string $error = null): int {}
/**
* @param resource $socket
*/
function pg_socket_poll($socket, int $read, int $write, int $timeout = -1): int {}
}
namespace PgSql {

View File

@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: edc626b255224ed76333223c90cfab062415637f */
* Stub hash: 4a2a5778003aa741952e16617e5bdb2ad06e6e16 */
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)
@@ -481,6 +481,13 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pg_put_copy_end, 0, 1, IS_LONG,
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, error, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pg_socket_poll, 0, 3, IS_LONG, 0)
ZEND_ARG_INFO(0, socket)
ZEND_ARG_TYPE_INFO(0, read, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, write, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, timeout, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
ZEND_FUNCTION(pg_connect);
ZEND_FUNCTION(pg_pconnect);
ZEND_FUNCTION(pg_connect_poll);
@@ -581,6 +588,7 @@ ZEND_FUNCTION(pg_result_memory_size);
ZEND_FUNCTION(pg_change_password);
ZEND_FUNCTION(pg_put_copy_data);
ZEND_FUNCTION(pg_put_copy_end);
ZEND_FUNCTION(pg_socket_poll);
static const zend_function_entry ext_functions[] = {
ZEND_FE(pg_connect, arginfo_pg_connect)
@@ -706,6 +714,7 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(pg_change_password, arginfo_pg_change_password)
ZEND_FE(pg_put_copy_data, arginfo_pg_put_copy_data)
ZEND_FE(pg_put_copy_end, arginfo_pg_put_copy_end)
ZEND_FE(pg_socket_poll, arginfo_pg_socket_poll)
ZEND_FE_END
};

View File

@@ -0,0 +1,49 @@
--TEST--
PostgreSQL poll on connection's socket
--EXTENSIONS--
pgsql
--SKIPIF--
<?php
include("inc/skipif.inc");
?>
--FILE--
<?php
include('inc/config.inc');
include('inc/nonblocking.inc');
if (!($db = pg_connect($conn_str, PGSQL_CONNECT_ASYNC))) die("pg_connect failed");
$socket = pg_socket($db);
$fp = fopen(__DIR__ . "/inc/config.inc", "r");
try {
pg_socket_poll($fp, 0, 0);
} catch (\TypeError $e) {
echo $e->getMessage() . PHP_EOL;
}
if (($topoll = pg_socket_poll($socket, 1, 1, 1)) === -1) die("pg_socket_poll failed");
stream_set_blocking($socket, false);
while (1) {
switch ($status = pg_connect_poll($db)) {
case PGSQL_POLLING_READING:
nb_is_writable($socket);
break;
case PGSQL_POLLING_WRITING:
nb_is_writable($socket);
break;
case PGSQL_POLLING_OK:
break 2;
default:
die("poll failed");
}
}
assert(pg_connection_status($db) === PGSQL_CONNECTION_OK);
echo "OK";
pg_close($db);
?>
--EXPECT--
pg_socket_poll(): Argument #1 ($socket) invalid resource socket
OK