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

Generated by: LCOV version 2.0-1