Line data Source code
1 : /* File: data_database.inl; Copyright and License: see below */ 2 : 3 : #include "u8/u8_log.h" 4 : #include <assert.h> 5 : 6 : /* ================================ Lifecycle ================================ */ 7 : 8 10 : static inline u8_error_t data_database_open ( data_database_t *this_, const char* db_file_path ) 9 : { 10 10 : assert( db_file_path != NULL ); 11 : /* there should not be pending transactions when calling open */ 12 10 : assert( (*this_).transaction_recursion == 0 ); 13 : 14 : const u8_error_t err 15 10 : = data_database_private_open( this_, db_file_path, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE ); 16 10 : return err; 17 : } 18 : 19 0 : static inline u8_error_t data_database_open_read_only ( data_database_t *this_, const char* db_file_path ) 20 : { 21 0 : assert( db_file_path != NULL ); 22 : /* there should not be pending transactions when calling open */ 23 0 : assert( (*this_).transaction_recursion == 0 ); 24 : 25 : const u8_error_t err 26 0 : = data_database_private_open( this_, db_file_path, SQLITE_OPEN_READONLY ); 27 0 : return err; 28 : } 29 : 30 53 : static inline u8_error_t data_database_open_in_memory ( data_database_t *this_ ) 31 : { 32 : /* there should not be pending transactions when calling open */ 33 53 : assert( (*this_).transaction_recursion == 0 ); 34 : 35 53 : const char* const IN_MEMORY_FILENAME = ":memory:"; /* magic filename, see https://www.sqlite.org/c3ref/open.html */ 36 : const u8_error_t err 37 53 : = data_database_private_open( this_, 38 : IN_MEMORY_FILENAME, 39 : SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY 40 : ); 41 53 : return err; 42 : } 43 : 44 8575 : static inline bool data_database_is_open( data_database_t *this_ ) 45 : { 46 : bool result; 47 : u8_error_t locking_error; 48 8575 : locking_error = data_database_lock_on_write( this_ ); 49 8575 : result = (*this_).db_state != DATA_DATABASE_STATE_CLOSED; 50 8575 : locking_error |= data_database_unlock_on_write( this_ ); 51 8575 : return result; 52 : } 53 : 54 : /* ================================ Actions on DB ================================ */ 55 : 56 5617 : static inline sqlite3 *data_database_get_database_ptr ( data_database_t *this_ ) 57 : { 58 5617 : return (*this_).db; 59 : } 60 : 61 1197 : static inline u8_error_t data_database_private_exec_sql( data_database_t *this_, const char* sql_command, bool ignore_errors ) 62 : { 63 1197 : assert( sql_command != NULL ); 64 : int sqlite_err; 65 1197 : char *error_msg = NULL; 66 1197 : u8_error_t result = U8_ERROR_NONE; 67 1197 : sqlite3 *const db = (*this_).db; 68 : 69 1197 : U8_LOG_EVENT_STR( "sqlite3_exec:", sql_command ); 70 1197 : sqlite_err = sqlite3_exec( db, sql_command, NULL, NULL, &error_msg ); 71 : 72 1197 : if ( SQLITE_READONLY == sqlite_err ) 73 : { 74 0 : if ( ! ignore_errors ) 75 : { 76 0 : U8_LOG_WARNING_STR( "sqlite3_exec() failed:", sql_command ); 77 : } 78 0 : result |= U8_ERROR_READ_ONLY_DB; 79 : } 80 1197 : else if ( SQLITE_OK != sqlite_err ) 81 : { 82 504 : if ( ! ignore_errors ) 83 : { 84 0 : U8_LOG_ERROR_STR( "sqlite3_exec() failed:", sql_command ); 85 0 : U8_LOG_ERROR_INT( "sqlite3_exec() failed:", sqlite_err ); 86 : } 87 504 : result |= U8_ERROR_AT_DB; 88 : } 89 1197 : if ( error_msg != NULL ) 90 : { 91 504 : U8_TRACE_INFO_STR( "sqlite3_exec() failed:", error_msg ); 92 504 : sqlite3_free( error_msg ); 93 504 : error_msg = NULL; 94 : } 95 1197 : return result; 96 : } 97 : 98 2486 : static inline u8_error_t data_database_prepare_statement ( data_database_t *this_, 99 : const char *string_statement, 100 : unsigned int string_size, 101 : sqlite3_stmt **out_statement_ptr ) 102 : { 103 2486 : assert( NULL != string_statement ); 104 2486 : assert( NULL != out_statement_ptr ); 105 2486 : u8_error_t result = U8_ERROR_NONE; 106 : const char *first_unused_statement_char; 107 : int sqlite_err; 108 2486 : sqlite3 *const db = (*this_).db; 109 : 110 2486 : U8_TRACE_INFO_STR( "sqlite3_prepare_v2():", string_statement ); 111 2486 : sqlite_err = sqlite3_prepare_v2( db, 112 : string_statement, 113 : string_size, 114 : out_statement_ptr, 115 : &first_unused_statement_char 116 : ); 117 2486 : if (( SQLITE_OK != sqlite_err ) 118 2486 : || ( first_unused_statement_char != &(string_statement[string_size-1]) )) 119 : { 120 0 : U8_LOG_ERROR_STR( "sqlite3_prepare_v2() failed:", string_statement ); 121 0 : U8_LOG_ERROR_INT( "sqlite3_prepare_v2() failed:", sqlite_err ); 122 0 : U8_LOG_ERROR_STR( "sqlite3_prepare_v2() failed:", sqlite3_errmsg( db ) ); 123 0 : result |= U8_ERROR_AT_DB; 124 : } 125 : 126 2486 : return result; 127 : } 128 : 129 2486 : static inline u8_error_t data_database_finalize_statement ( data_database_t *this_, sqlite3_stmt *statement_ptr ) 130 : { 131 2486 : assert( NULL != statement_ptr ); 132 2486 : u8_error_t result = U8_ERROR_NONE; 133 : int sqlite_err; 134 : 135 2486 : U8_TRACE_INFO_STR( "sqlite3_finalize():", sqlite3_sql(statement_ptr) ); 136 2486 : sqlite_err = sqlite3_finalize( statement_ptr ); 137 2486 : if ( SQLITE_OK != sqlite_err ) 138 : { 139 0 : U8_LOG_ERROR_STR( "sqlite3_finalize() failed:", sqlite3_sql(statement_ptr) ); 140 0 : U8_LOG_ERROR_INT( "sqlite3_finalize() failed:", sqlite_err ); 141 0 : result |= U8_ERROR_AT_DB; 142 : } 143 : 144 2486 : return result; 145 : } 146 : 147 : /* ================================ Information ================================ */ 148 : 149 30 : static inline const char *data_database_get_filename_ptr ( data_database_t *this_ ) 150 : { 151 30 : return ( data_database_is_open( this_ ) ? utf8stringbuf_get_string( (*this_).db_file_name ) : NULL ); 152 : } 153 : 154 : /* ================================ Change Listener ================================ */ 155 : 156 2692 : static inline data_change_notifier_t *data_database_get_notifier_ptr ( data_database_t *this_ ) 157 : { 158 2692 : return &((*this_).notifier); 159 : } 160 : 161 129 : static inline void data_database_private_clear_db_listener_list( data_database_t *this_ ) 162 : { 163 2709 : for( int index = 0; index < DATA_DATABASE_MAX_LISTENERS; index ++ ) 164 : { 165 2580 : (*this_).listener_list[index] = NULL; 166 : } 167 129 : } 168 : 169 : /* ================================ Lifecycle Lock ================================ */ 170 : 171 9410 : static inline u8_error_t data_database_lock_on_write ( data_database_t *this_ ) 172 : { 173 9410 : assert( (*this_).locked_on_write == false ); 174 9410 : u8_error_t result = U8_ERROR_NONE; 175 : 176 9410 : g_mutex_lock ( &((*this_).lock_on_write) ); 177 9410 : (*this_).locked_on_write = true; 178 : 179 9410 : return result; 180 : } 181 : 182 9410 : static inline u8_error_t data_database_unlock_on_write ( data_database_t *this_ ) 183 : { 184 9410 : assert( (*this_).locked_on_write == true ); 185 9410 : u8_error_t result = U8_ERROR_NONE; 186 : 187 9410 : (*this_).locked_on_write = false; 188 9410 : g_mutex_unlock ( &((*this_).lock_on_write) ); 189 : 190 9410 : return result; 191 : } 192 : 193 : 194 : /* 195 : Copyright 2016-2024 Andreas Warnke 196 : 197 : Licensed under the Apache License, Version 2.0 (the "License"); 198 : you may not use this file except in compliance with the License. 199 : You may obtain a copy of the License at 200 : 201 : http://www.apache.org/licenses/LICENSE-2.0 202 : 203 : Unless required by applicable law or agreed to in writing, software 204 : distributed under the License is distributed on an "AS IS" BASIS, 205 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 206 : See the License for the specific language governing permissions and 207 : limitations under the License. 208 : */