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

Generated by: LCOV version 2.0-1