diff options
author | Marcus Boerger <helly@php.net> | 2005-10-02 20:07:11 +0000 |
---|---|---|
committer | Marcus Boerger <helly@php.net> | 2005-10-02 20:07:11 +0000 |
commit | ca9dd7d82674dc802f9a4c6a6e4600627b3590ce (patch) | |
tree | 479302652fe4835dc1fb975f5d15ffd1a3fde21d | |
parent | 0ea0e1615f8892c3f024418c69b2398bd949b619 (diff) | |
download | php-git-ca9dd7d82674dc802f9a4c6a6e4600627b3590ce.tar.gz |
- Add PDO::setAttribute(PDO::ATTR_STATEMENT_CLASS)
-rwxr-xr-x | ext/pdo/pdo_dbh.c | 78 | ||||
-rwxr-xr-x | ext/pdo/php_pdo_driver.h | 4 | ||||
-rwxr-xr-x | ext/pdo/tests/pdo_030.phpt | 176 |
3 files changed, 252 insertions, 6 deletions
diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 2d59b8ec20..110a0af5b0 100755 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -539,8 +539,8 @@ static PHP_METHOD(PDO, prepare) ctor_args = NULL; } } else { - dbstmt_ce = 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)) { @@ -708,6 +708,62 @@ static PHP_METHOD(PDO, setAttribute) 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 + || Z_TYPE_PP(item) != IS_STRING + || zend_lookup_class(Z_STRVAL_PP(item), Z_STRLEN_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, 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: ; } @@ -763,6 +819,15 @@ static PHP_METHOD(PDO, getAttribute) case PDO_ATTR_DRIVER_NAME: RETURN_STRINGL((char*)dbh->driver->driver_name, dbh->driver->driver_name_len, 1); + + case PDO_ATTR_STATEMENT_CLASS: + array_init(return_value); + add_next_index_string(return_value, dbh->def_stmt_ce->name, 1); + if (dbh->def_stmt_ctor_args) { + dbh->def_stmt_ctor_args->refcount++; + add_next_index_zval(return_value, dbh->def_stmt_ctor_args); + } + return; } if (!dbh->methods->get_attribute) { @@ -895,7 +960,7 @@ static PHP_METHOD(PDO, query) PDO_DBH_CLEAR_ERR(); PDO_CONSTRUCT_CHECK; - if (!pdo_stmt_instantiate(dbh, return_value, 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; } @@ -929,7 +994,7 @@ static PHP_METHOD(PDO, query) stmt->executed = 1; } if (ret) { - pdo_stmt_construct(stmt, return_value, pdo_dbstmt_ce, NULL TSRMLS_CC); + pdo_stmt_construct(stmt, return_value, dbh->def_stmt_ce, dbh->def_stmt_ctor_args TSRMLS_CC); return; } } @@ -1145,7 +1210,7 @@ PDO_API void php_pdo_declare_stringl_constant(const char *const_name, size_t name_len, const char *value, size_t value_len TSRMLS_DC) { #if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1 - zend_declare_class_constant_stringl(pdo_dbh_ce, const_name, name_len, value, value_len TSRMLS_CC); + zend_declare_class_constant_stringl(pdo_dbh_ce, (char*)const_name, name_len, (char*)value, value_len TSRMLS_CC); #else zval *constant = malloc(sizeof(*constant)); ZVAL_STRINGL(constant, zend_strndup(value, value_len), value_len, 0); @@ -1158,7 +1223,7 @@ PDO_API void php_pdo_declare_long_constant(const char *const_name, unsigned int name_len, long value TSRMLS_DC) { #if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1 - zend_declare_class_constant_long(pdo_dbh_ce, const_name, name_len, value TSRMLS_CC); + zend_declare_class_constant_long(pdo_dbh_ce, (char*)const_name, name_len, value TSRMLS_CC); #else zval *constant = malloc(sizeof(*constant)); ZVAL_LONG(constant, value); @@ -1319,6 +1384,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 = 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 f1f2910cd3..15efc314c8 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..0ebbdf3730 --- /dev/null +++ b/ext/pdo/tests/pdo_030.phpt @@ -0,0 +1,176 @@ +--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"; + +var_dump($db->getAttribute(PDO::ATTR_STATEMENT_CLASS)); +$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatementx', array($db))); +var_dump($db->getAttribute(PDO::ATTR_STATEMENT_CLASS)); +$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); +?> +--EXPECTF-- +string(11) "PDODatabase" +string(12) "PDOStatement" +===QUERY=== +array(1) { + [0]=> + string(12) "PDOStatement" +} +array(2) { + [0]=> + string(13) "PDOStatementX" + [1]=> + array(1) { + [0]=> + object(PDODatabase)#%d (0) { + } + } +} +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() |