diff options
author | Marcus Boerger <helly@php.net> | 2005-10-02 18:32:05 +0000 |
---|---|---|
committer | Marcus Boerger <helly@php.net> | 2005-10-02 18:32:05 +0000 |
commit | 8ece2140cb1636ea1d2d15e98510812ae4d0a46c (patch) | |
tree | cc851de1eee18f7055d46956e9d87c271e33d4a3 /ext/pdo | |
parent | 9688e4017b0a53988b751f7e4347eccbc621b322 (diff) | |
download | php-git-8ece2140cb1636ea1d2d15e98510812ae4d0a46c.tar.gz |
- Add ability to change default statement class for PDO::execute()/query()
Diffstat (limited to 'ext/pdo')
-rwxr-xr-x | ext/pdo/pdo_dbh.c | 71 | ||||
-rwxr-xr-x | ext/pdo/php_pdo_driver.h | 4 | ||||
-rwxr-xr-x | ext/pdo/tests/pdo_030.phpt | 160 |
3 files changed, 230 insertions, 5 deletions
diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index cc35cac86d..0184aa771c 100755 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -511,7 +511,7 @@ static PHP_METHOD(PDO, prepare) || zend_u_lookup_class(Z_TYPE_PP(item), Z_UNIVAL_PP(item), Z_UNILEN_PP(item), &pce TSRMLS_CC) == FAILURE ) { pdo_raise_impl_error(dbh, NULL, "HY000", - "PDO_ATTR_STATEMENT_CLASS requires format array(classname, ctor_args); " + "PDO_ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); " "the classname must be a string specifying an existing class" TSRMLS_CC); PDO_HANDLE_DBH_ERR(); @@ -544,8 +544,8 @@ static PHP_METHOD(PDO, prepare) ctor_args = NULL; } } else { - dbstmt_ce = U_CLASS_ENTRY(pdo_dbstmt_ce); - ctor_args = NULL; + dbstmt_ce = dbh->def_stmt_ce; + ctor_args = dbh->def_stmt_ctor_args; } if (!pdo_stmt_instantiate(dbh, return_value, dbstmt_ce, ctor_args TSRMLS_CC)) { @@ -712,6 +712,62 @@ static PHP_METHOD(PDO, setAttribute) convert_to_long(value); dbh->stringify = Z_LVAL_P(value) ? 1 : 0; RETURN_TRUE; + + case PDO_ATTR_STATEMENT_CLASS: { + /* array(string classname, array(mixed ctor_args)) */ + zend_class_entry **pce; + zval **item; + + if (dbh->is_persistent) { + pdo_raise_impl_error(dbh, NULL, "HY000", + "PDO_ATTR_STATEMENT_CLASS cannot be used with persistent PDO instances" + TSRMLS_CC); + PDO_HANDLE_DBH_ERR(); + RETURN_FALSE; + } + if (Z_TYPE_P(value) != IS_ARRAY + || zend_hash_index_find(Z_ARRVAL_P(value), 0, (void**)&item) == FAILURE + || !PDO_ZVAL_PP_IS_TEXT(item) + || zend_u_lookup_class(Z_TYPE_PP(item), Z_UNIVAL_PP(item), Z_UNILEN_PP(item), &pce TSRMLS_CC) == FAILURE + ) { + pdo_raise_impl_error(dbh, NULL, "HY000", + "PDO_ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); " + "the classname must be a string specifying an existing class" + TSRMLS_CC); + PDO_HANDLE_DBH_ERR(); + RETURN_FALSE; + } + if (!instanceof_function(*pce, U_CLASS_ENTRY(pdo_dbstmt_ce) TSRMLS_CC)) { + pdo_raise_impl_error(dbh, NULL, "HY000", + "user-supplied statement class must be derived from PDOStatement" TSRMLS_CC); + PDO_HANDLE_DBH_ERR(); + RETURN_FALSE; + } + if ((*pce)->constructor && !((*pce)->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) { + pdo_raise_impl_error(dbh, NULL, "HY000", + "user-supplied statement class cannot have a public constructor" TSRMLS_CC); + PDO_HANDLE_DBH_ERR(); + RETURN_FALSE; + } + dbh->def_stmt_ce = *pce; + if (dbh->def_stmt_ctor_args) { + zval_ptr_dtor(&dbh->def_stmt_ctor_args); + dbh->def_stmt_ctor_args = NULL; + } + if (zend_hash_index_find(Z_ARRVAL_P(value), 1, (void**)&item) == SUCCESS) { + if (Z_TYPE_PP(item) != IS_ARRAY) { + pdo_raise_impl_error(dbh, NULL, "HY000", + "PDO_ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); " + "ctor_args must be an array" + TSRMLS_CC); + PDO_HANDLE_DBH_ERR(); + RETURN_FALSE; + } + (*item)->refcount++; + dbh->def_stmt_ctor_args = *item; + } + RETURN_TRUE; + } default: ; @@ -900,7 +956,7 @@ static PHP_METHOD(PDO, query) PDO_DBH_CLEAR_ERR(); PDO_CONSTRUCT_CHECK; - if (!pdo_stmt_instantiate(dbh, return_value, U_CLASS_ENTRY(pdo_dbstmt_ce), NULL TSRMLS_CC)) { + if (!pdo_stmt_instantiate(dbh, return_value, dbh->def_stmt_ce, dbh->def_stmt_ctor_args TSRMLS_CC)) { pdo_raise_impl_error(dbh, NULL, "HY000", "failed to instantiate user supplied statement class" TSRMLS_CC); return; } @@ -934,7 +990,7 @@ static PHP_METHOD(PDO, query) stmt->executed = 1; } if (ret) { - pdo_stmt_construct(stmt, return_value, U_CLASS_ENTRY(pdo_dbstmt_ce), NULL TSRMLS_CC); + pdo_stmt_construct(stmt, return_value, dbh->def_stmt_ce, dbh->def_stmt_ctor_args TSRMLS_CC); return; } } @@ -1244,6 +1300,10 @@ static void dbh_free(pdo_dbh_t *dbh TSRMLS_DC) if (dbh->password) { pefree(dbh->password, dbh->is_persistent); } + + if (dbh->def_stmt_ctor_args) { + zval_ptr_dtor(&dbh->def_stmt_ctor_args); + } pefree(dbh, dbh->is_persistent); } @@ -1281,6 +1341,7 @@ zend_object_value pdo_dbh_new(zend_class_entry *ce TSRMLS_DC) ALLOC_HASHTABLE(dbh->properties); zend_hash_init(dbh->properties, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_copy(dbh->properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + dbh->def_stmt_ce = U_CLASS_ENTRY(pdo_dbstmt_ce); retval.handle = zend_objects_store_put(dbh, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_dbh_free_storage, NULL TSRMLS_CC); retval.handlers = &pdo_dbh_object_handlers; diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index 04a63b0e90..171a25df2b 100755 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -475,6 +475,10 @@ struct _pdo_dbh_t { HashTable *cls_methods[PDO_DBH_DRIVER_METHOD_KIND__MAX]; pdo_driver_t *driver; + + zend_class_entry *def_stmt_ce; + + zval *def_stmt_ctor_args; }; /* describes a column */ diff --git a/ext/pdo/tests/pdo_030.phpt b/ext/pdo/tests/pdo_030.phpt new file mode 100755 index 0000000000..3e54750eae --- /dev/null +++ b/ext/pdo/tests/pdo_030.phpt @@ -0,0 +1,160 @@ +--TEST-- +PDO Common: extending PDO (4) +--SKIPIF-- +<?php # vim:ft=php +if (!extension_loaded('pdo')) die('skip'); +$dir = getenv('REDIR_TEST_DIR'); +if (false == $dir) die('skip no driver'); +require_once $dir . 'pdo_test.inc'; +PDOTest::skip(); +?> +--FILE-- +<?php +if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.dirname(__FILE__) . '/../../pdo/tests/'); +require getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; + +$data = array( + array('10', 'Abc', 'zxy'), + array('20', 'Def', 'wvu'), + array('30', 'Ghi', 'tsr'), +); + +class PDOStatementX extends PDOStatement +{ + public $dbh; + + protected function __construct($dbh) + { + $this->dbh = $dbh; + $this->setFetchMode(PDO::FETCH_ASSOC); + echo __METHOD__ . "()\n"; + } + + function __destruct() + { + echo __METHOD__ . "()\n"; + } + + function execute() + { + echo __METHOD__ . "()\n"; + parent::execute(); + } +} + +class PDODatabase extends PDO +{ + function __destruct() + { + echo __METHOD__ . "()\n"; + } + + function query($sql) + { + echo __METHOD__ . "()\n"; + return parent::query($sql); + } +} + +$db = PDOTest::factory('PDODatabase'); +var_dump(get_class($db)); + +$db->exec('CREATE TABLE test(id INT NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(16))'); + +$stmt = $db->prepare("INSERT INTO test VALUES(?, ?, ?)"); +var_dump(get_class($stmt)); +foreach ($data as $row) { + $stmt->execute($row); +} + +unset($stmt); + +echo "===QUERY===\n"; + +$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatementx', array($db))); +$stmt = $db->query('SELECT * FROM test'); +var_dump(get_class($stmt)); +var_dump(get_class($stmt->dbh)); + +echo "===FOREACH===\n"; + +foreach($stmt as $obj) { + var_dump($obj); +} + +echo "===DONE===\n"; +exit(0); +?> +--EXPECT-- +string(11) "PDODatabase" +string(12) "PDOStatement" +===QUERY=== +PDODatabase::query() +PDOStatementX::__construct() +string(13) "PDOStatementX" +string(11) "PDODatabase" +===FOREACH=== +array(3) { + ["id"]=> + string(2) "10" + ["val"]=> + string(3) "Abc" + ["val2"]=> + string(3) "zxy" +} +array(3) { + ["id"]=> + string(2) "20" + ["val"]=> + string(3) "Def" + ["val2"]=> + string(3) "wvu" +} +array(3) { + ["id"]=> + string(2) "30" + ["val"]=> + string(3) "Ghi" + ["val2"]=> + string(3) "tsr" +} +===DONE=== +PDODatabase::__destruct() +PDOStatementX::__destruct() +--UEXPECT-- +unicode(11) "PDODatabase" +unicode(12) "PDOStatement" +===QUERY=== +PDODatabase::query() +PDOStatementX::__construct() +PDOStatementX::execute() +unicode(13) "PDOStatementX" +unicode(11) "PDODatabase" +===FOREACH=== +array(3) { + [u"id"]=> + unicode(2) "10" + [u"val"]=> + unicode(3) "Abc" + [u"val2"]=> + unicode(3) "zxy" +} +array(3) { + [u"id"]=> + unicode(2) "20" + [u"val"]=> + unicode(3) "Def" + [u"val2"]=> + unicode(3) "wvu" +} +array(3) { + [u"id"]=> + unicode(2) "30" + [u"val"]=> + unicode(3) "Ghi" + [u"val2"]=> + unicode(3) "tsr" +} +===DONE=== +PDODatabase::__destruct() +PDOStatementX::__destruct() |