LCOV - code coverage report
Current view: top level - tests - catch_pbql_expression.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 537 537
Test Date: 2025-06-19 11:28:46 Functions: 100.0 % 3 3
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2019-2025  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/prinbee
       4              : // contact@m2osw.com
       5              : //
       6              : // This program is free software: you can redistribute it and/or modify
       7              : // it under the terms of the GNU General Public License as published by
       8              : // the Free Software Foundation, either version 3 of the License, or
       9              : // (at your option) any later version.
      10              : //
      11              : // This program is distributed in the hope that it will be useful,
      12              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : // GNU General Public License for more details.
      15              : //
      16              : // You should have received a copy of the GNU General Public License
      17              : // along with this program.  If not, see <https://www.gnu.org/licenses/>.
      18              : 
      19              : // prinbee
      20              : //
      21              : #include    <prinbee/pbql/parser.h>
      22              : 
      23              : #include    <prinbee/exception.h>
      24              : 
      25              : 
      26              : // self
      27              : //
      28              : #include    "catch_main.h"
      29              : 
      30              : 
      31              : // snaplogger
      32              : //
      33              : #include    <snaplogger/message.h>
      34              : 
      35              : 
      36              : // snapdev
      37              : //
      38              : #include    <snapdev/enum_class_math.h>
      39              : #include    <snapdev/to_lower.h>
      40              : 
      41              : 
      42              : // last include
      43              : //
      44              : #include    <snapdev/poison.h>
      45              : 
      46              : 
      47              : 
      48              : namespace
      49              : {
      50              : 
      51              : 
      52              : 
      53              : 
      54              : 
      55              : 
      56              : } // no name namespace
      57              : 
      58              : 
      59              : 
      60           13 : CATCH_TEST_CASE("expression", "[expression][parser][pbql]")
      61              : {
      62           15 :     CATCH_START_SECTION("expression: primary")
      63              :     {
      64              :         struct primary_t
      65              :         {
      66              :             char const *        f_primary = nullptr;
      67              :             char const *        f_expected = nullptr;
      68              :         };
      69            1 :         constexpr primary_t const primary_expressions[] =
      70              :         {
      71              :             {
      72              :                 "SELECT 'string';",
      73              :                 "\"string\"",
      74              :             },
      75              :             {
      76              :                 "SELECT 'str' 'ing';",
      77              :                 "\"string\"",
      78              :             },
      79              :             {
      80              :                 "SELECT 'quoted \"string\"';",
      81              :                 "\"quoted \\\"string\\\"\"",
      82              :             },
      83              :             {
      84              :                 "SELECT E'escape \\b';",
      85              :                 "\"escape \\b\"",
      86              :             },
      87              :             {
      88              :                 "SELECT E'escape \\f';",
      89              :                 "\"escape \\f\"",
      90              :             },
      91              :             {
      92              :                 "SELECT E'escape \\n';",
      93              :                 "\"escape \\n\"",
      94              :             },
      95              :             {
      96              :                 "SELECT E'escape \\r';",
      97              :                 "\"escape \\r\"",
      98              :             },
      99              :             {
     100              :                 "SELECT E'escape \\t';",
     101              :                 "\"escape \\t\"",
     102              :             },
     103              :             {
     104              :                 "SELECT E'escape \\13';", // SQL does not support "\v" as is
     105              :                 "\"escape \\v\"",
     106              :             },
     107              :             {
     108              :                 "SELECT 1234;",
     109              :                 "1234",
     110              :             },
     111              :             {
     112              :                 "SELECT 123.4;",
     113              :                 "123.4",
     114              :             },
     115              :             {
     116              :                 "SELECT true;",
     117              :                 "true",
     118              :             },
     119              :             {
     120              :                 "SELECT false;",
     121              :                 "false",
     122              :             },
     123              :             {
     124              :                 "SELECT True;",
     125              :                 "true",
     126              :             },
     127              :             {
     128              :                 "SELECT FALSE;",
     129              :                 "false",
     130              :             },
     131              :             {
     132              :                 "SELECT (TRUE);",
     133              :                 "true",
     134              :             },
     135              :             {
     136              :                 "SELECT (FaLsE);",
     137              :                 "false",
     138              :             },
     139              :             {
     140              :                 "SELECT table_name;",
     141              :                 "table_name",
     142              :             },
     143              :             {
     144              :                 "SELECT Table_Name;",
     145              :                 "table_name",
     146              :             },
     147              :             {
     148              :                 "SELECT *;",
     149              :                 "ALL_FIELDS",
     150              :             },
     151              :         };
     152           21 :         for(auto const & e : primary_expressions)
     153              :         {
     154           20 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     155           20 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_primary, "primary-expression.pbql"));
     156           20 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     157           20 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
     158              : 
     159              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_primary << "]" << SNAP_LOG_SEND;
     160           20 :             CATCH_REQUIRE(commands.size() == 1);
     161              : 
     162              :             // BEGIN
     163           20 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
     164              :             // SCHEMA/DATA
     165           20 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     166           20 :             CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION) == e.f_expected);
     167           20 :         }
     168              :     }
     169           14 :     CATCH_END_SECTION()
     170              : 
     171           15 :     CATCH_START_SECTION("expression: postfix (except functions)")
     172              :     {
     173              :         struct postfix_t
     174              :         {
     175              :             char const *        f_postfix = nullptr;
     176              :             std::vector<std::string>
     177              :                                 f_expected = std::vector<std::string>();
     178              :         };
     179            1 :         postfix_t const postfix_expressions[] =
     180              :         {
     181              :             {
     182              :                 "SELECT Table_Name.Column_Name.Field_Name;",
     183              :                 { "table_name.column_name.field_name" },
     184              :             },
     185              :             {
     186              :                 "SELECT Table_Name.*;",
     187              :                 { "table_name.ALL_FIELDS" },
     188              :             },
     189              :             {
     190              :                 "SELECT Cast1::BigInt, Cast2::Boolean, Cast3::Char,"
     191              :                     " Cast4::Double Precision,"
     192              :                     " Cast5::Int, Cast6::Int1, Cast7::Int2, Cast8::Int4,"
     193              :                     " Cast9::Int8, Cast10::Int16, Cast11::Int32, Cast12::Int64,"
     194              :                     " Cast13::Integer, Cast14::Float4, Cast15::Float8, Cast16::Float10,"
     195              :                     " Cast17::Real, Cast18::SmallInt, Cast19::Text,"
     196              :                     " Cast20::Unsigned BigInt, Cast21::Unsigned Int,"
     197              :                     " Cast22::Unsigned Int1, Cast23::Unsigned Int2,"
     198              :                     " Cast24::Unsigned Int4, Cast25::Unsigned Int8,"
     199              :                     " Cast26::Unsigned Int16, Cast27::Unsigned Int32,"
     200              :                     " Cast28::Unsigned Int64, Cast29::Unsigned Integer"
     201              :                     ";",
     202              :                 {
     203              :                     "new Integer(cast1)",
     204              :                     "!!(cast2)",
     205              :                     "new String(cast3)",
     206              :                     "new Number(cast4)",
     207              :                     "new Integer(cast5)",
     208              :                     "new Integer(cast6)",
     209              :                     "new Integer(cast7)",
     210              :                     "new Integer(cast8)",
     211              :                     "new Integer(cast9)",
     212              :                     "new Integer(cast10)",
     213              :                     "new Integer(cast11)",
     214              :                     "new Integer(cast12)",
     215              :                     "new Integer(cast13)",
     216              :                     "new Number(cast14)",
     217              :                     "new Number(cast15)",
     218              :                     "new Number(cast16)",
     219              :                     "new Number(cast17)",
     220              :                     "new Integer(cast18)",
     221              :                     "new String(cast19)",
     222              :                     "new Integer(cast20)",
     223              :                     "new Integer(cast21)",
     224              :                     "new Integer(cast22)",
     225              :                     "new Integer(cast23)",
     226              :                     "new Integer(cast24)",
     227              :                     "new Integer(cast25)",
     228              :                     "new Integer(cast26)",
     229              :                     "new Integer(cast27)",
     230              :                     "new Integer(cast28)",
     231              :                     "new Integer(cast29)",
     232              :                 },
     233              :             },
     234              :             {
     235              :                 "SELECT BigInt(Cast1), Boolean(Cast2), Char(Cast3),"
     236              :                     " Double Precision(Cast4),"
     237              :                     " Int(Cast5), Int1(Cast6), Int2(Cast7), Int4(Cast8),"
     238              :                     " Int8(Cast9), Int16(Cast10), Int32(Cast11), Int64(Cast12),"
     239              :                     " Integer(Cast13), Float4(Cast14), Float8(Cast15), Float10(Cast16),"
     240              :                     " Real(Cast17), SmallInt(Cast18), Text(Cast19),"
     241              :                     " Unsigned BigInt(Cast20), Unsigned Int(Cast21),"
     242              :                     " Unsigned Int1(Cast22), Unsigned Int2(Cast23),"
     243              :                     " Unsigned Int4(Cast24), Unsigned Int8(Cast25),"
     244              :                     " Unsigned Int16(Cast26), Unsigned Int32(Cast27),"
     245              :                     " Unsigned Int64(Cast28), Unsigned Integer(Cast29)"
     246              :                     ";",
     247              :                 {
     248              :                     "new Integer(cast1)",
     249              :                     "!!(cast2)",
     250              :                     "new String(cast3)",
     251              :                     "new Number(cast4)",
     252              :                     "new Integer(cast5)",
     253              :                     "new Integer(cast6)",
     254              :                     "new Integer(cast7)",
     255              :                     "new Integer(cast8)",
     256              :                     "new Integer(cast9)",
     257              :                     "new Integer(cast10)",
     258              :                     "new Integer(cast11)",
     259              :                     "new Integer(cast12)",
     260              :                     "new Integer(cast13)",
     261              :                     "new Number(cast14)",
     262              :                     "new Number(cast15)",
     263              :                     "new Number(cast16)",
     264              :                     "new Number(cast17)",
     265              :                     "new Integer(cast18)",
     266              :                     "new String(cast19)",
     267              :                     "new Integer(cast20)",
     268              :                     "new Integer(cast21)",
     269              :                     "new Integer(cast22)",
     270              :                     "new Integer(cast23)",
     271              :                     "new Integer(cast24)",
     272              :                     "new Integer(cast25)",
     273              :                     "new Integer(cast26)",
     274              :                     "new Integer(cast27)",
     275              :                     "new Integer(cast28)",
     276              :                     "new Integer(cast29)",
     277              :                 },
     278              :             },
     279              :             {
     280              :                 "SELECT BigInt Cast1, Boolean Cast2, Char Cast3,"
     281              :                     " Double Precision Cast4,"
     282              :                     " Int Cast5, Int1 Cast6, Int2 Cast7, Int4 Cast8,"
     283              :                     " Int8 Cast9, Int16 Cast10, Int32 Cast11, Int64 Cast12,"
     284              :                     " Integer Cast13, Float4 Cast14, Float8 Cast15, Float10 Cast16,"
     285              :                     " Real Cast17, SmallInt Cast18, Text Cast19,"
     286              :                     " Unsigned BigInt Cast20, Unsigned Int Cast21,"
     287              :                     " Unsigned Int1 Cast22, Unsigned Int2 Cast23,"
     288              :                     " Unsigned Int4 Cast24, Unsigned Int8 Cast25,"
     289              :                     " Unsigned Int16 Cast26, Unsigned Int32 Cast27,"
     290              :                     " Unsigned Int64 Cast28, Unsigned Integer Cast29"
     291              :                     ";",
     292              :                 {
     293              :                     "new Integer(cast1)",
     294              :                     "!!(cast2)",
     295              :                     "new String(cast3)",
     296              :                     "new Number(cast4)",
     297              :                     "new Integer(cast5)",
     298              :                     "new Integer(cast6)",
     299              :                     "new Integer(cast7)",
     300              :                     "new Integer(cast8)",
     301              :                     "new Integer(cast9)",
     302              :                     "new Integer(cast10)",
     303              :                     "new Integer(cast11)",
     304              :                     "new Integer(cast12)",
     305              :                     "new Integer(cast13)",
     306              :                     "new Number(cast14)",
     307              :                     "new Number(cast15)",
     308              :                     "new Number(cast16)",
     309              :                     "new Number(cast17)",
     310              :                     "new Integer(cast18)",
     311              :                     "new String(cast19)",
     312              :                     "new Integer(cast20)",
     313              :                     "new Integer(cast21)",
     314              :                     "new Integer(cast22)",
     315              :                     "new Integer(cast23)",
     316              :                     "new Integer(cast24)",
     317              :                     "new Integer(cast25)",
     318              :                     "new Integer(cast26)",
     319              :                     "new Integer(cast27)",
     320              :                     "new Integer(cast28)",
     321              :                     "new Integer(cast29)",
     322              :                 },
     323              :             },
     324              :             {
     325              :                 "SELECT Table_Name.Array_Field[3];",
     326              :                 { "table_name.array_field[3]" },
     327              :             },
     328           10 :         };
     329              : 
     330            7 :         for(auto const & e : postfix_expressions)
     331              :         {
     332              : //SNAP_LOG_WARNING << "ready to parse next expression [" << e.f_postfix << "]" << SNAP_LOG_SEND;
     333            6 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     334            6 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_postfix, "postfix-expression.pbql"));
     335            6 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     336            6 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
     337              : 
     338              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_postfix << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
     339            6 :             CATCH_REQUIRE(commands.size() == 1);
     340              : 
     341              :             // BEGIN
     342            6 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
     343              :             // SCHEMA/DATA
     344            6 :             std::size_t const max(e.f_expected.size());
     345            6 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
     346           96 :             for(std::size_t idx(0); idx < max; ++idx)
     347              :             {
     348           90 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     349           90 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
     350              :             }
     351            6 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
     352            6 :         }
     353            7 :     }
     354           14 :     CATCH_END_SECTION()
     355              : 
     356           15 :     CATCH_START_SECTION("expression: unary")
     357              :     {
     358              :         struct postfix_t
     359              :         {
     360              :             char const *        f_unary = nullptr;
     361              :             std::vector<std::string>
     362              :                                 f_expected = std::vector<std::string>();
     363              :         };
     364            1 :         postfix_t const unary_expressions[] =
     365              :         {
     366              :             {
     367              :                 "SELECT +304, +'111', +3.45, +'9.03';",
     368              :                 { "304", "111", "3.45", "9.03" },
     369              :             },
     370              :             {
     371              :                 "SELECT -129;",
     372              :                 { "-129" },
     373              :             },
     374              :             {
     375              :                 "SELECT -(-912);",
     376              :                 { "912" },
     377              :             },
     378              :             {
     379              :                 "SELECT -+-192;",
     380              :                 { "192" },
     381              :             },
     382              :             {
     383              :                 "SELECT +-+-+-871;",
     384              :                 { "-871" },
     385              :             },
     386              :             {
     387              :                 "SELECT -'3101', +-'15.98', +a, - - b, -c;",
     388              :                 { "-3101", "-15.98", "new Number(a)", "new Number(b)", "-c", },
     389              :             },
     390           10 :         };
     391            7 :         for(auto const & e : unary_expressions)
     392              :         {
     393            6 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     394            6 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_unary, "unary-expression.pbql"));
     395            6 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     396            6 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
     397              : 
     398              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_unary << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
     399            6 :             CATCH_REQUIRE(commands.size() == 1);
     400              : 
     401              :             // BEGIN
     402            6 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
     403              :             // SCHEMA/DATA
     404            6 :             std::size_t const max(e.f_expected.size());
     405            6 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
     406           19 :             for(std::size_t idx(0); idx < max; ++idx)
     407              :             {
     408           13 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     409           13 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
     410              :             }
     411            6 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
     412            6 :         }
     413            7 :     }
     414           14 :     CATCH_END_SECTION()
     415              : 
     416           15 :     CATCH_START_SECTION("expression: exponentiation")
     417              :     {
     418              :         struct postfix_t
     419              :         {
     420              :             char const *        f_exponentiation = nullptr;
     421              :             std::vector<std::string>
     422              :                                 f_expected = std::vector<std::string>();
     423              :         };
     424            1 :         postfix_t const exponentiation_expressions[] =
     425              :         {
     426              :             {
     427              :                 "SELECT 2^8, 3^3, 5 ^ 7;",
     428              :                 { "256", "27", "78125" },
     429              :             },
     430              :             {
     431              :                 "SELECT '2'^8, 3^'3', '5' ^ '7';",
     432              :                 { "256", "27", "78125" },
     433              :             },
     434              :             {
     435              :                 "SELECT 4.11^2, 0.03^3;",
     436              :                 { "16.8921", "0.000027" },
     437              :             },
     438              :             {
     439              :                 "SELECT 2.01^3.11, 0.5^4.03;",
     440              :                 { "8.768791", "0.061214" },
     441              :             },
     442              :             {
     443              :                 "SELECT '2.01'^3.11, 0.5^'4.03';",
     444              :                 { "8.768791", "0.061214" },
     445              :             },
     446              :             {
     447              :                 "SELECT a^b, a^2, a^2^b, 3^2^d, a^2^3;",
     448              :                 { "(a**b)", "(a**2)", "((a**2)**b)", "(9**d)", "((a**2)**3)" },
     449              :             },
     450           10 :         };
     451            7 :         for(auto const & e : exponentiation_expressions)
     452              :         {
     453            6 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     454            6 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_exponentiation, "exponentiation-expression.pbql"));
     455            6 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     456            6 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
     457              : 
     458              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_exponentiation << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
     459            6 :             CATCH_REQUIRE(commands.size() == 1);
     460              : 
     461              :             // BEGIN
     462            6 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
     463              :             // SCHEMA/DATA
     464            6 :             std::size_t const max(e.f_expected.size());
     465            6 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
     466           23 :             for(std::size_t idx(0); idx < max; ++idx)
     467              :             {
     468           17 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     469           17 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
     470              :             }
     471            6 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
     472            6 :         }
     473            7 :     }
     474           14 :     CATCH_END_SECTION()
     475              : 
     476           15 :     CATCH_START_SECTION("expression: multiplicative")
     477              :     {
     478              :         struct postfix_t
     479              :         {
     480              :             char const *        f_multiplicative = nullptr;
     481              :             std::vector<std::string>
     482              :                                 f_expected = std::vector<std::string>();
     483              :         };
     484            1 :         postfix_t const multiplicative_expressions[] =
     485              :         {
     486              :             {
     487              :                 "SELECT 2*8, 3 *3, 5 * 7, 5* 4;",
     488              :                 { "16", "9", "35", "20" },
     489              :             },
     490              :             {
     491              :                 "SELECT '2'*8, 3*'3', '5' * '7', 5* '4';",
     492              :                 { "16", "9", "35", "20" },
     493              :             },
     494              :             {
     495              :                 "SELECT 4.11*2, 0.03*3;",
     496              :                 { "8.22", "0.09" },
     497              :             },
     498              :             {
     499              :                 "SELECT 2.01*3.11, 0.5*4.03;",
     500              :                 { "6.2511", "2.015" },
     501              :             },
     502              :             {
     503              :                 "SELECT '2.01'*3.11, 0.5*'4.03';",
     504              :                 { "6.2511", "2.015" },
     505              :             },
     506              :             {
     507              :                 "SELECT a*b, a*2, a*2*b, 3*2*d, a*2*3;",
     508              :                 { "a*b", "a*2", "a*2*b", "6*d", "a*2*3" },
     509              :             },
     510              :             {
     511              :                 "SELECT 8/2, 13 /3, 85 / 7, 5/ 4;",
     512              :                 { "4", "4", "12", "1" },
     513              :             },
     514              :             {
     515              :                 "SELECT '8'/2, 13/'3', '85' / '7', 5/ '4';",
     516              :                 { "4", "4", "12", "1" },
     517              :             },
     518              :             {
     519              :                 "SELECT 4.11/2, 0.03/3;",
     520              :                 { "2.055", "0.01" },
     521              :             },
     522              :             {
     523              :                 "SELECT 2.01/3.11, 0.5/4.03;",
     524              :                 { "0.646302", "0.124069" },
     525              :             },
     526              :             {
     527              :                 "SELECT '2.01'/3.11, 0.5/'4.03';",
     528              :                 { "0.646302", "0.124069" },
     529              :             },
     530              :             {
     531              :                 "SELECT a/b, a/2, a/2/b, 3/2/d, a/2/3;",
     532              :                 { "a/b", "a/2", "a/2/b", "1/d", "a/2/3" },
     533              :             },
     534              :             {
     535              :                 "SELECT 8%5, 13 %3, 85 % 7, 5% 4;",
     536              :                 { "3", "1", "1", "1" },
     537              :             },
     538              :             {
     539              :                 "SELECT '8'%5, 23%'3', '85' % '7', 7% '4';",
     540              :                 { "3", "2", "1", "3" },
     541              :             },
     542              :             {
     543              :                 "SELECT 4.11%2, 0.03%3;",
     544              :                 { "0.11", "0.03" },
     545              :             },
     546              :             {
     547              :                 "SELECT 2.01%3.11, 0.5%4.03;",
     548              :                 { "2.01", "0.5" },
     549              :             },
     550              :             {
     551              :                 "SELECT '2.01'%3.11, 0.5%'4.03';",
     552              :                 { "2.01", "0.5" },
     553              :             },
     554              :             {
     555              :                 "SELECT a%b, a%2, a%2%b, 3%2%d, a%2%3;",
     556              :                 { "a%b", "a%2", "a%2%b", "1%d", "a%2%3" },
     557              :             },
     558           22 :         };
     559           19 :         for(auto const & e : multiplicative_expressions)
     560              :         {
     561           18 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     562           18 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_multiplicative, "multiplicative-expression.pbql"));
     563           18 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     564           18 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
     565              : 
     566              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_multiplicative << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
     567           18 :             CATCH_REQUIRE(commands.size() == 1);
     568              : 
     569              :             // BEGIN
     570           18 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
     571              :             // SCHEMA/DATA
     572           18 :             std::size_t const max(e.f_expected.size());
     573           18 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
     574           75 :             for(std::size_t idx(0); idx < max; ++idx)
     575              :             {
     576           57 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     577           57 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
     578              :             }
     579           18 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
     580           18 :         }
     581           19 :     }
     582           14 :     CATCH_END_SECTION()
     583              : 
     584           15 :     CATCH_START_SECTION("expression: additive")
     585              :     {
     586              :         struct postfix_t
     587              :         {
     588              :             char const *        f_additive = nullptr;
     589              :             std::vector<std::string>
     590              :                                 f_expected = std::vector<std::string>();
     591              :         };
     592            1 :         postfix_t const additive_expressions[] =
     593              :         {
     594              :             {
     595              :                 "SELECT 2+8, 3 +3, 5 + 7, 5+ 4;",
     596              :                 { "10", "6", "12", "9" },
     597              :             },
     598              :             {
     599              :                 "SELECT '2'+8, 3+'3', '5' + '7', 5+ '4';",
     600              :                 { "10", "6", "12", "9" },
     601              :             },
     602              :             {
     603              :                 "SELECT 4.11+2, 0.03+3;",
     604              :                 { "6.11", "3.03" },
     605              :             },
     606              :             {
     607              :                 "SELECT 2.01+3.11, 0.5+4.03;",
     608              :                 { "5.12", "4.53" },
     609              :             },
     610              :             {
     611              :                 "SELECT '2.01'+3.11, 0.5+'4.03';",
     612              :                 { "5.12", "4.53" },
     613              :             },
     614              :             {
     615              :                 "SELECT a+b, a+2, a+2+b, 3+2+d, a+2+3;",
     616              :                 { "a+b", "a+2", "a+2+b", "5+d", "a+2+3" },
     617              :             },
     618              :             {
     619              :                 "SELECT 8-2, 13 -3, 85 - 7, 5- 4;",
     620              :                 { "6", "10", "78", "1" },
     621              :             },
     622              :             {
     623              :                 "SELECT '8'-2, 13-'3', '85' - '7', 5- '4';",
     624              :                 { "6", "10", "78", "1" },
     625              :             },
     626              :             {
     627              :                 "SELECT 4.11-2, 0.03-3;",
     628              :                 { "2.11", "-2.97" },
     629              :             },
     630              :             {
     631              :                 "SELECT 2.01-3.11, 0.5-4.03;",
     632              :                 { "-1.1", "-3.53" },
     633              :             },
     634              :             {
     635              :                 "SELECT '2.01'-3.11, 0.5-'4.03';",
     636              :                 { "-1.1", "-3.53" },
     637              :             },
     638              :             {
     639              :                 "SELECT a-b, a-2, a-2-b, 3-2-d, a-2-3;",
     640              :                 { "a-b", "a-2", "a-2-b", "1-d", "a-2-3" },
     641              :             },
     642           16 :         };
     643           13 :         for(auto const & e : additive_expressions)
     644              :         {
     645           12 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     646           12 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_additive, "additive-expression.pbql"));
     647           12 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     648           12 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
     649              : 
     650              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_additive << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
     651           12 :             CATCH_REQUIRE(commands.size() == 1);
     652              : 
     653              :             // BEGIN
     654           12 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
     655              :             // SCHEMA/DATA
     656           12 :             std::size_t const max(e.f_expected.size());
     657           12 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
     658           50 :             for(std::size_t idx(0); idx < max; ++idx)
     659              :             {
     660           38 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     661           38 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
     662              :             }
     663           12 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
     664           12 :         }
     665           13 :     }
     666           14 :     CATCH_END_SECTION()
     667              : 
     668           15 :     CATCH_START_SECTION("expression: other (unary other than + and - and binary operators not found somewhere else)")
     669              :     {
     670              :         struct postfix_t
     671              :         {
     672              :             char const *        f_additive = nullptr;
     673              :             std::vector<std::string>
     674              :                                 f_expected = std::vector<std::string>();
     675              :         };
     676            1 :         postfix_t const other_expressions[] =
     677              :         {
     678              :             {
     679              :                 "SELECT 76 & 14, 3 | 9, 5 # 7;",
     680              :                 { "12", "11", "2" },
     681              :             },
     682              :             {
     683              :                 "SELECT a & b, c | d, e # f;",
     684              :                 { "a&b", "c|d", "e^f" },
     685              :             },
     686              :             {
     687              :                 "SELECT 76 << 14, 76.31 << 14, 3 << 9, 5 << 7, 760 >> 14, 30000 >> 9, 159 >> 7, -97845198764363672415796583254123645 >> 100;",
     688              :                 { "1245184", "1245184", "1536", "640", "0", "58", "1", "-77187" },
     689              :             },
     690              :             {
     691              :                 "SELECT a << b, c >> d;",
     692              :                 { "a<<b", "c>>d" },
     693              :             },
     694              :             {
     695              :                 "SELECT a || b, c || d || e || f, 'lit' || g, h || 'lit',"
     696              :                     " i || 'par' || 'tial', 'st' || 'art' || j, k || 'mid' || 'dle' || l,"
     697              :                     " m || 304 || 'n' || 10.5 || n, 'con' || 'cat' || ' to ' || 'literal';",
     698              :                 { "String.concat(a,b)", "String.concat(c,d,e,f)", "String.concat(\"lit\",g)", "String.concat(h,\"lit\")",
     699              :                   "String.concat(i,\"partial\")", "String.concat(\"start\",j)", "String.concat(k,\"middle\",l)",
     700              :                   "String.concat(m,\"304n10.5\",n)", "\"concat to literal\"" },
     701              :             },
     702              :             {
     703              :                 "SELECT 'this string' ~ 'matches that string?', 'this string' !~ 'matches that string?', a ~ b, c !~ d;",
     704              :                 { "false", "true", "new RegExp(b).test(a)", "!new RegExp(d).test(c)" },
     705              :             },
     706           10 :         };
     707            7 :         for(auto const & e : other_expressions)
     708              :         {
     709            6 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     710            6 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_additive, "other-expression.pbql"));
     711            6 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     712            6 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
     713              : 
     714              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_additive << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
     715            6 :             CATCH_REQUIRE(commands.size() == 1);
     716              : 
     717              :             // BEGIN
     718            6 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
     719              :             // SCHEMA/DATA
     720            6 :             std::size_t const max(e.f_expected.size());
     721            6 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
     722           35 :             for(std::size_t idx(0); idx < max; ++idx)
     723              :             {
     724           29 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     725           29 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
     726              :             }
     727            6 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
     728            6 :         }
     729            7 :     }
     730           14 :     CATCH_END_SECTION()
     731              : 
     732           15 :     CATCH_START_SECTION("expression: matching (BETWEEN, IN, LIKE, ILIKE)")
     733              :     {
     734              :         struct postfix_t
     735              :         {
     736              :             char const *        f_matching = nullptr;
     737              :             std::vector<std::string>
     738              :                                 f_expected = std::vector<std::string>();
     739              :         };
     740            1 :         postfix_t const other_expressions[] =
     741              :         {
     742              :             {
     743              :                 "SELECT 3 BETWEEN -10 AND +10;",
     744              :                 { "true" },
     745              :             },
     746              :             {
     747              :                 "SELECT -3 BETWEEN 0 AND '+10';",
     748              :                 { "false" },
     749              :             },
     750              :             {
     751              :                 "SELECT 30 BETWEEN '-10' AND 10;",
     752              :                 { "false" },
     753              :             },
     754              :             {
     755              :                 "SELECT 3.0 BETWEEN -'3.1' AND +3.1;",
     756              :                 { "true" },
     757              :             },
     758              :             {
     759              :                 "SELECT 3.0 NOT BETWEEN -'3.1' AND +3.1;",
     760              :                 { "false" },
     761              :             },
     762              :             {
     763              :                 "SELECT -3.3 BETWEEN '-3.2' AND +5;",
     764              :                 { "false" },
     765              :             },
     766              :             {
     767              :                 "SELECT 7.5 BETWEEN -5 AND 5.5;",
     768              :                 { "false" },
     769              :             },
     770              :             {
     771              :                 "SELECT 'hello' BETWEEN 'kitty' AND 'world';",
     772              :                 { "false" },
     773              :             },
     774              :             {
     775              :                 "SELECT 'kitty' BETWEEN 'hello' AND 'world';",
     776              :                 { "true" },
     777              :             },
     778              :             {
     779              :                 "SELECT 'hello' NOT BETWEEN 'kitty' AND 'world';",
     780              :                 { "true" },
     781              :             },
     782              :             {
     783              :                 "SELECT 'kitty' NOT BETWEEN 'hello' AND 'world';",
     784              :                 { "false" },
     785              :             },
     786              :             {
     787              :                 "SELECT null BETWEEN 0 AND 100;",
     788              :                 { "null" },
     789              :             },
     790              :             {
     791              :                 "SELECT true BETWEEN false AND true;",
     792              :                 { "true" },
     793              :             },
     794              :             {
     795              :                 "SELECT true BETWEEN true AND false;",
     796              :                 { "false" },
     797              :             },
     798              :             {
     799              :                 "SELECT true BETWEEN true AND true;",
     800              :                 { "true" },
     801              :             },
     802              :             {
     803              :                 "SELECT true BETWEEN false AND false;",
     804              :                 { "false" },
     805              :             },
     806              :             {
     807              :                 "SELECT false BETWEEN false AND true;",
     808              :                 { "true" },
     809              :             },
     810              :             {
     811              :                 "SELECT false BETWEEN true AND false;",
     812              :                 { "false" },
     813              :             },
     814              :             {
     815              :                 "SELECT false BETWEEN true AND true;",
     816              :                 { "false" },
     817              :             },
     818              :             {
     819              :                 "SELECT false BETWEEN false AND false;",
     820              :                 { "true" },
     821              :             },
     822              :             {
     823              :                 "SELECT a BETWEEN b AND c;",
     824              :                 { "(_t1=a,_t1>=b&&_t1<=c)" },
     825              :             },
     826              :             {
     827              :                 "SELECT a NOT BETWEEN b AND c;",
     828              :                 { "!(_t1=a,_t1>=b&&_t1<=c)" },
     829              :             },
     830              :             {
     831              :                 "SELECT 'hello world' LIKE '%world%', 'Hello World' ILIKE '%HELLO%',"
     832              :                       " 'hello world' LIKE '%world', 'Hello World' ILIKE 'HELLO%',"
     833              :                       " 'hello world' LIKE 'world%', 'Hello World' ILIKE '%HELLO',"
     834              :                       " 'hello world' NOT LIKE '%world%', 'Hello World' NOT ILIKE '%HELLO%',"
     835              :                       " 'hello world' NOT LIKE '%world', 'Hello World' NOT ILIKE 'HELLO%',"
     836              :                       " 'hello world' NOT LIKE 'world%', 'Hello World' NOT ILIKE '%HELLO';",
     837              :                 {
     838              :                     "true", "true", "true", "true", "false", "false",
     839              :                     "false", "false", "false", "false", "true", "true",
     840              :                 },
     841              :             },
     842              :             {
     843              :                 "SELECT a LIKE b, c ILIKE d, e NOT LIKE f, g NOT ILIKE h;",
     844              :                 {
     845              :                     "new RegExp(b).test(a)", "new RegExp(d,\"i\").test(c)",
     846              :                     "!new RegExp(f).test(e)", "!new RegExp(h,\"i\").test(g)",
     847              :                 },
     848              :             },
     849              :             {
     850              :                 "SELECT a LIKE '%word%', b ILIKE '%WORD%', c NOT LIKE '%word%', d NOT ILIKE '%WORD%';",
     851              :                 {
     852              :                     "new RegExp(\"^.*word.*$\").test(a)", "new RegExp(\"^.*WORD.*$\",\"i\").test(b)",
     853              :                     "!new RegExp(\"^.*word.*$\").test(c)", "!new RegExp(\"^.*WORD.*$\",\"i\").test(d)",
     854              :                 },
     855              :             },
     856           29 :         };
     857           26 :         for(auto const & e : other_expressions)
     858              :         {
     859           25 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     860           25 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_matching, "matching-expression.pbql"));
     861           25 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     862           25 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
     863              : 
     864              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_matching << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
     865           25 :             CATCH_REQUIRE(commands.size() == 1);
     866              : 
     867              :             // BEGIN
     868           25 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
     869              :             // SCHEMA/DATA
     870           25 :             std::size_t const max(e.f_expected.size());
     871           25 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
     872           67 :             for(std::size_t idx(0); idx < max; ++idx)
     873              :             {
     874           42 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     875           42 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
     876              :             }
     877           25 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
     878           25 :         }
     879           26 :     }
     880           14 :     CATCH_END_SECTION()
     881              : 
     882           15 :     CATCH_START_SECTION("expression: comparison")
     883              :     {
     884              :         struct postfix_t
     885              :         {
     886              :             char const *        f_comparison = nullptr;
     887              :             std::vector<std::string>
     888              :                                 f_expected = std::vector<std::string>();
     889              :         };
     890            1 :         postfix_t const other_expressions[] =
     891              :         {
     892              :             {
     893              :                 "SELECT NULL < 8, NULL <= 7.3, NULL = 'string', NULL > NULL, NULL >= True, NULL <> False,"
     894              :                       " 3 < NULL, 7.3 <= NULL, 'string' = NULL, NULL > NULL, True >= NULL, False <> NULL;",
     895              :                 {
     896              :                     "null", "null", "null", "null", "null", "null",
     897              :                     "null", "null", "null", "null", "null", "null",
     898              :                 },
     899              :             },
     900              :             {
     901              :                 "SELECT 3 < 8, 7 <= 7, 4 = 4, 9 > 7, 6 >= 6, 1 <> 9,"
     902              :                       " '3' < '18', '7' <= '7', '4' = '04', '19' > '7', '6' >= '6', '1' <> '9',"
     903              :                       " 3.5 < 8.2, 7.4 <= 7.4, 4.5 = 4.5, 9.2 > 7.01, 6.3 >= 6.2, 1.9 <> 9.1,"
     904              :                       " '3.5' < '8.2', '7.4' <= '7.4', '4.5' = '4.5', '11.2' > '7.01', '6.3' >= '6.2', '1.9' <> '9.1';",
     905              :                 {
     906              :                     "true", "true", "true", "true", "true", "true",
     907              :                     "true", "true", "true", "true", "true", "true",
     908              :                     "true", "true", "true", "true", "true", "true",
     909              :                     "true", "true", "true", "true", "true", "true",
     910              :                 },
     911              :             },
     912              :             {
     913              :                 "SELECT true < false, true <= true, false = false, true > true, false >= true, true <> true;",
     914              :                 {
     915              :                     "false", "true", "true", "false", "false", "false",
     916              :                 },
     917              :             },
     918              :             {
     919              :                 "SELECT 'hello' < 'world', 'hello' <= 'kitty', 'kitty' = 'food', 'orange' > 'violet', 'toy' >= 'brick', 'thick' <> 'thin';",
     920              :                 {
     921              :                     "true", "true", "false", "false", "true", "true",
     922              :                 },
     923              :             },
     924              :             {
     925              :                 "SELECT a < b, c <= d, e = f, g > h, i >= j, k <> l;",
     926              :                 { "a<b", "c<=d", "e==f", "g>h", "i>=j", "k!=l" },
     927              :             },
     928            9 :         };
     929            6 :         for(auto const & e : other_expressions)
     930              :         {
     931            5 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     932            5 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_comparison, "comparison-expression.pbql"));
     933            5 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     934            5 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
     935              : 
     936              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_comparison << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
     937            5 :             CATCH_REQUIRE(commands.size() == 1);
     938              : 
     939              :             // BEGIN
     940            5 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
     941              :             // SCHEMA/DATA
     942            5 :             std::size_t const max(e.f_expected.size());
     943            5 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
     944           59 :             for(std::size_t idx(0); idx < max; ++idx)
     945              :             {
     946           54 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
     947           54 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
     948              :             }
     949            5 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
     950            5 :         }
     951            6 :     }
     952           14 :     CATCH_END_SECTION()
     953              : 
     954           15 :     CATCH_START_SECTION("expression: expr IS ...")
     955              :     {
     956              :         struct postfix_t
     957              :         {
     958              :             char const *        f_is = nullptr;
     959              :             std::vector<std::string>
     960              :                                 f_expected = std::vector<std::string>();
     961              :         };
     962            1 :         postfix_t const other_expressions[] =
     963              :         {
     964              :             {
     965              :                 "SELECT 77 IS TRUE, 'string' IS TRUE, 3.9813 IS TRUE, TRUE IS TRUE, FALSE IS TRUE, NULL IS TRUE;",
     966              :                 {
     967              :                     "false", "false", "false", "true", "false", "false",
     968              :                 },
     969              :             },
     970              :             {
     971              :                 "SELECT 77 IS FALSE, 'string' IS FALSE, 3.9813 IS FALSE, TRUE IS FALSE, FALSE IS FALSE, NULL IS FALSE;",
     972              :                 {
     973              :                     "false", "false", "false", "false", "true", "false",
     974              :                 },
     975              :             },
     976              :             {
     977              :                 "SELECT 77 IS NULL, 'string' IS NULL, 3.9813 IS NULL, TRUE IS NULL, FALSE IS NULL, NULL IS NULL;",
     978              :                 {
     979              :                     "false", "false", "false", "false", "false", "true",
     980              :                 },
     981              :             },
     982              :             {
     983              :                 "SELECT a IS TRUE, b IS NOT TRUE, c IS FALSE, d IS NOT FALSE, e IS NULL, f IS NOT NULL;",
     984              :                 {
     985              :                     "a", "!b", "!c", "d", "e==null", "f!=null",
     986              :                 },
     987              :             },
     988            8 :         };
     989            5 :         for(auto const & e : other_expressions)
     990              :         {
     991            4 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
     992            4 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_is, "comparison-expression.pbql"));
     993            4 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
     994            4 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
     995              : 
     996              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_is << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
     997            4 :             CATCH_REQUIRE(commands.size() == 1);
     998              : 
     999              :             // BEGIN
    1000            4 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
    1001              :             // SCHEMA/DATA
    1002            4 :             std::size_t const max(e.f_expected.size());
    1003            4 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
    1004           28 :             for(std::size_t idx(0); idx < max; ++idx)
    1005              :             {
    1006           24 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
    1007           24 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
    1008              :             }
    1009            4 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
    1010            4 :         }
    1011            5 :     }
    1012           14 :     CATCH_END_SECTION()
    1013              : 
    1014           15 :     CATCH_START_SECTION("expression: NOT expr")
    1015              :     {
    1016              :         struct postfix_t
    1017              :         {
    1018              :             char const *        f_not = nullptr;
    1019              :             std::vector<std::string>
    1020              :                                 f_expected = std::vector<std::string>();
    1021              :         };
    1022            1 :         postfix_t const other_expressions[] =
    1023              :         {
    1024              :             {
    1025              :                 "SELECT NOT TRUE, NOT FALSE, NOT NOT TRUE, NOT NOT FALSE;",
    1026              :                 {
    1027              :                     "false", "true", "true", "false",
    1028              :                 },
    1029              :             },
    1030              :             {
    1031              :                 "SELECT NOT 'TRUE', NOT 'FalsE', NOT NOT 'tru', NOT NOT 'f';",
    1032              :                 {
    1033              :                     "false", "true", "true", "false",
    1034              :                 },
    1035              :             },
    1036              :             {
    1037              :                 "SELECT NOT 0, NOT 1, NOT NOT 3, NOT NOT 5.05, NOT NOT 0, NOT NOT 0.0;",
    1038              :                 {
    1039              :                     "true", "false", "true", "true", "false", "false",
    1040              :                 },
    1041              :             },
    1042              :             {
    1043              :                 "SELECT NOT a, NOT NOT b, NOT NOT NOT c, NOT NOT NOT NOT d;",
    1044              :                 {
    1045              :                     "!a", "!!b", "!c", "!!d",
    1046              :                 },
    1047              :             },
    1048            8 :         };
    1049            5 :         for(auto const & e : other_expressions)
    1050              :         {
    1051            4 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1052            4 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_not, "comparison-expression.pbql"));
    1053            4 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1054            4 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
    1055              : 
    1056              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_not << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
    1057            4 :             CATCH_REQUIRE(commands.size() == 1);
    1058              : 
    1059              :             // BEGIN
    1060            4 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
    1061              :             // SCHEMA/DATA
    1062            4 :             std::size_t const max(e.f_expected.size());
    1063            4 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
    1064           22 :             for(std::size_t idx(0); idx < max; ++idx)
    1065              :             {
    1066           18 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
    1067           18 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
    1068              :             }
    1069            4 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
    1070            4 :         }
    1071            5 :     }
    1072           14 :     CATCH_END_SECTION()
    1073              : 
    1074           15 :     CATCH_START_SECTION("expression: expr AND expr")
    1075              :     {
    1076              :         struct postfix_t
    1077              :         {
    1078              :             char const *        f_and = nullptr;
    1079              :             std::vector<std::string>
    1080              :                                 f_expected = std::vector<std::string>();
    1081              :         };
    1082            1 :         postfix_t const other_expressions[] =
    1083              :         {
    1084              :             {
    1085              :                 "SELECT TRUE AND TRUE, TRUE AND FALSE, FALSE AND TRUE, FALSE AND FALSE;",
    1086              :                 {
    1087              :                     "true", "false", "false", "false",
    1088              :                 },
    1089              :             },
    1090              :             {
    1091              :                 "SELECT a AND b, c AND TRUE, TRUE AND d, e AND FALSE, FALSE AND f;",
    1092              :                 {
    1093              :                     "a&&b", "c", "d", "false", "false",
    1094              :                 },
    1095              :             },
    1096            6 :         };
    1097            3 :         for(auto const & e : other_expressions)
    1098              :         {
    1099            2 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1100            2 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_and, "comparison-expression.pbql"));
    1101            2 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1102            2 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
    1103              : 
    1104              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_and << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
    1105            2 :             CATCH_REQUIRE(commands.size() == 1);
    1106              : 
    1107              :             // BEGIN
    1108            2 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
    1109              :             // SCHEMA/DATA
    1110            2 :             std::size_t const max(e.f_expected.size());
    1111            2 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
    1112           11 :             for(std::size_t idx(0); idx < max; ++idx)
    1113              :             {
    1114            9 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
    1115            9 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
    1116              :             }
    1117            2 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
    1118            2 :         }
    1119            3 :     }
    1120           14 :     CATCH_END_SECTION()
    1121              : 
    1122           15 :     CATCH_START_SECTION("expression: expr OR expr")
    1123              :     {
    1124              :         struct postfix_t
    1125              :         {
    1126              :             char const *        f_or = nullptr;
    1127              :             std::vector<std::string>
    1128              :                                 f_expected = std::vector<std::string>();
    1129              :         };
    1130            1 :         postfix_t const other_expressions[] =
    1131              :         {
    1132              :             {
    1133              :                 "SELECT TRUE OR TRUE, TRUE OR FALSE, FALSE OR TRUE, FALSE OR FALSE;",
    1134              :                 {
    1135              :                     "true", "true", "true", "false",
    1136              :                 },
    1137              :             },
    1138              :             {
    1139              :                 "SELECT a OR b, c OR TRUE, TRUE OR d, e OR FALSE, FALSE OR f;",
    1140              :                 {
    1141              :                     "a||b", "true", "true", "e", "f",
    1142              :                 },
    1143              :             },
    1144            6 :         };
    1145            3 :         for(auto const & e : other_expressions)
    1146              :         {
    1147            4 : SNAP_LOG_WARNING << "[early] got command for expression! [" << e.f_or << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
    1148            2 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1149            2 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_or, "comparison-expression.pbql"));
    1150            2 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1151            2 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
    1152              : 
    1153            4 : SNAP_LOG_WARNING << "got command for expression! [" << e.f_or << "] max=" << e.f_expected.size() << SNAP_LOG_SEND;
    1154            2 :             CATCH_REQUIRE(commands.size() == 1);
    1155              : 
    1156              :             // BEGIN
    1157            2 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
    1158              :             // SCHEMA/DATA
    1159            2 :             std::size_t const max(e.f_expected.size());
    1160            2 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
    1161           11 :             for(std::size_t idx(0); idx < max; ++idx)
    1162              :             {
    1163           18 : SNAP_LOG_WARNING << "compare #" << idx << SNAP_LOG_SEND;
    1164            9 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
    1165            9 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
    1166              :             }
    1167            2 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
    1168            2 :         }
    1169            3 :     }
    1170           14 :     CATCH_END_SECTION()
    1171           13 : }
    1172              : 
    1173              : 
    1174            1 : CATCH_TEST_CASE("expression_functions", "[expression][parser][pbql]")
    1175              : {
    1176            3 :     CATCH_START_SECTION("expression: functions")
    1177              :     {
    1178              :         struct function_t
    1179              :         {
    1180              :             char const *        f_function = nullptr;
    1181              :             std::vector<std::string>
    1182              :                                 f_expected = std::vector<std::string>();
    1183              :             std::vector<std::string>
    1184              :                                 f_column_name = std::vector<std::string>();
    1185              :         };
    1186            1 :         function_t const function_expressions[] =
    1187              :         {
    1188              :             {
    1189              :                 "SELECT @5 AS pos, @-6 AS neg, Sign(+32), SiGn(-9), siGN(0);",
    1190              :                 { "5", "6", "1", "-1", "0" },
    1191              :                 { "pos", "neg", "__col3", "__col4", "__col5" },
    1192              :             },
    1193              :             {
    1194              :                 "SELECT @3.05, @-4.32, Abs(45.3), aBs(-5.91), sign(57.61), SIGN(-101.0043), sIGn(0.0);",
    1195              :                 { "3.05", "4.32", "45.3", "5.91", "1", "-1", "0" },
    1196              :                 { "__col1", "__col2", "__col3", "__col4", "__col5", "__col6", "__col7" },
    1197              :             },
    1198              :             {
    1199              :                 "SELECT @a, @-b as neg, ABS(c), abs(d) As lc, sign(e) AS s;",
    1200              :                 { "Math.abs(a)", "Math.abs(b)", "Math.abs(c)", "Math.abs(d)", "Math.sign(e)" },
    1201              :                 { "__col1", "neg", "__col3", "lc", "s" },
    1202              :             },
    1203              :             {
    1204              :                 "SELECT Abs(45.3) - 9.1, Abs(-99) + 3;",
    1205              :                 { "36.2", "102" },
    1206              :             },
    1207              :             {
    1208              :                 "SELECT |/121, |/ 25.25, |/-81, |/a, |/-b, |/@c;",
    1209              :                 { "11.0", "5.024938", "NaN", "Math.sqrt(a)", "Math.sqrt(-b)", "Math.sqrt(Math.abs(c))" },
    1210              :             },
    1211              :             {
    1212              :                 "SELECT ||/1331, ||/ 25.25, ||/-729, ||/ -700 - 29, ||/a, ||/-b, ||/@c;",
    1213              :                 { "11.0", "2.933732", "-9.0", "-9.0", "Math.cbrt(a)", "Math.cbrt(-b)", "Math.cbrt(Math.abs(c))" },
    1214              :             },
    1215              :             {
    1216              :                 "SELECT SqRt(121.0), sqrt(a) + b, CbRt(1331), cbRT(c) - d;",
    1217              :                 { "11.0", "Math.sqrt(a)+b", "11.0", "Math.cbrt(c)-d" },
    1218              :             },
    1219              :             {
    1220              :                 "SELECT sin(4.3), cos(-0.75), tan(0.7775),"
    1221              :                       " sinh(4.3), cosh(-0.75), tanh(0.7775),"
    1222              :                       " asin(0.3), acos(-0.75), atan(0.7775), atan(45, 100),"
    1223              :                       " asinh(4.3), acosh(1.75), atanh(0.7775);",
    1224              :                 { "-0.916166", "0.731689", "0.984327",
    1225              :                   "36.843113", "1.294683", "0.651269",
    1226              :                    "0.304693", "2.418858", "0.66087", "0.422854",
    1227              :                    "2.165017", "1.15881",  "1.039018" },
    1228              :             },
    1229              :             {
    1230              :                 "SELECT sin(a), cos(b), tan(c),"
    1231              :                       " sinh(d), cosh(e), tanh(f),"
    1232              :                       " asin(g), acos(h), atan(i), atan(j, k),"
    1233              :                       " asinh(l), acosh(m), atanh(n);",
    1234              :                 { "Math.sin(a)",   "Math.cos(b)",   "Math.tan(c)",
    1235              :                   "Math.sinh(d)",  "Math.cosh(e)",  "Math.tanh(f)",
    1236              :                   "Math.asin(g)",  "Math.acos(h)",  "Math.atan(i)", "Math.atan2(j,k)",
    1237              :                   "Math.asinh(l)", "Math.acosh(m)", "Math.atanh(n)" },
    1238              :             },
    1239              :             {
    1240              :                 "SELECT ceil(17), ceil(4.3), ceil(-11.35),"
    1241              :                       " floor(101), floor(9.75), floor(-0.75),"
    1242              :                       " round(7.775), round(-14.1), round(17), round(-23),"
    1243              :                       " trunc(4.3), trunc(-44.3), trunc(45), trunc(-90);",
    1244              :                 { "17", "5.0", "-11.0",
    1245              :                   "101", "9.0", "-1.0",
    1246              :                   "8", "-14", "17", "-23",
    1247              :                   "4.0", "-44.0", "45", "-90" },
    1248              :             },
    1249              :             {
    1250              :                 "SELECT ceil(a), floor(b), round(c), trunc(d);",
    1251              :                 { "Math.ceil(a)", "Math.floor(b)", "Math.round(c)", "Math.trunc(d)" },
    1252              :             },
    1253              :             {
    1254              :                 "SELECT exp(4.3), expm1(0.003501), pow(9.75, 3.07), pow(4, 13),"
    1255              :                       " log(7.775), log1p(14.1), log10(10000), log2(65536);",
    1256              :                 { "73.699794", "0.003507", "1087.036608", "67108864",
    1257              :                   "2.050913", "2.714695", "4.0", "16.0" },
    1258              :             },
    1259              :             {
    1260              :                 "SELECT exp(a), expm1(b), pow(c, d),"
    1261              :                       " log(e), log1p(f), log10(g), log2(h);",
    1262              :                 { "Math.exp(a)", "Math.expm1(b)", "(c**d)",
    1263              :                   "Math.log(e)", "Math.log1p(f)", "Math.log10(g)", "Math.log2(h)" },
    1264              :             },
    1265              :             {
    1266              :                 "SELECT rand();",
    1267              :                 { "Math.rand()" },
    1268              :             },
    1269              :             {
    1270              :                 "SELECT hypot(), hypot(55.003), hypot(19.75, 23.07),"
    1271              :                       " hypot(7.775, 14.1, 100), hypot(-65.6);",
    1272              :                 { "0.0", "55.003", "30.369185",
    1273              :                   "101.288008", "65.6" },
    1274              :             },
    1275              :             {
    1276              :                 "SELECT hypot(a), hypot(b, c), hypot(d, e, f);",
    1277              :                 { "Math.abs(a)", "Math.hypot(b,c)", "Math.hypot(d,e,f)" },
    1278              :             },
    1279              :             {
    1280              :                 "SELECT imul(33.2, 25.03), imul(-13.02, 5.78), imul(3, 9), imul(5, -45);",
    1281              :                 { "825", "-65", "27", "-225" },
    1282              :             },
    1283              :             {
    1284              :                 "SELECT imul(a, b);",
    1285              :                 { "Math.imul(a,b)" },
    1286              :             },
    1287              :             {
    1288              :                 "SELECT length('this string is 33 characters long'), length(a);",
    1289              :                 { "33", "a.length" },
    1290              :             },
    1291              :             {
    1292              :                 "SELECT min(), min(1.0), min(2), min(33.2, 25.03), min(-13.02, 5.78, -45, +1000), min(78, -9, 34, 2, -8);",
    1293              :                 { "Infinity", "1.0", "2", "25.03", "-45.0", "-9" },
    1294              :             },
    1295              :             {
    1296              :                 "SELECT min(a, b), min(c, d, e, f, g, h);",
    1297              :                 { "Math.min(a,b)", "Math.min(c,d,e,f,g,h)" },
    1298              :             },
    1299              :             {
    1300              :                 "SELECT max(), max(1.0), max(2), max(33.2, 25.03), max(-13.02, 5.78, -45, +1000), max(78, -9, 34, 2, -8);",
    1301              :                 { "-Infinity", "1.0", "2", "33.2", "1000.0", "78" },
    1302              :             },
    1303              :             {
    1304              :                 "SELECT max(a, b), max(c, d, e, f, g, h);",
    1305              :                 { "Math.max(a,b)", "Math.max(c,d,e,f,g,h)" },
    1306              :             },
    1307              :             { // two identifiers one after the other when the first is not a type
    1308              :                 "SELECT Column AS c1, demonstration AS c2, idea as c3, fork AS c4,"
    1309              :                       " REACT AS C5, SMall As c6, tuition AS C7, urN aS c8, violet as c9"
    1310              :                     ";",
    1311              :                 { "column", "demonstration", "idea", "fork",
    1312              :                   "react", "small", "tuition", "urn", "violet" },
    1313              :                 { "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9" },
    1314              :             },
    1315           28 :         };
    1316           25 :         for(auto const & e : function_expressions)
    1317              :         {
    1318           24 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1319           24 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_function, "function-expression.pbql"));
    1320           24 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1321           24 :             prinbee::pbql::command::vector_t const & commands(parser->parse());
    1322              : 
    1323              : //SNAP_LOG_WARNING << "got command for expression! [" << e.f_function << "]" << SNAP_LOG_SEND;
    1324           24 :             CATCH_REQUIRE(commands.size() == 1);
    1325              : 
    1326              :             // BEGIN
    1327           24 :             CATCH_REQUIRE(commands[0]->get_command() == prinbee::pbql::command_t::COMMAND_SELECT);
    1328              :             // SCHEMA/DATA
    1329           24 :             std::size_t const max(e.f_expected.size());
    1330           24 :             CATCH_REQUIRE(max <= prinbee::pbql::MAX_EXPRESSIONS);
    1331          160 :             for(std::size_t idx(0); idx < max; ++idx)
    1332              :             {
    1333          136 :                 CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == prinbee::pbql::param_type_t::PARAM_TYPE_STRING);
    1334          136 :                 CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_EXPRESSION + idx) == e.f_expected[idx]);
    1335          136 :                 if(idx < e.f_column_name.size())
    1336              :                 {
    1337           26 :                     CATCH_REQUIRE(commands[0]->get_string(prinbee::pbql::param_t::PARAM_COLUMN_NAME + idx) == e.f_column_name[idx]);
    1338              :                 }
    1339              :             }
    1340           24 :             CATCH_REQUIRE(commands[0]->is_defined_as(prinbee::pbql::param_t::PARAM_EXPRESSION + max) == prinbee::pbql::param_type_t::PARAM_TYPE_UNKNOWN);
    1341           24 :         }
    1342           25 :     }
    1343            2 :     CATCH_END_SECTION()
    1344            1 : }
    1345              : 
    1346              : 
    1347           33 : CATCH_TEST_CASE("expression_error", "[expression][parser][pbql][error]")
    1348              : {
    1349           35 :     CATCH_START_SECTION("expression_error: unknown primary expression")
    1350              :     {
    1351            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1352            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT =;", "primary-expression.pbql"));
    1353            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1354              : 
    1355            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1356              :                   parser->parse()
    1357              :                 , prinbee::invalid_token
    1358              :                 , Catch::Matchers::ExceptionMessage(
    1359              :                           "prinbee_exception: primary-expression.pbql:1:8: expected a primary token not '=' (primary tokens are: string, number, true, false, identifier, '*', or an expression between parenthesis)."));
    1360            1 :     }
    1361           34 :     CATCH_END_SECTION()
    1362              : 
    1363           35 :     CATCH_START_SECTION("expression_error: missing ')'")
    1364              :     {
    1365            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1366            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT (true;", "primary-expression.pbql"));
    1367            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1368              : 
    1369            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1370              :                   parser->parse()
    1371              :                 , prinbee::invalid_token
    1372              :                 , Catch::Matchers::ExceptionMessage(
    1373              :                           "prinbee_exception: primary-expression.pbql:1:14: expected ')' to close the grouped expressions."));
    1374            1 :     }
    1375           34 :     CATCH_END_SECTION()
    1376              : 
    1377           35 :     CATCH_START_SECTION("expression_error: field name after '.*'")
    1378              :     {
    1379            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1380            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT table_name.*.more;", "postfix-expression.pbql"));
    1381            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1382              : 
    1383            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1384              :                   parser->parse()
    1385              :                 , prinbee::invalid_token
    1386              :                 , Catch::Matchers::ExceptionMessage(
    1387              :                           "prinbee_exception: postfix-expression.pbql:1:20: no more '.' can be used after '.*'."));
    1388            1 :     }
    1389           34 :     CATCH_END_SECTION()
    1390              : 
    1391           35 :     CATCH_START_SECTION("expression_error: field name cannot be an integer")
    1392              :     {
    1393            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1394            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT table_name.491;", "postfix-expression.pbql"));
    1395            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1396              : 
    1397            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1398              :                   parser->parse()
    1399              :                 , prinbee::invalid_token
    1400              :                 , Catch::Matchers::ExceptionMessage(
    1401              :                           "prinbee_exception: postfix-expression.pbql:1:19: expected '*' or a field name after '.'."));
    1402            1 :     }
    1403           34 :     CATCH_END_SECTION()
    1404              : 
    1405           35 :     CATCH_START_SECTION("expression_error: scope must be followed by an identifier")
    1406              :     {
    1407            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1408            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT table_name::491;", "postfix-expression.pbql"));
    1409            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1410              : 
    1411            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1412              :                   parser->parse()
    1413              :                 , prinbee::invalid_token
    1414              :                 , Catch::Matchers::ExceptionMessage(
    1415              :                           "prinbee_exception: postfix-expression.pbql:1:20: a type name was expected after the '::' operator, not INTEGER."));
    1416            1 :     }
    1417           34 :     CATCH_END_SECTION()
    1418              : 
    1419           35 :     CATCH_START_SECTION("expression_error: unknown type after scope")
    1420              :     {
    1421            1 :         constexpr char const * bad_names[] = {
    1422              :             "AMOEBA",
    1423              :             "BRILLANT",
    1424              :             "CHARLIE",
    1425              :             "DARLING",
    1426              :             "ENGINEERING",
    1427              :             "FLAKY",
    1428              :             "GLORY",
    1429              :             "HOVERING",
    1430              :             "INVENTORY",
    1431              :             "JOUST",
    1432              :             "KRAKEN",
    1433              :             "LUNAR",
    1434              :             "MOMENT",
    1435              :             "NORTH",
    1436              :             "OPAL",
    1437              :             "PARACHUTE",
    1438              :             "QUARTER",
    1439              :             "REST",
    1440              :             "STATUE",
    1441              :             "TRICKERY",
    1442              :             "UNIVERSE",
    1443              :             "VERTICAL",
    1444              :             "WISH",
    1445              :             "XENOPHOBE",
    1446              :             "YEAH",
    1447              :             "ZEBRA",
    1448              :         };
    1449           27 :         for(auto const & n : bad_names)
    1450              :         {
    1451           26 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1452           78 :             std::string in("SELECT table_name::");
    1453           26 :             in += n;
    1454           26 :             in += ";";
    1455           26 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(in, "postfix-expression.pbql"));
    1456           26 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1457              : 
    1458           78 :             CATCH_REQUIRE_THROWS_MATCHES(
    1459              :                       parser->parse()
    1460              :                     , prinbee::invalid_token
    1461              :                     , Catch::Matchers::ExceptionMessage(
    1462              :                               "prinbee_exception: postfix-expression.pbql:1:20: "
    1463              :                               "a type name was expected after the '::' operator, not IDENTIFIER \""
    1464              :                             + snapdev::to_lower(std::string(n))
    1465              :                             + "\"."));
    1466           26 :         }
    1467              :     }
    1468           34 :     CATCH_END_SECTION()
    1469              : 
    1470           35 :     CATCH_START_SECTION("expression_error: unknown UNSIGNED integer type after scope")
    1471              :     {
    1472            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1473            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT table_name::UNSIGNED NUMBER;", "postfix-expression.pbql"));
    1474            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1475              : 
    1476            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1477              :                   parser->parse()
    1478              :                 , prinbee::invalid_token
    1479              :                 , Catch::Matchers::ExceptionMessage(
    1480              :                           "prinbee_exception: postfix-expression.pbql:1:29: "
    1481              :                           "expected an integer name to follow the UNSIGNED word (not 'NUMBER')."));
    1482            1 :     }
    1483           34 :     CATCH_END_SECTION()
    1484              : 
    1485           35 :     CATCH_START_SECTION("expression_error: type is DOUBLE PRECISION, not DOUBLE NUMBER")
    1486              :     {
    1487            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1488            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT table_name::DOUBLE NUMBER;", "postfix-expression.pbql"));
    1489            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1490              : 
    1491            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1492              :                   parser->parse()
    1493              :                 , prinbee::invalid_token
    1494              :                 , Catch::Matchers::ExceptionMessage(
    1495              :                           "prinbee_exception: postfix-expression.pbql:1:20: expected"
    1496              :                           " DOUBLE to be followed by the word PRECISION."));
    1497            1 :     }
    1498           34 :     CATCH_END_SECTION()
    1499              : 
    1500           35 :     CATCH_START_SECTION("expression_error: type is DOUBLE PRECISION, not DOUBLE 3.1415926")
    1501              :     {
    1502            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1503            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT table_name::DOUBLE 3.1415926;", "postfix-expression.pbql"));
    1504            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1505              : 
    1506            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1507              :                   parser->parse()
    1508              :                 , prinbee::invalid_token
    1509              :                 , Catch::Matchers::ExceptionMessage(
    1510              :                           "prinbee_exception: postfix-expression.pbql:1:20: expected"
    1511              :                           " DOUBLE to be followed by the word PRECISION."));
    1512            1 :     }
    1513           34 :     CATCH_END_SECTION()
    1514              : 
    1515           35 :     CATCH_START_SECTION("expression_error: type is DOUBLE PRECISION, not DOUBLE 'PRECISION'")
    1516              :     {
    1517            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1518            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT table_name::DOUBLE 'PRECISION';", "postfix-expression.pbql"));
    1519            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1520              : 
    1521            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1522              :                   parser->parse()
    1523              :                 , prinbee::invalid_token
    1524              :                 , Catch::Matchers::ExceptionMessage(
    1525              :                           "prinbee_exception: postfix-expression.pbql:1:20: expected"
    1526              :                           " DOUBLE to be followed by the word PRECISION."));
    1527            1 :     }
    1528           34 :     CATCH_END_SECTION()
    1529              : 
    1530           35 :     CATCH_START_SECTION("expression_error: type is UNSIGNED <int name>, not UNSIGNED 42")
    1531              :     {
    1532            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1533            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT table_name::UNSIGNED 42;", "postfix-expression.pbql"));
    1534            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1535              : 
    1536            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1537              :                   parser->parse()
    1538              :                 , prinbee::invalid_token
    1539              :                 , Catch::Matchers::ExceptionMessage(
    1540              :                           "prinbee_exception: postfix-expression.pbql:1:29: expected an integer name to follow the UNSIGNED word (not a INTEGER)."));
    1541            1 :     }
    1542           34 :     CATCH_END_SECTION()
    1543              : 
    1544           35 :     CATCH_START_SECTION("expression_error: type is UNSIGNED <int>, not UNSIGNED 'INTEGER'")
    1545              :     {
    1546            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1547            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT table_name::UNSIGNED 'INTEGER';", "postfix-expression.pbql"));
    1548            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1549              : 
    1550            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1551              :                   parser->parse()
    1552              :                 , prinbee::invalid_token
    1553              :                 , Catch::Matchers::ExceptionMessage(
    1554              :                           "prinbee_exception: postfix-expression.pbql:1:29: expected an integer name to follow the UNSIGNED word (not a STRING)."));
    1555            1 :     }
    1556           34 :     CATCH_END_SECTION()
    1557              : 
    1558           35 :     CATCH_START_SECTION("expression_error: missing ']'")
    1559              :     {
    1560            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1561            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT MyTable.ExtendedField[INDEX;", "postfix-expression.pbql"));
    1562            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1563              : 
    1564            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1565              :                   parser->parse()
    1566              :                 , prinbee::invalid_token
    1567              :                 , Catch::Matchers::ExceptionMessage(
    1568              :                           "prinbee_exception: postfix-expression.pbql:1:36: expected a closing square bracket (]), not ';'."));
    1569            1 :     }
    1570           34 :     CATCH_END_SECTION()
    1571              : 
    1572           35 :     CATCH_START_SECTION("expression_error: function name not an identifier (integer)")
    1573              :     {
    1574            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1575            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT 45(11);", "postfix-expression.pbql"));
    1576            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1577              : 
    1578            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1579              :                   parser->parse()
    1580              :                 , prinbee::invalid_token
    1581              :                 , Catch::Matchers::ExceptionMessage(
    1582              :                           "prinbee_exception: postfix-expression.pbql:1:11: unexpected opening parenthesis ('(') after token INTEGER."));
    1583            1 :     }
    1584           34 :     CATCH_END_SECTION()
    1585              : 
    1586           35 :     CATCH_START_SECTION("expression_error: function name not an identifier (string)")
    1587              :     {
    1588            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1589            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT 'tan'(3.14159);", "postfix-expression.pbql"));
    1590            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1591              : 
    1592            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1593              :                   parser->parse()
    1594              :                 , prinbee::invalid_token
    1595              :                 , Catch::Matchers::ExceptionMessage(
    1596              :                           "prinbee_exception: postfix-expression.pbql:1:14: unexpected opening parenthesis ('(') after token STRING."));
    1597            1 :     }
    1598           34 :     CATCH_END_SECTION()
    1599              : 
    1600           35 :     CATCH_START_SECTION("expression_error: function name not an identifier (true)")
    1601              :     {
    1602            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1603            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT true(3.14159);", "postfix-expression.pbql"));
    1604            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1605              : 
    1606            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1607              :                   parser->parse()
    1608              :                 , prinbee::invalid_token
    1609              :                 , Catch::Matchers::ExceptionMessage(
    1610              :                           "prinbee_exception: postfix-expression.pbql:1:13: unexpected opening parenthesis ('(') after token TRUE."));
    1611            1 :     }
    1612           34 :     CATCH_END_SECTION()
    1613              : 
    1614           35 :     CATCH_START_SECTION("expression_error: function name not an identifier (false)")
    1615              :     {
    1616            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1617            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT false(3.14159);", "postfix-expression.pbql"));
    1618            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1619              : 
    1620            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1621              :                   parser->parse()
    1622              :                 , prinbee::invalid_token
    1623              :                 , Catch::Matchers::ExceptionMessage(
    1624              :                           "prinbee_exception: postfix-expression.pbql:1:14: unexpected opening parenthesis ('(') after token FALSE."));
    1625            1 :     }
    1626           34 :     CATCH_END_SECTION()
    1627              : 
    1628           35 :     CATCH_START_SECTION("expression_error: double 'precision'() expected an identifier")
    1629              :     {
    1630            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1631            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT double 'precision'(308);", "cast-expression.pbql"));
    1632            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1633              : 
    1634            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1635              :                   parser->parse()
    1636              :                 , prinbee::invalid_token
    1637              :                 , Catch::Matchers::ExceptionMessage(
    1638              :                           "prinbee_exception: cast-expression.pbql:1:8: expected DOUBLE to be followed by the word PRECISION."));
    1639            1 :     }
    1640           34 :     CATCH_END_SECTION()
    1641              : 
    1642           35 :     CATCH_START_SECTION("expression_error: atan() called with no parameters")
    1643              :     {
    1644            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1645            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT atan();", "postfix-expression.pbql"));
    1646            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1647              : 
    1648            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1649              :                   parser->parse()
    1650              :                 , prinbee::invalid_parameter
    1651              :                 , Catch::Matchers::ExceptionMessage(
    1652              :                           "prinbee_exception: postfix-expression.pbql:1:14: expected 1 or 2 parameters to ATAN(), found 0 instead."));
    1653            1 :     }
    1654           34 :     CATCH_END_SECTION()
    1655              : 
    1656           35 :     CATCH_START_SECTION("expression_error: atan() called with 3 parameters")
    1657              :     {
    1658            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1659            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT atan(x, y, z);", "postfix-expression.pbql"));
    1660            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1661              : 
    1662            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1663              :                   parser->parse()
    1664              :                 , prinbee::invalid_parameter
    1665              :                 , Catch::Matchers::ExceptionMessage(
    1666              :                           "prinbee_exception: postfix-expression.pbql:1:21: expected 1 or 2 parameters to ATAN(), found 3 instead."));
    1667            1 :     }
    1668           34 :     CATCH_END_SECTION()
    1669              : 
    1670           35 :     CATCH_START_SECTION("expression_error: unknown functions (to test the 'false' statements in all cases)")
    1671              :     {
    1672              :         struct function_t
    1673              :         {
    1674              :             char const *        f_function = nullptr;
    1675              :             char const *        f_error_msg = nullptr;
    1676              :         };
    1677            1 :         function_t const function_expressions[] =
    1678              :         {
    1679              :             {
    1680              :                 "SELECT algebra(15.03);",
    1681              :                 "prinbee_exception: function-expression.pbql:1:16: unknown function ALGEBRA().",
    1682              :             },
    1683              :             {
    1684              :                 "SELECT Brake(15.03);",
    1685              :                 "prinbee_exception: function-expression.pbql:1:14: unknown function BRAKE().",
    1686              :             },
    1687              :             {
    1688              :                 "SELECT COLUMNS(15.03);",
    1689              :                 "prinbee_exception: function-expression.pbql:1:16: unknown function COLUMNS().",
    1690              :             },
    1691              :             {
    1692              :                 "SELECT Edge_Case('car');",
    1693              :                 "prinbee_exception: function-expression.pbql:1:18: unknown function EDGE_CASE().",
    1694              :             },
    1695              :             {
    1696              :                 "SELECT FractioN(15.03);",
    1697              :                 "prinbee_exception: function-expression.pbql:1:17: unknown function FRACTION().",
    1698              :             },
    1699              :             {
    1700              :                 "SELECT HelloWorld(15.03);",
    1701              :                 "prinbee_exception: function-expression.pbql:1:19: unknown function HELLOWORLD().",
    1702              :             },
    1703              :             {
    1704              :                 "SELECT IS_Red(15.03);",
    1705              :                 "prinbee_exception: function-expression.pbql:1:15: unknown function IS_RED().",
    1706              :             },
    1707              :             {
    1708              :                 "SELECT Logarithm(15.03);",
    1709              :                 "prinbee_exception: function-expression.pbql:1:18: unknown function LOGARITHM().",
    1710              :             },
    1711              :             {
    1712              :                 "SELECT multi(15.03);",
    1713              :                 "prinbee_exception: function-expression.pbql:1:14: unknown function MULTI().",
    1714              :             },
    1715              :             {
    1716              :                 "SELECT price(15.03);",
    1717              :                 "prinbee_exception: function-expression.pbql:1:14: unknown function PRICE().",
    1718              :             },
    1719              :             {
    1720              :                 "SELECT Random_Chart(15.03);",
    1721              :                 "prinbee_exception: function-expression.pbql:1:21: unknown function RANDOM_CHART().",
    1722              :             },
    1723              :             {
    1724              :                 "SELECT STRING(15.03);",
    1725              :                 "prinbee_exception: function-expression.pbql:1:15: unknown function STRING().",
    1726              :             },
    1727              :             {
    1728              :                 "SELECT ToDay(15.03);",
    1729              :                 "prinbee_exception: function-expression.pbql:1:14: unknown function TODAY().",
    1730              :             },
    1731              :             {
    1732              :                 "SELECT Orange(15.03);",
    1733              :                 "prinbee_exception: function-expression.pbql:1:15: unknown function ORANGE().",
    1734              :             },
    1735              :         };
    1736           15 :         for(auto const & e : function_expressions)
    1737              :         {
    1738           14 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1739           14 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_function, "function-expression.pbql"));
    1740           14 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1741              : 
    1742           42 :             CATCH_REQUIRE_THROWS_MATCHES(
    1743              :                       parser->parse()
    1744              :                     , prinbee::type_not_found
    1745              :                     , Catch::Matchers::ExceptionMessage(e.f_error_msg));
    1746           14 :         }
    1747              :     }
    1748           34 :     CATCH_END_SECTION()
    1749              : 
    1750           35 :     CATCH_START_SECTION("expression_error: cast() with missing closing parenthesis")
    1751              :     {
    1752            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1753            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT BIGINT(expression;", "postfix-expression.pbql"));
    1754            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1755              : 
    1756            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1757              :                   parser->parse()
    1758              :                 , prinbee::invalid_parameter
    1759              :                 , Catch::Matchers::ExceptionMessage(
    1760              :                           "prinbee_exception: postfix-expression.pbql:1:26: type casting used '(' so a ')' was expected to end the casting expression."));
    1761            1 :     }
    1762           34 :     CATCH_END_SECTION()
    1763              : 
    1764           35 :     CATCH_START_SECTION("expression_error: func() with missing closing parenthesis")
    1765              :     {
    1766            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1767            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT ABS(expression;", "postfix-expression.pbql"));
    1768            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1769              : 
    1770            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1771              :                   parser->parse()
    1772              :                 , prinbee::invalid_token
    1773              :                 , Catch::Matchers::ExceptionMessage(
    1774              :                           "prinbee_exception: postfix-expression.pbql:1:23: expected ')' to end the list of parameters in a function call; not ';'."));
    1775            1 :     }
    1776           34 :     CATCH_END_SECTION()
    1777              : 
    1778           35 :     CATCH_START_SECTION("expression_error: ABS(a, b) fails since it accepts only one parameter")
    1779              :     {
    1780            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1781            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT ABS(a, b);", "postfix-expression.pbql"));
    1782            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1783              : 
    1784            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1785              :                   parser->parse()
    1786              :                 , prinbee::invalid_parameter
    1787              :                 , Catch::Matchers::ExceptionMessage(
    1788              :                           "prinbee_exception: postfix-expression.pbql:1:17: ABS() expected 1 parameter, found 2 instead."));
    1789            1 :     }
    1790           34 :     CATCH_END_SECTION()
    1791              : 
    1792           35 :     CATCH_START_SECTION("expression_error: [NOT] IN not yet implemented")
    1793              :     {
    1794              :         {
    1795            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1796            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT a IN b;", "postfix-expression.pbql"));
    1797            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1798              : 
    1799            3 :             CATCH_REQUIRE_THROWS_MATCHES(
    1800              :                       parser->parse()
    1801              :                     , prinbee::not_yet_implemented
    1802              :                     , Catch::Matchers::ExceptionMessage(
    1803              :                               "not_yet_implemented: [NOT] IN is not yet implemented."));
    1804            1 :         }
    1805              : 
    1806              :         {
    1807            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1808            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT a NOT IN b;", "postfix-expression.pbql"));
    1809            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1810              : 
    1811            3 :             CATCH_REQUIRE_THROWS_MATCHES(
    1812              :                       parser->parse()
    1813              :                     , prinbee::not_yet_implemented
    1814              :                     , Catch::Matchers::ExceptionMessage(
    1815              :                               "not_yet_implemented: [NOT] IN is not yet implemented."));
    1816            1 :         }
    1817              :     }
    1818           34 :     CATCH_END_SECTION()
    1819              : 
    1820           35 :     CATCH_START_SECTION("expression_error: a NOT 3|b is not valid")
    1821              :     {
    1822              :         {
    1823            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1824            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT a NOT 3;", "matching-expression.pbql"));
    1825            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1826              : 
    1827            3 :             CATCH_REQUIRE_THROWS_MATCHES(
    1828              :                       parser->parse()
    1829              :                     , prinbee::invalid_token
    1830              :                     , Catch::Matchers::ExceptionMessage(
    1831              :                               "prinbee_exception: matching-expression.pbql:1:14: expected NOT to be followed by BETWEEN, IN, LIKE, ILIKE, or SIMILAR TO."));
    1832            1 :         }
    1833              : 
    1834              :         {
    1835            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1836            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT a NOT b;", "matching-expression.pbql"));
    1837            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1838              : 
    1839            3 :             CATCH_REQUIRE_THROWS_MATCHES(
    1840              :                       parser->parse()
    1841              :                     , prinbee::invalid_token
    1842              :                     , Catch::Matchers::ExceptionMessage(
    1843              :                               "prinbee_exception: matching-expression.pbql:1:14: expected NOT to be followed by BETWEEN, IN, LIKE, ILIKE, or SIMILAR TO."));
    1844            1 :         }
    1845              :     }
    1846           34 :     CATCH_END_SECTION()
    1847              : 
    1848           35 :     CATCH_START_SECTION("expression_error: BETWEEN missing AND")
    1849              :     {
    1850            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1851            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT a BETWEEN b c;", "matching-expression.pbql"));
    1852            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1853              : 
    1854            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1855              :                   parser->parse()
    1856              :                 , prinbee::invalid_token
    1857              :                 , Catch::Matchers::ExceptionMessage(
    1858              :                           "prinbee_exception: matching-expression.pbql:1:20: expected AND between the lower and higher bounds of [NOT] BETWEEN operator."));
    1859            1 :     }
    1860           34 :     CATCH_END_SECTION()
    1861              : 
    1862           35 :     CATCH_START_SECTION("expression_error: x IS <not identifier>")
    1863              :     {
    1864              :         struct function_t
    1865              :         {
    1866              :             char const *        f_is = nullptr;
    1867              :             char const *        f_error_msg = nullptr;
    1868              :         };
    1869            1 :         function_t const function_expressions[] =
    1870              :         {
    1871              :             {
    1872              :                 "SELECT 77 IS 33;",
    1873              :                 "prinbee_exception: is-expression.pbql:1:14: expected one of TRUE, FALSE, NULL or DISTINCT after IS, not INTEGER.",
    1874              :             },
    1875              :             {
    1876              :                 "SELECT 77 IS NOT 33;",
    1877              :                 "prinbee_exception: is-expression.pbql:1:18: expected one of TRUE, FALSE, NULL or DISTINCT after IS, not INTEGER.",
    1878              :             },
    1879              :             {
    1880              :                 "SELECT 77 IS 'string';",
    1881              :                 "prinbee_exception: is-expression.pbql:1:14: expected one of TRUE, FALSE, NULL or DISTINCT after IS, not STRING.",
    1882              :             },
    1883              :             {
    1884              :                 "SELECT 77 IS NOT 'string';",
    1885              :                 "prinbee_exception: is-expression.pbql:1:18: expected one of TRUE, FALSE, NULL or DISTINCT after IS, not STRING.",
    1886              :             },
    1887              :             {
    1888              :                 "SELECT 77 IS 701.394;",
    1889              :                 "prinbee_exception: is-expression.pbql:1:14: expected one of TRUE, FALSE, NULL or DISTINCT after IS, not FLOATING_POINT.",
    1890              :             },
    1891              :             {
    1892              :                 "SELECT 77 IS NOT 701.394;",
    1893              :                 "prinbee_exception: is-expression.pbql:1:18: expected one of TRUE, FALSE, NULL or DISTINCT after IS, not FLOATING_POINT.",
    1894              :             },
    1895              :         };
    1896            7 :         for(auto const & e : function_expressions)
    1897              :         {
    1898            6 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1899            6 :             lexer->set_input(std::make_shared<prinbee::pbql::input>(e.f_is, "is-expression.pbql"));
    1900            6 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1901              : 
    1902           12 : SNAP_LOG_WARNING << "parsing [" << e.f_is << "]" << SNAP_LOG_SEND;
    1903           18 :             CATCH_REQUIRE_THROWS_MATCHES(
    1904              :                       parser->parse()
    1905              :                     , prinbee::invalid_token
    1906              :                     , Catch::Matchers::ExceptionMessage(e.f_error_msg));
    1907            6 :         }
    1908              :     }
    1909           34 :     CATCH_END_SECTION()
    1910              : 
    1911           35 :     CATCH_START_SECTION("expression_error: x IS UNKNOWN")
    1912              :     {
    1913            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1914            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT x IS UNKNOWN;", "is-expression.pbql"));
    1915            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1916              : 
    1917            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1918              :                   parser->parse()
    1919              :                 , prinbee::invalid_token
    1920              :                 , Catch::Matchers::ExceptionMessage(
    1921              :                           "prinbee_exception: is-expression.pbql:1:13: expected one of TRUE, FALSE, NULL or DISTINCT after IS, not UNKNOWN."));
    1922            1 :     }
    1923           34 :     CATCH_END_SECTION()
    1924              : 
    1925           35 :     CATCH_START_SECTION("expression_error: x IS DISTINCT TO (a, b, c) instead of FROM")
    1926              :     {
    1927            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1928            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT x IS DISTINCT TO (a, b, c);", "is-expression.pbql"));
    1929            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1930              : 
    1931            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1932              :                   parser->parse()
    1933              :                 , prinbee::invalid_token
    1934              :                 , Catch::Matchers::ExceptionMessage(
    1935              :                           "prinbee_exception: is-expression.pbql:1:22: expected FROM after IS [NOT] DISTINCT."));
    1936            1 :     }
    1937           34 :     CATCH_END_SECTION()
    1938              : 
    1939           35 :     CATCH_START_SECTION("expression_error: x IS DISTINCT FROM (a, b, c) not yet implemented...")
    1940              :     {
    1941            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1942            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT x IS DISTINCT FROM (a, b, c);", "is-expression.pbql"));
    1943            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1944              : 
    1945            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1946              :                   parser->parse()
    1947              :                 , prinbee::not_yet_implemented
    1948              :                 , Catch::Matchers::ExceptionMessage(
    1949              :                           "not_yet_implemented: IS [NOT] DISTINCT FROM is not yet implemented."));
    1950            1 :     }
    1951           34 :     CATCH_END_SECTION()
    1952              : 
    1953           35 :     CATCH_START_SECTION("expression_error: empty string is not a number (5 + '')")
    1954              :     {
    1955            1 :         prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1956            1 :         lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT 5 + '';", "empty-string-expression.pbql"));
    1957            1 :         prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1958              : 
    1959            3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1960              :                   parser->parse()
    1961              :                 , prinbee::invalid_token
    1962              :                 , Catch::Matchers::ExceptionMessage(
    1963              :                           "prinbee_exception: empty-string-expression.pbql:1:15:"
    1964              :                           " the + and - binary operators expect numbers as input."));
    1965            1 :     }
    1966           34 :     CATCH_END_SECTION()
    1967              : 
    1968           35 :     CATCH_START_SECTION("expression_error: some strings are not numbers (+'str')")
    1969              :     {
    1970              :         {
    1971            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1972            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT + '';", "number-expression.pbql"));
    1973            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1974              : 
    1975            3 :             CATCH_REQUIRE_THROWS_MATCHES(
    1976              :                       parser->parse()
    1977              :                     , prinbee::invalid_token
    1978              :                     , Catch::Matchers::ExceptionMessage(
    1979              :                               "prinbee_exception: number-expression.pbql:1:13:"
    1980              :                               " string \"\" cannot be converted to a number."));
    1981            1 :         }
    1982              : 
    1983              :         {
    1984            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1985            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT + '55a';", "number-expression.pbql"));
    1986            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    1987              : 
    1988            3 :             CATCH_REQUIRE_THROWS_MATCHES(
    1989              :                       parser->parse()
    1990              :                     , prinbee::invalid_token
    1991              :                     , Catch::Matchers::ExceptionMessage(
    1992              :                               "prinbee_exception: number-expression.pbql:1:16:"
    1993              :                               " string \"55a\" cannot be converted to a number."));
    1994            1 :         }
    1995              : 
    1996              :         {
    1997            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    1998            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT + '+';", "number-expression.pbql"));
    1999            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    2000              : 
    2001            3 :             CATCH_REQUIRE_THROWS_MATCHES(
    2002              :                       parser->parse()
    2003              :                     , prinbee::invalid_token
    2004              :                     , Catch::Matchers::ExceptionMessage(
    2005              :                               "prinbee_exception: number-expression.pbql:1:14:"
    2006              :                               " string \"+\" cannot be converted to a number."));
    2007            1 :         }
    2008              : 
    2009              :         {
    2010            1 :             prinbee::pbql::lexer::pointer_t lexer(std::make_shared<prinbee::pbql::lexer>());
    2011            1 :             lexer->set_input(std::make_shared<prinbee::pbql::input>("SELECT + '-';", "number-expression.pbql"));
    2012            1 :             prinbee::pbql::parser::pointer_t parser(std::make_shared<prinbee::pbql::parser>(lexer));
    2013              : 
    2014            3 :             CATCH_REQUIRE_THROWS_MATCHES(
    2015              :                       parser->parse()
    2016              :                     , prinbee::invalid_token
    2017              :                     , Catch::Matchers::ExceptionMessage(
    2018              :                               "prinbee_exception: number-expression.pbql:1:14:"
    2019              :                               " string \"-\" cannot be converted to a number."));
    2020            1 :         }
    2021              :     }
    2022           34 :     CATCH_END_SECTION()
    2023           33 : }
    2024              : 
    2025              : 
    2026              : 
    2027              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions