summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Boerger <helly@php.net>2005-10-02 20:07:11 +0000
committerMarcus Boerger <helly@php.net>2005-10-02 20:07:11 +0000
commitca9dd7d82674dc802f9a4c6a6e4600627b3590ce (patch)
tree479302652fe4835dc1fb975f5d15ffd1a3fde21d
parent0ea0e1615f8892c3f024418c69b2398bd949b619 (diff)
downloadphp-git-ca9dd7d82674dc802f9a4c6a6e4600627b3590ce.tar.gz
- Add PDO::setAttribute(PDO::ATTR_STATEMENT_CLASS)
-rwxr-xr-xext/pdo/pdo_dbh.c78
-rwxr-xr-xext/pdo/php_pdo_driver.h4
-rwxr-xr-xext/pdo/tests/pdo_030.phpt176
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()