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::__anon5b08a9160211::Interval_unit_validator501   Interval_unit_validator(const char* const error_msg)
502   : m_error_msg(error_msg)
503   {}
504 
operator ()xpl::__anon5b08a9160211::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::__anon5b08a9160211::Cast_type_validator541   Cast_type_validator(const char* const error_msg)
542   : m_error_msg(error_msg)
543   {}
544 
operator ()xpl::__anon5b08a9160211::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::__anon5b08a9160311::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