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