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.61.0_covts Lines: 0 265 0.0 %
Date: 2024-10-26 21:44:38 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           0 :                                                  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           0 :                                                     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           0 :                                                  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_type_t current_type = data_search_result_get_match_type( &current_result );
     494           0 :                 const data_feature_type_t f_type = data_type_get_feature_type( &current_type );
     495           0 :                 const data_classifier_type_t c_type = sqlite3_column_int( prepared_statement, RESULT_FEATURE_CLASSIFIER_MAIN_TYPE_COLUMN );
     496           0 :                 const data_diagram_type_t d_type = sqlite3_column_int( prepared_statement, RESULT_FEATURE_DIAGRAM_TYPE_COLUMN );
     497           0 :                 U8_TRACE_INFO_INT( "- c_type:", c_type );
     498           0 :                 U8_TRACE_INFO_INT( "- d_type:", d_type );
     499             : 
     500           0 :                 bool filter = false;
     501           0 :                 const bool is_scenario_feat = data_rules_feature_is_scenario_cond( &((*this_).data_rules), f_type );
     502           0 :                 if ( is_scenario_feat )
     503             :                 {
     504             :                     /* text search never returns lifelines, independant of data_rules_diagram_shows_scenario_features */
     505           0 :                     filter = true;
     506             :                 }
     507             :                 else
     508             :                 {
     509             :                     /* evaluate filter */
     510           0 :                     const bool vis_by_classifier = data_rules_classifier_has_uncond_features ( &((*this_).data_rules), c_type );
     511           0 :                     const bool vis_by_diagram = data_rules_diagram_shows_uncond_features ( &((*this_).data_rules), d_type );
     512           0 :                     filter = !( vis_by_classifier && vis_by_diagram );
     513             :                 }
     514             : 
     515           0 :                 if ( ! filter )
     516             :                 {
     517           0 :                     const u8_error_t err_full = data_search_result_list_add( io_results, &current_result );
     518           0 :                     if ( err_full != U8_ERROR_NONE )
     519             :                     {
     520           0 :                         U8_LOG_ANOMALY_INT( "io_results list full:", data_search_result_list_get_length( io_results ) );
     521           0 :                         result |= err_full;
     522             :                     }
     523             :                 }
     524             : 
     525           0 :                 data_search_result_trace( &current_result );
     526           0 :                 data_search_result_destroy( &current_result );
     527             :             }
     528             :         }
     529             :     }
     530             :     else
     531             :     {
     532           0 :         result |= U8_ERROR_NO_DB;
     533           0 :         U8_TRACE_INFO( "Database not open, cannot request data." );
     534             :     }
     535             : 
     536             : 
     537           0 :     U8_TRACE_END_ERR( result );
     538           0 :     return result;
     539             : }
     540             : 
     541             : 
     542             : /* ================================ RELATIONSHIP ================================ */
     543             : 
     544             : /*!
     545             :  *  \brief predefined search statement to find relationships by textfragment
     546             :  *
     547             :  *  note: relationships.name is needed for debugging only
     548             :  */
     549             : static const char data_database_text_search_SELECT_RELATIONSHIP_BY_TEXTFRAGMENT[] =
     550             :     "SELECT DISTINCT relationships.id,relationships.main_type,relationships.name,"
     551             :     "relationships.from_classifier_id,relationships.to_classifier_id,"
     552             :     "relationships.from_feature_id,relationships.to_feature_id,"
     553             :     "diagrams.id,diagrams.diagram_type "
     554             :     "FROM relationships "
     555             :     "INNER JOIN diagramelements AS source "
     556             :     "ON source.classifier_id=relationships.from_classifier_id "
     557             :     "INNER JOIN diagramelements AS dest "
     558             :     "ON (dest.classifier_id=relationships.to_classifier_id)AND(dest.diagram_id==source.diagram_id) "
     559             :     "INNER JOIN diagrams ON source.diagram_id=diagrams.id "
     560             :     "WHERE relationships.name LIKE ? ESCAPE \"\\\" "
     561             :     "OR relationships.stereotype LIKE ? ESCAPE \"\\\" "
     562             :     "OR relationships.description LIKE ? ESCAPE \"\\\" "
     563             :     "GROUP BY relationships.id,diagrams.id;";  /* no duplicates if a classifier is twice in a diagram */
     564             : 
     565             : /*!
     566             :  *  \brief the column id of the result where this parameter is stored: id
     567             :  */
     568             : static const int RESULT_RELATIONSHIP_ID_COLUMN = 0;
     569             : 
     570             : /*!
     571             :  *  \brief the column id of the result where this parameter is stored: main_type
     572             :  */
     573             : static const int RESULT_RELATIONSHIP_MAIN_TYPE_COLUMN = 1;
     574             : 
     575             : /*!
     576             :  *  \brief the column id of the result where this parameter is stored: name
     577             :  */
     578             : static const int RESULT_RELATIONSHIP_NAME_COLUMN = 2;
     579             : 
     580             : /*!
     581             :  *  \brief the column id of the result where this parameter is stored: from_classifier_id
     582             :  */
     583             : static const int RESULT_RELATIONSHIP_FROM_CLASSIFIER_ID_COLUMN = 3;
     584             : 
     585             : /*!
     586             :  *  \brief the column id of the result where this parameter is stored: to_classifier_id
     587             :  */
     588             : static const int RESULT_RELATIONSHIP_TO_CLASSIFIER_ID_COLUMN = 4;
     589             : 
     590             : /*!
     591             :  *  \brief the column id of the result where this parameter is stored: from_feature_id
     592             :  */
     593             : static const int RESULT_RELATIONSHIP_FROM_FEATURE_ID_COLUMN = 5;
     594             : 
     595             : /*!
     596             :  *  \brief the column id of the result where this parameter is stored: to_feature_id
     597             :  */
     598             : static const int RESULT_RELATIONSHIP_TO_FEATURE_ID_COLUMN = 6;
     599             : 
     600             : /*!
     601             :  *  \brief the column id of the result where this parameter is stored: diagrams.id
     602             :  */
     603             : static const int RESULT_RELATIONSHIP_DIAGRAM_ID_COLUMN = 7;
     604             : 
     605             : /*!
     606             :  *  \brief the column id of the result where this parameter is stored: diagrams.diagram_type
     607             :  */
     608             : static const int RESULT_RELATIONSHIP_DIAGRAM_TYPE_COLUMN = 8;
     609             : 
     610           0 : u8_error_t data_database_text_search_private_get_relationships_by_textfragment( data_database_text_search_t *this_,
     611             :                                                                                 const char *name_fragment,
     612             :                                                                                 const char *stereo_fragment,
     613             :                                                                                 const char *descr_fragment,
     614             :                                                                                 data_search_result_list_t *io_results )
     615             : {
     616           0 :     U8_TRACE_BEGIN();
     617           0 :     assert( NULL != io_results );
     618           0 :     assert( NULL != name_fragment );
     619           0 :     assert( NULL != stereo_fragment );
     620           0 :     assert( NULL != descr_fragment );
     621           0 :     u8_error_t result = U8_ERROR_NONE;
     622             : 
     623             :     int sqlite_err;
     624             :     sqlite3_stmt *prepared_statement;
     625           0 :     unsigned int dropped_scenario_rel = 0;
     626             : 
     627           0 :     if ( (*this_).is_open )
     628             :     {
     629           0 :         prepared_statement = (*this_).statement_relationship_ids_by_textfragment;
     630             : 
     631           0 :         result |= data_database_text_search_private_bind_three_texts_to_statement( this_,
     632             :                                                                                    prepared_statement,
     633             :                                                                                    name_fragment,
     634             :                                                                                    stereo_fragment,
     635             :                                                                                    descr_fragment
     636             :                                                                                  );
     637             : 
     638           0 :         sqlite_err = SQLITE_ROW;
     639           0 :         for ( uint32_t row_index = 0; (SQLITE_ROW == sqlite_err) && (U8_ERROR_NONE == result); row_index ++ )
     640             :         {
     641           0 :             U8_TRACE_INFO_INT( "sqlite3_step():", (row_index+1) );
     642           0 :             sqlite_err = sqlite3_step( prepared_statement );
     643           0 :             if ( SQLITE_DONE == sqlite_err )
     644             :             {
     645           0 :                 U8_TRACE_INFO( "sqlite3_step finished: SQLITE_DONE" );
     646             :             }
     647           0 :             else if ( SQLITE_ROW != sqlite_err )
     648             :             {
     649           0 :                 U8_LOG_ERROR_INT( "sqlite3_step failed:", sqlite_err );
     650           0 :                 result |= U8_ERROR_AT_DB;
     651             :             }
     652             :             else
     653             :             {
     654             :                 data_search_result_t current_result;
     655             : 
     656           0 :                 data_search_result_init_relationship( &current_result,
     657           0 :                                                       sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_ID_COLUMN ),
     658           0 :                                                       sqlite3_column_int( prepared_statement, RESULT_RELATIONSHIP_MAIN_TYPE_COLUMN ),
     659           0 :                                                       (const char*) sqlite3_column_text( prepared_statement, RESULT_RELATIONSHIP_NAME_COLUMN ),
     660           0 :                                                       sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_FROM_CLASSIFIER_ID_COLUMN ),
     661           0 :                                                       sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_TO_CLASSIFIER_ID_COLUMN ),
     662           0 :                                                       sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_DIAGRAM_ID_COLUMN )
     663             :                                                     );
     664           0 :                 const data_row_id_t from_feat = sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_FROM_FEATURE_ID_COLUMN );
     665           0 :                 const data_row_id_t to_feat = sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_TO_FEATURE_ID_COLUMN );
     666           0 :                 const data_diagram_type_t d_type = sqlite3_column_int( prepared_statement, RESULT_RELATIONSHIP_DIAGRAM_TYPE_COLUMN );
     667           0 :                 U8_TRACE_INFO_INT( "- from_feat:", from_feat );
     668           0 :                 U8_TRACE_INFO_INT( "- to_feat:", to_feat );
     669           0 :                 U8_TRACE_INFO_INT( "- d_type:", d_type );
     670             : 
     671           0 :                 bool filter = false;
     672           0 :                 const bool is_scenario_diag = data_rules_diagram_is_scenario ( &((*this_).data_rules), d_type );
     673             :                 /*const bool is_scenario_rel = data_rules_relationship_is_scenario_cond( &((*this_).data_rules), from_feature_type, to_feature_type);*/
     674           0 :                 if ( is_scenario_diag )
     675             :                 {
     676             :                     /* there could be valid relationships that are visible and match the search. */
     677             :                     /* but it is quite difficult to determine if the relationship is visible in the current diagram */
     678             :                     /* --> drop the result and write a not to the log */
     679           0 :                     dropped_scenario_rel ++;
     680           0 :                     filter = true;
     681             :                 }
     682             :                 else
     683             :                 {
     684             :                     /* there could be hidden scenario-typed relationships in a non-scenario diagram. */
     685             :                     /* but it is quite difficult to determine if the relationship is scenario-only */
     686             :                     /* --> show the result anyway */
     687           0 :                     const bool vis_by_diagram = data_rules_diagram_shows_uncond_relationships ( &((*this_).data_rules), d_type );
     688           0 :                     filter = ! vis_by_diagram;
     689             :                 }
     690             : 
     691           0 :                 if ( ! filter )
     692             :                 {
     693           0 :                     const u8_error_t err_full = data_search_result_list_add( io_results, &current_result );
     694           0 :                     if ( err_full != U8_ERROR_NONE )
     695             :                     {
     696           0 :                         U8_LOG_ANOMALY_INT( "io_results list full:", data_search_result_list_get_length( io_results ) );
     697           0 :                         result |= err_full;
     698             :                     }
     699             :                 }
     700             : 
     701           0 :                 data_search_result_trace( &current_result );
     702           0 :                 data_search_result_destroy( &current_result );
     703             :             }
     704             :         }
     705             :     }
     706             :     else
     707             :     {
     708           0 :         result |= U8_ERROR_NO_DB;
     709           0 :         U8_TRACE_INFO( "Database not open, cannot request data." );
     710             :     }
     711             : 
     712           0 :     if ( dropped_scenario_rel != 0 )
     713             :     {
     714           0 :         U8_LOG_ANOMALY_INT( "Full text search does not work on relationships in scenario based diagrams. Possibly missed relationships:",
     715             :                            dropped_scenario_rel
     716             :                          );
     717             :     }
     718             : 
     719           0 :     U8_TRACE_END_ERR( result );
     720           0 :     return result;
     721             : }
     722             : 
     723             : 
     724             : /* ================================ private ================================ */
     725             : 
     726           0 : u8_error_t data_database_text_search_private_open( data_database_text_search_t *this_ )
     727             : {
     728           0 :     U8_TRACE_BEGIN();
     729           0 :     u8_error_t result = U8_ERROR_NONE;
     730             : 
     731           0 :     if ( ! (*this_).is_open )
     732             :     {
     733           0 :         result |= data_database_prepare_statement( (*this_).database,
     734             :                                                    data_database_text_search_SELECT_DIAGRAM_BY_TEXTFRAGMENT,
     735             :                                                    sizeof( data_database_text_search_SELECT_DIAGRAM_BY_TEXTFRAGMENT ),
     736             :                                                    &((*this_).statement_diagram_ids_by_textfragment)
     737             :                                                  );
     738           0 :         result |= data_database_prepare_statement( (*this_).database,
     739             :                                                    data_database_text_search_SELECT_CLASSIFIER_BY_TEXTFRAGMENT,
     740             :                                                    sizeof( data_database_text_search_SELECT_CLASSIFIER_BY_TEXTFRAGMENT ),
     741             :                                                    &((*this_).statement_classifier_ids_by_textfragment)
     742             :                                                  );
     743           0 :         result |= data_database_prepare_statement( (*this_).database,
     744             :                                                    data_database_text_search_SELECT_FEATURE_BY_TEXTFRAGMENT,
     745             :                                                    sizeof( data_database_text_search_SELECT_FEATURE_BY_TEXTFRAGMENT ),
     746             :                                                    &((*this_).statement_feature_ids_by_textfragment)
     747             :                                                  );
     748           0 :         result |= data_database_prepare_statement( (*this_).database,
     749             :                                                    data_database_text_search_SELECT_RELATIONSHIP_BY_TEXTFRAGMENT,
     750             :                                                    sizeof( data_database_text_search_SELECT_RELATIONSHIP_BY_TEXTFRAGMENT ),
     751             :                                                    &((*this_).statement_relationship_ids_by_textfragment)
     752             :                                                  );
     753             : 
     754           0 :         (*this_).is_open = true;
     755             :     }
     756             :     else
     757             :     {
     758           0 :         result |= U8_ERROR_INVALID_REQUEST;
     759           0 :         U8_LOG_WARNING( "Database is already open." );
     760             :     }
     761             : 
     762           0 :     U8_TRACE_END_ERR(result);
     763           0 :     return result;
     764             : }
     765             : 
     766           0 : u8_error_t data_database_text_search_private_close( data_database_text_search_t *this_ )
     767             : {
     768           0 :     U8_TRACE_BEGIN();
     769           0 :     u8_error_t result = U8_ERROR_NONE;
     770             : 
     771           0 :     if ( (*this_).is_open )
     772             :     {
     773           0 :         result |= data_database_finalize_statement( (*this_).database, (*this_).statement_relationship_ids_by_textfragment );
     774           0 :         result |= data_database_finalize_statement( (*this_).database, (*this_).statement_feature_ids_by_textfragment );
     775           0 :         result |= data_database_finalize_statement( (*this_).database, (*this_).statement_classifier_ids_by_textfragment );
     776           0 :         result |= data_database_finalize_statement( (*this_).database, (*this_).statement_diagram_ids_by_textfragment );
     777             : 
     778           0 :         (*this_).is_open = false;
     779             :     }
     780             :     else
     781             :     {
     782           0 :         result |= U8_ERROR_INVALID_REQUEST;
     783           0 :         U8_LOG_WARNING( "Database was not open." );
     784             :     }
     785             : 
     786           0 :     U8_TRACE_END_ERR(result);
     787           0 :     return result;
     788             : }
     789             : 
     790             : 
     791             : /*
     792             : Copyright 2020-2024 Andreas Warnke
     793             : 
     794             : Licensed under the Apache License, Version 2.0 (the "License");
     795             : you may not use this file except in compliance with the License.
     796             : You may obtain a copy of the License at
     797             : 
     798             :     http://www.apache.org/licenses/LICENSE-2.0
     799             : 
     800             : Unless required by applicable law or agreed to in writing, software
     801             : distributed under the License is distributed on an "AS IS" BASIS,
     802             : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     803             : See the License for the specific language governing permissions and
     804             : limitations under the License.
     805             : */

Generated by: LCOV version 1.16