]> granicus.if.org Git - php/commitdiff
Inverse logic in do_fetch() to reduce a level of indentation
authorGeorge Peter Banyard <girgias@php.net>
Fri, 25 Sep 2020 03:05:53 +0000 (04:05 +0100)
committerGeorge Peter Banyard <girgias@php.net>
Fri, 25 Sep 2020 13:19:49 +0000 (14:19 +0100)
ext/pdo/pdo_stmt.c

index 81b30a9b2493c636b15af14367569d25702a6ea4..6100f5b8454cb8dc98a6bc376708d42319d2aab9 100644 (file)
@@ -741,12 +741,13 @@ static void do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs) /* {{{ */
 
 /* perform a fetch.
  * If return_value is not null, store values into it according to HOW. */
-static int do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type how, enum pdo_fetch_orientation ori, zend_long offset, zval *return_all) /* {{{ */
+static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type how, enum pdo_fetch_orientation ori, zend_long offset, zval *return_all) /* {{{ */
 {
        int flags, idx, old_arg_count = 0;
        zend_class_entry *ce = NULL, *old_ce = NULL;
        zval grp_val, *pgrp, retval, old_ctor_args = {{0}, {0}, {0}};
        int colno;
+       int i = 0;
 
        if (how == PDO_FETCH_USE_DEFAULT) {
                how = stmt->default_fetch_type;
@@ -769,341 +770,340 @@ static int do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type ho
                colno = stmt->fetch.column;
        }
 
-       if (return_value) {
-               int i = 0;
+       /* If no return value we are done */
+       if (!return_value) {
+               return true;
+       }
 
-               if (how == PDO_FETCH_LAZY) {
-                       get_lazy_object(stmt, return_value);
-                       return 1;
-               }
+       if (how == PDO_FETCH_LAZY) {
+               get_lazy_object(stmt, return_value);
+               return 1;
+       }
 
-               RETVAL_FALSE;
+       RETVAL_FALSE;
 
-               switch (how) {
-                       case PDO_FETCH_USE_DEFAULT:
-                       case PDO_FETCH_ASSOC:
-                       case PDO_FETCH_BOTH:
-                       case PDO_FETCH_NUM:
-                       case PDO_FETCH_NAMED:
-                               if (!return_all) {
-                                       array_init_size(return_value, stmt->column_count);
-                               } else {
-                                       array_init(return_value);
-                               }
-                               break;
+       switch (how) {
+               case PDO_FETCH_USE_DEFAULT:
+               case PDO_FETCH_ASSOC:
+               case PDO_FETCH_BOTH:
+               case PDO_FETCH_NUM:
+               case PDO_FETCH_NAMED:
+                       if (!return_all) {
+                               array_init_size(return_value, stmt->column_count);
+                       } else {
+                               array_init(return_value);
+                       }
+                       break;
 
-                       case PDO_FETCH_KEY_PAIR:
-                               if (stmt->column_count != 2) {
-                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_KEY_PAIR fetch mode requires the result set to contain exactly 2 columns.");
-                                       return 0;
+               case PDO_FETCH_KEY_PAIR:
+                       if (stmt->column_count != 2) {
+                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_KEY_PAIR fetch mode requires the result set to contain exactly 2 columns.");
+                               return 0;
+                       }
+                       if (!return_all) {
+                               array_init(return_value);
+                       }
+                       break;
+
+               case PDO_FETCH_COLUMN:
+                       if (colno >= 0 && colno < stmt->column_count) {
+                               if (flags == PDO_FETCH_GROUP && stmt->fetch.column == -1) {
+                                       fetch_value(stmt, return_value, 1, NULL);
+                               } else if (flags == PDO_FETCH_GROUP && colno) {
+                                       fetch_value(stmt, return_value, 0, NULL);
+                               } else {
+                                       fetch_value(stmt, return_value, colno, NULL);
                                }
                                if (!return_all) {
-                                       array_init(return_value);
+                                       return 1;
+                               } else {
+                                       break;
                                }
-                               break;
+                       } else {
+                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index");
+                       }
+                       return 0;
 
-                       case PDO_FETCH_COLUMN:
-                               if (colno >= 0 && colno < stmt->column_count) {
-                                       if (flags == PDO_FETCH_GROUP && stmt->fetch.column == -1) {
-                                               fetch_value(stmt, return_value, 1, NULL);
-                                       } else if (flags == PDO_FETCH_GROUP && colno) {
-                                               fetch_value(stmt, return_value, 0, NULL);
-                                       } else {
-                                               fetch_value(stmt, return_value, colno, NULL);
+               case PDO_FETCH_OBJ:
+                       object_init_ex(return_value, ZEND_STANDARD_CLASS_DEF_PTR);
+                       break;
+
+               case PDO_FETCH_CLASS:
+                       if (flags & PDO_FETCH_CLASSTYPE) {
+                               zval val;
+                               zend_class_entry *cep;
+
+                               old_ce = stmt->fetch.cls.ce;
+                               ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
+                               old_arg_count = stmt->fetch.cls.fci.param_count;
+                               do_fetch_opt_finish(stmt, 0);
+
+                               fetch_value(stmt, &val, i++, NULL);
+                               if (Z_TYPE(val) != IS_NULL) {
+                                       if (!try_convert_to_string(&val)) {
+                                               return 0;
                                        }
-                                       if (!return_all) {
-                                               return 1;
+                                       if ((cep = zend_lookup_class(Z_STR(val))) == NULL) {
+                                               stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
                                        } else {
-                                               break;
+                                               stmt->fetch.cls.ce = cep;
                                        }
-                               } else {
-                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index");
                                }
-                               return 0;
-
-                       case PDO_FETCH_OBJ:
-                               object_init_ex(return_value, ZEND_STANDARD_CLASS_DEF_PTR);
-                               break;
-
-                       case PDO_FETCH_CLASS:
-                               if (flags & PDO_FETCH_CLASSTYPE) {
-                                       zval val;
-                                       zend_class_entry *cep;
-
-                                       old_ce = stmt->fetch.cls.ce;
-                                       ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
-                                       old_arg_count = stmt->fetch.cls.fci.param_count;
-                                       do_fetch_opt_finish(stmt, 0);
-
-                                       fetch_value(stmt, &val, i++, NULL);
-                                       if (Z_TYPE(val) != IS_NULL) {
-                                               if (!try_convert_to_string(&val)) {
-                                                       return 0;
-                                               }
-                                               if ((cep = zend_lookup_class(Z_STR(val))) == NULL) {
-                                                       stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
-                                               } else {
-                                                       stmt->fetch.cls.ce = cep;
-                                               }
-                                       }
 
-                                       do_fetch_class_prepare(stmt);
-                                       zval_ptr_dtor_str(&val);
-                               }
-                               ce = stmt->fetch.cls.ce;
-                               if (!ce) {
-                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified");
+                               do_fetch_class_prepare(stmt);
+                               zval_ptr_dtor_str(&val);
+                       }
+                       ce = stmt->fetch.cls.ce;
+                       if (!ce) {
+                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified");
+                               return 0;
+                       }
+                       if ((flags & PDO_FETCH_SERIALIZE) == 0) {
+                               if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
                                        return 0;
                                }
-                               if ((flags & PDO_FETCH_SERIALIZE) == 0) {
-                                       if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
+                               if (!stmt->fetch.cls.fci.size) {
+                                       if (!do_fetch_class_prepare(stmt))
+                                       {
                                                return 0;
                                        }
-                                       if (!stmt->fetch.cls.fci.size) {
-                                               if (!do_fetch_class_prepare(stmt))
-                                               {
-                                                       return 0;
-                                               }
-                                       }
-                                       if (ce->constructor && (flags & PDO_FETCH_PROPS_LATE)) {
-                                               stmt->fetch.cls.fci.object = Z_OBJ_P(return_value);
-                                               stmt->fetch.cls.fcc.object = Z_OBJ_P(return_value);
-                                               if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc) == FAILURE) {
-                                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
-                                                       return 0;
-                                               } else {
-                                                       if (!Z_ISUNDEF(stmt->fetch.cls.retval)) {
-                                                               zval_ptr_dtor(&stmt->fetch.cls.retval);
-                                                               ZVAL_UNDEF(&stmt->fetch.cls.retval);
-                                                       }
+                               }
+                               if (ce->constructor && (flags & PDO_FETCH_PROPS_LATE)) {
+                                       stmt->fetch.cls.fci.object = Z_OBJ_P(return_value);
+                                       stmt->fetch.cls.fcc.object = Z_OBJ_P(return_value);
+                                       if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc) == FAILURE) {
+                                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
+                                               return 0;
+                                       } else {
+                                               if (!Z_ISUNDEF(stmt->fetch.cls.retval)) {
+                                                       zval_ptr_dtor(&stmt->fetch.cls.retval);
+                                                       ZVAL_UNDEF(&stmt->fetch.cls.retval);
                                                }
                                        }
                                }
-                               break;
+                       }
+                       break;
 
-                       case PDO_FETCH_INTO:
-                               if (Z_ISUNDEF(stmt->fetch.into)) {
-                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch-into object specified.");
-                                       return 0;
-                                       break;
-                               }
+               case PDO_FETCH_INTO:
+                       if (Z_ISUNDEF(stmt->fetch.into)) {
+                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch-into object specified.");
+                               return 0;
+                               break;
+                       }
 
-                               ZVAL_COPY(return_value, &stmt->fetch.into);
+                       ZVAL_COPY(return_value, &stmt->fetch.into);
 
-                               if (Z_OBJ_P(return_value)->ce == ZEND_STANDARD_CLASS_DEF_PTR) {
-                                       how = PDO_FETCH_OBJ;
-                               }
-                               break;
+                       if (Z_OBJ_P(return_value)->ce == ZEND_STANDARD_CLASS_DEF_PTR) {
+                               how = PDO_FETCH_OBJ;
+                       }
+                       break;
 
-                       case PDO_FETCH_FUNC:
-                               if (Z_ISUNDEF(stmt->fetch.func.function)) {
-                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch function specified");
+               case PDO_FETCH_FUNC:
+                       if (Z_ISUNDEF(stmt->fetch.func.function)) {
+                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch function specified");
+                               return 0;
+                       }
+                       if (!stmt->fetch.func.fci.size) {
+                               if (!do_fetch_func_prepare(stmt))
+                               {
                                        return 0;
                                }
-                               if (!stmt->fetch.func.fci.size) {
-                                       if (!do_fetch_func_prepare(stmt))
-                                       {
-                                               return 0;
-                                       }
-                               }
-                               break;
+                       }
+                       break;
 
+               default:
+                       /* shouldn't happen */
+                       return 0;
+       }
 
-                       default:
-                               /* shouldn't happen */
-                               return 0;
+       if (return_all && how != PDO_FETCH_KEY_PAIR) {
+               if (flags == PDO_FETCH_GROUP && how == PDO_FETCH_COLUMN && stmt->fetch.column > 0) {
+                       fetch_value(stmt, &grp_val, colno, NULL);
+               } else {
+                       fetch_value(stmt, &grp_val, i, NULL);
                }
-
-               if (return_all && how != PDO_FETCH_KEY_PAIR) {
-                       if (flags == PDO_FETCH_GROUP && how == PDO_FETCH_COLUMN && stmt->fetch.column > 0) {
-                               fetch_value(stmt, &grp_val, colno, NULL);
-                       } else {
-                               fetch_value(stmt, &grp_val, i, NULL);
-                       }
-                       convert_to_string(&grp_val);
-                       if (how == PDO_FETCH_COLUMN) {
-                               i = stmt->column_count; /* no more data to fetch */
-                       } else {
-                               i++;
-                       }
+               convert_to_string(&grp_val);
+               if (how == PDO_FETCH_COLUMN) {
+                       i = stmt->column_count; /* no more data to fetch */
+               } else {
+                       i++;
                }
+       }
 
-               for (idx = 0; i < stmt->column_count; i++, idx++) {
-                       zval val;
-                       fetch_value(stmt, &val, i, NULL);
+       for (idx = 0; i < stmt->column_count; i++, idx++) {
+               zval val;
+               fetch_value(stmt, &val, i, NULL);
 
-                       switch (how) {
-                               case PDO_FETCH_ASSOC:
-                                       zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
-                                       break;
+               switch (how) {
+                       case PDO_FETCH_ASSOC:
+                               zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
+                               break;
 
-                               case PDO_FETCH_KEY_PAIR:
-                                       {
-                                               zval tmp;
-                                               fetch_value(stmt, &tmp, ++i, NULL);
+                       case PDO_FETCH_KEY_PAIR:
+                               {
+                                       zval tmp;
+                                       fetch_value(stmt, &tmp, ++i, NULL);
 
-                                               if (Z_TYPE(val) == IS_LONG) {
-                                                       zend_hash_index_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_LVAL(val), &tmp);
-                                               } else {
-                                                       convert_to_string(&val);
-                                                       zend_symtable_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_STR(val), &tmp);
-                                               }
-                                               zval_ptr_dtor(&val);
-                                               return 1;
+                                       if (Z_TYPE(val) == IS_LONG) {
+                                               zend_hash_index_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_LVAL(val), &tmp);
+                                       } else {
+                                               convert_to_string(&val);
+                                               zend_symtable_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_STR(val), &tmp);
                                        }
-                                       break;
+                                       zval_ptr_dtor(&val);
+                                       return 1;
+                               }
+                               break;
 
-                               case PDO_FETCH_USE_DEFAULT:
-                               case PDO_FETCH_BOTH:
-                                       zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
-                                       if (zend_hash_index_add(Z_ARRVAL_P(return_value), i, &val) != NULL) {
-                                               Z_TRY_ADDREF(val);
-                                       }
-                                       break;
+                       case PDO_FETCH_USE_DEFAULT:
+                       case PDO_FETCH_BOTH:
+                               zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
+                               if (zend_hash_index_add(Z_ARRVAL_P(return_value), i, &val) != NULL) {
+                                       Z_TRY_ADDREF(val);
+                               }
+                               break;
 
-                               case PDO_FETCH_NAMED:
-                                       /* already have an item with this name? */
-                                       {
-                                               zval *curr_val;
-                                               if ((curr_val = zend_hash_find(Z_ARRVAL_P(return_value), stmt->columns[i].name))) {
-                                                       zval arr;
-                                                       if (Z_TYPE_P(curr_val) != IS_ARRAY) {
-                                                               /* a little bit of black magic here:
-                                                                * we're creating a new array and swapping it for the
-                                                                * zval that's already stored in the hash under the name
-                                                                * we want.  We then add that zval to the array.
-                                                                * This is effectively the same thing as:
-                                                                * if (!is_array($hash[$name])) {
-                                                                *   $hash[$name] = array($hash[$name]);
-                                                                * }
-                                                                * */
-                                                               zval cur;
-
-                                                               array_init(&arr);
-
-                                                               ZVAL_COPY_VALUE(&cur, curr_val);
-                                                               ZVAL_COPY_VALUE(curr_val, &arr);
-
-                                                               zend_hash_next_index_insert_new(Z_ARRVAL(arr), &cur);
-                                                       } else {
-                                                               ZVAL_COPY_VALUE(&arr, curr_val);
-                                                       }
-                                                       zend_hash_next_index_insert_new(Z_ARRVAL(arr), &val);
+                       case PDO_FETCH_NAMED:
+                               /* already have an item with this name? */
+                               {
+                                       zval *curr_val;
+                                       if ((curr_val = zend_hash_find(Z_ARRVAL_P(return_value), stmt->columns[i].name))) {
+                                               zval arr;
+                                               if (Z_TYPE_P(curr_val) != IS_ARRAY) {
+                                                       /* a little bit of black magic here:
+                                                        * we're creating a new array and swapping it for the
+                                                        * zval that's already stored in the hash under the name
+                                                        * we want.  We then add that zval to the array.
+                                                        * This is effectively the same thing as:
+                                                        * if (!is_array($hash[$name])) {
+                                                        *   $hash[$name] = array($hash[$name]);
+                                                        * }
+                                                        * */
+                                                       zval cur;
+
+                                                       array_init(&arr);
+
+                                                       ZVAL_COPY_VALUE(&cur, curr_val);
+                                                       ZVAL_COPY_VALUE(curr_val, &arr);
+
+                                                       zend_hash_next_index_insert_new(Z_ARRVAL(arr), &cur);
                                                } else {
-                                                       zend_hash_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
+                                                       ZVAL_COPY_VALUE(&arr, curr_val);
                                                }
+                                               zend_hash_next_index_insert_new(Z_ARRVAL(arr), &val);
+                                       } else {
+                                               zend_hash_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
                                        }
-                                       break;
+                               }
+                               break;
 
-                               case PDO_FETCH_NUM:
-                                       zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &val);
-                                       break;
+                       case PDO_FETCH_NUM:
+                               zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &val);
+                               break;
 
-                               case PDO_FETCH_OBJ:
-                               case PDO_FETCH_INTO:
-                                       zend_update_property_ex(NULL, Z_OBJ_P(return_value),
+                       case PDO_FETCH_OBJ:
+                       case PDO_FETCH_INTO:
+                               zend_update_property_ex(NULL, Z_OBJ_P(return_value),
+                                       stmt->columns[i].name,
+                                       &val);
+                               zval_ptr_dtor(&val);
+                               break;
+
+                       case PDO_FETCH_CLASS:
+                               if ((flags & PDO_FETCH_SERIALIZE) == 0 || idx) {
+                                       zend_update_property_ex(ce, Z_OBJ_P(return_value),
                                                stmt->columns[i].name,
                                                &val);
                                        zval_ptr_dtor(&val);
-                                       break;
-
-                               case PDO_FETCH_CLASS:
-                                       if ((flags & PDO_FETCH_SERIALIZE) == 0 || idx) {
-                                               zend_update_property_ex(ce, Z_OBJ_P(return_value),
-                                                       stmt->columns[i].name,
-                                                       &val);
+                               } else {
+                                       if (!ce->unserialize) {
                                                zval_ptr_dtor(&val);
-                                       } else {
-                                               if (!ce->unserialize) {
-                                                       zval_ptr_dtor(&val);
-                                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
-                                                       return 0;
-                                               } else if (ce->unserialize(return_value, ce, (unsigned char *)(Z_TYPE(val) == IS_STRING ? Z_STRVAL(val) : ""), Z_TYPE(val) == IS_STRING ? Z_STRLEN(val) : 0, NULL) == FAILURE) {
-                                                       zval_ptr_dtor(&val);
-                                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
-                                                       zval_ptr_dtor(return_value);
-                                                       ZVAL_NULL(return_value);
-                                                       return 0;
-                                               } else {
-                                                       zval_ptr_dtor(&val);
-                                               }
-                                       }
-                                       break;
-
-                               case PDO_FETCH_FUNC:
-                                       ZVAL_COPY_VALUE(&stmt->fetch.func.values[idx], &val);
-                                       ZVAL_COPY_VALUE(&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");
-                                       return 0;
-                                       break;
-                       }
-               }
-
-               switch (how) {
-                       case PDO_FETCH_CLASS:
-                               if (ce->constructor && !(flags & (PDO_FETCH_PROPS_LATE | PDO_FETCH_SERIALIZE))) {
-                                       stmt->fetch.cls.fci.object = Z_OBJ_P(return_value);
-                                       stmt->fetch.cls.fcc.object = Z_OBJ_P(return_value);
-                                       if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc) == FAILURE) {
-                                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
+                                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
+                                               return 0;
+                                       } else if (ce->unserialize(return_value, ce, (unsigned char *)(Z_TYPE(val) == IS_STRING ? Z_STRVAL(val) : ""), Z_TYPE(val) == IS_STRING ? Z_STRLEN(val) : 0, NULL) == FAILURE) {
+                                               zval_ptr_dtor(&val);
+                                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
+                                               zval_ptr_dtor(return_value);
+                                               ZVAL_NULL(return_value);
                                                return 0;
                                        } else {
-                                               if (!Z_ISUNDEF(stmt->fetch.cls.retval)) {
-                                                       zval_ptr_dtor(&stmt->fetch.cls.retval);
-                                               }
+                                               zval_ptr_dtor(&val);
                                        }
                                }
-                               if (flags & PDO_FETCH_CLASSTYPE) {
-                                       do_fetch_opt_finish(stmt, 0);
-                                       stmt->fetch.cls.ce = old_ce;
-                                       ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
-                                       stmt->fetch.cls.fci.param_count = old_arg_count;
-                               }
                                break;
 
                        case PDO_FETCH_FUNC:
-                               stmt->fetch.func.fci.param_count = idx;
-                               stmt->fetch.func.fci.retval = &retval;
-                               if (zend_call_function(&stmt->fetch.func.fci, &stmt->fetch.func.fcc) == FAILURE) {
-                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function");
-                                       return 0;
-                               } else {
-                                       if (return_all) {
-                                               zval_ptr_dtor(return_value); /* we don't need that */
-                                               ZVAL_COPY_VALUE(return_value, &retval);
-                                       } else if (!Z_ISUNDEF(retval)) {
-                                               ZVAL_COPY_VALUE(return_value, &retval);
-                                       }
-                               }
-                               while (idx--) {
-                                       zval_ptr_dtor(&stmt->fetch.func.values[idx]);
-                               }
+                               ZVAL_COPY_VALUE(&stmt->fetch.func.values[idx], &val);
+                               ZVAL_COPY_VALUE(&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");
+                               return 0;
                                break;
                }
+       }
 
-               if (return_all) {
-                       if ((flags & PDO_FETCH_UNIQUE) == PDO_FETCH_UNIQUE) {
-                               zend_symtable_update(Z_ARRVAL_P(return_all), Z_STR(grp_val), return_value);
-                       } else {
-                               zval grp;
-                               if ((pgrp = zend_symtable_find(Z_ARRVAL_P(return_all), Z_STR(grp_val))) == NULL) {
-                                       array_init(&grp);
-                                       zend_symtable_update(Z_ARRVAL_P(return_all), Z_STR(grp_val), &grp);
+       switch (how) {
+               case PDO_FETCH_CLASS:
+                       if (ce->constructor && !(flags & (PDO_FETCH_PROPS_LATE | PDO_FETCH_SERIALIZE))) {
+                               stmt->fetch.cls.fci.object = Z_OBJ_P(return_value);
+                               stmt->fetch.cls.fcc.object = Z_OBJ_P(return_value);
+                               if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc) == FAILURE) {
+                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
+                                       return 0;
                                } else {
-                                       ZVAL_COPY_VALUE(&grp, pgrp);
+                                       if (!Z_ISUNDEF(stmt->fetch.cls.retval)) {
+                                               zval_ptr_dtor(&stmt->fetch.cls.retval);
+                                       }
                                }
-                               zend_hash_next_index_insert(Z_ARRVAL(grp), return_value);
                        }
-                       zval_ptr_dtor_str(&grp_val);
-               }
+                       if (flags & PDO_FETCH_CLASSTYPE) {
+                               do_fetch_opt_finish(stmt, 0);
+                               stmt->fetch.cls.ce = old_ce;
+                               ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
+                               stmt->fetch.cls.fci.param_count = old_arg_count;
+                       }
+                       break;
 
+               case PDO_FETCH_FUNC:
+                       stmt->fetch.func.fci.param_count = idx;
+                       stmt->fetch.func.fci.retval = &retval;
+                       if (zend_call_function(&stmt->fetch.func.fci, &stmt->fetch.func.fcc) == FAILURE) {
+                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function");
+                               return 0;
+                       } else {
+                               if (return_all) {
+                                       zval_ptr_dtor(return_value); /* we don't need that */
+                                       ZVAL_COPY_VALUE(return_value, &retval);
+                               } else if (!Z_ISUNDEF(retval)) {
+                                       ZVAL_COPY_VALUE(return_value, &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) {
+                       zend_symtable_update(Z_ARRVAL_P(return_all), Z_STR(grp_val), return_value);
+               } else {
+                       zval grp;
+                       if ((pgrp = zend_symtable_find(Z_ARRVAL_P(return_all), Z_STR(grp_val))) == NULL) {
+                               array_init(&grp);
+                               zend_symtable_update(Z_ARRVAL_P(return_all), Z_STR(grp_val), &grp);
+                       } else {
+                               ZVAL_COPY_VALUE(&grp, pgrp);
+                       }
+                       zend_hash_next_index_insert(Z_ARRVAL(grp), return_value);
+               }
+               zval_ptr_dtor_str(&grp_val);
        }
 
        return 1;