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