From: Xinchen Hui Date: Mon, 26 May 2014 06:17:45 +0000 (+0800) Subject: Finished persistent PDO implement X-Git-Tag: POST_PHPNG_MERGE~286^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9fa9da483129b53b35b2c2106c17f8a7a5b402f6;p=php Finished persistent PDO implement --- diff --git a/ext/pdo/pdo.c b/ext/pdo/pdo.c index b0dd27a966..3e10a6d003 100644 --- a/ext/pdo/pdo.c +++ b/ext/pdo/pdo.c @@ -35,6 +35,11 @@ static zend_class_entry *spl_ce_RuntimeException; +zend_class_entry *pdo_dbh_ce, *pdo_dbstmt_ce, *pdo_row_ce; + +/* for exceptional circumstances */ +zend_class_entry *pdo_exception_ce; + ZEND_DECLARE_MODULE_GLOBALS(pdo) static PHP_GINIT_FUNCTION(pdo); @@ -46,32 +51,33 @@ HashTable pdo_driver_hash; /* we use persistent resources for the driver connection stuff */ static int le_ppdo; -int php_pdo_list_entry(void) +int php_pdo_list_entry(void) /* {{{ */ { return le_ppdo; } +/* }}} */ -/* for exceptional circumstances */ -zend_class_entry *pdo_exception_ce; - -PDO_API zend_class_entry *php_pdo_get_dbh_ce(void) +PDO_API zend_class_entry *php_pdo_get_dbh_ce(void) /* {{{ */ { return pdo_dbh_ce; } +/* }}} */ -PDO_API zend_class_entry *php_pdo_get_exception(void) +PDO_API zend_class_entry *php_pdo_get_exception(void) /* {{{ */ { return pdo_exception_ce; } +/* }}} */ -PDO_API char *php_pdo_str_tolower_dup(const char *src, int len) +PDO_API char *php_pdo_str_tolower_dup(const char *src, int len) /* {{{ */ { char *dest = emalloc(len + 1); zend_str_tolower_copy(dest, src, len); return dest; } +/* }}} */ -PDO_API zend_class_entry *php_pdo_get_exception_base(int root TSRMLS_DC) +PDO_API zend_class_entry *php_pdo_get_exception_base(int root TSRMLS_DC) /* {{{ */ { #if defined(HAVE_SPL) if (!root) { @@ -89,8 +95,7 @@ PDO_API zend_class_entry *php_pdo_get_exception_base(int root TSRMLS_DC) #endif return zend_exception_get_default(TSRMLS_C); } - -zend_class_entry *pdo_dbh_ce, *pdo_dbstmt_ce, *pdo_row_ce; +/* }}} */ /* {{{ proto array pdo_drivers() Return array of available PDO drivers */ @@ -171,7 +176,7 @@ static PHP_GINIT_FUNCTION(pdo) } /* }}} */ -PDO_API int php_pdo_register_driver(pdo_driver_t *driver) +PDO_API int php_pdo_register_driver(pdo_driver_t *driver) /* {{{ */ { if (driver->api_version != PDO_DRIVER_API) { zend_error(E_ERROR, "PDO: driver %s requires PDO API version %ld; this is PDO version %d", @@ -185,8 +190,9 @@ PDO_API int php_pdo_register_driver(pdo_driver_t *driver) return zend_hash_str_add_ptr(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len, driver) != NULL; } +/* }}} */ -PDO_API void php_pdo_unregister_driver(pdo_driver_t *driver) +PDO_API void php_pdo_unregister_driver(pdo_driver_t *driver) /* {{{ */ { if (!zend_hash_str_exists(&module_registry, "pdo", sizeof("pdo") - 1)) { return; @@ -194,15 +200,15 @@ PDO_API void php_pdo_unregister_driver(pdo_driver_t *driver) zend_hash_str_del(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len); } +/* }}} */ -pdo_driver_t *pdo_find_driver(const char *name, int namelen) +pdo_driver_t *pdo_find_driver(const char *name, int namelen) /* {{{ */ { return zend_hash_str_find_ptr(&pdo_driver_hash, (char*)name, namelen); } +/* }}} */ -PDO_API int php_pdo_parse_data_source(const char *data_source, - unsigned long data_source_len, struct pdo_data_src_parser *parsed, - int nparams) +PDO_API int php_pdo_parse_data_source(const char *data_source, unsigned long data_source_len, struct pdo_data_src_parser *parsed, int nparams) /* {{{ */ { int i, j; int valstart = -1; @@ -300,9 +306,10 @@ PDO_API int php_pdo_parse_data_source(const char *data_source, return n_matches; } +/* }}} */ static const char digit_vec[] = "0123456789"; -PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC) +PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC) /* {{{ */ { char buffer[65]; char outbuf[65] = ""; @@ -341,6 +348,7 @@ PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC) *dst = '\0'; return estrdup(outbuf); } +/* }}} */ /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(pdo) diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 0cc6ea5cf4..88f6e4e91e 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -273,9 +273,6 @@ static PHP_METHOD(PDO, dbh_constructor) char *hashkey = NULL; zend_resource *le; pdo_dbh_t *pdbh = NULL; - - //?? let's delay the persistent supports later -#if 0 zval *v; if ((v = zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_PERSISTENT)) != NULL) { @@ -295,7 +292,6 @@ static PHP_METHOD(PDO, dbh_constructor) password ? password : ""); } } -#endif if (is_persistent) { /* let's see if we have one cached.... */ @@ -328,30 +324,15 @@ static PHP_METHOD(PDO, dbh_constructor) } memcpy((char *)pdbh->persistent_id, hashkey, plen+1); pdbh->persistent_id_len = plen; - pdbh->refcount = 1; - pdbh->std.properties = NULL; + pdbh->def_stmt_ce = dbh->def_stmt_ce; } } if (pdbh) { - /* let's copy the emalloc bits over from the other handle */ - if (pdbh->std.properties) { - zend_hash_destroy(dbh->std.properties); - efree(dbh->std.properties); - } else { - pdbh->std.ce = dbh->std.ce; - pdbh->def_stmt_ce = dbh->def_stmt_ce; - ZVAL_COPY_VALUE(&pdbh->def_stmt_ctor_args, &dbh->def_stmt_ctor_args); - pdbh->std.properties = dbh->std.properties; - //??? - //pdbh->std.properties_table = dbh->std.properties_table; - } - /* kill the non-persistent thingamy */ efree(dbh); /* switch over to the persistent one */ + Z_PDO_OBJECT_P(object)->inner = pdbh; dbh = pdbh; - zend_object_store_set_object(object, &dbh->std TSRMLS_CC); - dbh->refcount++; } if (hashkey) { @@ -391,8 +372,8 @@ static PHP_METHOD(PDO, dbh_constructor) le.type = php_pdo_list_entry(); le.ptr = dbh; - if (zend_hash_str_update_mem(&EG(persistent_list), - (char*)dbh->persistent_id, dbh->persistent_id_len, &le, sizeof(le))) { + if ((zend_hash_str_update_mem(&EG(persistent_list), + (char*)dbh->persistent_id, dbh->persistent_id_len, &le, sizeof(le))) == NULL) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to register persistent entry"); } } @@ -493,12 +474,13 @@ static void pdo_stmt_construct(pdo_stmt_t *stmt, zval *object, zend_class_entry Prepares a statement for execution and returns a statement object */ static PHP_METHOD(PDO, prepare) { - pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis()); pdo_stmt_t *stmt; char *statement; int statement_len; zval *options = NULL, *opt, *item, ctor_args; zend_class_entry *dbstmt_ce, *pce; + pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(getThis()); + pdo_dbh_t *dbh = dbh_obj->inner; if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &statement, &statement_len, &options)) { @@ -566,7 +548,7 @@ static PHP_METHOD(PDO, prepare) stmt->default_fetch_type = dbh->default_fetch_type; stmt->dbh = dbh; /* give it a reference to me */ - ZVAL_OBJ(&stmt->database_object_handle, &dbh->std); + ZVAL_OBJ(&stmt->database_object_handle, &dbh_obj->std); Z_ADDREF(stmt->database_object_handle); /* we haven't created a lazy object yet */ ZVAL_UNDEF(&stmt->lazy_object_ref); @@ -1070,10 +1052,11 @@ static PHP_METHOD(PDO, errorInfo) Prepare and execute $sql; returns the statement object for iteration */ static PHP_METHOD(PDO, query) { - pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis()); pdo_stmt_t *stmt; char *statement; int statement_len; + pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(getThis()); + pdo_dbh_t *dbh = dbh_obj->inner; /* Return a meaningful error when no parameters were passed */ if (!ZEND_NUM_ARGS()) { @@ -1104,7 +1087,7 @@ static PHP_METHOD(PDO, query) stmt->active_query_stringlen = statement_len; stmt->dbh = dbh; /* give it a reference to me */ - ZVAL_OBJ(&stmt->database_object_handle, &dbh->std); + ZVAL_OBJ(&stmt->database_object_handle, &dbh_obj->std); Z_ADDREF(stmt->database_object_handle); /* we haven't created a lazy object yet */ ZVAL_UNDEF(&stmt->lazy_object_ref); @@ -1247,7 +1230,7 @@ ZEND_BEGIN_ARG_INFO(arginfo_pdo__void, 0) ZEND_END_ARG_INFO() /* }}} */ -const zend_function_entry pdo_dbh_functions[] = { +const zend_function_entry pdo_dbh_functions[] = /* {{{ */ { ZEND_MALIAS(PDO, __construct, dbh_constructor, arginfo_pdo___construct, ZEND_ACC_PUBLIC) PHP_ME(PDO, prepare, arginfo_pdo_prepare, ZEND_ACC_PUBLIC) PHP_ME(PDO, beginTransaction, arginfo_pdo__void, ZEND_ACC_PUBLIC) @@ -1267,23 +1250,26 @@ const zend_function_entry pdo_dbh_functions[] = { PHP_ME(PDO, getAvailableDrivers, arginfo_pdo__void, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) {NULL, NULL, NULL} }; +/* }}} */ -static void cls_method_dtor(zval *el) { +static void cls_method_dtor(zval *el) /* {{{ */ { zend_function *func = (zend_function*)Z_PTR_P(el); if (func->common.function_name) { STR_RELEASE(func->common.function_name); } efree(func); } +/* }}} */ /* {{{ overloaded object handlers for PDO class */ -int pdo_hash_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC) +int pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind TSRMLS_DC) { const zend_function_entry *funcs; zend_function func; zend_internal_function *ifunc = (zend_internal_function*)&func; int namelen; char *lc_name; + pdo_dbh_t *dbh = dbh_obj->inner; if (!dbh || !dbh->methods || !dbh->methods->get_driver_methods) { return 0; @@ -1302,7 +1288,7 @@ int pdo_hash_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC) ifunc->type = ZEND_INTERNAL_FUNCTION; ifunc->handler = funcs->handler; ifunc->function_name = STR_INIT(funcs->fname, strlen(funcs->fname), 0); - ifunc->scope = dbh->std.ce; + ifunc->scope = dbh_obj->std.ce; ifunc->prototype = NULL; if (funcs->flags) { ifunc->fn_flags = funcs->flags | ZEND_ACC_NEVER_CACHE; @@ -1344,7 +1330,7 @@ int pdo_hash_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC) static union _zend_function *dbh_method_get(zend_object **object, zend_string *method_name, const zval *key TSRMLS_DC) { zend_function *fbc = NULL; - pdo_dbh_t *dbh = php_pdo_dbh_fetch_object(*object); + pdo_dbh_object_t *dbh_obj = php_pdo_dbh_fetch_object(*object); zend_string *lc_method_name; lc_method_name = STR_INIT(method_name->val, method_name->len, 0); @@ -1353,15 +1339,15 @@ static union _zend_function *dbh_method_get(zend_object **object, zend_string *m if ((fbc = std_object_handlers.get_method(object, method_name, key TSRMLS_CC)) == NULL) { /* not a pre-defined method, nor a user-defined method; check * the driver specific methods */ - if (!dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) { - if (!pdo_hash_methods(dbh, + if (!dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) { + if (!pdo_hash_methods(dbh_obj, PDO_DBH_DRIVER_METHOD_KIND_DBH TSRMLS_CC) - || !dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) { + || !dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) { goto out; } } - fbc = zend_hash_find_ptr(dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH], lc_method_name); + fbc = zend_hash_find_ptr(dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH], lc_method_name); } out: @@ -1386,7 +1372,7 @@ void pdo_dbh_init(TSRMLS_D) pdo_dbh_ce->create_object = pdo_dbh_new; memcpy(&pdo_dbh_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); - pdo_dbh_object_handlers.offset = XtOffsetOf(pdo_dbh_t, std); + pdo_dbh_object_handlers.offset = XtOffsetOf(pdo_dbh_object_t, std); pdo_dbh_object_handlers.dtor_obj = zend_objects_destroy_object; pdo_dbh_object_handlers.free_obj = pdo_dbh_free_storage; pdo_dbh_object_handlers.get_method = dbh_method_get; @@ -1489,10 +1475,14 @@ void pdo_dbh_init(TSRMLS_D) } -static void dbh_free(pdo_dbh_t *dbh TSRMLS_DC) +static void dbh_free(pdo_dbh_t *dbh, zend_bool free_persistent TSRMLS_DC) { int i; + if (dbh->is_persistent && !free_persistent) { + return; + } + if (dbh->query_stmt) { zval_ptr_dtor(&dbh->query_stmt_zval); dbh->query_stmt = NULL; @@ -1527,12 +1517,12 @@ static void dbh_free(pdo_dbh_t *dbh TSRMLS_DC) } } - //???pefree(dbh, dbh->is_persistent); + pefree(dbh, dbh->is_persistent); } static void pdo_dbh_free_storage(zend_object *std TSRMLS_DC) { - pdo_dbh_t *dbh = php_pdo_dbh_fetch_object(std); + pdo_dbh_t *dbh = php_pdo_dbh_fetch_inner(std); if (dbh->in_txn && dbh->methods && dbh->methods->rollback) { dbh->methods->rollback(dbh TSRMLS_CC); dbh->in_txn = 0; @@ -1542,19 +1532,19 @@ static void pdo_dbh_free_storage(zend_object *std TSRMLS_DC) dbh->methods->persistent_shutdown(dbh TSRMLS_CC); } zend_object_std_dtor(std TSRMLS_CC); - dbh_free(dbh TSRMLS_CC); + dbh_free(dbh, 0 TSRMLS_CC); } zend_object *pdo_dbh_new(zend_class_entry *ce TSRMLS_DC) { - pdo_dbh_t *dbh; + pdo_dbh_object_t *dbh; - dbh = ecalloc(1, sizeof(pdo_dbh_t) + sizeof(zval) * (ce->default_properties_count - 1)); + dbh = ecalloc(1, sizeof(pdo_dbh_object_t) + sizeof(zval) * (ce->default_properties_count - 1)); zend_object_std_init(&dbh->std, ce TSRMLS_CC); object_properties_init(&dbh->std, ce); rebuild_object_properties(&dbh->std); - dbh->refcount = 1; - dbh->def_stmt_ce = pdo_dbstmt_ce; + dbh->inner = ecalloc(1, sizeof(pdo_dbh_t)); + dbh->inner->def_stmt_ce = pdo_dbstmt_ce; dbh->std.handlers = &pdo_dbh_object_handlers; @@ -1563,14 +1553,15 @@ zend_object *pdo_dbh_new(zend_class_entry *ce TSRMLS_DC) /* }}} */ -ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor) +ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor) /* {{{ */ { if (res->ptr) { pdo_dbh_t *dbh = (pdo_dbh_t*)res->ptr; - dbh_free(dbh TSRMLS_CC); + dbh_free(dbh, 1 TSRMLS_CC); res->ptr = NULL; } } +/* }}} */ /* * Local variables: diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 5d291c0771..6f74889980 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -2229,7 +2229,7 @@ static union _zend_function *dbstmt_method_get(zend_object **object_pp, zend_str /* not a pre-defined method, nor a user-defined method; check * the driver specific methods */ if (!stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) { - if (!pdo_hash_methods(stmt->dbh, + if (!pdo_hash_methods(Z_PDO_OBJECT_P(&stmt->database_object_handle), PDO_DBH_DRIVER_METHOD_KIND_STMT TSRMLS_CC) || !stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) { goto out; diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index 0326eaa5a1..4818bc6232 100644 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -24,9 +24,10 @@ #include "php_pdo.h" /* forward declarations */ -typedef struct _pdo_dbh_t pdo_dbh_t; -typedef struct _pdo_stmt_t pdo_stmt_t; -typedef struct _pdo_row_t pdo_row_t; +typedef struct _pdo_dbh_t pdo_dbh_t; +typedef struct _pdo_dbh_object_t pdo_dbh_object_t; +typedef struct _pdo_stmt_t pdo_stmt_t; +typedef struct _pdo_row_t pdo_row_t; struct pdo_bound_param_data; #ifdef PHP_WIN32 @@ -425,7 +426,6 @@ enum pdo_placeholder_support { PDO_PLACEHOLDER_POSITIONAL=2 }; -/* represents a connection to a database */ struct _pdo_dbh_t { /* driver specific methods */ struct pdo_dbh_methods *methods; @@ -501,7 +501,11 @@ struct _pdo_dbh_t { /* defaults for fetches */ enum pdo_fetch_type default_fetch_type; +}; +/* represents a connection to a database */ +struct _pdo_dbh_object_t { + pdo_dbh_t *inner; /* these items must appear in this order at the beginning of the struct so that this can be cast as a zend_object. we need this to allow the extending class to escape all the custom handlers @@ -510,11 +514,16 @@ struct _pdo_dbh_t { zend_object std; }; -static inline pdo_dbh_t *php_pdo_dbh_fetch_object(zend_object *obj) { - return (pdo_dbh_t *)((char*)(obj) - XtOffsetOf(pdo_dbh_t, std)); +static inline pdo_dbh_t *php_pdo_dbh_fetch_inner(zend_object *obj) { + return (pdo_dbh_t *)(((pdo_dbh_object_t *)((char*)(obj) - XtOffsetOf(pdo_dbh_object_t, std)))->inner); +} + +static inline pdo_dbh_object_t *php_pdo_dbh_fetch_object(zend_object *obj) { + return (pdo_dbh_object_t *)((char*)(obj) - XtOffsetOf(pdo_dbh_object_t, std)); } -#define Z_PDO_DBH_P(zv) php_pdo_dbh_fetch_object(Z_OBJ_P((zv))) +#define Z_PDO_DBH_P(zv) php_pdo_dbh_fetch_inner(Z_OBJ_P((zv))) +#define Z_PDO_OBJECT_P(zv) php_pdo_dbh_fetch_object(Z_OBJ_P((zv))) /* describes a column */ struct pdo_column_data { diff --git a/ext/pdo/php_pdo_int.h b/ext/pdo/php_pdo_int.h index a428a74a3a..27cca7c29f 100644 --- a/ext/pdo/php_pdo_int.h +++ b/ext/pdo/php_pdo_int.h @@ -60,7 +60,7 @@ extern pdo_driver_t *pdo_find_driver(const char *name, int namelen); int pdo_sqlstate_init_error_table(void); void pdo_sqlstate_fini_error_table(void); const char *pdo_sqlstate_state_to_description(char *state); -int pdo_hash_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC); +int pdo_hash_methods(pdo_dbh_object_t *dbh, int kind TSRMLS_DC); /*