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;
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)
PHP_MINIT(sqlite),
NULL,
NULL,
- NULL,
+ PHP_RSHUTDOWN(sqlite),
PHP_MINFO(sqlite),
#if ZEND_MODULE_API_NO >= 20010901
PHP_SQLITE_MODULE_VERSION,
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)
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)
{
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);
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) {
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;
/* 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);
}
/* }}} */
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);
}
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));
}
/* }}} */
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));
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;
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));
}
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));
}
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);
}