From db8bb9f23cc85bd60582e792c2e55fc934c96cdc Mon Sep 17 00:00:00 2001 From: Yasuo Ohgaki Date: Mon, 10 Dec 2001 04:02:08 +0000 Subject: [PATCH] Added async query functions --- ext/pgsql/pgsql.c | 289 +++++++++++++++++++++++++++++++++++++++++- ext/pgsql/php_pgsql.h | 8 +- 2 files changed, 294 insertions(+), 3 deletions(-) diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index cae0ce2aa8..79ae58a8cc 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -94,6 +94,12 @@ function_entry pgsql_functions[] = { PHP_FALIAS(pg_clientencoding, pg_client_encoding, NULL) PHP_FALIAS(pg_setclientencoding, pg_set_client_encoding, NULL) #endif + PHP_FE(pg_reset, NULL) + PHP_FE(pg_status, NULL) + PHP_FE(pg_send_query, NULL) + PHP_FE(pg_request_cancel, NULL) + PHP_FE(pg_get_result, NULL) + PHP_FE(pg_is_busy, NULL) {NULL, NULL, NULL} }; /* }}} */ @@ -147,7 +153,17 @@ static void php_pgsql_set_default_link(int id) static void _close_pgsql_link(zend_rsrc_list_entry *rsrc TSRMLS_DC) { PGconn *link = (PGconn *)rsrc->ptr; + PGresult *res; + PQsetnonblocking(link,1); + if (PQisBusy(link)) { + if (!PQrequestCancel(link)) { + php_error(E_WARNING,"PostgreSQL: failed to cancel qeury. %s", PQerrorMessage(link)); + } + } + while ((res = PQgetResult(link))) { + PQclear(res); + } PQfinish(link); PGG(num_links)--; } @@ -158,7 +174,17 @@ static void _close_pgsql_link(zend_rsrc_list_entry *rsrc TSRMLS_DC) static void _close_pgsql_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC) { PGconn *link = (PGconn *)rsrc->ptr; + PGresult *res; + PQsetnonblocking(link,1); + if (PQisBusy(link)) { + if (!PQrequestCancel(link)) { + php_error(E_WARNING,"PostgreSQL: failed to cancel qeury. %s", PQerrorMessage(link)); + } + } + while ((res = PQgetResult(link))) { + PQclear(res); + } PQfinish(link); PGG(num_persistent)--; PGG(num_links)--; @@ -187,12 +213,22 @@ static void _notice_handler(void *arg, const char *message) static int _rollback_transactions(zend_rsrc_list_entry *rsrc TSRMLS_DC) { PGconn *link; + PGresult *res; if (Z_TYPE_P(rsrc) != le_plink) return 0; link = (PGconn *) rsrc->ptr; + PQsetnonblocking(link,1); + if (PQisBusy(link)) { + if (!PQrequestCancel(link)) { + php_error(E_WARNING,"PostgreSQL: failed to cancel qeury. %s", PQerrorMessage(link)); + } + } + while ((res = PQgetResult(link))) { + PQclear(res); + } PGG(ignore_notices) = 1; PQexec(link,"BEGIN;ROLLBACK;"); PGG(ignore_notices) = 0; @@ -262,6 +298,9 @@ PHP_MINIT_FUNCTION(pgsql) REGISTER_LONG_CONSTANT("PGSQL_NUM", PGSQL_NUM, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PGSQL_BOTH", PGSQL_BOTH, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_BAD", CONNECTION_BAD, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_OK", CONNECTION_OK, CONST_CS | CONST_PERSISTENT); + return SUCCESS; } /* }}} */ @@ -717,11 +756,12 @@ PHP_FUNCTION(pg_exec) { zval **query, **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 1: if (zend_get_parameters_ex(1, &query)==FAILURE) { @@ -743,6 +783,17 @@ PHP_FUNCTION(pg_exec) ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink); convert_to_string_ex(query); + if (PQisBusy(pgsql)) { + php_error(E_NOTICE,"PostgreSQL: Cannot execute query while executing async query."); + RETURN_FALSE; + } + while ((pgsql_result = PQgetResult(pgsql))) { + PQclear(pgsql_result); + leftover = 1; + } + if (leftover) { + php_error(E_WARNING,"PostgreSQL: There are results on this connection. Use pg_get_result() to get results"); + } pgsql_result = PQexec(pgsql, Z_STRVAL_PP(query)); if (pgsql_result) { @@ -751,7 +802,6 @@ PHP_FUNCTION(pg_exec) status = (ExecStatusType) PQstatus(pgsql); } - switch (status) { case PGRES_EMPTY_QUERY: case PGRES_BAD_RESPONSE: @@ -816,6 +866,8 @@ PHP_FUNCTION(pg_end_copy) } /* }}} */ +#define COPYBUFSIZ 8192 + /* {{{ proto int pg_put_line([int connection,] string query) Send null-terminated string to backend server*/ PHP_FUNCTION(pg_put_line) @@ -1962,7 +2014,240 @@ PHP_FUNCTION(pg_client_encoding) } /* }}} */ #endif + + +/* {{{ proto long pg_status(resource conn) + Get connection status */ +PHP_FUNCTION(pg_status) +{ + zval **pgsql_link = NULL; + int id = -1; + PGconn *pgsql; + + switch(ZEND_NUM_ARGS()) { + case 0: + id = PGG(default_link); + CHECK_DEFAULT_LINK(id); + break; + case 1: + if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) { + RETURN_FALSE; + } + break; + default: + WRONG_PARAM_COUNT; + break; + } + + ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink); + Z_LVAL_P(return_value) = PQstatus(pgsql); + Z_TYPE_P(return_value) = IS_LONG; +} + +/* }}} */ + +/* {{{ proto bool pg_reset(resource conn) + Reset connection */ +PHP_FUNCTION(pg_reset) +{ + zval **pgsql_link = NULL; + int id = -1; + PGconn *pgsql; + + switch(ZEND_NUM_ARGS()) { + case 0: + id = PGG(default_link); + CHECK_DEFAULT_LINK(id); + break; + case 1: + if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) { + RETURN_FALSE; + } + break; + default: + WRONG_PARAM_COUNT; + break; + } + ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink); + PQreset(pgsql); + if (PQstatus(pgsql) == CONNECTION_BAD) { + RETURN_FALSE; + } + RETURN_TRUE; +} + +/* }}} */ + +/* Following functions are for asyncronous query + * Report bugs to yasuo_ohgaki@yahoo.com + */ +#define PHP_PG_ASYNC_IS_BUSY 1 +#define PHP_PG_ASYNC_REQUEST_CANCEL 2 + +/* {{{ php_pgsql_do_async + */ +void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type) +{ + zval **pgsql_link = NULL; + int id = -1; + PGconn *pgsql; + PGresult *pgsql_result; + + switch(ZEND_NUM_ARGS()) { + case 0: + id = PGG(default_link); + CHECK_DEFAULT_LINK(id); + break; + case 1: + if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) { + RETURN_FALSE; + } + break; + default: + WRONG_PARAM_COUNT; + break; + } + + ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink); + + switch(entry_type) { + case PHP_PG_ASYNC_IS_BUSY: + PQconsumeInput(pgsql); + Z_LVAL_P(return_value) = PQisBusy(pgsql); + Z_TYPE_P(return_value) = IS_LONG; + break; + case PHP_PG_ASYNC_REQUEST_CANCEL: + Z_LVAL_P(return_value) = PQrequestCancel(pgsql); + Z_TYPE_P(return_value) = IS_LONG; + while ((pgsql_result = PQgetResult(pgsql))) { + PQclear(pgsql_result); + } + break; + default: + php_error(E_ERROR,"Pgsql module error. Report this error"); + break; + } + convert_to_boolean_ex(&return_value); +} +/* }}} */ + +/* {{{ proto bool pg_async_request_cancel([resource connection]) + Cancel request */ +PHP_FUNCTION(pg_request_cancel) +{ + php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_REQUEST_CANCEL); +} +/* }}} */ + +/* {{{ proto query bool pg_isbusy([resource connection]) + Get connection is busy or not */ +PHP_FUNCTION(pg_is_busy) +{ + php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_IS_BUSY); +} +/* }}} */ + +/* {{{ proto bool pg_async_exec([resource connection], string qeury) + Send asynchronous query */ +PHP_FUNCTION(pg_send_query) +{ + zval **query, **pgsql_link = NULL; + int id = -1; + PGconn *pgsql; + PGresult *res; + int leftover = 0; + + switch(ZEND_NUM_ARGS()) { + case 1: + if (zend_get_parameters_ex(1, &query)==FAILURE) { + RETURN_FALSE; + } + id = PGG(default_link); + CHECK_DEFAULT_LINK(id); + break; + case 2: + if (zend_get_parameters_ex(2, &pgsql_link, &query)==FAILURE) { + RETURN_FALSE; + } + break; + default: + WRONG_PARAM_COUNT; + break; + } + ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink); + + convert_to_string_ex(query); + if (PQsetnonblocking(pgsql, 1)) { + php_error(E_NOTICE,"PostgreSQL: Cannot set connection to nonblocking mode in pg_send_query()"); + } + if (PQisBusy(pgsql)) { + php_error(E_WARNING,"PostgreSQL: Cannot send multiple query using pg_send_query()"); + RETURN_FALSE; + } + while ((res = PQgetResult(pgsql))) { + PQclear(res); + leftover = 1; + } + if (leftover) { + php_error(E_NOTICE,"PostgreSQL: There are results on this connection. Call pg_get_result() until it returns false"); + } + if (!PQsendQuery(pgsql, Z_STRVAL_PP(query))) { + RETURN_FALSE; + } + if (PQsetnonblocking(pgsql, 0)) { + php_error(E_NOTICE,"PostgreSQL: Cannot set connection to blocking mode in pg_send_query()"); + } + RETURN_TRUE; +} +/* }}} */ + + +/* {{{ proto query resouce pg_arync_result([resource connection]) + Get asynchronous query result */ +PHP_FUNCTION(pg_get_result) +{ + zval **pgsql_link = NULL; + int id = -1; + PGconn *pgsql; + PGresult *pgsql_result; + pgsql_result_handle *pg_result; + + switch(ZEND_NUM_ARGS()) { + case 0: + id = PGG(default_link); + CHECK_DEFAULT_LINK(id); + break; + case 1: + if (zend_get_parameters_ex(1, &pgsql_link)==FAILURE) { + RETURN_FALSE; + } + break; + default: + WRONG_PARAM_COUNT; + break; + } + + ZEND_FETCH_RESOURCE2(pgsql, PGconn *, pgsql_link, id, "PostgreSQL link", le_link, le_plink); + if (PQsetnonblocking(pgsql, 1)) { + php_error(E_NOTICE,"PostgreSQL: Cannot set connection to nonblocking mode in pg_get_result()"); + } + pgsql_result = PQgetResult(pgsql); + if (!pgsql_result) { + /* no result */ + RETURN_FALSE; + } + if (PQsetnonblocking(pgsql, 0)) { + php_error(E_NOTICE,"PostgreSQL: Cannot set connection to blocking mode in pg_get_result()"); + } + pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle)); + pg_result->conn = pgsql; + pg_result->result = pgsql_result; + pg_result->row = -1; + ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result); +} +/* }}} */ + #endif /* diff --git a/ext/pgsql/php_pgsql.h b/ext/pgsql/php_pgsql.h index f9295ac991..43cf4507b2 100644 --- a/ext/pgsql/php_pgsql.h +++ b/ext/pgsql/php_pgsql.h @@ -94,6 +94,12 @@ PHP_FUNCTION(pg_end_copy); PHP_FUNCTION(pg_client_encoding); PHP_FUNCTION(pg_set_client_encoding); #endif +PHP_FUNCTION(pg_reset); +PHP_FUNCTION(pg_status); +PHP_FUNCTION(pg_send_query); +PHP_FUNCTION(pg_request_cancel); +PHP_FUNCTION(pg_get_result); +PHP_FUNCTION(pg_is_busy); void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent); int php_pgsql_get_default_link(INTERNAL_FUNCTION_PARAMETERS); @@ -102,7 +108,7 @@ void php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type); char *get_field_name(PGconn *pgsql, Oid oid, HashTable *list); void php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type); void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type); - +void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS,int entry_type); typedef struct pgLofp { PGconn *conn; -- 2.40.0