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