1 /*
2 * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2.0,
6 * as published by the Free Software Foundation.
7 *
8 * This program is also distributed with certain software (including
9 * but not limited to OpenSSL) that is licensed under separate terms,
10 * as designated in a particular file or component or in included license
11 * documentation. The authors of MySQL hereby grant you an additional
12 * permission to link the program and your derivative works with the
13 * separately licensed software that they have included with MySQL.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License, version 2.0, for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
26 #include "expr_generator.h"
27
28 #include <algorithm>
29 #include "json_utils.h"
30 #include "ngs_common/bind.h"
31 #include "ngs_common/to_string.h"
32 #include "xpl_error.h"
33 #include "xpl_regex.h"
34 #include "mysql_function_names.h"
35
36 namespace xpl
37 {
38
Error(int error_code,const std::string & message)39 Expression_generator::Error::Error(int error_code, const std::string& message)
40 : std::invalid_argument(message), m_error(error_code)
41 {}
42
43
generate(const Mysqlx::Expr::Expr & arg) const44 void Expression_generator::generate(const Mysqlx::Expr::Expr &arg) const
45 {
46 switch(arg.type())
47 {
48 case Mysqlx::Expr::Expr::IDENT:
49 generate(arg.identifier());
50 break;
51
52 case Mysqlx::Expr::Expr::LITERAL:
53 generate(arg.literal());
54 break;
55
56 case Mysqlx::Expr::Expr::VARIABLE:
57 //m_qb.put("@").quote_identifier(arg.variable());
58 //break;
59 throw Error(ER_X_EXPR_BAD_TYPE_VALUE,
60 "Mysqlx::Expr::Expr::VARIABLE is not supported yet");
61
62 case Mysqlx::Expr::Expr::FUNC_CALL:
63 generate(arg.function_call());
64 break;
65
66 case Mysqlx::Expr::Expr::OPERATOR:
67 generate(arg.operator_());
68 break;
69
70 case Mysqlx::Expr::Expr::PLACEHOLDER:
71 generate(arg.position());
72 break;
73
74 case Mysqlx::Expr::Expr::OBJECT:
75 generate(arg.object());
76 break;
77
78 case Mysqlx::Expr::Expr::ARRAY:
79 generate(arg.array());
80 break;
81
82 default:
83 throw Error(ER_X_EXPR_BAD_TYPE_VALUE,
84 "Invalid value for Mysqlx::Expr::Expr_Type "+ngs::to_string(arg.type()));
85 }
86 }
87
88
generate(const Mysqlx::Expr::Identifier & arg,bool is_function) const89 void Expression_generator::generate(const Mysqlx::Expr::Identifier& arg, bool is_function) const
90 {
91 if (!m_default_schema.empty() &&
92 (!arg.has_schema_name() || arg.schema_name().empty()))
93 {
94 // automatically prefix with the schema name
95 if (!is_function || !is_native_mysql_function(arg.name()))
96 m_qb.quote_identifier_if_needed(m_default_schema).dot();
97 }
98
99 if (arg.has_schema_name() && !arg.schema_name().empty())
100 m_qb.quote_identifier(arg.schema_name()).dot();
101
102 m_qb.quote_identifier_if_needed(arg.name());
103 }
104
105
generate(const Mysqlx::Expr::ColumnIdentifier & arg) const106 void Expression_generator::generate(const Mysqlx::Expr::ColumnIdentifier &arg) const
107 {
108 bool has_schema_name = arg.has_schema_name() && !arg.schema_name().empty();
109
110 if (has_schema_name && arg.has_table_name() == false)
111 throw Error(ER_X_EXPR_MISSING_ARG,
112 "Table name is required if schema name is specified in ColumnIdentifier.");
113
114 const bool has_docpath = arg.document_path_size() > 0;
115
116 if (arg.has_table_name() && arg.has_name() == false &&
117 (m_is_relational || !has_docpath))
118 throw Error(ER_X_EXPR_MISSING_ARG,
119 "Column name is required if table name is specified in ColumnIdentifier.");
120
121 if (has_docpath)
122 m_qb.put("JSON_EXTRACT(");
123
124 if (has_schema_name)
125 m_qb.quote_identifier(arg.schema_name()).dot();
126
127 if (arg.has_table_name())
128 m_qb.quote_identifier(arg.table_name()).dot();
129
130 if (arg.has_name())
131 m_qb.quote_identifier(arg.name());
132
133 if (has_docpath)
134 {
135 if(arg.has_name() == false)
136 m_qb.put("doc");
137
138 m_qb.put(",");
139 generate(arg.document_path());
140 m_qb.put(")");
141 }
142 }
143
144
generate(const Document_path & arg) const145 void Expression_generator::generate(const Document_path &arg) const
146 {
147 using ::Mysqlx::Expr::DocumentPathItem;
148
149 if (arg.size() == 1 &&
150 arg.Get(0).type() == DocumentPathItem::MEMBER &&
151 arg.Get(0).value().empty())
152 {
153 m_qb.quote_string("$");
154 return;
155 }
156
157 m_qb.bquote().put("$");
158 for (Document_path::const_iterator item = arg.begin(); item != arg.end(); ++item)
159 {
160 switch (item->type())
161 {
162 case DocumentPathItem::MEMBER:
163 if (item->value().empty())
164 throw Error(ER_X_EXPR_BAD_VALUE,
165 "Invalid empty value for Mysqlx::Expr::DocumentPathItem::MEMBER");
166 m_qb.dot().put(quote_json_if_needed(item->value()));
167 break;
168 case DocumentPathItem::MEMBER_ASTERISK:
169 m_qb.put(".*");
170 break;
171 case DocumentPathItem::ARRAY_INDEX:
172 m_qb.put("[").put(item->index()).put("]");
173 break;
174 case DocumentPathItem::ARRAY_INDEX_ASTERISK:
175 m_qb.put("[*]");
176 break;
177 case DocumentPathItem::DOUBLE_ASTERISK:
178 m_qb.put("**");
179 break;
180 default:
181 throw Error(ER_X_EXPR_BAD_TYPE_VALUE,
182 "Invalid value for Mysqlx::Expr::DocumentPathItem::Type " +
183 ngs::to_string(item->type()));
184 }
185 }
186 m_qb.equote();
187 }
188
189
generate(const Mysqlx::Expr::FunctionCall & arg) const190 void Expression_generator::generate(const Mysqlx::Expr::FunctionCall &arg) const
191 {
192 generate(arg.name(), true);
193 m_qb.put("(");
194 generate_for_each(arg.param(), &Expression_generator::generate_unquote_param);
195 m_qb.put(")");
196 }
197
198
generate(const Mysqlx::Datatypes::Any & arg) const199 void Expression_generator::generate(const Mysqlx::Datatypes::Any &arg) const
200 {
201 switch(arg.type())
202 {
203 case Mysqlx::Datatypes::Any::SCALAR:
204 generate(arg.scalar());
205 break;
206 default:
207 throw Error(ER_X_EXPR_BAD_TYPE_VALUE,
208 "Invalid value for Mysqlx::Datatypes::Any::Type " +
209 ngs::to_string(arg.type()));
210 }
211 }
212
213
generate(const Mysqlx::Datatypes::Scalar & arg) const214 void Expression_generator::generate(const Mysqlx::Datatypes::Scalar &arg) const
215 {
216 switch(arg.type())
217 {
218 case Mysqlx::Datatypes::Scalar::V_UINT:
219 m_qb.put(arg.v_unsigned_int());
220 break;
221
222 case Mysqlx::Datatypes::Scalar::V_SINT:
223 m_qb.put(arg.v_signed_int());
224 break;
225
226 case Mysqlx::Datatypes::Scalar::V_NULL:
227 m_qb.put("NULL");
228 break;
229
230 case Mysqlx::Datatypes::Scalar::V_OCTETS:
231 generate(arg.v_octets());
232 break;
233
234 case Mysqlx::Datatypes::Scalar::V_STRING:
235 if (arg.v_string().has_collation())
236 {
237 //TODO handle _utf8'string' type charset specification... but 1st validate charset for alnum_
238 //m_qb.put("_").put(arg.v_string().charset());
239 }
240 m_qb.quote_string(arg.v_string().value());
241 break;
242
243 case Mysqlx::Datatypes::Scalar::V_DOUBLE:
244 m_qb.put(arg.v_double());
245 break;
246
247 case Mysqlx::Datatypes::Scalar::V_FLOAT:
248 m_qb.put(arg.v_float());
249 break;
250
251 case Mysqlx::Datatypes::Scalar::V_BOOL:
252 m_qb.put((arg.v_bool() ? "TRUE" : "FALSE"));
253 break;
254
255 default:
256 throw Error(ER_X_EXPR_BAD_TYPE_VALUE,
257 "Invalid value for Mysqlx::Datatypes::Scalar::Type " +
258 ngs::to_string(arg.type()));
259 }
260 }
261
262
generate(const Mysqlx::Datatypes::Scalar::Octets & arg) const263 void Expression_generator::generate(const Mysqlx::Datatypes::Scalar::Octets &arg) const
264 {
265 switch (arg.content_type())
266 {
267 case CT_PLAIN:
268 m_qb.quote_string(arg.value());
269 break;
270
271 case CT_GEOMETRY:
272 m_qb.put("ST_GEOMETRYFROMWKB(").quote_string(arg.value()).put(")");
273 break;
274
275 case CT_JSON:
276 m_qb.put("CAST(").quote_string(arg.value()).put(" AS JSON)");
277 break;
278
279 case CT_XML:
280 m_qb.quote_string(arg.value());
281 break;
282
283 default:
284 throw Error(ER_X_EXPR_BAD_TYPE_VALUE,
285 "Invalid content type for Mysqlx::Datatypes::Scalar::Octets " +
286 ngs::to_string(arg.content_type()));
287 }
288 }
289
290
generate(const Placeholder & arg) const291 void Expression_generator::generate(const Placeholder &arg) const
292 {
293 if (arg < static_cast<Placeholder>(m_args.size()))
294 generate(m_args.Get(arg));
295 else
296 throw Error(ER_X_EXPR_BAD_VALUE, "Invalid value of placeholder");
297 }
298
299
generate(const Mysqlx::Expr::Object & arg) const300 void Expression_generator::generate(const Mysqlx::Expr::Object &arg) const
301 {
302 m_qb.put("JSON_OBJECT(");
303 generate_for_each(arg.fld(), &Expression_generator::generate);
304 m_qb.put(")");
305 }
306
307
generate(const Mysqlx::Expr::Object::ObjectField & arg) const308 void Expression_generator::generate(const Mysqlx::Expr::Object::ObjectField &arg) const
309 {
310 if (!arg.has_key() || arg.key().empty())
311 throw Error(ER_X_EXPR_BAD_VALUE, "Invalid key for Mysqlx::Expr::Object");
312 if (!arg.has_value())
313 throw Error(ER_X_EXPR_BAD_VALUE, "Invalid value for Mysqlx::Expr::Object on key '" + arg.key() + "'");
314 m_qb.quote_string(arg.key()).put(",");
315 generate(arg.value());
316 }
317
318
generate(const Mysqlx::Expr::Array & arg) const319 void Expression_generator::generate(const Mysqlx::Expr::Array &arg) const
320 {
321 m_qb.put("JSON_ARRAY(");
322 generate_for_each(arg.value(), &Expression_generator::generate);
323 m_qb.put(")");
324 }
325
326
327 template <typename T>
generate_for_each(const::google::protobuf::RepeatedPtrField<T> & list,void (Expression_generator::* generate_fun)(const T &)const,const typename::google::protobuf::RepeatedPtrField<T>::size_type offset) const328 void Expression_generator::generate_for_each(const ::google::protobuf::RepeatedPtrField<T> &list,
329 void (Expression_generator::*generate_fun)(const T&) const,
330 const typename ::google::protobuf::RepeatedPtrField<T>::size_type offset) const
331 {
332 if (list.size() == 0)
333 return;
334 typedef typename ::google::protobuf::RepeatedPtrField<T>::const_iterator It;
335 It end = list.end() - 1;
336 for (It i = list.begin() + offset; i != end; ++i)
337 {
338 (this->*generate_fun)(*i);
339 m_qb.put(",");
340 }
341 (this->*generate_fun)(*end);
342 }
343
344
generate_unquote_param(const Mysqlx::Expr::Expr & arg) const345 void Expression_generator::generate_unquote_param(const Mysqlx::Expr::Expr &arg) const
346 {
347 if (arg.type() == Mysqlx::Expr::Expr::IDENT && arg.identifier().document_path_size() > 0)
348 {
349 m_qb.put("JSON_UNQUOTE(");
350 generate(arg);
351 m_qb.put(")");
352 }
353 else
354 generate(arg);
355 }
356
357
binary_operator(const Mysqlx::Expr::Operator & arg,const char * str) const358 void Expression_generator::binary_operator(const Mysqlx::Expr::Operator &arg, const char* str) const
359 {
360 if(arg.param_size() != 2)
361 {
362 throw Error(ER_X_EXPR_BAD_NUM_ARGS,
363 "Binary operations require exactly two operands in expression.");
364 }
365
366 m_qb.put("(");
367 generate(arg.param(0));
368 m_qb.put(str);
369 generate(arg.param(1));
370 m_qb.put(")");
371 }
372
373
unary_operator(const Mysqlx::Expr::Operator & arg,const char * str) const374 void Expression_generator::unary_operator(const Mysqlx::Expr::Operator &arg, const char* str) const
375 {
376 if(arg.param_size() != 1)
377 {
378 throw Error(ER_X_EXPR_BAD_NUM_ARGS,
379 "Unary operations require exactly one operand in expression.");
380 }
381
382 m_qb.put("(").put(str);
383 generate(arg.param(0));
384 m_qb.put(")");
385 }
386
387
388 namespace
389 {
390
is_array(const Mysqlx::Expr::Expr & arg)391 inline bool is_array(const Mysqlx::Expr::Expr &arg)
392 {
393 return arg.type() == Mysqlx::Expr::Expr_Type_ARRAY;
394 }
395
396
is_octets(const Mysqlx::Expr::Expr & arg)397 inline bool is_octets(const Mysqlx::Expr::Expr &arg)
398 {
399 return arg.type() == Mysqlx::Expr::Expr_Type_LITERAL &&
400 arg.literal().type() == Mysqlx::Datatypes::Scalar_Type_V_OCTETS &&
401 arg.literal().has_v_octets();
402 }
403
404
is_plain_octets(const Mysqlx::Expr::Expr & arg)405 inline bool is_plain_octets(const Mysqlx::Expr::Expr &arg)
406 {
407 return is_octets(arg) &&
408 arg.literal().v_octets().content_type() == Expression_generator::CT_PLAIN;
409 }
410
411 } // namespace
412
413
in_expression(const Mysqlx::Expr::Operator & arg,const char * str) const414 void Expression_generator::in_expression(const Mysqlx::Expr::Operator &arg, const char *str) const
415 {
416 switch (arg.param_size())
417 {
418 case 0:
419 case 1:
420 throw Error(ER_X_EXPR_BAD_NUM_ARGS,
421 "IN expression requires at least two parameters.");
422
423 case 2:
424 if (is_array(arg.param(1)))
425 {
426 m_qb.put(str).put("JSON_CONTAINS(");
427 generate(arg.param(1));
428 m_qb.put(",");
429 if (is_octets(arg.param(0)))
430 {
431 m_qb.put("JSON_QUOTE(");
432 generate(arg.param(0));
433 m_qb.put("))");
434 }
435 else
436 {
437 m_qb.put("CAST(");
438 generate(arg.param(0));
439 m_qb.put(" AS JSON))");
440 }
441 break;
442 }
443 // Fall through.
444
445 default:
446 m_qb.put("(");
447 generate_unquote_param(arg.param(0));
448 m_qb.put(" ").put(str).put("IN (");
449 generate_for_each(arg.param(), &Expression_generator::generate_unquote_param, 1);
450 m_qb.put("))");
451 }
452 }
453
454
like_expression(const Mysqlx::Expr::Operator & arg,const char * str) const455 void Expression_generator::like_expression(const Mysqlx::Expr::Operator &arg, const char *str) const
456 {
457 int paramSize = arg.param_size();
458
459 if(paramSize != 2 && paramSize != 3)
460 {
461 throw Error(ER_X_EXPR_BAD_NUM_ARGS,
462 "LIKE expression requires exactly two or three parameters.");
463 }
464
465 m_qb.put("(");
466 generate_unquote_param(arg.param(0));
467 m_qb.put(str);
468 generate_unquote_param(arg.param(1));
469 if(paramSize == 3)
470 {
471 m_qb.put(" ESCAPE ");
472 generate_unquote_param(arg.param(2));
473 }
474 m_qb.put(")");
475 }
476
477
between_expression(const Mysqlx::Expr::Operator & arg,const char * str) const478 void Expression_generator::between_expression(const Mysqlx::Expr::Operator &arg, const char *str) const
479 {
480 if(arg.param_size() != 3)
481 {
482 throw Error(ER_X_EXPR_BAD_NUM_ARGS,
483 "BETWEEN expression requires exactly three parameters.");
484 }
485
486 m_qb.put("(");
487 generate_unquote_param(arg.param(0));
488 m_qb.put(str);
489 generate_unquote_param(arg.param(1));
490 m_qb.put(" AND ");
491 generate_unquote_param(arg.param(2));
492 m_qb.put(")");
493 }
494
495
496 namespace
497 {
498
499 struct Interval_unit_validator
500 {
Interval_unit_validatorxpl::__anon5fd6582e0211::Interval_unit_validator501 Interval_unit_validator(const char* const error_msg)
502 : m_error_msg(error_msg)
503 {}
504
operator ()xpl::__anon5fd6582e0211::Interval_unit_validator505 bool operator() (const char* source) const
506 {
507 // keep patterns in asc order
508 static const char* const patterns[] = {
509 "DAY",
510 "DAY_HOUR",
511 "DAY_MICROSECOND",
512 "DAY_MINUTE",
513 "DAY_SECOND",
514 "HOUR",
515 "HOUR_MICROSECOND",
516 "HOUR_MINUTE",
517 "HOUR_SECOND",
518 "MICROSECOND",
519 "MINUTE",
520 "MINUTE_MICROSECOND",
521 "MINUTE_SECOND",
522 "MONTH",
523 "QUARTER",
524 "SECOND",
525 "SECOND_MICROSECOND",
526 "WEEK",
527 "YEAR",
528 "YEAR_MONTH"
529 };
530 static const char* const *patterns_end = get_array_end(patterns);
531
532 return std::binary_search(patterns, patterns_end, source, Is_less());
533 }
534
535 const char* const m_error_msg;
536 };
537
538
539 struct Cast_type_validator
540 {
Cast_type_validatorxpl::__anon5fd6582e0211::Cast_type_validator541 Cast_type_validator(const char* const error_msg)
542 : m_error_msg(error_msg)
543 {}
544
operator ()xpl::__anon5fd6582e0211::Cast_type_validator545 bool operator() (const char* str) const
546 {
547 static const xpl::Regex re(
548 "^("
549 "BINARY([[.left-parenthesis.]][[:digit:]]+[[.right-parenthesis.]])?|"
550 "DATE|DATETIME|TIME|JSON|"
551 "CHAR([[.left-parenthesis.]][[:digit:]]+[[.right-parenthesis.]])?|"
552 "DECIMAL([[.left-parenthesis.]][[:digit:]]+(,[[:digit:]]+)?[[.right-parenthesis.]])?|"
553 "SIGNED( INTEGER)?|UNSIGNED( INTEGER)?"
554 "){1}$");
555
556 return re.match(str);
557 }
558
559 const char* const m_error_msg;
560 };
561
562
563 template<typename V>
get_valid_string(const Expression_generator::Expr & expr,const V & is_valid)564 const std::string& get_valid_string(const Expression_generator::Expr &expr, const V& is_valid)
565 {
566 if (!is_plain_octets(expr) || !is_valid(expr.literal().v_octets().value().c_str()))
567 throw Expression_generator::Error(ER_X_EXPR_BAD_VALUE, is_valid.m_error_msg);
568
569 return expr.literal().v_octets().value();
570 }
571
572 } // namespace
573
574
date_expression(const Mysqlx::Expr::Operator & arg,const char * str) const575 void Expression_generator::date_expression(const Mysqlx::Expr::Operator &arg, const char* str) const
576 {
577 if(arg.param_size() != 3)
578 throw Error(ER_X_EXPR_BAD_NUM_ARGS,
579 "DATE expression requires exactly three parameters.");
580
581 m_qb.put(str).put("(");
582 generate_unquote_param(arg.param(0));
583 m_qb.put(", INTERVAL ");
584 generate_unquote_param(arg.param(1));
585 m_qb.put(" ");
586 m_qb.put(get_valid_string(arg.param(2),
587 Interval_unit_validator("DATE interval unit invalid.")));
588 m_qb.put(")");
589 }
590
591
cast_expression(const Mysqlx::Expr::Operator & arg) const592 void Expression_generator::cast_expression(const Mysqlx::Expr::Operator &arg) const
593 {
594 if(arg.param_size() != 2)
595 throw Error(ER_X_EXPR_BAD_NUM_ARGS,
596 "CAST expression requires exactly two parameters.");
597
598 m_qb.put("CAST(");
599 generate_unquote_param(arg.param(0));
600 m_qb.put(" AS ");
601 m_qb.put(get_valid_string(arg.param(1),
602 Cast_type_validator("CAST type invalid.")));
603 m_qb.put(")");
604 }
605
606
binary_expression(const Mysqlx::Expr::Operator & arg,const char * str) const607 void Expression_generator::binary_expression(const Mysqlx::Expr::Operator &arg, const char* str) const
608 {
609 if(arg.param_size() != 2)
610 {
611 throw Error(ER_X_EXPR_BAD_NUM_ARGS,
612 "Binary operations require exactly two operands in expression.");
613 }
614
615 m_qb.put("(");
616 generate_unquote_param(arg.param(0));
617 m_qb.put(str);
618 generate_unquote_param(arg.param(1));
619 m_qb.put(")");
620 }
621
622
623 namespace
624 {
625 typedef ngs::function<void (const Expression_generator*,
626 const Mysqlx::Expr::Operator&)> Operator_ptr;
627
628 typedef std::pair<const char* const, Operator_ptr> Operator_bind;
629
630 struct Is_operator_less
631 {
operator ()xpl::__anon5fd6582e0311::Is_operator_less632 bool operator() (const Operator_bind& pattern, const std::string& value) const
633 {
634 return std::strcmp(pattern.first, value.c_str()) < 0;
635 }
636 };
637
638 } // namespace
639
640
generate(const Mysqlx::Expr::Operator & arg) const641 void Expression_generator::generate(const Mysqlx::Expr::Operator &arg) const
642 {
643 // keep binding in asc order
644 static const Operator_bind operators[] = {
645 std::make_pair("!", ngs::bind(&Expression_generator::unary_operator, ngs::placeholders::_1, ngs::placeholders::_2, "!")),
646 std::make_pair("!=", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " != ")),
647 std::make_pair("%", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " % ")),
648 std::make_pair("&", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " & ")),
649 std::make_pair("&&", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " AND ")),
650 std::make_pair("*", ngs::bind(&Expression_generator::asterisk_operator, ngs::placeholders::_1, ngs::placeholders::_2)),
651 std::make_pair("+", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " + ")),
652 std::make_pair("-", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " - ")),
653 std::make_pair("/", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " / ")),
654 std::make_pair("<", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " < ")),
655 std::make_pair("<<", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " << ")),
656 std::make_pair("<=", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " <= ")),
657 std::make_pair("==", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " = ")),
658 std::make_pair(">", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " > ")),
659 std::make_pair(">=", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " >= ")),
660 std::make_pair(">>", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " >> ")),
661 std::make_pair("^", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " ^ ")),
662 std::make_pair("between", ngs::bind(&Expression_generator::between_expression, ngs::placeholders::_1, ngs::placeholders::_2, " BETWEEN ")),
663 std::make_pair("cast", ngs::bind(&Expression_generator::cast_expression, ngs::placeholders::_1, ngs::placeholders::_2)),
664 std::make_pair("date_add", ngs::bind(&Expression_generator::date_expression, ngs::placeholders::_1, ngs::placeholders::_2, "DATE_ADD")),
665 std::make_pair("date_sub", ngs::bind(&Expression_generator::date_expression, ngs::placeholders::_1, ngs::placeholders::_2, "DATE_SUB")),
666 std::make_pair("default", ngs::bind(&Expression_generator::nullary_operator, ngs::placeholders::_1, ngs::placeholders::_2, "DEFAULT")),
667 std::make_pair("div", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " DIV ")),
668 std::make_pair("in", ngs::bind(&Expression_generator::in_expression, ngs::placeholders::_1, ngs::placeholders::_2, "")),
669 std::make_pair("is", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " IS ")),
670 std::make_pair("is_not", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " IS NOT ")),
671 std::make_pair("like", ngs::bind(&Expression_generator::like_expression, ngs::placeholders::_1, ngs::placeholders::_2, " LIKE ")),
672 std::make_pair("not", ngs::bind(&Expression_generator::unary_operator, ngs::placeholders::_1, ngs::placeholders::_2, "NOT ")),
673 std::make_pair("not_between", ngs::bind(&Expression_generator::between_expression, ngs::placeholders::_1, ngs::placeholders::_2, " NOT BETWEEN ")),
674 std::make_pair("not_in", ngs::bind(&Expression_generator::in_expression, ngs::placeholders::_1, ngs::placeholders::_2, "NOT ")),
675 std::make_pair("not_like", ngs::bind(&Expression_generator::like_expression, ngs::placeholders::_1, ngs::placeholders::_2, " NOT LIKE ")),
676 std::make_pair("not_regexp", ngs::bind(&Expression_generator::binary_expression, ngs::placeholders::_1, ngs::placeholders::_2, " NOT REGEXP ")),
677 std::make_pair("regexp", ngs::bind(&Expression_generator::binary_expression, ngs::placeholders::_1, ngs::placeholders::_2, " REGEXP ")),
678 std::make_pair("sign_minus", ngs::bind(&Expression_generator::unary_operator, ngs::placeholders::_1, ngs::placeholders::_2, "-")),
679 std::make_pair("sign_plus", ngs::bind(&Expression_generator::unary_operator, ngs::placeholders::_1, ngs::placeholders::_2, "+")),
680 std::make_pair("xor",ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " XOR ")),
681 std::make_pair("|", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " | ")),
682 std::make_pair("||", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " OR ")),
683 std::make_pair("~", ngs::bind(&Expression_generator::unary_operator, ngs::placeholders::_1, ngs::placeholders::_2, "~"))
684 };
685 static const Operator_bind *operators_end = get_array_end(operators);
686
687 const Operator_bind *op = std::lower_bound(operators, operators_end,
688 arg.name(), Is_operator_less());
689
690 if (op == operators_end || std::strcmp(arg.name().c_str(), op->first) != 0)
691 throw Error(ER_X_EXPR_BAD_OPERATOR, "Invalid operator " + arg.name());
692
693 op->second(this, arg);
694 }
695
696
asterisk_operator(const Mysqlx::Expr::Operator & arg) const697 void Expression_generator::asterisk_operator(const Mysqlx::Expr::Operator &arg) const
698 {
699 switch (arg.param_size())
700 {
701 case 0:
702 m_qb.put("*");
703 break;
704
705 case 2:
706 m_qb.put("(");
707 generate_unquote_param(arg.param(0));
708 m_qb.put(" * ");
709 generate_unquote_param(arg.param(1));
710 m_qb.put(")");
711 break;
712
713 default:
714 throw Error(ER_X_EXPR_BAD_NUM_ARGS,
715 "Asterisk operator require zero or two operands in expression");
716 }
717 }
718
nullary_operator(const Mysqlx::Expr::Operator & arg,const char * str) const719 void Expression_generator::nullary_operator(const Mysqlx::Expr::Operator &arg, const char* str) const
720 {
721 if (arg.param_size() != 0)
722 throw Error(ER_X_EXPR_BAD_NUM_ARGS,
723 "Nullary operator require no operands in expression");
724
725 m_qb.put(str);
726 }
727
clone(Query_string_builder & qb) const728 Expression_generator Expression_generator::clone(Query_string_builder &qb) const
729 {
730 return Expression_generator(qb, m_args, m_default_schema, m_is_relational);
731 }
732
733 } // namespace xpl
734