From bcdd90296569b05e2daeb3e94a3ee8757b9eb635 Mon Sep 17 00:00:00 2001 From: bohwaz Date: Tue, 11 Apr 2023 14:02:03 +0200 Subject: [PATCH 1/8] Deprecate warnings in SQLite3, change returned exception class to SQLite3Exception --- ext/sqlite3/sqlite3.c | 158 ++++++++++-------- ext/sqlite3/sqlite3.stub.php | 4 + ext/sqlite3/sqlite3_arginfo.h | 17 +- .../tests/sqlite3_enable_exceptions.phpt | 2 + 4 files changed, 113 insertions(+), 68 deletions(-) diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index ef594208b8d51..ff648effd39e2 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -28,6 +28,7 @@ #include #include "zend_exceptions.h" +#include "ext/spl/spl_exceptions.h" #include "SAPI.h" #include "sqlite3_arginfo.h" @@ -38,28 +39,6 @@ static int php_sqlite3_authorizer(void *autharg, int action, const char *arg1, c static void sqlite3_param_dtor(zval *data); static int php_sqlite3_compare_stmt_zval_free(php_sqlite3_free_list **free_list, zval *statement); -/* {{{ Error Handler */ -static void php_sqlite3_error(php_sqlite3_db_object *db_obj, const char *format, ...) -{ - va_list arg; - char *message; - - va_start(arg, format); - vspprintf(&message, 0, format, arg); - va_end(arg); - - if (db_obj && db_obj->exception) { - zend_throw_exception(zend_ce_exception, message, 0); - } else { - php_error_docref(NULL, E_WARNING, "%s", message); - } - - if (message) { - efree(message); - } -} -/* }}} */ - #define SQLITE3_CHECK_INITIALIZED(db_obj, member, class_name) \ if (!(db_obj) || !(member)) { \ zend_throw_error(NULL, "The " #class_name " object has not been correctly initialised or is already closed"); \ @@ -87,10 +66,33 @@ static zend_object_handlers sqlite3_stmt_object_handlers; static zend_object_handlers sqlite3_result_object_handlers; /* Class entries */ +zend_class_entry *php_sqlite3_exception_ce; zend_class_entry *php_sqlite3_sc_entry; zend_class_entry *php_sqlite3_stmt_entry; zend_class_entry *php_sqlite3_result_entry; +/* {{{ Error Handler */ +static void php_sqlite3_error(php_sqlite3_db_object *db_obj, int errcode, const char *format, ...) +{ + va_list arg; + char *message; + + va_start(arg, format); + vspprintf(&message, 0, format, arg); + va_end(arg); + + if (db_obj && db_obj->exception && php_sqlite3_exception_ce) { + zend_throw_exception(php_sqlite3_exception_ce, message, errcode); + } else { + php_error_docref(NULL, E_WARNING, "%s", message); + } + + if (message) { + efree(message); + } +} +/* }}} */ + /* {{{ Opens a SQLite 3 Database, if the build includes encryption then it will attempt to use the key. */ PHP_METHOD(SQLite3, open) { @@ -188,7 +190,7 @@ PHP_METHOD(SQLite3, close) if(db_obj->db) { errcode = sqlite3_close(db_obj->db); if (errcode != SQLITE_OK) { - php_sqlite3_error(db_obj, "Unable to close database: %d, %s", errcode, sqlite3_errmsg(db_obj->db)); + php_sqlite3_error(db_obj, errcode, "Unable to close database: %s", sqlite3_errmsg(db_obj->db)); RETURN_FALSE; } } @@ -204,6 +206,7 @@ PHP_METHOD(SQLite3, exec) { php_sqlite3_db_object *db_obj; zval *object = ZEND_THIS; + int errcode; zend_string *sql; char *errtext = NULL; db_obj = Z_SQLITE3_DB_P(object); @@ -214,8 +217,10 @@ PHP_METHOD(SQLite3, exec) SQLITE3_CHECK_INITIALIZED(db_obj, db_obj->initialised, SQLite3) - if (sqlite3_exec(db_obj->db, ZSTR_VAL(sql), NULL, NULL, &errtext) != SQLITE_OK) { - php_sqlite3_error(db_obj, "%s", errtext); + errcode = sqlite3_exec(db_obj->db, ZSTR_VAL(sql), NULL, NULL, &errtext); + + if (errcode != SQLITE_OK) { + php_sqlite3_error(db_obj, errcode, "%s", errtext); sqlite3_free(errtext); RETURN_FALSE; } @@ -367,7 +372,7 @@ PHP_METHOD(SQLite3, busyTimeout) #ifdef SQLITE_ENABLE_API_ARMOR return_code = sqlite3_busy_timeout(db_obj->db, ms); if (return_code != SQLITE_OK) { - php_sqlite3_error(db_obj, "Unable to set busy timeout: %d, %s", return_code, sqlite3_errmsg(db_obj->db)); + php_sqlite3_error(db_obj, sqlite3_errcode(db_obj->db), "Unable to set busy timeout: %s", sqlite3_errmsg(db_obj->db)); RETURN_FALSE; } #else @@ -400,18 +405,18 @@ PHP_METHOD(SQLite3, loadExtension) if ((strncmp(sapi_module.name, "cgi", 3) != 0) && (strcmp(sapi_module.name, "cli") != 0) && (strncmp(sapi_module.name, "embed", 5) != 0) - ) { php_sqlite3_error(db_obj, "Not supported in multithreaded Web servers"); + ) { php_sqlite3_error(db_obj, 0, "Not supported in multithreaded Web servers"); RETURN_FALSE; } #endif if (!SQLITE3G(extension_dir)) { - php_sqlite3_error(db_obj, "SQLite Extension are disabled"); + php_sqlite3_error(db_obj, 0, "SQLite Extensions are disabled"); RETURN_FALSE; } if (extension_len == 0) { - php_sqlite3_error(db_obj, "Empty string as an extension"); + php_sqlite3_error(db_obj, 0, "Empty string as an extension"); RETURN_FALSE; } @@ -425,7 +430,7 @@ PHP_METHOD(SQLite3, loadExtension) } if (!VCWD_REALPATH(lib_path, fullpath)) { - php_sqlite3_error(db_obj, "Unable to load extension at '%s'", lib_path); + php_sqlite3_error(db_obj, 0, "Unable to load extension at '%s'", lib_path); efree(lib_path); RETURN_FALSE; } @@ -433,14 +438,14 @@ PHP_METHOD(SQLite3, loadExtension) efree(lib_path); if (strncmp(fullpath, extension_dir, extension_dir_len) != 0) { - php_sqlite3_error(db_obj, "Unable to open extensions outside the defined directory"); + php_sqlite3_error(db_obj, 0, "Unable to open extensions outside the defined directory"); RETURN_FALSE; } /* Extension loading should only be enabled for when we attempt to load */ sqlite3_enable_load_extension(db_obj->db, 1); if (sqlite3_load_extension(db_obj->db, fullpath, 0, &errtext) != SQLITE_OK) { - php_sqlite3_error(db_obj, "%s", errtext); + php_sqlite3_error(db_obj, 0, "%s", errtext); sqlite3_free(errtext); sqlite3_enable_load_extension(db_obj->db, 0); RETURN_FALSE; @@ -520,7 +525,7 @@ PHP_METHOD(SQLite3, prepare) errcode = sqlite3_prepare_v2(db_obj->db, ZSTR_VAL(sql), ZSTR_LEN(sql), &(stmt_obj->stmt), NULL); if (errcode != SQLITE_OK) { - php_sqlite3_error(db_obj, "Unable to prepare statement: %d, %s", errcode, sqlite3_errmsg(db_obj->db)); + php_sqlite3_error(db_obj, errcode, "Unable to prepare statement: %s", sqlite3_errmsg(db_obj->db)); zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -560,8 +565,10 @@ PHP_METHOD(SQLite3, query) /* If there was no return value then just execute the query */ if (!USED_RET()) { - if (sqlite3_exec(db_obj->db, ZSTR_VAL(sql), NULL, NULL, &errtext) != SQLITE_OK) { - php_sqlite3_error(db_obj, "%s", errtext); + int errcode; + errcode = sqlite3_exec(db_obj->db, ZSTR_VAL(sql), NULL, NULL, &errtext); + if (errcode != SQLITE_OK) { + php_sqlite3_error(db_obj, errcode, "%s", errtext); sqlite3_free(errtext); } RETURN_FALSE; @@ -574,7 +581,7 @@ PHP_METHOD(SQLite3, query) return_code = sqlite3_prepare_v2(db_obj->db, ZSTR_VAL(sql), ZSTR_LEN(sql), &(stmt_obj->stmt), NULL); if (return_code != SQLITE_OK) { - php_sqlite3_error(db_obj, "Unable to prepare statement: %d, %s", return_code, sqlite3_errmsg(db_obj->db)); + php_sqlite3_error(db_obj, return_code, "Unable to prepare statement: %s", sqlite3_errmsg(db_obj->db)); zval_ptr_dtor(&stmt); RETURN_FALSE; } @@ -605,7 +612,7 @@ PHP_METHOD(SQLite3, query) } default: if (!EG(exception)) { - php_sqlite3_error(db_obj, "Unable to execute statement: %s", sqlite3_errmsg(db_obj->db)); + php_sqlite3_error(db_obj, sqlite3_errcode(db_obj->db), "Unable to execute statement: %s", sqlite3_errmsg(db_obj->db)); } sqlite3_finalize(stmt_obj->stmt); stmt_obj->initialised = 0; @@ -676,8 +683,10 @@ PHP_METHOD(SQLite3, querySingle) /* If there was no return value then just execute the query */ if (!USED_RET()) { - if (sqlite3_exec(db_obj->db, ZSTR_VAL(sql), NULL, NULL, &errtext) != SQLITE_OK) { - php_sqlite3_error(db_obj, "%s", errtext); + int errcode; + errcode = sqlite3_exec(db_obj->db, ZSTR_VAL(sql), NULL, NULL, &errtext); + if (errcode != SQLITE_OK) { + php_sqlite3_error(db_obj, errcode, "%s", errtext); sqlite3_free(errtext); } RETURN_FALSE; @@ -685,7 +694,7 @@ PHP_METHOD(SQLite3, querySingle) return_code = sqlite3_prepare_v2(db_obj->db, ZSTR_VAL(sql), ZSTR_LEN(sql), &stmt, NULL); if (return_code != SQLITE_OK) { - php_sqlite3_error(db_obj, "Unable to prepare statement: %d, %s", return_code, sqlite3_errmsg(db_obj->db)); + php_sqlite3_error(db_obj, return_code, "Unable to prepare statement: %s", sqlite3_errmsg(db_obj->db)); RETURN_FALSE; } @@ -718,7 +727,7 @@ PHP_METHOD(SQLite3, querySingle) } default: if (!EG(exception)) { - php_sqlite3_error(db_obj, "Unable to execute statement: %s", sqlite3_errmsg(db_obj->db)); + php_sqlite3_error(db_obj, sqlite3_errcode(db_obj->db), "Unable to execute statement: %s", sqlite3_errmsg(db_obj->db)); } RETVAL_FALSE; } @@ -909,7 +918,7 @@ static int php_sqlite3_callback_compare(void *coll, int a_len, const void *a, in //retval ought to contain a ZVAL_LONG by now // (the result of a comparison, i.e. most likely -1, 0, or 1) //I suppose we could accept any scalar return type, though. - php_error_docref(NULL, E_WARNING, "An error occurred while invoking the compare callback (invalid return type). Collation behaviour is undefined."); + php_sqlite3_error(NULL, 0, "An error occurred while invoking the compare callback (invalid return type). Collation behaviour is undefined."); } else { ret = Z_LVAL(retval); } @@ -1081,12 +1090,12 @@ static ssize_t php_sqlite3_stream_write(php_stream *stream, const char *buf, siz php_stream_sqlite3_data *sqlite3_stream = (php_stream_sqlite3_data *) stream->abstract; if (sqlite3_stream->flags & SQLITE_OPEN_READONLY) { - php_error_docref(NULL, E_WARNING, "Can't write to blob stream: is open as read only"); + php_sqlite3_error(NULL, 0, "Can't write to blob stream: is open as read only"); return -1; } if (sqlite3_stream->position + count > sqlite3_stream->size) { - php_error_docref(NULL, E_WARNING, "It is not possible to increase the size of a BLOB"); + php_sqlite3_error(NULL, 0, "It is not possible to increase the size of a BLOB"); return -1; } @@ -1252,7 +1261,7 @@ PHP_METHOD(SQLite3, openBlob) sqlite_flags = (flags & SQLITE_OPEN_READWRITE) ? 1 : 0; if (sqlite3_blob_open(db_obj->db, dbname, table, column, rowid, sqlite_flags, &blob) != SQLITE_OK) { - php_sqlite3_error(db_obj, "Unable to open blob: %s", sqlite3_errmsg(db_obj->db)); + php_sqlite3_error(db_obj, sqlite3_errcode(db_obj->db), "Unable to open blob: %s", sqlite3_errmsg(db_obj->db)); RETURN_FALSE; } @@ -1291,6 +1300,10 @@ PHP_METHOD(SQLite3, enableExceptions) RETVAL_BOOL(db_obj->exception); + if (!enableExceptions) { + php_error_docref("ref.sqlite3", E_DEPRECATED, "Use of warnings for SQLite3 is deprecated"); + } + db_obj->exception = enableExceptions; } /* }}} */ @@ -1372,13 +1385,13 @@ PHP_METHOD(SQLite3, backup) if (rc != SQLITE_OK) { if (rc == SQLITE_BUSY) { - php_sqlite3_error(source_obj, "Backup failed: source database is busy"); + php_sqlite3_error(source_obj, rc, "Backup failed: source database is busy"); } else if (rc == SQLITE_LOCKED) { - php_sqlite3_error(source_obj, "Backup failed: source database is locked"); + php_sqlite3_error(source_obj, rc, "Backup failed: source database is locked"); } else { - php_sqlite3_error(source_obj, "Backup failed: %d, %s", rc, sqlite3_errmsg(source_obj->db)); + php_sqlite3_error(source_obj, rc, "Backup failed: %s", sqlite3_errmsg(source_obj->db)); } RETURN_FALSE; } @@ -1436,7 +1449,7 @@ PHP_METHOD(SQLite3Stmt, reset) SQLITE3_CHECK_INITIALIZED_STMT(stmt_obj->stmt, SQLite3Stmt); if (sqlite3_reset(stmt_obj->stmt) != SQLITE_OK) { - php_sqlite3_error(stmt_obj->db_obj, "Unable to reset statement: %s", sqlite3_errmsg(sqlite3_db_handle(stmt_obj->stmt))); + php_sqlite3_error(stmt_obj->db_obj, sqlite3_errcode(sqlite3_db_handle(stmt_obj->stmt)), "Unable to reset statement: %s", sqlite3_errmsg(sqlite3_db_handle(stmt_obj->stmt))); RETURN_FALSE; } RETURN_TRUE; @@ -1456,7 +1469,7 @@ PHP_METHOD(SQLite3Stmt, clear) SQLITE3_CHECK_INITIALIZED_STMT(stmt_obj->stmt, SQLite3Stmt); if (sqlite3_clear_bindings(stmt_obj->stmt) != SQLITE_OK) { - php_sqlite3_error(stmt_obj->db_obj, "Unable to clear statement: %s", sqlite3_errmsg(sqlite3_db_handle(stmt_obj->stmt))); + php_sqlite3_error(stmt_obj->db_obj, sqlite3_errcode(sqlite3_db_handle(stmt_obj->stmt)), "Unable to clear statement: %s", sqlite3_errmsg(sqlite3_db_handle(stmt_obj->stmt))); RETURN_FALSE; } @@ -1509,7 +1522,7 @@ static int php_sqlite3_bind_params(php_sqlite3_stmt *stmt_obj) /* {{{ */ if (Z_TYPE_P(parameter) == IS_NULL) { return_code = sqlite3_bind_null(stmt_obj->stmt, param->param_number); if (return_code != SQLITE_OK) { - php_sqlite3_error(stmt_obj->db_obj, "Unable to bind parameter number " ZEND_LONG_FMT " (%d)", param->param_number, return_code); + php_sqlite3_error(stmt_obj->db_obj, return_code, "Unable to bind parameter number " ZEND_LONG_FMT, param->param_number); } continue; } @@ -1523,7 +1536,7 @@ static int php_sqlite3_bind_params(php_sqlite3_stmt *stmt_obj) /* {{{ */ return_code = sqlite3_bind_int(stmt_obj->stmt, param->param_number, Z_LVAL_P(parameter)); #endif if (return_code != SQLITE_OK) { - php_sqlite3_error(stmt_obj->db_obj, "Unable to bind parameter number " ZEND_LONG_FMT " (%d)", param->param_number, return_code); + php_sqlite3_error(stmt_obj->db_obj, return_code, "Unable to bind parameter number " ZEND_LONG_FMT, param->param_number); } break; @@ -1531,7 +1544,7 @@ static int php_sqlite3_bind_params(php_sqlite3_stmt *stmt_obj) /* {{{ */ convert_to_double(parameter); return_code = sqlite3_bind_double(stmt_obj->stmt, param->param_number, Z_DVAL_P(parameter)); if (return_code != SQLITE_OK) { - php_sqlite3_error(stmt_obj->db_obj, "Unable to bind parameter number " ZEND_LONG_FMT " (%d)", param->param_number, return_code); + php_sqlite3_error(stmt_obj->db_obj, return_code, "Unable to bind parameter number " ZEND_LONG_FMT, param->param_number); } break; @@ -1542,7 +1555,7 @@ static int php_sqlite3_bind_params(php_sqlite3_stmt *stmt_obj) /* {{{ */ if (Z_TYPE_P(parameter) == IS_RESOURCE) { php_stream_from_zval_no_verify(stream, parameter); if (stream == NULL) { - php_sqlite3_error(stmt_obj->db_obj, "Unable to read stream for parameter %ld", param->param_number); + php_sqlite3_error(stmt_obj->db_obj, 0, "Unable to read stream for parameter %ld", param->param_number); return FAILURE; } buffer = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0); @@ -1554,12 +1567,12 @@ static int php_sqlite3_bind_params(php_sqlite3_stmt *stmt_obj) /* {{{ */ return_code = sqlite3_bind_blob(stmt_obj->stmt, param->param_number, ZSTR_VAL(buffer), ZSTR_LEN(buffer), SQLITE_TRANSIENT); zend_string_release_ex(buffer, 0); if (return_code != SQLITE_OK) { - php_sqlite3_error(stmt_obj->db_obj, "Unable to bind parameter number " ZEND_LONG_FMT " (%d)", param->param_number, return_code); + php_sqlite3_error(stmt_obj->db_obj, return_code, "Unable to bind parameter number " ZEND_LONG_FMT, param->param_number); } } else { return_code = sqlite3_bind_null(stmt_obj->stmt, param->param_number); if (return_code != SQLITE_OK) { - php_sqlite3_error(stmt_obj->db_obj, "Unable to bind parameter number " ZEND_LONG_FMT " (%d)", param->param_number, return_code); + php_sqlite3_error(stmt_obj->db_obj, return_code, "Unable to bind parameter number " ZEND_LONG_FMT, param->param_number); } } break; @@ -1572,7 +1585,7 @@ static int php_sqlite3_bind_params(php_sqlite3_stmt *stmt_obj) /* {{{ */ } return_code = sqlite3_bind_text(stmt_obj->stmt, param->param_number, ZSTR_VAL(str), ZSTR_LEN(str), SQLITE_TRANSIENT); if (return_code != SQLITE_OK) { - php_sqlite3_error(stmt_obj->db_obj, "Unable to bind parameter number " ZEND_LONG_FMT " (%d)", param->param_number, return_code); + php_sqlite3_error(stmt_obj->db_obj, return_code, "Unable to bind parameter number " ZEND_LONG_FMT, param->param_number); } zend_string_release(str); break; @@ -1581,12 +1594,12 @@ static int php_sqlite3_bind_params(php_sqlite3_stmt *stmt_obj) /* {{{ */ case SQLITE_NULL: return_code = sqlite3_bind_null(stmt_obj->stmt, param->param_number); if (return_code != SQLITE_OK) { - php_sqlite3_error(stmt_obj->db_obj, "Unable to bind parameter number " ZEND_LONG_FMT " (%d)", param->param_number, return_code); + php_sqlite3_error(stmt_obj->db_obj, return_code, "Unable to bind parameter number " ZEND_LONG_FMT, param->param_number); } break; default: - php_sqlite3_error(stmt_obj->db_obj, "Unknown parameter type: %pd for parameter %pd", param->type, param->param_number); + php_sqlite3_error(stmt_obj->db_obj, 0, "Unknown parameter type: %pd for parameter %pd", param->type, param->param_number); return FAILURE; } } ZEND_HASH_FOREACH_END(); @@ -1626,7 +1639,7 @@ PHP_METHOD(SQLite3Stmt, getSQL) RETVAL_STRING(sql); sqlite3_free(sql); #else - php_sqlite3_error(stmt_obj->db_obj, "The expanded parameter requires SQLite3 >= 3.14 and %s is installed", sqlite3_libversion()); + php_sqlite3_error(stmt_obj->db_obj, 0, "The expanded parameter requires SQLite3 >= 3.14 and %s is installed", sqlite3_libversion()); RETURN_FALSE; #endif } else { @@ -1808,7 +1821,7 @@ PHP_METHOD(SQLite3Stmt, execute) ZEND_FALLTHROUGH; default: if (!EG(exception)) { - php_sqlite3_error(stmt_obj->db_obj, "Unable to execute statement: %s", sqlite3_errmsg(sqlite3_db_handle(stmt_obj->stmt))); + php_sqlite3_error(stmt_obj->db_obj, sqlite3_errcode(sqlite3_db_handle(stmt_obj->stmt)), "Unable to execute statement: %s", sqlite3_errmsg(sqlite3_db_handle(stmt_obj->stmt))); } zval_ptr_dtor(return_value); RETURN_FALSE; @@ -1851,7 +1864,7 @@ PHP_METHOD(SQLite3Stmt, __construct) errcode = sqlite3_prepare_v2(db_obj->db, ZSTR_VAL(sql), ZSTR_LEN(sql), &(stmt_obj->stmt), NULL); if (errcode != SQLITE_OK) { - php_sqlite3_error(db_obj, "Unable to prepare statement: %d, %s", errcode, sqlite3_errmsg(db_obj->db)); + php_sqlite3_error(db_obj, errcode, "Unable to prepare statement: %s", sqlite3_errmsg(db_obj->db)); zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -1997,7 +2010,7 @@ PHP_METHOD(SQLite3Result, fetchArray) break; default: - php_sqlite3_error(result_obj->db_obj, "Unable to execute statement: %s", sqlite3_errmsg(sqlite3_db_handle(result_obj->stmt_obj->stmt))); + php_sqlite3_error(result_obj->db_obj, sqlite3_errcode(sqlite3_db_handle(result_obj->stmt_obj->stmt)), "Unable to execute statement: %s", sqlite3_errmsg(sqlite3_db_handle(result_obj->stmt_obj->stmt))); } } /* }}} */ @@ -2127,15 +2140,15 @@ static int php_sqlite3_authorizer(void *autharg, int action, const char *arg1, c zend_call_known_fcc(&db_obj->authorizer_fcc, &retval, /* argc */ 5, argv, /* named_params */ NULL); if (Z_ISUNDEF(retval)) { - php_sqlite3_error(db_obj, "An error occurred while invoking the authorizer callback"); + php_sqlite3_error(db_obj, 0, "An error occurred while invoking the authorizer callback"); } else { if (Z_TYPE(retval) != IS_LONG) { - php_sqlite3_error(db_obj, "The authorizer callback returned an invalid type: expected int"); + php_sqlite3_error(db_obj, 0, "The authorizer callback returned an invalid type: expected int"); } else { authreturn = Z_LVAL(retval); if (authreturn != SQLITE_OK && authreturn != SQLITE_IGNORE && authreturn != SQLITE_DENY) { - php_sqlite3_error(db_obj, "The authorizer callback returned an invalid value"); + php_sqlite3_error(db_obj, 0, "The authorizer callback returned an invalid value: %d", authreturn); authreturn = SQLITE_DENY; } } @@ -2349,6 +2362,9 @@ static void sqlite3_param_dtor(zval *data) /* {{{ */ /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(sqlite3) { + /* Register SQLite3Exception class */ + php_sqlite3_exception_ce = register_class_SQLite3Exception(spl_ce_RuntimeException); + #ifdef ZTS /* Refuse to load if this wasn't a threasafe library loaded */ if (!sqlite3_threadsafe()) { @@ -2414,6 +2430,13 @@ PHP_MINFO_FUNCTION(sqlite3) } /* }}} */ +/* {{{ */ +static const zend_module_dep sqlite3_deps[] = { + ZEND_MOD_REQUIRED("spl") + ZEND_MOD_END +}; +/* }}} */ + /* {{{ PHP_GINIT_FUNCTION */ static PHP_GINIT_FUNCTION(sqlite3) { @@ -2426,7 +2449,8 @@ static PHP_GINIT_FUNCTION(sqlite3) /* {{{ sqlite3_module_entry */ zend_module_entry sqlite3_module_entry = { - STANDARD_MODULE_HEADER, + STANDARD_MODULE_HEADER_EX,NULL, + sqlite3_deps, "sqlite3", NULL, PHP_MINIT(sqlite3), diff --git a/ext/sqlite3/sqlite3.stub.php b/ext/sqlite3/sqlite3.stub.php index 639a5fb782fc7..9a6b28b78ea48 100644 --- a/ext/sqlite3/sqlite3.stub.php +++ b/ext/sqlite3/sqlite3.stub.php @@ -68,6 +68,10 @@ const SQLITE3_DETERMINISTIC = UNKNOWN; #endif +class SQLite3Exception extends \RuntimeException +{ +} + /** @not-serializable */ class SQLite3 { diff --git a/ext/sqlite3/sqlite3_arginfo.h b/ext/sqlite3/sqlite3_arginfo.h index b99134ed1f24b..9ea67cff9e7f6 100644 --- a/ext/sqlite3/sqlite3_arginfo.h +++ b/ext/sqlite3/sqlite3_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 61f4a2611ed8cef37003610991e357b0f227bec9 */ + * Stub hash: ffe03d1df12ee9806bcbfcaa26818dc9177e0bd3 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -211,6 +211,11 @@ ZEND_METHOD(SQLite3Result, reset); ZEND_METHOD(SQLite3Result, finalize); +static const zend_function_entry class_SQLite3Exception_methods[] = { + ZEND_FE_END +}; + + static const zend_function_entry class_SQLite3_methods[] = { ZEND_MALIAS(SQLite3, __construct, open, arginfo_class_SQLite3___construct, ZEND_ACC_PUBLIC) ZEND_ME(SQLite3, open, arginfo_class_SQLite3_open, ZEND_ACC_PUBLIC) @@ -288,6 +293,16 @@ static void register_sqlite3_symbols(int module_number) #endif } +static zend_class_entry *register_class_SQLite3Exception(zend_class_entry *class_entry_RuntimeException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "SQLite3Exception", class_SQLite3Exception_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_RuntimeException); + + return class_entry; +} + static zend_class_entry *register_class_SQLite3(void) { zend_class_entry ce, *class_entry; diff --git a/ext/sqlite3/tests/sqlite3_enable_exceptions.phpt b/ext/sqlite3/tests/sqlite3_enable_exceptions.phpt index 0199b798e020e..a072f31c94763 100644 --- a/ext/sqlite3/tests/sqlite3_enable_exceptions.phpt +++ b/ext/sqlite3/tests/sqlite3_enable_exceptions.phpt @@ -24,6 +24,8 @@ echo "Done\n"; --EXPECTF-- bool(false) no such table: non_existent_table + +Deprecated: SQLite3::enableExceptions(): Use of warnings for SQLite3 is deprecated in %s bool(true) Warning: SQLite3::query(): no such table: non_existent_table in %s on line %d From f35c6d4b8eed8c45fca969f7b636130014a88ed0 Mon Sep 17 00:00:00 2001 From: bohwaz Date: Tue, 11 Apr 2023 14:02:44 +0200 Subject: [PATCH 2/8] Error code was removed from warnings --- ext/sqlite3/tests/bug69972.phpt | 2 +- ext/sqlite3/tests/gh9032.phpt | 4 ++-- ext/sqlite3/tests/sqlite3_20_error.phpt | 2 +- ext/sqlite3/tests/sqlite3_34_load_extension_ext_dir.phpt | 2 +- ext/sqlite3/tests/sqlite3_40_setauthorizer.phpt | 8 ++++---- ext/sqlite3/tests/sqlite3_defensive.phpt | 2 +- ext/sqlite3/tests/sqlite3_prepare_faultystmt.phpt | 2 +- ext/sqlite3/tests/sqlite3_trampoline_setauthorizer.phpt | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ext/sqlite3/tests/bug69972.phpt b/ext/sqlite3/tests/bug69972.phpt index 3c926a11ab5bb..24ec4ed771914 100644 --- a/ext/sqlite3/tests/bug69972.phpt +++ b/ext/sqlite3/tests/bug69972.phpt @@ -18,7 +18,7 @@ echo "Error Msg: " . $db->lastErrorMsg() . "\n"; --EXPECTF-- SELECTING from invalid table -Warning: SQLite3::query(): Unable to prepare statement: 1, no such table: non_existent_table in %sbug69972.php on line %d +Warning: SQLite3::query(): Unable to prepare statement: no such table: non_existent_table in %sbug69972.php on line %d Closing database bool(true) Done diff --git a/ext/sqlite3/tests/gh9032.phpt b/ext/sqlite3/tests/gh9032.phpt index 069e080406403..34ca992ab26b3 100644 --- a/ext/sqlite3/tests/gh9032.phpt +++ b/ext/sqlite3/tests/gh9032.phpt @@ -17,10 +17,10 @@ try { $st->bindValue("a", ":memory:"); $st->execute(); var_dump($db->exec('create table db2.r (id int)')); -} catch (Exception $ex) { +} catch (SQLite3Exception $ex) { echo $ex->getMessage(), PHP_EOL; } ?> --EXPECT-- bool(true) -Unable to prepare statement: 23, not authorized +Unable to prepare statement: not authorized diff --git a/ext/sqlite3/tests/sqlite3_20_error.phpt b/ext/sqlite3/tests/sqlite3_20_error.phpt index f5fb9a890c064..6fe59be778061 100644 --- a/ext/sqlite3/tests/sqlite3_20_error.phpt +++ b/ext/sqlite3/tests/sqlite3_20_error.phpt @@ -20,7 +20,7 @@ echo "Done\n"; --EXPECTF-- SELECTING from invalid table -Warning: SQLite3::query(): Unable to prepare statement: 1, no such table: non_existent_table in %s on line %d +Warning: SQLite3::query(): Unable to prepare statement: no such table: non_existent_table in %s on line %d Error Code: 1 Error Msg: no such table: non_existent_table Closing database diff --git a/ext/sqlite3/tests/sqlite3_34_load_extension_ext_dir.phpt b/ext/sqlite3/tests/sqlite3_34_load_extension_ext_dir.phpt index 1135d1b702b15..e23d9a8dad849 100644 --- a/ext/sqlite3/tests/sqlite3_34_load_extension_ext_dir.phpt +++ b/ext/sqlite3/tests/sqlite3_34_load_extension_ext_dir.phpt @@ -24,4 +24,4 @@ try { ?> --EXPECTF-- -Warning: SQLite3::loadExtension(): SQLite Extension are disabled in %s on line %d +Warning: SQLite3::loadExtension(): SQLite Extensions are disabled in %s on line %d diff --git a/ext/sqlite3/tests/sqlite3_40_setauthorizer.phpt b/ext/sqlite3/tests/sqlite3_40_setauthorizer.phpt index 73fcc790c0f6a..a4f30040334c3 100644 --- a/ext/sqlite3/tests/sqlite3_40_setauthorizer.phpt +++ b/ext/sqlite3/tests/sqlite3_40_setauthorizer.phpt @@ -71,7 +71,7 @@ try { ?> --EXPECT-- int(1) -Unable to prepare statement: 23, not authorized +Unable to prepare statement: not authorized bool(true) int(42) string(6) "SELECT" @@ -98,7 +98,7 @@ string(28) "sqlite_master,rootpage,main," string(4) "READ" string(28) "sqlite_master,rootpage,main," bool(true) -Unable to prepare statement: 23, not authorized +Unable to prepare statement: not authorized The authorizer callback returned an invalid type: expected int -Unable to prepare statement: 23, not authorized -The authorizer callback returned an invalid value +Unable to prepare statement: not authorized +The authorizer callback returned an invalid value: 4200 diff --git a/ext/sqlite3/tests/sqlite3_defensive.phpt b/ext/sqlite3/tests/sqlite3_defensive.phpt index 033e661d8a393..6614388ee226a 100644 --- a/ext/sqlite3/tests/sqlite3_defensive.phpt +++ b/ext/sqlite3/tests/sqlite3_defensive.phpt @@ -37,6 +37,6 @@ bool(true) int(1) int(1) -Warning: SQLite3::querySingle(): Unable to prepare statement: 1, table sqlite_master may not be modified in %s on line %d +Warning: SQLite3::querySingle(): Unable to prepare statement: table sqlite_master may not be modified in %s on line %d bool(false) int(1) \ No newline at end of file diff --git a/ext/sqlite3/tests/sqlite3_prepare_faultystmt.phpt b/ext/sqlite3/tests/sqlite3_prepare_faultystmt.phpt index 27a548a8aad9f..5eb7e17792c1b 100644 --- a/ext/sqlite3/tests/sqlite3_prepare_faultystmt.phpt +++ b/ext/sqlite3/tests/sqlite3_prepare_faultystmt.phpt @@ -16,5 +16,5 @@ $stmt = $db->prepare('SELECT foo FROM bar'); var_dump($stmt); ?> --EXPECTF-- -Warning: SQLite3::prepare(): Unable to prepare statement: 1, no such table: bar in %s on line %d +Warning: SQLite3::prepare(): Unable to prepare statement: no such table: bar in %s on line %d bool(false) diff --git a/ext/sqlite3/tests/sqlite3_trampoline_setauthorizer.phpt b/ext/sqlite3/tests/sqlite3_trampoline_setauthorizer.phpt index 919a9895e1202..9a89d36f8e688 100644 --- a/ext/sqlite3/tests/sqlite3_trampoline_setauthorizer.phpt +++ b/ext/sqlite3/tests/sqlite3_trampoline_setauthorizer.phpt @@ -38,4 +38,4 @@ try { Trampoline for authorizer int(1) Trampoline for authorizer -Unable to prepare statement: 23, not authorized +Unable to prepare statement: not authorized From 97ac2618bf77492adbb2362a11d36f2f7cc8f649 Mon Sep 17 00:00:00 2001 From: bohwaz Date: Tue, 11 Apr 2023 15:24:33 +0200 Subject: [PATCH 3/8] Don't test for exception_ce registered --- ext/sqlite3/sqlite3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index ff648effd39e2..aad45ca22145e 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -81,7 +81,7 @@ static void php_sqlite3_error(php_sqlite3_db_object *db_obj, int errcode, const vspprintf(&message, 0, format, arg); va_end(arg); - if (db_obj && db_obj->exception && php_sqlite3_exception_ce) { + if (db_obj && db_obj->exception) { zend_throw_exception(php_sqlite3_exception_ce, message, errcode); } else { php_error_docref(NULL, E_WARNING, "%s", message); From 9eed3217cd0adfff61437e1aa79a59b4ec551dd0 Mon Sep 17 00:00:00 2001 From: bohwaz Date: Wed, 12 Apr 2023 12:11:28 +0200 Subject: [PATCH 4/8] Use \Exception instead of \RuntimeException --- ext/sqlite3/sqlite3.c | 15 +++------------ ext/sqlite3/sqlite3.stub.php | 2 +- ext/sqlite3/sqlite3_arginfo.h | 6 +++--- .../tests/sqlite3_33_load_extension_param.phpt | 4 ++-- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index aad45ca22145e..cd324e4deafba 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -28,7 +28,6 @@ #include #include "zend_exceptions.h" -#include "ext/spl/spl_exceptions.h" #include "SAPI.h" #include "sqlite3_arginfo.h" @@ -416,7 +415,7 @@ PHP_METHOD(SQLite3, loadExtension) } if (extension_len == 0) { - php_sqlite3_error(db_obj, 0, "Empty string as an extension"); + zend_argument_value_error(1, "cannot be empty"); RETURN_FALSE; } @@ -2363,7 +2362,7 @@ static void sqlite3_param_dtor(zval *data) /* {{{ */ PHP_MINIT_FUNCTION(sqlite3) { /* Register SQLite3Exception class */ - php_sqlite3_exception_ce = register_class_SQLite3Exception(spl_ce_RuntimeException); + php_sqlite3_exception_ce = register_class_SQLite3Exception(zend_ce_exception); #ifdef ZTS /* Refuse to load if this wasn't a threasafe library loaded */ @@ -2430,13 +2429,6 @@ PHP_MINFO_FUNCTION(sqlite3) } /* }}} */ -/* {{{ */ -static const zend_module_dep sqlite3_deps[] = { - ZEND_MOD_REQUIRED("spl") - ZEND_MOD_END -}; -/* }}} */ - /* {{{ PHP_GINIT_FUNCTION */ static PHP_GINIT_FUNCTION(sqlite3) { @@ -2449,8 +2441,7 @@ static PHP_GINIT_FUNCTION(sqlite3) /* {{{ sqlite3_module_entry */ zend_module_entry sqlite3_module_entry = { - STANDARD_MODULE_HEADER_EX,NULL, - sqlite3_deps, + STANDARD_MODULE_HEADER, "sqlite3", NULL, PHP_MINIT(sqlite3), diff --git a/ext/sqlite3/sqlite3.stub.php b/ext/sqlite3/sqlite3.stub.php index 9a6b28b78ea48..e3ab140331f00 100644 --- a/ext/sqlite3/sqlite3.stub.php +++ b/ext/sqlite3/sqlite3.stub.php @@ -68,7 +68,7 @@ const SQLITE3_DETERMINISTIC = UNKNOWN; #endif -class SQLite3Exception extends \RuntimeException +class SQLite3Exception extends \Exception { } diff --git a/ext/sqlite3/sqlite3_arginfo.h b/ext/sqlite3/sqlite3_arginfo.h index 9ea67cff9e7f6..ce4f2c6124deb 100644 --- a/ext/sqlite3/sqlite3_arginfo.h +++ b/ext/sqlite3/sqlite3_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: ffe03d1df12ee9806bcbfcaa26818dc9177e0bd3 */ + * Stub hash: 921426faab7267354e0a58ebe8af5f4fff23010f */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -293,12 +293,12 @@ static void register_sqlite3_symbols(int module_number) #endif } -static zend_class_entry *register_class_SQLite3Exception(zend_class_entry *class_entry_RuntimeException) +static zend_class_entry *register_class_SQLite3Exception(zend_class_entry *class_entry_Exception) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "SQLite3Exception", class_SQLite3Exception_methods); - class_entry = zend_register_internal_class_ex(&ce, class_entry_RuntimeException); + class_entry = zend_register_internal_class_ex(&ce, class_entry_Exception); return class_entry; } diff --git a/ext/sqlite3/tests/sqlite3_33_load_extension_param.phpt b/ext/sqlite3/tests/sqlite3_33_load_extension_param.phpt index bb63e418c64cb..8ab22520267f0 100644 --- a/ext/sqlite3/tests/sqlite3_33_load_extension_param.phpt +++ b/ext/sqlite3/tests/sqlite3_33_load_extension_param.phpt @@ -20,10 +20,10 @@ $db = new SQLite3(':memory:'); try { $db->loadExtension(""); -} catch (Extension $ex) { +} catch (\Throwable $ex) { var_dump($ex->getMessage()); } ?> --EXPECTF-- -Warning: SQLite3::loadExtension(): Empty string as an extension in %s on line %d +string(61) "SQLite3::loadExtension(): Argument #1 ($name) cannot be empty" From 1be53d156a14933260d9afcdcff39810dd32a84a Mon Sep 17 00:00:00 2001 From: BohwaZ Date: Fri, 14 Apr 2023 13:59:53 +0200 Subject: [PATCH 5/8] Update ext/sqlite3/sqlite3.stub.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tim Düsterhus --- ext/sqlite3/sqlite3.stub.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ext/sqlite3/sqlite3.stub.php b/ext/sqlite3/sqlite3.stub.php index e3ab140331f00..f351a68079942 100644 --- a/ext/sqlite3/sqlite3.stub.php +++ b/ext/sqlite3/sqlite3.stub.php @@ -68,6 +68,9 @@ const SQLITE3_DETERMINISTIC = UNKNOWN; #endif +/** + * @strict-properties + */ class SQLite3Exception extends \Exception { } From 6ba91c4598563741e00650b7a7e12ca0e7803488 Mon Sep 17 00:00:00 2001 From: bohwaz Date: Fri, 14 Apr 2023 15:32:22 +0200 Subject: [PATCH 6/8] Update --- ext/sqlite3/sqlite3_arginfo.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/sqlite3/sqlite3_arginfo.h b/ext/sqlite3/sqlite3_arginfo.h index ce4f2c6124deb..7567bed8e7264 100644 --- a/ext/sqlite3/sqlite3_arginfo.h +++ b/ext/sqlite3/sqlite3_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 921426faab7267354e0a58ebe8af5f4fff23010f */ + * Stub hash: feabdc10872ef97add839505b6893bad0bb82879 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -299,6 +299,7 @@ static zend_class_entry *register_class_SQLite3Exception(zend_class_entry *class INIT_CLASS_ENTRY(ce, "SQLite3Exception", class_SQLite3Exception_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_Exception); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; return class_entry; } From 9413ea35d159dc82fe69a76c2a180679295fff09 Mon Sep 17 00:00:00 2001 From: bohwaz Date: Thu, 25 May 2023 22:20:27 +0200 Subject: [PATCH 7/8] Add EOL --- ext/sqlite3/tests/sqlite3_defensive.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/sqlite3/tests/sqlite3_defensive.phpt b/ext/sqlite3/tests/sqlite3_defensive.phpt index 6614388ee226a..b386f61ce04b2 100644 --- a/ext/sqlite3/tests/sqlite3_defensive.phpt +++ b/ext/sqlite3/tests/sqlite3_defensive.phpt @@ -39,4 +39,4 @@ int(1) Warning: SQLite3::querySingle(): Unable to prepare statement: table sqlite_master may not be modified in %s on line %d bool(false) -int(1) \ No newline at end of file +int(1) From 4973ca34e2f590cdbefb4589df907bb621a9f164 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Mon, 3 Jul 2023 04:12:54 +0100 Subject: [PATCH 8/8] Redd UPGRADING dropped during rebase --- UPGRADING | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/UPGRADING b/UPGRADING index 37c99586ac46c..3e939c8c3c968 100644 --- a/UPGRADING +++ b/UPGRADING @@ -117,6 +117,11 @@ PHP 8.3 UPGRADE NOTES . The ZipArchive::FL_RECOMPRESS constant is deprecated and will be removed in a future version of libzip +- SQLite3 + . Using exceptions is now preferred, warnings will be removed in the future. + Calling SQLite3::enableExceptions(false) will trigger a depreciation warning + in this version. + ======================================== 5. Changed Functions ======================================== @@ -262,6 +267,12 @@ PHP 8.3 UPGRADE NOTES 9. Other Changes to Extensions ======================================== +- SQLite3 + . The SQLite3 class now throws \SQLite3Exception (extends \Exception) instead + of \Exception. + . The SQLite error code is now passed in the exception error code instead of being + included in the error message. + ======================================== 10. New Global Constants ========================================