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