Skip to content

ext/pgsql: adding cache for the tables meta data. #11193

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 92 additions & 33 deletions ext/pgsql/pgsql.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@ PHP_RINIT_FUNCTION(pgsql)
PGG(num_links) = PGG(num_persistent);
zend_hash_init(&PGG(field_oids), 0, NULL, release_string, 0);
zend_hash_init(&PGG(table_oids), 0, NULL, release_string, 0);
zend_hash_init(&PGG(meta), 0, NULL, NULL, 0);
zend_hash_init(&PGG(meta_extended), 0, NULL, NULL, 0);
return SUCCESS;
}

Expand All @@ -506,6 +508,8 @@ PHP_RSHUTDOWN_FUNCTION(pgsql)

zend_hash_destroy(&PGG(field_oids));
zend_hash_destroy(&PGG(table_oids));
zend_hash_destroy(&PGG(meta));
zend_hash_destroy(&PGG(meta_extended));
/* clean up persistent connection */
zend_hash_apply(&EG(persistent_list), (apply_func_t) _rollback_transactions);
return SUCCESS;
Expand Down Expand Up @@ -4147,20 +4151,45 @@ PHP_FUNCTION(pg_flush)

/* {{{ php_pgsql_meta_data
* table_name must not be empty
* TODO: Add meta_data cache for better performance
*/
PHP_PGSQL_API zend_result php_pgsql_meta_data(PGconn *pg_link, const zend_string *table_name, zval *meta, bool extended)
PHP_PGSQL_API zend_result php_pgsql_meta_data(PGconn *pg_link, zend_string *table_name, zval *meta, bool extended, bool invalcache)
{
PGresult *pg_result;
char *src, *tmp_name, *tmp_name2 = NULL;
char *escaped;
smart_str querystr = {0};
size_t new_len;
int i, num_rows;
zval elem;
zend_string *field;
zval elem, nmeta, *tmp, *nelem, *val;
HashTable *zmeta;

const char pg_cache_field[] = "pg_meta_data_cached";

ZEND_ASSERT(ZSTR_LEN(table_name) != 0);

zmeta = (extended ? &PGG(meta_extended) : &PGG(meta));

if ((tmp = zend_hash_find(zmeta, table_name)) != NULL) {
if (!invalcache) {
ZVAL_COPY_VALUE(meta, tmp);
nelem = zend_hash_str_find(Z_ARR_P(meta), pg_cache_field, sizeof(pg_cache_field) - 1);
ZEND_ASSERT(nelem != NULL);
if (Z_TYPE_INFO_P(nelem) == IS_FALSE) {
ZVAL_BOOL(nelem, true);
}
zval_addref_p(tmp);
return SUCCESS;
} else {
ZEND_HASH_FOREACH_STR_KEY_VAL(&PGG(meta), field, val) {
zend_hash_del(&PGG(meta), field);
} ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_STR_KEY_VAL(&PGG(meta_extended), field, val) {
zend_hash_del(&PGG(meta_extended), field);
} ZEND_HASH_FOREACH_END();
}
}

src = estrdup(ZSTR_VAL(table_name));
tmp_name = php_strtok_r(src, ".", &tmp_name2);
if (!tmp_name) {
Expand Down Expand Up @@ -4250,6 +4279,31 @@ PHP_PGSQL_API zend_result php_pgsql_meta_data(PGconn *pg_link, const zend_string
name = PQgetvalue(pg_result,i,0);
add_assoc_zval(meta, name, &elem);
}

add_assoc_bool_ex(meta, pg_cache_field, sizeof(pg_cache_field) - 1, false);

tmp = zend_hash_add(zmeta, table_name, &nmeta);
array_init_size(tmp, zend_hash_num_elements(Z_ARR_P(meta)));

ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARR_P(meta), field, val) {
ZVAL_DEREF(val);
if (Z_TYPE_P(val) != IS_ARRAY) {
zend_hash_update(Z_ARR_P(tmp), field, val);
} else {
zend_string *sfield;
zval *nelem, *sval, ntmp;

zend_string_delref(field);
nelem = zend_hash_add(Z_ARR_P(tmp), field, &ntmp);
array_init_size(nelem, zend_hash_num_elements(Z_ARR_P(val)));

ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARR_P(val), sfield, sval) {
zend_string_delref(sfield);
zend_hash_update(Z_ARR_P(nelem), sfield, sval);
} ZEND_HASH_FOREACH_END();
}
} ZEND_HASH_FOREACH_END();

PQclear(pg_result);

return SUCCESS;
Expand All @@ -4263,11 +4317,11 @@ PHP_FUNCTION(pg_meta_data)
zval *pgsql_link;
pgsql_link_handle *link;
zend_string *table_name;
bool extended=0;
bool extended=0, invalcache=0;
PGconn *pgsql;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP|b",
&pgsql_link, pgsql_link_ce, &table_name, &extended) == FAILURE
if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP|bb",
&pgsql_link, pgsql_link_ce, &table_name, &extended, &invalcache) == FAILURE
) {
RETURN_THROWS();
}
Expand All @@ -4283,7 +4337,7 @@ PHP_FUNCTION(pg_meta_data)
}

array_init(return_value);
if (php_pgsql_meta_data(pgsql, table_name, return_value, extended) == FAILURE) {
if (php_pgsql_meta_data(pgsql, table_name, return_value, extended, invalcache) == FAILURE) {
zend_array_destroy(Z_ARR_P(return_value)); /* destroy array */
RETURN_FALSE;
}
Expand Down Expand Up @@ -4459,7 +4513,7 @@ static zend_string *php_pgsql_add_quotes(zend_string *src)
/* {{{ php_pgsql_convert
* check and convert array values (fieldname=>value pair) for sql
*/
PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *table_name, const zval *values, zval *result, zend_ulong opt)
PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, zend_string *table_name, const zval *values, zval *result, zend_ulong opt, bool invalcache)
{
zend_string *field = NULL;
zval meta, *def, *type, *not_null, *has_default, *is_enum, *val, new_val;
Expand All @@ -4476,7 +4530,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *

array_init(&meta);
/* table_name is escaped by php_pgsql_meta_data */
if (php_pgsql_meta_data(pg_link, table_name, &meta, 0) == FAILURE) {
if (php_pgsql_meta_data(pg_link, table_name, &meta, 0, invalcache) == FAILURE) {
zval_ptr_dtor(&meta);
return FAILURE;
}
Expand Down Expand Up @@ -5112,9 +5166,10 @@ PHP_FUNCTION(pg_convert)
pgsql_link_handle *link;
zend_string *table_name;
zend_ulong option = 0;
bool invalcache=0;
PGconn *pg_link;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|l", &pgsql_link, pgsql_link_ce, &table_name, &values, &option) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|lb", &pgsql_link, pgsql_link_ce, &table_name, &values, &option, &invalcache) == FAILURE) {
RETURN_THROWS();
}

Expand All @@ -5137,7 +5192,7 @@ PHP_FUNCTION(pg_convert)
php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
}
array_init(return_value);
if (php_pgsql_convert(pg_link, table_name, values, return_value, option) == FAILURE) {
if (php_pgsql_convert(pg_link, table_name, values, return_value, option, invalcache) == FAILURE) {
zend_array_destroy(Z_ARR_P(return_value));
RETURN_FALSE;
}
Expand Down Expand Up @@ -5198,7 +5253,7 @@ static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const z
/* }}} */

/* {{{ php_pgsql_insert */
PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *table, zval *var_array, zend_ulong opt, zend_string **sql)
PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, zend_string *table, zval *var_array, zend_ulong opt, zend_string **sql, bool invalcache)
{
zval *val, converted;
char buf[256];
Expand All @@ -5223,7 +5278,7 @@ PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *t
/* convert input array if needed */
if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
array_init(&converted);
if (php_pgsql_convert(pg_link, table, var_array, &converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
if (php_pgsql_convert(pg_link, table, var_array, &converted, (opt & PGSQL_CONV_OPTS), invalcache) == FAILURE) {
goto cleanup;
}
var_array = &converted;
Expand Down Expand Up @@ -5322,9 +5377,10 @@ PHP_FUNCTION(pg_insert)
PGresult *pg_result;
ExecStatusType status;
zend_string *sql = NULL;
bool invalcache=0;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|l",
&pgsql_link, pgsql_link_ce, &table, &values, &option) == FAILURE
if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|lb",
&pgsql_link, pgsql_link_ce, &table, &values, &option, &invalcache) == FAILURE
) {
RETURN_THROWS();
}
Expand All @@ -5351,7 +5407,7 @@ PHP_FUNCTION(pg_insert)
if (option & PGSQL_DML_EXEC) {
/* return object when executed */
option = option & ~PGSQL_DML_EXEC;
if (php_pgsql_insert(pg_link, table, values, option|PGSQL_DML_STRING, &sql) == FAILURE) {
if (php_pgsql_insert(pg_link, table, values, option|PGSQL_DML_STRING, &sql, invalcache) == FAILURE) {
RETURN_FALSE;
}
pg_result = PQexec(pg_link, ZSTR_VAL(sql));
Expand Down Expand Up @@ -5392,7 +5448,7 @@ PHP_FUNCTION(pg_insert)
}
break;
}
} else if (php_pgsql_insert(pg_link, table, values, option, &sql) == FAILURE) {
} else if (php_pgsql_insert(pg_link, table, values, option, &sql, invalcache) == FAILURE) {
RETURN_FALSE;
}
if (return_sql) {
Expand Down Expand Up @@ -5466,7 +5522,7 @@ static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr,
/* }}} */

/* {{{ php_pgsql_update */
PHP_PGSQL_API zend_result php_pgsql_update(PGconn *pg_link, const zend_string *table, zval *var_array, zval *ids_array, zend_ulong opt, zend_string **sql)
PHP_PGSQL_API zend_result php_pgsql_update(PGconn *pg_link, zend_string *table, zval *var_array, zval *ids_array, zend_ulong opt, zend_string **sql, bool invalcache)
{
zval var_converted, ids_converted;
smart_str querystr = {0};
Expand All @@ -5487,12 +5543,12 @@ PHP_PGSQL_API zend_result php_pgsql_update(PGconn *pg_link, const zend_string *t
ZVAL_UNDEF(&ids_converted);
if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
array_init(&var_converted);
if (php_pgsql_convert(pg_link, table, var_array, &var_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
if (php_pgsql_convert(pg_link, table, var_array, &var_converted, (opt & PGSQL_CONV_OPTS), invalcache) == FAILURE) {
goto cleanup;
}
var_array = &var_converted;
array_init(&ids_converted);
if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS), invalcache) == FAILURE) {
goto cleanup;
}
ids_array = &ids_converted;
Expand Down Expand Up @@ -5541,9 +5597,10 @@ PHP_FUNCTION(pg_update)
zend_ulong option = PGSQL_DML_EXEC;
PGconn *pg_link;
zend_string *sql = NULL;
bool invalcache=0;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPaa|l",
&pgsql_link, pgsql_link_ce, &table, &values, &ids, &option) == FAILURE
if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPaa|lb",
&pgsql_link, pgsql_link_ce, &table, &values, &ids, &option, &invalcache) == FAILURE
) {
RETURN_THROWS();
}
Expand All @@ -5566,7 +5623,7 @@ PHP_FUNCTION(pg_update)
if (php_pgsql_flush_query(pg_link)) {
php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
}
if (php_pgsql_update(pg_link, table, values, ids, option, &sql) == FAILURE) {
if (php_pgsql_update(pg_link, table, values, ids, option, &sql, invalcache) == FAILURE) {
RETURN_FALSE;
}
if (option & PGSQL_DML_STRING) {
Expand All @@ -5577,7 +5634,7 @@ PHP_FUNCTION(pg_update)
/* }}} */

/* {{{ php_pgsql_delete */
PHP_PGSQL_API zend_result php_pgsql_delete(PGconn *pg_link, const zend_string *table, zval *ids_array, zend_ulong opt, zend_string **sql)
PHP_PGSQL_API zend_result php_pgsql_delete(PGconn *pg_link, zend_string *table, zval *ids_array, zend_ulong opt, zend_string **sql, bool invalcache)
{
zval ids_converted;
smart_str querystr = {0};
Expand All @@ -5595,7 +5652,7 @@ PHP_PGSQL_API zend_result php_pgsql_delete(PGconn *pg_link, const zend_string *t
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) {
if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS), invalcache) == FAILURE) {
goto cleanup;
}
ids_array = &ids_converted;
Expand Down Expand Up @@ -5638,9 +5695,10 @@ PHP_FUNCTION(pg_delete)
zend_ulong option = PGSQL_DML_EXEC;
PGconn *pg_link;
zend_string *sql;
bool invalcache=0;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|l",
&pgsql_link, pgsql_link_ce, &table, &ids, &option
if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|lb",
&pgsql_link, pgsql_link_ce, &table, &ids, &option, &invalcache
) == FAILURE) {
RETURN_THROWS();
}
Expand All @@ -5663,7 +5721,7 @@ PHP_FUNCTION(pg_delete)
if (php_pgsql_flush_query(pg_link)) {
php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
}
if (php_pgsql_delete(pg_link, table, ids, option, &sql) == FAILURE) {
if (php_pgsql_delete(pg_link, table, ids, option, &sql, invalcache) == FAILURE) {
RETURN_FALSE;
}
if (option & PGSQL_DML_STRING) {
Expand Down Expand Up @@ -5715,7 +5773,7 @@ PHP_PGSQL_API void php_pgsql_result2array(PGresult *pg_result, zval *ret_array,
/* }}} */

/* {{{ php_pgsql_select */
PHP_PGSQL_API zend_result php_pgsql_select(PGconn *pg_link, const zend_string *table, zval *ids_array, zval *ret_array, zend_ulong opt, long result_type, zend_string **sql)
PHP_PGSQL_API zend_result php_pgsql_select(PGconn *pg_link, zend_string *table, zval *ids_array, zval *ret_array, zend_ulong opt, long result_type, zend_string **sql, bool invalcache)
{
zval ids_converted;
smart_str querystr = {0};
Expand All @@ -5735,7 +5793,7 @@ PHP_PGSQL_API zend_result php_pgsql_select(PGconn *pg_link, const zend_string *t
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) {
if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS), invalcache) == FAILURE) {
goto cleanup;
}
ids_array = &ids_converted;
Expand Down Expand Up @@ -5782,10 +5840,11 @@ PHP_FUNCTION(pg_select)
zend_long result_type = PGSQL_ASSOC;
PGconn *pg_link;
zend_string *sql = NULL;
bool invalcache=0;

/* 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",
&pgsql_link, pgsql_link_ce, &table, &ids, &option, &result_type
if (zend_parse_parameters(ZEND_NUM_ARGS(), "OPa|llb",
&pgsql_link, pgsql_link_ce, &table, &ids, &option, &result_type, &invalcache
) == FAILURE) {
RETURN_THROWS();
}
Expand Down Expand Up @@ -5813,7 +5872,7 @@ PHP_FUNCTION(pg_select)
php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
}
array_init(return_value);
if (php_pgsql_select(pg_link, table, ids, return_value, option, result_type, &sql) == FAILURE) {
if (php_pgsql_select(pg_link, table, ids, return_value, option, result_type, &sql, invalcache) == FAILURE) {
zval_ptr_dtor(return_value);
RETURN_FALSE;
}
Expand Down
12 changes: 6 additions & 6 deletions ext/pgsql/pgsql.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -922,28 +922,28 @@ function pg_flush(PgSql\Connection $connection): int|bool {}
* @return array<string, array>|false
* @refcount 1
*/
function pg_meta_data(PgSql\Connection $connection, string $table_name, bool $extended = false): array|false {}
function pg_meta_data(PgSql\Connection $connection, string $table_name, bool $extended = false, bool $invalcache = false): array|false {}

/**
* @return array<string, mixed>|false
* @refcount 1
*/
function pg_convert(PgSql\Connection $connection, string $table_name, array $values, int $flags = 0): array|false {}
function pg_convert(PgSql\Connection $connection, string $table_name, array $values, int $flags = 0, bool $invalcache = false): array|false {}

/** @refcount 1 */
function pg_insert(PgSql\Connection $connection, string $table_name, array $values, int $flags = PGSQL_DML_EXEC): PgSql\Result|string|bool {}
function pg_insert(PgSql\Connection $connection, string $table_name, array $values, int $flags = PGSQL_DML_EXEC, bool $invalcache = false): PgSql\Result|string|bool {}

/** @refcount 1 */
function pg_update(PgSql\Connection $connection, string $table_name, array $values, array $conditions, int $flags = PGSQL_DML_EXEC): string|bool {}
function pg_update(PgSql\Connection $connection, string $table_name, array $values, array $conditions, int $flags = PGSQL_DML_EXEC, bool $invalcache = false): string|bool {}

/** @refcount 1 */
function pg_delete(PgSql\Connection $connection, string $table_name, array $conditions, int $flags = PGSQL_DML_EXEC): string|bool {}
function pg_delete(PgSql\Connection $connection, string $table_name, array $conditions, int $flags = PGSQL_DML_EXEC, bool $invalcache = false): string|bool {}

/**
* @return array<int, 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, bool $invalcache = false): array|string|false {}

#ifdef LIBPQ_HAS_PIPELINING
function pg_enter_pipeline_mode(PgSql\Connection $connection): bool {}
Expand Down
Loading