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
|
|
|
|
2023-03-24 02:44:52 +00:00
|
|
|
#include <Common/assert_cast.h>
|
2021-01-13 19:29:52 +00:00
|
|
|
#include <Common/quoteString.h>
|
2021-06-14 04:13:35 +00:00
|
|
|
#include <Common/FieldVisitorToString.h>
|
2022-11-17 16:31:15 +00:00
|
|
|
#include <Common/KnownObjectNames.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>
|
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>
|
2022-11-17 16:31:15 +00:00
|
|
|
#include <Parsers/ASTExpressionList.h>
|
|
|
|
#include <Parsers/ASTIdentifier.h>
|
2020-12-16 21:44:05 +00:00
|
|
|
#include <Parsers/ASTLiteral.h>
|
2021-11-26 18:27:16 +00:00
|
|
|
#include <Parsers/ASTSelectWithUnionQuery.h>
|
2020-12-16 21:44:05 +00:00
|
|
|
#include <Parsers/ASTSubquery.h>
|
2021-07-03 20:17:02 +00:00
|
|
|
#include <Parsers/queryToString.h>
|
2022-08-03 15:00:24 +00:00
|
|
|
#include <Parsers/ASTSetQuery.h>
|
2024-03-01 20:58:22 +00:00
|
|
|
#include <Parsers/FunctionSecretArgumentsFinderAST.h>
|
2022-11-17 16:31:15 +00:00
|
|
|
#include <Core/QualifiedTableName.h>
|
|
|
|
|
2023-09-27 22:32:03 +00:00
|
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
|
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
|
|
|
|
{
|
2021-07-03 20:17:02 +00:00
|
|
|
extern const int UNEXPECTED_AST_STRUCTURE;
|
2023-03-20 12:42:30 +00:00
|
|
|
extern const int UNKNOWN_FUNCTION;
|
2021-04-06 13:08:29 +00:00
|
|
|
}
|
|
|
|
|
2022-11-17 16:31:15 +00:00
|
|
|
|
2018-06-27 16:34:11 +00:00
|
|
|
void ASTFunction::appendColumnNameImpl(WriteBuffer & ostr) const
|
2016-05-03 23:19:14 +00:00
|
|
|
{
|
2023-03-20 12:42:30 +00:00
|
|
|
/// These functions contain some unexpected ASTs in arguments (e.g. SETTINGS or even a SELECT query)
|
|
|
|
if (name == "view" || name == "viewIfPermitted" || name == "mysql" || name == "postgresql" || name == "mongodb" || name == "s3")
|
|
|
|
throw Exception(ErrorCodes::UNKNOWN_FUNCTION, "Table function '{}' cannot be used as an expression", name);
|
2021-04-06 13:08:29 +00:00
|
|
|
|
2022-01-24 12:26:54 +00:00
|
|
|
/// If function can be converted to literal it will be parsed as literal after formatting.
|
2023-11-23 20:10:49 +00:00
|
|
|
/// In distributed query it may lead to mismatched column names.
|
2022-01-24 07:46:30 +00:00
|
|
|
/// To avoid it we check whether we can convert function to literal.
|
|
|
|
if (auto literal = toLiteral())
|
|
|
|
{
|
|
|
|
literal->appendColumnName(ostr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-27 16:34:11 +00:00
|
|
|
writeString(name, ostr);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2016-05-03 23:19:14 +00:00
|
|
|
if (parameters)
|
|
|
|
{
|
2018-06-27 16:34:11 +00:00
|
|
|
writeChar('(', ostr);
|
2022-10-18 09:40:12 +00:00
|
|
|
for (auto * it = parameters->children.begin(); it != parameters->children.end(); ++it)
|
2016-05-03 23:19:14 +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);
|
2016-05-03 23:19:14 +00:00
|
|
|
}
|
2018-06-27 16:34:11 +00:00
|
|
|
writeChar(')', ostr);
|
2016-05-03 23:19:14 +00:00
|
|
|
}
|
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
|
|
|
{
|
2022-10-18 09:40:12 +00:00
|
|
|
for (auto * it = arguments->children.begin(); it != arguments->children.end(); ++it)
|
2020-12-04 02:15:44 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2023-11-23 20:10:49 +00:00
|
|
|
if (nulls_action == NullsAction::RESPECT_NULLS)
|
2023-11-30 12:16:51 +00:00
|
|
|
writeCString(" RESPECT NULLS", ostr);
|
2023-11-23 20:10:49 +00:00
|
|
|
else if (nulls_action == NullsAction::IGNORE_NULLS)
|
2023-11-30 12:16:51 +00:00
|
|
|
writeCString(" IGNORE NULLS", ostr);
|
2023-11-23 20:10:49 +00:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-06-13 22:39:18 +00:00
|
|
|
void ASTFunction::finishFormatWithWindow(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
|
|
|
|
{
|
2023-11-23 20:10:49 +00:00
|
|
|
if (nulls_action == NullsAction::RESPECT_NULLS)
|
2023-11-30 12:16:51 +00:00
|
|
|
settings.ostr << " RESPECT NULLS";
|
2023-11-23 20:10:49 +00:00
|
|
|
else if (nulls_action == NullsAction::IGNORE_NULLS)
|
2023-11-30 12:16:51 +00:00
|
|
|
settings.ostr << " IGNORE NULLS";
|
2023-11-23 20:10:49 +00:00
|
|
|
|
2022-06-13 22:39:18 +00:00
|
|
|
if (!is_window_function)
|
|
|
|
return;
|
|
|
|
|
|
|
|
settings.ostr << " OVER ";
|
|
|
|
if (!window_name.empty())
|
|
|
|
{
|
|
|
|
settings.ostr << backQuoteIfNeed(window_name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
settings.ostr << "(";
|
|
|
|
window_definition->formatImpl(settings, state, frame);
|
|
|
|
settings.ostr << ")";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
{
|
2016-05-28 15:42:22 +00:00
|
|
|
auto res = std::make_shared<ASTFunction>(*this);
|
2016-05-03 23:19:14 +00:00
|
|
|
res->children.clear();
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2016-05-28 15:42:22 +00:00
|
|
|
return res;
|
2016-05-03 23:19:14 +00:00
|
|
|
}
|
|
|
|
|
2019-02-10 19:11:47 +00:00
|
|
|
|
2023-11-10 12:15:23 +00:00
|
|
|
void ASTFunction::updateTreeHashImpl(SipHash & hash_state, bool ignore_aliases) const
|
2020-08-20 02:01:40 +00:00
|
|
|
{
|
2023-11-10 11:50:16 +00:00
|
|
|
hash_state.update(name.size());
|
|
|
|
hash_state.update(name);
|
2023-11-10 12:15:23 +00:00
|
|
|
ASTWithAlias::updateTreeHashImpl(hash_state, ignore_aliases);
|
2023-11-23 20:10:49 +00:00
|
|
|
|
|
|
|
hash_state.update(nulls_action);
|
|
|
|
if (is_window_function)
|
|
|
|
{
|
|
|
|
hash_state.update(window_name.size());
|
|
|
|
hash_state.update(window_name);
|
2023-11-24 11:35:06 +00:00
|
|
|
if (window_definition)
|
|
|
|
window_definition->updateTreeHashImpl(hash_state, ignore_aliases);
|
2023-11-23 20:10:49 +00:00
|
|
|
}
|
2020-08-20 02:01:40 +00:00
|
|
|
}
|
|
|
|
|
2022-01-24 07:46:30 +00:00
|
|
|
template <typename Container>
|
|
|
|
static ASTPtr createLiteral(const ASTs & arguments)
|
2020-12-04 02:15:44 +00:00
|
|
|
{
|
2022-01-24 07:46:30 +00:00
|
|
|
Container container;
|
2020-12-04 02:15:44 +00:00
|
|
|
|
2022-01-24 07:46:30 +00:00
|
|
|
for (const auto & arg : arguments)
|
2020-12-04 02:15:44 +00:00
|
|
|
{
|
2022-01-24 07:46:30 +00:00
|
|
|
if (const auto * literal = arg->as<ASTLiteral>())
|
2020-12-04 02:15:44 +00:00
|
|
|
{
|
2022-01-24 07:46:30 +00:00
|
|
|
container.push_back(literal->value);
|
2020-12-04 02:15:44 +00:00
|
|
|
}
|
2022-01-24 07:46:30 +00:00
|
|
|
else if (auto * func = arg->as<ASTFunction>())
|
|
|
|
{
|
|
|
|
if (auto func_literal = func->toLiteral())
|
|
|
|
container.push_back(func_literal->as<ASTLiteral>()->value);
|
2022-01-24 12:26:54 +00:00
|
|
|
else
|
|
|
|
return {};
|
2022-01-24 07:46:30 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
/// Some of the Array or Tuple arguments is not literal
|
|
|
|
return {};
|
2020-12-04 02:15:44 +00:00
|
|
|
}
|
|
|
|
|
2022-01-24 07:46:30 +00:00
|
|
|
return std::make_shared<ASTLiteral>(container);
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTPtr ASTFunction::toLiteral() const
|
|
|
|
{
|
|
|
|
if (!arguments)
|
|
|
|
return {};
|
|
|
|
|
|
|
|
if (name == "array")
|
|
|
|
return createLiteral<Array>(arguments->children);
|
|
|
|
|
|
|
|
if (name == "tuple")
|
|
|
|
return createLiteral<Tuple>(arguments->children);
|
|
|
|
|
2020-12-04 02:15:44 +00:00
|
|
|
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.
|
|
|
|
*
|
2022-04-15 22:20:47 +00:00
|
|
|
* Another case is regexp match. Suppose the user types match(URL, 'www.clickhouse.com'). It often means that the user is unaware that . is a metacharacter.
|
2019-02-10 19:11:47 +00:00
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-02-09 03:31:30 +00:00
|
|
|
static bool formatNamedArgWithHiddenValue(IAST * arg, const IAST::FormatSettings & settings, IAST::FormatState & state, IAST::FormatStateStacked frame)
|
|
|
|
{
|
|
|
|
const auto * equals_func = arg->as<ASTFunction>();
|
|
|
|
if (!equals_func || (equals_func->name != "equals"))
|
|
|
|
return false;
|
|
|
|
const auto * expr_list = equals_func->arguments->as<ASTExpressionList>();
|
|
|
|
if (!expr_list)
|
|
|
|
return false;
|
|
|
|
const auto & equal_args = expr_list->children;
|
|
|
|
if (equal_args.size() != 2)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
equal_args[0]->formatImpl(settings, state, frame);
|
|
|
|
settings.ostr << (settings.hilite ? IAST::hilite_operator : "") << " = " << (settings.hilite ? IAST::hilite_none : "");
|
|
|
|
settings.ostr << "'[HIDDEN]'";
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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;
|
2015-08-06 03:26:27 +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, ' ');
|
2023-03-27 16:04:14 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << name << (settings.hilite ? hilite_none : "");
|
2023-03-28 14:06:56 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << "(" << (settings.hilite ? hilite_none : "");
|
2023-03-27 16:04:14 +00:00
|
|
|
settings.ostr << nl_or_nothing;
|
2020-08-28 14:07:14 +00:00
|
|
|
FormatStateStacked frame_nested = frame;
|
|
|
|
frame_nested.need_parens = false;
|
|
|
|
++frame_nested.indent;
|
|
|
|
query->formatImpl(settings, state, frame_nested);
|
2023-03-27 16:04:14 +00:00
|
|
|
settings.ostr << nl_or_nothing << indent_str;
|
2023-03-28 14:06:56 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << ")" << (settings.hilite ? hilite_none : "");
|
2020-08-28 14:07:14 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-09-27 18:04:12 +00:00
|
|
|
|
2016-09-04 00:01:48 +00:00
|
|
|
/// Should this function to be written as operator?
|
2015-08-06 03:26:27 +00:00
|
|
|
bool written = false;
|
2024-02-23 14:22:21 +00:00
|
|
|
if (arguments && !parameters && nulls_action == NullsAction::EMPTY)
|
2015-08-05 21:39:42 +00:00
|
|
|
{
|
2021-09-27 18:04:12 +00:00
|
|
|
/// Unary prefix operators.
|
2015-08-06 03:26:27 +00:00
|
|
|
if (arguments->children.size() == 1)
|
2015-08-05 21:39:42 +00:00
|
|
|
{
|
2015-08-06 03:26:27 +00:00
|
|
|
const char * operators[] =
|
2015-08-05 21:39:42 +00:00
|
|
|
{
|
2021-09-27 18:04:12 +00:00
|
|
|
"negate", "-",
|
|
|
|
"not", "NOT ",
|
2015-08-06 03:26:27 +00:00
|
|
|
nullptr
|
|
|
|
};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2015-08-06 03:26:27 +00:00
|
|
|
for (const char ** func = operators; *func; func += 2)
|
|
|
|
{
|
2021-04-30 16:58:35 +00:00
|
|
|
if (strcasecmp(name.c_str(), func[0]) != 0)
|
2015-08-05 21:39:42 +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>();
|
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;
|
2024-02-15 20:42:47 +00:00
|
|
|
|
2021-05-23 13:34:31 +00:00
|
|
|
// negate always requires parentheses, otherwise -(-1) will be printed as --1
|
2024-02-15 20:42:47 +00:00
|
|
|
bool inside_parens = name == "negate" && (literal_need_parens || (function && function->name == "negate"));
|
|
|
|
|
|
|
|
/// We DO need parentheses around a single literal
|
|
|
|
/// For example, SELECT (NOT 0) + (NOT 0) cannot be transformed into SELECT NOT 0 + NOT 0, since
|
|
|
|
/// this is equal to SELECT NOT (0 + NOT 0)
|
|
|
|
bool outside_parens = frame.need_parens && !inside_parens;
|
2021-05-23 13:34:31 +00:00
|
|
|
|
|
|
|
// do not add extra parentheses for functions inside negate, i.e. -(-toUInt64(-(1)))
|
2024-02-15 20:42:47 +00:00
|
|
|
if (inside_parens)
|
2021-05-23 13:34:31 +00:00
|
|
|
nested_need_parens.need_parens = false;
|
|
|
|
|
2024-02-15 20:42:47 +00:00
|
|
|
if (outside_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
|
|
|
|
2024-02-15 20:42:47 +00:00
|
|
|
if (inside_parens)
|
2021-05-23 13:34:31 +00:00
|
|
|
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
|
|
|
|
2024-02-15 20:42:47 +00:00
|
|
|
if (inside_parens)
|
2021-05-23 13:34:31 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
|
2024-02-15 20:42:47 +00:00
|
|
|
if (outside_parens)
|
2021-03-25 15:38:02 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
|
|
|
|
break;
|
2015-08-05 21:39:42 +00:00
|
|
|
}
|
2015-08-06 03:26:27 +00:00
|
|
|
}
|
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
|
|
|
|
2015-08-06 03:26:27 +00:00
|
|
|
if (!written && arguments->children.size() == 2)
|
|
|
|
{
|
|
|
|
const char * operators[] =
|
2015-08-05 21:39:42 +00:00
|
|
|
{
|
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 ",
|
2015-08-06 03:26:27 +00:00
|
|
|
nullptr
|
|
|
|
};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2015-08-06 03:26:27 +00:00
|
|
|
for (const char ** func = operators; *func; func += 2)
|
|
|
|
{
|
2021-10-31 15:11:46 +00:00
|
|
|
if (name == std::string_view(func[0]))
|
2015-08-05 21:39:42 +00:00
|
|
|
{
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2015-08-06 03:26:27 +00:00
|
|
|
settings.ostr << '(';
|
2015-08-05 21:39:42 +00:00
|
|
|
arguments->children[0]->formatImpl(settings, state, nested_need_parens);
|
2015-08-06 03:26:27 +00:00
|
|
|
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)
|
2015-08-06 03:26:27 +00:00
|
|
|
settings.ostr << ')';
|
2015-08-05 21:39:42 +00:00
|
|
|
written = true;
|
|
|
|
}
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-10-31 15:11:46 +00:00
|
|
|
if (!written && name == "arrayElement"sv)
|
2015-08-05 21:39:42 +00:00
|
|
|
{
|
2019-06-16 22:51:09 +00:00
|
|
|
if (frame.need_parens)
|
|
|
|
settings.ostr << '(';
|
|
|
|
|
2015-08-06 03:26:27 +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);
|
2015-08-06 03:26:27 +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 << ')';
|
2015-08-05 21:39:42 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-10-31 15:11:46 +00:00
|
|
|
if (!written && name == "tupleElement"sv)
|
2015-08-05 21:39:42 +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
|
|
|
}
|
|
|
|
}
|
2015-08-05 21:39:42 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2024-02-15 05:54:18 +00:00
|
|
|
const auto & first_argument = arguments->children[0];
|
|
|
|
const ASTIdentifier * first_argument_identifier = first_argument->as<ASTIdentifier>();
|
|
|
|
const ASTFunction * first_argument_function = first_argument->as<ASTFunction>();
|
|
|
|
bool first_argument_is_tuple = first_argument_function && first_argument_function->name == "tuple";
|
|
|
|
|
|
|
|
/// Only these types of arguments are accepted by the parser of the '->' operator.
|
|
|
|
bool acceptable_first_argument_for_lambda_expression = first_argument_identifier || first_argument_is_tuple;
|
|
|
|
|
|
|
|
if (!written && name == "lambda"sv && acceptable_first_argument_for_lambda_expression)
|
2017-01-12 01:55:14 +00:00
|
|
|
{
|
2021-10-21 07:08:08 +00:00
|
|
|
/// Special case: zero elements tuple in lhs of lambda is printed as ().
|
2017-01-12 01:55:14 +00:00
|
|
|
/// Special case: one-element tuple in lhs of lambda is printed as its element.
|
2024-02-21 18:19:17 +00:00
|
|
|
/// If lambda function is not the first element in the list, it has to be put in parentheses.
|
|
|
|
/// Example: f(x, (y -> z)) should not be printed as f((x, y) -> z).
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2024-02-21 18:19:17 +00:00
|
|
|
if (frame.need_parens || frame.list_element_index > 0)
|
2017-01-12 01:55:14 +00:00
|
|
|
settings.ostr << '(';
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2024-02-15 05:54:18 +00:00
|
|
|
if (first_argument_is_tuple
|
|
|
|
&& first_argument_function->arguments
|
|
|
|
&& (first_argument_function->arguments->children.size() == 1 || first_argument_function->arguments->children.empty()))
|
2017-01-12 01:55:14 +00:00
|
|
|
{
|
2024-02-15 05:54:18 +00:00
|
|
|
if (first_argument_function->arguments->children.size() == 1)
|
|
|
|
first_argument_function->arguments->children[0]->formatImpl(settings, state, nested_need_parens);
|
2021-10-21 07:08:08 +00:00
|
|
|
else
|
|
|
|
settings.ostr << "()";
|
2017-01-12 01:55:14 +00:00
|
|
|
}
|
|
|
|
else
|
2024-02-15 05:54:18 +00:00
|
|
|
first_argument->formatImpl(settings, state, nested_need_parens);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-01-12 01:55:14 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << " -> " << (settings.hilite ? hilite_none : "");
|
|
|
|
arguments->children[1]->formatImpl(settings, state, nested_need_parens);
|
2024-02-21 18:19:17 +00:00
|
|
|
if (frame.need_parens || frame.list_element_index > 0)
|
2017-01-12 01:55:14 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
written = true;
|
|
|
|
}
|
2022-07-09 15:51:59 +00:00
|
|
|
|
|
|
|
if (!written && name == "viewIfPermitted"sv)
|
|
|
|
{
|
|
|
|
/// viewIfPermitted() needs special formatting: ELSE instead of comma between arguments, and better indents too.
|
|
|
|
const auto * nl_or_nothing = settings.one_line ? "" : "\n";
|
|
|
|
auto indent0 = settings.one_line ? "" : String(4u * frame.indent, ' ');
|
|
|
|
auto indent1 = settings.one_line ? "" : String(4u * (frame.indent + 1), ' ');
|
|
|
|
auto indent2 = settings.one_line ? "" : String(4u * (frame.indent + 2), ' ');
|
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << name << "(" << (settings.hilite ? hilite_none : "") << nl_or_nothing;
|
|
|
|
FormatStateStacked frame_nested = frame;
|
|
|
|
frame_nested.need_parens = false;
|
|
|
|
frame_nested.indent += 2;
|
|
|
|
arguments->children[0]->formatImpl(settings, state, frame_nested);
|
|
|
|
settings.ostr << nl_or_nothing << indent1 << (settings.hilite ? hilite_keyword : "") << (settings.one_line ? " " : "")
|
|
|
|
<< "ELSE " << (settings.hilite ? hilite_none : "") << nl_or_nothing << indent2;
|
|
|
|
arguments->children[1]->formatImpl(settings, state, frame_nested);
|
|
|
|
settings.ostr << nl_or_nothing << indent0 << ")";
|
|
|
|
return;
|
|
|
|
}
|
2015-08-06 03:26:27 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2015-08-06 03:26:27 +00:00
|
|
|
if (!written && arguments->children.size() >= 2)
|
|
|
|
{
|
|
|
|
const char * operators[] =
|
|
|
|
{
|
2017-12-09 20:56:53 +00:00
|
|
|
"and", " AND ",
|
|
|
|
"or", " OR ",
|
2015-08-06 03:26:27 +00:00
|
|
|
nullptr
|
|
|
|
};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2015-08-06 03:26:27 +00:00
|
|
|
for (const char ** func = operators; *func; func += 2)
|
2015-08-05 21:39:42 +00:00
|
|
|
{
|
2021-10-31 15:11:46 +00:00
|
|
|
if (name == std::string_view(func[0]))
|
2015-08-05 21:39:42 +00:00
|
|
|
{
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2015-08-06 03:26:27 +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 : "");
|
2022-08-03 15:00:24 +00:00
|
|
|
if (arguments->children[i]->as<ASTSetQuery>())
|
|
|
|
settings.ostr << "SETTINGS ";
|
2015-08-06 03:26:27 +00:00
|
|
|
arguments->children[i]->formatImpl(settings, state, nested_need_parens);
|
|
|
|
}
|
2018-05-17 15:17:07 +00:00
|
|
|
if (frame.need_parens)
|
2015-08-06 03:26:27 +00:00
|
|
|
settings.ostr << ')';
|
|
|
|
written = true;
|
2015-08-05 21:39:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-10-31 15:11:46 +00:00
|
|
|
if (!written && name == "array"sv)
|
2015-08-05 21:39:42 +00:00
|
|
|
{
|
2015-08-06 03:26:27 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << '[' << (settings.hilite ? hilite_none : "");
|
|
|
|
for (size_t i = 0; i < arguments->children.size(); ++i)
|
2015-08-05 21:39:42 +00:00
|
|
|
{
|
2015-08-06 03:26:27 +00:00
|
|
|
if (i != 0)
|
|
|
|
settings.ostr << ", ";
|
2022-08-03 15:00:24 +00:00
|
|
|
if (arguments->children[i]->as<ASTSetQuery>())
|
|
|
|
settings.ostr << "SETTINGS ";
|
2015-08-06 03:26:27 +00:00
|
|
|
arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens);
|
2015-08-05 21:39:42 +00:00
|
|
|
}
|
2015-08-06 03:26:27 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << ']' << (settings.hilite ? hilite_none : "");
|
|
|
|
written = true;
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-10-31 15:11:46 +00:00
|
|
|
if (!written && arguments->children.size() >= 2 && name == "tuple"sv)
|
2015-08-06 03:26:27 +00:00
|
|
|
{
|
2023-02-09 13:02:26 +00:00
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << ((frame.need_parens && !alias.empty()) ? "tuple" : "") << '('
|
|
|
|
<< (settings.hilite ? hilite_none : "");
|
2015-08-06 03:26:27 +00:00
|
|
|
for (size_t i = 0; i < arguments->children.size(); ++i)
|
2015-08-05 21:39:42 +00:00
|
|
|
{
|
2015-08-06 03:26:27 +00:00
|
|
|
if (i != 0)
|
|
|
|
settings.ostr << ", ";
|
2022-08-03 15:00:24 +00:00
|
|
|
if (arguments->children[i]->as<ASTSetQuery>())
|
|
|
|
settings.ostr << "SETTINGS ";
|
2015-08-06 03:26:27 +00:00
|
|
|
arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens);
|
2015-08-05 21:39:42 +00:00
|
|
|
}
|
2015-08-06 03:26:27 +00:00
|
|
|
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 << ", ";
|
2022-08-03 15:00:24 +00:00
|
|
|
if (arguments->children[i]->as<ASTSetQuery>())
|
|
|
|
settings.ostr << "SETTINGS ";
|
2020-11-02 06:05:53 +00:00
|
|
|
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;
|
|
|
|
}
|
2015-08-06 03:26:27 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2020-12-18 00:21:23 +00:00
|
|
|
if (written)
|
2015-08-06 03:26:27 +00:00
|
|
|
{
|
2022-06-13 22:39:18 +00:00
|
|
|
return finishFormatWithWindow(settings, state, frame);
|
2020-12-18 00:21:23 +00:00
|
|
|
}
|
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
|
|
|
|
2023-01-25 13:24:53 +00:00
|
|
|
FunctionSecretArgumentsFinder::Result secret_arguments;
|
2022-11-11 15:26:04 +00:00
|
|
|
if (!settings.show_secrets)
|
2024-03-01 20:58:22 +00:00
|
|
|
secret_arguments = FunctionSecretArgumentsFinderAST(*this).getResult();
|
2022-11-11 15:26:04 +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 << ", ";
|
2023-01-25 13:24:53 +00:00
|
|
|
|
|
|
|
const auto & argument = arguments->children[i];
|
|
|
|
if (argument->as<ASTSetQuery>())
|
2022-08-03 15:00:24 +00:00
|
|
|
settings.ostr << "SETTINGS ";
|
2019-02-10 19:11:47 +00:00
|
|
|
|
2024-02-09 03:31:30 +00:00
|
|
|
if (!settings.show_secrets)
|
2022-11-11 15:26:04 +00:00
|
|
|
{
|
2024-02-09 03:31:30 +00:00
|
|
|
if (secret_arguments.start <= i && i < secret_arguments.start + secret_arguments.count)
|
|
|
|
{
|
|
|
|
if (secret_arguments.are_named)
|
|
|
|
{
|
|
|
|
assert_cast<const ASTFunction *>(argument.get())->arguments->children[0]->formatImpl(settings, state, nested_dont_need_parens);
|
|
|
|
settings.ostr << (settings.hilite ? hilite_operator : "") << " = " << (settings.hilite ? hilite_none : "");
|
|
|
|
}
|
|
|
|
settings.ostr << "'[HIDDEN]'";
|
|
|
|
if (size <= secret_arguments.start + secret_arguments.count && !secret_arguments.are_named)
|
|
|
|
break; /// All other arguments should also be hidden.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ASTFunction * function = argument->as<ASTFunction>();
|
|
|
|
if (function && function->arguments && std::count(secret_arguments.nested_maps.begin(), secret_arguments.nested_maps.end(), function->name) != 0)
|
2023-01-25 13:24:53 +00:00
|
|
|
{
|
2024-02-09 03:31:30 +00:00
|
|
|
/// headers('foo' = '[HIDDEN]', 'bar' = '[HIDDEN]')
|
|
|
|
settings.ostr << (settings.hilite ? hilite_function : "") << function->name << (settings.hilite ? hilite_none : "") << "(";
|
|
|
|
for (size_t j = 0; j < function->arguments->children.size(); ++j)
|
|
|
|
{
|
|
|
|
if (j != 0)
|
|
|
|
settings.ostr << ", ";
|
|
|
|
auto inner_arg = function->arguments->children[j];
|
|
|
|
if (!formatNamedArgWithHiddenValue(inner_arg.get(), settings, state, nested_dont_need_parens))
|
|
|
|
inner_arg->formatImpl(settings, state, nested_dont_need_parens);
|
|
|
|
}
|
|
|
|
settings.ostr << ")";
|
|
|
|
continue;
|
2023-01-25 13:24:53 +00:00
|
|
|
}
|
2022-11-11 15:26:04 +00:00
|
|
|
}
|
2020-12-18 00:21:23 +00:00
|
|
|
|
2022-11-14 18:28:19 +00:00
|
|
|
if ((i == 1) && special_hilite_regexp
|
2023-01-25 13:24:53 +00:00
|
|
|
&& highlightStringLiteralWithMetacharacters(argument, settings, "|()^$.[]?*+{:-"))
|
2022-11-14 18:28:19 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-02-21 18:19:17 +00:00
|
|
|
nested_dont_need_parens.list_element_index = i;
|
2023-01-25 13:24:53 +00:00
|
|
|
argument->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 : "");
|
|
|
|
|
2022-06-13 22:39:18 +00:00
|
|
|
return finishFormatWithWindow(settings, state, frame);
|
2015-08-06 03:26:27 +00:00
|
|
|
}
|
|
|
|
|
2022-11-11 15:26:04 +00:00
|
|
|
bool ASTFunction::hasSecretParts() const
|
|
|
|
{
|
2024-03-01 20:58:22 +00:00
|
|
|
return (FunctionSecretArgumentsFinderAST(*this).getResult().hasSecrets()) || childrenHaveSecretParts();
|
2022-11-11 15:26:04 +00:00
|
|
|
}
|
|
|
|
|
2021-07-03 20:17:02 +00:00
|
|
|
String getFunctionName(const IAST * ast)
|
|
|
|
{
|
|
|
|
String res;
|
|
|
|
if (tryGetFunctionNameInto(ast, res))
|
|
|
|
return res;
|
2023-01-23 21:13:58 +00:00
|
|
|
if (ast)
|
|
|
|
throw Exception(ErrorCodes::UNEXPECTED_AST_STRUCTURE, "{} is not an function", queryToString(*ast));
|
|
|
|
throw Exception(ErrorCodes::UNEXPECTED_AST_STRUCTURE, "AST node is nullptr");
|
2021-07-03 20:17:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|