Index: pgsql.c
===================================================================
RCS file: /repository/php4/ext/pgsql/pgsql.c,v
retrieving revision 1.130
diff -u -r1.130 pgsql.c
--- pgsql.c	11 Oct 2001 23:33:40 -0000	1.130
+++ pgsql.c	25 Nov 2001 09:35:22 -0000
@@ -94,6 +94,12 @@
 	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 _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_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 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 @@
 	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 @@
 {
 	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 @@
 	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 @@
 		status = (ExecStatusType) PQstatus(pgsql);
 	}
 	
-	
 	switch (status) {
 		case PGRES_EMPTY_QUERY:
 		case PGRES_BAD_RESPONSE:
@@ -1962,7 +2012,240 @@
 }
 /* }}} */
 #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
 
 /*
Index: php_pgsql.h
===================================================================
RCS file: /repository/php4/ext/pgsql/php_pgsql.h,v
retrieving revision 1.33
diff -u -r1.33 php_pgsql.h
--- php_pgsql.h	26 Sep 2001 21:44:48 -0000	1.33
+++ php_pgsql.h	25 Nov 2001 09:35:23 -0000
@@ -94,6 +94,12 @@
 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 @@
 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;

