2021-10-31 15:11:46 +00:00
|
|
|
#include <string_view>
|
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Parsers/ASTFunction.h>
|
2020-12-16 21:44:05 +00:00
|
|
|
|
2021-01-13 19:29:52 +00:00
|
|
|
#include <Common/quoteString.h>
|
2021-06-14 04:13:35 +00:00
|
|
|
#include <Common/FieldVisitorToString.h>
|
2020-08-20 02:01:40 +00:00
|
|
|
#include <Common/SipHash.h>
|
2020-12-16 21:44:05 +00:00
|
|
|
#include <Common/typeid_cast.h>
|
2021-09-30 10:47:29 +00:00
|
|
|
#include <DataTypes/IDataType.h>
|
2021-04-16 16:28:07 +00:00
|
|
|
#include <DataTypes/NumberTraits.h>
|
2020-11-09 16:05:40 +00:00
|
|
|
#include <IO/Operators.h>
|
2020-12-16 21:44:05 +00:00
|
|
|
#include <IO/WriteBufferFromString.h>
|
|
|
|
#include <IO/WriteHelpers.h>
|
2020-12-16 21:46:14 +00:00
|
|
|
#include <Parsers/ASTExpressionList.h>
|
2020-12-16 21:44:05 +00:00
|
|
|
#include <Parsers/ASTIdentifier.h>
|
|
|
|
#include <Parsers/ASTLiteral.h>
|
|
|
|
#include <Parsers/ASTSubquery.h>
|
|
|
|
#include <Parsers/ASTWithAlias.h>
|
2021-07-03 20:17:02 +00:00
|
|
|
#include <Parsers/queryToString.h>
|
2015-08-05 21:39:42 +00:00
|
|
|
|
2021-10-31 15:11:46 +00:00
|
|
|
using namespace std::literals;
|
|
|
|
|
2021-06-14 04:13:35 +00:00
|
|
|
|
2015-08-05 21:39:42 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
2015-08-06 03:26:27 +00:00
|
|
|
|
2021-04-06 13:08:29 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int UNEXPECTED_EXPRESSION;
|
2021-07-03 20:17:02 +00:00
|
|
|
extern const int UNEXPECTED_AST_STRUCTURE;
|
2021-04-06 13:08:29 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 16:34:11 +00:00
|
|
|
void ASTFunction::appendColumnNameImpl(WriteBuffer & ostr) const
|
2016-05-03 23:19:14 +00:00
|
|
|
{
|
2021-04-06 13:08:29 +00:00
|
|
|
if (name == "view")
|
|
|
|
throw Exception("Table function view cannot be used as an expression", ErrorCodes::UNEXPECTED_EXPRESSION);
|
|
|
|
|
2018-06-27 16:34:11 +00:00
|
|
|
writeString(name, ostr);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (parameters)
|
|
|
|
{
|
2018-06-27 16:34:11 +00:00
|
|
|
writeChar('(', ostr);
|
|
|
|
for (auto it = parameters->children.begin(); it != parameters->children.end(); ++it)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
if (it != parameters->children.begin())
|
2018-06-27 16:34:11 +00:00
|
|
|
writeCString(", ", ostr);
|
2021-06-16 17:56:20 +00:00
|
|
|
|
2021-08-03 18:03:24 +00:00
|
|
|
(*it)->appendColumnName(ostr);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2018-06-27 16:34:11 +00:00
|
|
|
writeChar(')', ostr);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 16:34:11 +00:00
|
|
|
writeChar('(', ostr);
|
2020-12-04 02:15:44 +00:00
|
|
|
if (arguments)
|
2021-06-16 17:56:20 +00:00
|
|
|
{
|
2020-12-04 02:15:44 +00:00
|
|
|
for (auto it = arguments->children.begin(); it != arguments->children.end(); ++it)
|
|
|
|
{
|
|
|
|
if (it != arguments->children.begin())
|
|
|
|
writeCString(", ", ostr);
|
2021-06-16 17:56:20 +00:00
|
|
|
|
2021-08-03 18:03:24 +00:00
|
|
|
(*it)->appendColumnName(ostr);
|
2020-12-04 02:15:44 +00:00
|
|
|
}
|
2021-06-16 17:56:20 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 16:34:11 +00:00
|
|
|
writeChar(')', ostr);
|
2020-12-25 04:59:17 +00:00
|
|
|
|
|
|
|
if (is_window_function)
|
|
|
|
{
|
2021-01-13 19:29:52 +00:00
|
|
|
writeCString(" OVER ", ostr);
|
|
|
|
if (!window_name.empty())
|
|
|
|
{
|
|
|
|
ostr << window_name;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-06-16 17:56:20 +00:00
|
|
|
FormatSettings format_settings{ostr, true /* one_line */};
|
2021-01-13 19:29:52 +00:00
|
|
|
FormatState state;
|
|
|
|
FormatStateStacked frame;
|
|
|
|
writeCString("(", ostr);
|
2021-06-16 17:56:20 +00:00
|
|
|
window_definition->formatImpl(format_settings, state, frame);
|
2021-01-13 19:29:52 +00:00
|
|
|
writeCString(")", ostr);
|
|
|
|
}
|
2020-12-25 04:59:17 +00:00
|
|
|
}
|
2016-05-03 23:19:14 +00:00
|
|
|
}
|
|
|
|
|
2017-04-02 17:37:49 +00:00
|
|
|
/** Get the text that identifies this element. */
|
2018-12-07 12:34:40 +00:00
|
|
|
String ASTFunction::getID(char delim) const
|
2016-05-03 23:19:14 +00:00
|
|
|
{
|
2018-12-07 12:34:40 +00:00
|
|
|
return "Function" + (delim + name);
|
2016-05-03 23:19:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ASTPtr ASTFunction::clone() const
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
auto res = std::make_shared<ASTFunction>(*this);
|
|
|
|
res->children.clear();
|
2016-05-03 23:19:14 +00:00
|
|
|
|
2018-02-24 01:31:42 +00:00
|
|
|
if (arguments) { res->arguments = arguments->clone(); res->children.push_back(res->arguments); }
|
|
|
|
if (parameters) { res->parameters = parameters->clone(); res->children.push_back(res->parameters); }
|
2016-05-03 23:19:14 +00:00
|
|
|
|
2021-01-13 19:29:52 +00:00
|
|
|
if (window_definition)
|
2020-12-16 21:44:05 +00:00
|
|
|
{
|
2021-01-13 19:29:52 +00:00
|
|
|
res->window_definition = window_definition->clone();
|
|
|
|
res->children.push_back(res->window_definition);
|
2020-12-16 21:44:05 +00:00
|
|
|
}
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
return res;
|
2016-05-03 23:19:14 +00:00
|
|
|
}
|
|
|
|
|
2019-02-10 19:11:47 +00:00
|
|
|
|
2020-08-20 02:01:40 +00:00
|
|
|
void ASTFunction::updateTreeHashImpl(SipHash & hash_state) const
|
|
|
|
{
|
|
|
|
hash_state.update(name.size());
|
|
|
|
hash_state.update(name);
|
|
|
|
IAST::updateTreeHashImpl(hash_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-12-04 02:15:44 +00:00
|
|
|
ASTPtr ASTFunction::toLiteral() const
|
|
|
|
{
|
|
|
|
if (!arguments) return {};
|
|
|
|
|
|
|
|
if (name == "array")
|
|
|
|
{
|
|
|
|
Array array;
|
|
|
|
|
|
|
|
for (const auto & arg : arguments->children)
|
|
|
|
{
|
|
|
|
if (auto * literal = arg->as<ASTLiteral>())
|
|
|
|
array.push_back(literal->value);
|
|
|
|
else if (auto * func = arg->as<ASTFunction>())
|
|
|
|
{
|
|
|
|
if (auto func_literal = func->toLiteral())
|
|
|
|
array.push_back(func_literal->as<ASTLiteral>()->value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/// Some of the Array arguments is not literal
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::make_shared<ASTLiteral>(array);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-05 15:57:59 +00:00
|
|
|
/** A special hack. If it's [I]LIKE or NOT [I]LIKE expression and the right hand side is a string literal,
|
2019-02-10 19:11:47 +00:00
|
|
|
* we will highlight unescaped metacharacters % and _ in string literal for convenience.
|
2019-02-10 19:21:08 +00:00
|
|
|
* Motivation: most people are unaware that _ is a metacharacter and forgot to properly escape it with two backslashes.
|
2019-02-10 19:11:47 +00:00
|
|
|
* With highlighting we make it clearly obvious.
|
|
|
|
*
|
|
|
|
* Another case is regexp match. Suppose the user types match(URL, 'www.yandex.ru'). It often means that the user is unaware that . is a metacharacter.
|
|
|
|
*/
|
|
|
|
static bool highlightStringLiteralWithMetacharacters(const ASTPtr & node, const IAST::FormatSettings & settings, const char * metacharacters)
|
|
|
|
{
|
2019-03-11 13:22:51 +00:00
|
|
|
if (const auto * literal = node->as<ASTLiteral>())
|
2019-02-10 19:11:47 +00:00
|
|
|
{
|
|
|
|
if (literal->value.getType() == Field::Types::String)
|
|
|
|
{
|
|
|
|
auto string = applyVisitor(FieldVisitorToString(), literal->value);
|
|
|
|
|
|
|
|
unsigned escaping = 0;
|
|
|
|
for (auto c : string)
|
|
|
|
{
|
|
|
|
if (c == '\\')
|
|
|
|
{
|
|
|
|
settings.ostr << c;
|
|
|
|
if (escaping == 2)
|
|
|
|
escaping = 0;
|
|
|
|
++escaping;
|
|
|
|
}
|
|
|
|
else if (nullptr != strchr(metacharacters, c))
|
|
|
|
{
|
|
|
|
if (escaping == 2) /// Properly escaped metacharacter
|
|
|
|
settings.ostr << c;
|
|
|
|
else /// Unescaped metacharacter
|
|
|
|
settings.ostr << "\033[1;35m" << c << "\033[0m";
|
|
|
|
escaping = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
settings.ostr << c;
|
|
|
|
escaping = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-09 07:41:38 +00:00
|
|
|
ASTSelectWithUnionQuery * ASTFunction::tryGetQueryArgument() const
|
|
|
|
{
|
|
|
|
if (arguments && arguments->children.size() == 1)
|
|
|
|
{
|
|
|
|
return arguments->children[0]->as<ASTSelectWithUnionQuery>();
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-06 23:46:15 +00:00
|
|
|
void ASTFunction::formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
|
2015-08-06 03:26:27 +00:00
|
|
|
{
|
2020-09-08 20:34:10 +00:00
|
|
|
frame.expression_list_prepend_whitespace = false;
|
2017-04-01 07:20:54 +00:00
|
|
|
FormatStateStacked nested_need_parens = frame;
|
|
|
|
FormatStateStacked nested_dont_need_parens = frame;
|
2018-05-17 15:17:07 +00:00
|
|
|
nested_need_parens.need_parens = true;
|
|
|
|
nested_dont_need_parens.need_parens = false;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2020-09-09 07:41:38 +00:00
|
|
|
if (auto * query = tryGetQueryArgument())
|
2020-08-28 14:07:14 +00:00
|
|
|
{
|
|
|
|
std::string nl_or_nothing = settings.one_line ? "" : "\n";
|
|
|
|
std::string indent_str = settings.one_line ? "" : std::string(4u * frame.indent, ' ');
|
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << name << "(" << nl_or_nothing;
|
|
|
|
FormatStateStacked frame_nested = frame;
|
|
|
|
frame_nested.need_parens = false;
|
|
|
|
++frame_nested.indent;
|
|
|
|
query->formatImpl(settings, state, frame_nested);
|
|
|
|
settings.ostr << nl_or_nothing << indent_str << ")";
|
|
|
|
return;
|
|
|
|
}
|
2021-09-27 18:04:12 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/// Should this function to be written as operator?
|
|
|
|
bool written = false;
|
2021-09-27 18:04:12 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (arguments && !parameters)
|
|
|
|
{
|
2021-09-27 18:04:12 +00:00
|
|
|
/// Unary prefix operators.
|
2017-04-01 07:20:54 +00:00
|
|
|
if (arguments->children.size() == 1)
|
|
|
|
{
|
|
|
|
const char * operators[] =
|
|
|
|
{
|
2021-09-27 18:04:12 +00:00
|
|
|
"negate", "-",
|
|
|
|
"not", "NOT ",
|
2017-04-01 07:20:54 +00:00
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const char ** func = operators; *func; func += 2)
|
|
|
|
{
|
2021-04-30 16:58:35 +00:00
|
|
|
if (strcasecmp(name.c_str(), func[0]) != 0)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2021-03-25 15:38:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto * literal = arguments->children[0]->as<ASTLiteral>();
|
2021-05-23 13:34:31 +00:00
|
|
|
const auto * function = arguments->children[0]->as<ASTFunction>();
|
|
|
|
bool negate = name == "negate";
|
2021-09-30 10:47:29 +00:00
|
|
|
bool is_tuple = literal && literal->value.getType() == Field::Types::Tuple;
|
|
|
|
// do not add parentheses for tuple literal, otherwise extra parens will be added `-((3, 7, 3), 1)` -> `-(((3, 7, 3), 1))`
|
|
|
|
bool literal_need_parens = literal && !is_tuple;
|
2021-05-23 13:34:31 +00:00
|
|
|
// negate always requires parentheses, otherwise -(-1) will be printed as --1
|
2021-09-30 10:47:29 +00:00
|
|
|
bool negate_need_parens = negate && (literal_need_parens || (function && function->name == "negate"));
|
2021-03-25 15:38:02 +00:00
|
|
|
// We don't need parentheses around a single literal.
|
2021-05-23 13:34:31 +00:00
|
|
|
bool need_parens = !literal && frame.need_parens && !negate_need_parens;
|
|
|
|
|
|
|
|
// do not add extra parentheses for functions inside negate, i.e. -(-toUInt64(-(1)))
|
|
|
|
if (negate_need_parens)
|
|
|
|
nested_need_parens.need_parens = false;
|
|
|
|
|
|
|
|
if (need_parens)
|
2021-03-25 15:38:02 +00:00
|
|
|
settings.ostr << '(';
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-03-25 15:38:02 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << func[1] << (settings.hilite ? hilite_none : "");
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-05-23 13:34:31 +00:00
|
|
|
if (negate_need_parens)
|
|
|
|
settings.ostr << '(';
|
|
|
|
|
2021-03-25 15:38:02 +00:00
|
|
|
arguments->formatImpl(settings, state, nested_need_parens);
|
|
|
|
written = true;
|
2019-06-16 22:51:09 +00:00
|
|
|
|
2021-05-23 13:34:31 +00:00
|
|
|
if (negate_need_parens)
|
|
|
|
settings.ostr << ')';
|
|
|
|
|
|
|
|
if (need_parens)
|
2021-03-25 15:38:02 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
|
|
|
|
break;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-27 18:04:12 +00:00
|
|
|
/// Unary postfix operators.
|
|
|
|
if (!written && arguments->children.size() == 1)
|
|
|
|
{
|
|
|
|
const char * operators[] =
|
|
|
|
{
|
|
|
|
"isNull", " IS NULL",
|
|
|
|
"isNotNull", " IS NOT NULL",
|
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const char ** func = operators; *func; func += 2)
|
|
|
|
{
|
|
|
|
if (strcasecmp(name.c_str(), func[0]) != 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-10-21 18:18:00 +00:00
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << '(';
|
2021-09-27 18:04:12 +00:00
|
|
|
arguments->formatImpl(settings, state, nested_need_parens);
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << func[1] << (settings.hilite ? hilite_none : "");
|
2021-10-21 18:18:00 +00:00
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << ')';
|
2021-09-27 18:04:12 +00:00
|
|
|
|
|
|
|
written = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-16 19:12:58 +00:00
|
|
|
/** need_parens - do we need parentheses around the expression with the operator.
|
2017-04-02 17:37:49 +00:00
|
|
|
* They are needed only if this expression is included in another expression with the operator.
|
|
|
|
*/
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!written && arguments->children.size() == 2)
|
|
|
|
{
|
|
|
|
const char * operators[] =
|
|
|
|
{
|
2017-12-09 20:56:53 +00:00
|
|
|
"multiply", " * ",
|
|
|
|
"divide", " / ",
|
|
|
|
"modulo", " % ",
|
|
|
|
"plus", " + ",
|
|
|
|
"minus", " - ",
|
|
|
|
"notEquals", " != ",
|
|
|
|
"lessOrEquals", " <= ",
|
|
|
|
"greaterOrEquals", " >= ",
|
|
|
|
"less", " < ",
|
|
|
|
"greater", " > ",
|
|
|
|
"equals", " = ",
|
|
|
|
"like", " LIKE ",
|
2020-07-05 15:57:59 +00:00
|
|
|
"ilike", " ILIKE ",
|
2017-12-09 20:56:53 +00:00
|
|
|
"notLike", " NOT LIKE ",
|
2020-07-05 15:57:59 +00:00
|
|
|
"notILike", " NOT ILIKE ",
|
2017-12-09 20:56:53 +00:00
|
|
|
"in", " IN ",
|
|
|
|
"notIn", " NOT IN ",
|
|
|
|
"globalIn", " GLOBAL IN ",
|
|
|
|
"globalNotIn", " GLOBAL NOT IN ",
|
2017-04-01 07:20:54 +00:00
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const char ** func = operators; *func; func += 2)
|
|
|
|
{
|
2021-10-31 15:11:46 +00:00
|
|
|
if (name == std::string_view(func[0]))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << '(';
|
|
|
|
arguments->children[0]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << func[1] << (settings.hilite ? hilite_none : "");
|
2019-02-10 19:11:47 +00:00
|
|
|
|
|
|
|
bool special_hilite = settings.hilite
|
2020-07-05 15:57:59 +00:00
|
|
|
&& (name == "like" || name == "notLike" || name == "ilike" || name == "notILike")
|
2019-02-10 19:11:47 +00:00
|
|
|
&& highlightStringLiteralWithMetacharacters(arguments->children[1], settings, "%_");
|
|
|
|
|
2019-05-16 19:12:58 +00:00
|
|
|
/// Format x IN 1 as x IN (1): put parens around rhs even if there is a single element in set.
|
|
|
|
const auto * second_arg_func = arguments->children[1]->as<ASTFunction>();
|
2019-05-16 22:51:26 +00:00
|
|
|
const auto * second_arg_literal = arguments->children[1]->as<ASTLiteral>();
|
2019-05-16 19:19:30 +00:00
|
|
|
bool extra_parents_around_in_rhs = (name == "in" || name == "notIn" || name == "globalIn" || name == "globalNotIn")
|
2019-05-19 19:22:51 +00:00
|
|
|
&& !second_arg_func
|
|
|
|
&& !(second_arg_literal
|
|
|
|
&& (second_arg_literal->value.getType() == Field::Types::Tuple
|
|
|
|
|| second_arg_literal->value.getType() == Field::Types::Array))
|
2019-05-16 19:55:18 +00:00
|
|
|
&& !arguments->children[1]->as<ASTSubquery>();
|
2019-05-16 19:12:58 +00:00
|
|
|
|
2019-05-16 19:19:30 +00:00
|
|
|
if (extra_parents_around_in_rhs)
|
2019-05-16 19:12:58 +00:00
|
|
|
{
|
|
|
|
settings.ostr << '(';
|
2019-05-16 19:55:18 +00:00
|
|
|
arguments->children[1]->formatImpl(settings, state, nested_dont_need_parens);
|
2019-05-16 19:12:58 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
}
|
|
|
|
|
2019-05-16 19:55:18 +00:00
|
|
|
if (!special_hilite && !extra_parents_around_in_rhs)
|
2019-02-10 19:11:47 +00:00
|
|
|
arguments->children[1]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
written = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-31 15:11:46 +00:00
|
|
|
if (!written && name == "arrayElement"sv)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2019-06-16 22:51:09 +00:00
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << '(';
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
arguments->children[0]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << '[' << (settings.hilite ? hilite_none : "");
|
2019-06-16 22:51:09 +00:00
|
|
|
arguments->children[1]->formatImpl(settings, state, nested_dont_need_parens);
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << ']' << (settings.hilite ? hilite_none : "");
|
|
|
|
written = true;
|
2019-06-16 22:51:09 +00:00
|
|
|
|
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << ')';
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2021-10-31 15:11:46 +00:00
|
|
|
if (!written && name == "tupleElement"sv)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2021-07-21 01:47:56 +00:00
|
|
|
// fuzzer sometimes may insert tupleElement() created from ASTLiteral:
|
Fix inconsistent formatting for tupleElement (for fuzzer)
fuzzer sometimes [1] may inserts tupleElement() created from ASTLiteral:
Function_tupleElement, 0xx
-ExpressionList_, 0xx
--Literal_Int64_255, 0xx
--Literal_Int64_100, 0xx
And in this case it will be printed as "255.100", which
later will be parsed as float, and formatting will be
inconsistent.
So instead of printing it as regular tuple,
let's print it as ExpressionList instead (i.e. with ", " delimiter).
Simple reproducer:
void ast()
{
auto arg1 = std::make_shared<ASTLiteral>(Field(255));
auto arg2 = std::make_shared<ASTLiteral>(Field(100));
auto func = makeASTFunction("tupleElement", arg1, arg2);
auto ast = func;
std::cerr << ast->formatForErrorMessage() << std::endl;
std::cerr << ast->dumpTree() << std::endl;
}
[1]: https://clickhouse-test-reports.s3.yandex.net/23517/f1187aeb69109c88f0be978b8083080c7a843820/fuzzer_debug/report.html#fail1
2021-04-24 16:48:04 +00:00
|
|
|
//
|
|
|
|
// Function_tupleElement, 0xx
|
|
|
|
// -ExpressionList_, 0xx
|
|
|
|
// --Literal_Int64_255, 0xx
|
|
|
|
// --Literal_Int64_100, 0xx
|
|
|
|
//
|
|
|
|
// And in this case it will be printed as "255.100", which
|
|
|
|
// later will be parsed as float, and formatting will be
|
|
|
|
// inconsistent.
|
|
|
|
//
|
|
|
|
// So instead of printing it as regular tuple,
|
|
|
|
// let's print it as ExpressionList instead (i.e. with ", " delimiter).
|
|
|
|
bool tuple_arguments_valid = true;
|
|
|
|
const auto * lit_left = arguments->children[0]->as<ASTLiteral>();
|
|
|
|
const auto * lit_right = arguments->children[1]->as<ASTLiteral>();
|
|
|
|
|
|
|
|
if (lit_left)
|
|
|
|
{
|
|
|
|
Field::Types::Which type = lit_left->value.getType();
|
|
|
|
if (type != Field::Types::Tuple && type != Field::Types::Array)
|
|
|
|
{
|
|
|
|
tuple_arguments_valid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-18 23:28:13 +00:00
|
|
|
// It can be printed in a form of 'x.1' only if right hand side
|
|
|
|
// is an unsigned integer lineral. We also allow nonnegative
|
|
|
|
// signed integer literals, because the fuzzer sometimes inserts
|
|
|
|
// them, and we want to have consistent formatting.
|
Fix inconsistent formatting for tupleElement (for fuzzer)
fuzzer sometimes [1] may inserts tupleElement() created from ASTLiteral:
Function_tupleElement, 0xx
-ExpressionList_, 0xx
--Literal_Int64_255, 0xx
--Literal_Int64_100, 0xx
And in this case it will be printed as "255.100", which
later will be parsed as float, and formatting will be
inconsistent.
So instead of printing it as regular tuple,
let's print it as ExpressionList instead (i.e. with ", " delimiter).
Simple reproducer:
void ast()
{
auto arg1 = std::make_shared<ASTLiteral>(Field(255));
auto arg2 = std::make_shared<ASTLiteral>(Field(100));
auto func = makeASTFunction("tupleElement", arg1, arg2);
auto ast = func;
std::cerr << ast->formatForErrorMessage() << std::endl;
std::cerr << ast->dumpTree() << std::endl;
}
[1]: https://clickhouse-test-reports.s3.yandex.net/23517/f1187aeb69109c88f0be978b8083080c7a843820/fuzzer_debug/report.html#fail1
2021-04-24 16:48:04 +00:00
|
|
|
if (tuple_arguments_valid && lit_right)
|
2017-12-24 09:33:36 +00:00
|
|
|
{
|
2021-05-03 22:46:51 +00:00
|
|
|
if (isInt64OrUInt64FieldType(lit_right->value.getType())
|
Fix inconsistent formatting for tupleElement (for fuzzer)
fuzzer sometimes [1] may inserts tupleElement() created from ASTLiteral:
Function_tupleElement, 0xx
-ExpressionList_, 0xx
--Literal_Int64_255, 0xx
--Literal_Int64_100, 0xx
And in this case it will be printed as "255.100", which
later will be parsed as float, and formatting will be
inconsistent.
So instead of printing it as regular tuple,
let's print it as ExpressionList instead (i.e. with ", " delimiter).
Simple reproducer:
void ast()
{
auto arg1 = std::make_shared<ASTLiteral>(Field(255));
auto arg2 = std::make_shared<ASTLiteral>(Field(100));
auto func = makeASTFunction("tupleElement", arg1, arg2);
auto ast = func;
std::cerr << ast->formatForErrorMessage() << std::endl;
std::cerr << ast->dumpTree() << std::endl;
}
[1]: https://clickhouse-test-reports.s3.yandex.net/23517/f1187aeb69109c88f0be978b8083080c7a843820/fuzzer_debug/report.html#fail1
2021-04-24 16:48:04 +00:00
|
|
|
&& lit_right->value.get<Int64>() >= 0)
|
2017-12-24 09:33:36 +00:00
|
|
|
{
|
2019-06-16 22:42:06 +00:00
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << '(';
|
|
|
|
|
2017-12-24 09:33:36 +00:00
|
|
|
arguments->children[0]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << "." << (settings.hilite ? hilite_none : "");
|
2019-06-16 22:51:09 +00:00
|
|
|
arguments->children[1]->formatImpl(settings, state, nested_dont_need_parens);
|
2017-12-24 09:33:36 +00:00
|
|
|
written = true;
|
2019-06-16 22:42:06 +00:00
|
|
|
|
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << ')';
|
2017-12-24 09:33:36 +00:00
|
|
|
}
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2021-10-31 15:11:46 +00:00
|
|
|
if (!written && name == "lambda"sv)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2021-10-21 07:08:08 +00:00
|
|
|
/// Special case: zero elements tuple in lhs of lambda is printed as ().
|
2017-04-01 07:20:54 +00:00
|
|
|
/// Special case: one-element tuple in lhs of lambda is printed as its element.
|
|
|
|
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << '(';
|
|
|
|
|
2019-03-11 13:22:51 +00:00
|
|
|
const auto * first_arg_func = arguments->children[0]->as<ASTFunction>();
|
2017-04-01 07:20:54 +00:00
|
|
|
if (first_arg_func
|
|
|
|
&& first_arg_func->name == "tuple"
|
|
|
|
&& first_arg_func->arguments
|
2021-10-21 15:43:33 +00:00
|
|
|
&& (first_arg_func->arguments->children.size() == 1 || first_arg_func->arguments->children.empty()))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2021-10-21 07:08:08 +00:00
|
|
|
if (first_arg_func->arguments->children.size() == 1)
|
|
|
|
first_arg_func->arguments->children[0]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
else
|
|
|
|
settings.ostr << "()";
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
arguments->children[0]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << " -> " << (settings.hilite ? hilite_none : "");
|
|
|
|
arguments->children[1]->formatImpl(settings, state, nested_need_parens);
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
written = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!written && arguments->children.size() >= 2)
|
|
|
|
{
|
|
|
|
const char * operators[] =
|
|
|
|
{
|
2017-12-09 20:56:53 +00:00
|
|
|
"and", " AND ",
|
|
|
|
"or", " OR ",
|
2017-04-01 07:20:54 +00:00
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const char ** func = operators; *func; func += 2)
|
|
|
|
{
|
2021-10-31 15:11:46 +00:00
|
|
|
if (name == std::string_view(func[0]))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << '(';
|
|
|
|
for (size_t i = 0; i < arguments->children.size(); ++i)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << func[1] << (settings.hilite ? hilite_none : "");
|
|
|
|
arguments->children[i]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
}
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2017-04-01 07:20:54 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
written = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-31 15:11:46 +00:00
|
|
|
if (!written && name == "array"sv)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << '[' << (settings.hilite ? hilite_none : "");
|
|
|
|
for (size_t i = 0; i < arguments->children.size(); ++i)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
settings.ostr << ", ";
|
|
|
|
arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens);
|
|
|
|
}
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << ']' << (settings.hilite ? hilite_none : "");
|
|
|
|
written = true;
|
|
|
|
}
|
|
|
|
|
2021-10-31 15:11:46 +00:00
|
|
|
if (!written && arguments->children.size() >= 2 && name == "tuple"sv)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << '(' << (settings.hilite ? hilite_none : "");
|
|
|
|
for (size_t i = 0; i < arguments->children.size(); ++i)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
settings.ostr << ", ";
|
|
|
|
arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens);
|
|
|
|
}
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << ')' << (settings.hilite ? hilite_none : "");
|
|
|
|
written = true;
|
|
|
|
}
|
2020-11-02 06:05:53 +00:00
|
|
|
|
2021-10-31 15:11:46 +00:00
|
|
|
if (!written && name == "map"sv)
|
2020-11-02 06:05:53 +00:00
|
|
|
{
|
2021-04-04 10:00:30 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << "map(" << (settings.hilite ? hilite_none : "");
|
2020-11-02 06:05:53 +00:00
|
|
|
for (size_t i = 0; i < arguments->children.size(); ++i)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
settings.ostr << ", ";
|
|
|
|
arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens);
|
|
|
|
}
|
2021-04-04 09:23:47 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << ')' << (settings.hilite ? hilite_none : "");
|
2020-11-02 06:05:53 +00:00
|
|
|
written = true;
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2020-12-18 00:21:23 +00:00
|
|
|
if (written)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2020-12-18 00:21:23 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2020-12-18 00:21:23 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << name;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2020-12-18 00:21:23 +00:00
|
|
|
if (parameters)
|
|
|
|
{
|
|
|
|
settings.ostr << '(' << (settings.hilite ? hilite_none : "");
|
|
|
|
parameters->formatImpl(settings, state, nested_dont_need_parens);
|
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << ')';
|
|
|
|
}
|
2019-02-10 19:11:47 +00:00
|
|
|
|
2020-12-18 00:21:23 +00:00
|
|
|
if ((arguments && !arguments->children.empty()) || !no_empty_args)
|
|
|
|
settings.ostr << '(' << (settings.hilite ? hilite_none : "");
|
2019-02-10 19:11:47 +00:00
|
|
|
|
2020-12-18 00:21:23 +00:00
|
|
|
if (arguments)
|
|
|
|
{
|
|
|
|
bool special_hilite_regexp = settings.hilite
|
|
|
|
&& (name == "match" || name == "extract" || name == "extractAll" || name == "replaceRegexpOne"
|
|
|
|
|| name == "replaceRegexpAll");
|
2019-02-10 19:11:47 +00:00
|
|
|
|
2020-12-18 00:21:23 +00:00
|
|
|
for (size_t i = 0, size = arguments->children.size(); i < size; ++i)
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
settings.ostr << ", ";
|
2019-02-10 19:11:47 +00:00
|
|
|
|
2020-12-18 00:21:23 +00:00
|
|
|
bool special_hilite = false;
|
|
|
|
if (i == 1 && special_hilite_regexp)
|
|
|
|
special_hilite = highlightStringLiteralWithMetacharacters(arguments->children[i], settings, "|()^$.[]?*+{:-");
|
|
|
|
|
|
|
|
if (!special_hilite)
|
|
|
|
arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens);
|
2020-12-04 02:15:44 +00:00
|
|
|
}
|
2020-12-18 00:21:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((arguments && !arguments->children.empty()) || !no_empty_args)
|
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << ')';
|
2019-02-10 19:11:47 +00:00
|
|
|
|
2020-12-18 00:21:23 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_none : "");
|
|
|
|
|
|
|
|
if (!is_window_function)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-01-13 19:29:52 +00:00
|
|
|
settings.ostr << " OVER ";
|
|
|
|
if (!window_name.empty())
|
2020-12-18 00:21:23 +00:00
|
|
|
{
|
2021-01-13 19:29:52 +00:00
|
|
|
settings.ostr << backQuoteIfNeed(window_name);
|
2020-12-18 00:21:23 +00:00
|
|
|
}
|
2021-01-13 19:29:52 +00:00
|
|
|
else
|
2020-12-18 00:21:23 +00:00
|
|
|
{
|
2021-01-13 19:29:52 +00:00
|
|
|
settings.ostr << "(";
|
|
|
|
window_definition->formatImpl(settings, state, frame);
|
|
|
|
settings.ostr << ")";
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2015-08-06 03:26:27 +00:00
|
|
|
}
|
|
|
|
|
2021-07-03 20:17:02 +00:00
|
|
|
String getFunctionName(const IAST * ast)
|
|
|
|
{
|
|
|
|
String res;
|
|
|
|
if (tryGetFunctionNameInto(ast, res))
|
|
|
|
return res;
|
|
|
|
throw Exception(ast ? queryToString(*ast) + " is not an function" : "AST node is nullptr", ErrorCodes::UNEXPECTED_AST_STRUCTURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<String> tryGetFunctionName(const IAST * ast)
|
|
|
|
{
|
|
|
|
String res;
|
|
|
|
if (tryGetFunctionNameInto(ast, res))
|
|
|
|
return res;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tryGetFunctionNameInto(const IAST * ast, String & name)
|
|
|
|
{
|
|
|
|
if (ast)
|
|
|
|
{
|
|
|
|
if (const auto * node = ast->as<ASTFunction>())
|
|
|
|
{
|
|
|
|
name = node->name;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-08-05 21:39:42 +00:00
|
|
|
}
|