]> granicus.if.org Git - php/commitdiff
Fix bug #52098
authorDaniel Persson <daniel.persson@textalk.se>
Sat, 26 Sep 2015 10:43:40 +0000 (12:43 +0200)
committerJulien Pauli <jpauli@php.net>
Mon, 21 Mar 2016 14:04:11 +0000 (15:04 +0100)
ext/pdo/pdo_dbh.c
ext/pdo/pdo_stmt.c
ext/pdo/tests/bug_52098.phpt [new file with mode: 0644]

index 1609306552e2b6d697dd85f52b624928ca72081d..d027d9796328c47262c9166a7f9dc750a91d8431 100644 (file)
@@ -1348,18 +1348,12 @@ int pdo_hash_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC)
 }
 
 static union _zend_function *dbh_method_get(
-#if PHP_API_VERSION >= 20041225
        zval **object_pp,
-#else
-       zval *object,
-#endif
        char *method_name, int method_len, const zend_literal *key TSRMLS_DC)
 {
        zend_function *fbc = NULL;
        char *lc_method_name;
-#if PHP_API_VERSION >= 20041225
        zval *object = *object_pp;
-#endif
        pdo_dbh_t *dbh = zend_object_store_get_object(object TSRMLS_CC);
 
        lc_method_name = emalloc(method_len + 1);
index 2dca3873135a114df5ca452a1ebf224b8d549a12..db295ee43083143ffee051876923b3b8549fdd9a 100644 (file)
@@ -145,7 +145,7 @@ static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_pa
                        pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
                        return 0;
                }
-    
+
                zend_hash_internal_pointer_reset(stmt->bound_param_map);
                while (SUCCESS == zend_hash_get_current_data(stmt->bound_param_map, (void**)&name)) {
                        if (strcmp(name, param->name)) {
@@ -163,7 +163,7 @@ static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_pa
                pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
                return 0;
        }
-       return 1;       
+       return 1;
 }
 /* }}} */
 
@@ -188,7 +188,7 @@ iterate:
                                ret = 0;
                                break;
                        }
-                       
+
                        zend_hash_move_forward(ht);
                }
        }
@@ -442,14 +442,14 @@ static PHP_METHOD(PDOStatement, execute)
        }
 
        PDO_STMT_CLEAR_ERR();
-       
+
        if (input_params) {
                struct pdo_bound_param_data param;
                zval **tmp;
                uint str_length;
                ulong num_index;
-       
-               if (stmt->bound_params) {       
+
+               if (stmt->bound_params) {
                        zend_hash_destroy(stmt->bound_params);
                        FREE_HASHTABLE(stmt->bound_params);
                        stmt->bound_params = NULL;
@@ -490,7 +490,7 @@ static PHP_METHOD(PDOStatement, execute)
 
        if (PDO_PLACEHOLDER_NONE == stmt->supports_placeholders) {
                /* handle the emulated parameter binding,
-         * stmt->active_query_string holds the query with binds expanded and 
+         * stmt->active_query_string holds the query with binds expanded and
                 * quoted.
          */
 
@@ -531,7 +531,7 @@ static PHP_METHOD(PDOStatement, execute)
                if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST TSRMLS_CC)) {
                        RETURN_FALSE;
                }
-                       
+
                RETURN_BOOL(ret);
        }
        if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
@@ -569,12 +569,12 @@ static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *typ
                        } else {
                                ZVAL_NULL(dest);
                        }
-                       
+
                        if (Z_TYPE_P(dest) == IS_NULL) {
                                type = new_type;
                        }
                        break;
-                       
+
                case PDO_PARAM_INT:
                        if (value && value_len == sizeof(long)) {
                                ZVAL_LONG(dest, *(long*)value);
@@ -635,7 +635,7 @@ static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *typ
                                }
                        }
                        break;
-               
+
                case PDO_PARAM_STR:
                        if (value && !(value_len == 0 && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING)) {
                                ZVAL_STRINGL(dest, value, value_len, !caller_frees);
@@ -666,7 +666,7 @@ static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *typ
                                ;
                }
        }
-       
+
        if (caller_frees && value) {
                efree(value);
        }
@@ -705,7 +705,7 @@ static int do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori,
        if (!stmt->columns && !pdo_stmt_describe_columns(stmt TSRMLS_CC)) {
                return 0;
        }
-       
+
        if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_POST TSRMLS_CC)) {
                return 0;
        }
@@ -751,7 +751,7 @@ static int do_fetch_class_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
                stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
                ce = ZEND_STANDARD_CLASS_DEF_PTR;
        }
-       
+
        if (ce->constructor) {
                fci->function_table = &ce->function_table;
                fci->function_name = NULL;
@@ -780,7 +780,7 @@ static int make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info *
 {
        char *is_callable_error = NULL;
 
-       if (zend_fcall_info_init(callable, 0, fci, fcc, NULL, &is_callable_error TSRMLS_CC) == FAILURE) { 
+       if (zend_fcall_info_init(callable, 0, fci, fcc, NULL, &is_callable_error TSRMLS_CC) == FAILURE) {
                if (is_callable_error) {
                        pdo_raise_impl_error(stmt->dbh, stmt, "HY000", is_callable_error TSRMLS_CC);
                        efree(is_callable_error);
@@ -793,10 +793,10 @@ static int make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info *
                /* Possible E_STRICT error message */
                efree(is_callable_error);
        }
-       
+
        fci->param_count = num_args; /* probably less */
        fci->params = safe_emalloc(sizeof(zval**), num_args, 0);
-       
+
        return 1;
 }
 /* }}} */
@@ -909,7 +909,7 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
                                        } else if (flags == PDO_FETCH_GROUP && colno) {
                                                fetch_value(stmt, return_value, 0, NULL TSRMLS_CC);
                                        } else {
-                                               fetch_value(stmt, return_value, colno, NULL TSRMLS_CC); 
+                                               fetch_value(stmt, return_value, colno, NULL TSRMLS_CC);
                                        }
                                        if (!return_all) {
                                                return 1;
@@ -976,7 +976,7 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
                                        }
                                }
                                break;
-                       
+
                        case PDO_FETCH_INTO:
                                if (!stmt->fetch.into) {
                                        pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch-into object specified." TSRMLS_CC);
@@ -1006,13 +1006,13 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
                                        }
                                }
                                break;
-                               
+
 
                        default:
                                /* shouldn't happen */
                                return 0;
                }
-               
+
                if (return_all && how != PDO_FETCH_KEY_PAIR) {
                        INIT_PZVAL(&grp_val);
                        if (flags == PDO_FETCH_GROUP && how == PDO_FETCH_COLUMN && stmt->fetch.column > 0) {
@@ -1037,7 +1037,7 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
                                case PDO_FETCH_ASSOC:
                                        add_assoc_zval(return_value, stmt->columns[i].name, val);
                                        break;
-                                       
+
                                case PDO_FETCH_KEY_PAIR:
                                        {
                                                zval *tmp;
@@ -1144,12 +1144,12 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
                                                }
                                        }
                                        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);
@@ -1157,7 +1157,7 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
                                        break;
                        }
                }
-               
+
                switch (how) {
                        case PDO_FETCH_CLASS:
                                if (ce->constructor && !(flags & (PDO_FETCH_PROPS_LATE | PDO_FETCH_SERIALIZE))) {
@@ -1199,7 +1199,7 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
                                        zval_ptr_dtor(&stmt->fetch.func.values[idx]);
                                }
                                break;
-                       
+
                        default:
                                break;
                }
@@ -1236,7 +1236,7 @@ static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, long mode, int fetch_all TSRML
                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode" TSRMLS_CC);
                return 0;
        }
-       
+
        if (mode == PDO_FETCH_USE_DEFAULT) {
                flags = stmt->default_fetch_type & PDO_FETCH_FLAGS;
                mode = stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
@@ -1256,7 +1256,7 @@ static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, long mode, int fetch_all TSRML
                        return 0;
                }
                /* fall through */
-       
+
        default:
                if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
                        pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_SERIALIZE can only be used together with PDO::FETCH_CLASS" TSRMLS_CC);
@@ -1333,7 +1333,7 @@ static PHP_METHOD(PDOStatement, fetchObject)
        old_ce = stmt->fetch.cls.ce;
        old_ctor_args = stmt->fetch.cls.ctor_args;
        old_arg_count = stmt->fetch.cls.fci.param_count;
-       
+
        do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
 
        if (ctor_args) {
@@ -1405,7 +1405,7 @@ static PHP_METHOD(PDOStatement, fetchAll)
        zend_class_entry *old_ce;
        zval *old_ctor_args, *ctor_args = NULL;
        int error = 0, flags, old_arg_count;
-       PHP_STMT_GET_OBJ;         
+       PHP_STMT_GET_OBJ;
 
        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lzz", &how, &arg2, &ctor_args)) {
                RETURN_FALSE;
@@ -1474,7 +1474,7 @@ static PHP_METHOD(PDOStatement, fetchAll)
                        break;
                }
                break;
-       
+
        case PDO_FETCH_COLUMN:
                switch(ZEND_NUM_ARGS()) {
                case 0:
@@ -1499,7 +1499,7 @@ static PHP_METHOD(PDOStatement, fetchAll)
        }
 
        flags = how & PDO_FETCH_FLAGS;
-       
+
        if ((how & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
                flags |= stmt->default_fetch_type & PDO_FETCH_FLAGS;
                how |= stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
@@ -1508,7 +1508,7 @@ static PHP_METHOD(PDOStatement, fetchAll)
        if (!error)     {
                PDO_STMT_CLEAR_ERR();
                MAKE_STD_ZVAL(data);
-               if (    (how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR || 
+               if (    (how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR ||
                        (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)
                ) {
                        array_init(return_value);
@@ -1537,13 +1537,13 @@ static PHP_METHOD(PDOStatement, fetchAll)
                }
                FREE_ZVAL(data);
        }
-       
+
        do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
 
        stmt->fetch.cls.ce = old_ce;
        stmt->fetch.cls.ctor_args = old_ctor_args;
        stmt->fetch.cls.fci.param_count = old_arg_count;
-       
+
        if (error) {
                PDO_HANDLE_STMT_ERR();
                if (error != 2) {
@@ -1569,14 +1569,14 @@ static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt,
                        "lz|llz!", &param.paramno, &param.parameter, &param_type, &param.max_value_len,
                        &param.driver_params)) {
                if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|llz!", &param.name,
-                               &param.namelen, &param.parameter, &param_type, &param.max_value_len, 
+                               &param.namelen, &param.parameter, &param_type, &param.max_value_len,
                                &param.driver_params)) {
                        return 0;
-               }       
+               }
        }
-       
+
        param.param_type = (int) param_type;
-       
+
        if (param.paramno > 0) {
                --param.paramno; /* make it zero-based internally */
        } else if (!param.name) {
@@ -1604,7 +1604,7 @@ static PHP_METHOD(PDOStatement, bindValue)
        PHP_STMT_GET_OBJ;
 
        param.paramno = -1;
-       
+
        if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
                        "lz/|l", &param.paramno, &param.parameter, &param_type)) {
                if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/|l", &param.name,
@@ -1614,14 +1614,14 @@ static PHP_METHOD(PDOStatement, bindValue)
        }
 
        param.param_type = (int) param_type;
-       
+
        if (param.paramno > 0) {
                --param.paramno; /* make it zero-based internally */
        } else if (!param.name) {
                pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
                RETURN_FALSE;
        }
-       
+
        Z_ADDREF_P(param.parameter);
        if (!really_register_bound_param(&param, stmt, TRUE TSRMLS_CC)) {
                if (param.parameter) {
@@ -1758,7 +1758,7 @@ static int generic_stmt_attr_get(pdo_stmt_t *stmt, zval *return_value, long attr
        }
        return 0;
 }
-   
+
 static PHP_METHOD(PDOStatement, getAttribute)
 {
        long attr;
@@ -1859,7 +1859,7 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
        zval ***args;
        zend_class_entry **cep;
        int retval;
-       
+
        do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
 
        switch (stmt->default_fetch_type) {
@@ -1872,7 +1872,7 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
                default:
                        ;
        }
-       
+
        stmt->default_fetch_type = PDO_FETCH_BOTH;
 
        if (argc == 0) {
@@ -1882,7 +1882,7 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
        args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval*), 0);
 
        retval = zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args);
-       
+
        if (SUCCESS == retval) {
                if (Z_TYPE_PP(args[skip]) != IS_LONG) {
                        pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "mode must be an integer" TSRMLS_CC);
@@ -1890,11 +1890,11 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
                } else {
                        mode = Z_LVAL_PP(args[skip]);
                        flags = mode & PDO_FETCH_FLAGS;
-       
+
                        retval = pdo_stmt_verify_mode(stmt, mode, 0 TSRMLS_CC);
                }
        }
-       
+
        if (FAILURE == retval) {
                PDO_STMT_CLEAR_ERR();
                efree(args);
@@ -1978,7 +1978,7 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
                                        do_fetch_class_prepare(stmt TSRMLS_CC);
                                }
                        }
-                       
+
                        break;
 
                case PDO_FETCH_INTO:
@@ -1989,13 +1989,13 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
                        } else {
                                retval = SUCCESS;
                        }
-                       
+
                        if (SUCCESS == retval) {
 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
                                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");
                                }
-#endif 
+#endif
                                MAKE_STD_ZVAL(stmt->fetch.into);
 
                                Z_TYPE_P(stmt->fetch.into) = IS_OBJECT;
@@ -2003,9 +2003,9 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
                                Z_OBJ_HT_P(stmt->fetch.into) = Z_OBJ_HT_PP(args[skip+1]);
                                zend_objects_store_add_ref(stmt->fetch.into TSRMLS_CC);
                        }
-                       
+
                        break;
-               
+
                default:
                        pdo_raise_impl_error(stmt->dbh, stmt, "22003", "Invalid fetch mode specified" TSRMLS_CC);
        }
@@ -2024,10 +2024,10 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in
        PDO_STMT_CLEAR_ERR();
 
        efree(args);
-               
+
        return retval;
 }
-   
+
 static PHP_METHOD(PDOStatement, setFetchMode)
 {
        PHP_STMT_GET_OBJ;
@@ -2048,7 +2048,7 @@ static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
        if (stmt->columns) {
                int i;
                struct pdo_column_data *cols = stmt->columns;
-               
+
                for (i = 0; i < stmt->column_count; i++) {
                        efree(cols[i].name);
                }
@@ -2078,7 +2078,7 @@ static PHP_METHOD(PDOStatement, nextRowset)
        }
 
        PDO_STMT_CLEAR_ERR();
-       
+
        if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
                PDO_HANDLE_STMT_ERR();
                RETURN_FALSE;
@@ -2106,7 +2106,7 @@ static PHP_METHOD(PDOStatement, closeCursor)
                        if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
                                break;
                        }
-                               
+
                } while (1);
                stmt->executed = 0;
                RETURN_TRUE;
@@ -2135,14 +2135,14 @@ static PHP_METHOD(PDOStatement, debugDumpParams)
        if (out == NULL) {
                RETURN_FALSE;
        }
-       
+
        php_stream_printf(out TSRMLS_CC, "SQL: [%d] %.*s\n",
                stmt->query_stringlen,
                stmt->query_stringlen, stmt->query_string);
 
        php_stream_printf(out TSRMLS_CC, "Params:  %d\n",
                stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
-       
+
        if (stmt->bound_params) {
                zend_hash_internal_pointer_reset_ex(stmt->bound_params, &pos);
                while (SUCCESS == zend_hash_get_current_data_ex(stmt->bound_params,
@@ -2163,7 +2163,7 @@ static PHP_METHOD(PDOStatement, debugDumpParams)
                                param->paramno, param->namelen, param->namelen, param->name ? param->name : "",
                                param->is_param,
                                param->param_type);
-                       
+
                        zend_hash_move_forward_ex(stmt->bound_params, &pos);
                }
        }
@@ -2241,47 +2241,51 @@ static void dbstmt_prop_delete(zval *object, zval *member, const zend_literal *k
 }
 
 static union _zend_function *dbstmt_method_get(
-#if PHP_API_VERSION >= 20041225
        zval **object_pp,
-#else
-       zval *object,
-#endif
        char *method_name, int method_len, const zend_literal *key TSRMLS_DC)
 {
        zend_function *fbc = NULL;
        char *lc_method_name;
-#if PHP_API_VERSION >= 20041225
        zval *object = *object_pp;
-#endif
+       zend_function *fbc_fallback = NULL;
 
        lc_method_name = emalloc(method_len + 1);
        zend_str_tolower_copy(lc_method_name, method_name, method_len);
 
-       if (zend_hash_find(&Z_OBJCE_P(object)->function_table, lc_method_name, 
+       if (zend_hash_find(&Z_OBJCE_P(object)->function_table, lc_method_name,
                        method_len+1, (void**)&fbc) == FAILURE) {
+
+               /* Prepare fallback by running standard method for functions.
+                * If the function does not find a method to instanciate it will return this fallback method. */
+               fbc_fallback = std_object_handlers.get_method(object_pp, method_name, method_len, key TSRMLS_CC);
+
                pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
                /* instance not created by PDO object */
                if (!stmt->dbh) {
+                       fbc = fbc_fallback;
                        goto out;
                }
                /* not a pre-defined method, nor a user-defined method; check
                 * the driver specific methods */
                if (!stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
-                       if (!pdo_hash_methods(stmt->dbh, 
+                       if (!pdo_hash_methods(stmt->dbh,
                                PDO_DBH_DRIVER_METHOD_KIND_STMT TSRMLS_CC)
                                || !stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
+
+                               fbc = fbc_fallback;
                                goto out;
                        }
                }
 
                if (zend_hash_find(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT],
                                lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
-                       fbc = NULL;
+
+                       fbc = fbc_fallback;
                        goto out;
                }
                /* got it */
        }
-       
+
 out:
        efree(lc_method_name);
        return fbc;
@@ -2305,15 +2309,15 @@ static zend_object_value dbstmt_clone_obj(zval *zobject TSRMLS_DC)
        stmt->refcount = 1;
 
        old_stmt = (pdo_stmt_t *)zend_object_store_get_object(zobject TSRMLS_CC);
-       
+
        retval.handle = zend_objects_store_put(stmt, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_dbstmt_free_storage, (zend_objects_store_clone_t)dbstmt_clone_obj TSRMLS_CC);
        retval.handlers = Z_OBJ_HT_P(zobject);
 
        zend_objects_clone_members((zend_object *)stmt, retval, (zend_object *)old_stmt, handle TSRMLS_CC);
-       
+
        zend_objects_store_add_ref(&old_stmt->database_object_handle TSRMLS_CC);
        stmt->database_object_handle = old_stmt->database_object_handle;
-                       
+
        return retval;
 }
 
@@ -2328,7 +2332,7 @@ void pdo_stmt_init(TSRMLS_D)
        pdo_dbstmt_ce = zend_register_internal_class(&ce TSRMLS_CC);
        pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
        pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
-       zend_class_implements(pdo_dbstmt_ce TSRMLS_CC, 1, zend_ce_traversable); 
+       zend_class_implements(pdo_dbstmt_ce TSRMLS_CC, 1, zend_ce_traversable);
        zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
 
        memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
@@ -2388,7 +2392,7 @@ static void free_statement(pdo_stmt_t *stmt TSRMLS_DC)
                FREE_ZVAL(stmt->fetch.into);
                stmt->fetch.into = NULL;
        }
-       
+
        do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
 
        zend_objects_store_del_ref(&stmt->database_object_handle TSRMLS_CC);
@@ -2450,7 +2454,7 @@ static void pdo_stmt_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
        if (--I->stmt->refcount == 0) {
                free_statement(I->stmt TSRMLS_CC);
        }
-               
+
        if (I->fetch_ahead) {
                zval_ptr_dtor(&I->fetch_ahead);
        }
@@ -2594,7 +2598,7 @@ static zval *row_prop_read(zval *object, zval *member, int type, const zend_lite
 
        Z_SET_REFCOUNT_P(return_value, 0);
        Z_UNSET_ISREF_P(return_value);
-       
+
        return return_value;
 }
 
@@ -2660,7 +2664,7 @@ static HashTable *row_get_properties(zval *object TSRMLS_DC)
        if (stmt == NULL) {
                return NULL;
        }
-       
+
        if (!stmt->std.properties) {
                rebuild_object_properties(&stmt->std);
        }
@@ -2676,11 +2680,7 @@ static HashTable *row_get_properties(zval *object TSRMLS_DC)
 }
 
 static union _zend_function *row_method_get(
-#if PHP_API_VERSION >= 20041225
        zval **object_pp,
-#else
-       zval *object,
-#endif
        char *method_name, int method_len, const zend_literal *key TSRMLS_DC)
 {
        zend_function *fbc;
@@ -2693,7 +2693,7 @@ static union _zend_function *row_method_get(
                efree(lc_method_name);
                return NULL;
        }
-       
+
        efree(lc_method_name);
        return fbc;
 }
@@ -2767,7 +2767,7 @@ void pdo_row_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
 {
        if (stmt) {
                ZVAL_NULL(&stmt->lazy_object_ref);
-               
+
                if (--stmt->refcount == 0) {
                        free_statement(stmt TSRMLS_CC);
                }
diff --git a/ext/pdo/tests/bug_52098.phpt b/ext/pdo/tests/bug_52098.phpt
new file mode 100644 (file)
index 0000000..c9d39af
--- /dev/null
@@ -0,0 +1,59 @@
+--TEST--
+PDO Common: Bug #52098 Own PDOStatement implementation ignore __call()
+--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_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
+$db = PDOTest::factory();
+
+@$db->exec("DROP TABLE test");
+$db->exec("CREATE TABLE test (x int)");
+$db->exec("INSERT INTO test VALUES (1)");
+
+class MyStatement extends PDOStatement
+{
+    public function __call($name, $arguments)
+    {
+        echo "Calling object method '$name'" . implode(', ', $arguments). "\n";
+    }
+}
+/*
+Test prepared statement with PDOStatement class.
+*/
+$derived = $db->prepare('SELECT * FROM test', array(PDO::ATTR_STATEMENT_CLASS=>array('MyStatement')));
+$derived->execute();
+$derived->foo();
+$derived->fetchAll();
+$derived = null;
+
+/*
+Test regular statement with PDOStatement class.
+*/
+$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('MyStatement'));
+$r =  $db->query('SELECT * FROM test');
+echo $r->bar();
+$r->fetchAll();
+$r = null;
+
+/*
+Test object instance of PDOStatement class.
+*/
+$obj = new MyStatement;
+echo $obj->lucky();
+
+$db->exec("DROP TABLE test");
+?>
+===DONE===
+--EXPECTF--
+Calling object method 'foo'
+Calling object method 'bar'
+Calling object method 'lucky'
+===DONE===
\ No newline at end of file