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