Line data Source code
1 : /* File: data_search_result_iterator.c; Copyright and License: see below */
2 :
3 : #include "storage/data_search_result_iterator.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 : #include <stdint.h>
10 :
11 2 : u8_error_t data_search_result_iterator_init_empty ( data_search_result_iterator_t *this_ )
12 : {
13 2 : U8_TRACE_BEGIN();
14 2 : u8_error_t result = U8_ERROR_NONE;
15 :
16 2 : data_database_borrowed_stmt_init_void( &((*this_).diagram_statement) );
17 2 : data_database_borrowed_stmt_init_void( &((*this_).classifier_statement) );
18 2 : data_database_borrowed_stmt_init_void( &((*this_).feature_statement) );
19 2 : data_database_borrowed_stmt_init_void( &((*this_).relationship_statement) );
20 2 : (*this_).is_at_diagram_end = true;
21 2 : (*this_).is_at_classifier_end = true;
22 2 : (*this_).is_at_feature_end = true;
23 2 : (*this_).is_at_relationship_end = true;
24 2 : data_search_result_init_void( &((*this_).next_search_result_buf) );
25 :
26 2 : data_rules_init ( &((*this_).data_rules) );
27 :
28 2 : (*this_).last_relationship_id = DATA_ROW_VOID;
29 2 : (*this_).last_relationship_was_scenario = false;
30 :
31 2 : U8_TRACE_END_ERR(result);
32 2 : return result;
33 : }
34 :
35 2 : u8_error_t data_search_result_iterator_reinit ( data_search_result_iterator_t *this_,
36 : data_database_borrowed_stmt_t diagram_statement,
37 : data_database_borrowed_stmt_t classifier_statement,
38 : data_database_borrowed_stmt_t feature_statement,
39 : data_database_borrowed_stmt_t relationship_statement )
40 : {
41 2 : U8_TRACE_BEGIN();
42 2 : assert( data_database_borrowed_stmt_is_valid( &diagram_statement ) );
43 2 : assert( data_database_borrowed_stmt_is_valid( &classifier_statement ) );
44 2 : assert( data_database_borrowed_stmt_is_valid( &feature_statement ) );
45 2 : assert( data_database_borrowed_stmt_is_valid( &relationship_statement ) );
46 2 : u8_error_t result = U8_ERROR_NONE;
47 :
48 : /* destroy old state */
49 2 : result = data_search_result_iterator_destroy( this_ );
50 :
51 : /* init new state */
52 2 : (*this_).diagram_statement = diagram_statement;
53 2 : (*this_).classifier_statement = classifier_statement;
54 2 : (*this_).feature_statement = feature_statement;
55 2 : (*this_).relationship_statement = relationship_statement;
56 2 : (*this_).is_at_diagram_end = false;
57 2 : (*this_).is_at_classifier_end = false;
58 2 : (*this_).is_at_feature_end = false;
59 2 : (*this_).is_at_relationship_end = false;
60 2 : data_search_result_init_void( &((*this_).next_search_result_buf) );
61 2 : (*this_).last_relationship_id = DATA_ROW_VOID;
62 2 : (*this_).last_relationship_was_scenario = false;
63 :
64 2 : result |= data_search_result_iterator_private_step_to_next( this_ );
65 :
66 2 : data_rules_init ( &((*this_).data_rules) );
67 :
68 2 : U8_TRACE_END_ERR(result);
69 2 : return result;
70 : }
71 :
72 4 : u8_error_t data_search_result_iterator_destroy ( data_search_result_iterator_t *this_ )
73 : {
74 4 : U8_TRACE_BEGIN();
75 4 : u8_error_t result = U8_ERROR_NONE;
76 :
77 4 : (*this_).last_relationship_id = DATA_ROW_VOID;
78 4 : (*this_).last_relationship_was_scenario = false;
79 :
80 4 : data_rules_destroy ( &((*this_).data_rules) );
81 :
82 4 : result |= data_database_borrowed_stmt_destroy( &((*this_).diagram_statement) );
83 4 : result |= data_database_borrowed_stmt_destroy( &((*this_).classifier_statement) );
84 4 : result |= data_database_borrowed_stmt_destroy( &((*this_).feature_statement) );
85 4 : result |= data_database_borrowed_stmt_destroy( &((*this_).relationship_statement) );
86 4 : (*this_).is_at_diagram_end = true;
87 4 : (*this_).is_at_classifier_end = true;
88 4 : (*this_).is_at_feature_end = true;
89 4 : (*this_).is_at_relationship_end = true;
90 4 : data_search_result_destroy( &((*this_).next_search_result_buf) );
91 :
92 4 : U8_TRACE_END_ERR(result);
93 4 : return result;
94 : }
95 :
96 6 : bool data_search_result_iterator_has_next ( const data_search_result_iterator_t *this_ )
97 : {
98 5 : const bool finished = (*this_).is_at_diagram_end && (*this_).is_at_classifier_end
99 11 : && (*this_).is_at_feature_end && (*this_).is_at_relationship_end;
100 6 : assert( ( ! finished ) == data_search_result_is_valid( &((*this_).next_search_result_buf) ) );
101 6 : return ( ! finished );
102 : }
103 :
104 4 : u8_error_t data_search_result_iterator_next ( data_search_result_iterator_t *this_, data_search_result_t *out_search_result )
105 : {
106 4 : U8_TRACE_BEGIN();
107 4 : assert( NULL != out_search_result );
108 4 : assert( data_database_borrowed_stmt_is_valid( &((*this_).diagram_statement) ) );
109 4 : assert( data_database_borrowed_stmt_is_valid( &((*this_).classifier_statement) ) );
110 4 : assert( data_database_borrowed_stmt_is_valid( &((*this_).feature_statement) ) );
111 4 : assert( data_database_borrowed_stmt_is_valid( &((*this_).relationship_statement) ) );
112 4 : u8_error_t result = U8_ERROR_NONE;
113 :
114 : /* copy the next data_search_result_t to out */
115 4 : data_search_result_copy( out_search_result, &((*this_).next_search_result_buf) );
116 :
117 : /* search (and filter) for the next valid, unfiltered search result */
118 4 : data_search_result_iterator_private_step_to_next( this_ );
119 :
120 4 : U8_TRACE_END_ERR( result );
121 4 : return result;
122 : }
123 :
124 6 : u8_error_t data_search_result_iterator_private_step_to_next ( data_search_result_iterator_t *this_ )
125 : {
126 6 : U8_TRACE_BEGIN();
127 6 : assert( data_database_borrowed_stmt_is_valid( &((*this_).diagram_statement) ) );
128 6 : assert( data_database_borrowed_stmt_is_valid( &((*this_).classifier_statement) ) );
129 6 : assert( data_database_borrowed_stmt_is_valid( &((*this_).feature_statement) ) );
130 6 : assert( data_database_borrowed_stmt_is_valid( &((*this_).relationship_statement) ) );
131 6 : u8_error_t result = U8_ERROR_NONE;
132 :
133 : /* invalidate the next_search_result_buf */
134 6 : data_search_result_init_void( &((*this_).next_search_result_buf) );
135 :
136 6 : if ( ! (*this_).is_at_diagram_end )
137 : {
138 3 : sqlite3_stmt *const sql_statement = data_database_borrowed_stmt_get_statement( &((*this_).diagram_statement) );
139 :
140 : /* do one step, check if is_at_end */
141 3 : U8_TRACE_INFO( "sqlite3_step() at diagrams" );
142 3 : const int sqlite_err = sqlite3_step( sql_statement );
143 3 : if ( SQLITE_DONE == sqlite_err )
144 : {
145 2 : U8_TRACE_INFO( "sqlite3_step finished: SQLITE_DONE" );
146 2 : (*this_).is_at_diagram_end = true;
147 : }
148 1 : else if ( SQLITE_ROW == sqlite_err )
149 : {
150 1 : (*this_).is_at_diagram_end = false;
151 : /* read next */
152 1 : result |= data_search_result_iterator_private_get_diagram( this_, &((*this_).next_search_result_buf) );
153 : }
154 : else
155 : {
156 0 : U8_LOG_ERROR_INT( "sqlite3_step failed:", sqlite_err );
157 0 : (*this_).is_at_diagram_end = true;
158 0 : result |= U8_ERROR_AT_DB;
159 : }
160 : }
161 :
162 6 : if ( (*this_).is_at_diagram_end && ( ! (*this_).is_at_classifier_end ))
163 : {
164 3 : sqlite3_stmt *const sql_statement = data_database_borrowed_stmt_get_statement( &((*this_).classifier_statement) );
165 :
166 : /* do one step, check if is_at_end */
167 3 : U8_TRACE_INFO( "sqlite3_step() at classifiers" );
168 3 : const int sqlite_err = sqlite3_step( sql_statement );
169 3 : if ( SQLITE_DONE == sqlite_err )
170 : {
171 2 : U8_TRACE_INFO( "sqlite3_step finished: SQLITE_DONE" );
172 2 : (*this_).is_at_classifier_end = true;
173 : }
174 1 : else if ( SQLITE_ROW == sqlite_err )
175 : {
176 1 : (*this_).is_at_classifier_end = false;
177 : /* read next */
178 1 : result |= data_search_result_iterator_private_get_classifier( this_, &((*this_).next_search_result_buf) );
179 : }
180 : else
181 : {
182 0 : U8_LOG_ERROR_INT( "sqlite3_step failed:", sqlite_err );
183 0 : (*this_).is_at_classifier_end = true;
184 0 : result |= U8_ERROR_AT_DB;
185 : }
186 : }
187 :
188 9 : while ( (*this_).is_at_classifier_end && ( ! (*this_).is_at_feature_end ) && ( ! data_search_result_is_valid( &((*this_).next_search_result_buf) ) ) )
189 : {
190 3 : sqlite3_stmt *const sql_statement = data_database_borrowed_stmt_get_statement( &((*this_).feature_statement) );
191 :
192 : /* do one step, check if is_at_end */
193 3 : U8_TRACE_INFO( "sqlite3_step() at features" );
194 3 : const int sqlite_err = sqlite3_step( sql_statement );
195 3 : if ( SQLITE_DONE == sqlite_err )
196 : {
197 2 : U8_TRACE_INFO( "sqlite3_step finished: SQLITE_DONE" );
198 2 : (*this_).is_at_feature_end = true;
199 : }
200 1 : else if ( SQLITE_ROW == sqlite_err )
201 : {
202 1 : (*this_).is_at_feature_end = false;
203 : /* read next */
204 1 : result |= data_search_result_iterator_private_get_feature( this_, &((*this_).next_search_result_buf) );
205 : }
206 : else
207 : {
208 0 : U8_LOG_ERROR_INT( "sqlite3_step failed:", sqlite_err );
209 0 : (*this_).is_at_feature_end = true;
210 0 : result |= U8_ERROR_AT_DB;
211 : }
212 : }
213 :
214 9 : while ( (*this_).is_at_feature_end && ( ! (*this_).is_at_relationship_end ) && ( ! data_search_result_is_valid( &((*this_).next_search_result_buf) ) ) )
215 : {
216 3 : sqlite3_stmt *const sql_statement = data_database_borrowed_stmt_get_statement( &((*this_).relationship_statement) );
217 :
218 : /* do one step, check if is_at_end */
219 3 : U8_TRACE_INFO( "sqlite3_step() at relationships" );
220 3 : const int sqlite_err = sqlite3_step( sql_statement );
221 3 : if ( SQLITE_DONE == sqlite_err )
222 : {
223 2 : U8_TRACE_INFO( "sqlite3_step finished: SQLITE_DONE" );
224 2 : (*this_).is_at_relationship_end = true;
225 : }
226 1 : else if ( SQLITE_ROW == sqlite_err )
227 : {
228 1 : (*this_).is_at_relationship_end = false;
229 : /* read next */
230 1 : result |= data_search_result_iterator_private_get_relationship( this_, &((*this_).next_search_result_buf) );
231 : }
232 : else
233 : {
234 0 : U8_LOG_ERROR_INT( "sqlite3_step failed:", sqlite_err );
235 0 : (*this_).is_at_relationship_end = true;
236 0 : result |= U8_ERROR_AT_DB;
237 : }
238 : }
239 :
240 6 : U8_TRACE_END_ERR(result);
241 6 : return result;
242 : }
243 :
244 : /* ================================ DIAGRAM ================================ */
245 :
246 : /*!
247 : * \brief predefined search statement to find diagrams by textfragment
248 : *
249 : * note: name is needed for debugging only
250 : */
251 : const char *const DATA_SEARCH_RESULT_ITERATOR_SELECT_DIAGRAM_BY_TEXTFRAGMENT =
252 : "SELECT id,diagram_type,name "
253 : "FROM diagrams "
254 : "WHERE name LIKE ? ESCAPE \"\\\" "
255 : "OR stereotype LIKE ? ESCAPE \"\\\" "
256 : "OR description LIKE ? ESCAPE \"\\\";";
257 :
258 : /*!
259 : * \brief the column id of the result where this parameter is stored: id
260 : */
261 : static const int RESULT_DIAGRAM_ID_COLUMN = 0;
262 :
263 : /*!
264 : * \brief the column id of the result where this parameter is stored: diagram_type
265 : */
266 : static const int RESULT_DIAGRAM_TYPE_COLUMN = 1;
267 :
268 : /*!
269 : * \brief the column id of the result where this parameter is stored: name
270 : */
271 : static const int RESULT_DIAGRAM_NAME_COLUMN = 2;
272 :
273 :
274 1 : u8_error_t data_search_result_iterator_private_get_diagram( data_search_result_iterator_t *this_,
275 : data_search_result_t *out_search_result )
276 : {
277 1 : U8_TRACE_BEGIN();
278 1 : assert( NULL != out_search_result );
279 1 : u8_error_t result = U8_ERROR_NONE;
280 :
281 1 : sqlite3_stmt *const prepared_statement = data_database_borrowed_stmt_get_statement( &((*this_).diagram_statement) );
282 :
283 1 : data_search_result_init_diagram( out_search_result,
284 1 : sqlite3_column_int64( prepared_statement, RESULT_DIAGRAM_ID_COLUMN ),
285 1 : sqlite3_column_int( prepared_statement, RESULT_DIAGRAM_TYPE_COLUMN ),
286 1 : (const char*) sqlite3_column_text( prepared_statement, RESULT_DIAGRAM_NAME_COLUMN )
287 : );
288 1 : data_search_result_trace( out_search_result );
289 :
290 1 : U8_TRACE_END_ERR( result );
291 1 : return result;
292 : }
293 :
294 :
295 : /* ================================ CLASSIFIER ================================ */
296 :
297 : /*!
298 : * \brief predefined search statement to find classifiers by textfragment
299 : *
300 : * note: classifiers.name is needed for debugging only
301 : */
302 : const char *const DATA_SEARCH_RESULT_ITERATOR_SELECT_CLASSIFIER_BY_TEXTFRAGMENT =
303 : "SELECT classifiers.id,classifiers.main_type,classifiers.name,diagrams.id "
304 : "FROM classifiers "
305 : "INNER JOIN diagramelements ON diagramelements.classifier_id=classifiers.id "
306 : "INNER JOIN diagrams ON diagramelements.diagram_id=diagrams.id "
307 : "WHERE classifiers.name LIKE ? ESCAPE \"\\\" "
308 : "OR classifiers.stereotype LIKE ? ESCAPE \"\\\" "
309 : "OR classifiers.description LIKE ? ESCAPE \"\\\" "
310 : "GROUP BY classifiers.id,diagrams.id;"; /* no duplicates if a classifier is twice in a diagram */
311 :
312 : /*!
313 : * \brief the column id of the result where this parameter is stored: id
314 : */
315 : static const int RESULT_CLASSIFIER_ID_COLUMN = 0;
316 :
317 : /*!
318 : * \brief the column id of the result where this parameter is stored: main_type
319 : */
320 : static const int RESULT_CLASSIFIER_MAIN_TYPE_COLUMN = 1;
321 :
322 : /*!
323 : * \brief the column id of the result where this parameter is stored: name
324 : */
325 : static const int RESULT_CLASSIFIER_NAME_COLUMN = 2;
326 :
327 : /*!
328 : * \brief the column id of the result where this parameter is stored: diagrams.id
329 : */
330 : static const int RESULT_CLASSIFIER_DIAGRAM_ID_COLUMN = 3;
331 :
332 1 : u8_error_t data_search_result_iterator_private_get_classifier( data_search_result_iterator_t *this_,
333 : data_search_result_t *out_search_result )
334 : {
335 1 : U8_TRACE_BEGIN();
336 1 : assert( NULL != out_search_result );
337 1 : u8_error_t result = U8_ERROR_NONE;
338 :
339 1 : sqlite3_stmt *const prepared_statement = data_database_borrowed_stmt_get_statement( &((*this_).classifier_statement) );
340 :
341 1 : data_search_result_init_classifier( out_search_result,
342 1 : sqlite3_column_int64( prepared_statement, RESULT_CLASSIFIER_ID_COLUMN ),
343 1 : sqlite3_column_int( prepared_statement, RESULT_CLASSIFIER_MAIN_TYPE_COLUMN ),
344 1 : (const char*) sqlite3_column_text( prepared_statement, RESULT_CLASSIFIER_NAME_COLUMN ),
345 1 : sqlite3_column_int64( prepared_statement, RESULT_CLASSIFIER_DIAGRAM_ID_COLUMN )
346 : );
347 1 : data_search_result_trace( out_search_result );
348 :
349 1 : U8_TRACE_END_ERR( result );
350 1 : return result;
351 : }
352 :
353 : /* ================================ DIAGRAMELEMENT ================================ */
354 :
355 : /* ================================ FEATURE ================================ */
356 :
357 : /*!
358 : * \brief predefined search statement to find features by textfragment
359 : *
360 : * note: features.key is needed for debugging only
361 : */
362 : const char *const DATA_SEARCH_RESULT_ITERATOR_SELECT_FEATURE_BY_TEXTFRAGMENT =
363 : "SELECT features.id,features.main_type,features.key,features.classifier_id,"
364 : "classifiers.main_type,diagrams.id,diagrams.diagram_type "
365 : "FROM features "
366 : "INNER JOIN classifiers ON features.classifier_id=classifiers.id "
367 : "INNER JOIN diagramelements ON diagramelements.classifier_id=classifiers.id "
368 : "INNER JOIN diagrams ON diagramelements.diagram_id=diagrams.id "
369 : "WHERE features.key LIKE ? ESCAPE \"\\\" "
370 : "OR features.value LIKE ? ESCAPE \"\\\" "
371 : "OR features.description LIKE ? ESCAPE \"\\\" "
372 : "GROUP BY features.id,diagrams.id;"; /* no duplicates if a classifier is twice in a diagram */
373 :
374 : /*!
375 : * \brief the column id of the result where this parameter is stored: id
376 : */
377 : static const int RESULT_FEATURE_ID_COLUMN = 0;
378 :
379 : /*!
380 : * \brief the column id of the result where this parameter is stored: main_type
381 : */
382 : static const int RESULT_FEATURE_MAIN_TYPE_COLUMN = 1;
383 :
384 : /*!
385 : * \brief the column id of the result where this parameter is stored: key
386 : */
387 : static const int RESULT_FEATURE_KEY_COLUMN = 2;
388 :
389 : /*!
390 : * \brief the column id of the result where this parameter is stored: classifiers.id
391 : */
392 : static const int RESULT_FEATURE_CLASSIFIER_ID_COLUMN = 3;
393 :
394 : /*!
395 : * \brief the column id of the result where this parameter is stored: classifiers.main_type
396 : */
397 : static const int RESULT_FEATURE_CLASSIFIER_MAIN_TYPE_COLUMN = 4;
398 :
399 : /*!
400 : * \brief the column id of the result where this parameter is stored: diagrams.id
401 : */
402 : static const int RESULT_FEATURE_DIAGRAM_ID_COLUMN = 5;
403 :
404 : /*!
405 : * \brief the column id of the result where this parameter is stored: diagrams.diagram_type
406 : */
407 : static const int RESULT_FEATURE_DIAGRAM_TYPE_COLUMN = 6;
408 :
409 1 : u8_error_t data_search_result_iterator_private_get_feature( data_search_result_iterator_t *this_,
410 : data_search_result_t *out_search_result )
411 : {
412 1 : U8_TRACE_BEGIN();
413 1 : assert( NULL != out_search_result );
414 1 : u8_error_t result = U8_ERROR_NONE;
415 :
416 1 : sqlite3_stmt *const prepared_statement = data_database_borrowed_stmt_get_statement( &((*this_).feature_statement) );
417 :
418 1 : data_search_result_init_feature( out_search_result,
419 1 : sqlite3_column_int64( prepared_statement, RESULT_FEATURE_ID_COLUMN ),
420 1 : sqlite3_column_int( prepared_statement, RESULT_FEATURE_MAIN_TYPE_COLUMN ),
421 1 : (const char*) sqlite3_column_text( prepared_statement, RESULT_FEATURE_KEY_COLUMN ),
422 1 : sqlite3_column_int64( prepared_statement, RESULT_FEATURE_CLASSIFIER_ID_COLUMN ),
423 1 : sqlite3_column_int64( prepared_statement, RESULT_FEATURE_DIAGRAM_ID_COLUMN )
424 : );
425 1 : const data_type_t current_type = data_search_result_get_match_type( out_search_result );
426 1 : const data_feature_type_t f_type = data_type_get_feature_type( ¤t_type );
427 1 : const data_classifier_type_t c_type = sqlite3_column_int( prepared_statement, RESULT_FEATURE_CLASSIFIER_MAIN_TYPE_COLUMN );
428 1 : const data_diagram_type_t d_type = sqlite3_column_int( prepared_statement, RESULT_FEATURE_DIAGRAM_TYPE_COLUMN );
429 1 : U8_TRACE_INFO_INT( "- c_type:", c_type );
430 1 : U8_TRACE_INFO_INT( "- d_type:", d_type );
431 :
432 1 : bool filter = false;
433 1 : const bool is_scenario_feat = data_rules_feature_is_scenario_cond( &((*this_).data_rules), f_type );
434 1 : if ( is_scenario_feat )
435 : {
436 : /* text search never returns lifelines, independant of data_rules_diagram_shows_scenario_features */
437 0 : filter = true;
438 : }
439 : else
440 : {
441 : /* evaluate filter */
442 1 : const bool vis_by_classifier = data_rules_classifier_has_uncond_features ( &((*this_).data_rules), c_type );
443 1 : const bool vis_by_diagram = data_rules_diagram_shows_uncond_features ( &((*this_).data_rules), d_type );
444 1 : filter = !( vis_by_classifier && vis_by_diagram );
445 : }
446 :
447 1 : if ( filter )
448 : {
449 : /* invalidate the out_search_result */
450 0 : data_search_result_init_void( out_search_result );
451 : }
452 :
453 1 : data_search_result_trace( out_search_result );
454 :
455 1 : U8_TRACE_END_ERR( result );
456 1 : return result;
457 : }
458 :
459 :
460 : /* ================================ RELATIONSHIP ================================ */
461 :
462 : /*!
463 : * \brief predefined search statement to find relationships by textfragment
464 : *
465 : * note: relationships.name is needed for debugging only
466 : */
467 : const char *const DATA_SEARCH_RESULT_ITERATOR_SELECT_RELATIONSHIP_BY_TEXTFRAGMENT =
468 : "SELECT DISTINCT relationships.id,relationships.main_type,relationships.name,"
469 : "relationships.from_classifier_id,relationships.to_classifier_id,"
470 : "relationships.from_feature_id,relationships.to_feature_id,"
471 : "source.focused_feature_id,dest.focused_feature_id," /* challenge: the group by clause may randomly select ids here */
472 : "diagrams.id,diagrams.diagram_type "
473 : "FROM relationships "
474 : "INNER JOIN diagramelements AS source "
475 : "ON source.classifier_id=relationships.from_classifier_id "
476 : "INNER JOIN diagramelements AS dest "
477 : "ON (dest.classifier_id=relationships.to_classifier_id)AND(dest.diagram_id==source.diagram_id) "
478 : "INNER JOIN diagrams ON source.diagram_id=diagrams.id "
479 : "WHERE relationships.name LIKE ? ESCAPE \"\\\" "
480 : "OR relationships.stereotype LIKE ? ESCAPE \"\\\" "
481 : "OR relationships.description LIKE ? ESCAPE \"\\\" "
482 : //"GROUP BY relationships.id,diagrams.id " /* good: no duplicates if a classifier is twice in a diagram / bad: randomly chosen source and dest --> use DISTINCT */
483 : "ORDER BY relationships.id,( (source.focused_feature_id ISNULL) AND (dest.focused_feature_id ISNULL) ) ASC;"; /* start with interactions/scenarios */
484 :
485 : /*!
486 : * \brief the column id of the result where this parameter is stored: id
487 : */
488 : static const int RESULT_RELATIONSHIP_ID_COLUMN = 0;
489 :
490 : /*!
491 : * \brief the column id of the result where this parameter is stored: main_type
492 : */
493 : static const int RESULT_RELATIONSHIP_MAIN_TYPE_COLUMN = 1;
494 :
495 : /*!
496 : * \brief the column id of the result where this parameter is stored: name
497 : */
498 : static const int RESULT_RELATIONSHIP_NAME_COLUMN = 2;
499 :
500 : /*!
501 : * \brief the column id of the result where this parameter is stored: from_classifier_id
502 : */
503 : static const int RESULT_RELATIONSHIP_FROM_CLASSIFIER_ID_COLUMN = 3;
504 :
505 : /*!
506 : * \brief the column id of the result where this parameter is stored: to_classifier_id
507 : */
508 : static const int RESULT_RELATIONSHIP_TO_CLASSIFIER_ID_COLUMN = 4;
509 :
510 : /*!
511 : * \brief the column id of the result where this parameter is stored: from_feature_id
512 : */
513 : static const int RESULT_RELATIONSHIP_FROM_FEATURE_ID_COLUMN = 5;
514 :
515 : /*!
516 : * \brief the column id of the result where this parameter is stored: to_feature_id
517 : */
518 : static const int RESULT_RELATIONSHIP_TO_FEATURE_ID_COLUMN = 6;
519 :
520 : /*!
521 : * \brief the column id of the result where this parameter is stored: source.focused_feature_id
522 : *
523 : * In case of a GROUP BY clause, this id may not be related to the RESULT_RELATIONSHIP_FROM_FEATURE_ID_COLUMN due to random selection
524 : * One may consider to remove the GROUP BY and accept more search results
525 : */
526 : static const int RESULT_RELATIONSHIP_FROM_FOCUSED_ID_COLUMN = 7;
527 :
528 : /*!
529 : * \brief the column id of the result where this parameter is stored: dest.focused_feature_id
530 : *
531 : * In case of a GROUP BY clause, this id may not be related to the RESULT_RELATIONSHIP_TO_FEATURE_ID_COLUMN due to random selection
532 : * One may consider to remove the GROUP BY and accept more search results
533 : */
534 : static const int RESULT_RELATIONSHIP_TO_FOCUSED_ID_COLUMN = 8;
535 :
536 : /*!
537 : * \brief the column id of the result where this parameter is stored: diagrams.id
538 : */
539 : static const int RESULT_RELATIONSHIP_DIAGRAM_ID_COLUMN = 9;
540 :
541 : /*!
542 : * \brief the column id of the result where this parameter is stored: diagrams.diagram_type
543 : */
544 : static const int RESULT_RELATIONSHIP_DIAGRAM_TYPE_COLUMN = 10;
545 :
546 1 : u8_error_t data_search_result_iterator_private_get_relationship( data_search_result_iterator_t *this_,
547 : data_search_result_t *out_search_result )
548 : {
549 1 : U8_TRACE_BEGIN();
550 1 : assert( NULL != out_search_result );
551 1 : u8_error_t result = U8_ERROR_NONE;
552 :
553 1 : sqlite3_stmt *const prepared_statement = data_database_borrowed_stmt_get_statement( &((*this_).relationship_statement) );
554 :
555 1 : data_search_result_init_relationship( out_search_result,
556 1 : sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_ID_COLUMN ),
557 1 : sqlite3_column_int( prepared_statement, RESULT_RELATIONSHIP_MAIN_TYPE_COLUMN ),
558 1 : (const char*) sqlite3_column_text( prepared_statement, RESULT_RELATIONSHIP_NAME_COLUMN ),
559 1 : sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_FROM_CLASSIFIER_ID_COLUMN ),
560 1 : sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_TO_CLASSIFIER_ID_COLUMN ),
561 1 : sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_DIAGRAM_ID_COLUMN )
562 : );
563 1 : const data_row_t from_feat
564 1 : = ( SQLITE_NULL != sqlite3_column_type( prepared_statement, RESULT_RELATIONSHIP_FROM_FEATURE_ID_COLUMN ) )
565 1 : ? sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_FROM_FEATURE_ID_COLUMN )
566 1 : : DATA_ROW_VOID;
567 1 : const data_row_t to_feat
568 1 : = ( SQLITE_NULL != sqlite3_column_type( prepared_statement, RESULT_RELATIONSHIP_TO_FEATURE_ID_COLUMN ) )
569 0 : ? sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_TO_FEATURE_ID_COLUMN )
570 1 : : DATA_ROW_VOID;
571 1 : const data_row_t from_focused
572 1 : = ( SQLITE_NULL != sqlite3_column_type( prepared_statement, RESULT_RELATIONSHIP_FROM_FOCUSED_ID_COLUMN ) )
573 0 : ? sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_FROM_FOCUSED_ID_COLUMN )
574 1 : : DATA_ROW_VOID;
575 1 : const data_row_t to_focused
576 1 : = ( SQLITE_NULL != sqlite3_column_type( prepared_statement, RESULT_RELATIONSHIP_TO_FOCUSED_ID_COLUMN ) )
577 0 : ? sqlite3_column_int64( prepared_statement, RESULT_RELATIONSHIP_TO_FOCUSED_ID_COLUMN )
578 1 : : DATA_ROW_VOID;
579 1 : const data_diagram_type_t d_type = sqlite3_column_int( prepared_statement, RESULT_RELATIONSHIP_DIAGRAM_TYPE_COLUMN );
580 1 : U8_TRACE_INFO_INT( "- from_feat:", from_feat );
581 1 : U8_TRACE_INFO_INT( "- to_feat:", to_feat );
582 1 : U8_TRACE_INFO_INT( "- d_type:", d_type );
583 1 : const data_row_t rel_row_id = data_id_get_row_id( data_search_result_get_match_id_const( out_search_result ) );
584 :
585 1 : bool filter = false;
586 1 : const bool is_scenario_diag = data_rules_diagram_is_scenario ( &((*this_).data_rules), d_type );
587 : /*const bool is_scenario_rel = data_rules_relationship_is_scenario_cond( &((*this_).data_rules), from_feature_type, to_feature_type);*/
588 1 : if ( is_scenario_diag )
589 : {
590 : /* in theory, we would need to know the from_feature_type and the to_feature_type to determine the visibility: */
591 : /*
592 : * const bool is_shown = data_rules_relationship_is_scenario_cond( const data_rules_t *this_,
593 : * data_feature_type_t from_feature_type,
594 : * data_feature_type_t to_feature_type
595 : * );
596 : */
597 : /* but we only have the data_relationship_type_t and the data_diagramelement_t here and we control the order of results: */
598 0 : const bool from_is_lifeline = ( DATA_ROW_VOID != from_feat )&&( from_focused == from_feat );
599 0 : const bool to_is_lifeline = ( DATA_ROW_VOID != to_feat )&&( to_focused == to_feat );
600 0 : const bool visible = from_is_lifeline && to_is_lifeline;
601 0 : if ( visible )
602 : {
603 0 : filter = false;
604 0 : (*this_).last_relationship_was_scenario = true;
605 0 : (*this_).last_relationship_id = rel_row_id;
606 0 : U8_TRACE_INFO_INT( "data_search_result_iterator: in scenario found relationship", rel_row_id );
607 : }
608 : else
609 : {
610 0 : filter = true;
611 0 : U8_TRACE_INFO_INT( "data_search_result_iterator: in scenario skipped invisible relationship", rel_row_id );
612 : }
613 : }
614 : else
615 : {
616 : /* in theory, we would need to know the from_feature_type and the to_feature_type to determine the visibility: */
617 : /*
618 : * const bool is_shown = data_rules_relationship_is_scenario_cond( const data_rules_t *this_,
619 : * data_feature_type_t from_feature_type,
620 : * data_feature_type_t to_feature_type
621 : * );
622 : */
623 : /* but we only have the data_relationship_type_t and the data_diagramelement_t here and we control the order of results: */
624 1 : const bool is_scenario = ( (*this_).last_relationship_id == rel_row_id )&&( (*this_).last_relationship_was_scenario );
625 1 : const bool vis_by_diagram = data_rules_diagram_shows_uncond_relationships ( &((*this_).data_rules), d_type );
626 1 : if ( vis_by_diagram && ( ! is_scenario ) )
627 : {
628 1 : filter = false;
629 1 : (*this_).last_relationship_was_scenario = false;
630 1 : (*this_).last_relationship_id = rel_row_id;
631 1 : U8_TRACE_INFO_INT( "data_search_result_iterator: non-scenario found relationship", rel_row_id );
632 : }
633 : else
634 : {
635 0 : filter = true;
636 0 : U8_TRACE_INFO_INT( "data_search_result_iterator: non-scenario skipped scenario-specific relationship", rel_row_id );
637 : }
638 : }
639 :
640 1 : if ( filter )
641 : {
642 : /* invalidate the out_search_result */
643 0 : data_search_result_init_void( out_search_result );
644 : }
645 :
646 1 : data_search_result_trace( out_search_result );
647 :
648 1 : U8_TRACE_END_ERR( result );
649 1 : return result;
650 : }
651 :
652 :
653 : /*
654 : Copyright 2020-2025 Andreas Warnke
655 :
656 : Licensed under the Apache License, Version 2.0 (the "License");
657 : you may not use this file except in compliance with the License.
658 : You may obtain a copy of the License at
659 :
660 : http://www.apache.org/licenses/LICENSE-2.0
661 :
662 : Unless required by applicable law or agreed to in writing, software
663 : distributed under the License is distributed on an "AS IS" BASIS,
664 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
665 : See the License for the specific language governing permissions and
666 : limitations under the License.
667 : */
|