}
/* }}} */
-/* {{{ proto object PDO::prepare(string statment [, array driver_options])
+static zval * pdo_instanciate_stmt(zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args TSRMLS_DC) /* {{{ */
+{
+ if (ctor_args) {
+ if (Z_TYPE_P(ctor_args) != IS_ARRAY) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "Parameter ctor_args must be an array");
+ return NULL;
+ }
+ if (!dbstmt_ce->constructor) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "Statement object's constructor does not take any arguments", dbstmt_ce->name);
+ return NULL;
+ }
+ }
+
+ Z_TYPE_P(object) = IS_OBJECT;
+ object_init_ex(object, dbstmt_ce);
+ object->refcount = 1;
+ object->is_ref = 1;
+
+ if (dbstmt_ce->constructor) {
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ zval *retval;
+
+ fci.size = sizeof(zend_fcall_info);
+ fci.function_table = &dbstmt_ce->function_table;
+ fci.function_name = NULL;
+ fci.object_pp = &object;
+ fci.symbol_table = NULL;
+ fci.retval_ptr_ptr = &retval;
+ if (ctor_args) {
+ HashTable *ht = Z_ARRVAL_P(ctor_args);
+ Bucket *p;
+
+ fci.param_count = 0;
+ fci.params = safe_emalloc(sizeof(zval*), ht->nNumOfElements, 0);
+ p = ht->pListHead;
+ while (p != NULL) {
+ fci.params[fci.param_count++] = (zval**)p->pData;
+ p = p->pListNext;
+ }
+ } else {
+ fci.param_count = 0;
+ fci.params = NULL;
+ }
+ fci.no_separation = 1;
+
+ fcc.initialized = 1;
+ fcc.function_handler = dbstmt_ce->constructor;
+ fcc.calling_scope = EG(scope);
+ fcc.object_pp = &object;
+
+ if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
+ zval_dtor(object);
+ ZVAL_NULL(object);
+ object = NULL; /* marks failure */
+ } else {
+ zval_ptr_dtor(&retval);
+ }
+
+ if (fci.params) {
+ efree(fci.params);
+ }
+ }
+
+ return object;
+}
+/* }}} */
+
+/* {{{ proto object PDO::prepare(string statment [, array driver_options [, string classname ]])
Prepares a statement for execution and returns a statement object */
static PHP_METHOD(PDO, prepare)
{
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;
+ char *statement, *class_name = NULL;
+ int statement_len, class_name_len;
+ zval *driver_options = NULL, *ctor_args = NULL;
+ zend_class_entry *dbstmt_ce, **pce;
- if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &statement,
- &statement_len, &driver_options)) {
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|asz", &statement,
+ &statement_len, &driver_options, &class_name, &class_name_len, &ctor_args)) {
RETURN_FALSE;
}
PDO_DBH_CLEAR_ERR();
- stmt = ecalloc(1, sizeof(*stmt));
+
+ switch(ZEND_NUM_ARGS()) {
+ case 4:
+ case 3:
+ if (zend_lookup_class(class_name, class_name_len, &pce TSRMLS_CC) == FAILURE) {
+ RETURN_FALSE;
+ }
+ if (!instanceof_function(*pce, pdo_dbstmt_ce TSRMLS_CC)) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "The provided statement class must be derived from %s", pdo_dbstmt_ce->name);
+ RETURN_FALSE;
+ }
+ dbstmt_ce = *pce;
+ if (dbstmt_ce->constructor && !(dbstmt_ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "The provided statement class %s must not have a protected or public constructor", dbstmt_ce->name);
+ RETURN_FALSE;
+ }
+ break;
+
+ case 2:
+ case 1:
+ case 0:
+ dbstmt_ce = pdo_dbstmt_ce;
+ break;
+ }
+
+ if (!pdo_instanciate_stmt(return_value, dbstmt_ce, ctor_args TSRMLS_CC)) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "Failed to instanciate statement class %s", dbstmt_ce->name);
+ return;
+ }
+ stmt = (pdo_stmt_t*)zend_object_store_get_object(return_value TSRMLS_CC);
+
/* 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;
stmt->dbh = dbh;
+ /* give it a reference to me */
+ zend_objects_store_add_ref(getThis() TSRMLS_CC);
+ stmt->database_object_handle = *getThis();
+ /* we haven't created a lazy object yet */
+ ZVAL_NULL(&stmt->lazy_object_ref);
if (dbh->methods->preparer(dbh, statement, statement_len, stmt, 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;
return;
}
- efree(stmt->query_string);
- efree(stmt);
PDO_HANDLE_DBH_ERR();
+
+ /* kill the object handle for the stmt here */
+ zval_dtor(return_value);
+
RETURN_FALSE;
}
/* }}} */
}
PDO_DBH_CLEAR_ERR();
- stmt = ecalloc(1, sizeof(*stmt));
+
+ if (!pdo_instanciate_stmt(return_value, pdo_dbstmt_ce, NULL TSRMLS_CC)) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "Failed to instanciate statement class %s", pdo_dbstmt_ce->name);
+ return;
+ }
+ stmt = (pdo_stmt_t*)zend_object_store_get_object(return_value TSRMLS_CC);
+
/* 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;
stmt->active_query_string = stmt->query_string;
stmt->active_query_stringlen = statement_len;
+ stmt->dbh = dbh;
+ /* give it a reference to me */
+ zend_objects_store_add_ref(getThis() TSRMLS_CC);
+ stmt->database_object_handle = *getThis();
+ /* we haven't created a lazy object yet */
+ ZVAL_NULL(&stmt->lazy_object_ref);
if (dbh->methods->preparer(dbh, statement, statement_len, stmt, 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)) {
+ if (1) {//ZEND_NUM_ARGS() > 1 || SUCCESS == pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 1)) {
PDO_STMT_CLEAR_ERR();
/* now execute the statement */
}
}
/* something broke */
- PDO_HANDLE_STMT_ERR();
-
- /* TODO: kill the object handle for the stmt here */
- } else {
- efree(stmt->query_string);
- efree(stmt);
- PDO_HANDLE_DBH_ERR();
}
+
+ PDO_HANDLE_STMT_ERR();
+
+ /* kill the object handle for the stmt here */
+ zval_dtor(return_value);
+
RETURN_FALSE;
}
/* }}} */
pefree(dbh, dbh->is_persistent);
}
-static void pdo_dbh_free_storage(zend_object *object TSRMLS_DC)
+static void pdo_dbh_free_storage(void *object TSRMLS_DC)
{
pdo_dbh_t *dbh = (pdo_dbh_t*)object;
if (!dbh) {
}
/* }}} */
-static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param TSRMLS_DC)
+static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param TSRMLS_DC) /* {{{ */
{
if (stmt->bound_param_map) {
/* rewriting :name to ? style.
}
return 1;
}
+/* }}} */
/* trigger callback hook for parameters */
-static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type TSRMLS_DC)
+static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type TSRMLS_DC) /* {{{ */
{
int ret = 1, is_param = 1;
struct pdo_bound_param_data *param;
return ret;
}
+/* }}} */
-int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC)
+int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
{
int col;
}
return 1;
}
+/* }}} */
-static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value TSRMLS_DC)
+static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value TSRMLS_DC) /* {{{ */
{
if (Z_TYPE(stmt->lazy_object_ref) == IS_NULL) {
Z_TYPE(stmt->lazy_object_ref) = IS_OBJECT;
- Z_OBJ_HANDLE(stmt->lazy_object_ref) = zend_objects_store_put(stmt, NULL, pdo_row_free_storage, NULL TSRMLS_CC);
+ Z_OBJ_HANDLE(stmt->lazy_object_ref) = zend_objects_store_put(stmt, zend_objects_destroy_object, pdo_row_free_storage, NULL TSRMLS_CC);
Z_OBJ_HT(stmt->lazy_object_ref) = &pdo_row_object_handlers;
stmt->refcount++;
}
Z_OBJ_HANDLE_P(return_value) = Z_OBJ_HANDLE(stmt->lazy_object_ref);
Z_OBJ_HT_P(return_value) = Z_OBJ_HT(stmt->lazy_object_ref);
}
+/* }}} */
-static void param_dtor(void *data)
+static void param_dtor(void *data) /* {{{ */
{
struct pdo_bound_param_data *param = (struct pdo_bound_param_data *)data;
TSRMLS_FETCH();
zval_ptr_dtor(&(param->driver_params));
}
}
+/* }}} */
-static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_stmt_t *stmt, int is_param TSRMLS_DC)
+static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_stmt_t *stmt, int is_param TSRMLS_DC) /* {{{ */
{
HashTable *hash;
struct pdo_bound_param_data *pparam = NULL;
return 1;
}
-
+/* }}} */
/* {{{ proto bool PDOStatement::execute([array $bound_input_params])
Execute a prepared statement, optionally binding parameters */
}
/* }}} */
-static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno TSRMLS_DC)
+static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno TSRMLS_DC) /* {{{ */
{
struct pdo_column_data *col;
char *value = NULL;
efree(value);
}
}
+/* }}} */
static int do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori,
- long offset, int do_bind TSRMLS_DC)
+ long offset, int do_bind TSRMLS_DC) /* {{{ */
{
if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_PRE TSRMLS_CC)) {
return 0;
return 1;
}
+/* }}} */
-static int do_fetch_class_prepare(pdo_stmt_t *stmt TSRMLS_DC)
+static int do_fetch_class_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
{
zend_class_entry * ce = stmt->fetch.cls.ce;
return 1; /* no ctor no args is also ok */
}
}
+/* }}} */
+
+static int make_callable_ex(zval *callable, zend_fcall_info * fci, zend_fcall_info_cache * fcc, int num_args TSRMLS_DC) /* {{{ */
+{
+ zval **object = NULL, **method;
+ char *fname, *cname;
+ zend_class_entry * ce = NULL, **pce;
+ zend_function *function_handler;
+
+ if (Z_TYPE_P(callable) == IS_ARRAY) {
+ if (Z_ARRVAL_P(callable)->nNumOfElements < 2) {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function must be a valid function name or an array specifying object or class and method name");
+ return 0;
+ }
+ object = (zval**)Z_ARRVAL_P(callable)->pListHead->pData;
+ method = (zval**)Z_ARRVAL_P(callable)->pListHead->pListNext->pData;
+
+ if (Z_TYPE_PP(object) == IS_STRING) { /* static call */
+ object = NULL;
+ } else if (Z_TYPE_PP(object) == IS_OBJECT) { /* object call */
+ ce = Z_OBJCE_PP(object);
+ } else {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function may be an array but the provided array did neither contain a class name nor an object as first member");
+ return 0;
+ }
+
+ if (Z_TYPE_PP(method) != IS_STRING) {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function may be an array but the provided array did not contain a method name as second member");
+ }
+ }
+
+ if (!zend_is_callable(callable, 0, &fname)) {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function must contain something callable");
+ return 0;
+ }
+
+ /* ATM we do not support array($obj, "CLASS::FUNC") or "CLASS_FUNC" */
+ cname = fname;
+ if ((fname = strstr(fname, "::")) == NULL) {
+ fname = cname;
+ cname = NULL;
+ } else {
+ *fname = '\0';
+ fname += 2;
+ }
+ if (cname) {
+ if (zend_lookup_class(cname, strlen(cname), &pce TSRMLS_CC) == FAILURE) {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function references non existing class %s", cname);
+ } else {
+ if (ce) {
+ /* pce must be base of ce or ce itself */
+ if (ce != *pce && !instanceof_function(ce, *pce TSRMLS_CC)) {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function would result in calling %s::%s but class %s is not base of %s", (*pce)->name, fname, (*pce)->name, ce->name);
+ }
+ }
+ ce = *pce;
+ }
+ }
+
+ fci->function_table = ce ? &ce->function_table : EG(function_table);
+ if (zend_hash_find(fci->function_table, fname, strlen(fname)+1, (void **)&function_handler) == FAILURE) {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function '%s%s%s' not found", cname ? cname : "", cname ? "::" : "", fname);
+ efree(cname ? cname : fname);
+ return 0;
+ }
+ efree(cname ? cname : fname);
+
+ fci->size = sizeof(zend_fcall_info);
+ fci->function_name = NULL;
+ fci->symbol_table = NULL;
+ fci->param_count = num_args; /* probably less */
+ fci->params = safe_emalloc(sizeof(zval**), num_args, 0);
+ fci->object_pp = object;
+
+ fcc->initialized = 1;
+ fcc->function_handler = function_handler;
+ fcc->calling_scope = EG(scope);
+ fcc->object_pp = object;
+
+ return 1;
+}
+/* }}} */
-static int do_fetch_class_finish(pdo_stmt_t *stmt, int free_ctor_agrs TSRMLS_DC)
+static int do_fetch_func_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
+{
+ zend_fcall_info * fci = &stmt->fetch.cls.fci;
+ zend_fcall_info_cache * fcc = &stmt->fetch.cls.fcc;
+
+ if (!make_callable_ex(stmt->fetch.func.function, fci, fcc, stmt->column_count TSRMLS_CC)) {
+ return 0;
+ } else {
+ stmt->fetch.func.values = safe_emalloc(sizeof(zval*), stmt->column_count, 0);
+ return 1;
+ }
+}
+/* }}} */
+
+static int do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs TSRMLS_DC) /* {{{ */
{
/* fci.size is used to check if it is valid */
if (stmt->fetch.cls.fci.size && stmt->fetch.cls.fci.params) {
efree(stmt->fetch.cls.fci.params);
+ stmt->fetch.cls.fci.params = NULL;
stmt->fetch.cls.fci.size = 0;
}
if (stmt->fetch.cls.ctor_args && free_ctor_agrs) {
FREE_ZVAL(stmt->fetch.cls.ctor_args);
stmt->fetch.cls.ctor_args = NULL;
}
+ if (stmt->fetch.func.values && free_ctor_agrs) {
+ FREE_ZVAL(stmt->fetch.func.values);
+ stmt->fetch.func.values = NULL;
+ }
return 1;
}
+/* }}} */
/* perform a fetch. If do_bind is true, update any bound columns.
* If return_value is not null, store values into it according to HOW. */
static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
- enum pdo_fetch_type how, enum pdo_fetch_orientation ori, long offset, zval *return_all TSRMLS_DC)
+ enum pdo_fetch_type how, enum pdo_fetch_orientation ori, long offset, zval *return_all TSRMLS_DC) /* {{{ */
{
- int flags = how & PDO_FETCH_FLAGS;
+ int flags = how & PDO_FETCH_FLAGS, idx;
zend_class_entry * ce, * old_ce;
+ zval grp_val, *grp, **pgrp, *retval;
how = how & ~PDO_FETCH_FLAGS;
if (how == PDO_FETCH_USE_DEFAULT) {
zval val;
zend_class_entry **cep;
- do_fetch_class_finish(stmt, 0 TSRMLS_CC);
+ do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
old_ce = stmt->fetch.cls.ce;
INIT_PZVAL(&val);
}
break;
+ case PDO_FETCH_FUNC:
+ if (!stmt->fetch.func.fci.size) {
+ if (!do_fetch_func_prepare(stmt TSRMLS_CC))
+ {
+ return 0;
+ }
+ }
+ break;
+
+
default:
/* shouldn't happen */
return 0;
}
if (return_all) {
- zval val, *grp, **pgrp;
- INIT_PZVAL(&val);
- fetch_value(stmt, &val, i TSRMLS_CC);
- convert_to_string(&val);
- if ((flags & PDO_FETCH_UNIQUE) == PDO_FETCH_UNIQUE) {
- add_assoc_zval(return_all, Z_STRVAL(val), return_value);
- } else {
- if (zend_symtable_find(Z_ARRVAL_P(return_all), Z_STRVAL(val), Z_STRLEN(val)+1, (void**)&pgrp) == FAILURE) {
- MAKE_STD_ZVAL(grp);
- array_init(grp);
- add_assoc_zval(return_all, Z_STRVAL(val), grp);
- } else {
- grp = *pgrp;
- }
- add_next_index_zval(grp, return_value);
- }
- zval_dtor(&val);
+ INIT_PZVAL(&grp_val);
+ fetch_value(stmt, &grp_val, i TSRMLS_CC);
+ convert_to_string(&grp_val);
i++;
}
- for (; i < stmt->column_count; i++) {
+ for (idx = 0; i < stmt->column_count; i++, idx++) {
zval *val;
MAKE_STD_ZVAL(val);
fetch_value(stmt, val, i TSRMLS_CC);
val TSRMLS_CC);
break;
+ case PDO_FETCH_FUNC:
+ stmt->fetch.func.values[idx] = val;
+ stmt->fetch.cls.fci.params[idx] = &stmt->fetch.func.values[idx];
+ break;
+
default:
+ zval_ptr_dtor(&val);
pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range" TSRMLS_CC);
break;
}
}
}
if (flags & PDO_FETCH_CLASSTYPE) {
- do_fetch_class_finish(stmt, 0 TSRMLS_CC);
+ do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
stmt->fetch.cls.ce = old_ce;
}
break;
+
+ case PDO_FETCH_FUNC:
+ stmt->fetch.func.fci.param_count = idx;
+ stmt->fetch.func.fci.retval_ptr_ptr = &retval;
+ if (zend_call_function(&stmt->fetch.func.fci, &stmt->fetch.func.fcc TSRMLS_CC) == FAILURE) {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Could not execute %s%s%s()", ce->name, ce->constructor->common.function_name);
+ } else {
+ if (return_all) {
+ zval_ptr_dtor(&return_value); /* we don't need that */
+ return_value = retval;
+ } else {
+ *return_value = *retval;
+ zval_copy_ctor(return_value);
+ zval_ptr_dtor(&retval);
+ }
+ }
+ while(idx--) {
+ zval_ptr_dtor(&stmt->fetch.func.values[idx]);
+ }
+ break;
default:
break;
}
+
+ if (return_all) {
+ if ((flags & PDO_FETCH_UNIQUE) == PDO_FETCH_UNIQUE) {
+ add_assoc_zval(return_all, Z_STRVAL(grp_val), return_value);
+ } else {
+ if (zend_symtable_find(Z_ARRVAL_P(return_all), Z_STRVAL(grp_val), Z_STRLEN(grp_val)+1, (void**)&pgrp) == FAILURE) {
+ MAKE_STD_ZVAL(grp);
+ array_init(grp);
+ add_assoc_zval(return_all, Z_STRVAL(grp_val), grp);
+ } else {
+ grp = *pgrp;
+ }
+ add_next_index_zval(grp, return_value);
+ }
+ zval_dtor(&grp_val);
+ }
+
}
return 1;
}
+/* }}} */
+
+static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, int mode, int fetch_all TSRMLS_DC) /* {{{ */
+{
+ int flags = mode & PDO_FETCH_FLAGS;
+
+ mode = mode & ~PDO_FETCH_FLAGS;
+
+ if (mode == PDO_FETCH_USE_DEFAULT) {
+ mode = stmt->default_fetch_type;
+ }
+
+ switch(mode) {
+ case PDO_FETCH_FUNC:
+ if (!fetch_all) {
+ zend_throw_exception(pdo_exception_ce, "Fetch mode PDO_FETCH_FUNC is only allowed in PDOStatement::fetchAll()", 0 TSRMLS_CC);
+ return 0;
+ }
+ return 1;
+
+ default:
+ if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Fetch mode flag PDO_FETCH_CLASSTYPE requires mode PDO_FETCH_CLASS", mode);
+ return 0;
+ }
+ /* no break; */
+
+ case PDO_FETCH_CLASS:
+ if (mode >= PDO_FETCH__MAX) {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Fetch mode %d is invalid", mode);
+ return 0;
+ }
+ return 1;
+ }
+}
+/* }}} */
/* {{{ proto mixed PDOStatement::fetch([int $how = PDO_FETCH_BOTH [, int $orientation [, int $offset]]])
Fetches the next row and returns it, or false if there are no more rows */
}
PDO_STMT_CLEAR_ERR();
+
+ if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
if (!do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
PDO_HANDLE_STMT_ERR();
RETURN_FALSE;
RETURN_FALSE;
}
+ PDO_STMT_CLEAR_ERR();
+
+ if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
switch(ZEND_NUM_ARGS()) {
case 0:
stmt->fetch.cls.ce = zend_standard_class_def;
}
}
- PDO_STMT_CLEAR_ERR();
if (!error && !do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
error = 1;
PDO_HANDLE_STMT_ERR();
}
PDO_STMT_CLEAR_ERR();
+
if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0, TRUE TSRMLS_CC)) {
PDO_HANDLE_STMT_ERR();
RETURN_FALSE;
pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC);
long how = PDO_FETCH_USE_DEFAULT;
zval *data, *return_all;
- char *class_name;
- int class_name_len;
+ zval *arg2;
zend_class_entry *old_ce;
zval *old_ctor_args, *ctor_args;
int error = 0;
old_ce = stmt->fetch.cls.ce;
old_ctor_args = stmt->fetch.cls.ctor_args;
+ stmt->fetch.cls.ctor_args = NULL;
- if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lsz", &how, &class_name, &class_name_len, &ctor_args)) {
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lzz", &how, &arg2, &ctor_args)) {
RETURN_FALSE;
}
-
- switch(ZEND_NUM_ARGS()) {
- case 0:
- case 1:
- stmt->fetch.cls.ce = zend_standard_class_def;
- break;
- case 3:
- if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
- zend_throw_exception(pdo_exception_ce, "Parameter ctor_args must either be NULL or an array ", 0 TSRMLS_CC);
- error = 1;
+
+ if (!pdo_stmt_verify_mode(stmt, how, 1 TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ switch(how & ~PDO_FETCH_FLAGS) {
+ case PDO_FETCH_CLASS:
+ do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
+ switch(ZEND_NUM_ARGS()) {
+ case 0:
+ case 1:
+ stmt->fetch.cls.ce = zend_standard_class_def;
break;
+ case 3:
+ if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
+ zend_throw_exception(pdo_exception_ce, "Parameter ctor_args must either be NULL or an array ", 0 TSRMLS_CC);
+ error = 1;
+ break;
+ }
+ if (Z_TYPE_P(ctor_args) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
+ stmt->fetch.cls.ctor_args = ctor_args;
+ } else {
+ stmt->fetch.cls.ctor_args = NULL;
+ }
+ /* no break */
+ case 2:
+ if (Z_TYPE_P(arg2) != IS_STRING) {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "In fetch mode PDO_FETCH_CLASS the 2nd parameter must be a class name string", Z_TYPE_P(arg2));
+ error = 1;
+ break;
+ } else {
+ stmt->fetch.cls.ce = zend_fetch_class(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
+ if (!stmt->fetch.cls.ce) {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Could not find class '%s'", Z_TYPE_P(arg2));
+ error = 1;
+ break;
+ }
+ }
}
- if (Z_TYPE_P(ctor_args) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
- stmt->fetch.cls.ctor_args = ctor_args;
- } else {
- stmt->fetch.cls.ctor_args = NULL;
+// do_fetch_class_prepare(stmt TSRMLS_CC);
+ break;
+
+ case PDO_FETCH_FUNC:
+ do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
+ switch(ZEND_NUM_ARGS()) {
+ case 0:
+ case 1:
+ break;
+ case 3:
+ case 2:
+ stmt->fetch.func.function = arg2;
+ break;
}
- /* no break */
- case 2:
- stmt->fetch.cls.ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
+ do_fetch_func_prepare(stmt TSRMLS_CC);
+ break;
- if (!stmt->fetch.cls.ce) {
- zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Could not find class '%s'", class_name);
+ default:
+ if (ZEND_NUM_ARGS() > 1) {
+ zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Additional parameter not allowed for specified fetch mode");
error = 1;
- break;
}
}
if (!error)
{
- do_fetch_class_prepare(stmt TSRMLS_CC);
-
PDO_STMT_CLEAR_ERR();
MAKE_STD_ZVAL(data);
if (how & PDO_FETCH_GROUP) {
FREE_ZVAL(data);
}
+ do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
+
stmt->fetch.cls.ce = old_ce;
stmt->fetch.cls.ctor_args = old_ctor_args;
- do_fetch_class_finish(stmt, 1 TSRMLS_CC);
-
if (error) {
RETURN_FALSE;
}
switch (stmt->default_fetch_type) {
case PDO_FETCH_CLASS:
- do_fetch_class_finish(stmt, 1 TSRMLS_CC);
+ case PDO_FETCH_FUNC:
+ do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
break;
case PDO_FETCH_INTO:
convert_to_long_ex(args[skip]);
mode = Z_LVAL_PP(args[skip]);
+
+ if (!pdo_stmt_verify_mode(stmt, mode, 0 TSRMLS_CC)) {
+ return FAILURE;
+ }
switch (mode & ~PDO_FETCH_FLAGS) {
case PDO_FETCH_LAZY:
static union _zend_function *dbstmt_get_ctor(zval *object TSRMLS_DC)
{
- static zend_internal_function ctor = {0};
-
- ctor.type = ZEND_INTERNAL_FUNCTION;
- ctor.function_name = "__construct";
- ctor.scope = pdo_dbstmt_ce;
- ctor.handler = ZEND_FN(dbstmt_constructor);
-
- return (union _zend_function*)&ctor;
+ return std_object_handlers.get_constructor(object TSRMLS_CC);
}
static zend_class_entry *dbstmt_get_ce(zval *object TSRMLS_DC)
{
- return pdo_dbstmt_ce;
+ return std_object_handlers.get_class_entry(object TSRMLS_CC);
}
static int dbstmt_get_classname(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
{
- *class_name = estrndup("PDOStatement", sizeof("PDOStatement")-1);
- *class_name_len = sizeof("PDOStatement")-1;
- return 0;
+ return std_object_handlers.get_class_name(object, class_name, class_name_len, parent TSRMLS_CC);
}
static int dbstmt_compare(zval *object1, zval *object2 TSRMLS_DC)
static void free_statement(pdo_stmt_t *stmt TSRMLS_DC)
{
+ if (stmt->properties) {
+ zend_hash_destroy(stmt->properties);
+ efree(stmt->properties);
+ stmt->properties = NULL;
+ }
+
if (stmt->methods && stmt->methods->dtor) {
stmt->methods->dtor(stmt TSRMLS_CC);
}
FREE_HASHTABLE(stmt->bound_columns);
}
- do_fetch_class_finish(stmt, 1 TSRMLS_CC);
+ do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
zend_objects_store_del_ref(&stmt->database_object_handle TSRMLS_CC);
efree(stmt);
}
-void pdo_dbstmt_free_storage(zend_object *object TSRMLS_DC)
+void pdo_dbstmt_free_storage(void *object TSRMLS_DC)
{
pdo_stmt_t *stmt = (pdo_stmt_t*)object;
{
zend_object_value retval;
- retval.handle = zend_objects_store_put(NULL, NULL, pdo_dbstmt_free_storage, NULL TSRMLS_CC);
+ pdo_stmt_t *stmt;
+ stmt = emalloc(sizeof(*stmt));
+ memset(stmt, 0, sizeof(*stmt));
+ stmt->ce = ce;
+ stmt->refcount = 1;
+ ALLOC_HASHTABLE(stmt->properties);
+ zend_hash_init(stmt->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+
+ retval.handle = zend_objects_store_put(stmt, zend_objects_destroy_object, pdo_dbstmt_free_storage, NULL TSRMLS_CC);
retval.handlers = &pdo_dbstmt_object_handlers;
return retval;
NULL
};
-void pdo_row_free_storage(zend_object *object TSRMLS_DC)
+void pdo_row_free_storage(void *object TSRMLS_DC)
{
pdo_stmt_t *stmt = (pdo_stmt_t*)object;
{
zend_object_value retval;
- retval.handle = zend_objects_store_put(NULL, NULL, pdo_row_free_storage, NULL TSRMLS_CC);
+ retval.handle = zend_objects_store_put(NULL, zend_objects_destroy_object, pdo_row_free_storage, NULL TSRMLS_CC);
retval.handlers = &pdo_row_object_handlers;
return retval;