From e2c568ef96331b97ae7c13ac83324593ab162e26 Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Sun, 8 Oct 2023 18:39:36 +0300 Subject: [PATCH] PGSQL: Allow unconditional selection in pg_select Previously, pg_select did not allow unconditional selection, where an empty ids array would result in a function failure. This patch implements two changes: - Make the ids array an optional parameter. - Allow the ids array to be empty. In both cases, unconditional selection happen, which is equivalent to pg_query('SELECT * FROM ;'). Two test cases were added to test the aforementioned changes. --- ext/pgsql/pgsql.c | 40 ++++++++++++++++++------------ ext/pgsql/pgsql.stub.php | 2 +- ext/pgsql/pgsql_arginfo.h | 6 ++--- ext/pgsql/tests/pg_select_001.phpt | 38 ++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 20 deletions(-) diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index b94becd3f701c..09d8c2875db75 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -5777,29 +5777,34 @@ PHP_PGSQL_API zend_result php_pgsql_select(PGconn *pg_link, const zend_string *t ZEND_ASSERT(pg_link != NULL); ZEND_ASSERT(table != NULL); - ZEND_ASSERT(Z_TYPE_P(ids_array) == IS_ARRAY); + if (ids_array) { + ZEND_ASSERT(Z_TYPE_P(ids_array) == IS_ARRAY); + } ZEND_ASSERT(Z_TYPE_P(ret_array) == IS_ARRAY); ZEND_ASSERT(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE))); - if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) { - return FAILURE; - } + zend_bool is_valid_ids_array = ids_array && zend_hash_num_elements(Z_ARRVAL_P(ids_array)) != 0; - ZVAL_UNDEF(&ids_converted); - if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) { - array_init(&ids_converted); - if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) { - goto cleanup; + if (is_valid_ids_array) { + ZVAL_UNDEF(&ids_converted); + if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) { + array_init(&ids_converted); + if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) { + goto cleanup; + } + ids_array = &ids_converted; } - ids_array = &ids_converted; } smart_str_appends(&querystr, "SELECT * FROM "); build_tablename(&querystr, pg_link, table); - smart_str_appends(&querystr, " WHERE "); - if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt)) - goto cleanup; + if (is_valid_ids_array) { + smart_str_appends(&querystr, " WHERE "); + if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt)) { + goto cleanup; + } + } smart_str_appendc(&querystr, ';'); smart_str_0(&querystr); @@ -5814,7 +5819,9 @@ PHP_PGSQL_API zend_result php_pgsql_select(PGconn *pg_link, const zend_string *t PQclear(pg_result); cleanup: - zval_ptr_dtor(&ids_converted); + if (is_valid_ids_array) { + zval_ptr_dtor(&ids_converted); + } if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) { *sql = querystr.s; } @@ -5828,7 +5835,8 @@ PHP_PGSQL_API zend_result php_pgsql_select(PGconn *pg_link, const zend_string *t /* {{{ Select records that has ids (id=>value) */ PHP_FUNCTION(pg_select) { - zval *pgsql_link, *ids; + zval *pgsql_link; + zval *ids = NULL; pgsql_link_handle *link; zend_string *table; zend_ulong option = PGSQL_DML_EXEC; @@ -5837,7 +5845,7 @@ PHP_FUNCTION(pg_select) zend_string *sql = NULL; /* TODO Document result_type param on php.net (apparently it was added in PHP 7.1) */ - if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|ll", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP|all", &pgsql_link, pgsql_link_ce, &table, &ids, &option, &result_type ) == FAILURE) { RETURN_THROWS(); diff --git a/ext/pgsql/pgsql.stub.php b/ext/pgsql/pgsql.stub.php index 7ce709d17e2d8..c19409be50388 100644 --- a/ext/pgsql/pgsql.stub.php +++ b/ext/pgsql/pgsql.stub.php @@ -961,7 +961,7 @@ function pg_delete(PgSql\Connection $connection, string $table_name, array $cond * @return array|string|false * @refcount 1 */ - function pg_select(PgSql\Connection $connection, string $table_name, array $conditions, int $flags = PGSQL_DML_EXEC, int $mode = PGSQL_ASSOC): array|string|false {} + function pg_select(PgSql\Connection $connection, string $table_name, array $conditions = [], int $flags = PGSQL_DML_EXEC, int $mode = PGSQL_ASSOC): array|string|false {} #ifdef LIBPQ_HAS_PIPELINING function pg_enter_pipeline_mode(PgSql\Connection $connection): bool {} diff --git a/ext/pgsql/pgsql_arginfo.h b/ext/pgsql/pgsql_arginfo.h index 6f035f19246cf..8f95b6f8e2821 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: 29e402e7c708a25c99a4b2df0e858ea65a221e9b */ 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) @@ -444,10 +444,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_pg_delete, 0, 3, MAY_BE_STRING|M ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "PGSQL_DML_EXEC") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_pg_select, 0, 3, MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_FALSE) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_pg_select, 0, 2, MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_FALSE) ZEND_ARG_OBJ_INFO(0, connection, PgSql\\Connection, 0) ZEND_ARG_TYPE_INFO(0, table_name, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, conditions, IS_ARRAY, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, conditions, IS_ARRAY, 0, "[]") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "PGSQL_DML_EXEC") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "PGSQL_ASSOC") ZEND_END_ARG_INFO() diff --git a/ext/pgsql/tests/pg_select_001.phpt b/ext/pgsql/tests/pg_select_001.phpt index 838182740dcd9..e3fb8b1eeaf27 100644 --- a/ext/pgsql/tests/pg_select_001.phpt +++ b/ext/pgsql/tests/pg_select_001.phpt @@ -36,6 +36,12 @@ var_dump(pg_select($conn, 'phptests.bar', array('id4' => 4))); /* Use a different result type */ var_dump(pg_select($conn, 'phptests.bar', array('id4' => 4), 0, PGSQL_NUM)); +/* Empty array */ +var_dump(pg_select($conn, 'phptests.bar', array())); + +/* No array */ +var_dump(pg_select($conn, 'phptests.bar')); + pg_query($conn, 'DROP TABLE phptests.foo'); pg_query($conn, 'DROP TABLE phptests.bar'); pg_query($conn, 'DROP SCHEMA phptests'); @@ -74,3 +80,35 @@ array(1) { string(1) "5" } } +array(2) { + [0]=> + array(2) { + ["id4"]=> + string(1) "4" + ["id3"]=> + string(1) "5" + } + [1]=> + array(2) { + ["id4"]=> + string(1) "6" + ["id3"]=> + string(1) "7" + } +} +array(2) { + [0]=> + array(2) { + ["id4"]=> + string(1) "4" + ["id3"]=> + string(1) "5" + } + [1]=> + array(2) { + ["id4"]=> + string(1) "6" + ["id3"]=> + string(1) "7" + } +}