LCOV - code coverage report
Current view: top level - data/include/storage - data_database.inl (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.67.0_covts Lines: 87.0 % 108 94
Test Date: 2025-11-06 17:22:08 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           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              : */
        

Generated by: LCOV version 2.0-1