Server IP : 172.67.216.182 / Your IP : 108.162.226.253 Web Server : Apache System : Linux krdc-ubuntu-s-2vcpu-4gb-amd-blr1-01.localdomain 5.15.0-142-generic #152-Ubuntu SMP Mon May 19 10:54:31 UTC 2025 x86_64 User : www ( 1000) PHP Version : 7.4.33 Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /www/server/mysql/src/rapid/plugin/x/src/ |
Upload File : |
/* * Copyright (c) 2015, 2023, Oracle and/or its affiliates. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2.0, * as published by the Free Software Foundation. * * This program is also distributed with certain software (including * but not limited to OpenSSL) that is licensed under separate terms, * as designated in a particular file or component or in included license * documentation. The authors of MySQL hereby grant you an additional * permission to link the program and your derivative works with the * separately licensed software that they have included with MySQL. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License, version 2.0, for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ #include "expr_generator.h" #include <algorithm> #include "json_utils.h" #include "ngs_common/bind.h" #include "ngs_common/to_string.h" #include "xpl_error.h" #include "xpl_regex.h" #include "mysql_function_names.h" namespace xpl { Expression_generator::Error::Error(int error_code, const std::string& message) : std::invalid_argument(message), m_error(error_code) {} void Expression_generator::generate(const Mysqlx::Expr::Expr &arg) const { switch(arg.type()) { case Mysqlx::Expr::Expr::IDENT: generate(arg.identifier()); break; case Mysqlx::Expr::Expr::LITERAL: generate(arg.literal()); break; case Mysqlx::Expr::Expr::VARIABLE: //m_qb.put("@").quote_identifier(arg.variable()); //break; throw Error(ER_X_EXPR_BAD_TYPE_VALUE, "Mysqlx::Expr::Expr::VARIABLE is not supported yet"); case Mysqlx::Expr::Expr::FUNC_CALL: generate(arg.function_call()); break; case Mysqlx::Expr::Expr::OPERATOR: generate(arg.operator_()); break; case Mysqlx::Expr::Expr::PLACEHOLDER: generate(arg.position()); break; case Mysqlx::Expr::Expr::OBJECT: generate(arg.object()); break; case Mysqlx::Expr::Expr::ARRAY: generate(arg.array()); break; default: throw Error(ER_X_EXPR_BAD_TYPE_VALUE, "Invalid value for Mysqlx::Expr::Expr_Type "+ngs::to_string(arg.type())); } } void Expression_generator::generate(const Mysqlx::Expr::Identifier& arg, bool is_function) const { if (!m_default_schema.empty() && (!arg.has_schema_name() || arg.schema_name().empty())) { // automatically prefix with the schema name if (!is_function || !is_native_mysql_function(arg.name())) m_qb.quote_identifier_if_needed(m_default_schema).dot(); } if (arg.has_schema_name() && !arg.schema_name().empty()) m_qb.quote_identifier(arg.schema_name()).dot(); m_qb.quote_identifier_if_needed(arg.name()); } void Expression_generator::generate(const Mysqlx::Expr::ColumnIdentifier &arg) const { bool has_schema_name = arg.has_schema_name() && !arg.schema_name().empty(); if (has_schema_name && arg.has_table_name() == false) throw Error(ER_X_EXPR_MISSING_ARG, "Table name is required if schema name is specified in ColumnIdentifier."); const bool has_docpath = arg.document_path_size() > 0; if (arg.has_table_name() && arg.has_name() == false && (m_is_relational || !has_docpath)) throw Error(ER_X_EXPR_MISSING_ARG, "Column name is required if table name is specified in ColumnIdentifier."); if (has_docpath) m_qb.put("JSON_EXTRACT("); if (has_schema_name) m_qb.quote_identifier(arg.schema_name()).dot(); if (arg.has_table_name()) m_qb.quote_identifier(arg.table_name()).dot(); if (arg.has_name()) m_qb.quote_identifier(arg.name()); if (has_docpath) { if(arg.has_name() == false) m_qb.put("doc"); m_qb.put(","); generate(arg.document_path()); m_qb.put(")"); } } void Expression_generator::generate(const Document_path &arg) const { using ::Mysqlx::Expr::DocumentPathItem; if (arg.size() == 1 && arg.Get(0).type() == DocumentPathItem::MEMBER && arg.Get(0).value().empty()) { m_qb.quote_string("$"); return; } m_qb.bquote().put("$"); for (Document_path::const_iterator item = arg.begin(); item != arg.end(); ++item) { switch (item->type()) { case DocumentPathItem::MEMBER: if (item->value().empty()) throw Error(ER_X_EXPR_BAD_VALUE, "Invalid empty value for Mysqlx::Expr::DocumentPathItem::MEMBER"); m_qb.dot().put(quote_json_if_needed(item->value())); break; case DocumentPathItem::MEMBER_ASTERISK: m_qb.put(".*"); break; case DocumentPathItem::ARRAY_INDEX: m_qb.put("[").put(item->index()).put("]"); break; case DocumentPathItem::ARRAY_INDEX_ASTERISK: m_qb.put("[*]"); break; case DocumentPathItem::DOUBLE_ASTERISK: m_qb.put("**"); break; default: throw Error(ER_X_EXPR_BAD_TYPE_VALUE, "Invalid value for Mysqlx::Expr::DocumentPathItem::Type " + ngs::to_string(item->type())); } } m_qb.equote(); } void Expression_generator::generate(const Mysqlx::Expr::FunctionCall &arg) const { generate(arg.name(), true); m_qb.put("("); generate_for_each(arg.param(), &Expression_generator::generate_unquote_param); m_qb.put(")"); } void Expression_generator::generate(const Mysqlx::Datatypes::Any &arg) const { switch(arg.type()) { case Mysqlx::Datatypes::Any::SCALAR: generate(arg.scalar()); break; default: throw Error(ER_X_EXPR_BAD_TYPE_VALUE, "Invalid value for Mysqlx::Datatypes::Any::Type " + ngs::to_string(arg.type())); } } void Expression_generator::generate(const Mysqlx::Datatypes::Scalar &arg) const { switch(arg.type()) { case Mysqlx::Datatypes::Scalar::V_UINT: m_qb.put(arg.v_unsigned_int()); break; case Mysqlx::Datatypes::Scalar::V_SINT: m_qb.put(arg.v_signed_int()); break; case Mysqlx::Datatypes::Scalar::V_NULL: m_qb.put("NULL"); break; case Mysqlx::Datatypes::Scalar::V_OCTETS: generate(arg.v_octets()); break; case Mysqlx::Datatypes::Scalar::V_STRING: if (arg.v_string().has_collation()) { //TODO handle _utf8'string' type charset specification... but 1st validate charset for alnum_ //m_qb.put("_").put(arg.v_string().charset()); } m_qb.quote_string(arg.v_string().value()); break; case Mysqlx::Datatypes::Scalar::V_DOUBLE: m_qb.put(arg.v_double()); break; case Mysqlx::Datatypes::Scalar::V_FLOAT: m_qb.put(arg.v_float()); break; case Mysqlx::Datatypes::Scalar::V_BOOL: m_qb.put((arg.v_bool() ? "TRUE" : "FALSE")); break; default: throw Error(ER_X_EXPR_BAD_TYPE_VALUE, "Invalid value for Mysqlx::Datatypes::Scalar::Type " + ngs::to_string(arg.type())); } } void Expression_generator::generate(const Mysqlx::Datatypes::Scalar::Octets &arg) const { switch (arg.content_type()) { case CT_PLAIN: m_qb.quote_string(arg.value()); break; case CT_GEOMETRY: m_qb.put("ST_GEOMETRYFROMWKB(").quote_string(arg.value()).put(")"); break; case CT_JSON: m_qb.put("CAST(").quote_string(arg.value()).put(" AS JSON)"); break; case CT_XML: m_qb.quote_string(arg.value()); break; default: throw Error(ER_X_EXPR_BAD_TYPE_VALUE, "Invalid content type for Mysqlx::Datatypes::Scalar::Octets " + ngs::to_string(arg.content_type())); } } void Expression_generator::generate(const Placeholder &arg) const { if (arg < static_cast<Placeholder>(m_args.size())) generate(m_args.Get(arg)); else throw Error(ER_X_EXPR_BAD_VALUE, "Invalid value of placeholder"); } void Expression_generator::generate(const Mysqlx::Expr::Object &arg) const { m_qb.put("JSON_OBJECT("); generate_for_each(arg.fld(), &Expression_generator::generate); m_qb.put(")"); } void Expression_generator::generate(const Mysqlx::Expr::Object::ObjectField &arg) const { if (!arg.has_key() || arg.key().empty()) throw Error(ER_X_EXPR_BAD_VALUE, "Invalid key for Mysqlx::Expr::Object"); if (!arg.has_value()) throw Error(ER_X_EXPR_BAD_VALUE, "Invalid value for Mysqlx::Expr::Object on key '" + arg.key() + "'"); m_qb.quote_string(arg.key()).put(","); generate(arg.value()); } void Expression_generator::generate(const Mysqlx::Expr::Array &arg) const { m_qb.put("JSON_ARRAY("); generate_for_each(arg.value(), &Expression_generator::generate); m_qb.put(")"); } template <typename T> void Expression_generator::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) const { if (list.size() == 0) return; typedef typename ::google::protobuf::RepeatedPtrField<T>::const_iterator It; It end = list.end() - 1; for (It i = list.begin() + offset; i != end; ++i) { (this->*generate_fun)(*i); m_qb.put(","); } (this->*generate_fun)(*end); } void Expression_generator::generate_unquote_param(const Mysqlx::Expr::Expr &arg) const { if (arg.type() == Mysqlx::Expr::Expr::IDENT && arg.identifier().document_path_size() > 0) { m_qb.put("JSON_UNQUOTE("); generate(arg); m_qb.put(")"); } else generate(arg); } void Expression_generator::binary_operator(const Mysqlx::Expr::Operator &arg, const char* str) const { if(arg.param_size() != 2) { throw Error(ER_X_EXPR_BAD_NUM_ARGS, "Binary operations require exactly two operands in expression."); } m_qb.put("("); generate(arg.param(0)); m_qb.put(str); generate(arg.param(1)); m_qb.put(")"); } void Expression_generator::unary_operator(const Mysqlx::Expr::Operator &arg, const char* str) const { if(arg.param_size() != 1) { throw Error(ER_X_EXPR_BAD_NUM_ARGS, "Unary operations require exactly one operand in expression."); } m_qb.put("(").put(str); generate(arg.param(0)); m_qb.put(")"); } namespace { inline bool is_array(const Mysqlx::Expr::Expr &arg) { return arg.type() == Mysqlx::Expr::Expr_Type_ARRAY; } inline bool is_octets(const Mysqlx::Expr::Expr &arg) { return arg.type() == Mysqlx::Expr::Expr_Type_LITERAL && arg.literal().type() == Mysqlx::Datatypes::Scalar_Type_V_OCTETS && arg.literal().has_v_octets(); } inline bool is_plain_octets(const Mysqlx::Expr::Expr &arg) { return is_octets(arg) && arg.literal().v_octets().content_type() == Expression_generator::CT_PLAIN; } } // namespace void Expression_generator::in_expression(const Mysqlx::Expr::Operator &arg, const char *str) const { switch (arg.param_size()) { case 0: case 1: throw Error(ER_X_EXPR_BAD_NUM_ARGS, "IN expression requires at least two parameters."); case 2: if (is_array(arg.param(1))) { m_qb.put(str).put("JSON_CONTAINS("); generate(arg.param(1)); m_qb.put(","); if (is_octets(arg.param(0))) { m_qb.put("JSON_QUOTE("); generate(arg.param(0)); m_qb.put("))"); } else { m_qb.put("CAST("); generate(arg.param(0)); m_qb.put(" AS JSON))"); } break; } // Fall through. default: m_qb.put("("); generate_unquote_param(arg.param(0)); m_qb.put(" ").put(str).put("IN ("); generate_for_each(arg.param(), &Expression_generator::generate_unquote_param, 1); m_qb.put("))"); } } void Expression_generator::like_expression(const Mysqlx::Expr::Operator &arg, const char *str) const { int paramSize = arg.param_size(); if(paramSize != 2 && paramSize != 3) { throw Error(ER_X_EXPR_BAD_NUM_ARGS, "LIKE expression requires exactly two or three parameters."); } m_qb.put("("); generate_unquote_param(arg.param(0)); m_qb.put(str); generate_unquote_param(arg.param(1)); if(paramSize == 3) { m_qb.put(" ESCAPE "); generate_unquote_param(arg.param(2)); } m_qb.put(")"); } void Expression_generator::between_expression(const Mysqlx::Expr::Operator &arg, const char *str) const { if(arg.param_size() != 3) { throw Error(ER_X_EXPR_BAD_NUM_ARGS, "BETWEEN expression requires exactly three parameters."); } m_qb.put("("); generate_unquote_param(arg.param(0)); m_qb.put(str); generate_unquote_param(arg.param(1)); m_qb.put(" AND "); generate_unquote_param(arg.param(2)); m_qb.put(")"); } namespace { struct Interval_unit_validator { Interval_unit_validator(const char* const error_msg) : m_error_msg(error_msg) {} bool operator() (const char* source) const { // keep patterns in asc order static const char* const patterns[] = { "DAY", "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND", "HOUR", "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_SECOND", "MICROSECOND", "MINUTE", "MINUTE_MICROSECOND", "MINUTE_SECOND", "MONTH", "QUARTER", "SECOND", "SECOND_MICROSECOND", "WEEK", "YEAR", "YEAR_MONTH" }; static const char* const *patterns_end = get_array_end(patterns); return std::binary_search(patterns, patterns_end, source, Is_less()); } const char* const m_error_msg; }; struct Cast_type_validator { Cast_type_validator(const char* const error_msg) : m_error_msg(error_msg) {} bool operator() (const char* str) const { static const xpl::Regex re( "^(" "BINARY([[.left-parenthesis.]][[:digit:]]+[[.right-parenthesis.]])?|" "DATE|DATETIME|TIME|JSON|" "CHAR([[.left-parenthesis.]][[:digit:]]+[[.right-parenthesis.]])?|" "DECIMAL([[.left-parenthesis.]][[:digit:]]+(,[[:digit:]]+)?[[.right-parenthesis.]])?|" "SIGNED( INTEGER)?|UNSIGNED( INTEGER)?" "){1}$"); return re.match(str); } const char* const m_error_msg; }; template<typename V> const std::string& get_valid_string(const Expression_generator::Expr &expr, const V& is_valid) { if (!is_plain_octets(expr) || !is_valid(expr.literal().v_octets().value().c_str())) throw Expression_generator::Error(ER_X_EXPR_BAD_VALUE, is_valid.m_error_msg); return expr.literal().v_octets().value(); } } // namespace void Expression_generator::date_expression(const Mysqlx::Expr::Operator &arg, const char* str) const { if(arg.param_size() != 3) throw Error(ER_X_EXPR_BAD_NUM_ARGS, "DATE expression requires exactly three parameters."); m_qb.put(str).put("("); generate_unquote_param(arg.param(0)); m_qb.put(", INTERVAL "); generate_unquote_param(arg.param(1)); m_qb.put(" "); m_qb.put(get_valid_string(arg.param(2), Interval_unit_validator("DATE interval unit invalid."))); m_qb.put(")"); } void Expression_generator::cast_expression(const Mysqlx::Expr::Operator &arg) const { if(arg.param_size() != 2) throw Error(ER_X_EXPR_BAD_NUM_ARGS, "CAST expression requires exactly two parameters."); m_qb.put("CAST("); generate_unquote_param(arg.param(0)); m_qb.put(" AS "); m_qb.put(get_valid_string(arg.param(1), Cast_type_validator("CAST type invalid."))); m_qb.put(")"); } void Expression_generator::binary_expression(const Mysqlx::Expr::Operator &arg, const char* str) const { if(arg.param_size() != 2) { throw Error(ER_X_EXPR_BAD_NUM_ARGS, "Binary operations require exactly two operands in expression."); } m_qb.put("("); generate_unquote_param(arg.param(0)); m_qb.put(str); generate_unquote_param(arg.param(1)); m_qb.put(")"); } namespace { typedef ngs::function<void (const Expression_generator*, const Mysqlx::Expr::Operator&)> Operator_ptr; typedef std::pair<const char* const, Operator_ptr> Operator_bind; struct Is_operator_less { bool operator() (const Operator_bind& pattern, const std::string& value) const { return std::strcmp(pattern.first, value.c_str()) < 0; } }; } // namespace void Expression_generator::generate(const Mysqlx::Expr::Operator &arg) const { // keep binding in asc order static const Operator_bind operators[] = { std::make_pair("!", ngs::bind(&Expression_generator::unary_operator, ngs::placeholders::_1, ngs::placeholders::_2, "!")), std::make_pair("!=", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " != ")), std::make_pair("%", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " % ")), std::make_pair("&", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " & ")), std::make_pair("&&", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " AND ")), std::make_pair("*", ngs::bind(&Expression_generator::asterisk_operator, ngs::placeholders::_1, ngs::placeholders::_2)), std::make_pair("+", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " + ")), std::make_pair("-", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " - ")), std::make_pair("/", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " / ")), std::make_pair("<", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " < ")), std::make_pair("<<", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " << ")), std::make_pair("<=", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " <= ")), std::make_pair("==", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " = ")), std::make_pair(">", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " > ")), std::make_pair(">=", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " >= ")), std::make_pair(">>", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " >> ")), std::make_pair("^", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " ^ ")), std::make_pair("between", ngs::bind(&Expression_generator::between_expression, ngs::placeholders::_1, ngs::placeholders::_2, " BETWEEN ")), std::make_pair("cast", ngs::bind(&Expression_generator::cast_expression, ngs::placeholders::_1, ngs::placeholders::_2)), std::make_pair("date_add", ngs::bind(&Expression_generator::date_expression, ngs::placeholders::_1, ngs::placeholders::_2, "DATE_ADD")), std::make_pair("date_sub", ngs::bind(&Expression_generator::date_expression, ngs::placeholders::_1, ngs::placeholders::_2, "DATE_SUB")), std::make_pair("default", ngs::bind(&Expression_generator::nullary_operator, ngs::placeholders::_1, ngs::placeholders::_2, "DEFAULT")), std::make_pair("div", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " DIV ")), std::make_pair("in", ngs::bind(&Expression_generator::in_expression, ngs::placeholders::_1, ngs::placeholders::_2, "")), std::make_pair("is", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " IS ")), std::make_pair("is_not", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " IS NOT ")), std::make_pair("like", ngs::bind(&Expression_generator::like_expression, ngs::placeholders::_1, ngs::placeholders::_2, " LIKE ")), std::make_pair("not", ngs::bind(&Expression_generator::unary_operator, ngs::placeholders::_1, ngs::placeholders::_2, "NOT ")), std::make_pair("not_between", ngs::bind(&Expression_generator::between_expression, ngs::placeholders::_1, ngs::placeholders::_2, " NOT BETWEEN ")), std::make_pair("not_in", ngs::bind(&Expression_generator::in_expression, ngs::placeholders::_1, ngs::placeholders::_2, "NOT ")), std::make_pair("not_like", ngs::bind(&Expression_generator::like_expression, ngs::placeholders::_1, ngs::placeholders::_2, " NOT LIKE ")), std::make_pair("not_regexp", ngs::bind(&Expression_generator::binary_expression, ngs::placeholders::_1, ngs::placeholders::_2, " NOT REGEXP ")), std::make_pair("regexp", ngs::bind(&Expression_generator::binary_expression, ngs::placeholders::_1, ngs::placeholders::_2, " REGEXP ")), std::make_pair("sign_minus", ngs::bind(&Expression_generator::unary_operator, ngs::placeholders::_1, ngs::placeholders::_2, "-")), std::make_pair("sign_plus", ngs::bind(&Expression_generator::unary_operator, ngs::placeholders::_1, ngs::placeholders::_2, "+")), std::make_pair("xor",ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " XOR ")), std::make_pair("|", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " | ")), std::make_pair("||", ngs::bind(&Expression_generator::binary_operator, ngs::placeholders::_1, ngs::placeholders::_2, " OR ")), std::make_pair("~", ngs::bind(&Expression_generator::unary_operator, ngs::placeholders::_1, ngs::placeholders::_2, "~")) }; static const Operator_bind *operators_end = get_array_end(operators); const Operator_bind *op = std::lower_bound(operators, operators_end, arg.name(), Is_operator_less()); if (op == operators_end || std::strcmp(arg.name().c_str(), op->first) != 0) throw Error(ER_X_EXPR_BAD_OPERATOR, "Invalid operator " + arg.name()); op->second(this, arg); } void Expression_generator::asterisk_operator(const Mysqlx::Expr::Operator &arg) const { switch (arg.param_size()) { case 0: m_qb.put("*"); break; case 2: m_qb.put("("); generate_unquote_param(arg.param(0)); m_qb.put(" * "); generate_unquote_param(arg.param(1)); m_qb.put(")"); break; default: throw Error(ER_X_EXPR_BAD_NUM_ARGS, "Asterisk operator require zero or two operands in expression"); } } void Expression_generator::nullary_operator(const Mysqlx::Expr::Operator &arg, const char* str) const { if (arg.param_size() != 0) throw Error(ER_X_EXPR_BAD_NUM_ARGS, "Nullary operator require no operands in expression"); m_qb.put(str); } Expression_generator Expression_generator::clone(Query_string_builder &qb) const { return Expression_generator(qb, m_args, m_default_schema, m_is_relational); } } // namespace xpl