diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index ae5f5505fc8..a039c835abc 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -112,7 +112,7 @@ ZEND_TSRMLS_CACHE_DEFINE() ZEND_GET_MODULE(pgsql) #endif -static int le_link, le_plink, le_result, le_lofp, le_string; +static int le_link, le_plink, le_result, le_lofp; /* Compatibility definitions */ @@ -278,9 +278,9 @@ static void _free_result(zend_resource *rsrc) } /* }}} */ -static void release_string(zend_resource *rsrc) +static void release_string(zval *zv) { - zend_string_release((zend_string *) rsrc->ptr); + zend_string_release((zend_string *) Z_PTR_P(zv)); } static bool _php_pgsql_identifier_is_escaped(const char *identifier, size_t len) /* {{{ */ @@ -356,7 +356,6 @@ PHP_MINIT_FUNCTION(pgsql) le_plink = zend_register_list_destructors_ex(NULL, _close_pgsql_plink, "pgsql link persistent", module_number); le_result = zend_register_list_destructors_ex(_free_result, NULL, "pgsql result", module_number); le_lofp = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql large object", module_number); - le_string = zend_register_list_destructors_ex(release_string, NULL, "pgsql string", module_number); /* libpq version */ php_libpq_version(buf, sizeof(buf)); REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION", buf, CONST_CS | CONST_PERSISTENT); @@ -480,6 +479,8 @@ PHP_RINIT_FUNCTION(pgsql) { PGG(default_link) = NULL; 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); return SUCCESS; } /* }}} */ @@ -490,6 +491,8 @@ PHP_RSHUTDOWN_FUNCTION(pgsql) /* clean up notice messages */ zend_hash_clean(&PGG(notices)); zend_hash_clean(&PGG(hashes)); + zend_hash_destroy(&PGG(field_oids)); + zend_hash_destroy(&PGG(table_oids)); /* clean up persistent connection */ zend_hash_apply(&EG(persistent_list), (apply_func_t) _rollback_transactions); return SUCCESS; @@ -1481,61 +1484,47 @@ static inline bool is_valid_oid_string(zend_string *oid, Oid *return_oid) } /* {{{ get_field_name */ -static zend_string *get_field_name(PGconn *pgsql, Oid oid, HashTable *list) +static zend_string *get_field_name(PGconn *pgsql, Oid oid) { - smart_str str = {0}; - zend_resource *field_type; - zend_string *ret = NULL; - - /* try to lookup the type in the resource list */ - smart_str_appends(&str, "pgsql_oid_"); - smart_str_append_unsigned(&str, oid); - smart_str_0(&str); - - if ((field_type = zend_hash_find_ptr(list, str.s)) != NULL) { - ret = zend_string_copy((zend_string *) field_type->ptr); - } else { /* hash all oid's */ - int i, num_rows; - int oid_offset,name_offset; - char *tmp_oid, *end_ptr, *tmp_name; - zend_resource new_oid_entry; - PGresult *result; - - if ((result = PQexec(pgsql, "select oid,typname from pg_type")) == NULL || PQresultStatus(result) != PGRES_TUPLES_OK) { - if (result) { - PQclear(result); - } - smart_str_free(&str); - return ZSTR_EMPTY_ALLOC(); - } - num_rows = PQntuples(result); - oid_offset = PQfnumber(result,"oid"); - name_offset = PQfnumber(result,"typname"); - - for (i=0; iresult, (int)fnum); - + Oid oid = PQftable(pg_result->result, (int)fnum); if (InvalidOid == oid) { RETURN_FALSE; } @@ -1580,49 +1564,37 @@ PHP_FUNCTION(pg_field_table) PGSQL_RETURN_OID(oid); } - /* try to lookup the table name in the resource list */ - smart_str_appends(&hash_key, "pgsql_table_oid_"); - smart_str_append_unsigned(&hash_key, oid); - smart_str_0(&hash_key); - - if ((field_table = zend_hash_find_ptr(&EG(regular_list), hash_key.s)) != NULL) { - smart_str_free(&hash_key); - RETURN_STR_COPY((zend_string *)field_table->ptr); - } else { /* Not found, lookup by querying PostgreSQL system tables */ - PGresult *tmp_res; - smart_str querystr = {0}; - zend_resource new_field_table; - - smart_str_appends(&querystr, "select relname from pg_class where oid="); - smart_str_append_unsigned(&querystr, oid); - smart_str_0(&querystr); - - if ((tmp_res = PQexec(pg_result->conn, ZSTR_VAL(querystr.s))) == NULL || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) { - if (tmp_res) { - PQclear(tmp_res); - } - smart_str_free(&querystr); - smart_str_free(&hash_key); - RETURN_FALSE; - } - - smart_str_free(&querystr); - - if ((table_name = PQgetvalue(tmp_res, 0, 0)) == NULL) { - PQclear(tmp_res); - smart_str_free(&hash_key); - RETURN_FALSE; - } - - new_field_table.type = le_string; - new_field_table.ptr = zend_string_init(table_name, strlen(table_name), 0); - zend_hash_update_mem(&EG(regular_list), hash_key.s, (void *)&new_field_table, sizeof(zend_resource)); - - smart_str_free(&hash_key); - PQclear(tmp_res); - RETURN_STR_COPY(new_field_table.ptr); + zend_string *field_table = zend_hash_index_find_ptr(&PGG(table_oids), oid); + if (field_table) { + RETURN_STR_COPY(field_table); } + /* Not found, lookup by querying PostgreSQL system tables */ + smart_str querystr = {0}; + smart_str_appends(&querystr, "select relname from pg_class where oid="); + smart_str_append_unsigned(&querystr, oid); + smart_str_0(&querystr); + + PGresult *tmp_res = PQexec(pg_result->conn, ZSTR_VAL(querystr.s)); + smart_str_free(&querystr); + if (!tmp_res || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) { + if (tmp_res) { + PQclear(tmp_res); + } + RETURN_FALSE; + } + + char *table_name = PQgetvalue(tmp_res, 0, 0); + if (!table_name) { + PQclear(tmp_res); + RETURN_FALSE; + } + + field_table = zend_string_init(table_name, strlen(table_name), 0); + zend_hash_index_update_ptr(&PGG(table_oids), oid, field_table); + + PQclear(tmp_res); + RETURN_STR_COPY(field_table); } /* }}} */ @@ -1668,8 +1640,7 @@ static void php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_typ RETURN_LONG(PQfsize(pgsql_result, (int)field)); break; case PHP_PG_FIELD_TYPE: - RETURN_STR(get_field_name( - pg_result->conn, PQftype(pgsql_result, (int)field), &EG(regular_list))); + RETURN_STR(get_field_name(pg_result->conn, PQftype(pgsql_result, (int)field))); break; case PHP_PG_FIELD_TYPE_OID: diff --git a/ext/pgsql/php_pgsql.h b/ext/pgsql/php_pgsql.h index 4280c2a3481..79fbc66c065 100644 --- a/ext/pgsql/php_pgsql.h +++ b/ext/pgsql/php_pgsql.h @@ -283,6 +283,8 @@ ZEND_BEGIN_MODULE_GLOBALS(pgsql) HashTable notices; /* notice message for each connection */ zend_resource *default_link; /* default link when connection is omitted */ HashTable hashes; /* hashes for each connection */ + HashTable field_oids; + HashTable table_oids; ZEND_END_MODULE_GLOBALS(pgsql) ZEND_EXTERN_MODULE_GLOBALS(pgsql)