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