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