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