DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
query.cpp
Go to the documentation of this file.
1// DUNE DAQ modification notice:
2// This file has been modified from the original ATLAS oks source for the DUNE DAQ project.
3// Fork baseline commit: oks-08-03-04 (2022-04-14).
4// Renamed since fork: no.
5
6#define _OksBuildDll_
7
8#include "oks/query.hpp"
9#include "oks/attribute.hpp"
10#include "oks/relationship.hpp"
11#include "oks/class.hpp"
12#include "oks/object.hpp"
13#include "oks/kernel.hpp"
14#include "oks/index.hpp"
15#include "oks/profiler.hpp"
16
17#include <stdexcept>
18#include <sstream>
19
20namespace dunedaq {
21namespace oks {
22
23const char * OksQuery::OR = "or";
24const char * OksQuery::AND = "and";
25const char * OksQuery::NOT = "not";
26const char * OksQuery::SOME = "some";
27const char * OksQuery::THIS_CLASS = "this";
28const char * OksQuery::ALL_SUBCLASSES = "all";
29const char * OksQuery::OID = "object-id";
30const char * OksQuery::EQ = "=";
31const char * OksQuery::NE = "!=";
32const char * OksQuery::RE = "~=";
33const char * OksQuery::LE = "<=";
34const char * OksQuery::GE = ">=";
35const char * OksQuery::LS = "<";
36const char * OksQuery::GT = ">";
37const char * OksQuery::PATH_TO = "path-to";
38const char * OksQuery::DIRECT = "direct";
39const char * OksQuery::NESTED = "nested";
40
41 std::string
42 QueryFailed::fill(const OksQueryExpression& query, const OksClass& c, const std::string& reason) noexcept
43 {
44 std::ostringstream text;
45 text << "query \"" << query << "\" in class \"" << c.get_name() << "\" failed:\n" << reason;
46 return text.str();
47 }
48
49 std::string
50 BadReqExp::fill(const std::string& what, const std::string& reason) noexcept
51 {
52 return std::string("failed to create reqular expression \"") + what + "\": " + reason;
53 }
54
55
56bool OksQuery::equal_cmp(const OksData *d1, const OksData *d2) {return (*d1 == *d2);}
57bool OksQuery::not_equal_cmp(const OksData *d1, const OksData *d2) {return (*d1 != *d2);}
58bool OksQuery::less_or_equal_cmp(const OksData *d1, const OksData *d2) {return (*d1 <= *d2);}
59bool OksQuery::greater_or_equal_cmp(const OksData *d1, const OksData *d2) {return (*d1 >= *d2);}
60bool OksQuery::less_cmp(const OksData *d1, const OksData *d2) {return (*d1 < *d2);}
61bool OksQuery::greater_cmp(const OksData *d1, const OksData *d2) {return (*d1 > *d2);}
62bool OksQuery::reg_exp_cmp(const OksData *d, const OksData * re) {
63 return boost::regex_match(d->str(), *reinterpret_cast<const boost::regex *>(re));
64}
65
66
68{
69 delete value;
70 value = v;
71
73}
74
76{
77 if(m_reg_exp) {
78 delete m_reg_exp;
79 m_reg_exp = 0;
80 }
81}
82
83
84inline void erase_empty_chars(std::string& s)
85{
86 while(s[0] == ' ' || s[0] == '\n' || s[0] == '\t') s.erase(0, 1);
87}
88
89
90OksQuery::OksQuery(const OksClass *c, const std::string & str) : p_expression (0), p_status (1)
91{
93
94 const char * fname = "OksQuery::OksQuery(OksClass *, const char *)";
95 const char * error_str = "Can't create query ";
96
97 char delimiter = '\0';
98
99 if(!c) {
100 Oks::error_msg(fname) << error_str << "without specified class\n";
101 return;
102 }
103
104 if(str.empty()) {
105 Oks::error_msg(fname) << error_str << "from empty string\n";
106 return;
107 }
108
109 std::string s(str);
110
112
113 if(s.empty()) {
114 Oks::error_msg(fname) << error_str << "from string which consists of space symbols\n";
115 return;
116 }
117
118 if(s[0] == '(') {
119 s.erase(0, 1);
120 delimiter = ')';
121 }
122
123 std::string::size_type p = s.find(' ');
124
125 if(p == std::string::npos) {
126 Oks::error_msg(fname)
127 << "Can't parse query expression \"" << str << "\"\n"
128 "it must consists of as minimum two tokens separated by space\n";
129 return;
130 }
131
132 if(s.substr(0, p) == OksQuery::ALL_SUBCLASSES)
133 p_sub_classes = true;
134 else if(s.substr(0, p) == OksQuery::THIS_CLASS)
135 p_sub_classes = false;
136 else {
137 Oks::error_msg(fname)
138 << "Can't parse query expression \"" << str << "\"\n"
139 "the first token must be \'"<< OksQuery::ALL_SUBCLASSES
140 << "\' or \'"<< OksQuery::THIS_CLASS << "\'\n";
141 return;
142 }
143
144 s.erase(0, p + 1);
145
146 if(delimiter == ')') {
147 p = s.rfind(delimiter);
148 if(p == std::string::npos) {
149 Oks::error_msg(fname)
150 << "Can't parse query expression \"" << str << "\"\n"
151 "it must contain closing bracket \')\' if it has opening bracket \'(\'\n";
152 return;
153 }
154
155 s.erase(p);
156 }
157
158
160
161
162 if(s[0] == '(') {
163 p = s.rfind(')');
164
165 if(p == std::string::npos) {
166 Oks::error_msg(fname)
167 << "Can't parse query expression \"" << s << "\"\n"
168 "it must contain closing bracket \')\' if it has opening bracket \'(\'\n";
169 return;
170 }
171
172 s.erase(p);
173 s.erase(0, 1);
174
176
177 if(p_expression) p_status = 0;
178 }
179 else
180 Oks::error_msg(fname)
181 << "Can't parse subquery expression \"" << s << "\"\n"
182 "it must be enclosed by brackets\n";
183}
184
185
187OksQuery::create_expression(const OksClass *c, const std::string & str)
188{
189 const char * fname = "OksQuery::create_expression()";
190
192
193 OksQueryExpression *qe = 0;
194
195 if(!c) {
196 Oks::error_msg(fname) << "Can't create query without specified class\n";
197 return qe;
198 }
199
200 if(str.empty()) {
201 Oks::error_msg(fname) << "Can't create query from empty string\n";
202 return qe;
203 }
204
205 std::string s(str);
206
207 std::list<std::string> slist;
208
209 while(s.length()) {
211
212 if(!s.length()) break;
213
214 if(
215 s[0] == '\"' ||
216 s[0] == '\'' ||
217 s[0] == '`'
218 ) {
219 char delimiter = s[0];
220 s.erase(0, 1);
221
222 std::string::size_type p = s.find(delimiter);
223
224 if(p == std::string::npos) {
225 Oks::error_msg(fname)
226 << "Can't parse query expression \"" << str << "\"\n"
227 "the delimiter is \' "<< delimiter << " \'\n"
228 "the rest of the expression is \"" << s << "\"\n";
229 return qe;
230 }
231
232 s.erase(p, 1);
233 slist.push_back(std::string(s, 0, p));
234
235 s.erase(0, p + 1);
236 }
237 else if(s[0] == '(') {
238 std::string::size_type p = 1;
239 size_t strLength = s.length();
240 size_t r = 1;
241
242 while(p < strLength) {
243 if(s[p] == '(') r++;
244 if(s[p] == ')') {
245 r--;
246 if(!r) break;
247 }
248 p++;
249 }
250
251 if(r) {
252 Oks::error_msg(fname)
253 << "Can't parse query expression \"" << str << "\"\n"
254 << "There is no closing \')\' for " << '\"' << s << "\"\n";
255 return qe;
256 }
257
258 s.erase(p, 1);
259 s.erase(0, 1);
260
261 slist.push_back(std::string(s, 0, p - 1));
262
263 s.erase(0, p - 1);
264 }
265 else {
266 std::string::size_type p = 0;
267 size_t strLength = s.length();
268
269 while(p < strLength && s[p] != ' ') p++;
270
271 slist.push_back(std::string(s, 0, p));
272
273 s.erase(0, p);
274 }
275 }
276
277 if(slist.empty()) {
278 Oks::error_msg(fname)
279 << "Can't create query from empty string \"" << str << "\"\n";
280 return qe;
281 }
282
283 const std::string first = slist.front();
284 slist.pop_front();
285
286 if(
287 first == OksQuery::AND ||
288 first == OksQuery::OR
289 ) {
290 if(slist.size() < 2) {
291 Oks::error_msg(fname) << "\'" << first << "\' must have two or more arguments: (" << str << ")'\n";
292 return qe;
293 }
294
295 qe = (
296 (first == OksQuery::AND)
299 );
300
301 while(!slist.empty()) {
302 const std::string item2 = slist.front();
303 slist.pop_front();
304
305 OksQueryExpression *qe2 = create_expression(c, item2);
306
307 if(qe2) {
308 if(first == OksQuery::AND)
309 ((OksAndExpression *)qe)->add(qe2);
310 else
311 ((OksOrExpression *)qe)->add(qe2);
312 }
313 }
314
315 return qe; /* SUCCESS */
316 }
317 else if(first == OksQuery::NOT) {
318 if(slist.size() != 1) {
319 Oks::error_msg(fname) << "\'" << first << "\' must have exactly one argument: (" << str << ")\n";
320 return qe;
321 }
322
324
325 const std::string item2 = slist.front();
326 slist.pop_front();
327
328 OksQueryExpression *qe2 = create_expression(c, item2);
329
330 if(qe2) ((OksNotExpression *)qe)->set(qe2);
331
332 return qe; /* SUCCESS */
333 }
334 else if(slist.size() != 2) {
335 Oks::error_msg(fname) << "Can't parse query expression \"" << str << "\"\n";
336 return qe;
337 }
338 else {
339 const std::string second = slist.front();
340 slist.pop_front();
341
342 const std::string third = slist.front();
343 slist.pop_front();
344
345 if(second == OksQuery::SOME || second == OksQuery::ALL_SUBCLASSES) {
346 OksRelationship *r = c->find_relationship(first);
347
348 if(!r) {
349 Oks::error_msg(fname)
350 << "For expression \"" << str << "\"\n"
351 "can't find relationship \"" << first << "\" in class \"" << c->get_name() << "\"\n";
352
353 return qe;
354 }
355
356 bool b;
357
358 if(second == OksQuery::SOME) b = false;
359 else if(second == OksQuery::ALL_SUBCLASSES) b = true;
360 else {
361 Oks::error_msg(fname)
362 << "For relationship expression \"" << str << "\"\n"
363 "second parameter \'" << second << "\' must be \'" << *OksQuery::SOME
364 << "\' or \'" << *OksQuery::ALL_SUBCLASSES << "\'\n";
365 return qe;
366 }
367
368 OksClass *relc = c->get_kernel()->find_class(r->get_type());
369
370 if(!relc) {
371 Oks::error_msg(fname)
372 << "For expression \"" << str << "\"\n"
373 << "can't find class \"" << r->get_type() << "\"\n";
374 return qe;
375 }
376
377 OksQueryExpression *qe2 = create_expression(relc, third);
378
379 if(qe2) qe = (OksQueryExpression *)new OksRelationshipExpression(r, qe2, b);
380
381 return qe; /* SUCCESS */
382 }
383 else {
384 OksAttribute *a = ((first != OksQuery::OID) ? c->find_attribute(first) : 0);
385
386 if(first != OksQuery::OID && !a) {
387 Oks::error_msg(fname)
388 << "For expression \"" << str << "\"\n"
389 << "can't find attribute \"" << first << "\" in class \""
390 << c->get_name() << "\"\n";
391 return qe;
392 }
393
394 OksData * d = new OksData();
395
397 (third == OksQuery::EQ) ? OksQuery::equal_cmp :
402 (third == OksQuery::LS) ? OksQuery::less_cmp :
404 0
405 );
406
407 if(a) {
408 if(f == OksQuery::reg_exp_cmp) {
409 d->type = OksData::string_type;
410 d->data.STRING = new OksString(second);
411 }
412 else {
413 d->type = OksData::unknown_type;
414 d->SetValues(second.c_str(), a);
415 }
416 }
417 else {
418 d->Set(second);
419 }
420
421 if(!f)
422 Oks::error_msg(fname)
423 << "For expression \"" << str << "\"\n"
424 << "can't find comparator function \"" << third << "\"\n";
425 else
426 qe = (OksQueryExpression *)new OksComparator(a, d, f);
427
428 return qe; /* (UN)SUCCESS */
429 }
430 }
431}
432
433
434
437{
438 const char * fname = "OksClass::execute_query()";
439
441
442
443 OksObject::List * olist = 0;
444 OksQueryExpression *sqe = qe->get();
445
446 if(sqe->CheckSyntax() == false) {
447 Oks::error_msg(fname) << "Can't execute query \"" << *sqe << "\"\n";
448 return 0;
449 }
450
451 if(p_objects && !p_objects->empty()) {
452 bool indexedSearch = false;
453
454 if(p_indices) {
455 if(sqe->type() == OksQuery::comparator_type) {
456 OksComparator *cq = (OksComparator *)sqe;
457 OksIndex::Map::iterator j = p_indices->find(cq->GetAttribute());
458
459 if(j != p_indices->end()) {
460 indexedSearch = true;
461 olist = (*j).second->find_all(cq->GetValue(), cq->GetFunction());
462 }
463 }
464 else if(
465 (sqe->type() == OksQuery::and_type) ||
466 (sqe->type() == OksQuery::or_type)
467 ) {
468 std::list<OksQueryExpression *> * qlist = &((OksListBaseQueryExpression *)sqe)->p_expressions;
469 OksQueryExpression *q1, *q2;
470 OksComparator *cq1 = 0, *cq2 = 0;
471
472 if(
473 (qlist->size() == 2) &&
474 ((q1 = qlist->front())->type() == OksQuery::comparator_type) &&
475 ((q2 = qlist->back())->type() == OksQuery::comparator_type) &&
476 ((cq1 = (OksComparator *)q1) != 0) &&
477 ((cq2 = (OksComparator *)q2) != 0) &&
478 (cq1->GetAttribute() == cq2->GetAttribute())
479 ) {
480 OksIndex::Map::iterator j = p_indices->find(cq1->GetAttribute());
481
482 if(j != p_indices->end()) {
483 indexedSearch = true;
484
485 olist = (*j).second->find_all(
486 ((sqe->type() == OksQuery::and_type) ? true : false),
487 cq1->GetValue(),
488 cq1->GetFunction(),
489 cq2->GetValue(),
490 cq2->GetFunction()
491 );
492 }
493 }
494 }
495 }
496
497 if(indexedSearch == false) {
498 for(OksObject::Map::iterator i = p_objects->begin(); i != p_objects->end(); ++i) {
499 OksObject *o = (*i).second;
500
501 try {
502 if(o->SatisfiesQueryExpression(sqe) == true) {
503 if(!olist) olist = new OksObject::List();
504 olist->push_back(o);
505 }
506 }
507 catch(oks::exception& ex) {
508 throw oks::QueryFailed(*sqe, *this, ex);
509 }
510 catch(std::exception& ex) {
511 throw oks::QueryFailed(*sqe, *this, ex.what());
512 }
513 }
514 }
515 }
516
517
518 if(qe->search_in_subclasses() == true && p_all_sub_classes && !p_all_sub_classes->empty()) {
519 for(OksClass::FList::iterator i = p_all_sub_classes->begin(); i != p_all_sub_classes->end(); ++i) {
520 OksClass *c = *i;
521
522 if(c->p_objects && !c->p_objects->empty()) {
523 for(OksObject::Map::iterator i2 = c->p_objects->begin(); i2 != c->p_objects->end(); ++i2) {
524 OksObject *o = (*i2).second;
525
526 try {
527 if(o->SatisfiesQueryExpression(sqe) == true) {
528 if(!olist) olist = new OksObject::List();
529 olist->push_back(o);
530 }
531 }
532 catch(oks::exception& ex) {
533 throw oks::QueryFailed(*sqe, *this, ex);
534 }
535 catch(std::exception& ex) {
536 throw oks::QueryFailed(*sqe, *this, ex.what());
537 }
538 }
539 }
540 }
541 }
542
543 return olist;
544}
545
546
547bool
549{
550 const char * fname = "OksQueryExpression::CheckSyntax()";
551
552 switch(p_type) {
554 if(!((OksComparator *)this)->attribute && !((OksComparator *)this)->value) {
555 Oks::error_msg(fname)
556 << "OksComparator: Can't execute query for nil attribute or nil object-id\n";
557 return false;
558 }
559 else if(!((OksComparator *)this)->m_comp_f) {
560 Oks::error_msg(fname)
561 << "OksComparator: Can't execute query for nil compare function\n";
562 return false;
563 }
564
565 return true;
566
568 if(!((OksRelationshipExpression *)this)->relationship) {
569 Oks::error_msg(fname)
570 << "OksRelationshipExpression: Can't execute query for nil relationship\n";
571 return false;
572 }
573 else if(!((OksRelationshipExpression *)this)->p_expression) {
574 Oks::error_msg(fname)
575 << "OksRelationshipExpression: Can't execute query for nil query expression\n";
576 return false;
577 }
578 else
579 return (((OksRelationshipExpression *)this)->p_expression)->CheckSyntax();
580
582 if(!((OksNotExpression *)this)->p_expression) {
583 Oks::error_msg(fname)
584 << "OksNotExpression: Can't execute \'not\' for nil query expression\n";
585 return false;
586 }
587
588 return (((OksNotExpression *)this)->p_expression)->CheckSyntax();
589
591 if(((OksAndExpression *)this)->p_expressions.size() < 2) {
592 Oks::error_msg(fname)
593 << "OksAndExpression: Can't execute \'and\' for "
594 << ((OksAndExpression *)this)->p_expressions.size() << " argument\n"
595 "Two or more arguments are required\n";
596 return false;
597 }
598 else {
599 std::list<OksQueryExpression *> & elist = ((OksAndExpression *)this)->p_expressions;
600
601 for(std::list<OksQueryExpression *>::iterator i = elist.begin(); i != elist.end(); ++i)
602 if((*i)->CheckSyntax() == false) return false;
603
604 return true;
605 }
606
608 if(((OksOrExpression *)this)->p_expressions.size() < 2) {
609 Oks::error_msg(fname)
610 << "OksOrExpression: Can't execute \'or\' for "
611 << ((OksOrExpression *)this)->p_expressions.size() << " argument\n"
612 "Two or more arguments are required\n";
613
614 return false;
615 }
616 else {
617 std::list<OksQueryExpression *> & elist = ((OksOrExpression *)this)->p_expressions;
618
619 for(std::list<OksQueryExpression *>::iterator i = elist.begin(); i != elist.end(); ++i)
620 if((*i)->CheckSyntax() == false) return false;
621
622 return true;
623 }
624
625 default:
626 Oks::error_msg(fname)
627 << "Unexpected query type " << (int)p_type << std::endl;
628
629 return false;
630 }
631}
632
633
634bool
636{
638
639 if(!qe) {
640 throw std::runtime_error("cannot execute nil query");
641 }
642
643 switch(qe->type()) {
645 OksComparator *cmp = (OksComparator *)qe;
646 const OksAttribute *a = cmp->attribute;
648
649 if(!a && !cmp->value) {
650 throw std::runtime_error("cannot execute query for nil attribute");
651 }
652 else if(!f) {
653 throw std::runtime_error("cannot execute query for nil compare function");
654 }
655
656 const OksData * cmp_value(cmp->value);
657
658 if(f == OksQuery::reg_exp_cmp) {
659 if(!cmp->m_reg_exp) {
660 try {
661 std::string s(cmp->value->str());
662 cmp->m_reg_exp = new boost::regex(s.c_str());
663 }
664 catch(std::exception& ex) {
665 throw oks::BadReqExp(cmp->value->str(), ex.what());
666 }
667 }
668 cmp_value = reinterpret_cast<const OksData *>(cmp->m_reg_exp);
669 }
670
671 if(!a) {
672 OksData d(GetId());
673 return (*f)(&d, cmp_value);
674 }
675
676 return (*f)(
677 &(data[(*(uid.class_id->p_data_info->find(a->get_name()))).second->offset]),
678 cmp_value
679 );
680 }
681
683 if(!((OksRelationshipExpression *)qe)->relationship) {
684 throw std::runtime_error("cannot execute query for nil relationship");
685 }
686 else {
687 OksData *d = &data[((*(uid.class_id->p_data_info->find(((OksRelationshipExpression *)qe)->relationship->get_name()))).second)->offset];
688
689 if(((OksRelationshipExpression *)qe)->relationship->get_high_cardinality_constraint() == OksRelationship::Many) {
690 if(!d->data.LIST || d->data.LIST->empty()) return false;
691
692 for(OksData::List::iterator i = d->data.LIST->begin(); i != d->data.LIST->end(); ++i) {
693 OksData *d2 = (*i);
694
695 if(d2->type == OksData::uid2_type) {
696 std::ostringstream text;
697 text << "cannot process relationship expression: object \"" << *d2->data.UID2.object_id << '@' << *d2->data.UID2.class_id
698 << "\" referenced through multi values relationship \"" << ((OksRelationshipExpression *)qe)->relationship->get_name()
699 << "\" is not loaded in memory";
700 throw std::runtime_error(text.str().c_str());
701 }
702
703 if(((OksRelationshipExpression *)qe)->checkAllObjects == true) {
704 if(
705 !d2->data.OBJECT ||
706 d2->data.OBJECT->SatisfiesQueryExpression(((OksRelationshipExpression *)qe)->p_expression) == false
707 ) return false;
708 }
709 else {
710 if(
711 d2->data.OBJECT &&
712 d2->data.OBJECT->SatisfiesQueryExpression(((OksRelationshipExpression *)qe)->p_expression) == true
713 ) return true;
714 }
715 }
716
717 return (((OksRelationshipExpression *)qe)->checkAllObjects == true) ? true : false;
718 }
719 else {
720 if(d->type != OksData::object_type) {
721 std::ostringstream text;
722 text << "cannot process relationship expression: object \"" << *d << "\" referenced through single value relationship \""
723 << ((OksRelationshipExpression *)qe)->relationship->get_name() << "\" is not loaded in memory";
724 throw std::runtime_error(text.str().c_str());
725 }
726
727 return (
728 d->data.OBJECT
729 ? d->data.OBJECT->SatisfiesQueryExpression(((OksRelationshipExpression *)qe)->p_expression)
730 : false
731 );
732 }
733 }
734
736 if(!((OksNotExpression *)qe)->p_expression) {
737 throw std::runtime_error("cannot process \'not\' expression: referenced query expression is nil");
738 }
739
740 return (SatisfiesQueryExpression(((OksNotExpression *)qe)->p_expression) ? false : true);
741
743 if(((OksAndExpression *)qe)->p_expressions.size() < 2) {
744 std::ostringstream text;
745 text << "cannot process \'and\' expression for " << ((OksAndExpression *)qe)->p_expressions.size()
746 << " argument (two or more arguments are required)";
747 throw std::runtime_error(text.str().c_str());
748 }
749 else {
750 std::list<OksQueryExpression *> & elist = ((OksAndExpression *)qe)->p_expressions;
751
752 for(std::list<OksQueryExpression *>::iterator i = elist.begin(); i != elist.end();++i)
753 if(SatisfiesQueryExpression(*i) == false) return false;
754
755 return true;
756 }
757
759 if(((OksOrExpression *)qe)->p_expressions.size() < 2) {
760 std::ostringstream text;
761 text << "cannot process \'or\' expression for " << ((OksAndExpression *)qe)->p_expressions.size()
762 << " argument (two or more arguments are required)";
763 throw std::runtime_error(text.str().c_str());
764 }
765 else {
766 std::list<OksQueryExpression *> & elist = ((OksOrExpression *)qe)->p_expressions;
767
768 for(std::list<OksQueryExpression *>::iterator i = elist.begin(); i != elist.end();++i)
769 if(SatisfiesQueryExpression(*i) == true) return true;
770
771 return false;
772 }
773
774 default: {
775 std::ostringstream text;
776 text << "unexpected query type " << (int)(qe->type());
777 throw std::runtime_error(text.str().c_str());
778 }
779 }
780}
781
782
783std::ostream&
784operator<<(std::ostream& s, const OksQueryExpression& qe)
785{
786 s << '(';
787
788 switch(qe.type()) {
790 OksComparator *cmpr = (OksComparator *)&qe;
791 const OksAttribute *a = cmpr->GetAttribute();
792 OksData *v = cmpr->GetValue();
794
795 if(a) {
796 s << '\"' << a->get_name() << "\" ";
797 }
798 else if(v) {
799 s << OksQuery::OID << ' ';
800 }
801 else {
802 s << "(null) ";
803 }
804
805 if(v) {
806 s << *v << ' ';
807 }
808 else {
809 s << "(null) ";
810 }
811
812 if(f) {
813 if(f == OksQuery::equal_cmp) s << OksQuery::EQ;
814 else if(f == OksQuery::not_equal_cmp) s << OksQuery::NE;
815 else if(f == OksQuery::reg_exp_cmp) s << OksQuery::RE;
816 else if(f == OksQuery::less_or_equal_cmp) s << OksQuery::LE;
818 else if(f == OksQuery::less_cmp) s << OksQuery::LS;
819 else if(f == OksQuery::greater_cmp) s << OksQuery::GT;
820 }
821 else
822 s << "(null)";
823
824 break; }
825
828 const OksRelationship *r = re->GetRelationship();
829 bool b = re->IsCheckAllObjects();
830 OksQueryExpression *rqe = re->get();
831
832 if(r)
833 s << '\"' << r->get_name() << "\" ";
834 else
835 s << "(null) ";
836
837 s << (b == true ? OksQuery::ALL_SUBCLASSES : OksQuery::SOME) << ' ';
838
839 if(rqe) s << *rqe;
840 else s << "(null)";
841
842 break; }
843
845 s << OksQuery::NOT << ' ' << *(((OksNotExpression *)&qe)->get());
846
847 break;
848
849 case OksQuery::and_type: {
850 s << OksQuery::AND << ' ';
851
852 const std::list<OksQueryExpression *> & elist = ((OksAndExpression *)&qe)->expressions();
853
854 if(!elist.empty()) {
855 const OksQueryExpression * last = elist.back();
856
857 for(std::list<OksQueryExpression *>::const_iterator i = elist.begin(); i != elist.end(); ++i) {
858 s << *(*i);
859 if(*i != last) s << ' ';
860 }
861 }
862
863 break;
864 }
865
866 case OksQuery::or_type: {
867 s << OksQuery::OR << ' ';
868
869 const std::list<OksQueryExpression *> & elist = ((OksOrExpression *)&qe)->expressions();
870
871 if(!elist.empty()) {
872 const OksQueryExpression * last = elist.back();
873
874 for(std::list<OksQueryExpression *>::const_iterator i = elist.begin(); i != elist.end(); ++i) {
875 s << *(*i);
876 if(*i != last) s << ' ';
877 }
878 }
879
880 break;
881 }
882
884 s << "(unknown)";
885
886 break;
887 }
888 }
889
890 s << ')';
891
892 return s;
893}
894
895
896std::ostream&
897operator<<(std::ostream& s, const OksQuery& gqe)
898{
899 s << '('
901 << ' ';
902
903 if(gqe.p_expression)
904 s << *gqe.p_expression;
905 else
906 s << "(null)";
907
908 s << ')';
909
910 return s;
911}
912
913
914std::ostream&
915operator<<(std::ostream& s, const oks::QueryPath& query)
916{
917 s << '(' << OksQuery::PATH_TO << ' ' << query.get_goal_object() << ' ' << *query.get_start_expression() << ')';
918 return s;
919}
920
921
922std::ostream&
923operator<<(std::ostream& s, const oks::QueryPathExpression& e)
924{
925 s << '(' << (e.get_use_nested_lookup() ? OksQuery::NESTED : OksQuery::DIRECT) << ' ';
926
927 for(std::list<std::string>::const_iterator i = e.get_rel_names().begin(); i != e.get_rel_names().end(); ++i) {
928 if(i != e.get_rel_names().begin()) s << ' ';
929 s << '\"' << *i << '\"';
930 }
931
932 if(e.get_next()) s << ' ' << *(e.get_next());
933
934 s << ')';
935
936 return s;
937}
938
939
942{
943 OksObject::List * path = new OksObject::List();
944
945 if(satisfies(query.get_goal_object(), *query.get_start_expression(), *path) == false) {
946 delete path;
947 path = 0;
948 }
949
950 return path;
951}
952
953
954bool
955OksObject::satisfies(const OksObject * goal, const oks::QueryPathExpression& expression, OksObject::List& path) const
956{
957 // check the object is not in the path
958
959 {
960 for(std::list<OksObject *>::const_iterator i = path.begin(); i != path.end(); ++i) {
961 if(*i == this) return false;
962 }
963 }
964
965 path.push_back(const_cast<OksObject *>(this));
966
967
968 for(std::list<std::string>::const_iterator i = expression.get_rel_names().begin(); i != expression.get_rel_names().end(); ++i) {
969 OksData * d = 0;
970
971 if(!(*i).empty() && (*i)[0] == '?') {
972 std::string nm = (*i).substr(1);
973 OksDataInfo::Map::iterator i = uid.class_id->p_data_info->find(nm);
974
975 if(i != uid.class_id->p_data_info->end()) {
976 d = GetRelationshipValue((*i).second);
977 }
978 else {
979 continue;
980 }
981 }
982 else {
983 try {
984 d = GetRelationshipValue(*i);
985 }
986 catch(oks::exception& ex) {
987 Oks::error_msg("OksObject::satisfies") << ex.what() << std::endl;
988 continue;
989 }
990 }
991
992 // check if given relationship points to destination object
993
994 if(d->type == OksData::object_type && d->data.OBJECT == goal) return true;
995 else if(d->type == OksData::list_type && d->data.LIST) {
996 for(OksData::List::iterator i2 = d->data.LIST->begin(); i2 != d->data.LIST->end(); ++i2) {
997 OksData * d2 = (*i2);
998 if(d2->type == OksData::object_type && d2->data.OBJECT == goal) return true;
999 }
1000 }
1001
1002
1003 // go to next path, if there are no more expressions
1004
1005 if(!expression.get_next()) {
1006 continue;
1007 }
1008
1009
1010 // check, if there is need for nested path lookup
1011
1012 else if(expression.get_use_nested_lookup()) {
1013
1014 // go directly
1015
1016 path.pop_back();
1017 if(satisfies(goal, *expression.get_next(), path) == true) return true;
1018 path.push_back(const_cast<OksObject *>(this));
1019
1020 // go nested
1021
1022 if(d->type == OksData::object_type && d->data.OBJECT) {
1023 if(d->data.OBJECT->satisfies(goal, expression, path) == true) return true;
1024 }
1025 else if(d->type == OksData::list_type && d->data.LIST) {
1026 for(OksData::List::iterator i2 = d->data.LIST->begin(); i2 != d->data.LIST->end(); ++i2) {
1027 OksData * d2 = (*i2);
1028 if(d2->type == OksData::object_type && d2->data.OBJECT) {
1029 if(d2->data.OBJECT->satisfies(goal, expression, path) == true) return true;
1030 }
1031 }
1032 }
1033 }
1034
1035 else {
1036 if(d->type == OksData::object_type && d->data.OBJECT) {
1037 if(d->data.OBJECT->satisfies(goal, *expression.get_next(), path) == true) return true;
1038 }
1039 else if(d->type == OksData::list_type && d->data.LIST) {
1040 for(OksData::List::iterator i2 = d->data.LIST->begin(); i2 != d->data.LIST->end(); ++i2) {
1041 OksData * d2 = (*i2);
1042 if(d2->type == OksData::object_type && d2->data.OBJECT) {
1043 if(d2->data.OBJECT->satisfies(goal, *expression.get_next(), path) == true) return true;
1044 }
1045 }
1046 }
1047 }
1048 }
1049
1050 path.pop_back();
1051 return false;
1052}
1053
1054oks::QueryPath::QueryPath(const std::string& str, const OksKernel& kernel) : p_start(0)
1055{
1056 std::string s(str);
1058
1059 if(s.empty()) {
1060 throw oks::bad_query_syntax( "Empty query" );
1061 }
1062
1063 if(s[0] == '(') {
1064 std::string::size_type p = s.rfind(')');
1065
1066 if(p == std::string::npos) {
1067 throw oks::bad_query_syntax(std::string("Query expression \'") + str + "\' must contain closing bracket");
1068 }
1069
1070 s.erase(p);
1071 s.erase(0, 1);
1072 }
1073 else {
1074 throw oks::bad_query_syntax(std::string("Query expression \'") + str + "\' must be enclosed by brackets");
1075 }
1076
1078
1079 Oks::Tokenizer t(s, " \t\n");
1080 std::string token;
1081 t.next(token);
1082
1083 if(token != OksQuery::PATH_TO) {
1084 throw oks::bad_query_syntax(std::string("Expression \'") + s + "\' must start from " + OksQuery::DIRECT + " or " + OksQuery::NESTED + " keyword");
1085 }
1086
1087 s.erase(0, token.size());
1089
1090 if( s[0] == '\"' ) {
1091 std::string::size_type p = s.find('\"', 1);
1092
1093 if(p == std::string::npos) {
1094 throw oks::bad_query_syntax(std::string("No trailing delimiter of object name in query \'") + str + "\'");
1095 }
1096
1097 std::string::size_type p2 = s.find('@');
1098
1099 if(p2 == std::string::npos || p2 > p) {
1100 throw oks::bad_query_syntax(std::string("Bad format of object name ") + s.substr(0, p+1) + " in query \'" + str + "\'");
1101 }
1102
1103 std::string object_id = std::string(s, 1, p2 - 1);
1104 std::string class_name = std::string(s, p2 + 1, p - p2 - 1);
1105
1106 if(OksClass * c = kernel.find_class(class_name)) {
1107 if((p_goal = c->get_object(object_id)) == 0) {
1108 throw oks::bad_query_syntax(std::string("Cannot find object ") + s.substr(0, p+1) + " in query \'" + str + "\': no such object");
1109 }
1110 }
1111 else {
1112 throw oks::bad_query_syntax(std::string("Cannot find object ") + s.substr(0, p+1) + " in query \'" + str + "\': no such class");
1113 }
1114
1115 s.erase(0, p + 1);
1116 }
1117 else {
1118 throw oks::bad_query_syntax(std::string("No name of object in \'") + str + "\'");
1119 }
1120
1121 try {
1122 p_start = new QueryPathExpression(s);
1123 }
1124 catch ( oks::bad_query_syntax& e ) {
1125 throw oks::bad_query_syntax(std::string("Failed to parse expression \'") + str + "\' because \'" + e.what() + "\'");
1126 }
1127}
1128
1129oks::QueryPathExpression::QueryPathExpression(const std::string& str) : p_next(0)
1130{
1131 std::string s(str);
1133
1134 if(s.empty()) {
1135 throw oks::bad_query_syntax( "Empty expression" );
1136 }
1137
1138 if(s[0] == '(') {
1139 std::string::size_type p = s.rfind(')');
1140
1141 if(p == std::string::npos) {
1142 throw oks::bad_query_syntax(std::string("Expression \'") + str + "\' must contain closing bracket");
1143 }
1144
1145 s.erase(p);
1146 s.erase(0, 1);
1147
1148 // build nested expression if any
1149
1150 std::string::size_type p1 = s.find('(');
1151
1152 if(p1 != std::string::npos) {
1153 std::string::size_type p2 = s.rfind(')');
1154
1155 if(p2 == std::string::npos) {
1156 throw oks::bad_query_syntax(std::string("Nested expression of \'") + str + "\' must contain closing bracket");
1157 }
1158
1159 p_next = new QueryPathExpression(s.substr(p1, p2));
1160
1161 s.erase(p1, p2);
1162 }
1163
1165
1166 Oks::Tokenizer t(s, " \t\n");
1167 std::string token;
1168 t.next(token);
1169
1170 if(token == OksQuery::DIRECT) {
1171 p_use_nested_lookup = false;
1172 }
1173 else if(token == OksQuery::NESTED) {
1174 p_use_nested_lookup = true;
1175 }
1176 else {
1177 delete p_next; p_next = 0;
1178 throw oks::bad_query_syntax(std::string("Expression \'") + s + "\' must start from " + OksQuery::DIRECT + " or " + OksQuery::NESTED + " keyword");
1179 }
1180
1181 s.erase(0, token.size());
1182
1183 while(s.length()) {
1185
1186 if(!s.length()) break;
1187
1188 if( s[0] == '\"' || s[0] == '\'' || s[0] == '`' ) {
1189 char delimiter = s[0];
1190
1191 p = s.find(delimiter, 1);
1192
1193 if(p == std::string::npos) {
1194 delete p_next; p_next = 0;
1195 throw oks::bad_query_syntax(std::string("No trailing delimiter of \'") + s + "\' (expression \'" + str + "\')");
1196 }
1197
1198 p_rel_names.push_back(std::string(s, 1, p-1));
1199
1200 s.erase(0, p + 1);
1201 }
1202 else {
1203 delete p_next; p_next = 0;
1204 throw oks::bad_query_syntax(std::string("Name of relationship \'") + s + "\' must start from a delimiter (expression \'" + str + "\')");
1205 }
1206 }
1207
1208 if(p_rel_names.empty()) {
1209 delete p_next; p_next = 0;
1210 throw oks::bad_query_syntax(std::string("An expression of \'") + str + "\' has no relationship names defined");
1211 }
1212 }
1213 else {
1214 throw oks::bad_query_syntax(std::string("Expression \'") + str + "\' must be enclosed by brackets");
1215 }
1216}
1217
1218} // namespace oks
1219} // namespace dunedaq
static std::string fill(const std::string &what, const std::string &reason) noexcept
Definition query.cpp:50
OKS query logical AND expression class.
Definition query.hpp:287
OKS attribute class.
const std::string & get_name() const noexcept
out stream operator
The OKS class.
Definition class.hpp:205
OksKernel * p_kernel
Definition class.hpp:958
OksObject::Map * p_objects
Definition class.hpp:963
FList * p_all_sub_classes
Definition class.hpp:949
OksIndex::Map * p_indices
Definition class.hpp:964
const std::string & get_name() const noexcept
Definition class.hpp:368
OksClass(const std::string &name, OksKernel *kernel, bool transient=false)
Create OKS class.
Definition class.cpp:80
friend class OksObject
Definition class.hpp:206
OksObject::List * execute_query(OksQuery *query) const
Execute query.
Definition query.cpp:436
OKS query expression comparator class.
Definition query.hpp:144
OksQuery::Comparator GetFunction() const
Definition query.hpp:171
boost::regex * m_reg_exp
Definition query.hpp:179
const OksAttribute * attribute
Definition query.hpp:176
void SetValue(OksData *v)
Definition query.cpp:67
const OksAttribute * GetAttribute() const
Definition query.hpp:163
OksQuery::Comparator m_comp_f
Definition query.hpp:178
Provides interface to the OKS kernel.
Definition kernel.hpp:582
OksClass * find_class(const std::string &class_name) const
Find class by name (C++ string).
Definition kernel.hpp:1819
Abstract class describing list of OKS query expressions.
Definition query.hpp:258
OKS query logical NOT expression class.
Definition query.hpp:233
struct dunedaq::oks::OksObject::OksUid uid
friend class OksClass
Definition object.hpp:842
OksData * GetRelationshipValue(const std::string &) const
Get value of relationship by name.
Definition object.cpp:2009
std::list< OksObject * > List
Definition object.hpp:880
friend struct OksData
Definition object.hpp:843
bool satisfies(const OksObject *goal, const oks::QueryPathExpression &expresssion, OksObject::List &path) const
Definition query.cpp:955
OksObject(const OksClass *oks_class, const char *object_id=0, bool skip_init=false)
OKS object constructor.
Definition object.cpp:1180
OksObject::List * find_path(const oks::QueryPath &query) const
Definition query.cpp:941
bool SatisfiesQueryExpression(OksQueryExpression *query_exp) const
Check if object satisfies query expression.
Definition query.cpp:635
const std::string & GetId() const
Definition object.hpp:1000
OKS query logical OR expression class.
Definition query.hpp:299
OKS query expression class.
Definition query.hpp:112
const OksQuery::QueryType p_type
Definition query.hpp:131
OksQuery::QueryType type() const
Definition query.hpp:119
OksQueryExpression(OksQuery::QueryType qet=OksQuery::unknown_type)
Definition query.hpp:126
OKS query class.
Definition query.hpp:41
static const char * ALL_SUBCLASSES
Definition query.hpp:72
static bool equal_cmp(const OksData *, const OksData *)
Definition query.cpp:56
static bool reg_exp_cmp(const OksData *, const OksData *regexp)
Definition query.cpp:62
static bool greater_cmp(const OksData *, const OksData *)
Definition query.cpp:61
static const char * OR
Definition query.hpp:67
bool search_in_subclasses() const
Definition query.hpp:50
static const char * RE
Definition query.hpp:76
static const char * THIS_CLASS
Definition query.hpp:71
static const char * OID
Definition query.hpp:73
static bool less_or_equal_cmp(const OksData *, const OksData *)
Definition query.cpp:58
static bool not_equal_cmp(const OksData *, const OksData *)
Definition query.cpp:57
static const char * GT
Definition query.hpp:80
static const char * NOT
Definition query.hpp:69
static const char * SOME
Definition query.hpp:70
static const char * PATH_TO
Definition query.hpp:81
OksQueryExpression * p_expression
Definition query.hpp:99
static const char * GE
Definition query.hpp:78
static const char * AND
Definition query.hpp:68
static const char * NESTED
Definition query.hpp:83
static bool greater_or_equal_cmp(const OksData *, const OksData *)
Definition query.cpp:59
static const char * EQ
Definition query.hpp:74
static bool less_cmp(const OksData *, const OksData *)
Definition query.cpp:60
static const char * DIRECT
Definition query.hpp:82
static const char * LE
Definition query.hpp:77
OksQuery(bool b, OksQueryExpression *q=0)
Definition query.hpp:44
static const char * NE
Definition query.hpp:75
static OksQueryExpression * create_expression(const OksClass *, const std::string &)
Definition query.cpp:187
bool(* Comparator)(const OksData *, const OksData *)
Definition query.hpp:93
static const char * LS
Definition query.hpp:79
OksQueryExpression * get() const
Definition query.hpp:53
OKS query relationship expression class.
Definition query.hpp:192
OksQueryExpression * get() const
Definition query.hpp:210
const OksRelationship * GetRelationship() const
Definition query.hpp:207
Class OKS string.
Definition object.hpp:374
static std::ostream & error_msg(const char *)
Definition kernel.cpp:561
static std::string fill(const OksQueryExpression &query, const OksClass &c, const std::string &reason) noexcept
Definition query.cpp:42
const QueryPathExpression * get_next() const
Definition query.hpp:348
const std::list< std::string > & get_rel_names() const
Definition query.hpp:347
const OksObject * get_goal_object() const
Definition query.hpp:397
const QueryPathExpression * get_start_expression() const
Definition query.hpp:396
QueryPath(const OksObject *o, QueryPathExpression *qpe)
Definition query.hpp:392
virtual const char * what() const noexcept
#define OSK_PROFILING(FID, K)
Definition defs.hpp:102
std::ostream & operator<<(std::ostream &s, const oks::exception &ex)
void erase_empty_chars(std::string &s)
Definition query.cpp:84
Including Qt Headers.
Definition module.cpp:16
default char v[0]
Definition ral.hpp:35
the structure to pass common parameters to various read() methods of OksData and OksObject class
Definition object.hpp:454
std::string str(int base=0) const
union dunedaq::oks::OksData::Data data
enum dunedaq::oks::OksData::Type type
const OksClass * class_id
Definition object.hpp:505
struct dunedaq::oks::OksData::Data::@226266061051241020017305361066131172152317024337 UID2