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 11 : static inline u8_error_t data_database_open ( data_database_t *this_, const char* db_file_path ) 9 : { 10 11 : assert( db_file_path != NULL ); 11 : /* there should not be pending transactions when calling open */ 12 11 : assert( (*this_).transaction_recursion == 0 ); 13 : 14 : const u8_error_t err 15 11 : = data_database_private_open( this_, db_file_path, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE ); 16 11 : 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 51 : 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 51 : assert( (*this_).transaction_recursion == 0 ); 34 : 35 51 : const char* const IN_MEMORY_FILENAME = ":memory:"; /* magic filename, see https://www.sqlite.org/c3ref/open.html */ 36 : const u8_error_t err 37 51 : = data_database_private_open( this_, 38 : IN_MEMORY_FILENAME, 39 : SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY 40 : ); 41 51 : return err; 42 : } 43 : 44 5866 : static inline bool data_database_is_open( data_database_t *this_ ) 45 : { 46 : bool result; 47 : u8_error_t locking_error; 48 5866 : locking_error = data_database_lock_on_write( this_ ); 49 5866 : result = (*this_).db_state != DATA_DATABASE_STATE_CLOSED; 50 5866 : locking_error |= data_database_unlock_on_write( this_ ); 51 5866 : assert( locking_error == U8_ERROR_NONE ); 52 : (void) locking_error; /* this should not happen in RELEASE mode */ 53 5866 : return result; 54 : } 55 : 56 : /* ================================ Actions on DB ================================ */ 57 : 58 3810 : static inline sqlite3 *data_database_get_database_ptr ( data_database_t *this_ ) 59 : { 60 3810 : return (*this_).db; 61 : } 62 : 63 1178 : static inline u8_error_t data_database_private_exec_sql( data_database_t *this_, const char* sql_command, bool ignore_errors ) 64 : { 65 1178 : assert( sql_command != NULL ); 66 : int sqlite_err; 67 1178 : char *error_msg = NULL; 68 1178 : u8_error_t result = U8_ERROR_NONE; 69 1178 : sqlite3 *const db = (*this_).db; 70 : 71 1178 : U8_LOG_EVENT_STR( "sqlite3_exec:", sql_command ); 72 1178 : sqlite_err = sqlite3_exec( db, sql_command, NULL, NULL, &error_msg ); 73 : 74 1178 : if ( SQLITE_READONLY == sqlite_err ) 75 : { 76 0 : if ( ! ignore_errors ) 77 : { 78 0 : U8_LOG_WARNING_STR( "sqlite3_exec() failed:", sql_command ); 79 : } 80 0 : result |= U8_ERROR_READ_ONLY_DB; 81 : } 82 1178 : else if ( SQLITE_OK != sqlite_err ) 83 : { 84 496 : if ( ! ignore_errors ) 85 : { 86 0 : U8_LOG_ERROR_STR( "sqlite3_exec() failed:", sql_command ); 87 0 : U8_LOG_ERROR_INT( "sqlite3_exec() failed:", sqlite_err ); 88 : } 89 496 : result |= U8_ERROR_AT_DB; 90 : } 91 1178 : if ( error_msg != NULL ) 92 : { 93 496 : U8_TRACE_INFO_STR( "sqlite3_exec() failed:", error_msg ); 94 496 : sqlite3_free( error_msg ); 95 496 : error_msg = NULL; 96 : } 97 1178 : return result; 98 : } 99 : 100 2738 : static inline u8_error_t data_database_prepare_statement ( data_database_t *this_, 101 : const char *string_statement, 102 : int string_size, 103 : sqlite3_stmt **out_statement_ptr ) 104 : { 105 2738 : assert( NULL != string_statement ); 106 2738 : assert( NULL != out_statement_ptr ); 107 2738 : u8_error_t result = U8_ERROR_NONE; 108 : const char *first_unused_statement_char; 109 : int sqlite_err; 110 2738 : sqlite3 *const db = (*this_).db; 111 : 112 2738 : U8_TRACE_INFO_STR( "sqlite3_prepare_v2():", string_statement ); 113 2738 : sqlite_err = sqlite3_prepare_v2( db, 114 : string_statement, 115 : string_size, 116 : out_statement_ptr, 117 : &first_unused_statement_char 118 : ); 119 2738 : if (( string_size != DATA_DATABASE_SQL_LENGTH_AUTO_DETECT ) 120 1425 : && ( first_unused_statement_char != &(string_statement[string_size-1]) )) 121 : { 122 0 : U8_LOG_ERROR_INT( "sqlite3_prepare_v2() consumed wrong amount of characters, expected:", string_size-1 ); 123 0 : result |= U8_ERROR_AT_DB; 124 : } 125 2738 : if ( SQLITE_OK != sqlite_err ) 126 : { 127 0 : U8_LOG_ERROR_STR( "sqlite3_prepare_v2() failed:", string_statement ); 128 0 : U8_LOG_ERROR_INT( "sqlite3_prepare_v2() failed:", sqlite_err ); 129 0 : U8_LOG_ERROR_STR( "sqlite3_prepare_v2() failed:", sqlite3_errmsg( db ) ); 130 0 : result |= U8_ERROR_AT_DB; 131 : } 132 : 133 2738 : return result; 134 : } 135 : 136 2738 : static inline u8_error_t data_database_finalize_statement ( data_database_t *this_, sqlite3_stmt *statement_ptr ) 137 : { 138 2738 : assert( NULL != statement_ptr ); 139 2738 : u8_error_t result = U8_ERROR_NONE; 140 : int sqlite_err; 141 : 142 2738 : U8_TRACE_INFO_STR( "sqlite3_finalize():", sqlite3_sql(statement_ptr) ); 143 2738 : sqlite_err = sqlite3_finalize( statement_ptr ); 144 2738 : if ( SQLITE_OK != sqlite_err ) 145 : { 146 0 : U8_LOG_ERROR_STR( "sqlite3_finalize() failed:", sqlite3_sql(statement_ptr) ); 147 0 : U8_LOG_ERROR_INT( "sqlite3_finalize() failed:", sqlite_err ); 148 0 : result |= U8_ERROR_AT_DB; 149 : } 150 : 151 2738 : return result; 152 : } 153 : 154 : /* ================================ Information ================================ */ 155 : 156 5 : static inline uint32_t data_database_get_revision ( data_database_t *this_ ) 157 : { 158 : uint32_t result; 159 : u8_error_t locking_error; 160 5 : locking_error = data_database_lock_on_write( this_ ); 161 5 : result = (*this_).revision; 162 5 : locking_error |= data_database_unlock_on_write( this_ ); 163 5 : assert( locking_error == U8_ERROR_NONE ); 164 : (void) locking_error; /* ignore errors at lock */ 165 5 : return result; 166 : } 167 : 168 : static inline void data_database_set_revision ( data_database_t *this_, uint32_t revision ) 169 : { 170 : u8_error_t locking_error; 171 : locking_error = data_database_lock_on_write( this_ ); 172 : (*this_).revision = revision; 173 : locking_error |= data_database_unlock_on_write( this_ ); 174 : assert( locking_error == U8_ERROR_NONE ); 175 : (void) locking_error; /* ignore errors at lock */ 176 : } 177 : 178 30 : static inline const char *data_database_get_filename_ptr ( data_database_t *this_ ) 179 : { 180 30 : return ( data_database_is_open( this_ ) ? utf8stringbuf_get_string( (*this_).db_file_name ) : NULL ); 181 : } 182 : 183 : /* ================================ Change Listener ================================ */ 184 : 185 1787 : static inline data_change_notifier_t *data_database_get_notifier_ptr ( data_database_t *this_ ) 186 : { 187 1787 : return &((*this_).notifier); 188 : } 189 : 190 125 : static inline void data_database_private_clear_db_listener_list( data_database_t *this_ ) 191 : { 192 2625 : for( int index = 0; index < DATA_DATABASE_MAX_LISTENERS; index ++ ) 193 : { 194 2500 : (*this_).listener_list[index] = NULL; 195 : } 196 125 : } 197 : 198 : /* ================================ Lifecycle Lock ================================ */ 199 : 200 8487 : static inline u8_error_t data_database_lock_on_write ( data_database_t *this_ ) 201 : { 202 8487 : assert( (*this_).locked_on_write == false ); 203 8487 : u8_error_t result = U8_ERROR_NONE; 204 : 205 8487 : g_mutex_lock ( &((*this_).lock_on_write) ); 206 8487 : (*this_).locked_on_write = true; 207 : 208 8487 : return result; 209 : } 210 : 211 8487 : static inline u8_error_t data_database_unlock_on_write ( data_database_t *this_ ) 212 : { 213 8487 : assert( (*this_).locked_on_write == true ); 214 8487 : u8_error_t result = U8_ERROR_NONE; 215 : 216 8487 : (*this_).locked_on_write = false; 217 8487 : g_mutex_unlock ( &((*this_).lock_on_write) ); 218 : 219 8487 : return result; 220 : } 221 : 222 : 223 : /* 224 : Copyright 2016-2024 Andreas Warnke 225 : 226 : Licensed under the Apache License, Version 2.0 (the "License"); 227 : you may not use this file except in compliance with the License. 228 : You may obtain a copy of the License at 229 : 230 : http://www.apache.org/licenses/LICENSE-2.0 231 : 232 : Unless required by applicable law or agreed to in writing, software 233 : distributed under the License is distributed on an "AS IS" BASIS, 234 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 235 : See the License for the specific language governing permissions and 236 : limitations under the License. 237 : */