From 49e7b3da4cb5de5d88c24a4e7a8399cef21a1c71 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Fri, 10 Jun 2005 05:47:55 +0000 Subject: [PATCH] Fix a dumb bug that would effecively ignore persistent connections and create a new one each time. Add a hook for persistent connections: it is called when the object goes out of scope, and offers the driver an opportunity to release per-request scoped data at the right time. This hook is used by pdo_sqlite to unregister UDFs, which are dangerous to keep registered between requests. --- ext/pdo/pdo_dbh.c | 70 ++++++++++++++++++++++++++-------------- ext/pdo/php_pdo_driver.h | 10 ++++-- 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 15e2384ebb..09421863a5 100755 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -216,6 +216,7 @@ static PHP_FUNCTION(dbh_constructor) pdo_driver_t *driver = NULL; zval *options = NULL; char alt_dsn[512]; + int call_factory = 1; if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ssa!", &data_source, &data_source_len, &username, &usernamelen, &password, &passwordlen, &options)) { @@ -300,35 +301,39 @@ static PHP_FUNCTION(dbh_constructor) } } - /* let's see if we have one cached.... */ - if (is_persistent && SUCCESS == zend_hash_find(&EG(persistent_list), hashkey, plen+1, (void*)&le)) { - if (Z_TYPE_P(le) == php_pdo_list_entry()) { - pdbh = (pdo_dbh_t*)le->ptr; - - /* is the connection still alive ? */ - if (pdbh->methods->check_liveness && FAILURE == (pdbh->methods->check_liveness)(pdbh TSRMLS_CC)) { - /* nope... need to kill it */ - pdbh = NULL; + if (is_persistent) { + /* let's see if we have one cached.... */ + if (SUCCESS == zend_hash_find(&EG(persistent_list), hashkey, plen+1, (void*)&le)) { + if (Z_TYPE_P(le) == php_pdo_list_entry()) { + pdbh = (pdo_dbh_t*)le->ptr; + + /* is the connection still alive ? */ + if (pdbh->methods->check_liveness && FAILURE == (pdbh->methods->check_liveness)(pdbh TSRMLS_CC)) { + /* nope... need to kill it */ + pdbh = NULL; + } } } - } - if (is_persistent && !pdbh) { - /* need a brand new pdbh */ - pdbh = pecalloc(1, sizeof(*pdbh), 1); + if (pdbh) { + call_factory = 0; + } else { + /* need a brand new pdbh */ + pdbh = pecalloc(1, sizeof(*pdbh), 1); + + if (!pdbh) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO handle"); + /* NOTREACHED */ + } - if (!pdbh) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO handle"); - /* NOTREACHED */ - } - - pdbh->is_persistent = 1; - if (!(pdbh->persistent_id = pemalloc(plen + 1, 1))) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO handle"); + pdbh->is_persistent = 1; + if (!(pdbh->persistent_id = pemalloc(plen + 1, 1))) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO handle"); + } + memcpy((char *)pdbh->persistent_id, hashkey, plen+1); + pdbh->persistent_id_len = plen+1; + pdbh->refcount = 1; } - memcpy((char *)pdbh->persistent_id, hashkey, plen+1); - pdbh->persistent_id_len = plen+1; - pdbh->refcount = 1; } if (pdbh) { @@ -358,7 +363,12 @@ static PHP_FUNCTION(dbh_constructor) if (!dbh->data_source || (username && !dbh->username) || (password && !dbh->password)) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory"); } - + + if (!call_factory) { + /* we got a persistent guy from our cache */ + return; + } + if (driver->db_handle_factory(dbh, options TSRMLS_CC)) { /* all set */ @@ -1106,6 +1116,14 @@ static void dbh_free(pdo_dbh_t *dbh TSRMLS_DC) static void pdo_dbh_free_storage(pdo_dbh_t *dbh TSRMLS_DC) { + if (dbh->methods->rollback) { + /* roll back transactions, that are possibly nested, even though we don't + * official support them */ + while (dbh->methods->rollback(dbh TSRMLS_CC)) + ; + dbh->in_txn = 0; + } + if (dbh->properties) { zend_hash_destroy(dbh->properties); efree(dbh->properties); @@ -1114,6 +1132,8 @@ static void pdo_dbh_free_storage(pdo_dbh_t *dbh TSRMLS_DC) if (!dbh->is_persistent) { dbh_free(dbh TSRMLS_CC); + } else if (dbh->methods->persistent_shutdown) { + dbh->methods->persistent_shutdown(dbh TSRMLS_CC); } } diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index 2036a1381d..4d86cdeb59 100755 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -44,7 +44,7 @@ PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC); # define FALSE 0 #endif -#define PDO_DRIVER_API 20050227 +#define PDO_DRIVER_API 20050610 enum pdo_param_type { PDO_PARAM_NULL, @@ -262,6 +262,11 @@ typedef int (*pdo_dbh_get_attr_func)(pdo_dbh_t *dbh, long attr, zval *val TSRMLS * You may set this handler to NULL, which is equivalent to returning SUCCESS. */ typedef int (*pdo_dbh_check_liveness_func)(pdo_dbh_t *dbh TSRMLS_DC); +/* called at request end for each persistent dbh; this gives the driver + * the opportunity to safely release resources that only have per-request + * scope */ +typedef void (*pdo_dbh_request_shutdown)(pdo_dbh_t *dbh TSRMLS_DC); + /* for adding methods to the dbh or stmt objects pointer to a list of driver specific functions. The convention is to prefix the function names using the PDO driver name; this will @@ -290,6 +295,7 @@ struct pdo_dbh_methods { pdo_dbh_get_attr_func get_attribute; pdo_dbh_check_liveness_func check_liveness; pdo_dbh_get_driver_methods_func get_driver_methods; + pdo_dbh_request_shutdown persistent_shutdown; }; /* }}} */ @@ -473,7 +479,7 @@ struct pdo_column_data { unsigned long precision; /* don't touch this unless your name is dbdo */ - void *dbdo_stuff; + void *dbdo_data; }; /* describes a bound parameter */ -- 2.50.1