From: Wez Furlong Date: Sun, 6 Feb 2005 21:05:59 +0000 (+0000) Subject: better handling of pdo-level errors X-Git-Tag: RELEASE_0_2~56 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e3ba31e899b5b1e6cf639086e71b033c5bbb3725;p=php better handling of pdo-level errors --- diff --git a/ext/pdo/TODO b/ext/pdo/TODO index 5f00d244eb..ff3b6ed505 100755 --- a/ext/pdo/TODO +++ b/ext/pdo/TODO @@ -2,14 +2,14 @@ $Id$ In no particular order: +Probable Bugs: +- persistent connections with bound parameters might segv on subsequent + requests + Low-level: - $dbh->quote() -- Scrollable cursors -- meta data from driver, such as server version and supported features -- field meta data from statement handles - LOB support via Streams API -- iterator support - make errors generated at the pdo level (as opposed to driver level) use the selected error mode. diff --git a/ext/pdo/config.m4 b/ext/pdo/config.m4 index 41bf1bf4ad..a5abc65683 100755 --- a/ext/pdo/config.m4 +++ b/ext/pdo/config.m4 @@ -1,8 +1,8 @@ dnl $Id$ dnl config.m4 for extension pdo -PHP_ARG_ENABLE(pdo, whether to enable PDO support, -[ --enable-pdo Enable PHP Data Objects support]) +PHP_ARG_ENABLE(pdo, whether to disable PDO support, +[ --disable-pdo Disable PHP Data Objects support], yes) if test "$PHP_PDO" != "no"; then PHP_NEW_EXTENSION(pdo, pdo.c pdo_dbh.c pdo_stmt.c pdo_sql_parser.c pdo_sqlstate.c, $ext_shared) diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index f31a20f1ef..a8f0ec9e4f 100755 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -36,6 +36,74 @@ #include "zend_object_handlers.h" #include "zend_hash.h" +void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *sqlstate, const char *supp TSRMLS_DC) +{ + pdo_error_type *pdo_err = &dbh->error_code; + char *message = NULL; + const char *msg; + zval *info = NULL; + + if (dbh->error_mode == PDO_ERRMODE_SILENT) { +#if 0 + /* BUG: if user is running in silent mode and hits an error at the driver level + * when they use the PDO methods to call up the error information, they may + * get bogus information */ + return; +#endif + } + + if (stmt) { + pdo_err = &stmt->error_code; + } + + strcpy(*pdo_err, sqlstate); + + /* hash sqlstate to error messages */ + msg = pdo_sqlstate_state_to_description(*pdo_err); + if (!msg) { + msg = "<>"; + } + + MAKE_STD_ZVAL(info); + array_init(info); + + add_next_index_string(info, *pdo_err, 1); + add_next_index_long(info, 0); + + if (supp) { + spprintf(&message, 0, "SQLSTATE[%s]: %s: 0 %s", *pdo_err, msg, supp); + } else { + spprintf(&message, 0, "SQLSTATE[%s]: %s", *pdo_err, msg); + } + + if (dbh->error_mode != PDO_ERRMODE_EXCEPTION) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message); + + if (info) { + zval_ptr_dtor(&info); + } + } else { + zval *ex; + zend_class_entry *def_ex = zend_exception_get_default(), *pdo_ex = php_pdo_get_exception(); + + MAKE_STD_ZVAL(ex); + object_init_ex(ex, pdo_ex); + + zend_update_property_string(def_ex, ex, "message", sizeof("message")-1, message TSRMLS_CC); + zend_update_property_string(def_ex, ex, "code", sizeof("code")-1, *pdo_err TSRMLS_CC); + + if (info) { + zend_update_property(pdo_ex, ex, "errorInfo", sizeof("errorInfo")-1, info TSRMLS_CC); + } + + zend_throw_exception_object(ex TSRMLS_CC); + } + + if (message) { + efree(message); + } +} + void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC) { pdo_error_type *pdo_err = &dbh->error_code; @@ -495,8 +563,7 @@ fail: if (attr == PDO_ATTR_AUTOCOMMIT) { zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "The auto-commit mode cannot be changed for this driver"); } else if (!dbh->methods->set_attribute) { - /* XXX: do something better here */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "This driver doesn't support setting attributes"); + pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support setting attributes" TSRMLS_CC); } else { PDO_HANDLE_DBH_ERR(); } @@ -534,7 +601,7 @@ static PHP_METHOD(PDO, getAttribute) } if (!dbh->methods->get_attribute) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "This driver doesn't support fetching attributes"); + pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support getting attributes" TSRMLS_CC); RETURN_FALSE; } @@ -544,9 +611,8 @@ static PHP_METHOD(PDO, getAttribute) RETURN_FALSE; case 0: - /* XXX: should do something better here */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "This driver doesn't support fetching %ld attribute", attr); - break; + pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support that attribute" TSRMLS_CC); + RETURN_FALSE; default: return; @@ -594,7 +660,8 @@ static PHP_METHOD(PDO, lastInsertId) PDO_DBH_CLEAR_ERR(); if (!dbh->methods->last_id) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "This driver does not support last inserted id retrieval."); + pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support lastInsertId()" TSRMLS_CC); + RETURN_FALSE; } else { RETURN_LONG(dbh->methods->last_id(dbh TSRMLS_CC)); } diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index a3614180d1..83bbec7e96 100755 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -293,7 +293,7 @@ static PHP_METHOD(PDOStatement, execute) } else { /* we're okay to be zero based here */ if (num_index < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter index"); + pdo_raise_impl_error(stmt->dbh, stmt, "HY093", NULL TSRMLS_CC); RETURN_FALSE; } param.paramno = num_index; @@ -646,7 +646,7 @@ static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, if (param.paramno > 0) { --param.paramno; /* make it zero-based internally */ } else if (!param.name) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter number: columns are 1-based"); + pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC); return 0; } @@ -737,8 +737,7 @@ static PHP_METHOD(PDOStatement, setAttribute) fail: if (!stmt->methods->set_attribute) { - /* XXX: do something better here */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "This driver doesn't support setting attributes"); + pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes" TSRMLS_CC); } else { PDO_HANDLE_STMT_ERR(); } @@ -758,7 +757,7 @@ static PHP_METHOD(PDOStatement, getAttribute) } if (!stmt->methods->get_attribute) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "This driver doesn't support fetching attributes"); + pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support getting attributes" TSRMLS_CC); RETURN_FALSE; } @@ -770,8 +769,8 @@ static PHP_METHOD(PDOStatement, getAttribute) case 0: /* XXX: should do something better here */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "This driver doesn't support fetching %ld attribute", attr); - break; + pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support getting that attribute" TSRMLS_CC); + RETURN_FALSE; default: return; @@ -804,7 +803,7 @@ static PHP_METHOD(PDOStatement, getColumnMeta) } if (!stmt->methods->get_column_meta) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "This driver does not support meta data"); + pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support meta data" TSRMLS_CC); RETURN_FALSE; } @@ -824,7 +823,7 @@ static PHP_METHOD(PDOStatement, getColumnMeta) /* }}} */ /* {{{ proto bool PDOStatement::setFetchMode(int mode [) - Returns meta data for a numbered column */ + changes the default fetch mode for subsequent fetches */ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip) { @@ -833,7 +832,6 @@ int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, in zval ***args; zend_class_entry **cep; - /* TODO: clear up class stuff here */ switch (stmt->default_fetch_type) { case PDO_FETCH_CLASS: if (stmt->fetch.cls.ctor_args) { @@ -935,7 +933,7 @@ fail_out: break; default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "mode is out of range"); + pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range" TSRMLS_CC); return FAILURE; } @@ -965,8 +963,7 @@ static PHP_METHOD(PDOStatement, nextRowset) struct pdo_column_data *col; if (!stmt->methods->next_rowset) { - /* TODO: need a better pdo-level error function */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "This driver does not support multiple rowsets"); + pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets" TSRMLS_CC); RETURN_FALSE; } diff --git a/ext/pdo/php_pdo_int.h b/ext/pdo/php_pdo_int.h index 48e0df1850..fed5c861f4 100755 --- a/ext/pdo/php_pdo_int.h +++ b/ext/pdo/php_pdo_int.h @@ -50,6 +50,7 @@ zend_object_iterator *php_pdo_dbstmt_iter_get(zend_class_entry *ce, zval *object extern pdo_driver_t *pdo_find_driver(const char *name, int namelen); extern void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC); +extern void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *sqlstate, const char *supp TSRMLS_DC); #define PDO_DBH_CLEAR_ERR() strcpy(dbh->error_code, PDO_ERR_NONE) #define PDO_STMT_CLEAR_ERR() strcpy(stmt->error_code, PDO_ERR_NONE)