From f7ebff804d28042dd2e7cd866e86dc27d43d9412 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Wed, 9 Mar 2005 05:50:03 +0000 Subject: [PATCH] "thou shalt not throw exceptions except in really exceptional circumstances." The only allowed places to throw them directly are from within the PDO class constructors or when dealing with transaction level attributes, where "hard-failure" is a feature. All other errors should use the PDO error handling mechanism and respect the users selected error mode. --- ext/pdo/pdo_dbh.c | 47 +++++++++++++++++++++---------- ext/pdo/pdo_stmt.c | 70 ++++++++++++++++++++++++++-------------------- 2 files changed, 72 insertions(+), 45 deletions(-) diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index f7e64b6b5b..6587de1bce 100755 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -385,15 +385,15 @@ static PHP_FUNCTION(dbh_constructor) } /* }}} */ -static zval * pdo_stmt_instantiate(zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args TSRMLS_DC) /* {{{ */ +static zval *pdo_stmt_instantiate(pdo_dbh_t *dbh, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args TSRMLS_DC) /* {{{ */ { if (ctor_args) { if (Z_TYPE_P(ctor_args) != IS_ARRAY) { - zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "Parameter ctor_args must be an array"); + pdo_raise_impl_error(dbh, NULL, "HY000", "constructor arguments must be passed as an array" TSRMLS_CC); return NULL; } if (!dbstmt_ce->constructor) { - zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "Statement object's constructor does not take any arguments", dbstmt_ce->name); + pdo_raise_impl_error(dbh, NULL, "HY000", "user-supplied statement does not accept constructor arguments" TSRMLS_CC); return NULL; } } @@ -479,21 +479,33 @@ static PHP_METHOD(PDO, prepare) || Z_TYPE_PP(item) != IS_STRING || zend_lookup_class(Z_STRVAL_PP(item), Z_STRLEN_PP(item), &pce TSRMLS_CC) == FAILURE ) { - zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "PDO_ATTR_STATEMENT_CLASS requires format array(classname, ctor_args) and classname must be a string specifying an existing class"); + pdo_raise_impl_error(dbh, NULL, "HY000", + "PDO_ATTR_STATEMENT_CLASS requires format array(classname, ctor_args); " + "the classname must be a string specifying an existing class" + TSRMLS_CC); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } dbstmt_ce = *pce; if (!instanceof_function(dbstmt_ce, pdo_dbstmt_ce TSRMLS_CC)) { - zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "The provided statement class must be derived from %s", pdo_dbstmt_ce->name); + pdo_raise_impl_error(dbh, NULL, "HY000", + "user-supplied statement class must be derived from PDOStatement" TSRMLS_CC); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } if (dbstmt_ce->constructor && !(dbstmt_ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "The provided statement class %s must not have a protected or public constructor", dbstmt_ce->name); + pdo_raise_impl_error(dbh, NULL, "HY000", + "user-supplied statement class must have a public constructor" TSRMLS_CC); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } if (zend_hash_index_find(Z_ARRVAL_PP(opt), 1, (void**)&item) == SUCCESS) { if (Z_TYPE_PP(item) != IS_ARRAY) { - zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "PDO_ATTR_STATEMENT_CLASS requires format array(classname, ctor_args) and ctor args must be an array"); + pdo_raise_impl_error(dbh, NULL, "HY000", + "PDO_ATTR_STATEMENT_CLASS requires format array(classname, ctor_args); " + "ctor_args must be an array" + TSRMLS_CC); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } ctor_args = *item; @@ -505,9 +517,12 @@ static PHP_METHOD(PDO, prepare) ctor_args = NULL; } - if (!pdo_stmt_instantiate(return_value, dbstmt_ce, ctor_args TSRMLS_CC)) { - zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "Failed to instantiate statement class %s", dbstmt_ce->name); - return; + if (!pdo_stmt_instantiate(dbh, return_value, dbstmt_ce, ctor_args TSRMLS_CC)) { + pdo_raise_impl_error(dbh, NULL, "HY000", + "failed to instantiate user-supplied statement class" + TSRMLS_CC); + PDO_HANDLE_DBH_ERR(); + RETURN_FALSE; } stmt = (pdo_stmt_t*)zend_object_store_get_object(return_value TSRMLS_CC); @@ -628,7 +643,9 @@ static PHP_METHOD(PDO, setAttribute) dbh->error_mode = Z_LVAL_P(value); RETURN_TRUE; default: - zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "Error mode %d is invalid", Z_LVAL_P(value)); + pdo_raise_impl_error(dbh, NULL, "HY000", "invalid error mode" TSRMLS_CC); + PDO_HANDLE_DBH_ERR(); + RETURN_FALSE; } RETURN_FALSE; @@ -641,7 +658,9 @@ static PHP_METHOD(PDO, setAttribute) dbh->desired_case = Z_LVAL_P(value); RETURN_TRUE; default: - zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "Case folding mode %d is invalid", Z_LVAL_P(value)); + pdo_raise_impl_error(dbh, NULL, "HY000", "invalid case folding mode" TSRMLS_CC); + PDO_HANDLE_DBH_ERR(); + RETURN_FALSE; } RETURN_FALSE; @@ -829,8 +848,8 @@ static PHP_METHOD(PDO, query) PDO_DBH_CLEAR_ERR(); - if (!pdo_stmt_instantiate(return_value, pdo_dbstmt_ce, NULL TSRMLS_CC)) { - zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "Failed to instantiate statement class %s", pdo_dbstmt_ce->name); + if (!pdo_stmt_instantiate(dbh, return_value, pdo_dbstmt_ce, NULL TSRMLS_CC)) { + pdo_raise_impl_error(dbh, NULL, "HY000", "failed to instantiate user supplied statement class" TSRMLS_CC); return; } stmt = (pdo_stmt_t*)zend_object_store_get_object(return_value TSRMLS_CC); diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 7092ad32f1..ec7182e17b 100755 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -571,7 +571,7 @@ static int do_fetch_class_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */ fcc->calling_scope = EG(scope); return 1; } else if (stmt->fetch.cls.ctor_args) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Class %s does not have a constructor, use NULL for parameter ctor_params or omit it", ce->name); + 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" TSRMLS_CC); return 0; } else { return 1; /* no ctor no args is also ok */ @@ -579,7 +579,7 @@ static int do_fetch_class_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */ } /* }}} */ -static int make_callable_ex(zval *callable, zend_fcall_info * fci, zend_fcall_info_cache * fcc, int num_args TSRMLS_DC) /* {{{ */ +static int make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info * fci, zend_fcall_info_cache * fcc, int num_args TSRMLS_DC) /* {{{ */ { zval **object = NULL, **method; char *fname, *cname; @@ -588,7 +588,7 @@ static int make_callable_ex(zval *callable, zend_fcall_info * fci, zend_fcall_in if (Z_TYPE_P(callable) == IS_ARRAY) { if (Z_ARRVAL_P(callable)->nNumOfElements < 2) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function must be a valid function name or an array specifying object or class and method name"); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback" TSRMLS_CC); return 0; } object = (zval**)Z_ARRVAL_P(callable)->pListHead->pData; @@ -599,17 +599,18 @@ static int make_callable_ex(zval *callable, zend_fcall_info * fci, zend_fcall_in } else if (Z_TYPE_PP(object) == IS_OBJECT) { /* object call */ ce = Z_OBJCE_PP(object); } else { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function may be an array but the provided array did neither contain a class name nor an object as first member"); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback; bogus object/class name" TSRMLS_CC); return 0; } if (Z_TYPE_PP(method) != IS_STRING) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function may be an array but the provided array did not contain a method name as second member"); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback; bogus method name" TSRMLS_CC); + return 0; } } if (!zend_is_callable(callable, 0, &fname)) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function must contain something callable"); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback" TSRMLS_CC); return 0; } @@ -624,12 +625,14 @@ static int make_callable_ex(zval *callable, zend_fcall_info * fci, zend_fcall_in } if (cname) { if (zend_lookup_class(cname, strlen(cname), &pce TSRMLS_CC) == FAILURE) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function references non existing class %s", cname); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied class does not exist" TSRMLS_CC); + return 0; } else { if (ce) { /* pce must be base of ce or ce itself */ if (ce != *pce && !instanceof_function(ce, *pce TSRMLS_CC)) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function would result in calling %s::%s but class %s is not base of %s", (*pce)->name, fname, (*pce)->name, ce->name); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied class has bogus lineage" TSRMLS_CC); + return 0; } } ce = *pce; @@ -638,8 +641,7 @@ static int make_callable_ex(zval *callable, zend_fcall_info * fci, zend_fcall_in fci->function_table = ce ? &ce->function_table : EG(function_table); if (zend_hash_find(fci->function_table, fname, strlen(fname)+1, (void **)&function_handler) == FAILURE) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Argument function '%s%s%s' not found", cname ? cname : "", cname ? "::" : "", fname); - efree(cname ? cname : fname); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function does not exist" TSRMLS_CC); return 0; } efree(cname ? cname : fname); @@ -665,7 +667,7 @@ static int do_fetch_func_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */ zend_fcall_info * fci = &stmt->fetch.cls.fci; zend_fcall_info_cache * fcc = &stmt->fetch.cls.fcc; - if (!make_callable_ex(stmt->fetch.func.function, fci, fcc, stmt->column_count TSRMLS_CC)) { + if (!make_callable_ex(stmt, stmt->fetch.func.function, fci, fcc, stmt->column_count TSRMLS_CC)) { return 0; } else { stmt->fetch.func.values = safe_emalloc(sizeof(zval*), stmt->column_count, 0); @@ -860,7 +862,7 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value, PHP_VAR_UNSERIALIZE_INIT(var_hash); if (php_var_unserialize(&return_value, (const unsigned char**)&Z_STRVAL_P(val), Z_STRVAL_P(val)+Z_STRLEN_P(val), NULL TSRMLS_CC) == FAILURE) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Cannot unserialize data"); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize data" TSRMLS_CC); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return 0; } @@ -868,12 +870,13 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value, #endif #if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1 if (!ce->unserialize) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Class %s cannot be unserialized", ce->name); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class" TSRMLS_CC); return 0; } else if (ce->unserialize(&return_value, ce, Z_TYPE_P(val) == IS_STRING ? Z_STRVAL_P(val) : "", Z_TYPE_P(val) == IS_STRING ? Z_STRLEN_P(val) : 0, NULL TSRMLS_CC) == FAILURE) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Class %s cannot be unserialized", ce->name); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class" TSRMLS_CC); zval_dtor(return_value); ZVAL_NULL(return_value); + return 0; } #endif } @@ -898,7 +901,7 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value, stmt->fetch.cls.fci.object_pp = &return_value; stmt->fetch.cls.fcc.object_pp = &return_value; if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc TSRMLS_CC) == FAILURE) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Could not execute %s::%s()", ce->name, ce->constructor->common.function_name); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor" TSRMLS_CC); return 0; } else { if (stmt->fetch.cls.retval_ptr) { @@ -918,7 +921,7 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value, stmt->fetch.func.fci.param_count = idx; stmt->fetch.func.fci.retval_ptr_ptr = &retval; if (zend_call_function(&stmt->fetch.func.fci, &stmt->fetch.func.fcc TSRMLS_CC) == FAILURE) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Could not execute %s%s%s()", ce->name, ce->constructor->common.function_name); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function" TSRMLS_CC); return 0; } else { if (return_all) { @@ -974,7 +977,7 @@ static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, int mode, int fetch_all TSRMLS #if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 1 if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) { - zend_throw_exception(pdo_exception_ce, "Fetch flag PDO_FETCH_SERIALIZE only allowed in PHP version 5.1 and higher", 0 TSRMLS_CC); + pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "PDO_FETCH_SERIALIZE is not supported in this PHP version" TSRMLS_CC); return 0; } #endif @@ -982,22 +985,22 @@ static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, int mode, int fetch_all TSRMLS switch(mode) { case PDO_FETCH_FUNC: if (!fetch_all) { - zend_throw_exception(pdo_exception_ce, "Fetch mode PDO_FETCH_FUNC is only allowed in PDOStatement::fetchAll()", 0 TSRMLS_CC); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_FETCH_FUNC is only allowed in PDOStatement::fetchAll()" TSRMLS_CC); return 0; } return 1; default: if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Fetch mode flag PDO_FETCH_SERIALIZE requires mode PDO_FETCH_CLASS", mode); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_FETCH_SERIALIZE can only be used together with PDO_FETCH_CLASS" TSRMLS_CC); return 0; } if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Fetch mode flag PDO_FETCH_CLASSTYPE requires mode PDO_FETCH_CLASS", mode); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_FETCH_CLASSTYPE can only be used together with PDO_FETCH_CLASS" TSRMLS_CC); return 0; } if (mode >= PDO_FETCH__MAX) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Fetch mode %d is invalid", mode); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode" TSRMLS_CC); return 0; } /* no break; */ @@ -1073,7 +1076,7 @@ static PHP_METHOD(PDOStatement, fetchObject) break; case 2: if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) { - zend_throw_exception(pdo_exception_ce, "Parameter ctor_args must either be NULL or an array ", 0 TSRMLS_CC); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC); error = 1; break; } @@ -1089,7 +1092,7 @@ static PHP_METHOD(PDOStatement, fetchObject) stmt->fetch.cls.ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC); if (!stmt->fetch.cls.ce) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Could not find class '%s'", class_name); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Could not find user-supplied class" TSRMLS_CC); error = 1; break; } @@ -1097,6 +1100,8 @@ static PHP_METHOD(PDOStatement, fetchObject) if (!error && !do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) { error = 1; + } + if (error) { PDO_HANDLE_STMT_ERR(); } do_fetch_opt_finish(stmt, 1 TSRMLS_CC); @@ -1166,7 +1171,7 @@ static PHP_METHOD(PDOStatement, fetchAll) break; case 3: if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) { - zend_throw_exception(pdo_exception_ce, "Parameter ctor_args must either be NULL or an array ", 0 TSRMLS_CC); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC); error = 1; break; } @@ -1177,19 +1182,21 @@ static PHP_METHOD(PDOStatement, fetchAll) case 2: stmt->fetch.cls.ctor_args = ctor_args; /* we're not going to free these */ if (Z_TYPE_P(arg2) != IS_STRING) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "In fetch mode PDO_FETCH_CLASS the 2nd parameter must be a class name string", Z_TYPE_P(arg2)); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid class name (should be a string)" TSRMLS_CC); error = 1; break; } else { stmt->fetch.cls.ce = zend_fetch_class(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2), ZEND_FETCH_CLASS_AUTO TSRMLS_CC); if (!stmt->fetch.cls.ce) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Could not find class '%s'", Z_TYPE_P(arg2)); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not find user-specified class" TSRMLS_CC); error = 1; break; } } } - do_fetch_class_prepare(stmt TSRMLS_CC); + if (!error) { + do_fetch_class_prepare(stmt TSRMLS_CC); + } break; case PDO_FETCH_FUNC: @@ -1216,14 +1223,14 @@ static PHP_METHOD(PDOStatement, fetchAll) stmt->fetch.column = Z_LVAL_P(arg2); break; case 3: - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Third parameter not allowed for specified fetch mode"); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Third parameter not allowed for PDO_FETCH_COLUMN" TSRMLS_CC); error = 1; } break; default: if (ZEND_NUM_ARGS() > 1) { - zend_throw_exception_ex(pdo_exception_ce, 0 TSRMLS_CC, "Additional parameters not allowed for specified fetch mode"); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Extraneous additional parameters" TSRMLS_CC); error = 1; } } @@ -1239,7 +1246,6 @@ static PHP_METHOD(PDOStatement, fetchAll) } if (!do_fetch(stmt, TRUE, data, how, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC)) { FREE_ZVAL(data); - PDO_HANDLE_STMT_ERR(); zval_dtor(return_value); error = 1; } @@ -1266,6 +1272,7 @@ static PHP_METHOD(PDOStatement, fetchAll) stmt->fetch.cls.fci.param_count = old_arg_count; if (error) { + PDO_HANDLE_STMT_ERR(); RETURN_FALSE; } } @@ -1547,12 +1554,13 @@ fail_out: stmt->fetch.cls.ctor_args = NULL; if (stmt->dbh->is_persistent) { + /* TODO: CRITICAL for final release */ php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement. This will be fixed in a later release"); } if (argc == 3) { if (Z_TYPE_PP(args[skip+2]) != IS_NULL && Z_TYPE_PP(args[skip+2]) != IS_ARRAY) { - zend_throw_exception(pdo_exception_ce, "Parameter ctor_args must either be NULL or an array ", 0 TSRMLS_CC); + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC); } else if (Z_TYPE_PP(args[skip+2]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_PP(args[skip+2]))) { ALLOC_ZVAL(stmt->fetch.cls.ctor_args); *stmt->fetch.cls.ctor_args = **args[skip+2]; -- 2.40.0