]> granicus.if.org Git - php/commitdiff
better handling of pdo-level errors
authorWez Furlong <wez@php.net>
Sun, 6 Feb 2005 21:05:59 +0000 (21:05 +0000)
committerWez Furlong <wez@php.net>
Sun, 6 Feb 2005 21:05:59 +0000 (21:05 +0000)
ext/pdo/TODO
ext/pdo/config.m4
ext/pdo/pdo_dbh.c
ext/pdo/pdo_stmt.c
ext/pdo/php_pdo_int.h

index 5f00d244eb09131fea9be5356c3f6613f5ea017f..ff3b6ed505ca739c093565f666736e638b05b71b 100755 (executable)
@@ -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.
 
index 41bf1bf4ad7c015d3346792cb579b7924ce52244..a5abc65683dc5027b59f1531533cb8b5a44cf50d 100755 (executable)
@@ -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)
index f31a20f1ef67a2727814d931b51b545f81e117f9..a8f0ec9e4f02c9f7b1e3d0cc6ba9902751b30162 100755 (executable)
 #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));
        }
index a3614180d1b5a04c6d33018a8f7a34da129dccaa..83bbec7e962e0c5942fa5d6bc40d8c36852df19e 100755 (executable)
@@ -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;
        }
 
index 48e0df185022d6a32e869f142fa95c3186b0c220..fed5c861f447524b82dfefbd7ac40898bee69b2e 100755 (executable)
@@ -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)