From d3b653e97b5e226f1f3fad86bb5359557e06f875 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sat, 9 Jul 2005 03:52:41 +0000 Subject: [PATCH] Added: proto bool PDOStatement::closeCursor() Closes the cursor, leaving the statement ready for re-execution. The purpose of the function is to free up the connection to the server so that other queries may be issued, but leaving the statement in a state that it can be re-executed. This is implemented either as an optional driver specific method (allowing for maximum efficiency), or as the generic PDO fallback if no driver specific function is installed. The PDO generic fallback is semantically the same as writing the following code in your PHP script: do { while ($stmt->fetch()) ; if (!$stmt->nextRowset()) break; } while (true); --- ext/pdo/pdo_stmt.c | 70 ++++++++++++++++++++++++++++++++------ ext/pdo/php_pdo_driver.h | 9 ++++- ext/pdo/tests/pdo_016.phpt | 9 ++--- ext/pdo/tests/pdo_018.phpt | 4 --- ext/pdo/tests/pdo_021.phpt | 2 +- 5 files changed, 73 insertions(+), 21 deletions(-) diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 51770d3130..c6e4b481a5 100755 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -1681,17 +1681,13 @@ static PHP_METHOD(PDOStatement, setFetchMode) /* {{{ proto bool PDOStatement::nextRowset() Advances to the next rowset in a multi-rowset statement handle. Returns true if it succeded, false otherwise */ -static PHP_METHOD(PDOStatement, nextRowset) -{ - pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC); - if (!stmt->methods->next_rowset) { - pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets" TSRMLS_CC); - RETURN_FALSE; +static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) +{ + if (!stmt->methods->next_rowset(stmt TSRMLS_CC)) { + return 0; } - PDO_STMT_CLEAR_ERR(); - /* un-describe */ if (stmt->columns) { int i; @@ -1701,11 +1697,27 @@ static PHP_METHOD(PDOStatement, nextRowset) efree(cols[i].name); } efree(stmt->columns); + stmt->columns = NULL; + stmt->column_count = 0; } - stmt->columns = NULL; - if (!stmt->methods->next_rowset(stmt TSRMLS_CC)) { - stmt->column_count = 0; + pdo_stmt_describe_columns(stmt TSRMLS_CC); + + return 1; +} + +static PHP_METHOD(PDOStatement, nextRowset) +{ + pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (!stmt->methods->next_rowset) { + pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets" TSRMLS_CC); + RETURN_FALSE; + } + + PDO_STMT_CLEAR_ERR(); + + if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) { PDO_HANDLE_STMT_ERR(); RETURN_FALSE; } @@ -1716,6 +1728,41 @@ static PHP_METHOD(PDOStatement, nextRowset) } /* }}} */ +/* {{{ proto bool PDOStatement::closeCursor() + Closes the cursor, leaving the statement ready for re-execution. */ +static PHP_METHOD(PDOStatement, closeCursor) +{ + pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (!stmt->methods->cursor_closer) { + /* emulate it by fetching and discarding rows */ + do { + while (stmt->methods->fetcher(stmt, PDO_FETCH_ORI_NEXT, 0 TSRMLS_CC)) + ; + if (!stmt->methods->next_rowset) { + break; + } + + if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) { + break; + } + + } while (1); + RETURN_TRUE; + } + + PDO_STMT_CLEAR_ERR(); + + if (!stmt->methods->cursor_closer(stmt TSRMLS_CC)) { + PDO_HANDLE_STMT_ERR(); + RETURN_FALSE; + } + + RETURN_TRUE; +} +/* }}} */ + + function_entry pdo_dbstmt_functions[] = { PHP_ME(PDOStatement, execute, NULL, ZEND_ACC_PUBLIC) PHP_ME(PDOStatement, fetch, NULL, ZEND_ACC_PUBLIC) @@ -1733,6 +1780,7 @@ function_entry pdo_dbstmt_functions[] = { PHP_ME(PDOStatement, getColumnMeta, NULL, ZEND_ACC_PUBLIC) PHP_ME(PDOStatement, setFetchMode, NULL, ZEND_ACC_PUBLIC) PHP_ME(PDOStatement, nextRowset, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PDOStatement, closeCursor, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index d0259e5b30..0f0b115ac1 100755 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -44,7 +44,7 @@ PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC); # define FALSE 0 #endif -#define PDO_DRIVER_API 20050708 +#define PDO_DRIVER_API 20050709 enum pdo_param_type { PDO_PARAM_NULL, @@ -367,6 +367,12 @@ typedef int (*pdo_stmt_get_column_meta_func)(pdo_stmt_t *stmt, long colno, zval * to the caller. */ typedef int (*pdo_stmt_next_rowset_func)(pdo_stmt_t *stmt TSRMLS_DC); +/* closes the active cursor on a statement, leaving the prepared + * statement ready for re-execution. Useful to explicitly state + * that you are done with a given rowset, without having to explicitly + * fetch all the rows. */ +typedef int (*pdo_stmt_cursor_closer_func)(pdo_stmt_t *stmt TSRMLS_DC); + struct pdo_stmt_methods { pdo_stmt_dtor_func dtor; pdo_stmt_execute_func executer; @@ -378,6 +384,7 @@ struct pdo_stmt_methods { pdo_stmt_get_attr_func get_attribute; pdo_stmt_get_column_meta_func get_column_meta; pdo_stmt_next_rowset_func next_rowset; + pdo_stmt_cursor_closer_func cursor_closer; }; /* }}} */ diff --git a/ext/pdo/tests/pdo_016.phpt b/ext/pdo/tests/pdo_016.phpt index f6f7cea177..e2faf05c46 100644 --- a/ext/pdo/tests/pdo_016.phpt +++ b/ext/pdo/tests/pdo_016.phpt @@ -18,15 +18,12 @@ $db->exec('INSERT INTO test VALUES(0, \'String0\')'); $db->exec('INSERT INTO test VALUES(1, \'String1\')'); $db->exec('INSERT INTO test VALUES(2, \'String2\')'); -if ($db->getAttribute(PDO_ATTR_DRIVER_NAME) == 'mysql') { - $db->setAttribute(PDO_MYSQL_ATTR_USE_BUFFERED_QUERY, 1); -} - $stmt1 = $db->prepare('SELECT COUNT(idx) FROM test'); $stmt2 = $db->prepare('SELECT idx, txt FROM test ORDER by idx'); $stmt1->execute(); var_dump($stmt1->fetchColumn()); +$stmt1 = null; $stmt2->execute(); $cont = $stmt2->fetchAll(PDO_FETCH_COLUMN|PDO_FETCH_UNIQUE); @@ -61,6 +58,7 @@ foreach($cont as $idx => $txt) $stmt3->bindColumn('txt', $col1); } var_dump($stmt3->fetch(PDO_FETCH_BOUND)); + $stmt3->closeCursor(); var_dump($stmt4->execute()); if ($idx == 0) { @@ -69,6 +67,7 @@ foreach($cont as $idx => $txt) $stmt4->bindColumn('idx', $col2); } var_dump($stmt4->fetch(PDO_FETCH_BOUND)); + $stmt4->closeCursor(); var_dump(array($col2=>$col1)); } @@ -81,9 +80,11 @@ foreach($cont as $idx => $txt) var_dump(array($idx=>$txt)); var_dump($stmt3->execute()); var_dump($stmt3->fetch(PDO_FETCH_BOUND)); + $stmt3->closeCursor(); var_dump($col1); var_dump($stmt4->execute()); var_dump($stmt4->fetch(PDO_FETCH_BOUND)); + $stmt4->closeCursor(); var_dump($col1); } diff --git a/ext/pdo/tests/pdo_018.phpt b/ext/pdo/tests/pdo_018.phpt index b0fc07e5b5..6c45869bd8 100644 --- a/ext/pdo/tests/pdo_018.phpt +++ b/ext/pdo/tests/pdo_018.phpt @@ -77,10 +77,6 @@ $db->setAttribute(PDO_ATTR_ERRMODE, PDO_ERRMODE_EXCEPTION); var_dump($db->query('SELECT COUNT(*) FROM classtypes')->fetchColumn()); var_dump($db->query('SELECT id, name FROM classtypes ORDER by id')->fetchAll(PDO_FETCH_COLUMN|PDO_FETCH_UNIQUE)); -if ($db->getAttribute(PDO_ATTR_DRIVER_NAME) == 'mysql') { - $db->setAttribute(PDO_MYSQL_ATTR_USE_BUFFERED_QUERY, 1); -} - $objs = array(); $objs[0] = new stdClass; $objs[1] = new TestBase; diff --git a/ext/pdo/tests/pdo_021.phpt b/ext/pdo/tests/pdo_021.phpt index c2ac95dbe7..c1688c092b 100644 --- a/ext/pdo/tests/pdo_021.phpt +++ b/ext/pdo/tests/pdo_021.phpt @@ -36,7 +36,7 @@ $select->execute(); $num = $select->fetchColumn(); echo 'There are ' . $num . " rows in the table.\n"; -unset($stmt); +$select->closeCursor(); // Insert using named parameters $stmt2 = $db->prepare("INSERT INTO test VALUES(:first, :second, :third)"); -- 2.40.0