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.
This commit is contained in:
Wez Furlong 2005-06-10 05:47:55 +00:00
parent 3ff7178126
commit 49e7b3da4c
2 changed files with 52 additions and 26 deletions

View File

@ -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;
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;
/* 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");
}
memcpy((char *)pdbh->persistent_id, hashkey, plen+1);
pdbh->persistent_id_len = plen+1;
pdbh->refcount = 1;
}
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;
}
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);
}
}

View File

@ -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 */