REGISTER_LONG_CONSTANT("PDO_ATTR_SCROLL", (long)PDO_ATTR_SCROLL, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_PREFETCH", (long)PDO_ATTR_PREFETCH, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_TIMEOUT", (long)PDO_ATTR_TIMEOUT, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("PDO_ATTR_ERRMODE", (long)PDO_ATTR_ERRMODE, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_SERVER_VERSION", (long)PDO_ATTR_SERVER_VERSION, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_CLIENT_VERSION", (long)PDO_ATTR_CLIENT_VERSION, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_SERVER_INFO", (long)PDO_ATTR_SERVER_INFO, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_CONNECTION_STATUS", (long)PDO_ATTR_CONNECTION_STATUS, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("PDO_ERRMODE_SILENT", (long)PDO_ERRMODE_SILENT, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("PDO_ERRMODE_WARNING", (long)PDO_ERRMODE_WARNING, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("PDO_ERRMODE_EXCEPTION", (long)PDO_ERRMODE_EXCEPTION, CONST_CS|CONST_PERSISTENT);
+
REGISTER_LONG_CONSTANT("PDO_ERR_NONE", (long)PDO_ERR_NONE, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERR_CANT_MAP", (long)PDO_ERR_CANT_MAP, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERR_SYNTAX", (long)PDO_ERR_SYNTAX, CONST_CS|CONST_PERSISTENT);
INIT_CLASS_ENTRY(ce, "PDOException", NULL);
pdo_exception_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default(), NULL TSRMLS_CC);
+ zend_declare_property_null(pdo_exception_ce, "errorInfo", sizeof("errorInfo")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
INIT_CLASS_ENTRY(ce, "PDO", pdo_dbh_functions);
ce.create_object = pdo_dbh_new;
const char *msg = "<<Unknown>>";
char *supp = NULL;
long native_code = 0;
+ char *message = NULL;
+ zval *info = NULL;
- /* TODO: if the dbh->error_mode is set to "silent" mode, just return */
+ if (dbh->error_mode == PDO_ERRMODE_SILENT) {
+ return;
+ }
if (stmt) {
pdo_err = &stmt->error_code;
}
if (dbh->methods->fetch_err) {
- zval *info;
MAKE_STD_ZVAL(info);
array_init(info);
+ add_next_index_long(info, *pdo_err);
+
if (dbh->methods->fetch_err(dbh, stmt, info TSRMLS_CC)) {
zval **item;
- if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(info), 0, (void**)&item)) {
+ if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(info), 1, (void**)&item)) {
native_code = Z_LVAL_PP(item);
}
- if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(info), 1, (void**)&item)) {
+ if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(info), 2, (void**)&item)) {
supp = estrndup(Z_STRVAL_PP(item), Z_STRLEN_PP(item));
}
-
}
- FREE_ZVAL(info);
}
- /* TODO: if the dbh->error_mode is set to exception mode, set up an
- * exception instead */
-
if (supp && *pdo_err == PDO_ERR_CANT_MAP) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%ld %s", native_code, supp);
+ spprintf(&message, 0, "%ld %s", native_code, supp);
} else if (supp) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: %ld %s", msg, native_code, supp);
+ spprintf(&message, 0, "%s: %ld %s", msg, native_code, supp);
} else {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", msg);
+ spprintf(&message, 0, "%s", msg);
+ }
+
+ if (dbh->error_mode == PDO_ERRMODE_WARNING) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, message);
+
+ if (info) {
+ FREE_ZVAL(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_long(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);
}
if (supp) {
RETURN_FALSE;
}
+ switch (attr) {
+ case PDO_ATTR_ERRMODE:
+ convert_to_long(value);
+ switch (Z_LVAL_P(value)) {
+ case PDO_ERRMODE_SILENT:
+ case PDO_ERRMODE_WARNING:
+ case PDO_ERRMODE_EXCEPTION:
+ dbh->error_mode = Z_LVAL_P(value);
+ RETURN_TRUE;
+ default:
+ zend_throw_exception_ex(php_pdo_get_exception(), PDO_ERR_SYNTAX TSRMLS_CC, "Error mode %d is invalid", Z_LVAL_P(value));
+ }
+ RETURN_FALSE;
+
+ default:
+ ;
+ }
+
if (!dbh->methods->set_attribute) {
goto fail;
}
PDO_ATTR_SCROLL, /* ask for a scrollable cursor (when you prepare()) */
PDO_ATTR_PREFETCH, /* configure the prefetch size for drivers that support it */
PDO_ATTR_TIMEOUT, /* connection timeout in seconds */
+ PDO_ATTR_ERRMODE, /* control how errors are handled */
PDO_ATTR_SERVER_VERSION, /* database server version */
PDO_ATTR_CLIENT_VERSION, /* client library version */
PDO_ATTR_SERVER_INFO, /* server information */
PDO_ERR_DISCONNECTED,
};
+enum pdo_error_mode {
+ PDO_ERRMODE_SILENT, /* just set error codes */
+ PDO_ERRMODE_WARNING, /* raise E_WARNING */
+ PDO_ERRMODE_EXCEPTION, /* throw exceptions */
+};
+
/* {{{ utils for reading attributes set as driver_options */
static inline long pdo_attr_lval(zval *options, enum pdo_fetch_type option_name, long defval TSRMLS_DC)
{
/* the global error code. */
enum pdo_error_type error_code;
+
+ enum pdo_error_mode error_mode;
#if 0
/* persistent hash key associated with this handle */
const char *persistent_id;
#define PDO_DBH_CLEAR_ERR() dbh->error_code = PDO_ERR_NONE
#define PDO_STMT_CLEAR_ERR() stmt->error_code = PDO_ERR_NONE
-#define PDO_HANDLE_DBH_ERR() pdo_handle_error(dbh, NULL TSRMLS_CC)
-#define PDO_HANDLE_STMT_ERR() pdo_handle_error(stmt->dbh, stmt TSRMLS_CC)
+#define PDO_HANDLE_DBH_ERR() if (dbh->error_code) { pdo_handle_error(dbh, NULL TSRMLS_CC); }
+#define PDO_HANDLE_STMT_ERR() if (stmt->error_code) { pdo_handle_error(stmt->dbh, stmt TSRMLS_CC); }
/*