From 14aef13827b95e4454e7cdb58b2cf9d458ffcbf6 Mon Sep 17 00:00:00 2001 From: Rahim Kanji Date: Wed, 24 Dec 2025 16:21:38 +0500 Subject: [PATCH] Add method to execute already prepared SQLite3 statements, supporting both non-SELECT and SELECT queries. --- include/sqlite3db.h | 2 ++ lib/sqlite3db.cpp | 72 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/include/sqlite3db.h b/include/sqlite3db.h index bdd01fc9b..5364efe66 100644 --- a/include/sqlite3db.h +++ b/include/sqlite3db.h @@ -206,6 +206,8 @@ class SQLite3DB { bool execute_statement(const char *, char **, int *, int *, SQLite3_result **); SQLite3_result* execute_statement(const char *, char **_error=NULL, int *_cols=NULL, int *_affected_rows=NULL); bool execute_statement_raw(const char *, char **, int *, int *, sqlite3_stmt **); + bool execute_prepared(sqlite3_stmt* statement, char** error, int* cols, int* affected_rows, SQLite3_result** resultset); + SQLite3_result* execute_prepared(sqlite3_stmt* statement, char** _error, int* cols, int* affected_rows); int return_one_int(const char *); int check_table_structure(char *table_name, char *table_def); bool build_table(char *table_name, char *table_def, bool dropit); diff --git a/lib/sqlite3db.cpp b/lib/sqlite3db.cpp index 37d7f3cb1..ad9656bef 100644 --- a/lib/sqlite3db.cpp +++ b/lib/sqlite3db.cpp @@ -425,6 +425,78 @@ __exit_execute_statement: return ret; } +/** + * @brief Executes a prepared SQL statement and returns the result set. + * + * @param str The SQL statement to execute. + * @param _error Pointer to a variable to store the error message. + * @param _cols Pointer to a variable to store the number of columns. + * @param _affected_rows Pointer to a variable to store the number of affected rows. + * @return A pointer to the SQLite3_result object representing the result set. + */ +SQLite3_result* SQLite3DB::execute_prepared(sqlite3_stmt* statement, char** error, int* cols, int* affected_rows) { + SQLite3_result* resultset; + + char* myerror; + char** _error = (error == NULL ? &myerror : error); + + int mycols; + int* _cols = (cols == NULL ? &mycols : cols); + + int my_affected_rows; + int* _affected_rows = (affected_rows == NULL ? &my_affected_rows : affected_rows); + + if (execute_prepared(statement, _error, _cols, _affected_rows, &resultset)) + return resultset; + + return NULL; +} + +/** + * @brief Executes a prepared SQL statement and returns the result set. + * + * @param statement The prepared SQLite statement to execute. + * @param error Pointer to a variable to store the error message. + * @param cols Pointer to a variable to store the number of columns. + * @param affected_rows Pointer to a variable to store the number of affected rows. + * @param resultset Pointer to a pointer to a SQLite3_result object representing the result set. + * @return True if the execution was successful, false otherwise. + */ +bool SQLite3DB::execute_prepared(sqlite3_stmt* statement, char** error, int* cols, int* affected_rows, SQLite3_result** resultset) { + int rc; + *error = NULL; + bool ret = false; + VALGRIND_DISABLE_ERROR_REPORTING; + *cols = (*proxy_sqlite3_column_count)(statement); + if (*cols == 0) { // not a SELECT + *resultset = NULL; + // Get total changes before executing the statement + long long total_changes_before = (*proxy_sqlite3_total_changes64)(db); + do { + rc = (*proxy_sqlite3_step)(statement); + if (rc == SQLITE_LOCKED || rc == SQLITE_BUSY) { // the execution of the prepared statement failed because locked + usleep(USLEEP_SQLITE_LOCKED); + } + } while (rc == SQLITE_LOCKED || rc == SQLITE_BUSY); + if (rc == SQLITE_DONE) { + // Calculate affected rows as the difference in total changes + long long total_changes_after = (*proxy_sqlite3_total_changes64)(db); + *affected_rows = (int)(total_changes_after - total_changes_before); + ret = true; + } else { + *error = strdup((*proxy_sqlite3_errmsg)(db)); + goto __exit_execute_prepared; + } + } else { + *affected_rows = 0; + *resultset = new SQLite3_result(statement); + ret = true; + } +__exit_execute_prepared: + //(*proxy_sqlite3_reset)(statement); + return ret; +} + /** * @brief Executes a SQL statement and returns a single integer result. *