diff options
Diffstat (limited to 'ext/pgsql/pgsql.c')
-rw-r--r-- | ext/pgsql/pgsql.c | 144 |
1 files changed, 99 insertions, 45 deletions
diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index e8e5a536f7..5c82fd8b43 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2015 The PHP Group | + | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -56,9 +56,13 @@ #define InvalidOid ((Oid) 0) #endif -#define PGSQL_ASSOC 1<<0 -#define PGSQL_NUM 1<<1 -#define PGSQL_BOTH (PGSQL_ASSOC|PGSQL_NUM) +#define PGSQL_ASSOC 1<<0 +#define PGSQL_NUM 1<<1 +#define PGSQL_BOTH (PGSQL_ASSOC|PGSQL_NUM) + +#define PGSQL_NOTICE_LAST 1 /* Get the last notice */ +#define PGSQL_NOTICE_ALL 2 /* Get all notices */ +#define PGSQL_NOTICE_CLEAR 3 /* Remove notices */ #define PGSQL_STATUS_LONG 1 #define PGSQL_STATUS_STRING 2 @@ -208,6 +212,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_notice, 0, 0, 1) ZEND_ARG_INFO(0, connection) + ZEND_ARG_INFO(0, option) ZEND_END_ARG_INFO() #ifdef HAVE_PQFTABLE @@ -276,6 +281,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all, 0, 0, 1) ZEND_ARG_INFO(0, result) + ZEND_ARG_INFO(0, result_type) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all_columns, 0, 0, 1) @@ -582,6 +588,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_select, 0, 0, 3) ZEND_ARG_INFO(0, table) ZEND_ARG_INFO(0, ids) ZEND_ARG_INFO(0, options) + ZEND_ARG_INFO(0, result_type) ZEND_END_ARG_INFO() /* }}} */ @@ -961,29 +968,24 @@ static void _close_pgsql_plink(zend_resource *rsrc) */ static void _php_pgsql_notice_handler(void *resource_id, const char *message) { - php_pgsql_notice *notice; + zval *notices; + zval tmp; + char *trimed_message; + size_t trimed_message_len; if (! PGG(ignore_notices)) { - notice = (php_pgsql_notice *)emalloc(sizeof(php_pgsql_notice)); - notice->message = _php_pgsql_trim_message(message, ¬ice->len); + notices = zend_hash_index_find(&PGG(notices), (zend_ulong)resource_id); + if (!notices) { + array_init(&tmp); + notices = &tmp; + zend_hash_index_update(&PGG(notices), (zend_ulong)resource_id, notices); + } + trimed_message = _php_pgsql_trim_message(message, &trimed_message_len); if (PGG(log_notices)) { - php_error_docref(NULL, E_NOTICE, "%s", notice->message); + php_error_docref(NULL, E_NOTICE, "%s", trimed_message); } - zend_hash_index_update_ptr(&PGG(notices), (zend_ulong)resource_id, notice); - } -} -/* }}} */ - -#define PHP_PGSQL_NOTICE_PTR_DTOR _php_pgsql_notice_ptr_dtor - -/* {{{ _php_pgsql_notice_dtor - */ -static void _php_pgsql_notice_ptr_dtor(zval *el) -{ - php_pgsql_notice *notice = (php_pgsql_notice *)Z_PTR_P(el); - if (notice) { - efree(notice->message); - efree(notice); + add_next_index_stringl(notices, trimed_message, trimed_message_len); + efree(trimed_message); } } /* }}} */ @@ -1096,7 +1098,7 @@ static PHP_GINIT_FUNCTION(pgsql) #endif memset(pgsql_globals, 0, sizeof(zend_pgsql_globals)); /* Initilize notice message hash at MINIT only */ - zend_hash_init_ex(&pgsql_globals->notices, 0, NULL, PHP_PGSQL_NOTICE_PTR_DTOR, 1, 0); + zend_hash_init_ex(&pgsql_globals->notices, 0, NULL, ZVAL_PTR_DTOR, 1, 0); } /* }}} */ @@ -1123,6 +1125,10 @@ PHP_MINIT_FUNCTION(pgsql) REGISTER_LONG_CONSTANT("PGSQL_ASSOC", PGSQL_ASSOC, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PGSQL_NUM", PGSQL_NUM, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PGSQL_BOTH", PGSQL_BOTH, CONST_CS | CONST_PERSISTENT); + /* For pg_last_notice() */ + REGISTER_LONG_CONSTANT("PGSQL_NOTICE_LAST", PGSQL_NOTICE_LAST, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PGSQL_NOTICE_ALL", PGSQL_NOTICE_ALL, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PGSQL_NOTICE_CLEAR", PGSQL_NOTICE_CLEAR, CONST_CS | CONST_PERSISTENT); /* For pg_connection_status() */ REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_BAD", CONNECTION_BAD, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_OK", CONNECTION_OK, CONST_CS | CONST_PERSISTENT); @@ -2306,15 +2312,16 @@ PHP_FUNCTION(pg_affected_rows) /* }}} */ #endif -/* {{{ proto string pg_last_notice(resource connection) +/* {{{ proto mixed pg_last_notice(resource connection [, long option]) Returns the last notice set by the backend */ PHP_FUNCTION(pg_last_notice) { zval *pgsql_link = NULL; + zval *notice, *notices; PGconn *pg_link; - php_pgsql_notice *notice; + zend_long option = PGSQL_NOTICE_LAST; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &pgsql_link, &option) == FAILURE) { return; } @@ -2323,10 +2330,38 @@ PHP_FUNCTION(pg_last_notice) RETURN_FALSE; } - if ((notice = zend_hash_index_find_ptr(&PGG(notices), (zend_ulong)Z_RES_HANDLE_P(pgsql_link))) == NULL) { - RETURN_FALSE; + notices = zend_hash_index_find(&PGG(notices), (zend_ulong)Z_RES_HANDLE_P(pgsql_link)); + switch (option) { + case PGSQL_NOTICE_LAST: + if (notices) { + zend_hash_internal_pointer_end(Z_ARRVAL_P(notices)); + if ((notice = zend_hash_get_current_data(Z_ARRVAL_P(notices))) == NULL) { + RETURN_EMPTY_STRING(); + } + RETURN_ZVAL(notice, 1, 0); + } else { + RETURN_EMPTY_STRING(); + } + break; + case PGSQL_NOTICE_ALL: + if (notices) { + RETURN_ZVAL(notices, 1, 0); + } else { + array_init(return_value); + return; + } + break; + case PGSQL_NOTICE_CLEAR: + if (notices) { + zend_hash_clean(&PGG(notices)); + } + RETURN_TRUE; + break; + default: + php_error_docref(NULL, E_WARNING, + "Invalid option specified (" ZEND_LONG_FMT ")", option); } - RETURN_STRINGL(notice->message, notice->len); + RETURN_FALSE; } /* }}} */ @@ -2870,25 +2905,31 @@ PHP_FUNCTION(pg_fetch_object) } /* }}} */ -/* {{{ proto array pg_fetch_all(resource result) +/* {{{ proto array pg_fetch_all(resource result [, int result_type]) Fetch all rows into array */ PHP_FUNCTION(pg_fetch_all) { zval *result; + long result_type = PGSQL_ASSOC; PGresult *pgsql_result; pgsql_result_handle *pg_result; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &result, &result_type) == FAILURE) { return; } + if (!(result_type & PGSQL_BOTH)) { + php_error_docref(NULL, E_WARNING, "Invalid result type"); + RETURN_FALSE; + } + if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) { RETURN_FALSE; } pgsql_result = pg_result->result; array_init(return_value); - if (php_pgsql_result2array(pgsql_result, return_value) == FAILURE) { + if (php_pgsql_result2array(pgsql_result, return_value, result_type) == FAILURE) { zval_dtor(return_value); RETURN_FALSE; } @@ -3033,7 +3074,7 @@ static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) RETVAL_LONG(PQgetlength(pgsql_result, pgsql_row, field_offset)); break; case PHP_PG_DATA_ISNULL: - RETVAL_LONG(PQgetisnull(pgsql_result, pgsql_row, field_offset)) + RETVAL_LONG(PQgetisnull(pgsql_result, pgsql_row, field_offset)); break; } } @@ -7002,7 +7043,7 @@ PHP_FUNCTION(pg_delete) /* {{{ php_pgsql_result2array */ -PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array) +PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array, long result_type) { zval row; char *field_name; @@ -7017,16 +7058,24 @@ PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array) for (pg_row = 0; pg_row < pg_numrows; pg_row++) { array_init(&row); for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) { + field_name = PQfname(pg_result, i); if (PQgetisnull(pg_result, pg_row, i)) { - field_name = PQfname(pg_result, i); - add_assoc_null(&row, field_name); + if (result_type & PGSQL_ASSOC) { + add_assoc_null(&row, field_name); + } + if (result_type & PGSQL_NUM) { + add_next_index_null(&row); + } } else { char *element = PQgetvalue(pg_result, pg_row, i); if (element) { const size_t element_len = strlen(element); - - field_name = PQfname(pg_result, i); - add_assoc_stringl(&row, field_name, element, element_len); + if (result_type & PGSQL_ASSOC) { + add_assoc_stringl(&row, field_name, element, element_len); + } + if (result_type & PGSQL_NUM) { + add_next_index_stringl(&row, element, element_len); + } } } } @@ -7038,7 +7087,7 @@ PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array) /* {{{ php_pgsql_select */ -PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids_array, zval *ret_array, zend_ulong opt, zend_string **sql) + PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids_array, zval *ret_array, zend_ulong opt, long result_type, zend_string **sql) { zval ids_converted; smart_str querystr = {0}; @@ -7076,7 +7125,7 @@ PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids pg_result = PQexec(pg_link, ZSTR_VAL(querystr.s)); if (PQresultStatus(pg_result) == PGRES_TUPLES_OK) { - ret = php_pgsql_result2array(pg_result, ret_array); + ret = php_pgsql_result2array(pg_result, ret_array, result_type); } else { php_error_docref(NULL, E_NOTICE, "Failed to execute '%s'", ZSTR_VAL(querystr.s)); } @@ -7094,7 +7143,7 @@ cleanup: } /* }}} */ -/* {{{ proto mixed pg_select(resource db, string table, array ids[, int options]) +/* {{{ proto mixed pg_select(resource db, string table, array ids[, int options [, int result_type]) Select records that has ids (id=>value) */ PHP_FUNCTION(pg_select) { @@ -7102,18 +7151,23 @@ PHP_FUNCTION(pg_select) char *table; size_t table_len; zend_ulong option = PGSQL_DML_EXEC; + long result_type = PGSQL_ASSOC; PGconn *pg_link; zend_string *sql = NULL; int argc = ZEND_NUM_ARGS(); if (zend_parse_parameters(argc, "rsa|l", - &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) { + &pgsql_link, &table, &table_len, &ids, &option, &result_type) == FAILURE) { return; } if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) { php_error_docref(NULL, E_WARNING, "Invalid option is specified"); RETURN_FALSE; } + if (!(result_type & PGSQL_BOTH)) { + php_error_docref(NULL, E_WARNING, "Invalid result type"); + RETURN_FALSE; + } if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) { RETURN_FALSE; @@ -7123,7 +7177,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, &sql) == FAILURE) { + if (php_pgsql_select(pg_link, table, ids, return_value, option, result_type, &sql) == FAILURE) { zval_ptr_dtor(return_value); RETURN_FALSE; } |