LCOV - code coverage report
Current view: top level - data/include/storage - data_database.inl (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.63.2_covts Lines: 80.4 % 97 78
Test Date: 2025-05-01 10:10:14 Functions: 92.9 % 14 13

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

Generated by: LCOV version 2.0-1