LCOV - code coverage report
Current view: top level - oks/src - query.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 654 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 25 0

            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
        

Generated by: LCOV version 2.0-1