diff --git a/ext/pgsql/config.m4 b/ext/pgsql/config.m4 index 48fbbae34ace0..c3f540cdd15d6 100644 --- a/ext/pgsql/config.m4 +++ b/ext/pgsql/config.m4 @@ -31,6 +31,9 @@ if test "$PHP_PGSQL" != "no"; then PHP_CHECK_LIBRARY([pq], [PQclosePrepared], [AC_DEFINE([HAVE_PG_CLOSE_STMT], [1], [PostgreSQL 17 or later])],, [$PGSQL_LIBS]) + PHP_CHECK_LIBRARY([pq], [PQresultVerboseErrorMessage], + [AC_DEFINE([HAVE_PG_RESULT_VERBOSE_ERROR_MESSAGE], [1], [PostgreSQL 14 or later])],, + [$PGSQL_LIBS]) old_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $PGSQL_CFLAGS" diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 3f16c2e88f2fa..bf3e5fc83b149 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -6347,3 +6347,39 @@ PHP_FUNCTION(pg_close_stmt) } } #endif + +#if defined(HAVE_PG_RESULT_VERBOSE_ERROR_MESSAGE) +PHP_FUNCTION(pg_result_verbose_error) +{ + zval *result; + pgsql_result_handle *pg_result; + zend_long verbosity, visibility; + char *err = NULL; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJECT_OF_CLASS(result, pgsql_result_ce) + Z_PARAM_LONG(verbosity) + Z_PARAM_LONG(visibility) + ZEND_PARSE_PARAMETERS_END(); + + if (!(verbosity & (PQERRORS_TERSE|PQERRORS_DEFAULT|PQERRORS_VERBOSE|PQERRORS_SQLSTATE))) { + zend_argument_value_error(2, "verbosity must be one of the PQERRORS_* constants"); + RETURN_THROWS(); + } + if (visibility < PQSHOW_CONTEXT_NEVER || !(visibility & (PQSHOW_CONTEXT_ERRORS|PQSHOW_CONTEXT_ALWAYS))) { + zend_argument_value_error(3, "visibility must be one of the PQSHOW_CONTEXT_* constants"); + RETURN_THROWS(); + } + + pg_result = Z_PGSQL_RESULT_P(result); + CHECK_PGSQL_RESULT(pg_result); + + err = PQresultVerboseErrorMessage(pg_result->result, verbosity, visibility); + if (UNEXPECTED(!err)) { + RETURN_FALSE; + } else { + RETVAL_STRING(err); + PQfreemem(err); + } +} +#endif diff --git a/ext/pgsql/pgsql.stub.php b/ext/pgsql/pgsql.stub.php index 22177fec367b3..722e07717118a 100644 --- a/ext/pgsql/pgsql.stub.php +++ b/ext/pgsql/pgsql.stub.php @@ -973,6 +973,10 @@ function pg_set_chunked_rows_size(PgSql\Connection $connection, int $size): bool #ifdef HAVE_PG_CLOSE_STMT function pg_close_stmt(Pgsql\Connection $connection, string $statement_name): Pgsql\Result|false {} #endif +#ifdef HAVE_PG_RESULT_ERROR_MESSAGE + /** @refcount 1 */ + function pg_result_verbose_error(PgSql\Result $result, int $verbosity, int $visibility): string|false {} +#endif } namespace PgSql { diff --git a/ext/pgsql/pgsql_arginfo.h b/ext/pgsql/pgsql_arginfo.h index cb79f83971301..7867643470d30 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: 13be2a3c9a4ef4a72c0a67019b7400418752b603 */ + * Stub hash: d2d1653309c442627202d28ae27dcb4d6a828a24 */ 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) @@ -502,6 +502,14 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pg_close_stmt, 0, 2, Pgsql\\ ZEND_END_ARG_INFO() #endif +#if defined(HAVE_PG_RESULT_ERROR_MESSAGE) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_pg_result_verbose_error, 0, 3, MAY_BE_STRING|MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, result, PgSql\\Result, 0) + ZEND_ARG_TYPE_INFO(0, verbosity, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, visibility, IS_LONG, 0) +ZEND_END_ARG_INFO() +#endif + ZEND_FUNCTION(pg_connect); ZEND_FUNCTION(pg_pconnect); ZEND_FUNCTION(pg_connect_poll); @@ -608,6 +616,9 @@ ZEND_FUNCTION(pg_set_chunked_rows_size); #if defined(HAVE_PG_CLOSE_STMT) ZEND_FUNCTION(pg_close_stmt); #endif +#if defined(HAVE_PG_RESULT_ERROR_MESSAGE) +ZEND_FUNCTION(pg_result_verbose_error); +#endif static const zend_function_entry ext_functions[] = { ZEND_FE(pg_connect, arginfo_pg_connect) @@ -738,6 +749,9 @@ static const zend_function_entry ext_functions[] = { #endif #if defined(HAVE_PG_CLOSE_STMT) ZEND_FE(pg_close_stmt, arginfo_pg_close_stmt) +#endif +#if defined(HAVE_PG_RESULT_ERROR_MESSAGE) + ZEND_FE(pg_result_verbose_error, arginfo_pg_result_verbose_error) #endif ZEND_FE_END };