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-2025 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 : */
|