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

ext/pdo_pgsql: Retrieve the memory usage of the query result resource (#14260)

`getAttribute()` can now retrieve the memory usage of query results.
`PDO::PGSQL_ATTR_RESULT_MEMORY_SIZE` was added for this feature.

closes #14260
This commit is contained in:
武田 憲太郎
2024-05-15 11:15:33 +00:00
committed by Saki Takamachi
parent ba534e70e6
commit b7dd3d8347
9 changed files with 96 additions and 2 deletions

1
NEWS
View File

@@ -175,6 +175,7 @@ PHP NEWS
PDO constructor arguments. (SakiTakamachi)
. Fixed native float support with pdo_pgsql query results. (Yurunsoft)
. Added class PdoPgsql. (danack, kocsismate)
. Retrieve the memory usage of the query result resource. (KentarouTakeda)
- PDO_SQLITE:
. Added class PdoSqlite. (danack, kocsismate)

View File

@@ -421,6 +421,10 @@ PHP 8.4 UPGRADE NOTES
- PDO_MYSQL:
. getAttribute, enabled to get the value of ATTR_FETCH_TABLE_NAMES.
- PDO_PGSQL:
. getAttribute() can now retrieve the memory usage of query results.
PDO::PGSQL_ATTR_RESULT_MEMORY_SIZE was added for this feature.
- PGSQL:
. pg_select, the conditions arguments accepts an empty array and is optional.

View File

@@ -67,6 +67,7 @@ if test "$PHP_PDO_PGSQL" != "no"; then
LDFLAGS="-L$PGSQL_LIBDIR $LDFLAGS"
AC_CHECK_LIB(pq, PQlibVersion,, AC_MSG_ERROR([Unable to build the PDO PostgreSQL driver: at least libpq 9.1 is required]))
AC_CHECK_LIB(pq, PQresultMemorySize, AC_DEFINE(HAVE_PG_RESULT_MEMORY_SIZE,1,[PostgreSQL 12 or later]))
LIBS=$old_LIBS
LDFLAGS=$old_LDFLAGS

View File

@@ -156,6 +156,9 @@ PHP_MINIT_FUNCTION(pdo_pgsql)
REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_INTRANS", (zend_long)PGSQL_TRANSACTION_INTRANS);
REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_INERROR", (zend_long)PGSQL_TRANSACTION_INERROR);
REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_UNKNOWN", (zend_long)PGSQL_TRANSACTION_UNKNOWN);
#ifdef HAVE_PG_RESULT_MEMORY_SIZE
REGISTER_PDO_CLASS_CONST_LONG("PGSQL_ATTR_RESULT_MEMORY_SIZE", (zend_long)PDO_PGSQL_ATTR_RESULT_MEMORY_SIZE);
#endif
PdoPgsql_ce = register_class_PdoPgsql(pdo_dbh_ce);
PdoPgsql_ce->create_object = pdo_dbh_new;

View File

@@ -11,6 +11,11 @@ class PdoPgsql extends PDO
/** @cvalue PDO_PGSQL_ATTR_DISABLE_PREPARES */
public const int ATTR_DISABLE_PREPARES = UNKNOWN;
#ifdef HAVE_PG_RESULT_MEMORY_SIZE
/** @cvalue PDO_PGSQL_ATTR_RESULT_MEMORY_SIZE */
public const int ATTR_RESULT_MEMORY_SIZE = UNKNOWN;
#endif
/** @cvalue PGSQL_TRANSACTION_IDLE */
public const int TRANSACTION_IDLE = UNKNOWN;

View File

@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 2be4e9679d29fcbc3330b78f9e63c4c6e1284f19 */
* Stub hash: 57eb44ac4546230b33165b7226b05d006b651e46 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PdoPgsql_escapeIdentifier, 0, 1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, input, IS_STRING, 0)
@@ -88,6 +88,14 @@ static zend_class_entry *register_class_PdoPgsql(zend_class_entry *class_entry_P
zend_string *const_ATTR_DISABLE_PREPARES_name = zend_string_init_interned("ATTR_DISABLE_PREPARES", sizeof("ATTR_DISABLE_PREPARES") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_DISABLE_PREPARES_name, &const_ATTR_DISABLE_PREPARES_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_DISABLE_PREPARES_name);
#if defined(HAVE_PG_RESULT_MEMORY_SIZE)
zval const_ATTR_RESULT_MEMORY_SIZE_value;
ZVAL_LONG(&const_ATTR_RESULT_MEMORY_SIZE_value, PDO_PGSQL_ATTR_RESULT_MEMORY_SIZE);
zend_string *const_ATTR_RESULT_MEMORY_SIZE_name = zend_string_init_interned("ATTR_RESULT_MEMORY_SIZE", sizeof("ATTR_RESULT_MEMORY_SIZE") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_RESULT_MEMORY_SIZE_name, &const_ATTR_RESULT_MEMORY_SIZE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_RESULT_MEMORY_SIZE_name);
#endif
zval const_TRANSACTION_IDLE_value;
ZVAL_LONG(&const_TRANSACTION_IDLE_value, PGSQL_TRANSACTION_IDLE);

View File

@@ -705,6 +705,32 @@ static int pdo_pgsql_stmt_cursor_closer(pdo_stmt_t *stmt)
return 1;
}
static int pgsql_stmt_get_attr(pdo_stmt_t *stmt, zend_long attr, zval *val)
{
pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
switch (attr) {
#ifdef HAVE_PG_RESULT_MEMORY_SIZE
case PDO_PGSQL_ATTR_RESULT_MEMORY_SIZE:
if(stmt->executed) {
ZVAL_LONG(val, PQresultMemorySize(S->result));
} else {
char *tmp;
spprintf(&tmp, 0, "statement '%s' has not been executed yet", S->stmt_name);
pdo_pgsql_error_stmt_msg(stmt, 0, "HY000", tmp);
efree(tmp);
ZVAL_NULL(val);
}
return 1;
#endif
default:
return 0;
}
}
const struct pdo_stmt_methods pgsql_stmt_methods = {
pgsql_stmt_dtor,
pgsql_stmt_execute,
@@ -713,7 +739,7 @@ const struct pdo_stmt_methods pgsql_stmt_methods = {
pgsql_stmt_get_col,
pgsql_stmt_param_hook,
NULL, /* set_attr */
NULL, /* get_attr */
pgsql_stmt_get_attr,
pgsql_stmt_get_column_meta,
NULL, /* next_rowset */
pdo_pgsql_stmt_cursor_closer

View File

@@ -86,6 +86,7 @@ extern const struct pdo_stmt_methods pgsql_stmt_methods;
enum {
PDO_PGSQL_ATTR_DISABLE_PREPARES = PDO_ATTR_DRIVER_SPECIFIC,
PDO_PGSQL_ATTR_RESULT_MEMORY_SIZE,
};
struct pdo_pgsql_lob_self {

View File

@@ -0,0 +1,45 @@
--TEST--
PDO PgSQL PDOStatement::getAttribute(PDO::PGSQL_ATTR_RESULT_MEMORY_SIZE)
--EXTENSIONS--
pdo_pgsql
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
require dirname(__DIR__, 2) . '/pdo/tests/pdo_test.inc';
PDOTest::skip();
if (!defined('PDO::PGSQL_ATTR_RESULT_MEMORY_SIZE')) die('skip constant PDO::PGSQL_ATTR_RESULT_MEMORY_SIZE does not exist');
--FILE--
<?php
require_once __DIR__ . "/config.inc";
/** @var Pdo */
$db = Pdo::connect($config['ENV']['PDOTEST_DSN']);
echo 'Result set with only 1 row: ';
$statement = $db->query('select 1');
$result_1 = $statement->getAttribute(PDO::PGSQL_ATTR_RESULT_MEMORY_SIZE);
var_dump($result_1);
echo 'Result set with many rows: ';
$result = $db->query('select generate_series(1, 10000)');
$result_2 = $result->getAttribute(PDO::PGSQL_ATTR_RESULT_MEMORY_SIZE);
var_dump($result_2);
echo 'Large result sets should require more memory than small ones: ';
var_dump($result_2 > $result_1);
echo 'Statements that are not executed should not consume memory: ';
$statement = $db->prepare('select 1');
$result_3 = $statement->getAttribute(PDO::PGSQL_ATTR_RESULT_MEMORY_SIZE);
var_dump($result_3);
echo 'and should emit Error: ';
printf("%s: %d: %s\n", ...$statement->errorInfo());
--EXPECTF--
Result set with only 1 row: int(%d)
Result set with many rows: int(%d)
Large result sets should require more memory than small ones: bool(true)
Statements that are not executed should not consume memory: NULL
and should emit Error: HY000: 0: statement '%s' has not been executed yet