diff options
| -rw-r--r-- | ext/pgsql/config.m4 | 7 | ||||
| -rw-r--r-- | ext/pgsql/config.w32 | 2 | ||||
| -rw-r--r-- | ext/pgsql/pgsql.c | 712 | ||||
| -rw-r--r-- | ext/pgsql/php_pgsql.h | 24 | ||||
| -rw-r--r-- | ext/pgsql/tests/23sync_query_params.phpt | 53 | ||||
| -rw-r--r-- | ext/pgsql/tests/24sync_query_prepared.phpt | 59 | ||||
| -rw-r--r-- | ext/pgsql/tests/25async_query_params.phpt | 63 | ||||
| -rw-r--r-- | ext/pgsql/tests/26async_query_prepared.phpt | 99 | 
8 files changed, 1017 insertions, 2 deletions
diff --git a/ext/pgsql/config.m4 b/ext/pgsql/config.m4 index 334ea86248..1d29d007f3 100644 --- a/ext/pgsql/config.m4 +++ b/ext/pgsql/config.m4 @@ -76,6 +76,13 @@ if test "$PHP_PGSQL" != "no"; then    AC_CHECK_LIB(pq, PQparameterStatus,AC_DEFINE(HAVE_PQPARAMETERSTATUS,1,[PostgreSQL 7.4 or later]))    AC_CHECK_LIB(pq, PQprotocolVersion,AC_DEFINE(HAVE_PQPROTOCOLVERSION,1,[PostgreSQL 7.4 or later]))    AC_CHECK_LIB(pq, PQtransactionStatus,AC_DEFINE(HAVE_PGTRANSACTIONSTATUS,1,[PostgreSQL 7.4 or later])) +  AC_CHECK_LIB(pq, PQexecParams,AC_DEFINE(HAVE_PQEXECPARAMS,1,[PostgreSQL 7.4 or later])) +  AC_CHECK_LIB(pq, PQprepare,AC_DEFINE(HAVE_PQPREPARE,1,[PostgreSQL 7.4 or later])) +  AC_CHECK_LIB(pq, PQexecPrepared,AC_DEFINE(HAVE_PQEXECPREPARED,1,[PostgreSQL 7.4 or later])) +  AC_CHECK_LIB(pq, PQresultErrorField,AC_DEFINE(HAVE_PQRESULTERRORFIELD,1,[PostgreSQL 7.4 or later])) +  AC_CHECK_LIB(pq, PQsendQueryParams,AC_DEFINE(HAVE_PQSENDQUERYPARAMS,1,[PostgreSQL 7.4 or later])) +  AC_CHECK_LIB(pq, PQsendPrepare,AC_DEFINE(HAVE_PQSENDPREPARE,1,[PostgreSQL 7.4 or later])) +  AC_CHECK_LIB(pq, PQsendQueryPrepared,AC_DEFINE(HAVE_PQSENDQUERYPREPARED,1,[PostgreSQL 7.4 or later]))    AC_CHECK_LIB(pq, pg_encoding_to_char,AC_DEFINE(HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT,1,[Whether libpq is compiled with --enable-multibye]))    LIBS=$old_LIBS    LDFLAGS=$old_LDFLAGS diff --git a/ext/pgsql/config.w32 b/ext/pgsql/config.w32 index 30477ad459..d4d5324d8b 100644 --- a/ext/pgsql/config.w32 +++ b/ext/pgsql/config.w32 @@ -8,7 +8,7 @@ if (PHP_PGSQL != "no") {  		CHECK_HEADER_ADD_INCLUDE("libpq-fe.h", "CFLAGS_PGSQL", PHP_PHP_BUILD + "\\include\\pgsql;" + PHP_PGSQL)) {  		EXTENSION("pgsql", "pgsql.c");  		AC_DEFINE('HAVE_PGSQL', 1, 'Have PostgreSQL library'); -		ADD_FLAG("CFLAGS_PGSQL", "/D HAVE_PG_CONFIG_H /D PGSQL_EXPORTS /D HAVE_PQSETNONBLOCKING /D HAVE_PQCMDTUPLES /D HAVE_PQCLIENTENCODING /D HAVE_PQESCAPE /D HAVE_PQPARAMETERSTATUS /D HAVE_PGTRANSACTIONSTATUS"); +		ADD_FLAG("CFLAGS_PGSQL", "/D HAVE_PG_CONFIG_H /D PGSQL_EXPORTS /D HAVE_PQSETNONBLOCKING /D HAVE_PQCMDTUPLES /D HAVE_PQCLIENTENCODING /D HAVE_PQESCAPE /D HAVE_PQPARAMETERSTATUS /D HAVE_PGTRANSACTIONSTATUS /D HAVE_PQEXECPARAMS /D HAVE_PQPREPARE /D HAVE_PQEXECPREPARED /D HAVE_PQRESULTERRORFIELD /D HAVE_PQSENDQUERYPARAMS /D HAVE_PQSENDPREPARE /D HAVE_PQSENDQUERYPREPARED ");  	} else {  		WARNING("pgsql not enabled; libraries and headers not found");  	} diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 41fff0ed80..387f1e9465 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -94,9 +94,30 @@ function_entry pgsql_functions[] = {  #if HAVE_PQPARAMETERSTATUS  	PHP_FE(pg_parameter_status, NULL)  #endif +#if HAVE_PGTRANSACTIONSTATUS +	PHP_FE(pg_transaction_status, NULL) +#endif  	/* query functions */  	PHP_FE(pg_query,		NULL) +#if HAVE_PQEXECPARAMS +	PHP_FE(pg_query_params,		NULL) +#endif +#if HAVE_PQPREPARE +	PHP_FE(pg_prepare,		NULL) +#endif +#if HAVE_PQEXECPREPARED +	PHP_FE(pg_execute,		NULL) +#endif  	PHP_FE(pg_send_query,	NULL) +#if HAVE_PQSENDQUERYPARAMS +	PHP_FE(pg_send_query_params,	NULL) +#endif +#if HAVE_PQSENDPREPARE +	PHP_FE(pg_send_prepare,	NULL) +#endif +#if HAVE_PQSENDQUERYPREPARED +	PHP_FE(pg_send_execute,	NULL) +#endif  	PHP_FE(pg_cancel_query, NULL)  	/* result functions */  	PHP_FE(pg_fetch_result,	NULL) @@ -125,6 +146,9 @@ function_entry pgsql_functions[] = {  	PHP_FE(pg_get_pid,      NULL)  	/* error message functions */  	PHP_FE(pg_result_error, NULL) +#if HAVE_PQRESULTERRORFIELD +	PHP_FE(pg_result_error_field, NULL) +#endif  	PHP_FE(pg_last_error,   NULL)  	PHP_FE(pg_last_notice,  NULL)  	/* copy functions */ @@ -435,6 +459,14 @@ PHP_MINIT_FUNCTION(pgsql)  	/* 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); +#if HAVE_PGTRANSACTIONSTATUS +	/* For pg_transaction_status() */ +	REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_IDLE", PQTRANS_IDLE, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_ACTIVE", PQTRANS_ACTIVE, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INTRANS", PQTRANS_INTRANS, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INERROR", PQTRANS_INERROR, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_UNKNOWN", PQTRANS_UNKNOWN, CONST_CS | CONST_PERSISTENT); +#endif  	/* For lo_seek() */  	REGISTER_LONG_CONSTANT("PGSQL_SEEK_SET", SEEK_SET, CONST_CS | CONST_PERSISTENT);  	REGISTER_LONG_CONSTANT("PGSQL_SEEK_CUR", SEEK_CUR, CONST_CS | CONST_PERSISTENT); @@ -451,6 +483,19 @@ PHP_MINIT_FUNCTION(pgsql)  	REGISTER_LONG_CONSTANT("PGSQL_BAD_RESPONSE", PGRES_BAD_RESPONSE, CONST_CS | CONST_PERSISTENT);  	REGISTER_LONG_CONSTANT("PGSQL_NONFATAL_ERROR", PGRES_NONFATAL_ERROR, CONST_CS | CONST_PERSISTENT);  	REGISTER_LONG_CONSTANT("PGSQL_FATAL_ERROR", PGRES_FATAL_ERROR, CONST_CS | CONST_PERSISTENT); +	/* For pg_result_error_field() field codes */ +	REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY", PG_DIAG_SEVERITY, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_DIAG_SQLSTATE", PG_DIAG_SQLSTATE, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_PRIMARY", PG_DIAG_MESSAGE_PRIMARY, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_DETAIL", PG_DIAG_MESSAGE_DETAIL, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_HINT", PG_DIAG_MESSAGE_HINT, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_DIAG_STATEMENT_POSITION", PG_DIAG_STATEMENT_POSITION, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_POSITION", PG_DIAG_INTERNAL_POSITION, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_QUERY", PG_DIAG_INTERNAL_QUERY, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONTEXT", PG_DIAG_CONTEXT, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FILE", PG_DIAG_SOURCE_FILE, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_LINE", PG_DIAG_SOURCE_LINE, CONST_CS | CONST_PERSISTENT); +	REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FUNCTION", PG_DIAG_SOURCE_FUNCTION, CONST_CS | CONST_PERSISTENT);  	/* pg_convert options */  	REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_DEFAULT", PGSQL_CONV_IGNORE_DEFAULT, CONST_CS | CONST_PERSISTENT);  	REGISTER_LONG_CONSTANT("PGSQL_CONV_FORCE_NULL", PGSQL_CONV_FORCE_NULL, CONST_CS | CONST_PERSISTENT); @@ -1099,6 +1144,374 @@ PHP_FUNCTION(pg_query)  }  /* }}} */ +#if HAVE_PQEXECPARAMS || HAVE_PQEXECPREPARED +/* {{{ _php_pgsql_free_params */ +static void _php_pgsql_free_params(char **params, int num_params) +{ +	if (num_params > 0) { +		efree(params); +	} +} +/* }}} */ +#endif + +#if HAVE_PQEXECPARAMS +/* {{{ proto resource pg_query_params([resource connection,] string query, array params) +   Execute a query */ +PHP_FUNCTION(pg_query_params) +{ +	zval **query, **pgsql_link = NULL; +	zval **pv_param_arr, **tmp; +	int id = -1; +	int leftover = 0; +	int num_params = 0; +	char **params = NULL; +	unsigned char otype; +	PGconn *pgsql; +	PGresult *pgsql_result; +	ExecStatusType status; +	pgsql_result_handle *pg_result; + +	switch(ZEND_NUM_ARGS()) { +		case 2: +			if (zend_get_parameters_ex(2, &query, &pv_param_arr)==FAILURE) { +				RETURN_FALSE; +			} +			id = PGG(default_link); +			CHECK_DEFAULT_LINK(id); +			break; +		case 3: +			if (zend_get_parameters_ex(3, &pgsql_link, &query, &pv_param_arr)==FAILURE) { +				RETURN_FALSE; +			} +			break; +		default: +			WRONG_PARAM_COUNT; +			break; +	} +	if (pgsql_link == NULL && id == -1) { +		RETURN_FALSE; +	}	 + +	if (Z_TYPE_PP(pv_param_arr) != IS_ARRAY) { +		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No array passed"); +		RETURN_FALSE; +	} + +	ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink); + +	convert_to_string_ex(query); +	if (PQ_SETNONBLOCKING(pgsql, 0)) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode"); +		RETURN_FALSE; +	} +	while ((pgsql_result = PQgetResult(pgsql))) { +		PQclear(pgsql_result); +		leftover = 1; +	} +	if (leftover) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first"); +	} + +	zend_hash_internal_pointer_reset(Z_ARRVAL_PP(pv_param_arr)); +	num_params = zend_hash_num_elements(Z_ARRVAL_PP(pv_param_arr)); +	if (num_params > 0) { +		int i = 0; +		params = (char **)safe_emalloc(sizeof(char *), num_params, 0); +		 +		for(i = 0; i < num_params; i++) { +			if (zend_hash_get_current_data(Z_ARRVAL_PP(pv_param_arr), (void **) &tmp) == FAILURE) { +				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter"); +				_php_pgsql_free_params(params, num_params); +				RETURN_FALSE; +			} + +			otype = (*tmp)->type; +			convert_to_string(*tmp); +			if (Z_TYPE_PP(tmp) != IS_STRING) { +				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter"); +				_php_pgsql_free_params(params, num_params); +				RETURN_FALSE; +			} + +			if (otype == IS_NULL) { +				params[i] = NULL; +			} +			else { +				params[i] = Z_STRVAL_PP(tmp); +			} + +			zend_hash_move_forward(Z_ARRVAL_PP(pv_param_arr)); +		} +	} + +	pgsql_result = PQexecParams(pgsql, Z_STRVAL_PP(query), num_params,  +					NULL, (const char * const *)params, NULL, NULL, 0); +	if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { +		PQclear(pgsql_result); +		PQreset(pgsql); +		pgsql_result = PQexecParams(pgsql, Z_STRVAL_PP(query), num_params,  +						NULL, (const char * const *)params, NULL, NULL, 0); +	} + +	if (pgsql_result) { +		status = PQresultStatus(pgsql_result); +	} else { +		status = (ExecStatusType) PQstatus(pgsql); +	} +	 +	_php_pgsql_free_params(params, num_params); + +	switch (status) { +		case PGRES_EMPTY_QUERY: +		case PGRES_BAD_RESPONSE: +		case PGRES_NONFATAL_ERROR: +		case PGRES_FATAL_ERROR: +			PHP_PQ_ERROR("Query failed: %s", pgsql); +			PQclear(pgsql_result); +			RETURN_FALSE; +			break; +		case PGRES_COMMAND_OK: /* successful command that did not return rows */ +		default: +			if (pgsql_result) { +				pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle)); +				pg_result->conn = pgsql; +				pg_result->result = pgsql_result; +				pg_result->row = 0; +				ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result); +			} else { +				PQclear(pgsql_result); +				RETURN_FALSE; +			} +			break; +	} +} +/* }}} */ +#endif + +#if HAVE_PQPREPARE +/* {{{ proto resource pg_prepare([resource connection,] string stmtname, string query) +   Prepare a query for future execution */ +PHP_FUNCTION(pg_prepare) +{ +	zval **query, **stmtname, **pgsql_link = NULL; +	int id = -1; +	int leftover = 0; +	PGconn *pgsql; +	PGresult *pgsql_result; +	ExecStatusType status; +	pgsql_result_handle *pg_result; + +	switch(ZEND_NUM_ARGS()) { +		case 2: +			if (zend_get_parameters_ex(2, &stmtname, &query)==FAILURE) { +				RETURN_FALSE; +			} +			id = PGG(default_link); +			CHECK_DEFAULT_LINK(id); +			break; +		case 3: +			if (zend_get_parameters_ex(3, &pgsql_link, &stmtname, &query)==FAILURE) { +				RETURN_FALSE; +			} +			break; +		default: +			WRONG_PARAM_COUNT; +			break; +	} +	if (pgsql_link == NULL && id == -1) { +		RETURN_FALSE; +	}	 + +	ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink); + +	convert_to_string_ex(stmtname); +	convert_to_string_ex(query); +	if (PQ_SETNONBLOCKING(pgsql, 0)) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode"); +		RETURN_FALSE; +	} +	while ((pgsql_result = PQgetResult(pgsql))) { +		PQclear(pgsql_result); +		leftover = 1; +	} +	if (leftover) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first"); +	} +	pgsql_result = PQprepare(pgsql, Z_STRVAL_PP(stmtname), Z_STRVAL_PP(query), 0, NULL); +	if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { +		PQclear(pgsql_result); +		PQreset(pgsql); +		pgsql_result = PQprepare(pgsql, Z_STRVAL_PP(stmtname), Z_STRVAL_PP(query), 0, NULL); +	} + +	if (pgsql_result) { +		status = PQresultStatus(pgsql_result); +	} else { +		status = (ExecStatusType) PQstatus(pgsql); +	} +	 +	switch (status) { +		case PGRES_EMPTY_QUERY: +		case PGRES_BAD_RESPONSE: +		case PGRES_NONFATAL_ERROR: +		case PGRES_FATAL_ERROR: +			PHP_PQ_ERROR("Query failed: %s", pgsql); +			PQclear(pgsql_result); +			RETURN_FALSE; +			break; +		case PGRES_COMMAND_OK: /* successful command that did not return rows */ +		default: +			if (pgsql_result) { +				pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle)); +				pg_result->conn = pgsql; +				pg_result->result = pgsql_result; +				pg_result->row = 0; +				ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result); +			} else { +				PQclear(pgsql_result); +				RETURN_FALSE; +			} +			break; +	} +} +/* }}} */ +#endif + +#if HAVE_PQEXECPREPARED +/* {{{ proto resource pg_execute([resource connection,] string stmtname, array params) +   Execute a prepared query  */ +PHP_FUNCTION(pg_execute) +{ +	zval **stmtname, **pgsql_link = NULL; +	zval **pv_param_arr, **tmp; +	int id = -1; +	int leftover = 0; +	int num_params = 0; +	char **params = NULL; +	unsigned char otype; +	PGconn *pgsql; +	PGresult *pgsql_result; +	ExecStatusType status; +	pgsql_result_handle *pg_result; + +	switch(ZEND_NUM_ARGS()) { +		case 2: +			if (zend_get_parameters_ex(2, &stmtname, &pv_param_arr)==FAILURE) { +				RETURN_FALSE; +			} +			id = PGG(default_link); +			CHECK_DEFAULT_LINK(id); +			break; +		case 3: +			if (zend_get_parameters_ex(3, &pgsql_link, &stmtname, &pv_param_arr)==FAILURE) { +				RETURN_FALSE; +			} +			break; +		default: +			WRONG_PARAM_COUNT; +			break; +	} +	if (pgsql_link == NULL && id == -1) { +		RETURN_FALSE; +	}	 + +	if (Z_TYPE_PP(pv_param_arr) != IS_ARRAY) { +		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No array passed"); +		RETURN_FALSE; +	} + +	ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink); + +	convert_to_string_ex(stmtname); +	if (PQ_SETNONBLOCKING(pgsql, 0)) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode"); +		RETURN_FALSE; +	} +	while ((pgsql_result = PQgetResult(pgsql))) { +		PQclear(pgsql_result); +		leftover = 1; +	} +	if (leftover) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first"); +	} + +	zend_hash_internal_pointer_reset(Z_ARRVAL_PP(pv_param_arr)); +	num_params = zend_hash_num_elements(Z_ARRVAL_PP(pv_param_arr)); +	if (num_params > 0) { +		int i = 0; +		params = (char **)safe_emalloc(sizeof(char *), num_params, 0); +		 +		for(i = 0; i < num_params; i++) { +			if (zend_hash_get_current_data(Z_ARRVAL_PP(pv_param_arr), (void **) &tmp) == FAILURE) { +				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter"); +				_php_pgsql_free_params(params, num_params); +				RETURN_FALSE; +			} + +			otype = (*tmp)->type; +			convert_to_string(*tmp); +			if (Z_TYPE_PP(tmp) != IS_STRING) { +				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter"); +				_php_pgsql_free_params(params, num_params); +				RETURN_FALSE; +			} + +			if (otype == IS_NULL) { +				params[i] = NULL; +			} +			else { +				params[i] = Z_STRVAL_PP(tmp); +			} + +			zend_hash_move_forward(Z_ARRVAL_PP(pv_param_arr)); +		} +	} + +	pgsql_result = PQexecPrepared(pgsql, Z_STRVAL_PP(stmtname), num_params,  +					(const char * const *)params, NULL, NULL, 0); +	if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { +		PQclear(pgsql_result); +		PQreset(pgsql); +		pgsql_result = PQexecPrepared(pgsql, Z_STRVAL_PP(stmtname), num_params,  +						(const char * const *)params, NULL, NULL, 0); +	} + +	if (pgsql_result) { +		status = PQresultStatus(pgsql_result); +	} else { +		status = (ExecStatusType) PQstatus(pgsql); +	} +	 +	_php_pgsql_free_params(params, num_params); + +	switch (status) { +		case PGRES_EMPTY_QUERY: +		case PGRES_BAD_RESPONSE: +		case PGRES_NONFATAL_ERROR: +		case PGRES_FATAL_ERROR: +			PHP_PQ_ERROR("Query failed: %s", pgsql); +			PQclear(pgsql_result); +			RETURN_FALSE; +			break; +		case PGRES_COMMAND_OK: /* successful command that did not return rows */ +		default: +			if (pgsql_result) { +				pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle)); +				pg_result->conn = pgsql; +				pg_result->result = pgsql_result; +				pg_result->row = 0; +				ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result); +			} else { +				PQclear(pgsql_result); +				RETURN_FALSE; +			} +			break; +	} +} +/* }}} */ +#endif +  #define PHP_PG_NUM_ROWS 1  #define PHP_PG_NUM_FIELDS 2  #define PHP_PG_CMD_TUPLES 3 @@ -3046,6 +3459,45 @@ PHP_FUNCTION(pg_result_error)  }  /* }}} */ +#if HAVE_PQRESULTERRORFIELD +/* {{{ proto string pg_result_error_field(resource result, int fieldcode) +   Get error message field associated with result */ +PHP_FUNCTION(pg_result_error_field) +{ +	zval *result; +	long fieldcode; +	PGresult *pgsql_result; +	pgsql_result_handle *pg_result; +	char *field = NULL; + +	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "rl", +								 &result, &fieldcode) == FAILURE) { +		RETURN_FALSE; +	} +	 +	ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); + +	pgsql_result = pg_result->result; +	if (!pgsql_result) { +		RETURN_FALSE; +	} +	if (fieldcode & (PG_DIAG_SEVERITY|PG_DIAG_SQLSTATE|PG_DIAG_MESSAGE_PRIMARY|PG_DIAG_MESSAGE_DETAIL +				|PG_DIAG_MESSAGE_HINT|PG_DIAG_STATEMENT_POSITION|PG_DIAG_INTERNAL_POSITION +				|PG_DIAG_INTERNAL_QUERY|PG_DIAG_CONTEXT|PG_DIAG_SOURCE_FILE|PG_DIAG_SOURCE_LINE +				|PG_DIAG_SOURCE_FUNCTION)) { +		field = (char *)PQresultErrorField(pgsql_result, fieldcode); +		if (field == NULL) { +			RETURN_NULL(); +		} else { +			RETURN_STRING(field, 1); +		} +	} else { +		RETURN_FALSE; +	} +} +/* }}} */ +#endif +  /* {{{ proto int pg_connection_status(resource connnection)     Get connection status */  PHP_FUNCTION(pg_connection_status) @@ -3066,6 +3518,28 @@ PHP_FUNCTION(pg_connection_status)  /* }}} */ +#if HAVE_PGTRANSACTIONSTATUS +/* {{{ proto int pg_transaction_status(resource connnection) +   Get transaction status */ +PHP_FUNCTION(pg_transaction_status) +{ +	zval *pgsql_link = NULL; +	int id = -1; +	PGconn *pgsql; + +	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", +								 &pgsql_link) == FAILURE) { +		RETURN_FALSE; +	} + +	ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); + +	RETURN_LONG(PQtransactionStatus(pgsql)); +} +#endif + +/* }}} */ +  /* {{{ proto bool pg_connection_reset(resource connection)     Reset connection (reconnect) */  PHP_FUNCTION(pg_connection_reset) @@ -3173,7 +3647,7 @@ PHP_FUNCTION(pg_connection_busy)  }  /* }}} */ -/* {{{ proto bool pg_send_query(resource connection, string qeury) +/* {{{ proto bool pg_send_query(resource connection, string query)     Send asynchronous query */  PHP_FUNCTION(pg_send_query)  { @@ -3218,6 +3692,242 @@ PHP_FUNCTION(pg_send_query)  }  /* }}} */ +#if HAVE_PQSENDQUERYPARAMS +/* {{{ proto bool pg_send_query_params(resource connection, string query) +   Send asynchronous parameterized query */ +PHP_FUNCTION(pg_send_query_params) +{ +	zval **pgsql_link; +	zval **pv_param_arr, **tmp; +	int num_params = 0; +	char **params = NULL; +	unsigned char otype; +	zval **query; +	int id = -1; +	PGconn *pgsql; +	PGresult *res; +	int leftover = 0; + +	if (zend_get_parameters_ex(3, &pgsql_link, &query, &pv_param_arr) == FAILURE) { +		return; +	} + +	if (pgsql_link == NULL && id == -1) { +		RETURN_FALSE; +	}	 + +	if (Z_TYPE_PP(pv_param_arr) != IS_ARRAY) { +		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No array passed"); +		RETURN_FALSE; +	} + +	ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink); + +	convert_to_string_ex(query); +	if (PQ_SETNONBLOCKING(pgsql, 1)) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode"); +		RETURN_FALSE; +	} +	while ((res = PQgetResult(pgsql))) { +		PQclear(res); +		leftover = 1; +	} +	if (leftover) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE"); +	} + +	zend_hash_internal_pointer_reset(Z_ARRVAL_PP(pv_param_arr)); +	num_params = zend_hash_num_elements(Z_ARRVAL_PP(pv_param_arr)); +	if (num_params > 0) { +		int i = 0; +		params = (char **)safe_emalloc(sizeof(char *), num_params, 0); +		 +		for(i = 0; i < num_params; i++) { +			if (zend_hash_get_current_data(Z_ARRVAL_PP(pv_param_arr), (void **) &tmp) == FAILURE) { +				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter"); +				_php_pgsql_free_params(params, num_params); +				RETURN_FALSE; +			} + +			otype = (*tmp)->type; +			convert_to_string(*tmp); +			if (Z_TYPE_PP(tmp) != IS_STRING) { +				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter"); +				_php_pgsql_free_params(params, num_params); +				RETURN_FALSE; +			} + +			if (otype == IS_NULL) { +				params[i] = NULL; +			} +			else { +				params[i] = Z_STRVAL_PP(tmp); +			} + +			zend_hash_move_forward(Z_ARRVAL_PP(pv_param_arr)); +		} +	} + +	if (!PQsendQueryParams(pgsql, Z_STRVAL_PP(query), num_params, NULL, (const char * const *)params, NULL, NULL, 0)) { +		if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { +			PQreset(pgsql); +		} +		if (!PQsendQueryParams(pgsql, Z_STRVAL_PP(query), num_params, NULL, (const char * const *)params, NULL, NULL, 0)) { +			_php_pgsql_free_params(params, num_params); +			RETURN_FALSE; +		} +	} +	_php_pgsql_free_params(params, num_params); +	if (PQ_SETNONBLOCKING(pgsql, 0)) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode"); +	} +	RETURN_TRUE; +} +/* }}} */ +#endif + +#if HAVE_PQSENDPREPARE +/* {{{ proto bool pg_send_prepare(resource connection, string stmtname, string query) +   Asynchronously prepare a query for future execution */ +PHP_FUNCTION(pg_send_prepare) +{ +	zval **pgsql_link; +	zval **query, **stmtname; +	int id = -1; +	PGconn *pgsql; +	PGresult *res; +	int leftover = 0; + +	if (zend_get_parameters_ex(3, &pgsql_link, &stmtname, &query) == FAILURE) { +		return; +	} +	if (pgsql_link == NULL && id == -1) { +		RETURN_FALSE; +	}	 + +	ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink); + +	convert_to_string_ex(stmtname); +	convert_to_string_ex(query); +	if (PQ_SETNONBLOCKING(pgsql, 1)) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode"); +		RETURN_FALSE; +	} +	while ((res = PQgetResult(pgsql))) { +		PQclear(res); +		leftover = 1; +	} +	if (leftover) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE"); +	} +	if (!PQsendPrepare(pgsql, Z_STRVAL_PP(stmtname), Z_STRVAL_PP(query), 0, NULL)) { +		if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { +			PQreset(pgsql); +		} +		if (!PQsendPrepare(pgsql, Z_STRVAL_PP(stmtname), Z_STRVAL_PP(query), 0, NULL)) { +			RETURN_FALSE; +		} +	} +	if (PQ_SETNONBLOCKING(pgsql, 0)) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode"); +	} +	RETURN_TRUE; +} +/* }}} */ +#endif + +#if HAVE_PQSENDQUERYPREPARED +/* {{{ proto bool pg_send_execute(resource connection, string stmtname, array params) +   Executes prevriously prepared stmtname asynchronously */ +PHP_FUNCTION(pg_send_execute) +{ +	zval **pgsql_link; +	zval **pv_param_arr, **tmp; +	int num_params = 0; +	char **params = NULL; +	unsigned char otype; +	zval **stmtname; +	int id = -1; +	PGconn *pgsql; +	PGresult *res; +	int leftover = 0; + +	if (zend_get_parameters_ex(3, &pgsql_link, &stmtname, &pv_param_arr)==FAILURE) { +		return; +	} +	if (pgsql_link == NULL && id == -1) { +		RETURN_FALSE; +	}	 + +	if (Z_TYPE_PP(pv_param_arr) != IS_ARRAY) { +		php_error_docref(NULL TSRMLS_CC, E_WARNING, "No array passed"); +		RETURN_FALSE; +	} + +	ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink); + +	convert_to_string_ex(stmtname); +	if (PQ_SETNONBLOCKING(pgsql, 1)) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode"); +		RETURN_FALSE; +	} +	while ((res = PQgetResult(pgsql))) { +		PQclear(res); +		leftover = 1; +	} +	if (leftover) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE"); +	} + +	zend_hash_internal_pointer_reset(Z_ARRVAL_PP(pv_param_arr)); +	num_params = zend_hash_num_elements(Z_ARRVAL_PP(pv_param_arr)); +	if (num_params > 0) { +		int i = 0; +		params = (char **)safe_emalloc(sizeof(char *), num_params, 0); +		 +		for(i = 0; i < num_params; i++) { +			if (zend_hash_get_current_data(Z_ARRVAL_PP(pv_param_arr), (void **) &tmp) == FAILURE) { +				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter"); +				_php_pgsql_free_params(params, num_params); +				RETURN_FALSE; +			} + +			otype = (*tmp)->type; +			convert_to_string(*tmp); +			if (Z_TYPE_PP(tmp) != IS_STRING) { +				php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter"); +				_php_pgsql_free_params(params, num_params); +				RETURN_FALSE; +			} + +			if (otype == IS_NULL) { +				params[i] = NULL; +			} +			else { +				params[i] = Z_STRVAL_PP(tmp); +			} + +			zend_hash_move_forward(Z_ARRVAL_PP(pv_param_arr)); +		} +	} + +	if (!PQsendQueryPrepared(pgsql, Z_STRVAL_PP(stmtname), num_params, (const char * const *)params, NULL, NULL, 0)) { +		if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { +			PQreset(pgsql); +		} +		if (!PQsendQueryPrepared(pgsql, Z_STRVAL_PP(stmtname), num_params, (const char * const *)params, NULL, NULL, 0)) { +			_php_pgsql_free_params(params, num_params); +			RETURN_FALSE; +		} +	} +	_php_pgsql_free_params(params, num_params); +	if (PQ_SETNONBLOCKING(pgsql, 0)) { +		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode"); +	} +	RETURN_TRUE; +} +/* }}} */ +#endif  /* {{{ proto resource pg_get_result(resource connection)     Get asynchronous query result */ diff --git a/ext/pgsql/php_pgsql.h b/ext/pgsql/php_pgsql.h index 835219d983..3d27e7d5f3 100644 --- a/ext/pgsql/php_pgsql.h +++ b/ext/pgsql/php_pgsql.h @@ -75,9 +75,30 @@ PHP_FUNCTION(pg_ping);  #if HAVE_PQPARAMETERSTATUS  PHP_FUNCTION(pg_parameter_status);  #endif +#if HAVE_PGTRANSACTIONSTATUS +PHP_FUNCTION(pg_transaction_status); +#endif  /* query functions */  PHP_FUNCTION(pg_query); +#if HAVE_PQEXECPARAMS +PHP_FUNCTION(pg_query_params); +#endif +#if HAVE_PQPREPARE +PHP_FUNCTION(pg_prepare); +#endif +#if HAVE_PQEXECPREPARED +PHP_FUNCTION(pg_execute); +#endif  PHP_FUNCTION(pg_send_query); +#if HAVE_PQSENDQUERYPARAMS +PHP_FUNCTION(pg_send_query_params); +#endif +#if HAVE_PQSENDPREPARE +PHP_FUNCTION(pg_send_prepare); +#endif +#if HAVE_PQSENDQUERYPREPARED +PHP_FUNCTION(pg_send_execute); +#endif  PHP_FUNCTION(pg_cancel_query);  /* result functions */  PHP_FUNCTION(pg_fetch_assoc); @@ -106,6 +127,9 @@ PHP_FUNCTION(pg_get_notify);  PHP_FUNCTION(pg_get_pid);  /* error message functions */  PHP_FUNCTION(pg_result_error); +#if HAVE_PQRESULTERRORFIELD +PHP_FUNCTION(pg_result_error_field); +#endif  PHP_FUNCTION(pg_last_error);  PHP_FUNCTION(pg_last_notice);  /* copy functions */ diff --git a/ext/pgsql/tests/23sync_query_params.phpt b/ext/pgsql/tests/23sync_query_params.phpt new file mode 100644 index 0000000000..db1cfb24f9 --- /dev/null +++ b/ext/pgsql/tests/23sync_query_params.phpt @@ -0,0 +1,53 @@ +--TEST-- +PostgreSQL sync query params +--SKIPIF-- +<?php include("skipif.inc"); ?> +--FILE-- +<?php + +include('config.inc'); + +$db = pg_connect($conn_str); + +$result = pg_query_params($db, "SELECT * FROM ".$table_name." WHERE num > \$1;", array(100)); +if (!($rows   = pg_num_rows($result))) +{ +	echo "pg_num_row() error\n"; +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_array($result, $i, PGSQL_NUM); +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_object($result); +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_row($result, $i); +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_result($result, $i, 0); +} + +pg_result_error($result); +pg_num_rows(pg_query_params($db, "SELECT * FROM ".$table_name." WHERE num > \$1;", array(100))); +pg_num_fields(pg_query_params($db, "SELECT * FROM ".$table_name." WHERE num > \$1;", array(100))); +pg_field_name($result, 0); +pg_field_num($result, $field_name); +pg_field_size($result, 0); +pg_field_type($result, 0); +pg_field_prtlen($result, 0); +pg_field_is_null($result, 0); + +$result = pg_query_params($db, "INSERT INTO ".$table_name." VALUES (\$1, \$2);", array(9999, "A'BC")); +pg_last_oid($result); + +pg_free_result($result); +pg_close($db); + +echo "OK"; +?> +--EXPECT-- +OK diff --git a/ext/pgsql/tests/24sync_query_prepared.phpt b/ext/pgsql/tests/24sync_query_prepared.phpt new file mode 100644 index 0000000000..273353b6df --- /dev/null +++ b/ext/pgsql/tests/24sync_query_prepared.phpt @@ -0,0 +1,59 @@ +--TEST-- +PostgreSQL sync prepared queries +--SKIPIF-- +<?php include("skipif.inc"); ?> +--FILE-- +<?php + +include('config.inc'); + +$db = pg_connect($conn_str); + +$result = pg_prepare($db, "php_test", "SELECT * FROM ".$table_name." WHERE num > \$1;"); +pg_result_error($result); +pg_free_result($result); +$result = pg_execute($db, "php_test", array(100)); +if (!($rows   = pg_num_rows($result))) +{ +	echo "pg_num_row() error\n"; +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_array($result, $i, PGSQL_NUM); +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_object($result); +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_row($result, $i); +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_result($result, $i, 0); +} + +pg_result_error($result); +pg_num_rows(pg_execute($db, "php_test", array(100))); +pg_num_fields(pg_execute($db, "php_test", array(100))); +pg_field_name($result, 0); +pg_field_num($result, $field_name); +pg_field_size($result, 0); +pg_field_type($result, 0); +pg_field_prtlen($result, 0); +pg_field_is_null($result, 0); + +$result = pg_prepare($db, "php_test2", "INSERT INTO ".$table_name." VALUES (\$1, \$2);"); +pg_result_error($result); +pg_free_result($result); +$result = pg_execute($db, "php_test2", array(9999, "A'BC")); +pg_last_oid($result); + +pg_free_result($result); +pg_close($db); + +echo "OK"; +?> +--EXPECT-- +OK diff --git a/ext/pgsql/tests/25async_query_params.phpt b/ext/pgsql/tests/25async_query_params.phpt new file mode 100644 index 0000000000..2d0edbb724 --- /dev/null +++ b/ext/pgsql/tests/25async_query_params.phpt @@ -0,0 +1,63 @@ +--TEST-- +PostgreSQL async query params +--SKIPIF-- +<?php include("skipif.inc"); ?> +--FILE-- +<?php + +include('config.inc'); + +$db = pg_connect($conn_str); + +if (!pg_send_query_params($db, "SELECT * FROM ".$table_name." WHERE num > \$1;", array(100))) { +	echo "pg_send_query_params() error\n"; +} +while(pg_connection_busy($db));  // busy wait: intended +if (pg_connection_status($db) === PGSQL_CONNECTION_BAD) { +	echo "pg_connection_status() error\n"; +} +if (!($result = pg_get_result($db)))  +{ +	echo "pg_get_result() error\n"; +} +if (!($rows = pg_num_rows($result))) { +	echo "pg_num_rows() error\n"; +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_array($result, $i, PGSQL_NUM); +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_object($result); +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_row($result, $i); +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_result($result, $i, 0); +} + +pg_num_rows(pg_query_params($db, "SELECT * FROM ".$table_name." WHERE num > \$1;", array(100))); +pg_num_fields(pg_query_params($db, "SELECT * FROM ".$table_name." WHERE num > \$1;", array(100))); +pg_field_name($result, 0); +pg_field_num($result, $field_name); +pg_field_size($result, 0); +pg_field_type($result, 0); +pg_field_prtlen($result, 0); +pg_field_is_null($result, 0); + +if (!pg_send_query_params($db, "INSERT INTO ".$table_name." VALUES (\$1, \$2);", array(9999, "A'BC"))) +{ +	echo "pg_send_query_params() error\n"; +} + +pg_last_oid($result); +pg_free_result($result); + +echo "OK"; +?> +--EXPECT-- +OK diff --git a/ext/pgsql/tests/26async_query_prepared.phpt b/ext/pgsql/tests/26async_query_prepared.phpt new file mode 100644 index 0000000000..84945be323 --- /dev/null +++ b/ext/pgsql/tests/26async_query_prepared.phpt @@ -0,0 +1,99 @@ +--TEST-- +PostgreSQL async prepared queries +--SKIPIF-- +<?php include("skipif.inc"); ?> +--FILE-- +<?php + +include('config.inc'); + +$db = pg_connect($conn_str); + +if (!pg_send_prepare($db, 'php_test', "SELECT * FROM ".$table_name." WHERE num > \$1;")) { +	echo "pg_send_prepare() error\n"; +} +while(pg_connection_busy($db));  // busy wait: intended +if (pg_connection_status($db) === PGSQL_CONNECTION_BAD) { +	echo "pg_connection_status() error\n"; +} +if (!($result = pg_get_result($db)))  +{ +	echo "pg_get_result() error\n"; +} +pg_free_result($result); + +if (!pg_send_execute($db, 'php_test', array(100))) { +	echo "pg_send_execute() error\n"; +} +while(pg_connection_busy($db));  // busy wait: intended +if (pg_connection_status($db) === PGSQL_CONNECTION_BAD) { +	echo "pg_connection_status() error\n"; +} +if (!($result = pg_get_result($db)))  +{ +	echo "pg_get_result() error\n"; +} + +if (!($rows = pg_num_rows($result))) { +	echo "pg_num_rows() error\n"; +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_array($result, $i, PGSQL_NUM); +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_object($result); +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_row($result, $i); +} +for ($i=0; $i < $rows; $i++)  +{ +	pg_fetch_result($result, $i, 0); +} + +pg_num_rows(pg_query_params($db, "SELECT * FROM ".$table_name." WHERE num > \$1;", array(100))); +pg_num_fields(pg_query_params($db, "SELECT * FROM ".$table_name." WHERE num > \$1;", array(100))); +pg_field_name($result, 0); +pg_field_num($result, $field_name); +pg_field_size($result, 0); +pg_field_type($result, 0); +pg_field_prtlen($result, 0); +pg_field_is_null($result, 0); + +if (!pg_send_prepare($db, "php_test2", "INSERT INTO ".$table_name." VALUES (\$1, \$2);")) +{ +	echo "pg_send_prepare() error\n"; +} +while(pg_connection_busy($db));  // busy wait: intended +if (pg_connection_status($db) === PGSQL_CONNECTION_BAD) { +	echo "pg_connection_status() error\n"; +} +if (!($result = pg_get_result($db)))  +{ +	echo "pg_get_result() error\n"; +} +pg_free_result($result); + +if (!pg_send_execute($db, "php_test2", array(9999, "A'BC"))) +{ +	echo "pg_send_execute() error\n"; +} +while(pg_connection_busy($db));  // busy wait: intended +if (pg_connection_status($db) === PGSQL_CONNECTION_BAD) { +	echo "pg_connection_status() error\n"; +} +if (!($result = pg_get_result($db)))  +{ +	echo "pg_get_result() error\n"; +} + +pg_last_oid($result); +pg_free_result($result); + +echo "OK"; +?> +--EXPECT-- +OK  | 
