From: Scott MacVicar Date: Tue, 29 Jul 2008 00:56:53 +0000 (+0000) Subject: MFH: Add freelist for tracking sqlite statements to free on implicit SQLite3::close() X-Git-Tag: php-5.3.0alpha1~65 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2b040f2d66bf1f79a4eae6038b6707d8e6d3fa72;p=php MFH: Add freelist for tracking sqlite statements to free on implicit SQLite3::close() --- diff --git a/ext/sqlite3/php_sqlite3_structs.h b/ext/sqlite3/php_sqlite3_structs.h index 47cf88a799..e1f5254339 100644 --- a/ext/sqlite3/php_sqlite3_structs.h +++ b/ext/sqlite3/php_sqlite3_structs.h @@ -68,23 +68,18 @@ typedef struct _php_sqlite3_db_object { int initialised; sqlite3 *db; php_sqlite3_func *funcs; -} php_sqlite3_db_object; -/*typedef struct _php_sqlite3_stmt { - sqlite3_stmt *stmt; - int initialised; -} php_sqlite3_stmt;*/ + zend_llist free_list; +} php_sqlite3_db_object; typedef struct _php_sqlite3_stmt_object php_sqlite3_stmt; typedef struct _php_sqlite3_result_object php_sqlite3_result; /* sqlite3 objects to be destroyed */ -typedef struct _php_sqlite3_stmt_free_list { - sqlite3_stmt *stmt; - - zval *statement_object; - zval *result_object; -} php_sqlite3_stmt_free_list; +typedef struct _php_sqlite3_free_list { + zval *stmt_obj_zval; + php_sqlite3_stmt *stmt_obj; +} php_sqlite3_free_list; /* Structure for SQLite Result object. */ struct _php_sqlite3_result_object { @@ -92,8 +87,6 @@ struct _php_sqlite3_result_object { php_sqlite3_db_object *db_obj; php_sqlite3_stmt *stmt_obj; zval *stmt_obj_zval; - - int initialised; int is_prepared_statement; int complete; diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 10724633c1..7e2a546deb 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -38,7 +38,7 @@ ZEND_DECLARE_MODULE_GLOBALS(sqlite3) static PHP_GINIT_FUNCTION(sqlite3); static int php_sqlite3_authorizer(void *autharg, int access_type, const char *arg3, const char *arg4, const char *arg5, const char *arg6); static void sqlite3_param_dtor(void *data); -static int php_sqlite3_compare_stmt_free( php_sqlite3_stmt_free_list **stmt_list, sqlite3_stmt *statement ); +static int php_sqlite3_compare_stmt_zval_free( php_sqlite3_free_list **free_list, zval *statement ); #define SQLITE3_CHECK_INITIALIZED(member, class_name) \ if (!(member)) { \ @@ -146,6 +146,7 @@ PHP_METHOD(sqlite3, close) } if (db_obj->initialised) { + zend_llist_clean(&(db_obj->free_list)); errcode = sqlite3_close(db_obj->db); if (errcode != SQLITE_OK) { RETURN_TRUE; @@ -394,6 +395,7 @@ PHP_METHOD(sqlite3, prepare) zval_dtor(return_value); RETURN_FALSE; } + stmt_obj->initialised = 1; } /* }}} */ @@ -445,31 +447,32 @@ PHP_METHOD(sqlite3, query) RETURN_FALSE; } + stmt_obj->initialised = 1; + object_init_ex(return_value, php_sqlite3_result_entry); result = (php_sqlite3_result *)zend_object_store_get_object(return_value TSRMLS_CC); result->db_obj = db_obj; result->stmt_obj = stmt_obj; result->stmt_obj_zval = stmt; - result->initialised = 1; return_code = sqlite3_step(result->stmt_obj->stmt); switch (return_code) { case SQLITE_ROW: /* Valid Row */ case SQLITE_DONE: /* Valid but no results */ { - /*php_sqlite3_stmt_free_list *free_item; - free_item = emalloc(sizeof(php_sqlite3_stmt_free_list)); - free_item->stmt = result->intern_stmt; - free_item->statement_object = NULL; - free_item->result_object = return_value; - zend_llist_add_element(&(db_obj->stmt_list), &free_item);*/ + php_sqlite3_free_list *free_item; + free_item = emalloc(sizeof(php_sqlite3_free_list)); + free_item->stmt_obj = stmt_obj; + free_item->stmt_obj_zval = stmt; + zend_llist_add_element(&(db_obj->free_list), &free_item); sqlite3_reset(result->stmt_obj->stmt); break; } default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to execute statement: %s", sqlite3_errmsg(db_obj->db)); - sqlite3_finalize(result->stmt_obj->stmt); + sqlite3_finalize(stmt_obj->stmt); + stmt_obj->initialised = 0; zval_dtor(return_value); RETURN_FALSE; } @@ -890,7 +893,7 @@ PHP_METHOD(sqlite3_stmt, close) return; } - /*zend_llist_del_element(&(stmt_obj->db_obj->stmt_list), stmt_obj->stmt, (int (*)(void *, void *)) php_sqlite3_compare_stmt_free);*/ + zend_llist_del_element(&(stmt_obj->db_obj->free_list), object, (int (*)(void *, void *)) php_sqlite3_compare_stmt_zval_free); RETURN_TRUE; } @@ -1128,6 +1131,8 @@ PHP_METHOD(sqlite3_stmt, execute) case SQLITE_ROW: /* Valid Row */ case SQLITE_DONE: /* Valid but no results */ { + php_sqlite3_free_list *free_item; + sqlite3_reset(stmt_obj->stmt); object_init_ex(return_value, php_sqlite3_result_entry); result = (php_sqlite3_result *)zend_object_store_get_object(return_value TSRMLS_CC); @@ -1135,11 +1140,16 @@ PHP_METHOD(sqlite3_stmt, execute) Z_ADDREF_P(object); result->is_prepared_statement = 1; - result->initialised = 1; result->db_obj = stmt_obj->db_obj; result->stmt_obj = stmt_obj; result->stmt_obj_zval = getThis(); + free_item = emalloc(sizeof(php_sqlite3_free_list)); + free_item->stmt_obj = stmt_obj; + free_item->stmt_obj_zval = getThis(); + + zend_llist_add_element(&(stmt_obj->db_obj->free_list), &free_item); + break; } case SQLITE_ERROR: @@ -1163,7 +1173,7 @@ PHP_METHOD(sqlite3_result, numColumns) zval *object = getThis(); result_obj = (php_sqlite3_result *)zend_object_store_get_object(object TSRMLS_CC); - SQLITE3_CHECK_INITIALIZED(result_obj->initialised, SQLite3_result) + SQLITE3_CHECK_INITIALIZED(result_obj->stmt_obj->initialised, SQLite3_result) if (zend_parse_parameters_none() == FAILURE) { return; @@ -1182,7 +1192,7 @@ PHP_METHOD(sqlite3_result, columnName) int column = 0; result_obj = (php_sqlite3_result *)zend_object_store_get_object(object TSRMLS_CC); - SQLITE3_CHECK_INITIALIZED(result_obj->initialised, SQLite3_result) + SQLITE3_CHECK_INITIALIZED(result_obj->stmt_obj->initialised, SQLite3_result) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &column) == FAILURE) { return; @@ -1201,7 +1211,7 @@ PHP_METHOD(sqlite3_result, columnType) int column = 0; result_obj = (php_sqlite3_result *)zend_object_store_get_object(object TSRMLS_CC); - SQLITE3_CHECK_INITIALIZED(result_obj->initialised, SQLite3_result) + SQLITE3_CHECK_INITIALIZED(result_obj->stmt_obj->initialised, SQLite3_result) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &column) == FAILURE) { return; @@ -1220,7 +1230,7 @@ PHP_METHOD(sqlite3_result, fetchArray) int i, ret, mode = PHP_SQLITE3_BOTH; result_obj = (php_sqlite3_result *)zend_object_store_get_object(object TSRMLS_CC); - SQLITE3_CHECK_INITIALIZED(result_obj->initialised, SQLite3_result) + SQLITE3_CHECK_INITIALIZED(result_obj->stmt_obj->initialised, SQLite3_result) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &mode) == FAILURE) { return; @@ -1272,7 +1282,7 @@ PHP_METHOD(sqlite3_result, reset) zval *object = getThis(); result_obj = (php_sqlite3_result *)zend_object_store_get_object(object TSRMLS_CC); - SQLITE3_CHECK_INITIALIZED(result_obj->initialised, SQLite3_result) + SQLITE3_CHECK_INITIALIZED(result_obj->stmt_obj->initialised, SQLite3_result) if (zend_parse_parameters_none() == FAILURE) { return; @@ -1296,7 +1306,7 @@ PHP_METHOD(sqlite3_result, finalize) zval *object = getThis(); result_obj = (php_sqlite3_result *)zend_object_store_get_object(object TSRMLS_CC); - SQLITE3_CHECK_INITIALIZED(result_obj->initialised, SQLite3_result) + SQLITE3_CHECK_INITIALIZED(result_obj->stmt_obj->initialised, SQLite3_result) if (zend_parse_parameters_none() == FAILURE) { return; @@ -1304,8 +1314,8 @@ PHP_METHOD(sqlite3_result, finalize) /* We need to finalize an internal statement */ if (result_obj->is_prepared_statement == 0) { - result_obj->initialised = 0; - sqlite3_finalize(result_obj->stmt_obj->stmt); + zend_llist_del_element(&(result_obj->db_obj->free_list), result_obj->stmt_obj_zval, + (int (*)(void *, void *)) php_sqlite3_compare_stmt_zval_free); } else { sqlite3_reset(result_obj->stmt_obj->stmt); } @@ -1528,25 +1538,29 @@ static int php_sqlite3_authorizer(void *autharg, int access_type, const char *ar } /* }}} */ -/* {{{ php_sqlite3_stmt_free +/* {{{ php_sqlite3_free_list_dtor */ -static void php_sqlite3_stmt_free(void **item) +static void php_sqlite3_free_list_dtor(void **item) { - php_sqlite3_stmt_free_list *free_item = (php_sqlite3_stmt_free_list *)*item; + php_sqlite3_free_list *free_item = (php_sqlite3_free_list *)*item; - zval_dtor(free_item->result_object); - Z_TYPE_P(free_item->result_object) = IS_NULL; - if (free_item->statement_object) { - zval_dtor(free_item->statement_object); - Z_TYPE_P(free_item->statement_object) = IS_NULL; + if (free_item->stmt_obj && free_item->stmt_obj->initialised) { + sqlite3_finalize(free_item->stmt_obj->stmt); + free_item->stmt_obj->initialised = 0; } efree(*item); } /* }}} */ -static int php_sqlite3_compare_stmt_free( php_sqlite3_stmt_free_list **stmt_list, sqlite3_stmt *statement ) /* {{{ */ +static int php_sqlite3_compare_stmt_zval_free( php_sqlite3_free_list **free_list, zval *statement ) /* {{{ */ { - return (statement == (*stmt_list)->stmt); + return ((*free_list)->stmt_obj->initialised && statement == (*free_list)->stmt_obj_zval); +} +/* }}} */ + +static int php_sqlite3_compare_stmt_free( php_sqlite3_free_list **free_list, sqlite3_stmt *statement ) /* {{{ */ +{ + return ((*free_list)->stmt_obj->initialised && statement == (*free_list)->stmt_obj->stmt); } /* }}} */ @@ -1605,8 +1619,8 @@ static void php_sqlite3_stmt_object_free_storage(void *object TSRMLS_DC) /* {{{ } if (intern->initialised) { - intern->initialised = 0; - sqlite3_finalize(intern->stmt); + zend_llist_del_element(&(intern->db_obj->free_list), intern->stmt, + (int (*)(void *, void *)) php_sqlite3_compare_stmt_free); } Z_DELREF_P(intern->db_obj_zval); @@ -1650,8 +1664,8 @@ static zend_object_value php_sqlite3_object_new(zend_class_entry *class_type TSR intern = emalloc(sizeof(php_sqlite3_db_object)); memset(&intern->zo, 0, sizeof(php_sqlite3_db_object)); - /* Non standard stuff, not sure if this is really required still - zend_llist_init(&(intern->stmt_list), sizeof(php_sqlite3_stmt_free_list *), (llist_dtor_func_t)php_sqlite3_stmt_free, 0);*/ + /* Need to keep track of things to free */ + zend_llist_init(&(intern->free_list), sizeof(php_sqlite3_free_list *), (llist_dtor_func_t)php_sqlite3_free_list_dtor, 0); zend_object_std_init(&intern->zo, class_type TSRMLS_CC); zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref,(void *) &tmp, sizeof(zval *)); diff --git a/ext/sqlite3/tests/sqlite3_12_unfinalized_stmt_cleanup.phpt b/ext/sqlite3/tests/sqlite3_12_unfinalized_stmt_cleanup.phpt index 8211ed518e..73cb9a07f4 100644 --- a/ext/sqlite3/tests/sqlite3_12_unfinalized_stmt_cleanup.phpt +++ b/ext/sqlite3/tests/sqlite3_12_unfinalized_stmt_cleanup.phpt @@ -26,8 +26,8 @@ while ($result = $results->fetchArray(SQLITE3_NUM)) echo "Closing database\n"; var_dump($db->close()); -echo "Check result was freed\n"; -var_dump($results); +echo "Check db was closed\n"; +var_dump($results->numColumns()); echo "Done\n"; ?> --EXPECTF-- @@ -45,6 +45,8 @@ array(2) { } Closing database bool(true) -Check result was freed -NULL +Check db was closed + +Warning: SQLite3_result::numColumns(): The SQLite3_result object has not been correctly initialised in %s on line %d +bool(false) Done