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
|