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: 2025-12-21 13:07:08 Functions: 0.0 % 25 0

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

Generated by: LCOV version 2.0-1