summaryrefslogtreecommitdiff
path: root/ext/sqlite/sqlite.c
diff options
context:
space:
mode:
authorWez Furlong <wez@php.net>2003-04-18 16:30:16 +0000
committerWez Furlong <wez@php.net>2003-04-18 16:30:16 +0000
commit8f30d3e54506dcf1540524c2abc9990b9ad17a56 (patch)
treea613ad21d4b5bb237113a96d676ac11b2221c775 /ext/sqlite/sqlite.c
parentd28e06d3b216ea079e9cec53df0746b95f96c0b9 (diff)
downloadphp-git-8f30d3e54506dcf1540524c2abc9990b9ad17a56.tar.gz
Implement sqlite_popen(), which opens persistent connections to an sqlite
database file. (This saves the cost of sqlite reading/parsing the indices). Persistent db connections have any pending transactions rolled back at request shutdown time. (non-persistent connections are automatically rolled back when they are closed). Enhance sqlite_query() and sqlite_unbuffered_query() to use the C api sqlite_exec() when the PHP script does not use the return value. This avoids the extra work and memory allocation for holding result sets when they are not needed.
Diffstat (limited to 'ext/sqlite/sqlite.c')
-rw-r--r--ext/sqlite/sqlite.c214
1 files changed, 176 insertions, 38 deletions
diff --git a/ext/sqlite/sqlite.c b/ext/sqlite/sqlite.c
index b41605537c..40827925cc 100644
--- a/ext/sqlite/sqlite.c
+++ b/ext/sqlite/sqlite.c
@@ -38,7 +38,9 @@
static unsigned char arg3_force_ref[] = {3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
-static int le_sqlite_db, le_sqlite_result;
+static int le_sqlite_db, le_sqlite_result, le_sqlite_pdb;
+
+#define DB_FROM_ZVAL(db, zv) ZEND_FETCH_RESOURCE2(db, struct php_sqlite_db *, zv, -1, "sqlite database", le_sqlite_db, le_sqlite_pdb)
struct php_sqlite_result {
sqlite_vm *vm;
@@ -55,12 +57,14 @@ struct php_sqlite_db {
sqlite *db;
int last_err_code;
int is_persistent;
+ int rsrc_id;
};
enum { PHPSQLITE_ASSOC = 1, PHPSQLITE_NUM = 2, PHPSQLITE_BOTH = PHPSQLITE_ASSOC|PHPSQLITE_NUM };
function_entry sqlite_functions[] = {
PHP_FE(sqlite_open, arg3_force_ref)
+ PHP_FE(sqlite_popen, arg3_force_ref)
PHP_FE(sqlite_close, NULL)
PHP_FE(sqlite_query, NULL)
PHP_FE(sqlite_fetch_array, NULL)
@@ -90,7 +94,7 @@ zend_module_entry sqlite_module_entry = {
PHP_MINIT(sqlite),
NULL,
NULL,
- NULL,
+ PHP_RSHUTDOWN(sqlite),
PHP_MINFO(sqlite),
#if ZEND_MODULE_API_NO >= 20010901
PHP_SQLITE_MODULE_VERSION,
@@ -119,11 +123,14 @@ static void short_sleep(void)
static ZEND_RSRC_DTOR_FUNC(php_sqlite_db_dtor)
{
- struct php_sqlite_db *db = (struct php_sqlite_db*)rsrc->ptr;
-
- sqlite_close(db->db);
+ if (rsrc->ptr) {
+ struct php_sqlite_db *db = (struct php_sqlite_db*)rsrc->ptr;
+ sqlite_close(db->db);
+
+ pefree(db, db->is_persistent);
- pefree(db, db->is_persistent);
+ rsrc->ptr = NULL;
+ }
}
static void real_result_dtor(struct php_sqlite_result *res)
@@ -159,6 +166,30 @@ static ZEND_RSRC_DTOR_FUNC(php_sqlite_result_dtor)
real_result_dtor(res);
}
+static int php_sqlite_forget_persistent_id_numbers(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ struct php_sqlite_db *db;
+
+ if (Z_TYPE_P(rsrc) != le_sqlite_pdb) {
+ return 0;
+ }
+
+ db = (struct php_sqlite_db*)rsrc->ptr;
+
+ db->rsrc_id = FAILURE;
+
+ /* don't leave pending commits hanging around */
+ sqlite_exec(db->db, "ROLLBACK", NULL, NULL, NULL);
+
+ return 0;
+}
+
+PHP_RSHUTDOWN_FUNCTION(sqlite)
+{
+ zend_hash_apply(&EG(persistent_list), (apply_func_t)php_sqlite_forget_persistent_id_numbers TSRMLS_CC);
+ return SUCCESS;
+}
+
/* {{{ PHP Function interface */
static void php_sqlite_function_callback(sqlite_func *func, int argc, const char **argv)
{
@@ -268,6 +299,7 @@ static int php_sqlite_authorizer(void *autharg, int access_type, const char *arg
PHP_MINIT_FUNCTION(sqlite)
{
le_sqlite_db = zend_register_list_destructors_ex(php_sqlite_db_dtor, NULL, "sqlite database", module_number);
+ le_sqlite_pdb = zend_register_list_destructors_ex(NULL, php_sqlite_db_dtor, "sqlite database (persistent)", module_number);
le_sqlite_result = zend_register_list_destructors_ex(php_sqlite_result_dtor, NULL, "sqlite result", module_number);
REGISTER_LONG_CONSTANT("SQLITE_BOTH", PHPSQLITE_BOTH, CONST_CS|CONST_PERSISTENT);
@@ -314,31 +346,12 @@ PHP_MINFO_FUNCTION(sqlite)
php_info_print_table_end();
}
-/* {{{ proto resource sqlite_open(string filename [, int mode, string &errmessage])
- Opens an SQLite database. Will create the database if it does not exist */
-PHP_FUNCTION(sqlite_open)
+static struct php_sqlite_db *php_sqlite_open(char *filename, int mode, char *persistent_id, zval *return_value, zval *errmsg)
{
- int mode = 0666;
- char *filename;
- long filename_len;
- zval *errmsg = NULL;
char *errtext = NULL;
- struct php_sqlite_db *db = NULL;
sqlite *sdb = NULL;
+ struct php_sqlite_db *db = NULL;
- if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz/",
- &filename, &filename_len, &mode, &errmsg)) {
- return;
- }
-
- if (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
- RETURN_FALSE;
- }
-
- if (php_check_open_basedir(filename TSRMLS_CC)) {
- RETURN_FALSE;
- }
-
sdb = sqlite_open(filename, mode, &errtext);
if (sdb == NULL) {
@@ -350,11 +363,12 @@ PHP_FUNCTION(sqlite_open)
sqlite_freemem(errtext);
- RETURN_FALSE;
+ RETVAL_FALSE;
+ return NULL;
}
- db = (struct php_sqlite_db *)emalloc(sizeof(struct php_sqlite_db));
- db->is_persistent = 0;
+ db = (struct php_sqlite_db *)pemalloc(sizeof(struct php_sqlite_db), persistent_id ? 1 : 0);
+ db->is_persistent = persistent_id ? 1 : 0;
db->last_err_code = SQLITE_OK;
db->db = sdb;
@@ -368,8 +382,109 @@ PHP_FUNCTION(sqlite_open)
/* authorizer hook so we can enforce safe mode */
sqlite_set_authorizer(sdb, php_sqlite_authorizer, NULL);
- ZEND_REGISTER_RESOURCE(return_value, db, le_sqlite_db);
+ db->rsrc_id = ZEND_REGISTER_RESOURCE(return_value, db, persistent_id ? le_sqlite_pdb : le_sqlite_db);
+
+ if (persistent_id) {
+ list_entry le;
+
+ Z_TYPE(le) = le_sqlite_pdb;
+ le.ptr = db;
+
+ if (FAILURE == zend_hash_update(&EG(persistent_list), persistent_id,
+ strlen(persistent_id)+1,
+ (void *)&le, sizeof(le), NULL)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to register persistent resource");
+ }
+ }
+
+ return db;
+}
+
+/* {{{ proto resource sqlite_popen(string filename [, int mode, string &errmessage])
+ Opens a persistent handle to an SQLite database. Will create the database if it does not exist */
+PHP_FUNCTION(sqlite_popen)
+{
+ int mode = 0666;
+ char *filename, *fullpath, *hashkey;
+ long filename_len, hashkeylen;
+ zval *errmsg = NULL;
+ char *errtext = NULL;
+ struct php_sqlite_db *db = NULL;
+ list_entry *le;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz/",
+ &filename, &filename_len, &mode, &errmsg)) {
+ return;
+ }
+
+ /* resolve the fully-qualified path name to use as the hash key */
+ fullpath = expand_filepath(filename, NULL TSRMLS_CC);
+
+ if (PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
+ RETURN_FALSE;
+ }
+
+ if (php_check_open_basedir(fullpath TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ hashkeylen = spprintf(&hashkey, 0, "sqlite_pdb_%s:%d", fullpath, mode);
+ /* do we have an existing persistent connection ? */
+ if (SUCCESS == zend_hash_find(&EG(persistent_list), hashkey, hashkeylen+1, (void*)&le)) {
+ if (Z_TYPE_P(le) == le_sqlite_pdb) {
+ db = (struct php_sqlite_db*)le->ptr;
+
+ if (db->rsrc_id == FAILURE) {
+ /* give it a valid resource id for this request */
+ db->rsrc_id = ZEND_REGISTER_RESOURCE(return_value, db, le_sqlite_pdb);
+ } else {
+ /* already accessed this request; map it */
+ ZVAL_RESOURCE(return_value, db->rsrc_id);
+ }
+
+ /* all set */
+ efree(fullpath);
+ efree(hashkey);
+ return;
+ }
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "some other type of persistent resource is using this hash key!?");
+ RETURN_FALSE;
+ }
+
+ /* now we need to open the database */
+ php_sqlite_open(fullpath, mode, hashkey, return_value, errmsg);
+
+ efree(fullpath);
+ efree(hashkey);
+}
+/* }}} */
+
+
+/* {{{ proto resource sqlite_open(string filename [, int mode, string &errmessage])
+ Opens an SQLite database. Will create the database if it does not exist */
+PHP_FUNCTION(sqlite_open)
+{
+ int mode = 0666;
+ char *filename;
+ long filename_len;
+ zval *errmsg = NULL;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz/",
+ &filename, &filename_len, &mode, &errmsg)) {
+ return;
+ }
+
+ if (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
+ RETURN_FALSE;
+ }
+
+ if (php_check_open_basedir(filename TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ php_sqlite_open(filename, mode, NULL, return_value, errmsg);
}
/* }}} */
@@ -385,7 +500,7 @@ PHP_FUNCTION(sqlite_busy_timeout)
return;
}
- ZEND_FETCH_RESOURCE(db, struct php_sqlite_db *, &zdb, -1, "sqlite database", le_sqlite_db);
+ DB_FROM_ZVAL(db, &zdb);
sqlite_busy_timeout(db->db, ms);
}
@@ -402,7 +517,8 @@ PHP_FUNCTION(sqlite_close)
return;
}
- ZEND_FETCH_RESOURCE(db, struct php_sqlite_db *, &zdb, -1, "sqlite database", le_sqlite_db);
+ DB_FROM_ZVAL(db, &zdb);
+
zend_list_delete(Z_RESVAL_P(zdb));
}
/* }}} */
@@ -425,7 +541,18 @@ PHP_FUNCTION(sqlite_unbuffered_query)
return;
}
- ZEND_FETCH_RESOURCE(db, struct php_sqlite_db *, &zdb, -1, "sqlite database", le_sqlite_db);
+ DB_FROM_ZVAL(db, &zdb);
+
+ /* avoid doing work if we can */
+ if (!return_value_used) {
+ db->last_err_code = sqlite_exec(db->db, sql, NULL, NULL, &errtext);
+
+ if (db->last_err_code != SQLITE_OK) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext);
+ sqlite_freemem(errtext);
+ }
+ return;
+ }
memset(&res, 0, sizeof(res));
@@ -467,8 +594,19 @@ PHP_FUNCTION(sqlite_query)
return;
}
- ZEND_FETCH_RESOURCE(db, struct php_sqlite_db *, &zdb, -1, "sqlite database", le_sqlite_db);
+ DB_FROM_ZVAL(db, &zdb);
+ /* avoid doing work if we can */
+ if (!return_value_used) {
+ db->last_err_code = sqlite_exec(db->db, sql, NULL, NULL, &errtext);
+
+ if (db->last_err_code != SQLITE_OK) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext);
+ sqlite_freemem(errtext);
+ }
+ return;
+ }
+
memset(&res, 0, sizeof(res));
res.buffered = 1;
@@ -661,7 +799,7 @@ PHP_FUNCTION(sqlite_changes)
return;
}
- ZEND_FETCH_RESOURCE(db, struct php_sqlite_db *, &zdb, -1, "sqlite database", le_sqlite_db);
+ DB_FROM_ZVAL(db, &zdb);
RETURN_LONG(sqlite_changes(db->db));
}
@@ -678,7 +816,7 @@ PHP_FUNCTION(sqlite_last_insert_rowid)
return;
}
- ZEND_FETCH_RESOURCE(db, struct php_sqlite_db *, &zdb, -1, "sqlite database", le_sqlite_db);
+ DB_FROM_ZVAL(db, &zdb);
RETURN_LONG(sqlite_last_insert_rowid(db->db));
}
@@ -818,7 +956,7 @@ PHP_FUNCTION(sqlite_last_error)
return;
}
- ZEND_FETCH_RESOURCE(db, struct php_sqlite_db *, &zdb, -1, "sqlite database", le_sqlite_db);
+ DB_FROM_ZVAL(db, &zdb);
RETURN_LONG(db->last_err_code);
}