LCOV - code coverage report
Current view: top level - data/include/storage - data_database.inl (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.70.2_covts Lines: 87.0 % 108 94
Test Date: 2026-05-03 11:56:31 Functions: 100.0 % 14 14

            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           58 : 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           58 :     assert( (*this_).transaction_recursion == 0 );
      34              : 
      35           58 :     const char* const IN_MEMORY_FILENAME = ":memory:"; /* magic filename, see https://www.sqlite.org/c3ref/open.html */
      36              :     const u8_error_t err
      37           58 :         = data_database_private_open( this_,
      38              :                                       IN_MEMORY_FILENAME,
      39              :                                       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY
      40              :                                     );
      41           58 :     return err;
      42              : }
      43              : 
      44         6222 : static inline bool data_database_is_open( data_database_t *this_ )
      45              : {
      46              :     bool result;
      47              :     u8_error_t locking_error;
      48         6222 :     locking_error = data_database_lock_on_write( this_ );
      49         6222 :     result = (*this_).db_state != DATA_DATABASE_STATE_CLOSED;
      50         6222 :     locking_error |= data_database_unlock_on_write( this_ );
      51         6222 :     assert( locking_error == U8_ERROR_NONE );
      52              :     (void) locking_error;  /* this should not happen in RELEASE mode */
      53         6222 :     return result;
      54              : }
      55              : 
      56              : /* ================================ Actions on DB ================================ */
      57              : 
      58         4028 : static inline sqlite3 *data_database_get_database_ptr ( data_database_t *this_ )
      59              : {
      60         4028 :     return (*this_).db;
      61              : }
      62              : 
      63         1292 : static inline u8_error_t data_database_private_exec_sql( data_database_t *this_, const char* sql_command, bool ignore_errors )
      64              : {
      65         1292 :     U8_TRACE_BEGIN();
      66         1292 :     assert( sql_command != NULL );
      67              :     int sqlite_err;
      68         1292 :     char *error_msg = NULL;
      69         1292 :     u8_error_t result = U8_ERROR_NONE;
      70         1292 :     sqlite3 *const db = (*this_).db;
      71              : 
      72         1292 :     U8_LOG_EVENT_STR( "sqlite3_exec:", sql_command );
      73         1292 :     sqlite_err = sqlite3_exec( db, sql_command, NULL, NULL, &error_msg );
      74              : 
      75         1292 :     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         1292 :     else if ( SQLITE_OK != sqlite_err )
      84              :     {
      85          544 :         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          544 :         result |= U8_ERROR_AT_DB;
      91              :     }
      92         1292 :     if ( error_msg != NULL )
      93              :     {
      94          544 :         U8_TRACE_INFO_STR( "sqlite3_exec() failed:", error_msg );
      95          544 :         sqlite3_free( error_msg );
      96          544 :         error_msg = NULL;
      97              :     }
      98              : 
      99         1292 :     U8_TRACE_END_ERR( result );
     100         1292 :     return result;
     101              : }
     102              : 
     103         3152 : 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         3152 :     U8_TRACE_BEGIN();
     109         3152 :     assert( NULL != string_statement );
     110         3152 :     assert( NULL != out_statement_ptr );
     111         3152 :     u8_error_t result = U8_ERROR_NONE;
     112              :     const char *first_unused_statement_char;
     113              :     int sqlite_err;
     114         3152 :     sqlite3 *const db = (*this_).db;
     115              : 
     116         3152 :     U8_TRACE_INFO_STR( "sqlite3_prepare_v2():", string_statement );
     117         3152 :     sqlite_err = sqlite3_prepare_v2( db,
     118              :                                      string_statement,
     119              :                                      string_size,
     120              :                                      out_statement_ptr,
     121              :                                      &first_unused_statement_char
     122              :                                    );
     123         3152 :     if (( string_size != DATA_DATABASE_SQL_LENGTH_AUTO_DETECT )
     124         1576 :         && ( 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         3152 :     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         3152 :     U8_TRACE_END_ERR( result );
     138         3152 :     return result;
     139              : }
     140              : 
     141         3152 : static inline u8_error_t data_database_finalize_statement ( data_database_t *this_, sqlite3_stmt *statement_ptr )
     142              : {
     143         3152 :     U8_TRACE_BEGIN();
     144         3152 :     assert( NULL != statement_ptr );
     145         3152 :     u8_error_t result = U8_ERROR_NONE;
     146              :     int sqlite_err;
     147              : 
     148         3152 :     U8_TRACE_INFO_STR( "sqlite3_finalize():", sqlite3_sql(statement_ptr) );
     149         3152 :     sqlite_err = sqlite3_finalize( statement_ptr );
     150         3152 :     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         3152 :     U8_TRACE_END_ERR( result );
     158         3152 :     return result;
     159              : }
     160              : 
     161              : /* ================================ Information ================================ */
     162              : 
     163          544 : 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          544 :     locking_error = data_database_lock_on_write( this_ );
     168          544 :     result = (*this_).revision;
     169          544 :     locking_error |= data_database_unlock_on_write( this_ );
     170          544 :     assert( locking_error == U8_ERROR_NONE );
     171              :     (void) locking_error;  /* ignore errors at lock */
     172          544 :     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         1896 : static inline data_change_notifier_t *data_database_get_notifier_ptr ( data_database_t *this_ )
     204              : {
     205         1896 :     return &((*this_).notifier);
     206              : }
     207              : 
     208          139 : static inline void data_database_private_clear_db_listener_list( data_database_t *this_ )
     209              : {
     210         2919 :     for( int index = 0; index < DATA_DATABASE_MAX_LISTENERS; index ++ )
     211              :     {
     212         2780 :         (*this_).listener_list[index] = NULL;
     213              :     }
     214          139 : }
     215              : 
     216              : /* ================================ Lifecycle Lock ================================ */
     217              : 
     218         9745 : static inline u8_error_t data_database_lock_on_write ( data_database_t *this_ )
     219              : {
     220         9745 :     assert( (*this_).locked_on_write == false );
     221         9745 :     u8_error_t result = U8_ERROR_NONE;
     222              : 
     223         9745 :     g_mutex_lock ( &((*this_).lock_on_write) );
     224         9745 :     (*this_).locked_on_write = true;
     225              : 
     226         9745 :     return result;
     227              : }
     228              : 
     229         9745 : static inline u8_error_t data_database_unlock_on_write ( data_database_t *this_ )
     230              : {
     231         9745 :     assert( (*this_).locked_on_write == true );
     232         9745 :     u8_error_t result = U8_ERROR_NONE;
     233              : 
     234         9745 :     (*this_).locked_on_write = false;
     235         9745 :     g_mutex_unlock ( &((*this_).lock_on_write) );
     236              : 
     237         9745 :     return result;
     238              : }
     239              : 
     240              : 
     241              : /*
     242              : Copyright 2016-2026 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              : */
        

Generated by: LCOV version 2.0-1