From: Wez Furlong Date: Wed, 27 Oct 2004 10:26:27 +0000 (+0000) Subject: Synopsis: X-Git-Tag: RELEASE_0_2~825 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=35b00ffdabfadbb78f564358a6cf7a595f1227fe;p=php Synopsis: PDOStatement::setFetchMode() reset default fetch() mode for a statement to PDO_FETCH_BOTH PDOStatement::setFetchMode(PDO_FETCH_NUM) PDOStatement::setFetchMode(PDO_FETCH_ASSOC) PDOStatement::setFetchMode(PDO_FETCH_BOTH) PDOStatement::setFetchMode(PDO_FETCH_OBJ) set default fetch() mode for a statement. PDOStatement::setFetchMode(PDO_FETCH_COLUMN, int colno) set default fetch() mode to retrieve colno-th column on each fetch() call. PDOStatement::setFetchMode(PDO_FETCH_CLASS, string classname [, array ctor args]) set default fetch() mode to create an instance of classname, calling it's ctor, passing the optional ctor args. The names of the columns in the result set will be used as property names on the object instance. PPP rules apply. [NOTE: calling ctor is not yet implemented] [TODO: this might crash PHP for persistent PDO handles] PDOStatement::setFetchMode(PDO_FETCH_INTO, object obj) Similar to PDO_FETCH_CLASS, except that each iteration will update the supplied object properties. [TODO: this might crash PHP for persistent PDO handles] The default fetch() mode is used when no parameters are passed to PDOStatement::fetch(). When using a statement in an iterator context, PDOStatement::fetch() is called implicitly on each iteration. object PDO::queryAndIterate(string sql, ) This is semantically equivalent to: $stmt = $pdo->prepare($sql); $stmt->execute(); $stmt->setFetchMode($args); return $stmt; Example/Intended usage: /* fetch an array with numeric and string keys */ foreach ($pdo->queryAndIterate("select NAME, VALUE from test") as $row) { debug_zval_dump($row); } /* fetch the value of column 1 into $row on each iteration */ foreach ($pdo->queryAndIterate("select NAME, VALUE from test", PDO_FETCH_COLUMN, 1) as $row) { debug_zval_dump($row); // string(3) "foo" } /* create a new instance of class Foo on each iteration */ foreach ($pdo->queryAndIterate("select NAME, VALUE from test", PDO_FETCH_CLASS, 'Foo') as $row) { debug_zval_dump($row); /* Object(Foo)#4 (2) refcount(2){ ["NAME"]=> string(12) "foo220051429" refcount(2) ["VALUE"]=> string(12) "bar789825748" refcount(2) } */ } etc. --- diff --git a/ext/pdo/pdo.c b/ext/pdo/pdo.c index cc620d810e..ea03f61cf3 100755 --- a/ext/pdo/pdo.c +++ b/ext/pdo/pdo.c @@ -225,6 +225,9 @@ PHP_MINIT_FUNCTION(pdo) REGISTER_LONG_CONSTANT("PDO_FETCH_BOTH", (long)PDO_FETCH_BOTH, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PDO_FETCH_OBJ", (long)PDO_FETCH_OBJ, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PDO_FETCH_BOUND",(long)PDO_FETCH_BOUND, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PDO_FETCH_COLUMN",(long)PDO_FETCH_COLUMN, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PDO_FETCH_CLASS",(long)PDO_FETCH_CLASS, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PDO_FETCH_INTO", (long)PDO_FETCH_INTO, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PDO_ATTR_AUTOCOMMIT", (long)PDO_ATTR_AUTOCOMMIT, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PDO_ATTR_SCROLL", (long)PDO_ATTR_SCROLL, CONST_CS|CONST_PERSISTENT); @@ -272,6 +275,7 @@ PHP_MINIT_FUNCTION(pdo) INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions); ce.create_object = pdo_dbstmt_new; pdo_dbstmt_ce = zend_register_internal_class(&ce TSRMLS_CC); + pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get; INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions); ce.create_object = pdo_row_new; diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index b1cda08f37..2e814ed99c 100755 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -348,6 +348,8 @@ static PHP_METHOD(PDO, prepare) /* unconditionally keep this for later reference */ stmt->query_string = estrndup(statement, statement_len); stmt->query_stringlen = statement_len; + stmt->default_fetch_type = PDO_FETCH_BOTH; + if (dbh->methods->preparer(dbh, statement, statement_len, stmt, options, driver_options TSRMLS_CC)) { /* prepared; create a statement object for PHP land to access it */ Z_TYPE_P(return_value) = IS_OBJECT; @@ -630,6 +632,76 @@ static PHP_METHOD(PDO, errorInfo) } /* }}} */ +/* {{{ proto object PDO::queryAndIterate(string sql [, PDOStatement::setFetchMode() args]) + Prepare and execute $sql; returns the statement object for iteration */ +static PHP_METHOD(PDO, queryAndIterate) +{ + pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + pdo_stmt_t *stmt; + char *statement; + int statement_len; + zval *driver_options = NULL; + long options = 0; + + if (FAILURE == zend_parse_parameters(1 TSRMLS_CC, "s", &statement, + &statement_len)) { + RETURN_FALSE; + } + + PDO_DBH_CLEAR_ERR(); + stmt = ecalloc(1, sizeof(*stmt)); + /* unconditionally keep this for later reference */ + stmt->query_string = estrndup(statement, statement_len); + stmt->query_stringlen = statement_len; + stmt->default_fetch_type = PDO_FETCH_BOTH; + + if (dbh->methods->preparer(dbh, statement, statement_len, stmt, options, driver_options TSRMLS_CC)) { + /* prepared; create a statement object for PHP land to access it */ + Z_TYPE_P(return_value) = IS_OBJECT; + Z_OBJ_HANDLE_P(return_value) = zend_objects_store_put(stmt, NULL, pdo_dbstmt_free_storage, NULL TSRMLS_CC); + Z_OBJ_HT_P(return_value) = &pdo_dbstmt_object_handlers; + + /* give it a reference to me */ + stmt->database_object_handle = *getThis(); + zend_objects_store_add_ref(getThis() TSRMLS_CC); + stmt->dbh = dbh; + + /* we haven't created a lazy object yet */ + ZVAL_NULL(&stmt->lazy_object_ref); + + stmt->refcount = 1; + + if (ZEND_NUM_ARGS() == 1 || + SUCCESS == pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, + stmt, 1)) { + PDO_STMT_CLEAR_ERR(); + + /* now execute the statement */ + PDO_STMT_CLEAR_ERR(); + if (stmt->methods->executer(stmt TSRMLS_CC)) { + int ret = 1; + if (!stmt->executed) { + if (stmt->dbh->alloc_own_columns) { + ret = pdo_stmt_describe_columns(stmt TSRMLS_CC); + } + stmt->executed = 1; + } + if (ret) { + return; + } + } + } + /* something broke */ + PDO_HANDLE_STMT_ERR(); + + /* TODO: kill the object handle for the stmt here */ + } else { + efree(stmt); + PDO_HANDLE_DBH_ERR(); + } + RETURN_FALSE; +} +/* }}} */ function_entry pdo_dbh_functions[] = { PHP_ME_MAPPING(__construct, dbh_constructor, NULL) @@ -644,6 +716,7 @@ function_entry pdo_dbh_functions[] = { PHP_ME(PDO, errorCode, NULL, ZEND_ACC_PUBLIC) PHP_ME(PDO, errorInfo, NULL, ZEND_ACC_PUBLIC) PHP_ME(PDO, getAttribute, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PDO, queryAndIterate,NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 3d2d183190..e4f89b16a4 100755 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -108,7 +108,7 @@ iterate: return ret; } -static int describe_columns(pdo_stmt_t *stmt TSRMLS_DC) +int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC) { int col; @@ -338,7 +338,7 @@ static PHP_METHOD(PDOStatement, execute) if (stmt->dbh->alloc_own_columns) { /* for "big boy" drivers, we need to allocate memory to fetch * the results into, so lets do that now */ - ret = describe_columns(stmt TSRMLS_CC); + ret = pdo_stmt_describe_columns(stmt TSRMLS_CC); } stmt->executed = 1; @@ -394,7 +394,7 @@ static int do_fetch_common(pdo_stmt_t *stmt, int do_bind TSRMLS_DC) } /* some drivers might need to describe the columns now */ - if (!stmt->columns && !describe_columns(stmt TSRMLS_CC)) { + if (!stmt->columns && !pdo_stmt_describe_columns(stmt TSRMLS_CC)) { return 0; } @@ -436,6 +436,10 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value, enum pdo_ { enum pdo_fetch_type really_how = how; + if (really_how == PDO_FETCH_USE_DEFAULT) { + really_how = how = stmt->default_fetch_type; + } + if (!do_fetch_common(stmt, do_bind TSRMLS_CC)) { return 0; } @@ -453,10 +457,44 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value, enum pdo_ return 1; } - array_init(return_value); + switch (how) { + case PDO_FETCH_ASSOC: + case PDO_FETCH_BOTH: + case PDO_FETCH_NUM: + array_init(return_value); + break; + + case PDO_FETCH_COLUMN: + if (stmt->fetch.column >= 0 && stmt->fetch.column < stmt->column_count) { + fetch_value(stmt, return_value, stmt->fetch.column TSRMLS_CC); + return 1; + } + return 0; - if (how == PDO_FETCH_OBJ) { - how = PDO_FETCH_ASSOC; + case PDO_FETCH_OBJ: + object_init_ex(return_value, ZEND_STANDARD_CLASS_DEF_PTR); + break; + + case PDO_FETCH_CLASS: + object_init_ex(return_value, stmt->fetch.cls.ce); + + /* TODO: call ctor */ + break; + + case PDO_FETCH_INTO: + Z_TYPE_P(return_value) = IS_OBJECT; + Z_OBJ_HANDLE_P(return_value) = Z_OBJ_HANDLE_P(stmt->fetch.into); + Z_OBJ_HT_P(return_value) = Z_OBJ_HT_P(stmt->fetch.into); + zend_objects_store_add_ref(stmt->fetch.into); + + if (zend_get_class_entry(return_value) == ZEND_STANDARD_CLASS_DEF_PTR) { + how = PDO_FETCH_OBJ; + } + break; + + default: + /* shouldn't happen */ + return 0; } for (i = 0; i < stmt->column_count; i++) { @@ -464,20 +502,29 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value, enum pdo_ MAKE_STD_ZVAL(val); fetch_value(stmt, val, i TSRMLS_CC); - if (how == PDO_FETCH_ASSOC || how == PDO_FETCH_BOTH) { - add_assoc_zval(return_value, stmt->columns[i].name, val); - } - if (how == PDO_FETCH_NUM || how == PDO_FETCH_BOTH) { - add_next_index_zval(return_value, val); - } + switch (how) { + case PDO_FETCH_ASSOC: + add_assoc_zval(return_value, stmt->columns[i].name, val); + break; - if (how == PDO_FETCH_BOTH) { - ZVAL_ADDREF(val); - } - } + case PDO_FETCH_BOTH: + add_assoc_zval(return_value, stmt->columns[i].name, val); + ZVAL_ADDREF(val); + add_next_index_zval(return_value, val); + break; + + case PDO_FETCH_NUM: + add_next_index_zval(return_value, val); + break; - if (really_how == PDO_FETCH_OBJ) { - object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value)); + case PDO_FETCH_OBJ: + case PDO_FETCH_INTO: + case PDO_FETCH_CLASS: + zend_update_property(NULL, return_value, + stmt->columns[i].name, stmt->columns[i].namelen, + val TSRMLS_CC); + break; + } } } @@ -488,7 +535,7 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value, enum pdo_ Fetches the next row and returns it, or false if there are no more rows */ static PHP_METHOD(PDOStatement, fetch) { - long how = PDO_FETCH_BOTH; + long how = PDO_FETCH_USE_DEFAULT; pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC); if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &how)) { @@ -528,7 +575,7 @@ static PHP_METHOD(PDOStatement, fetchSingle) static PHP_METHOD(PDOStatement, fetchAll) { pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC); - long how = PDO_FETCH_BOTH; + long how = PDO_FETCH_USE_DEFAULT; zval *data; if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &how)) { @@ -750,6 +797,140 @@ static PHP_METHOD(PDOStatement, getColumnMeta) } /* }}} */ +/* {{{ proto bool PDOStatement::setFetchMode(int mode [) + Returns meta data for a numbered column */ + +int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip) +{ + long mode = PDO_FETCH_BOTH; + int argc = ZEND_NUM_ARGS() - skip; + zval ***args; + zend_class_entry **cep; + + /* TODO: clear up class stuff here */ + switch (stmt->default_fetch_type) { + case PDO_FETCH_CLASS: + if (stmt->fetch.cls.ctor_args) { + FREE_ZVAL(stmt->fetch.cls.ctor_args); + stmt->fetch.cls.ctor_args = NULL; + } + break; + + case PDO_FETCH_INTO: + if (stmt->fetch.into) { + ZVAL_DELREF(stmt->fetch.into); + stmt->fetch.into = NULL; + } + break; + default: + ; + } + + stmt->default_fetch_type = PDO_FETCH_BOTH; + + if (argc == 0) { + return SUCCESS; + } + + args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval*), 0); + + if (FAILURE == zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args)) { +fail_out: + efree(args); + return FAILURE; + } + + convert_to_long_ex(args[skip]); + mode = Z_LVAL_PP(args[skip]); + + switch (mode) { + case PDO_FETCH_LAZY: + case PDO_FETCH_ASSOC: + case PDO_FETCH_NUM: + case PDO_FETCH_BOTH: + case PDO_FETCH_OBJ: + case PDO_FETCH_BOUND: + break; + + case PDO_FETCH_COLUMN: + if (argc != 2) { + goto fail_out; + } + convert_to_long_ex(args[skip+1]); + stmt->fetch.column = Z_LVAL_PP(args[skip+1]); + break; + + case PDO_FETCH_CLASS: + if (argc < 2 || argc > 3) { + goto fail_out; + } + convert_to_string_ex(args[skip+1]); + + if (FAILURE == zend_lookup_class(Z_STRVAL_PP(args[skip+1]), + Z_STRLEN_PP(args[skip+1]), &cep)) { + goto fail_out; + } + + if (!cep || !*cep) { + goto fail_out; + } + + stmt->fetch.cls.ce = *cep; + + if (stmt->dbh->is_persistent) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement. This will be fixed in a later release"); + } + + if (argc == 3) { + convert_to_array_ex(args[skip+2]); + stmt->fetch.cls.ctor_args = *args[skip+2]; + zval_copy_ctor(stmt->fetch.cls.ctor_args); + } + break; + + case PDO_FETCH_INTO: + if (argc != 2) { + goto fail_out; + } + if (Z_TYPE_PP(args[skip+1]) != IS_OBJECT) { + goto fail_out; + } + + if (stmt->dbh->is_persistent) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement. This will be fixed in a later release"); + } + + MAKE_STD_ZVAL(stmt->fetch.into); + + Z_TYPE_P(stmt->fetch.into) = IS_OBJECT; + Z_OBJ_HANDLE_P(stmt->fetch.into) = Z_OBJ_HANDLE_PP(args[skip+1]); + Z_OBJ_HT_P(stmt->fetch.into) = Z_OBJ_HT_PP(args[skip+1]); + zend_objects_store_add_ref(stmt->fetch.into); + break; + + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "mode is out of range"); + return FAILURE; + } + + stmt->default_fetch_type = mode; + efree(args); + + return SUCCESS; +} + +static PHP_METHOD(PDOStatement, setFetchMode) +{ + pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETVAL_BOOL( + pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, + stmt, 0) == SUCCESS ? 1 : 0 + ); +} +/* }}} */ + + function_entry pdo_dbstmt_functions[] = { PHP_ME(PDOStatement, execute, NULL, ZEND_ACC_PUBLIC) PHP_ME(PDOStatement, fetch, NULL, ZEND_ACC_PUBLIC) @@ -764,6 +945,7 @@ function_entry pdo_dbstmt_functions[] = { PHP_ME(PDOStatement, getAttribute, NULL, ZEND_ACC_PUBLIC) PHP_ME(PDOStatement, columnCount, NULL, ZEND_ACC_PUBLIC) PHP_ME(PDOStatement, getColumnMeta, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PDOStatement, setFetchMode, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; @@ -959,6 +1141,126 @@ zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC) } /* }}} */ +/* {{{ statement iterator */ + +struct php_pdo_iterator { + zend_object_iterator iter; + pdo_stmt_t *stmt; + ulong key; + zval *fetch_ahead; +}; + +static void pdo_stmt_iter_dtor(zend_object_iterator *iter TSRMLS_DC) +{ + struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data; + + if (--I->stmt->refcount == 0) { + free_statement(I->stmt TSRMLS_CC); + } + + if (I->fetch_ahead) { + ZVAL_DELREF(I->fetch_ahead); + } + + efree(I); +} + +static int pdo_stmt_iter_valid(zend_object_iterator *iter TSRMLS_DC) +{ + struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data; + + return I->fetch_ahead ? SUCCESS : FAILURE; +} + +static void pdo_stmt_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) +{ + struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data; + zval **ptr_ptr; + zval *ptr; + + /* sanity */ + if (!I->fetch_ahead) { + *data = NULL; + return; + } + + ptr_ptr = emalloc(sizeof(*ptr_ptr)); + *ptr_ptr = I->fetch_ahead; + ZVAL_ADDREF(I->fetch_ahead); + + *data = ptr_ptr; +} + +static int pdo_stmt_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, + ulong *int_key TSRMLS_DC) +{ + struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data; + + if (I->key == (ulong)-1) { + return HASH_KEY_NON_EXISTANT; + } + *int_key = I->key; + return HASH_KEY_IS_LONG; +} + +static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC) +{ + struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data; + + if (I->fetch_ahead) { + ZVAL_DELREF(I->fetch_ahead); + I->fetch_ahead = NULL; + } + + MAKE_STD_ZVAL(I->fetch_ahead); + + if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT TSRMLS_CC)) { + pdo_stmt_t *stmt = I->stmt; /* for PDO_HANDLE_STMT_ERR() */ + + PDO_HANDLE_STMT_ERR(); + I->key = (ulong)-1; + FREE_ZVAL(I->fetch_ahead); + I->fetch_ahead = NULL; + + return; + } + + I->key++; +} + +static zend_object_iterator_funcs pdo_stmt_iter_funcs = { + pdo_stmt_iter_dtor, + pdo_stmt_iter_valid, + pdo_stmt_iter_get_data, + pdo_stmt_iter_get_key, + pdo_stmt_iter_move_forwards, + NULL +}; + +zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object TSRMLS_DC) +{ + pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC); + struct php_pdo_iterator *I; + + I = ecalloc(1, sizeof(*I)); + I->iter.funcs = &pdo_stmt_iter_funcs; + I->iter.data = I; + I->stmt = stmt; + stmt->refcount++; + + MAKE_STD_ZVAL(I->fetch_ahead); + if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT TSRMLS_CC)) { + PDO_HANDLE_STMT_ERR(); + I->key = (ulong)-1; + FREE_ZVAL(I->fetch_ahead); + I->fetch_ahead = NULL; + } + + return &I->iter; +} + +/* }}} */ + /* {{{ overloaded handlers for PDORow class (used by PDO_FETCH_LAZY) */ function_entry pdo_row_functions[] = { diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index 082154a533..4bc96d51b3 100755 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -35,7 +35,7 @@ struct pdo_bound_param_data; # define FALSE 0 #endif -#define PDO_DRIVER_API 20040925 +#define PDO_DRIVER_API 20041027 enum pdo_param_type { PDO_PARAM_NULL, @@ -43,16 +43,20 @@ enum pdo_param_type { PDO_PARAM_STR, PDO_PARAM_LOB, PDO_PARAM_STMT, /* hierarchical result set */ - }; enum pdo_fetch_type { + PDO_FETCH_USE_DEFAULT, PDO_FETCH_LAZY, PDO_FETCH_ASSOC, PDO_FETCH_NUM, PDO_FETCH_BOTH, PDO_FETCH_OBJ, PDO_FETCH_BOUND, /* return true/false only; rely on bound columns */ + PDO_FETCH_COLUMN, /* fetch a numbered column only */ + PDO_FETCH_CLASS, /* create an instance of named class, call ctor and set properties */ + PDO_FETCH_INTO, /* fetch row into an existing object */ + PDO_FETCH__MAX /* must be last */ }; enum pdo_attribute_type { @@ -358,6 +362,7 @@ struct _pdo_dbh_t { const char *persistent_id; int persistent_id_len; unsigned int refcount; + }; /* describes a column */ @@ -434,6 +439,17 @@ struct _pdo_stmt_t { * Let's keep it here. */ zval lazy_object_ref; unsigned long refcount; + + /* defaults for fetches */ + enum pdo_fetch_type default_fetch_type; + union { + int column; + struct { + zend_class_entry *ce; + zval *ctor_args; + } cls; + zval *into; + } fetch; }; /* call this in MINIT to register your PDO driver */ diff --git a/ext/pdo/php_pdo_int.h b/ext/pdo/php_pdo_int.h index 8d2be68450..8e00989567 100755 --- a/ext/pdo/php_pdo_int.h +++ b/ext/pdo/php_pdo_int.h @@ -34,7 +34,10 @@ extern zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC); extern function_entry pdo_dbstmt_functions[]; extern zend_class_entry *pdo_dbstmt_ce; void pdo_dbstmt_free_storage(zend_object *object TSRMLS_DC); +zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object TSRMLS_DC); extern zend_object_handlers pdo_dbstmt_object_handlers; +int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC); +int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip_first_arg); extern zend_object_value pdo_row_new(zend_class_entry *ce TSRMLS_DC); extern function_entry pdo_row_functions[];