LCOV - code coverage report
Current view: top level - data/source/storage - data_database_text_search.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.57.0_covts Lines: 0 260 0.0 %
Date: 2024-04-07 11:14:42 Functions: 0 10 0.0 %

          Line data    Source code
       1             : /* File: data_database_text_search.c; Copyright and License: see below */
       2             : 
       3             : #include "storage/data_database_text_search.h"
       4             : #include "u8/u8_trace.h"
       5             : #include "u8/u8_log.h"
       6             : #include "utf8stringbuf/utf8stringbuf.h"
       7             : #include <sqlite3.h>
       8             : #include <assert.h>
       9             : 
      10             : /*!
      11             :  *  \brief translation table to encode strings for usage in LIKE search string literals
      12             :  */
      13             : const char *const DATA_DATABASE_TEXT_SEARCH_SQL_ENCODE[][2] = {
      14             :     { "%", "\\%" },
      15             :     { "_", "\\_" },
      16             :     { "\\", "\\\\" },
      17             :     { NULL, NULL }
      18             : };
      19             : 
      20           0 : u8_error_t data_database_text_search_init( data_database_text_search_t *this_, data_database_t *database )
      21             : {
      22           0 :     U8_TRACE_BEGIN();
      23           0 :     assert( NULL != database );
      24           0 :     u8_error_t result = U8_ERROR_NONE;
      25             : 
      26           0 :     (*this_).database = database;
      27           0 :     (*this_).is_open = false;
      28             : 
      29           0 :     data_database_listener_init( &((*this_).me_as_listener), this_, (void (*)(void*,data_database_listener_signal_t)) &data_database_text_search_db_change_callback );
      30           0 :     data_database_add_db_listener( database, &((*this_).me_as_listener) );
      31             : 
      32           0 :     if ( data_database_is_open( database ) )
      33             :     {
      34             :         /* if the database is open, open also the reader */
      35           0 :         result |= data_database_text_search_private_open( this_ );
      36             :     }
      37             : 
      38           0 :     data_rules_init ( &((*this_).data_rules) );
      39             : 
      40           0 :     U8_TRACE_END_ERR(result);
      41           0 :     return result;
      42             : }
      43             : 
      44           0 : u8_error_t data_database_text_search_destroy( data_database_text_search_t *this_ )
      45             : {
      46           0 :     U8_TRACE_BEGIN();
      47           0 :     u8_error_t result = U8_ERROR_NONE;
      48             : 
      49           0 :     data_rules_destroy ( &((*this_).data_rules) );
      50             : 
      51           0 :     if ( (*this_).is_open )
      52             :     {
      53           0 :         result |= data_database_text_search_private_close( this_ );
      54             :     }
      55             : 
      56           0 :     data_database_remove_db_listener( (*this_).database, &((*this_).me_as_listener) );
      57             : 
      58           0 :     (*this_).database = NULL;
      59             : 
      60           0 :     U8_TRACE_END_ERR(result);
      61           0 :     return result;
      62             : }
      63             : 
      64           0 : void data_database_text_search_db_change_callback( data_database_text_search_t *this_, data_database_listener_signal_t signal_id )
      65             : {
      66           0 :     U8_TRACE_BEGIN();
      67           0 :     u8_error_t result = U8_ERROR_NONE;
      68             : 
      69           0 :     switch ( signal_id )
      70             :     {
      71           0 :         case DATA_DATABASE_LISTENER_SIGNAL_PREPARE_CLOSE:
      72             :         {
      73           0 :             U8_TRACE_INFO( "DATA_DATABASE_LISTENER_SIGNAL_PREPARE_CLOSE" );
      74           0 :             if ( (*this_).is_open )
      75             :             {
      76           0 :                 result |= data_database_text_search_private_close( this_ );
      77             :             }
      78             :         }
      79           0 :         break;
      80             : 
      81           0 :         case DATA_DATABASE_LISTENER_SIGNAL_DB_OPENED:
      82             :         {
      83           0 :             U8_TRACE_INFO( "DATA_DATABASE_LISTENER_SIGNAL_DB_OPENED" );
      84           0 :             if ( (*this_).is_open )
      85             :             {
      86           0 :                 result |= data_database_text_search_private_close( this_ );
      87             :             }
      88           0 :             result |= data_database_text_search_private_open( this_ );
      89             :         }
      90           0 :         break;
      91             : 
      92           0 :         default:
      93             :         {
      94           0 :             U8_LOG_ERROR( "unexpected data_database_listener_signal_t" );
      95             :         }
      96             :     }
      97             : 
      98           0 :     U8_TRACE_END();
      99           0 : }
     100             : 
     101           0 : u8_error_t data_database_text_search_get_objects_by_textfragment( data_database_text_search_t *this_,
     102             :                                                                   const char *textfragment,
     103             :                                                                   data_search_result_list_t *io_results )
     104             : {
     105           0 :     U8_TRACE_BEGIN();
     106           0 :     assert( NULL != io_results );
     107           0 :     assert( NULL != textfragment );
     108           0 :     u8_error_t result = U8_ERROR_NONE;
     109             : 
     110             :     /* escape-encode textfragment */
     111           0 :     utf8error_t u8err = UTF8ERROR_SUCCESS;
     112           0 :     char like_search_buf[48] = "";
     113           0 :     utf8stringbuf_t like_search = UTF8STRINGBUF( like_search_buf );
     114           0 :     const bool search_empty = (0 == utf8string_get_length( textfragment ));
     115           0 :     if ( search_empty )
     116             :     {
     117             :         /* no wildcards and no excaping if search string is empty */
     118           0 :         utf8stringbuf_clear( like_search );
     119             :     }
     120             :     else
     121             :     {
     122           0 :         u8err |= utf8stringbuf_append_str( like_search, "%" );
     123           0 :         utf8stringbuf_t escape_me = utf8stringbuf_get_end( like_search );
     124           0 :         u8err |= utf8stringbuf_append_str( escape_me, textfragment );
     125           0 :         u8err |= utf8stringbuf_replace_all( escape_me, &DATA_DATABASE_TEXT_SEARCH_SQL_ENCODE );
     126           0 :         u8err |= utf8stringbuf_append_str( like_search, "%" );
     127             :     }
     128           0 :     U8_TRACE_INFO_STR( "LIKE SEARCH:", utf8stringbuf_get_string( like_search ) );
     129           0 :     if ( u8err != UTF8ERROR_SUCCESS )
     130             :     {
     131           0 :         U8_LOG_WARNING_STR( "error at escaping the search string", textfragment );
     132             :     }
     133             :     /* search for the prepared pattern. In case of empty, search for a non-existing pattern in the type fields */
     134           0 :     const char *const search_name = search_empty ? "" : utf8stringbuf_get_string( like_search );
     135           0 :     const char *const search_type = search_empty ? "\n" : utf8stringbuf_get_string( like_search );
     136           0 :     const char *const search_descr = search_empty ? "" : utf8stringbuf_get_string( like_search );
     137             : 
     138           0 :     result |= data_database_text_search_private_get_diagrams_by_textfragment( this_,
     139             :                                                                               search_name,
     140             :                                                                               search_type,
     141             :                                                                               search_descr,
     142             :                                                                               io_results
     143             :                                                                             );
     144             : 
     145           0 :     result |= data_database_text_search_private_get_classifiers_by_textfragment( this_,
     146             :                                                                                  search_name,
     147             :                                                                                  search_type,
     148             :                                                                                  search_descr,
     149             :                                                                                  io_results
     150             :                                                                                );
     151             : 
     152           0 :     result |= data_database_text_search_private_get_features_by_textfragment( this_,
     153             :                                                                               search_name,
     154             :                                                                               search_type,
     155             :                                                                               search_descr,
     156             :                                                                               io_results
     157             :                                                                             );
     158             : 
     159           0 :     result |= data_database_text_search_private_get_relationships_by_textfragment( this_,
     160             :                                                                                    search_name,
     161             :                                                                                    search_type,
     162             :                                                                                    search_descr,
     163             :                                                                                    io_results
     164             :                                                                                  );
     165             : 
     166           0 :     U8_TRACE_END_ERR( result );
     167           0 :     return result;
     168             : }
     169             : 
     170             : /* ================================ DIAGRAM ================================ */
     171             : 
     172             : /*!
     173             :  *  \brief predefined search statement to find diagrams by textfragment
     174             :  *
     175             :  *  note: name is needed for debugging only
     176             :  */
     177             : static const char data_database_text_search_SELECT_DIAGRAM_BY_TEXTFRAGMENT[] =
     178             :     "SELECT id,diagram_type,name "
     179             :     "FROM diagrams "
     180             :     "WHERE name LIKE ? ESCAPE \"\\\" "
     181             :     "OR stereotype LIKE ? ESCAPE \"\\\" "
     182             :     "OR description LIKE ? ESCAPE \"\\\";";
     183             : 
     184             : /*!
     185             :  *  \brief the column id of the result where this parameter is stored: id
     186             :  */
     187             : static const int RESULT_DIAGRAM_ID_COLUMN = 0;
     188             : 
     189             : /*!
     190             :  *  \brief the column id of the result where this parameter is stored: diagram_type
     191             :  */
     192             : static const int RESULT_DIAGRAM_TYPE_COLUMN = 1;
     193             : 
     194             : /*!
     195             :  *  \brief the column id of the result where this parameter is stored: name
     196             :  */
     197             : static const int RESULT_DIAGRAM_NAME_COLUMN = 2;
     198             : 
     199             : 
     200           0 : u8_error_t data_database_text_search_private_get_diagrams_by_textfragment( data_database_text_search_t *this_,
     201             :                                                                            const char *name_fragment,
     202             :                                                                            const char *stereo_fragment,
     203             :                                                                            const char *descr_fragment,
     204             :                                                                            data_search_result_list_t *io_results )
     205             : {
     206           0 :     U8_TRACE_BEGIN();
     207           0 :     assert( NULL != io_results );
     208           0 :     assert( NULL != name_fragment );
     209           0 :     assert( NULL != stereo_fragment );
     210           0 :     assert( NULL != descr_fragment );
     211           0 :     u8_error_t result = U8_ERROR_NONE;
     212             : 
     213             :     int sqlite_err;
     214             :     sqlite3_stmt *prepared_statement;
     215             : 
     216           0 :     if ( (*this_).is_open )
     217             :     {
     218           0 :         prepared_statement = (*this_).statement_diagram_ids_by_textfragment;
     219             : 
     220           0 :         result |= data_database_text_search_private_bind_three_texts_to_statement( this_,
     221             :                                                                                    prepared_statement,
     222             :                                                                                    name_fragment,
     223             :                                                                                    stereo_fragment,
     224             :                                                                                    descr_fragment
     225             :                                                                                  );
     226             : 
     227           0 :         sqlite_err = SQLITE_ROW;
     228           0 :         for ( uint32_t row_index = 0; (SQLITE_ROW == sqlite_err) && (U8_ERROR_NONE == result); row_index ++ )
     229             :         {
     230           0 :             U8_TRACE_INFO_INT( "sqlite3_step():", (row_index+1) );
     231           0 :             sqlite_err = sqlite3_step( prepared_statement );
     232           0 :             if ( SQLITE_DONE == sqlite_err )
     233             :             {
     234           0 :                 U8_TRACE_INFO( "sqlite3_step finished: SQLITE_DONE" );
     235             :             }
     236           0 :             else if ( SQLITE_ROW != sqlite_err )
     237             :             {
     238           0 :                 U8_LOG_ERROR_INT( "sqlite3_step failed:", sqlite_err );
     239           0 :                 result |= U8_ERROR_AT_DB;
     240             :             }
     241             :             else
     242             :             {
     243             :                 data_search_result_t current_result;
     244             : 
     245           0 :                 data_search_result_init_diagram( &current_result,
     246           0 :                                                  sqlite3_column_int64( prepared_statement, RESULT_DIAGRAM_ID_COLUMN ),
     247             :                                                  sqlite3_column_int( prepared_statement, RESULT_DIAGRAM_TYPE_COLUMN ),
     248           0 :                                                  (const char*) sqlite3_column_text( prepared_statement, RESULT_DIAGRAM_NAME_COLUMN )
     249             :                                                );
     250             : 
     251           0 :                 const u8_error_t err_full = data_search_result_list_add( io_results, &current_result );
     252           0 :                 if ( err_full != U8_ERROR_NONE )
     253             :                 {
     254           0 :                     U8_LOG_ANOMALY_INT( "io_results list full:", data_search_result_list_get_length( io_results ) );
     255           0 :                     result |= err_full;
     256             :                 }
     257             : 
     258           0 :                 data_search_result_trace( &current_result );
     259           0 :                 data_search_result_destroy( &current_result );
     260             :             }
     261             :         }
     262             :     }
     263             :     else
     264             :     {
     265           0 :         result |= U8_ERROR_NO_DB;
     266           0 :         U8_TRACE_INFO( "Database not open, cannot request data." );
     267             :     }
     268             : 
     269           0 :     U8_TRACE_END_ERR( result );
     270           0 :     return result;
     271             : }
     272             : 
     273             : 
     274             : /* ================================ CLASSIFIER ================================ */
     275             : 
     276             : /*!
     277             :  *  \brief predefined search statement to find classifiers by textfragment
     278             :  *
     279             :  *  note: classifiers.name is needed for debugging only
     280             :  */
     281             : static const char data_database_text_search_SELECT_CLASSIFIER_BY_TEXTFRAGMENT[] =
     282             :     "SELECT classifiers.id,classifiers.main_type,classifiers.name,diagrams.id "
     283             :     "FROM classifiers "
     284             :     "INNER JOIN diagramelements ON diagramelements.classifier_id=classifiers.id "
     285             :     "INNER JOIN diagrams ON diagramelements.diagram_id=diagrams.id "
     286             :     "WHERE classifiers.name LIKE ? ESCAPE \"\\\" "
     287             :     "OR classifiers.stereotype LIKE ? ESCAPE \"\\\" "
     288             :     "OR classifiers.description LIKE ? ESCAPE \"\\\" "
     289             :     "GROUP BY classifiers.id,diagrams.id;";  /* no duplicates if a classifier is twice in a diagram */
     290             : 
     291             : /*!
     292             :  *  \brief the column id of the result where this parameter is stored: id
     293             :  */
     294             : static const int RESULT_CLASSIFIER_ID_COLUMN = 0;
     295             : 
     296             : /*!
     297             :  *  \brief the column id of the result where this parameter is stored: main_type
     298             :  */
     299             : static const int RESULT_CLASSIFIER_MAIN_TYPE_COLUMN = 1;
     300             : 
     301             : /*!
     302             :  *  \brief the column id of the result where this parameter is stored: name
     303             :  */
     304             : static const int RESULT_CLASSIFIER_NAME_COLUMN = 2;
     305             : 
     306             : /*!
     307             :  *  \brief the column id of the result where this parameter is stored: diagrams.id
     308             :  */
     309             : static const int RESULT_CLASSIFIER_DIAGRAM_ID_COLUMN = 3;
     310             : 
     311           0 : u8_error_t data_database_text_search_private_get_classifiers_by_textfragment( data_database_text_search_t *this_,
     312             :                                                                               const char *name_fragment,
     313             :                                                                               const char *stereo_fragment,
     314             :                                                                               const char *descr_fragment,
     315             :                                                                               data_search_result_list_t *io_results )
     316             : {
     317           0 :     U8_TRACE_BEGIN();
     318           0 :     assert( NULL != io_results );
     319           0 :     assert( NULL != name_fragment );
     320           0 :     assert( NULL != stereo_fragment );
     321           0 :     assert( NULL != descr_fragment );
     322           0 :     u8_error_t result = U8_ERROR_NONE;
     323             : 
     324             :     int sqlite_err;
     325             :     sqlite3_stmt *prepared_statement;
     326             : 
     327           0 :     if ( (*this_).is_open )
     328             :     {
     329           0 :         prepared_statement = (*this_).statement_classifier_ids_by_textfragment;
     330             : 
     331           0 :         result |= data_database_text_search_private_bind_three_texts_to_statement( this_,
     332             :                                                                                    prepared_statement,
     333             :                                                                                    name_fragment,
     334             :                                                                                    stereo_fragment,
     335             :                                                                                    descr_fragment
     336             :                                                                                  );
     337             : 
     338           0 :         sqlite_err = SQLITE_ROW;
     339           0 :         for ( uint32_t row_index = 0; (SQLITE_ROW == sqlite_err) && (U8_ERROR_NONE == result); row_index ++ )
     340             :         {
     341           0 :             U8_TRACE_INFO_INT( "sqlite3_step():", (row_index+1) );
     342           0 :             sqlite_err = sqlite3_step( prepared_statement );
     343           0 :             if ( SQLITE_DONE == sqlite_err )
     344             :             {
     345           0 :                 U8_TRACE_INFO( "sqlite3_step finished: SQLITE_DONE" );
     346             :             }
     347           0 :             else if ( SQLITE_ROW != sqlite_err )
     348             :             {
     349           0 :                 U8_LOG_ERROR_INT( "sqlite3_step failed:", sqlite_err );
     350           0 :                 result |= U8_ERROR_AT_DB;
     351             :             }
     352             :             else
     353             :             {
     354             :                 data_search_result_t current_result;
     355             : 
     356           0 :                 data_search_result_init_classifier( &current_result,
     357           0 :                                                     sqlite3_column_int64( prepared_statement, RESULT_CLASSIFIER_ID_COLUMN ),
     358             :                                                     sqlite3_column_int( prepared_statement, RESULT_CLASSIFIER_MAIN_TYPE_COLUMN ),
     359           0 :                                                     (const char*) sqlite3_column_text( prepared_statement, RESULT_CLASSIFIER_NAME_COLUMN ),
     360           0 :                                                     sqlite3_column_int64( prepared_statement, RESULT_CLASSIFIER_DIAGRAM_ID_COLUMN )
     361             :                                                   );
     362             : 
     363           0 :                 const u8_error_t err_full = data_search_result_list_add( io_results, &current_result );
     364           0 :                 if ( err_full != U8_ERROR_NONE )
     365             :                 {
     366           0 :                     U8_LOG_ANOMALY_INT( "io_results list full:", data_search_result_list_get_length( io_results ) );
     367           0 :                     result |= err_full;
     368             :                 }
     369             : 
     370           0 :                 data_search_result_trace( &current_result );
     371           0 :                 data_search_result_destroy( &current_result );
     372             :             }
     373             :         }
     374             :     }
     375             :     else
     376             :     {
     377           0 :         result |= U8_ERROR_NO_DB;
     378           0 :         U8_TRACE_INFO( "Database not open, cannot request data." );
     379             :     }
     380             : 
     381           0 :     U8_TRACE_END_ERR( result );
     382           0 :     return result;
     383             : }
     384             : 
     385             : /* ================================ DIAGRAMELEMENT ================================ */
     386             : 
     387             : /* ================================ FEATURE ================================ */
     388             : 
     389             : /*!
     390             :  *  \brief predefined search statement to find features by textfragment
     391             :  *
     392             :  *  note: features.key is needed for debugging only
     393             :  */
     394             : static const char data_database_text_search_SELECT_FEATURE_BY_TEXTFRAGMENT[] =
     395             :     "SELECT DISTINCT features.id,features.main_type,features.key,features.classifier_id,"
     396             :     "classifiers.main_type,diagrams.id,diagrams.diagram_type "
     397             :     "FROM features "
     398             :     "INNER JOIN classifiers ON features.classifier_id=classifiers.id "
     399             :     "INNER JOIN diagramelements ON diagramelements.classifier_id=classifiers.id "
     400             :     "INNER JOIN diagrams ON diagramelements.diagram_id=diagrams.id "
     401             :     "WHERE features.key LIKE ? ESCAPE \"\\\" "
     402             :     "OR features.value LIKE ? ESCAPE \"\\\" "
     403             :     "OR features.description LIKE ? ESCAPE \"\\\" "
     404             :     "GROUP BY features.id,diagrams.id;";  /* no duplicates if a classifier is twice in a diagram */
     405             : 
     406             : /*!
     407             :  *  \brief the column id of the result where this parameter is stored: id
     408             :  */
     409             : static const int RESULT_FEATURE_ID_COLUMN = 0;
     410             : 
     411             : /*!
     412             :  *  \brief the column id of the result where this parameter is stored: main_type
     413             :  */
     414             : static const int RESULT_FEATURE_MAIN_TYPE_COLUMN = 1;
     415             : 
     416             : /*!
     417             :  *  \brief the column id of the result where this parameter is stored: key
     418             :  */
     419             : static const int RESULT_FEATURE_KEY_COLUMN = 2;
     420             : 
     421             : /*!
     422             :  *  \brief the column id of the result where this parameter is stored: classifiers.id
     423             :  */
     424             : static const int RESULT_FEATURE_CLASSIFIER_ID_COLUMN = 3;
     425             : 
     426             : /*!
     427             :  *  \brief the column id of the result where this parameter is stored: classifiers.main_type
     428             :  */
     429             : static const int RESULT_FEATURE_CLASSIFIER_MAIN_TYPE_COLUMN = 4;
     430             : 
     431             : /*!
     432             :  *  \brief the column id of the result where this parameter is stored: diagrams.id
     433             :  */
     434             : static const int RESULT_FEATURE_DIAGRAM_ID_COLUMN = 5;
     435             : 
     436             : /*!
     437             :  *  \brief the column id of the result where this parameter is stored: diagrams.diagram_type
     438             :  */
     439             : static const int RESULT_FEATURE_DIAGRAM_TYPE_COLUMN = 6;
     440             : 
     441           0 : u8_error_t data_database_text_search_private_get_features_by_textfragment( data_database_text_search_t *this_,
     442             :                                                                            const char *key_fragment,
     443             :                                                                            const char *value_fragment,
     444             :                                                                            const char *descr_fragment,
     445             :                                                                            data_search_result_list_t *io_results )
     446             : {
     447           0 :     U8_TRACE_BEGIN();
     448           0 :     assert( NULL != io_results );
     449           0 :     assert( NULL != key_fragment );
     450           0 :     assert( NULL != value_fragment );
     451           0 :     assert( NULL != descr_fragment );
     452           0 :     u8_error_t result = U8_ERROR_NONE;
     453             : 
     454             :     int sqlite_err;
     455             :     sqlite3_stmt *prepared_statement;
     456             : 
     457           0 :     if ( (*this_).is_open )
     458             :     {
     459           0 :         prepared_statement = (*this_).statement_feature_ids_by_textfragment;
     460             : 
     461           0 :         result |= data_database_text_search_private_bind_three_texts_to_statement( this_,
     462             :                                                                                    prepared_statement,
     463             :                                                                                    key_fragment,
     464             :                                                                                    value_fragment,
     465             :                                                                                    descr_fragment
     466             :                                                                                  );
     467             : 
     468           0 :         sqlite_err = SQLITE_ROW;
     469           0 :         for ( uint32_t row_index = 0; (SQLITE_ROW == sqlite_err) && (U8_ERROR_NONE == result); row_index ++ )
     470             :         {
     471           0 :             U8_TRACE_INFO_INT( "sqlite3_step():", (row_index+1) );
     472           0 :             sqlite_err = sqlite3_step( prepared_statement );
     473           0 :             if ( SQLITE_DONE == sqlite_err )
     474             :             {
     475           0 :                 U8_TRACE_INFO( "sqlite3_step finished: SQLITE_DONE" );
     476             :             }
     477           0 :             else if ( SQLITE_ROW != sqlite_err )
     478             :             {
     479           0 :                 U8_LOG_ERROR_INT( "sqlite3_step failed:", sqlite_err );
     480           0 :                 result |= U8_ERROR_AT_DB;
     481             :             }
     482             :             else
     483             :             {
     484             :                 data_search_result_t current_result;
     485             : 
     486           0 :                 data_search_result_init_feature( &current_result,
     487           0 :                                                  sqlite3_column_int64( prepared_statement, RESULT_FEATURE_ID_COLUMN ),
     488             :                                                  sqlite3_column_int( prepared_statement, RESULT_FEATURE_MAIN_TYPE_COLUMN ),
     489           0 :                                                  (const char*) sqlite3_column_text( prepared_statement, RESULT_FEATURE_KEY_COLUMN ),
     490           0 :                                                  sqlite3_column_int64( prepared_statement, RESULT_FEATURE_CLASSIFIER_ID_COLUMN ),
     491           0 :                                                  sqlite3_column_int64( prepared_statement, RESULT_FEATURE_DIAGRAM_ID_COLUMN )
     492             :                                                );
     493           0 :                 const data_feature_type_t f_type = data_search_result_get_match_type( &current_result );
     494           0 :                 const data_classifier_type_t c_type = sqlite3_column_int( prepared_statement, RESULT_FEATURE_CLASSIFIER_MAIN_TYPE_COLUMN );
     495           0 :                 const data_diagram_type_t d_type = sqlite3_column_int( prepared_statement, RESULT_FEATURE_DIAGRAM_TYPE_COLUMN );
     496           0 :                 U8_TRACE_INFO_INT( "- c_type:", c_type );
     497           0 :                 U8_TRACE_INFO_INT( "- d_type:", d_type );
     498             : 
     499           0 :                 bool filter = false;
     500           0 :                 const bool is_scenario_feat = data_rules_feature_is_scenario_cond( &((*this_).data_rules), f_type );
     501           0 :                 if ( is_scenario_feat )
     502             :                 {
     503             :                     /* text search never returns lifelines, independant of data_rules_diagram_shows_scenario_features */
     504           0 :                     filter = true;
     505             :                 }
     506             :                 else
     507             :                 {
     508             :                     /* evaluate filter */
     509           0 :                     const bool vis_by_classifier = data_rules_classifier_has_uncond_features ( &((*this_).data_rules), c_type );
     510           0 :                     const bool vis_by_diagram = data_rules_diagram_shows_uncond_features ( &((*this_).data_rules), d_type );
     511           0 :                     filter = !( vis_by_classifier && vis_by_diagram );
     512             :                 }
     513             : 
     514           0 :                 if ( ! filter )
     515             :                 {
     516           0 :                     const u8_error_t err_full = data_search_result_list_add( io_results, &current_result );
     517           0 :                     if ( err_full != U8_ERROR_NONE )
     518             :                     {
     519           0 :                         U8_LOG_ANOMALY_INT( "io_results list full:", data_search_result_list_get_length( io_results ) );
     520           0 :                         result |= err_full;
     521             :                     }
     522             :                 }
     523             : 
     524           0 :                 data_search_result_trace( &current_result );
     525           0 :                 data_search_result_destroy( &current_result );
     526             :             }
     527             :         }
     528             :     }
     529             :     else
     530             :     {
     531           0 :         result |= U8_ERROR_NO_DB;
     532           0 :         U8_TRACE_INFO( "Database not open, cannot request data." );
     533             :     }
     534             : 
     535             : 
     536           0 :     U8_TRACE_END_ERR( result );
     537           0 :     return result;
     538             : }
     539             : 
     540             : 
     541             : /* ================================ RELATIONSHIP ================================ */
     542             : 
     543             : /*!
     544             :  *  \brief predefined search statement to find relationships by textfragment
     545             :  *
     546             :  *  note: relationships.name is needed for debugging only
     547             :  */
     548             : static const char data_database_text_search_SELECT_RELATIONSHIP_BY_TEXTFRAGMENT[] =
     549             :     "SELECT DISTINCT relationships.id,relationships.main_type,relationships.name,"
     550             :     "relationships.from_classifier_id,relationships.to_classifier_id,"
     551             :     "relationships.from_feature_id,relationships.to_feature_id,"
     552             :     "diagrams.id,diagrams.diagram_type "
     553             :     "FROM relationships "
     554             :     "INNER JOIN diagramelements AS source "
     555             :     "ON source.classifier_id=relationships.from_classifier_id "
     556             :     "INNER JOIN diagramelements AS dest "
     557             :     "ON (dest.classifier_id=relationships.to_classifier_id)AND(dest.diagram_id==source.diagram_id) "
     558             :     "INNER JOIN diagrams ON source.diagram_id=diagrams.id "
     559             :     "WHERE relationships.name LIKE ? ESCAPE \"\\\" "
     560             :     "OR relationships.stereotype LIKE ? ESCAPE \"\\\" "
     561             :     "OR relationships.description LIKE ? ESCAPE \"\\\" "
     562             :     "GROUP BY relationships.id,diagrams.id;";  /* no duplicates if a classifier is twice in a diagram */
     563             : 
     564             : /*!
     565             :  *  \brief the column id of the result where this parameter is stored: id
     566             :  */
     567             : static const int RESULT_RELATIONSHIP_ID_COLUMN = 0;
     568             : 
     569             : /*!
     570             :  *  \brief the column id of the result where this parameter is stored: main_type
     571             :  */
     572             : static const int RESULT_RELATIONSHIP_MAIN_TYPE_COLUMN = 1;
     573             : 
     574             : /*!
     575             :  *  \brief the column id of the result where this parameter is stored: name
     576             :  */
     577             : static const int RESULT_RELATIONSHIP_NAME_COLUMN = 2;
     578             : 
     579             : /*!
     580             :  *  \brief the column id of the result where this parameter is stored: from_classifier_id
     581             :  */
     582             : static const int RESULT_RELATIONSHIP_FROM_CLASSIFIER_ID_COLUMN = 3;
     583             : 
     584             : /*!
     585             :  *  \brief the column id of the result where this parameter is stored: to_classifier_id
     586             :  */
     587             : static const int RESULT_RELATIONSHIP_TO_CLASSIFIER_ID_COLUMN = 4;
     588             : 
     589             : /*!
     590             :  *  \brief the column id of the result where this parameter is stored: from_feature_id
     591             :  */
     592             : static const int RESULT_RELATIONSHIP_FROM_FEATURE_ID_COLUMN = 5;
     593             : 
     594             : /*!
     595             :  *  \brief the column id of the result where this parameter is stored: to_feature_id
     596             :  */
     597             : static const int RESULT_RELATIONSHIP_TO_FEATURE_ID_COLUMN = 6;
     598             : 
     599             : /*!
     600             :  *  \brief the column id of the result where this parameter is stored: diagrams.id
     601             :  */
     602             : static const int RESULT_RELATIONSHIP_DIAGRAM_ID_COLUMN = 7;
     603             : 
     604             : /*!
     605             :  *  \brief the column id of the result where this parameter is stored: diagrams.diagram_type
     606             :  */
     607             : static const int RESULT_RELATIONSHIP_DIAGRAM_TYPE_COLUMN = 8;
     608             : 
     609           0 : u8_error_t data_database_text_search_private_get_relationships_by_textfragment( data_database_text_search_t *this_,
     610             :                                                                                 const char *name_fragment,
     611             :                                                                                 const char *stereo_fragment,
     612             :                                                                                 const char *descr_fragment,
     613             :                                                                                 data_search_result_list_t *io_results )
     614             : {
     615           0 :     U8_TRACE_BEGIN();
     616           0 :     assert( NULL != io_results );
     617           0 :     assert( NULL != name_fragment );
     618           0 :     assert( NULL != stereo_fragment );
     619           0 :     assert( NULL != descr_fragment );
     620           0 :     u8_error_t result = U8_ERROR_NONE;
     621             : 
     622             :     int sqlite_err;
     623             :     sqlite3_stmt *prepared_statement;
     624           0 :     unsigned int dropped_scenario_rel = 0;
     625             : 
     626           0 :     if ( (*this_).is_open )
     627             :     {
     628           0 :         prepared_statement = (*this_).statement_relationship_ids_by_textfragment;
     629             : 
     630           0 :         result |= data_database_text_search_private_bind_three_texts_to_statement( this_,
     631             :                                                                                    prepared_statement,
     632             :                                                                                    name_fragment,
     633             :                                                                                    stereo_fragment,
     634             :                                                                                    descr_fragment
     635             :                                                                                  );
     636             : 
     637           0 :         sqlite_err = SQLITE_ROW;
     638           0 :         for ( uint32_t row_index = 0; (SQLITE_ROW == sqlite_err) && (U8_ERROR_NONE == result); row_index ++ )
     639             :         {
     640           0 :             U8_TRACE_INFO_INT( "sqlite3_step():", (row_index+1) );
     641           0 :             sqlite_err = sqlite3_step( prepared_statement );
     642           0 :             if ( SQLITE_DONE == sqlite_err )
     643             :             {
     644           0 :                 U8_TRACE_INFO( "sqlite3_step finished: SQLITE_DONE" );
     645             :             }
     646           0 :             else if ( SQLITE_ROW != sqlite_err )
     647             :             {
     648           0 :                 U8_LOG_ERROR_INT( "sqlite3_step failed:", sqlite_err );
     649           0 :                 result |= U8_ERROR_AT_DB;
     650             :             }
     651             :             else
     652             :             {
     653             :                 data_search_result_t current_result;
     654             : 
     655           0 :                 data_search_result_init_relationship( &current_result,
     656           0 :                                                       sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_ID_COLUMN ),
     657             :                                                       sqlite3_column_int( prepared_statement, RESULT_RELATIONSHIP_MAIN_TYPE_COLUMN ),
     658           0 :                                                       (const char*) sqlite3_column_text( prepared_statement, RESULT_RELATIONSHIP_NAME_COLUMN ),
     659           0 :                                                       sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_FROM_CLASSIFIER_ID_COLUMN ),
     660           0 :                                                       sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_TO_CLASSIFIER_ID_COLUMN ),
     661           0 :                                                       sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_DIAGRAM_ID_COLUMN )
     662             :                                                     );
     663           0 :                 const data_row_id_t from_feat = sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_FROM_FEATURE_ID_COLUMN );
     664           0 :                 const data_row_id_t to_feat = sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_TO_FEATURE_ID_COLUMN );
     665           0 :                 const data_diagram_type_t d_type = sqlite3_column_int( prepared_statement, RESULT_RELATIONSHIP_DIAGRAM_TYPE_COLUMN );
     666           0 :                 U8_TRACE_INFO_INT( "- from_feat:", from_feat );
     667           0 :                 U8_TRACE_INFO_INT( "- to_feat:", to_feat );
     668           0 :                 U8_TRACE_INFO_INT( "- d_type:", d_type );
     669             : 
     670           0 :                 bool filter = false;
     671           0 :                 const bool is_scenario_diag = data_rules_diagram_is_scenario ( &((*this_).data_rules), d_type );
     672             :                 /*const bool is_scenario_rel = data_rules_relationship_is_scenario_cond( &((*this_).data_rules), from_feature_type, to_feature_type);*/
     673           0 :                 if ( is_scenario_diag )
     674             :                 {
     675             :                     /* there could be valid relationships that are visible and match the search. */
     676             :                     /* but it is quite difficult to determine if the relationship is visible in the current diagram */
     677             :                     /* --> drop the result and write a not to the log */
     678           0 :                     dropped_scenario_rel ++;
     679           0 :                     filter = true;
     680             :                 }
     681             :                 else
     682             :                 {
     683             :                     /* there could be hidden scenario-typed relationships in a non-scenario diagram. */
     684             :                     /* but it is quite difficult to determine if the relationship is scenario-only */
     685             :                     /* --> show the result anyway */
     686           0 :                     const bool vis_by_diagram = data_rules_diagram_shows_uncond_relationships ( &((*this_).data_rules), d_type );
     687           0 :                     filter = ! vis_by_diagram;
     688             :                 }
     689             : 
     690           0 :                 if ( ! filter )
     691             :                 {
     692           0 :                     const u8_error_t err_full = data_search_result_list_add( io_results, &current_result );
     693           0 :                     if ( err_full != U8_ERROR_NONE )
     694             :                     {
     695           0 :                         U8_LOG_ANOMALY_INT( "io_results list full:", data_search_result_list_get_length( io_results ) );
     696           0 :                         result |= err_full;
     697             :                     }
     698             :                 }
     699             : 
     700           0 :                 data_search_result_trace( &current_result );
     701           0 :                 data_search_result_destroy( &current_result );
     702             :             }
     703             :         }
     704             :     }
     705             :     else
     706             :     {
     707           0 :         result |= U8_ERROR_NO_DB;
     708           0 :         U8_TRACE_INFO( "Database not open, cannot request data." );
     709             :     }
     710             : 
     711           0 :     if ( dropped_scenario_rel != 0 )
     712             :     {
     713           0 :         U8_LOG_ANOMALY_INT( "Full text search does not work on relationships in scenario based diagrams. Possibly missed relationships:",
     714             :                            dropped_scenario_rel
     715             :                          );
     716             :     }
     717             : 
     718           0 :     U8_TRACE_END_ERR( result );
     719           0 :     return result;
     720             : }
     721             : 
     722             : 
     723             : /* ================================ private ================================ */
     724             : 
     725           0 : u8_error_t data_database_text_search_private_open( data_database_text_search_t *this_ )
     726             : {
     727           0 :     U8_TRACE_BEGIN();
     728           0 :     u8_error_t result = U8_ERROR_NONE;
     729             : 
     730           0 :     if ( ! (*this_).is_open )
     731             :     {
     732           0 :         result |= data_database_prepare_statement( (*this_).database,
     733             :                                                    data_database_text_search_SELECT_DIAGRAM_BY_TEXTFRAGMENT,
     734             :                                                    sizeof( data_database_text_search_SELECT_DIAGRAM_BY_TEXTFRAGMENT ),
     735             :                                                    &((*this_).statement_diagram_ids_by_textfragment)
     736             :                                                  );
     737           0 :         result |= data_database_prepare_statement( (*this_).database,
     738             :                                                    data_database_text_search_SELECT_CLASSIFIER_BY_TEXTFRAGMENT,
     739             :                                                    sizeof( data_database_text_search_SELECT_CLASSIFIER_BY_TEXTFRAGMENT ),
     740             :                                                    &((*this_).statement_classifier_ids_by_textfragment)
     741             :                                                  );
     742           0 :         result |= data_database_prepare_statement( (*this_).database,
     743             :                                                    data_database_text_search_SELECT_FEATURE_BY_TEXTFRAGMENT,
     744             :                                                    sizeof( data_database_text_search_SELECT_FEATURE_BY_TEXTFRAGMENT ),
     745             :                                                    &((*this_).statement_feature_ids_by_textfragment)
     746             :                                                  );
     747           0 :         result |= data_database_prepare_statement( (*this_).database,
     748             :                                                    data_database_text_search_SELECT_RELATIONSHIP_BY_TEXTFRAGMENT,
     749             :                                                    sizeof( data_database_text_search_SELECT_RELATIONSHIP_BY_TEXTFRAGMENT ),
     750             :                                                    &((*this_).statement_relationship_ids_by_textfragment)
     751             :                                                  );
     752             : 
     753           0 :         (*this_).is_open = true;
     754             :     }
     755             :     else
     756             :     {
     757           0 :         result |= U8_ERROR_INVALID_REQUEST;
     758           0 :         U8_LOG_WARNING( "Database is already open." );
     759             :     }
     760             : 
     761           0 :     U8_TRACE_END_ERR(result);
     762           0 :     return result;
     763             : }
     764             : 
     765           0 : u8_error_t data_database_text_search_private_close( data_database_text_search_t *this_ )
     766             : {
     767           0 :     U8_TRACE_BEGIN();
     768           0 :     u8_error_t result = U8_ERROR_NONE;
     769             : 
     770           0 :     if ( (*this_).is_open )
     771             :     {
     772           0 :         result |= data_database_finalize_statement( (*this_).database, (*this_).statement_relationship_ids_by_textfragment );
     773           0 :         result |= data_database_finalize_statement( (*this_).database, (*this_).statement_feature_ids_by_textfragment );
     774           0 :         result |= data_database_finalize_statement( (*this_).database, (*this_).statement_classifier_ids_by_textfragment );
     775           0 :         result |= data_database_finalize_statement( (*this_).database, (*this_).statement_diagram_ids_by_textfragment );
     776             : 
     777           0 :         (*this_).is_open = false;
     778             :     }
     779             :     else
     780             :     {
     781           0 :         result |= U8_ERROR_INVALID_REQUEST;
     782           0 :         U8_LOG_WARNING( "Database was not open." );
     783             :     }
     784             : 
     785           0 :     U8_TRACE_END_ERR(result);
     786           0 :     return result;
     787             : }
     788             : 
     789             : 
     790             : /*
     791             : Copyright 2020-2024 Andreas Warnke
     792             : 
     793             : Licensed under the Apache License, Version 2.0 (the "License");
     794             : you may not use this file except in compliance with the License.
     795             : You may obtain a copy of the License at
     796             : 
     797             :     http://www.apache.org/licenses/LICENSE-2.0
     798             : 
     799             : Unless required by applicable law or agreed to in writing, software
     800             : distributed under the License is distributed on an "AS IS" BASIS,
     801             : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     802             : See the License for the specific language governing permissions and
     803             : limitations under the License.
     804             : */

Generated by: LCOV version 1.16