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.
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)
#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;
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();
}
}
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;
}
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;
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));
}
} 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;
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;
}
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();
}
}
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;
}
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;
}
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;
}
/* }}} */
/* {{{ 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)
{
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) {
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;
}
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;
}
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)