Browse Source

better handling of pdo-level errors

PHP-5.1
Wez Furlong 22 years ago
parent
commit
e3ba31e899
  1. 8
      ext/pdo/TODO
  2. 4
      ext/pdo/config.m4
  3. 81
      ext/pdo/pdo_dbh.c
  4. 23
      ext/pdo/pdo_stmt.c
  5. 1
      ext/pdo/php_pdo_int.h

8
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.

4
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)

81
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 = "<<Unknown error>>";
}
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));
}

23
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;
}

1
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)

Loading…
Cancel
Save