]> granicus.if.org Git - php/commitdiff
Make various failure conditions in PDO unconditional errors
authorGeorge Peter Banyard <girgias@php.net>
Thu, 24 Sep 2020 23:41:21 +0000 (00:41 +0100)
committerGeorge Peter Banyard <girgias@php.net>
Mon, 28 Sep 2020 17:51:36 +0000 (18:51 +0100)
This includes TypeErrors, ValueErrors, Error for uninitialized objects
and invalid user classes/callable instanciation

Closes GH-6212

18 files changed:
ext/pdo/pdo_dbh.c
ext/pdo/pdo_stmt.c
ext/pdo/pdo_stmt.stub.php
ext/pdo/pdo_stmt_arginfo.h
ext/pdo/php_pdo.h
ext/pdo/php_pdo_int.h
ext/pdo/tests/bug_44159.phpt
ext/pdo/tests/bug_44173.phpt
ext/pdo/tests/pdo_038.phpt
ext/pdo/tests/pdo_quote_empty_string.phpt [new file with mode: 0644]
ext/pdo_mysql/tests/pdo_mysql_attr_errmode.phpt
ext/pdo_mysql/tests/pdo_mysql_attr_oracle_nulls.phpt
ext/pdo_mysql/tests/pdo_mysql_attr_statement_class.phpt
ext/pdo_mysql/tests/pdo_mysql_prepare_emulated.phpt
ext/pdo_mysql/tests/pdo_mysql_prepare_native.phpt
ext/pdo_mysql/tests/pdo_mysql_stmt_getcolumnmeta.phpt
ext/pdo_sqlite/tests/bug_44159_sqlite_version.phpt [new file with mode: 0644]
ext/pdo_sqlite/tests/pdo_fetch_func_001.phpt

index 780de94707b1eac854d2ad2dbf2824a009fdaf2a..0f5eaab2e6e62b54569e7ff44340b633b0da26d4 100644 (file)
@@ -425,12 +425,10 @@ options:
 static zval *pdo_stmt_instantiate(pdo_dbh_t *dbh, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args) /* {{{ */
 {
        if (!Z_ISUNDEF_P(ctor_args)) {
-               if (Z_TYPE_P(ctor_args) != IS_ARRAY) {
-                       pdo_raise_impl_error(dbh, NULL, "HY000", "constructor arguments must be passed as an array");
-                       return NULL;
-               }
+               /* This implies an error within PDO if this does not hold */
+               ZEND_ASSERT(Z_TYPE_P(ctor_args) == IS_ARRAY);
                if (!dbstmt_ce->constructor) {
-                       pdo_raise_impl_error(dbh, NULL, "HY000", "user-supplied statement does not accept constructor arguments");
+                       zend_throw_error(NULL, "User-supplied statement does not accept constructor arguments");
                        return NULL;
                }
        }
@@ -487,7 +485,7 @@ PHP_METHOD(PDO, prepare)
        pdo_stmt_t *stmt;
        char *statement;
        size_t statement_len;
-       zval *options = NULL, *opt, *item, ctor_args;
+       zval *options = NULL, *value, *item, ctor_args;
        zend_class_entry *dbstmt_ce, *pce;
        pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(ZEND_THIS);
        pdo_dbh_t *dbh = dbh_obj->inner;
@@ -498,42 +496,44 @@ PHP_METHOD(PDO, prepare)
                Z_PARAM_ARRAY(options)
        ZEND_PARSE_PARAMETERS_END();
 
-       PDO_DBH_CLEAR_ERR();
        PDO_CONSTRUCT_CHECK;
 
-       if (ZEND_NUM_ARGS() > 1 && (opt = zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_STATEMENT_CLASS)) != NULL) {
-               if (Z_TYPE_P(opt) != IS_ARRAY || (item = zend_hash_index_find(Z_ARRVAL_P(opt), 0)) == NULL
-                       || Z_TYPE_P(item) != IS_STRING
-                       || (pce = zend_lookup_class(Z_STR_P(item))) == NULL
-               ) {
-                       pdo_raise_impl_error(dbh, NULL, "HY000",
-                               "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
-                               "the classname must be a string specifying an existing class"
-                               );
-                       PDO_HANDLE_DBH_ERR();
-                       RETURN_FALSE;
+       if (statement_len == 0) {
+               zend_argument_value_error(1, "cannot be empty");
+               RETURN_THROWS();
+       }
+
+       PDO_DBH_CLEAR_ERR();
+
+       if (options && (value = zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_STATEMENT_CLASS)) != NULL) {
+               if (Z_TYPE_P(value) != IS_ARRAY) {
+                       zend_type_error("PDO::ATTR_STATEMENT_CLASS value must be of type array, %s given",
+                               zend_zval_type_name(value));
+                       RETURN_THROWS();
+               }
+               if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL) {
+                       zend_value_error("PDO::ATTR_STATEMENT_CLASS value must be an array with the format "
+                               "array(classname, array(ctor_args))");
+                       RETURN_THROWS();
+               }
+               if (Z_TYPE_P(item) != IS_STRING || (pce = zend_lookup_class(Z_STR_P(item))) == NULL) {
+                       zend_type_error("PDO::ATTR_STATEMENT_CLASS class must be a valid class");
+                       RETURN_THROWS();
                }
                dbstmt_ce = pce;
                if (!instanceof_function(dbstmt_ce, pdo_dbstmt_ce)) {
-                       pdo_raise_impl_error(dbh, NULL, "HY000",
-                               "user-supplied statement class must be derived from PDOStatement");
-                       PDO_HANDLE_DBH_ERR();
-                       RETURN_FALSE;
+                       zend_type_error("PDO::ATTR_STATEMENT_CLASS class must be derived from PDOStatement");
+                       RETURN_THROWS();
                }
                if (dbstmt_ce->constructor && !(dbstmt_ce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
-                       pdo_raise_impl_error(dbh, NULL, "HY000",
-                               "user-supplied statement class cannot have a public constructor");
-                       PDO_HANDLE_DBH_ERR();
-                       RETURN_FALSE;
+                       zend_type_error("User-supplied statement class cannot have a public constructor");
+                       RETURN_THROWS();
                }
-               if ((item = zend_hash_index_find(Z_ARRVAL_P(opt), 1)) != NULL) {
+               if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 1)) != NULL) {
                        if (Z_TYPE_P(item) != IS_ARRAY) {
-                               pdo_raise_impl_error(dbh, NULL, "HY000",
-                                       "PDO::ATTR_STATEMENT_CLASS requires format array(classname, ctor_args); "
-                                       "ctor_args must be an array"
-                               );
-                               PDO_HANDLE_DBH_ERR();
-                               RETURN_FALSE;
+                               zend_type_error("PDO::ATTR_STATEMENT_CLASS ctor_args must be of type ?array, %s given",
+                                       zend_zval_type_name(value));
+                               RETURN_THROWS();
                        }
                        ZVAL_COPY_VALUE(&ctor_args, item);
                } else {
@@ -544,11 +544,10 @@ PHP_METHOD(PDO, prepare)
                ZVAL_COPY_VALUE(&ctor_args, &dbh->def_stmt_ctor_args);
        }
 
+       /* Need to check if pdo_stmt_instantiate() throws an exception unconditionally to see if can change the RETURN_FALSE; */
        if (!pdo_stmt_instantiate(dbh, return_value, dbstmt_ce, &ctor_args)) {
                if (EXPECTED(!EG(exception))) {
-                       pdo_raise_impl_error(dbh, NULL, "HY000",
-                               "failed to instantiate user-supplied statement class"
-                               );
+                       zend_throw_error(NULL, "Cannot instantiate user-supplied statement class");
                }
                PDO_HANDLE_DBH_ERR();
                RETURN_FALSE;
@@ -679,10 +678,10 @@ static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /*
 {
        zend_long lval;
 
+/* TODO: Make distinction between numeric and non-numeric strings */
 #define PDO_LONG_PARAM_CHECK \
        if (Z_TYPE_P(value) != IS_LONG && Z_TYPE_P(value) != IS_STRING && Z_TYPE_P(value) != IS_FALSE && Z_TYPE_P(value) != IS_TRUE) { \
-               pdo_raise_impl_error(dbh, NULL, "HY000", "attribute value must be an integer"); \
-               PDO_HANDLE_DBH_ERR(); \
+               zend_type_error("Attribute value must be of type int for selected attribute, %s given", zend_zval_type_name(value)); \
                return FAILURE; \
        } \
 
@@ -697,8 +696,7 @@ static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /*
                                        dbh->error_mode = lval;
                                        return SUCCESS;
                                default:
-                                       pdo_raise_impl_error(dbh, NULL, "HY000", "invalid error mode");
-                                       PDO_HANDLE_DBH_ERR();
+                                       zend_value_error("Error mode must be one of the PDO::ERRMODE_* constants");
                                        return FAILURE;
                        }
                        return FAILURE;
@@ -713,8 +711,7 @@ static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /*
                                        dbh->desired_case = lval;
                                        return SUCCESS;
                                default:
-                                       pdo_raise_impl_error(dbh, NULL, "HY000", "invalid case folding mode");
-                                       PDO_HANDLE_DBH_ERR();
+                                       zend_value_error("Case folding mode must be one of the PDO::CASE_* constants");
                                        return FAILURE;
                        }
                        return FAILURE;
@@ -729,7 +726,7 @@ static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /*
                                zval *tmp;
                                if ((tmp = zend_hash_index_find(Z_ARRVAL_P(value), 0)) != NULL && Z_TYPE_P(tmp) == IS_LONG) {
                                        if (Z_LVAL_P(tmp) == PDO_FETCH_INTO || Z_LVAL_P(tmp) == PDO_FETCH_CLASS) {
-                                               pdo_raise_impl_error(dbh, NULL, "HY000", "FETCH_INTO and FETCH_CLASS are not yet supported as default fetch modes");
+                                               zend_value_error("PDO::FETCH_INTO and PDO::FETCH_CLASS cannot be set as the default fetch mode");
                                                return FAILURE;
                                        }
                                }
@@ -738,7 +735,7 @@ static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /*
                        }
                        lval = zval_get_long(value);
                        if (lval == PDO_FETCH_USE_DEFAULT) {
-                               pdo_raise_impl_error(dbh, NULL, "HY000", "invalid fetch mode type");
+                               zend_value_error("Fetch mode must be a bitmask of PDO::FETCH_* constants");
                                return FAILURE;
                        }
                        dbh->default_fetch_type = lval;
@@ -761,28 +758,26 @@ static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /*
                                PDO_HANDLE_DBH_ERR();
                                return FAILURE;
                        }
-                       if (Z_TYPE_P(value) != IS_ARRAY
-                               || (item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL
-                               || Z_TYPE_P(item) != IS_STRING
-                               || (pce = zend_lookup_class(Z_STR_P(item))) == NULL
-                       ) {
-                               pdo_raise_impl_error(dbh, NULL, "HY000",
-                                       "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
-                                       "the classname must be a string specifying an existing class"
-                                       );
-                               PDO_HANDLE_DBH_ERR();
+                       if (Z_TYPE_P(value) != IS_ARRAY) {
+                               zend_type_error("PDO::ATTR_STATEMENT_CLASS value must be of type array, %s given",
+                                       zend_zval_type_name(value));
+                               return FAILURE;
+                       }
+                       if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL) {
+                               zend_value_error("PDO::ATTR_STATEMENT_CLASS value must be an array with the format "
+                                       "array(classname, array(ctor_args))");
+                               return FAILURE;
+                       }
+                       if (Z_TYPE_P(item) != IS_STRING || (pce = zend_lookup_class(Z_STR_P(item))) == NULL) {
+                               zend_type_error("PDO::ATTR_STATEMENT_CLASS class must be a valid class");
                                return FAILURE;
                        }
                        if (!instanceof_function(pce, pdo_dbstmt_ce)) {
-                               pdo_raise_impl_error(dbh, NULL, "HY000",
-                                       "user-supplied statement class must be derived from PDOStatement");
-                               PDO_HANDLE_DBH_ERR();
+                               zend_type_error("PDO::ATTR_STATEMENT_CLASS class must be derived from PDOStatement");
                                return FAILURE;
                        }
                        if (pce->constructor && !(pce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
-                               pdo_raise_impl_error(dbh, NULL, "HY000",
-                                       "user-supplied statement class cannot have a public constructor");
-                               PDO_HANDLE_DBH_ERR();
+                               zend_type_error("User-supplied statement class cannot have a public constructor");
                                return FAILURE;
                        }
                        dbh->def_stmt_ce = pce;
@@ -792,11 +787,8 @@ static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /*
                        }
                        if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 1)) != NULL) {
                                if (Z_TYPE_P(item) != IS_ARRAY) {
-                                       pdo_raise_impl_error(dbh, NULL, "HY000",
-                                               "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
-                                               "ctor_args must be an array"
-                                       );
-                                       PDO_HANDLE_DBH_ERR();
+                                       zend_type_error("PDO::ATTR_STATEMENT_CLASS ctor_args must be of type ?array, %s given",
+                                               zend_zval_type_name(value));
                                        return FAILURE;
                                }
                                ZVAL_COPY(&dbh->def_stmt_ctor_args, item);
@@ -927,10 +919,11 @@ PHP_METHOD(PDO, exec)
                Z_PARAM_STRING(statement, statement_len)
        ZEND_PARSE_PARAMETERS_END();
 
-       if (!statement_len) {
-               pdo_raise_impl_error(dbh, NULL, "HY000",  "trying to execute an empty query");
-               RETURN_FALSE;
+       if (statement_len == 0) {
+               zend_argument_value_error(1, "cannot be empty");
+               RETURN_THROWS();
        }
+
        PDO_DBH_CLEAR_ERR();
        PDO_CONSTRUCT_CHECK;
        ret = dbh->methods->doer(dbh, statement, statement_len);
@@ -955,8 +948,10 @@ PHP_METHOD(PDO, lastInsertId)
                Z_PARAM_STRING_OR_NULL(name, namelen)
        ZEND_PARSE_PARAMETERS_END();
 
-       PDO_DBH_CLEAR_ERR();
        PDO_CONSTRUCT_CHECK;
+
+       PDO_DBH_CLEAR_ERR();
+
        if (!dbh->methods->last_id) {
                pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support lastInsertId()");
                RETURN_FALSE;
@@ -1060,13 +1055,20 @@ PHP_METHOD(PDO, query)
        pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(ZEND_THIS);
        pdo_dbh_t *dbh = dbh_obj->inner;
 
-       if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l!*", &statement, &statement_len, &fetch_mode, &fetch_mode_is_null, &args, &num_args)) {
+       if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l!*", &statement, &statement_len,
+                       &fetch_mode, &fetch_mode_is_null, &args, &num_args)) {
                RETURN_THROWS();
        }
 
-       PDO_DBH_CLEAR_ERR();
        PDO_CONSTRUCT_CHECK;
 
+       if (statement_len == 0) {
+               zend_argument_value_error(1, "cannot be empty");
+               RETURN_THROWS();
+       }
+
+       PDO_DBH_CLEAR_ERR();
+
        if (!pdo_stmt_instantiate(dbh, return_value, dbh->def_stmt_ce, &dbh->def_stmt_ctor_args)) {
                if (EXPECTED(!EG(exception))) {
                        pdo_raise_impl_error(dbh, NULL, "HY000", "failed to instantiate user supplied statement class");
@@ -1090,8 +1092,7 @@ PHP_METHOD(PDO, query)
 
        if (dbh->methods->preparer(dbh, statement, statement_len, stmt, NULL)) {
                PDO_STMT_CLEAR_ERR();
-               if (fetch_mode_is_null || SUCCESS == pdo_stmt_setup_fetch_mode(stmt, fetch_mode, args, num_args)) {
-
+               if (fetch_mode_is_null || pdo_stmt_setup_fetch_mode(stmt, fetch_mode, 2, args, num_args)) {
                        /* now execute the statement */
                        PDO_STMT_CLEAR_ERR();
                        if (stmt->methods->executer(stmt)) {
@@ -1139,8 +1140,9 @@ PHP_METHOD(PDO, quote)
                Z_PARAM_LONG(paramtype)
        ZEND_PARSE_PARAMETERS_END();
 
-       PDO_DBH_CLEAR_ERR();
        PDO_CONSTRUCT_CHECK;
+
+       PDO_DBH_CLEAR_ERR();
        if (!dbh->methods->quoter) {
                pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support quoting");
                RETURN_FALSE;
index 8ed0a77636e8b7c0ec1bad99e6d4abb158ba628a..0cec5d9955c53ef71cf7785b353722cf5c6a47b7 100644 (file)
 #include "php_memory_streams.h"
 #include "pdo_stmt_arginfo.h"
 
-#define PHP_STMT_GET_OBJ       \
-  pdo_stmt_t *stmt = Z_PDO_STMT_P(ZEND_THIS);  \
-  if (!stmt->dbh) {    \
-         RETURN_FALSE; \
-  }    \
+#define PHP_STMT_GET_OBJ \
+       pdo_stmt_t *stmt = Z_PDO_STMT_P(ZEND_THIS); \
+       if (!stmt->dbh) { \
+               zend_throw_error(NULL, "PDO object is uninitialized"); \
+               RETURN_THROWS(); \
+       } \
 
 static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param) /* {{{ */
 {
@@ -62,6 +63,7 @@ static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_pa
                                param->name = zend_string_init(name, strlen(name), 0);
                                return 1;
                        }
+                       /* TODO Error? */
                        pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined");
                        return 0;
                }
@@ -72,12 +74,14 @@ static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_pa
                                continue;
                        }
                        if (param->paramno >= 0) {
+                               /* TODO Error? */
                                pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "PDO refuses to handle repeating the same :named parameter for multiple positions with this driver, as it might be unsafe to do so.  Consider using a separate name for each parameter instead");
                                return -1;
                        }
                        param->paramno = position;
                        return 1;
                } ZEND_HASH_FOREACH_END();
+               /* TODO Error? */
                pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined");
                return 0;
        }
@@ -256,7 +260,7 @@ static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_s
 
                for (i = 0; i < stmt->column_count; i++) {
                        if (ZSTR_LEN(stmt->columns[i].name) == ZSTR_LEN(param->name) &&
-                           strncmp(ZSTR_VAL(stmt->columns[i].name), ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1) == 0) {
+                               strncmp(ZSTR_VAL(stmt->columns[i].name), ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1) == 0) {
                                param->paramno = i;
                                break;
                        }
@@ -265,7 +269,9 @@ static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_s
                /* if you prepare and then execute passing an array of params keyed by names,
                 * then this will trigger, and we don't want that */
                if (param->paramno == -1) {
+                       /* Should this always be an Error? */
                        char *tmp;
+                       /* TODO Error? */
                        spprintf(&tmp, 0, "Did not find column name '%s' in the defined columns; it will not be bound", ZSTR_VAL(param->name));
                        pdo_raise_impl_error(stmt->dbh, stmt, "HY000", tmp);
                        efree(tmp);
@@ -398,9 +404,9 @@ 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.
-         */
+                */
 
                /* string is leftover from previous calls so PDOStatement::debugDumpParams() can access */
                if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
@@ -457,10 +463,15 @@ static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *typ
        int caller_frees = 0;
        int type, new_type;
 
-       if (colno < 0 || colno >= stmt->column_count) {
-               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index");
-               ZVAL_FALSE(dest);
+       if (colno < 0) {
+               zend_value_error("Column index must be greater than or equal to 0");
+               ZVAL_NULL(dest);
+               return;
+       }
 
+       if (colno >= stmt->column_count) {
+               zend_value_error("Invalid column index");
+               ZVAL_NULL(dest);
                return;
        }
 
@@ -666,6 +677,7 @@ static int do_fetch_class_prepare(pdo_stmt_t *stmt) /* {{{ */
                fcc->called_scope = ce;
                return 1;
        } else if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args)) {
+               /* TODO Error? */
                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied class does not have a constructor, use NULL for the ctor_params parameter, or simply omit it");
                return 0;
        } else {
@@ -680,12 +692,12 @@ static int make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info *
 
        if (zend_fcall_info_init(callable, 0, fci, fcc, NULL, &is_callable_error) == FAILURE) {
                if (is_callable_error) {
-                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", is_callable_error);
+                       zend_type_error("%s", is_callable_error);
                        efree(is_callable_error);
                } else {
-                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback");
+                       zend_type_error("User-supplied function must be a valid callback");
                }
-               return 0;
+               return false;
        }
        if (is_callable_error) {
                /* Possible error message */
@@ -695,20 +707,20 @@ static int make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info *
        fci->param_count = num_args; /* probably less */
        fci->params = safe_emalloc(sizeof(zval), num_args, 0);
 
-       return 1;
+       return true;
 }
 /* }}} */
 
-static int do_fetch_func_prepare(pdo_stmt_t *stmt) /* {{{ */
+static bool do_fetch_func_prepare(pdo_stmt_t *stmt) /* {{{ */
 {
        zend_fcall_info *fci = &stmt->fetch.cls.fci;
        zend_fcall_info_cache *fcc = &stmt->fetch.cls.fcc;
 
        if (!make_callable_ex(stmt, &stmt->fetch.func.function, fci, fcc, stmt->column_count)) {
-               return 0;
+               return false;
        } else {
                stmt->fetch.func.values = safe_emalloc(sizeof(zval), stmt->column_count, 0);
-               return 1;
+               return true;
        }
 }
 /* }}} */
@@ -718,7 +730,7 @@ static void do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs) /* {{{ */
        /* fci.size is used to check if it is valid */
        if (stmt->fetch.cls.fci.size && stmt->fetch.cls.fci.params) {
                if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args)) {
-                   /* Added to free constructor arguments */
+                       /* Added to free constructor arguments */
                        zend_fcall_info_args_clear(&stmt->fetch.cls.fci, 1);
                } else {
                        efree(stmt->fetch.cls.fci.params);
@@ -806,23 +818,27 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
                        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) {
-                                       return 1;
-                               } else {
-                                       break;
-                               }
+                       if (colno < 0 ) {
+                               zend_value_error("Column index must be greater than or equal to 0");
+                               return false;
+                       }
+
+                       if (colno >= stmt->column_count) {
+                               zend_value_error("Invalid column index");
+                               return false;
+                       }
+
+                       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 {
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index");
+                               fetch_value(stmt, return_value, colno, NULL);
                        }
-                       return 0;
+                       if (!return_all) {
+                               return 1;
+                       }
+                       break;
 
                case PDO_FETCH_OBJ:
                        object_init_ex(return_value, ZEND_STANDARD_CLASS_DEF_PTR);
@@ -854,7 +870,9 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
                                zval_ptr_dtor_str(&val);
                        }
                        ce = stmt->fetch.cls.ce;
+                       /* TODO: Make this an assertion and ensure this is true higher up? */
                        if (!ce) {
+                               /* TODO Error? */
                                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified");
                                return 0;
                        }
@@ -872,6 +890,7 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
                                        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) {
+                                               /* TODO Error? */
                                                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
                                                return 0;
                                        } else {
@@ -886,6 +905,7 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
 
                case PDO_FETCH_INTO:
                        if (Z_ISUNDEF(stmt->fetch.into)) {
+                               /* TODO ArgumentCountError? */
                                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch-into object specified.");
                                return 0;
                                break;
@@ -900,6 +920,7 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
 
                case PDO_FETCH_FUNC:
                        if (Z_ISUNDEF(stmt->fetch.func.function)) {
+                               /* TODO ArgumentCountError? */
                                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch function specified");
                                return 0;
                        }
@@ -910,10 +931,7 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
                                }
                        }
                        break;
-
-               default:
-                       /* shouldn't happen */
-                       return 0;
+               EMPTY_SWITCH_DEFAULT_CASE();
        }
 
        if (return_all && how != PDO_FETCH_KEY_PAIR) {
@@ -1039,9 +1057,8 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
 
                        default:
                                zval_ptr_dtor(&val);
-                               pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range");
+                               zend_value_error("Fetch mode must be a bitmask of PDO::FETCH_* constants");
                                return 0;
-                               break;
                }
        }
 
@@ -1051,6 +1068,7 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
                                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) {
+                                       /* TODO Error? */
                                        pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
                                        return 0;
                                } else {
@@ -1071,6 +1089,7 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
                        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) {
+                               /* TODO Error? */
                                pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function");
                                return 0;
                        } else {
@@ -1110,14 +1129,14 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
 }
 /* }}} */
 
-static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, zend_long mode, int fetch_all) /* {{{ */
+static bool pdo_stmt_verify_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_arg_num, bool fetch_all) /* {{{ */
 {
        int flags = mode & PDO_FETCH_FLAGS;
 
        mode = mode & ~PDO_FETCH_FLAGS;
 
        if (mode < 0 || mode > PDO_FETCH__MAX) {
-               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode");
+               zend_argument_value_error(mode_arg_num, "must be a bitmask of PDO::FETCH_* constants");
                return 0;
        }
 
@@ -1129,28 +1148,28 @@ static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, zend_long mode, int fetch_all)
        switch(mode) {
                case PDO_FETCH_FUNC:
                        if (!fetch_all) {
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_FUNC is only allowed in PDOStatement::fetchAll()");
+                               zend_value_error("Can only use PDO::FETCH_FUNC in PDOStatement::fetchAll()");
                                return 0;
                        }
                        return 1;
 
                case PDO_FETCH_LAZY:
                        if (fetch_all) {
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_LAZY can't be used with PDOStatement::fetchAll()");
+                               zend_argument_value_error(mode_arg_num, "cannot be PDO::FETCH_LAZY in PDOStatement::fetchAll()");
                                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");
+                               zend_argument_value_error(mode_arg_num, "must use PDO::FETCH_SERIALIZE with PDO::FETCH_CLASS");
                                return 0;
                        }
                        if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_CLASSTYPE can only be used together with PDO::FETCH_CLASS");
+                               zend_argument_value_error(mode_arg_num, "must use PDO::FETCH_CLASSTYPE with PDO::FETCH_CLASS");
                                return 0;
                        }
                        if (mode >= PDO_FETCH__MAX) {
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode");
+                               zend_argument_value_error(mode_arg_num, "must be a bitmask of PDO::FETCH_* constants");
                                return 0;
                        }
                        /* no break; */
@@ -1175,14 +1194,14 @@ PHP_METHOD(PDOStatement, fetch)
                Z_PARAM_LONG(off)
        ZEND_PARSE_PARAMETERS_END();
 
-    PHP_STMT_GET_OBJ;
+       PHP_STMT_GET_OBJ;
        PDO_STMT_CLEAR_ERR();
 
-       if (!pdo_stmt_verify_mode(stmt, how, 0)) {
-               RETURN_FALSE;
+       if (!pdo_stmt_verify_mode(stmt, how, 1, false)) {
+               RETURN_THROWS();
        }
 
-       if (!do_fetch(stmt, return_value, how, ori, off, 0)) {
+       if (!do_fetch(stmt, return_value, how, ori, off, NULL)) {
                PDO_HANDLE_STMT_ERR();
                RETURN_FALSE;
        }
@@ -1192,9 +1211,6 @@ PHP_METHOD(PDOStatement, fetch)
 /* {{{ Fetches the next row and returns it as an object. */
 PHP_METHOD(PDOStatement, fetchObject)
 {
-       zend_long how = PDO_FETCH_CLASS;
-       zend_long ori = PDO_FETCH_ORI_NEXT;
-       zend_long off = 0;
        zend_class_entry *ce = NULL;
        zend_class_entry *old_ce;
        zval old_ctor_args, *ctor_args = NULL;
@@ -1209,10 +1225,6 @@ PHP_METHOD(PDOStatement, fetchObject)
        PHP_STMT_GET_OBJ;
        PDO_STMT_CLEAR_ERR();
 
-       if (!pdo_stmt_verify_mode(stmt, how, 0)) {
-               RETURN_FALSE;
-       }
-
        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;
@@ -1232,7 +1244,7 @@ PHP_METHOD(PDOStatement, fetchObject)
                stmt->fetch.cls.ce = zend_standard_class_def;
        }
 
-       if (!do_fetch(stmt, return_value, how, ori, off, 0)) {
+       if (!do_fetch(stmt, return_value, PDO_FETCH_CLASS, PDO_FETCH_ORI_NEXT, /* offset */ 0, NULL)) {
                PDO_HANDLE_STMT_ERR();
                RETVAL_FALSE;
        }
@@ -1270,22 +1282,23 @@ PHP_METHOD(PDOStatement, fetchColumn)
 PHP_METHOD(PDOStatement, fetchAll)
 {
        zend_long how = PDO_FETCH_USE_DEFAULT;
-       zval data, *return_all;
+       zval data, *return_all = NULL;
        zval *arg2 = NULL;
        zend_class_entry *old_ce;
        zval old_ctor_args, *ctor_args = NULL;
-       int error = 0, flags, old_arg_count;
+       bool error = false;
+       int flags, old_arg_count;
 
        ZEND_PARSE_PARAMETERS_START(0, 3)
                Z_PARAM_OPTIONAL
                Z_PARAM_LONG(how)
-               Z_PARAM_ZVAL(arg2)
-               Z_PARAM_ZVAL(ctor_args)
+               Z_PARAM_ZVAL_OR_NULL(arg2)
+               Z_PARAM_ARRAY_OR_NULL(ctor_args)
        ZEND_PARSE_PARAMETERS_END();
 
        PHP_STMT_GET_OBJ;
-       if (!pdo_stmt_verify_mode(stmt, how, 1)) {
-               RETURN_FALSE;
+       if (!pdo_stmt_verify_mode(stmt, how, 1, true)) {
+               RETURN_THROWS();
        }
 
        old_ce = stmt->fetch.cls.ce;
@@ -1294,85 +1307,88 @@ PHP_METHOD(PDOStatement, fetchAll)
 
        do_fetch_opt_finish(stmt, 0);
 
-       switch(how & ~PDO_FETCH_FLAGS) {
-       case PDO_FETCH_CLASS:
-               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) {
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array");
-                               error = 1;
-                               break;
-                       }
-                       if (Z_TYPE_P(ctor_args) != IS_ARRAY || !zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
-                               ctor_args = NULL;
+       /* TODO Would be good to reuse part of pdo_stmt_setup_fetch_mode() in some way */
+
+       switch (how & ~PDO_FETCH_FLAGS) {
+               case PDO_FETCH_CLASS:
+                       /* Figure out correct class */
+                       if (arg2) {
+                               if (Z_TYPE_P(arg2) != IS_STRING) {
+                                       zend_argument_type_error(2, "must be of type string, %s given", zend_zval_type_name(arg2));
+                                       RETURN_THROWS();
+                               }
+                               stmt->fetch.cls.ce = zend_fetch_class(Z_STR_P(arg2), ZEND_FETCH_CLASS_AUTO);
+                               if (!stmt->fetch.cls.ce) {
+                                       zend_argument_type_error(2, "must be a valid class");
+                                       RETURN_THROWS();
+                               }
+                       } else {
+                               stmt->fetch.cls.ce = zend_standard_class_def;
                        }
-                       /* no break */
-               case 2:
-                       if (ctor_args) {
+
+                       if (ctor_args && zend_hash_num_elements(Z_ARRVAL_P(ctor_args)) > 0) {
                                ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, ctor_args); /* we're not going to free these */
                        } else {
                                ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
                        }
-                       if (Z_TYPE_P(arg2) != IS_STRING) {
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid class name (should be a string)");
-                               error = 1;
-                               break;
-                       } else {
-                               stmt->fetch.cls.ce = zend_fetch_class(Z_STR_P(arg2), ZEND_FETCH_CLASS_AUTO);
-                               if (!stmt->fetch.cls.ce) {
-                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not find user-specified class");
-                                       error = 1;
-                                       break;
-                               }
-                       }
-               }
-               if (!error) {
+
                        do_fetch_class_prepare(stmt);
-               }
-               break;
-
-       case PDO_FETCH_FUNC:
-               switch (ZEND_NUM_ARGS()) {
-                       case 0:
-                       case 1:
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "no fetch function specified");
-                               error = 1;
-                               break;
-                       case 3:
-                       case 2:
-                               ZVAL_COPY_VALUE(&stmt->fetch.func.function, arg2);
-                               if (do_fetch_func_prepare(stmt) == 0) {
-                                       error = 1;
-                               }
-                               break;
-               }
-               break;
+                       break;
 
-       case PDO_FETCH_COLUMN:
-               switch(ZEND_NUM_ARGS()) {
-               case 0:
-               case 1:
-                       stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
+               case PDO_FETCH_FUNC: /* Cannot be a default fetch mode */
+                       if (ZEND_NUM_ARGS() != 2) {
+                               zend_string *func = get_active_function_or_method_name();
+                               zend_argument_count_error("%s() expects exactly 2 argument for PDO::FETCH_FUNC, %d given",
+                                       ZSTR_VAL(func), ZEND_NUM_ARGS());
+                               zend_string_release(func);
+                               RETURN_THROWS();
+                       }
+                       if (arg2 == NULL) {
+                               /* TODO use "must be of type callable" format? */
+                               zend_argument_type_error(2, "must be a callable, null given");
+                               RETURN_THROWS();
+                       }
+                       /* TODO Check it is a callable? */
+                       ZVAL_COPY_VALUE(&stmt->fetch.func.function, arg2);
+                       if (do_fetch_func_prepare(stmt) == false) {
+                               RETURN_THROWS();
+                       }
                        break;
-               case 2:
-                       convert_to_long(arg2);
-                       stmt->fetch.column = Z_LVAL_P(arg2);
+
+               case PDO_FETCH_COLUMN:
+                       if (ZEND_NUM_ARGS() > 2) {
+                               zend_string *func = get_active_function_or_method_name();
+                               zend_argument_count_error("%s() expects at most 2 argument for the fetch mode provided, %d given",
+                                       ZSTR_VAL(func), ZEND_NUM_ARGS());
+                               zend_string_release(func);
+                               RETURN_THROWS();
+                       }
+                       /* Is column index passed? */
+                       if (arg2) {
+                               // Reuse convert_to_long(arg2); ?
+                               if (Z_TYPE_P(arg2) != IS_LONG) {
+                                       zend_argument_type_error(2, "must be of type int, %s given", zend_zval_type_name(arg2));
+                                       RETURN_THROWS();
+                               }
+                               if (Z_LVAL_P(arg2) < 0) {
+                                       zend_argument_value_error(2, "must be greater than or equal to 0");
+                                       RETURN_THROWS();
+                               }
+                               stmt->fetch.column = Z_LVAL_P(arg2);
+                       } else {
+                               stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
+                       }
                        break;
-               case 3:
-                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Third parameter not allowed for PDO::FETCH_COLUMN");
-                       error = 1;
-               }
-               break;
 
-       default:
-               if (ZEND_NUM_ARGS() > 1) {
-                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Extraneous additional parameters");
-                       error = 1;
-               }
+               default:
+                       /* No support for PDO_FETCH_INTO which takes 2 args??? */
+                       if (ZEND_NUM_ARGS() > 1) {
+                               zend_string *func = get_active_function_or_method_name();
+                               zend_argument_count_error("%s() expects exactly 1 argument for the fetch mode provided, %d given",
+                               ZSTR_VAL(func), ZEND_NUM_ARGS());
+                               zend_string_release(func);
+                               RETURN_THROWS();
+                       }
        }
 
        flags = how & PDO_FETCH_FLAGS;
@@ -1382,48 +1398,42 @@ PHP_METHOD(PDOStatement, fetchAll)
                how |= stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
        }
 
-       if (!error)     {
-               PDO_STMT_CLEAR_ERR();
-               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);
-                       return_all = return_value;
-               } else {
-                       return_all = 0;
-               }
-               if (!do_fetch(stmt, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all)) {
-                       error = 2;
-               }
+       PDO_STMT_CLEAR_ERR();
+       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);
+               return_all = return_value;
+       }
+       if (!do_fetch(stmt, &data, how | flags, PDO_FETCH_ORI_NEXT, /* offset */ 0, return_all)) {
+               error = true;
        }
+
        if (!error) {
                if ((how & PDO_FETCH_GROUP)) {
-                       while (do_fetch(stmt, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all));
+                       while (do_fetch(stmt, &data, how | flags, PDO_FETCH_ORI_NEXT, /* offset */ 0, return_all));
                } else if (how == PDO_FETCH_KEY_PAIR || (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)) {
-                       while (do_fetch(stmt, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all));
+                       while (do_fetch(stmt, &data, how | flags, PDO_FETCH_ORI_NEXT, /* offset */ 0, return_all));
                } else {
                        array_init(return_value);
                        do {
                                zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &data);
-                       } while (do_fetch(stmt, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, 0));
+                       } while (do_fetch(stmt, &data, how | flags, PDO_FETCH_ORI_NEXT, /* offset */ 0, NULL));
                }
        }
 
        do_fetch_opt_finish(stmt, 0);
 
+       /* Restore defaults which were changed by PDO_FETCH_CLASS mode */
        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;
 
+       /* on no results, return an empty array */
        if (error) {
                PDO_HANDLE_STMT_ERR();
-               if (error != 2) {
-                       RETURN_FALSE;
-               } else { /* on no results, return an empty array */
-                       if (Z_TYPE_P(return_value) != IS_ARRAY) {
-                               array_init(return_value);
-                       }
-                       return;
+               if (Z_TYPE_P(return_value) != IS_ARRAY) {
+                       array_init(return_value);
                }
        }
 }
@@ -1451,12 +1461,16 @@ static void register_bound_param(INTERNAL_FUNCTION_PARAMETERS, int is_param) /*
        param.param_type = (int) param_type;
 
        if (param.name) {
+               if (ZSTR_LEN(param.name) == 0) {
+                       zend_argument_value_error(1, "cannot be empty");
+                       RETURN_THROWS();
+               }
                param.paramno = -1;
        } else if (param.paramno > 0) {
                --param.paramno; /* make it zero-based internally */
        } else {
-               pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based");
-               RETURN_FALSE;
+               zend_argument_value_error(1, "must be greater than or equal to 1");
+               RETURN_THROWS();
        }
 
        if (driver_params) {
@@ -1495,12 +1509,16 @@ PHP_METHOD(PDOStatement, bindValue)
        param.param_type = (int) param_type;
 
        if (param.name) {
+               if (ZSTR_LEN(param.name) == 0) {
+                       zend_argument_value_error(1, "cannot be empty");
+                       RETURN_THROWS();
+               }
                param.paramno = -1;
        } else if (param.paramno > 0) {
                --param.paramno; /* make it zero-based internally */
        } else {
-               pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based");
-               RETURN_FALSE;
+               zend_argument_value_error(1, "must be greater than or equal to 1");
+               RETURN_THROWS();
        }
 
        ZVAL_COPY(&param.parameter, parameter);
@@ -1557,7 +1575,7 @@ PHP_METHOD(PDOStatement, errorCode)
 PHP_METHOD(PDOStatement, errorInfo)
 {
        int error_count;
-       int error_count_diff     = 0;
+       int error_count_diff = 0;
        int error_expected_count = 3;
 
        ZEND_PARSE_PARAMETERS_NONE();
@@ -1595,8 +1613,11 @@ PHP_METHOD(PDOStatement, setAttribute)
        ZEND_PARSE_PARAMETERS_END();
 
        PHP_STMT_GET_OBJ;
+
+       /* Driver hasn't registered a function for setting attributes */
        if (!stmt->methods->set_attribute) {
-               goto fail;
+               pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes");
+               RETURN_FALSE;
        }
 
        PDO_STMT_CLEAR_ERR();
@@ -1604,12 +1625,8 @@ PHP_METHOD(PDOStatement, setAttribute)
                RETURN_TRUE;
        }
 
-fail:
-       if (!stmt->methods->set_attribute) {
-               pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes");
-       } else {
-               PDO_HANDLE_STMT_ERR();
-       }
+       /* Error while setting attribute */
+       PDO_HANDLE_STMT_ERR();
        RETURN_FALSE;
 }
 /* }}} */
@@ -1686,9 +1703,9 @@ PHP_METHOD(PDOStatement, getColumnMeta)
        ZEND_PARSE_PARAMETERS_END();
 
        PHP_STMT_GET_OBJ;
-       if(colno < 0) {
-               pdo_raise_impl_error(stmt->dbh, stmt, "42P10", "column number must be non-negative");
-               RETURN_FALSE;
+       if (colno < 0) {
+               zend_argument_value_error(1, "must be greater than or equal to 0");
+               RETURN_THROWS();
        }
 
        if (!stmt->methods->get_column_meta) {
@@ -1716,13 +1733,13 @@ PHP_METHOD(PDOStatement, getColumnMeta)
 
 /* {{{ Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
 
-int pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, zval *args, uint32_t num_args)
+bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_arg_num,
+       zval *args, uint32_t variadic_num_args)
 {
        int flags = 0;
-       zend_class_entry *cep;
-       int retval;
-
-       do_fetch_opt_finish(stmt, 1);
+       uint32_t arg1_arg_num = mode_arg_num + 1;
+       uint32_t constructor_arg_num = mode_arg_num + 2;
+       uint32_t total_num_args = mode_arg_num + variadic_num_args;
 
        switch (stmt->default_fetch_type) {
                case PDO_FETCH_INTO:
@@ -1739,12 +1756,10 @@ int pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, zval *args, uint
 
        flags = mode & PDO_FETCH_FLAGS;
 
-       if (!pdo_stmt_verify_mode(stmt, mode, 0)) {
-               PDO_STMT_CLEAR_ERR();
-               return FAILURE;
+       if (!pdo_stmt_verify_mode(stmt, mode, mode_arg_num, false)) {
+               return false;
        }
 
-       retval = FAILURE;
        switch (mode & ~PDO_FETCH_FLAGS) {
                case PDO_FETCH_USE_DEFAULT:
                case PDO_FETCH_LAZY:
@@ -1755,100 +1770,120 @@ int pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, zval *args, uint
                case PDO_FETCH_BOUND:
                case PDO_FETCH_NAMED:
                case PDO_FETCH_KEY_PAIR:
-                       if (num_args != 0) {
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments");
-                       } else {
-                               retval = SUCCESS;
+                       if (variadic_num_args != 0) {
+                               zend_string *func = get_active_function_or_method_name();
+                               zend_argument_count_error("%s() expects exactly %d arguments for the fetch mode provided, %d given",
+                                       ZSTR_VAL(func), mode_arg_num, total_num_args);
+                               zend_string_release(func);
+                               return false;
                        }
                        break;
 
                case PDO_FETCH_COLUMN:
-                       if (num_args != 1) {
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the colno argument");
-                       } else  if (Z_TYPE(args[0]) != IS_LONG) {
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "colno must be an integer");
-                       } else {
-                               stmt->fetch.column = Z_LVAL(args[0]);
-                               retval = SUCCESS;
-                       }
+                       if (variadic_num_args != 1) {
+                               zend_string *func = get_active_function_or_method_name();
+                               zend_argument_count_error("%s() expects exactly %d arguments for the fetch mode provided, %d given",
+                                       ZSTR_VAL(func), arg1_arg_num, total_num_args);
+                               zend_string_release(func);
+                               return false;
+                       }
+                       if (Z_TYPE(args[0]) != IS_LONG) {
+                               zend_argument_type_error(arg1_arg_num, "must be of type int, %s given", zend_zval_type_name(&args[0]));
+                               return false;
+                       }
+                       if (Z_LVAL(args[0]) < 0) {
+                               zend_argument_value_error(arg1_arg_num, "must be greater than or equal to 0");
+                               return false;
+                       }
+                       stmt->fetch.column = Z_LVAL(args[0]);
                        break;
 
-               case PDO_FETCH_CLASS:
+               case PDO_FETCH_CLASS: {
+                       HashTable *constructor_args = NULL;
+                       /* Undef constructor arguments */
+                       ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
                        /* Gets its class name from 1st column */
                        if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
-                               if (num_args != 0) {
-                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments");
-                               } else {
-                                       stmt->fetch.cls.ce = NULL;
-                                       retval = SUCCESS;
+                               if (variadic_num_args != 0) {
+                                       zend_string *func = get_active_function_or_method_name();
+                                       zend_argument_count_error("%s() expects exactly %d arguments for the fetch mode provided, %d given",
+                                               ZSTR_VAL(func), mode_arg_num, total_num_args);
+                                       zend_string_release(func);
+                                       return false;
                                }
+                               stmt->fetch.cls.ce = NULL;
                        } else {
-                               if (num_args < 1) {
-                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the classname argument");
-                               } else if (num_args > 2) {
-                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "too many arguments");
-                               } else if (Z_TYPE(args[0]) != IS_STRING) {
-                                       pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "classname must be a string");
-                               } else {
-                                       cep = zend_lookup_class(Z_STR(args[0]));
-                                       if (cep) {
-                                               retval = SUCCESS;
-                                               stmt->fetch.cls.ce = cep;
-                                       }
+                               zend_class_entry *cep;
+                               if (variadic_num_args == 0) {
+                                       zend_string *func = get_active_function_or_method_name();
+                                       zend_argument_count_error("%s() expects at least %d arguments for the fetch mode provided, %d given",
+                                               ZSTR_VAL(func), arg1_arg_num, total_num_args);
+                                       zend_string_release(func);
+                                       return false;
                                }
-                       }
-
-                       if (SUCCESS == retval) {
-                               ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
-                               if (num_args == 2) {
+                               /* constructor_arguments can be null/not passed */
+                               if (variadic_num_args > 2) {
+                                       zend_string *func = get_active_function_or_method_name();
+                                       zend_argument_count_error("%s() expects at most %d arguments for the fetch mode provided, %d given",
+                                               ZSTR_VAL(func), constructor_arg_num, total_num_args);
+                                       zend_string_release(func);
+                                       return false;
+                               }
+                               if (Z_TYPE(args[0]) != IS_STRING) {
+                                       zend_argument_type_error(arg1_arg_num, "must be of type string, %s given", zend_zval_type_name(&args[0]));
+                                       return false;
+                               }
+                               cep = zend_lookup_class(Z_STR(args[0]));
+                               if (!cep) {
+                                       zend_argument_type_error(arg1_arg_num, "must be a valid class");
+                                       return false;
+                               }
+                               /* Verify constructor_args (args[1]) is ?array */
+                               /* TODO: Improve logic? */
+                               if (variadic_num_args == 2) {
                                        if (Z_TYPE(args[1]) != IS_NULL && Z_TYPE(args[1]) != IS_ARRAY) {
-                                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array");
-                                               retval = FAILURE;
-                                       } else if (Z_TYPE(args[1]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL(args[1]))) {
-                                               ZVAL_ARR(&stmt->fetch.cls.ctor_args, zend_array_dup(Z_ARRVAL(args[1])));
+                                               zend_argument_type_error(constructor_arg_num, "must be of type ?array, %s given",
+                                                       zend_zval_type_name(&args[1]));
+                                               return false;
+                                       }
+                                       if (Z_TYPE(args[1]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL(args[1]))) {
+                                               constructor_args = Z_ARRVAL(args[1]);
                                        }
                                }
+                               stmt->fetch.cls.ce = cep;
 
-                               if (SUCCESS == retval) {
-                                       do_fetch_class_prepare(stmt);
+                               /* If constructor arguments are present and not empty */
+                               if (constructor_args) {
+                                       ZVAL_ARR(&stmt->fetch.cls.ctor_args, zend_array_dup(constructor_args));
                                }
                        }
 
+                       do_fetch_class_prepare(stmt);
                        break;
-
+               }
                case PDO_FETCH_INTO:
-                       if (num_args != 1) {
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the object parameter");
-                       } else if (Z_TYPE(args[0]) != IS_OBJECT) {
-                               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "object must be an object");
-                       } else {
-                               retval = SUCCESS;
+                       if (total_num_args != arg1_arg_num) {
+                               zend_string *func = get_active_function_or_method_name();
+                               zend_argument_count_error("%s() expects exactly %d arguments for the fetch mode provided, %d given",
+                                       ZSTR_VAL(func), arg1_arg_num, total_num_args);
+                               zend_string_release(func);
+                               return false;
                        }
-
-                       if (SUCCESS == retval) {
-                               ZVAL_COPY(&stmt->fetch.into, &args[0]);
+                       if (Z_TYPE(args[0]) != IS_OBJECT) {
+                               zend_argument_type_error(arg1_arg_num, "must be of type object, %s given", zend_zval_type_name(&args[0]));
+                               return false;
                        }
 
+                       ZVAL_COPY(&stmt->fetch.into, &args[0]);
                        break;
-
                default:
-                       pdo_raise_impl_error(stmt->dbh, stmt, "22003", "Invalid fetch mode specified");
+                       zend_argument_value_error(mode_arg_num, "must be one of the PDO::FETCH_* constants");
+                       return false;
        }
 
-       if (SUCCESS == retval) {
-               stmt->default_fetch_type = mode;
-       }
-
-       /*
-        * PDO error (if any) has already been raised at this point.
-        *
-        * The error_code is cleared, otherwise the caller will read the
-        * last error message from the driver.
-        *
-        */
-       PDO_STMT_CLEAR_ERR();
+       stmt->default_fetch_type = mode;
 
-       return retval;
+       return true;
 }
 
 PHP_METHOD(PDOStatement, setFetchMode)
@@ -1862,13 +1897,21 @@ PHP_METHOD(PDOStatement, setFetchMode)
        }
 
        PHP_STMT_GET_OBJ;
-       RETVAL_BOOL(pdo_stmt_setup_fetch_mode(stmt, fetch_mode, args, num_args) == SUCCESS);
+
+       do_fetch_opt_finish(stmt, 1);
+
+       if (!pdo_stmt_setup_fetch_mode(stmt, fetch_mode, 1, args, num_args)) {
+               RETURN_THROWS();
+       }
+
+       // TODO Void return?
+       RETURN_TRUE;
 }
 /* }}} */
 
 /* {{{ Advances to the next rowset in a multi-rowset statement handle. Returns true if it succeeded, false otherwise */
 
-static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt)
+static bool pdo_stmt_do_next_rowset(pdo_stmt_t *stmt)
 {
        /* un-describe */
        if (stmt->columns) {
@@ -1963,6 +2006,7 @@ PHP_METHOD(PDOStatement, debugDumpParams)
        ZEND_PARSE_PARAMETERS_NONE();
 
        PHP_STMT_GET_OBJ;
+
        if (out == NULL) {
                RETURN_FALSE;
        }
@@ -2024,10 +2068,8 @@ PHP_METHOD(PDOStatement, getIterator)
 /* {{{ overloaded handlers for PDOStatement class */
 static zval *dbstmt_prop_write(zend_object *object, zend_string *name, zval *value, void **cache_slot)
 {
-       pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(object);
-
        if (strcmp(ZSTR_VAL(name), "queryString") == 0) {
-               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only");
+               zend_throw_error(NULL, "Property queryString is read only");
                return value;
        } else {
                return zend_std_write_property(object, name, value, cache_slot);
@@ -2036,10 +2078,8 @@ static zval *dbstmt_prop_write(zend_object *object, zend_string *name, zval *val
 
 static void dbstmt_prop_delete(zend_object *object, zend_string *name, void **cache_slot)
 {
-       pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(object);
-
        if (strcmp(ZSTR_VAL(name), "queryString") == 0) {
-               pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only");
+               zend_throw_error(NULL, "Property queryString is read only");
        } else {
                zend_std_unset_property(object, name, cache_slot);
        }
@@ -2225,7 +2265,7 @@ static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter)
        }
 
        if (!do_fetch(stmt, &I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
-                       PDO_FETCH_ORI_NEXT, 0, 0)) {
+                       PDO_FETCH_ORI_NEXT, /* offset */ 0, NULL)) {
 
                PDO_HANDLE_STMT_ERR();
                I->key = (zend_ulong)-1;
@@ -2265,7 +2305,7 @@ zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int
        ZVAL_OBJ(&I->iter.data, Z_OBJ_P(object));
 
        if (!do_fetch(stmt, &I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
-                       PDO_FETCH_ORI_NEXT, 0, 0)) {
+                       PDO_FETCH_ORI_NEXT, /* offset */ 0, NULL)) {
                PDO_HANDLE_STMT_ERR();
                I->key = (zend_ulong)-1;
                ZVAL_UNDEF(&I->fetch_ahead);
@@ -2296,7 +2336,7 @@ static zval *row_prop_read(zend_object *object, zend_string *name, int type, voi
                         * numbers */
                        for (colno = 0; colno < stmt->column_count; colno++) {
                                if (ZSTR_LEN(stmt->columns[colno].name) == ZSTR_LEN(name) &&
-                                   strncmp(ZSTR_VAL(stmt->columns[colno].name), ZSTR_VAL(name), ZSTR_LEN(name)) == 0) {
+                                       strncmp(ZSTR_VAL(stmt->columns[colno].name), ZSTR_VAL(name), ZSTR_LEN(name)) == 0) {
                                        fetch_value(stmt, rv, colno, NULL);
                                        return rv;
                                }
@@ -2338,7 +2378,7 @@ static zval *row_dim_read(zend_object *object, zval *member, int type, zval *rv)
                         * numbers */
                        for (colno = 0; colno < stmt->column_count; colno++) {
                                if (ZSTR_LEN(stmt->columns[colno].name) == Z_STRLEN_P(member) &&
-                                   strncmp(ZSTR_VAL(stmt->columns[colno].name), Z_STRVAL_P(member), Z_STRLEN_P(member)) == 0) {
+                                       strncmp(ZSTR_VAL(stmt->columns[colno].name), Z_STRVAL_P(member), Z_STRLEN_P(member)) == 0) {
                                        fetch_value(stmt, rv, colno, NULL);
                                        return rv;
                                }
@@ -2380,7 +2420,7 @@ static int row_prop_exists(zend_object *object, zend_string *name, int check_emp
                 * numbers */
                for (colno = 0; colno < stmt->column_count; colno++) {
                        if (ZSTR_LEN(stmt->columns[colno].name) == ZSTR_LEN(name) &&
-                           strncmp(ZSTR_VAL(stmt->columns[colno].name), ZSTR_VAL(name), ZSTR_LEN(name)) == 0) {
+                               strncmp(ZSTR_VAL(stmt->columns[colno].name), ZSTR_VAL(name), ZSTR_LEN(name)) == 0) {
                                        int res;
                                        zval val;
 
@@ -2420,7 +2460,7 @@ static int row_dim_exists(zend_object *object, zval *member, int check_empty)
                 * numbers */
                for (colno = 0; colno < stmt->column_count; colno++) {
                        if (ZSTR_LEN(stmt->columns[colno].name) == Z_STRLEN_P(member) &&
-                           strncmp(ZSTR_VAL(stmt->columns[colno].name), Z_STRVAL_P(member), Z_STRLEN_P(member)) == 0) {
+                               strncmp(ZSTR_VAL(stmt->columns[colno].name), Z_STRVAL_P(member), Z_STRLEN_P(member)) == 0) {
                                        int res;
                                        zval val;
 
index b280f73ffdb3d32db30a005cd0f06d079357d067..2732c8a71da565ecc1c257f69ae3af863fdd2837 100644 (file)
@@ -16,16 +16,16 @@ class PDOStatement implements IteratorAggregate
     /** @return bool */
     public function closeCursor() {}
 
-    /** @return int|false */
+    /** @return int */
     public function columnCount() {}
 
     /** @return bool|null */
     public function debugDumpParams() {}
 
-    /** @return string|false|null */
+    /** @return string|null */
     public function errorCode() {}
 
-    /** @return array|false */
+    /** @return array */
     public function errorInfo() {}
 
     /** @return bool */
@@ -34,8 +34,8 @@ class PDOStatement implements IteratorAggregate
     /** @return mixed */
     public function fetch(int $fetch_style = PDO::FETCH_BOTH, int $cursor_orientation = PDO::FETCH_ORI_NEXT, int $cursor_offset = 0) {}
 
-    /** @return array|false */
-    public function fetchAll(int $fetch_style = PDO::FETCH_BOTH, mixed ...$fetch_args) {}
+    /** @return array */
+    public function fetchAll(int $fetch_style = PDO::FETCH_BOTH, mixed ...$fetch_mode_args) {}
 
     /** @return mixed */
     public function fetchColumn(int $column_number = 0) {}
@@ -52,14 +52,14 @@ class PDOStatement implements IteratorAggregate
     /** @return bool */
     public function nextRowset() {}
 
-    /** @return int|false */
+    /** @return int */
     public function rowCount() {}
 
     /** @return bool */
     public function setAttribute(int $attribute, mixed $value) {}
 
     /** @return bool */
-    public function setFetchMode(int $mode, mixed ...$params) {}
+    public function setFetchMode(int $mode, mixed ...$fetch_mode_args) {}
 
     public function getIterator(): Iterator {}
 }
index 116449ad3aefec8dcf8b3a7bab45d9fde0d5d134..157507a852ded8673858492ecc89efe3f30028e6 100644 (file)
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: a35e66ccff5e569f07ae8372e661e005943dfbc7 */
+ * Stub hash: c12bc1c5d1e3dbd8cce67e50c974b20ec5564e67 */
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDOStatement_bindColumn, 0, 0, 2)
        ZEND_ARG_TYPE_MASK(0, column, MAY_BE_STRING|MAY_BE_LONG, NULL)
@@ -46,7 +46,7 @@ ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDOStatement_fetchAll, 0, 0, 0)
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, fetch_style, IS_LONG, 0, "PDO::FETCH_BOTH")
-       ZEND_ARG_VARIADIC_TYPE_INFO(0, fetch_args, IS_MIXED, 0)
+       ZEND_ARG_VARIADIC_TYPE_INFO(0, fetch_mode_args, IS_MIXED, 0)
 ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDOStatement_fetchColumn, 0, 0, 0)
@@ -77,7 +77,7 @@ ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDOStatement_setFetchMode, 0, 0, 1)
        ZEND_ARG_TYPE_INFO(0, mode, IS_LONG, 0)
-       ZEND_ARG_VARIADIC_TYPE_INFO(0, params, IS_MIXED, 0)
+       ZEND_ARG_VARIADIC_TYPE_INFO(0, fetch_mode_args, IS_MIXED, 0)
 ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_PDOStatement_getIterator, 0, 0, Iterator, 0)
index 9d9e73915dfc6b2ac49a9f6ef865496b224b5f66..89cd22c8e8baf4f2b50df65d395af571983653a8 100644 (file)
@@ -53,11 +53,11 @@ PHP_MINFO_FUNCTION(pdo);
 #define REGISTER_PDO_CLASS_CONST_STRING(const_name, value) \
        zend_declare_class_constant_stringl(php_pdo_get_dbh_ce(), const_name, sizeof(const_name)-1, value, sizeof(value)-1);
 
-#define PDO_CONSTRUCT_CHECK    \
-       if (!dbh->driver) {     \
-               pdo_raise_impl_error(dbh, NULL, "00000", "PDO constructor was not called");     \
-               return; \
-       }       \
+#define PDO_CONSTRUCT_CHECK \
+       if (!dbh->driver) { \
+               zend_throw_error(NULL, "PDO object is not initialized, constructor was not called"); \
+               RETURN_THROWS(); \
+       } \
 
 
 #endif /* PHP_PDO_H */
index 7fe3bfc85023f6c3cb29ed65c20299201fb599df..7f992a5fd0de2aebe54177662cf77d2ca16d9925 100644 (file)
@@ -40,7 +40,8 @@ void pdo_dbstmt_free_storage(zend_object *std);
 zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref);
 extern zend_object_handlers pdo_dbstmt_object_handlers;
 int pdo_stmt_describe_columns(pdo_stmt_t *stmt);
-int pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long fetch_mode, zval *args, uint32_t num_args);
+bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_arg_num,
+       zval *args, uint32_t variadic_num_args);
 
 extern zend_object *pdo_row_new(zend_class_entry *ce);
 extern const zend_function_entry pdo_row_functions[];
index 0e1116d58863ebebdb40d123b01ebd9214666125..b5601eed41c47e56bca344c13a00b3e3984da278 100644 (file)
@@ -2,51 +2,46 @@
 PDO Common: Bug #44159 (Crash: $pdo->setAttribute(PDO::STATEMENT_ATTR_CLASS, NULL))
 --SKIPIF--
 <?php
-if (!extension_loaded('pdo')) die('skip PDO not available');
-try {
-    $pdo = new PDO("sqlite:".__DIR__."/foo.db");
-} catch (Exception $e) {
-    die("skip PDP_SQLITE not available");
-}
+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
-$pdo = new PDO("sqlite:".__DIR__."/foo.db");
+if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
+require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
+$pdo = PDOTest::factory();
 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
 
-$attrs = array(PDO::ATTR_STATEMENT_CLASS, PDO::ATTR_STRINGIFY_FETCHES, PDO::NULL_TO_STRING);
+$attrs = array(PDO::ATTR_STATEMENT_CLASS, PDO::ATTR_STRINGIFY_FETCHES);
 
 foreach ($attrs as $attr) {
-    var_dump($pdo->setAttribute($attr, NULL));
-    var_dump($pdo->setAttribute($attr, 1));
-    var_dump($pdo->setAttribute($attr, 'nonsense'));
+    try {
+        var_dump($pdo->setAttribute($attr, NULL));
+    } catch (\Error $e) {
+        echo  get_class($e), ': ', $e->getMessage(), \PHP_EOL;
+    }
+    try {
+        var_dump($pdo->setAttribute($attr, 1));
+    } catch (\Error $e) {
+        echo  get_class($e), ': ', $e->getMessage(), \PHP_EOL;
+    }
+    try {
+        var_dump($pdo->setAttribute($attr, 'nonsense'));
+    } catch (\Error $e) {
+        echo  get_class($e), ': ', $e->getMessage(), \PHP_EOL;
+    }
 }
 
 @unlink(__DIR__."/foo.db");
 
 ?>
---EXPECTF--
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); the classname must be a string specifying an existing class in %s on line %d
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
-bool(false)
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); the classname must be a string specifying an existing class in %s on line %d
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
-bool(false)
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); the classname must be a string specifying an existing class in %s on line %d
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
-bool(false)
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: attribute value must be an integer in %s on line %d
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
-bool(false)
-bool(true)
-bool(true)
-bool(true)
+--EXPECT--
+TypeError: PDO::ATTR_STATEMENT_CLASS value must be of type array, null given
+TypeError: PDO::ATTR_STATEMENT_CLASS value must be of type array, int given
+TypeError: PDO::ATTR_STATEMENT_CLASS value must be of type array, string given
+TypeError: Attribute value must be of type int for selected attribute, null given
 bool(true)
 bool(true)
index df98f332fe1882dcd18f1b73bbec6228ee49c778..0baa7973e5a705a83da4446e526f69af834e866b 100644 (file)
@@ -19,8 +19,12 @@ $db->exec("INSERT INTO test VALUES (1)");
 
 
 // Bug entry [2] -- 1 is PDO::FETCH_LAZY
-$stmt = $db->query("SELECT * FROM test", PDO::FETCH_LAZY, 0, 0);
-var_dump($stmt);
+try {
+    $stmt = $db->query("SELECT * FROM test", PDO::FETCH_LAZY, 0, []);
+    var_dump($stmt);
+} catch (\TypeError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
 
 // Bug entry [3]
@@ -31,39 +35,46 @@ try {
 }
 
 // Bug entry [4]
-$stmt = $db->query("SELECT * FROM test", PDO::FETCH_CLASS, 0, 0, 0);
-var_dump($stmt);
+try {
+    $stmt = $db->query("SELECT * FROM test", PDO::FETCH_CLASS, 0, 0, 0);
+    var_dump($stmt);
+} catch (\ArgumentCountError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
 
 // Bug entry [5]
-$stmt = $db->query("SELECT * FROM test", PDO::FETCH_INTO);
-var_dump($stmt);
+try {
+    $stmt = $db->query("SELECT * FROM test", PDO::FETCH_INTO);
+    var_dump($stmt);
+} catch (\ArgumentCountError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
 
 // Bug entry [6]
-$stmt = $db->query("SELECT * FROM test", PDO::FETCH_COLUMN);
-var_dump($stmt);
+try {
+    $stmt = $db->query("SELECT * FROM test", PDO::FETCH_COLUMN);
+    var_dump($stmt);
+} catch (\ArgumentCountError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
 
 // Bug entry [7]
-$stmt = $db->query("SELECT * FROM test", PDO::FETCH_CLASS);
-var_dump($stmt);
+try {
+    $stmt = $db->query("SELECT * FROM test", PDO::FETCH_CLASS);
+    var_dump($stmt);
+} catch (\ArgumentCountError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
 
 ?>
---EXPECTF--
-Warning: PDO::query(): SQLSTATE[HY000]: General error: fetch mode doesn't allow any extra arguments in %s
-bool(false)
+--EXPECT--
+PDO::query() expects exactly 2 arguments for the fetch mode provided, 4 given
 PDO::query(): Argument #2 ($fetch_mode) must be of type ?int, string given
-
-Warning: PDO::query(): SQLSTATE[HY000]: General error: too many arguments in %s
-bool(false)
-
-Warning: PDO::query(): SQLSTATE[HY000]: General error: fetch mode requires the object parameter in %s
-bool(false)
-
-Warning: PDO::query(): SQLSTATE[HY000]: General error: fetch mode requires the colno argument in %s
-bool(false)
-
-Warning: PDO::query(): SQLSTATE[HY000]: General error: fetch mode requires the classname argument in %s
-bool(false)
+PDO::query() expects at most 4 arguments for the fetch mode provided, 5 given
+PDO::query() expects exactly 3 arguments for the fetch mode provided, 2 given
+PDO::query() expects exactly 3 arguments for the fetch mode provided, 2 given
+PDO::query() expects at least 3 arguments for the fetch mode provided, 2 given
index 3ff2d090a85800c41790ec308cfd68267e1a311e..a2887f35dbf8967ac5f9812f0de5e5a50adbe118 100644 (file)
@@ -32,14 +32,19 @@ switch ($conn->getAttribute(PDO::ATTR_DRIVER_NAME)) {
 
 $stmt = $conn->prepare($query);
 
-var_dump(fetchColumn($stmt, -1));
+try {
+    var_dump(fetchColumn($stmt, -1));
+} catch (\ValueError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 var_dump(fetchColumn($stmt, 0));
-var_dump(fetchColumn($stmt, 1));
+try {
+    var_dump(fetchColumn($stmt, 1));
+} catch (\ValueError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 ?>
---EXPECTF--
-Warning: PDOStatement::fetchColumn(): SQLSTATE[HY000]: General error: Invalid column index in %s
-bool(false)
+--EXPECT--
+Column index must be greater than or equal to 0
 string(1) "1"
-
-Warning: PDOStatement::fetchColumn(): SQLSTATE[HY000]: General error: Invalid column index in %s
-bool(false)
+Invalid column index
diff --git a/ext/pdo/tests/pdo_quote_empty_string.phpt b/ext/pdo/tests/pdo_quote_empty_string.phpt
new file mode 100644 (file)
index 0000000..214d101
--- /dev/null
@@ -0,0 +1,31 @@
+--TEST--
+PDO::quote() must accept empty string for drivers which support this feature
+--SKIPIF--
+<?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='.__DIR__ . '/../../pdo/tests/');
+require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
+
+$pdo = PDOTest::factory();
+$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+try {
+    $result = $pdo->quote('');
+    if (!is_string($result)) {
+        var_dump($result);
+    }
+} catch (\PDOException) {
+    // Do nothing as quoting is not supported with this driver
+}
+?>
+DONE
+
+--EXPECT--
+DONE
index 0d6cee356ebbdb07b05628e27c10fefd9c18e9f7..d6ebd87f603275793014d8fb95b5fb99a88b8a42 100644 (file)
@@ -14,29 +14,27 @@ error_reporting=E_ALL
     require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
     $db = MySQLPDOTest::factory();
 
-    $valid = array(PDO::ERRMODE_SILENT, PDO::ERRMODE_WARNING, PDO::ERRMODE_EXCEPTION);
-    do {
-        $invalid = mt_rand(-1000, 1000);
-    } while (in_array($invalid, $valid));
-
-
-    $tmp = array();
-    if (false != @$db->setAttribute(PDO::ATTR_ERRMODE, $tmp))
-        printf("[001] Maybe PDO could indicate that this is not a proper way of setting the ERRMODE...\n");
-
-    $tmp = new stdClass();
-    $ret = @$db->setAttribute(PDO::ATTR_ERRMODE, $tmp);
-    if (false != $ret)
-        printf("[002] Maybe PDO could indicate that this is not a proper way of setting the ERRMODE...%s\n",
-            var_export($ret, true));
-
-    $ret = @$db->setAttribute(PDO::ATTR_ERRMODE, 'pdo');
-    if (false != $ret)
-        printf("[003] Maybe PDO could indicate that this is not a proper way of setting the ERRMODE...%s\n",
-            var_export($ret, true));
-
-    if (false != @$db->setAttribute(PDO::ATTR_ERRMODE, $invalid))
-        printf("[004] Invalid ERRMODE should be rejected\n");
+    try {
+        $db->setAttribute(PDO::ATTR_ERRMODE, []);
+    } catch (\Error $e) {
+        echo get_class($e), ': ', $e->getMessage(), \PHP_EOL;
+    }
+    try {
+        $db->setAttribute(PDO::ATTR_ERRMODE, new stdClass());
+    } catch (\Error $e) {
+        echo get_class($e), ': ', $e->getMessage(), \PHP_EOL;
+    }
+    try {
+        /* This currently passes */
+        $db->setAttribute(PDO::ATTR_ERRMODE, 'pdo');
+    } catch (\Error $e) {
+        echo get_class($e), ': ', $e->getMessage(), \PHP_EOL;
+    }
+    try {
+        $db->setAttribute(PDO::ATTR_ERRMODE, 1000);
+    } catch (\Error $e) {
+        echo get_class($e), ': ', $e->getMessage(), \PHP_EOL;
+    }
 
     $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
     // no message for any PDO call but...
@@ -160,7 +158,9 @@ error_reporting=E_ALL
     print "done!\n";
 ?>
 --EXPECTF--
-[003] Maybe PDO could indicate that this is not a proper way of setting the ERRMODE...true
+TypeError: Attribute value must be of type int for selected attribute, array given
+TypeError: Attribute value must be of type int for selected attribute, stdClass given
+ValueError: Error mode must be one of the PDO::ERRMODE_* constants
 
 Warning: PDO::query(): SQLSTATE[42000]: Syntax error or access violation: %d You have an error in your SQL syntax; check the manual that corresponds to your %s server version for the right syntax to use near '%s' at line %d in %s on line %d
 
index 694a0394415ca41e90ed04e84402c660c405f0a9..6d922a037def86c80266e7064507e955b9bd414a 100644 (file)
@@ -12,16 +12,22 @@ MySQLPDOTest::skip();
     $db = MySQLPDOTest::factory();
     MySQLPDOTest::createTestTable($db);
 
-    $tmp = array();
-    if (false !== @$db->setAttribute(PDO::ATTR_ORACLE_NULLS, $tmp))
-        printf("[001] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...\n");
-
-    $tmp = new stdClass();
-    if (false !== @$db->setAttribute(PDO::ATTR_ORACLE_NULLS, $tmp));
-        printf("[002] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...\n");
-
-    if (false !== @$db->setAttribute(PDO::ATTR_ORACLE_NULLS, 'pdo'))
-        printf("[003] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...\n");
+    try {
+        $db->setAttribute(PDO::ATTR_ORACLE_NULLS, []);
+    } catch (\TypeError $e) {
+        echo $e->getMessage(), \PHP_EOL;
+    }
+    try {
+        $db->setAttribute(PDO::ATTR_ORACLE_NULLS, new stdClass());
+    } catch (\TypeError $e) {
+        echo $e->getMessage(), \PHP_EOL;
+    }
+    try {
+        /* Currently passes... */
+        $db->setAttribute(PDO::ATTR_ORACLE_NULLS, 'pdo');
+    } catch (\TypeError $e) {
+        echo $e->getMessage(), \PHP_EOL;
+    }
 
     $db->setAttribute(PDO::ATTR_ORACLE_NULLS, 1);
     $stmt = $db->query("SELECT NULL AS z, '' AS a, ' ' AS b, TRIM(' ') as c, ' d' AS d, '" . chr(0) . " e' AS e");
@@ -82,8 +88,8 @@ MySQLPDOTest::skip();
     print "done!";
 ?>
 --EXPECTF--
-[002] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...
-[003] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...
+Attribute value must be of type int for selected attribute, array given
+Attribute value must be of type int for selected attribute, stdClass given
 array(1) {
   [0]=>
   array(6) {
index 66df0cda459a124a0bb50194b14734b7c094fb65..6d536f9deddd215fc0a7fd0275d8b3af752267cb 100644 (file)
@@ -16,15 +16,22 @@ $db = MySQLPDOTest::factory();
     $default =  $db->getAttribute(PDO::ATTR_STATEMENT_CLASS);
     var_dump($default);
 
-    if (false !== ($tmp = @$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, 'foo')))
-        printf("[002] Expecting boolean/false got %s\n", var_export($tmp, true));
-
-    if (false !== ($tmp = @$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('classname'))))
-        printf("[003] Expecting boolean/false got %s\n", var_export($tmp, true));
-
+    try {
+        $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, 'foo');
+    } catch (\TypeError $e) {
+        echo $e->getMessage(), \PHP_EOL;
+    }
+    try {
+        $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['classname']);
+    } catch (\TypeError $e) {
+        echo $e->getMessage(), \PHP_EOL;
+    }
     // unknown class
-    if (false !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('classname', array()))))
-        printf("[004] Expecting boolean/false got %s\n", var_export($tmp, true));
+    try {
+        $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['classname', []]);
+    } catch (\TypeError $e) {
+        echo $e->getMessage(), \PHP_EOL;
+    }
 
     // class not derived from PDOStatement
     class myclass {
@@ -32,8 +39,12 @@ $db = MySQLPDOTest::factory();
             printf("myclass\n");
         }
     }
-    if (false !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('myclass', array()))))
-        printf("[005] Expecting boolean/false got %s\n", var_export($tmp, true));
+
+    try {
+        $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['myclass', []]);
+    } catch (\TypeError $e) {
+        echo $e->getMessage(), \PHP_EOL;
+    }
 
     // public constructor not allowed
     class mystatement extends PDOStatement {
@@ -42,8 +53,13 @@ $db = MySQLPDOTest::factory();
         }
     }
 
-    if (false !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('mystatement', array()))))
-        printf("[006] Expecting boolean/false got %s\n", var_export($tmp, true));
+    try {
+        if (false !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['mystatement', []])))
+            printf("[006] Expecting boolean/false got %s\n", var_export($tmp, true));
+    } catch (\Error $e) {
+        echo get_class($e), ': ', $e->getMessage(), \PHP_EOL;
+    }
+
 
     // ... but a public destructor is allowed
     class mystatement2 extends PDOStatement {
@@ -109,18 +125,11 @@ array(1) {
   [0]=>
   string(12) "PDOStatement"
 }
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); the classname must be a string specifying an existing class in %s on line %d
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: user-supplied statement class must be derived from PDOStatement in %s on line %d
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: user-supplied statement class cannot have a public constructor in %s on line %d
-
-Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
+PDO::ATTR_STATEMENT_CLASS value must be of type array, string given
+PDO::ATTR_STATEMENT_CLASS class must be a valid class
+PDO::ATTR_STATEMENT_CLASS class must be a valid class
+PDO::ATTR_STATEMENT_CLASS class must be derived from PDOStatement
+TypeError: User-supplied statement class cannot have a public constructor
 array(2) {
   [0]=>
   string(12) "mystatement4"
index 6fe2ff20ba61626148252b3ecc6a38f051057b4b..6afd57420f9f48b92189c629fce0f81f760cd980 100644 (file)
@@ -88,9 +88,11 @@ $db = MySQLPDOTest::factory();
         if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
             printf("[002] Unable to switch to emulated prepared statements, test will fail\n");
 
-        // TODO - that's PDO - you can prepare empty statements!
-        prepex(3, $db, '',
-            array(), array('execute' => array('sqlstate' => '42000')));
+        try {
+            prepex(3, $db, '', [], ['execute' => ['sqlstate' => '42000']]);
+        } catch (\ValueError $e) {
+            echo $e->getMessage(), \PHP_EOL;
+        }
 
         // lets be fair and do the most simple SELECT first
         $stmt = prepex(4, $db, 'SELECT 1 as "one"');
@@ -328,6 +330,7 @@ $db->exec('DROP TABLE IF EXISTS test');
 PDO's PS parser has some problems with invalid SQL and crashes from time to time
 (check with valgrind...)
 --EXPECT--
+PDO::prepare(): Argument #1 ($statement) cannot be empty
 array(1) {
   ["one"]=>
   string(1) "1"
index 5ea3e94c1e138d28fa69a075c76245601333bbea..839fc43c15db4d001887618d44c31abeac7724ef 100644 (file)
@@ -99,9 +99,11 @@ $db = MySQLPDOTest::factory();
         if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
             printf("[002] Unable to turn off emulated prepared statements\n");
 
-        // TODO - that's PDO - you can prepare empty statements!
-        prepex(3, $db, '',
-            array(), array('prepare' => array('sqlstate' => '42000')));
+        try {
+            prepex(3, $db, '', [], ['prepare' => ['sqlstate' => '42000']]);
+        } catch (\ValueError $e) {
+            echo $e->getMessage(), \PHP_EOL;
+        }
 
         // lets be fair and do the most simple SELECT first
         $stmt = prepex(4, $db, 'SELECT 1 as "one"');
@@ -342,6 +344,7 @@ $db = MySQLPDOTest::factory();
 $db->exec('DROP TABLE IF EXISTS test');
 ?>
 --EXPECT--
+PDO::prepare(): Argument #1 ($statement) cannot be empty
 array(1) {
   [0]=>
   array(1) {
index 44f0a0ebb18d28d0ffeec2bbf575c30375ed3362..b5b0275f04f7d905f51082042ff6933c7a6ffbc6 100644 (file)
@@ -32,8 +32,11 @@ try {
     $stmt->execute();
 
     // invalid offset
-    if (false !== ($tmp = @$stmt->getColumnMeta(-1)))
-        printf("[004] Expecting false got %s\n", var_export($tmp, true));
+    try {
+        $stmt->getColumnMeta(-1);
+    } catch (\ValueError $e) {
+        echo $e->getMessage(), \PHP_EOL;
+    }
 
     $emulated =  $stmt->getColumnMeta(0);
 
@@ -299,5 +302,6 @@ $db->exec('DROP TABLE IF EXISTS test');
 print "done!";
 ?>
 --EXPECT--
+PDOStatement::getColumnMeta(): Argument #1 ($column) must be greater than or equal to 0
 Testing native PS...
 done!
diff --git a/ext/pdo_sqlite/tests/bug_44159_sqlite_version.phpt b/ext/pdo_sqlite/tests/bug_44159_sqlite_version.phpt
new file mode 100644 (file)
index 0000000..fc30f1d
--- /dev/null
@@ -0,0 +1,22 @@
+--TEST--
+PDO Common: Bug #44159: SQLite variant
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo_sqlite')) die('skip PDO SQLite not available');
+?>
+--FILE--
+<?php
+$pdo = new PDO("sqlite:".__DIR__."/foo.db");
+$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
+
+var_dump($pdo->setAttribute(PDO::NULL_TO_STRING, NULL));
+var_dump($pdo->setAttribute(PDO::NULL_TO_STRING, 1));
+var_dump($pdo->setAttribute(PDO::NULL_TO_STRING, 'nonsense'));
+
+@unlink(__DIR__."/foo.db");
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
index 4600b7935be09ffe3851328e64e62c78f1781e12..814a01a6472d63cbd8afbe8d58dc0ee6aff45842 100644 (file)
@@ -20,20 +20,40 @@ $st->fetchAll(PDO::FETCH_FUNC, function($x, $y) use ($st) { var_dump($st); print
 $st = $db->query('SELECT name FROM testing');
 var_dump($st->fetchAll(PDO::FETCH_FUNC, 'strtoupper'));
 
-$st = $db->query('SELECT * FROM testing');
-var_dump($st->fetchAll(PDO::FETCH_FUNC, 'nothing'));
+try {
+    $st = $db->query('SELECT * FROM testing');
+    var_dump($st->fetchAll(PDO::FETCH_FUNC, 'nothing'));
+} catch (\TypeError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
-$st = $db->query('SELECT * FROM testing');
-var_dump($st->fetchAll(PDO::FETCH_FUNC, ''));
+try {
+    $st = $db->query('SELECT * FROM testing');
+    var_dump($st->fetchAll(PDO::FETCH_FUNC, ''));
+} catch (\TypeError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
-$st = $db->query('SELECT * FROM testing');
-var_dump($st->fetchAll(PDO::FETCH_FUNC, NULL));
+try {
+    $st = $db->query('SELECT * FROM testing');
+    var_dump($st->fetchAll(PDO::FETCH_FUNC, NULL));
+} catch (\TypeError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
-$st = $db->query('SELECT * FROM testing');
-var_dump($st->fetchAll(PDO::FETCH_FUNC, 1));
+try {
+    $st = $db->query('SELECT * FROM testing');
+    var_dump($st->fetchAll(PDO::FETCH_FUNC, 1));
+} catch (\TypeError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
-$st = $db->query('SELECT * FROM testing');
-var_dump($st->fetchAll(PDO::FETCH_FUNC, array('self', 'foo')));
+try {
+    $st = $db->query('SELECT * FROM testing');
+    var_dump($st->fetchAll(PDO::FETCH_FUNC, array('self', 'foo')));
+} catch (\TypeError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
 class foo {
     public function method($x) {
@@ -64,14 +84,26 @@ new bar($db);
 $st = $db->query('SELECT * FROM testing');
 var_dump($st->fetchAll(PDO::FETCH_FUNC, array('bar', 'test')));
 
-$st = $db->query('SELECT * FROM testing');
-var_dump($st->fetchAll(PDO::FETCH_FUNC, array('bar', 'test2')));
+try {
+    $st = $db->query('SELECT * FROM testing');
+    var_dump($st->fetchAll(PDO::FETCH_FUNC, array('bar', 'test2')));
+} catch (\TypeError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
-$st = $db->query('SELECT * FROM testing');
-var_dump($st->fetchAll(PDO::FETCH_FUNC, array('bar', 'test3')));
+try {
+    $st = $db->query('SELECT * FROM testing');
+    var_dump($st->fetchAll(PDO::FETCH_FUNC, array('bar', 'test3')));
+} catch (\TypeError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
-$st = $db->query('SELECT * FROM testing');
-var_dump($st->fetchAll(PDO::FETCH_FUNC, array('bar', 'inexistent')));
+try {
+    $st = $db->query('SELECT * FROM testing');
+    var_dump($st->fetchAll(PDO::FETCH_FUNC, array('bar', 'inexistent')));
+} catch (\TypeError $e) {
+    echo $e->getMessage(), \PHP_EOL;
+}
 
 ?>
 --EXPECTF--
@@ -91,31 +123,11 @@ array(2) {
   [1]=>
   string(0) ""
 }
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error: function "nothing" not found or invalid function name in %s on line %d
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error in %s on line %d
-bool(false)
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error: function "" not found or invalid function name in %s on line %d
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error in %s on line %d
-bool(false)
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error: no array or string given in %s on line %d
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error in %s on line %d
-bool(false)
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error: no array or string given in %s on line %d
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error in %s on line %d
-bool(false)
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error: cannot access "self" when no class scope is active in %s on line %d
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error in %s on line %d
-bool(false)
+function "nothing" not found or invalid function name
+function "" not found or invalid function name
+PDOStatement::fetchAll(): Argument #2 must be a callable, null given
+no array or string given
+cannot access "self" when no class scope is active
 array(2) {
   [0]=>
   string(9) "--- 1 ---"
@@ -128,18 +140,6 @@ array(2) {
   [1]=>
   string(4) "2---"
 }
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error: non-static method bar::test2() cannot be called statically in %s on line %d
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error in %s on line %d
-bool(false)
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error: non-static method bar::test3() cannot be called statically in %s on line %d
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error in %s on line %d
-bool(false)
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error: class bar does not have a method "inexistent" in %s on line %d
-
-Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error in %s on line %d
-bool(false)
+non-static method bar::test2() cannot be called statically
+non-static method bar::test3() cannot be called statically
+class bar does not have a method "inexistent"