mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-26 17:41:59 +00:00
Merge pull request #36167 from kitaisreal/special-operators-broken-aliases-fix
Fix broken aliases during parsing of special operators
This commit is contained in:
commit
bac1f12a2b
@ -298,28 +298,69 @@ namespace
|
||||
{
|
||||
bool parseCastAs(IParser::Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
/// expr AS type
|
||||
/** Possible variants for cast operator cast(expr [[AS] alias_1] AS Type), cast(expr [[AS] alias_1], type_expr [[as] alias_2]).
|
||||
* First try to match with cast(expr [[AS] alias_1] AS Type)
|
||||
* Then try to match with cast(expr [[AS] alias_1], type_expr [[as] alias_2]).
|
||||
*/
|
||||
|
||||
ASTPtr expr_node;
|
||||
ASTPtr type_node;
|
||||
ASTPtr identifier_node;
|
||||
|
||||
if (ParserExpression().parse(pos, expr_node, expected))
|
||||
{
|
||||
if (ParserKeyword("AS").ignore(pos, expected))
|
||||
ParserKeyword as_keyword_parser("AS");
|
||||
bool parse_as = as_keyword_parser.ignore(pos, expected);
|
||||
|
||||
/// CAST (a b AS UInt32) OR CAST (a b, expr)
|
||||
|
||||
if (!parse_as && ParserIdentifier().parse(pos, identifier_node, expected))
|
||||
{
|
||||
if (ParserDataType().parse(pos, type_node, expected))
|
||||
expr_node->setAlias(getIdentifierName(identifier_node));
|
||||
parse_as = as_keyword_parser.ignore(pos, expected);
|
||||
}
|
||||
|
||||
if (parse_as)
|
||||
{
|
||||
/// CAST (a AS Type) OR CAST (a AS b AS Type) OR CAST (a AS b, expr)
|
||||
|
||||
auto begin = pos;
|
||||
auto expected_copy = expected;
|
||||
bool next_identifier = ParserIdentifier().ignore(begin, expected_copy);
|
||||
bool next_identifier_with_comma = next_identifier && ParserToken(TokenType::Comma).ignore(begin, expected_copy);
|
||||
bool next_identifier_with_as
|
||||
= next_identifier && !next_identifier_with_comma && as_keyword_parser.ignore(begin, expected_copy);
|
||||
|
||||
if (next_identifier_with_as)
|
||||
{
|
||||
if (ParserIdentifier().parse(pos, identifier_node, expected) && as_keyword_parser.ignore(pos, expected))
|
||||
expr_node->setAlias(getIdentifierName(identifier_node));
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!next_identifier_with_comma && ParserDataType().parse(pos, type_node, expected))
|
||||
{
|
||||
node = createFunctionCast(expr_node, type_node);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (ParserToken(TokenType::Comma).ignore(pos, expected))
|
||||
|
||||
/// CAST(a AS b, expr)
|
||||
|
||||
if (parse_as)
|
||||
{
|
||||
if (ParserExpression().parse(pos, type_node, expected))
|
||||
{
|
||||
node = makeASTFunction("CAST", expr_node, type_node);
|
||||
return true;
|
||||
}
|
||||
if (ParserIdentifier().parse(pos, identifier_node, expected))
|
||||
expr_node->setAlias(getIdentifierName(identifier_node));
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ParserToken(TokenType::Comma).ignore(pos, expected)
|
||||
&& ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, type_node, expected))
|
||||
{
|
||||
node = makeASTFunction("CAST", expr_node, type_node);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,6 +372,9 @@ namespace
|
||||
/// Either SUBSTRING(expr FROM start) or SUBSTRING(expr FROM start FOR length) or SUBSTRING(expr, start, length)
|
||||
/// The latter will be parsed normally as a function later.
|
||||
|
||||
ParserKeyword as_keyword_parser("AS");
|
||||
ParserIdentifier identifier_parser;
|
||||
|
||||
ASTPtr expr_node;
|
||||
ASTPtr start_node;
|
||||
ASTPtr length_node;
|
||||
@ -338,35 +382,65 @@ namespace
|
||||
if (!ParserExpression().parse(pos, expr_node, expected))
|
||||
return false;
|
||||
|
||||
if (pos->type != TokenType::Comma)
|
||||
auto from_keyword_parser = ParserKeyword("FROM");
|
||||
bool from_exists = from_keyword_parser.check(pos, expected);
|
||||
|
||||
if (!from_exists && pos->type != TokenType::Comma)
|
||||
{
|
||||
if (!ParserKeyword("FROM").ignore(pos, expected))
|
||||
ASTPtr identifier_node;
|
||||
bool parsed_as = as_keyword_parser.ignore(pos, expected);
|
||||
bool parsed_identifer = identifier_parser.parse(pos, identifier_node, expected);
|
||||
|
||||
if (parsed_as && !parsed_identifer)
|
||||
return false;
|
||||
|
||||
if (parsed_identifer)
|
||||
expr_node->setAlias(getIdentifierName(identifier_node));
|
||||
|
||||
from_exists = from_keyword_parser.check(pos, expected);
|
||||
}
|
||||
else
|
||||
|
||||
if (pos->type == TokenType::Comma)
|
||||
{
|
||||
if (from_exists)
|
||||
return false;
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
if (!ParserExpression().parse(pos, start_node, expected))
|
||||
return false;
|
||||
|
||||
if (pos->type != TokenType::ClosingRoundBracket)
|
||||
auto for_keyword_parser = ParserKeyword("FOR");
|
||||
bool for_exists = for_keyword_parser.check(pos, expected);
|
||||
if (!for_exists && pos->type != TokenType::Comma)
|
||||
{
|
||||
if (pos->type != TokenType::Comma)
|
||||
{
|
||||
if (!ParserKeyword("FOR").ignore(pos, expected))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++pos;
|
||||
}
|
||||
|
||||
if (!ParserExpression().parse(pos, length_node, expected))
|
||||
ASTPtr identifier_node;
|
||||
bool parsed_as = as_keyword_parser.ignore(pos, expected);
|
||||
bool parsed_identifer = identifier_parser.parse(pos, identifier_node, expected);
|
||||
if (parsed_as && !parsed_identifer)
|
||||
return false;
|
||||
|
||||
if (parsed_identifer)
|
||||
start_node->setAlias(getIdentifierName(identifier_node));
|
||||
|
||||
for_exists = for_keyword_parser.check(pos, expected);
|
||||
}
|
||||
|
||||
bool need_parse_length_expression = for_exists;
|
||||
if (pos->type == TokenType::Comma)
|
||||
{
|
||||
if (for_exists)
|
||||
return false;
|
||||
|
||||
++pos;
|
||||
need_parse_length_expression = true;
|
||||
}
|
||||
|
||||
if (need_parse_length_expression
|
||||
&& !ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, length_node, expected))
|
||||
return false;
|
||||
|
||||
/// Convert to canonical representation in functional form: SUBSTRING(expr, start, length)
|
||||
if (length_node)
|
||||
node = makeASTFunction("substring", expr_node, start_node, length_node);
|
||||
@ -378,7 +452,7 @@ namespace
|
||||
|
||||
bool parseTrim(bool trim_left, bool trim_right, IParser::Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
/// Handles all possible TRIM/LTRIM/RTRIM call variants
|
||||
/// Handles all possible TRIM/LTRIM/RTRIM call variants ([[LEADING|TRAILING|BOTH] trim_character FROM] input_string)
|
||||
|
||||
std::string func_name;
|
||||
bool char_override = false;
|
||||
@ -414,7 +488,26 @@ namespace
|
||||
{
|
||||
if (!ParserExpression().parse(pos, to_remove, expected))
|
||||
return false;
|
||||
if (!ParserKeyword("FROM").ignore(pos, expected))
|
||||
|
||||
auto from_keyword_parser = ParserKeyword("FROM");
|
||||
bool from_exists = from_keyword_parser.check(pos, expected);
|
||||
|
||||
if (!from_exists)
|
||||
{
|
||||
ASTPtr identifier_node;
|
||||
bool parsed_as = ParserKeyword("AS").ignore(pos, expected);
|
||||
bool parsed_identifer = ParserIdentifier().parse(pos, identifier_node, expected);
|
||||
|
||||
if (parsed_as && !parsed_identifer)
|
||||
return false;
|
||||
|
||||
if (parsed_identifer)
|
||||
to_remove->setAlias(getIdentifierName(identifier_node));
|
||||
|
||||
from_exists = from_keyword_parser.check(pos, expected);
|
||||
}
|
||||
|
||||
if (!from_exists)
|
||||
return false;
|
||||
|
||||
auto quote_meta_func_node = std::make_shared<ASTFunction>();
|
||||
@ -429,7 +522,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
if (!ParserExpression().parse(pos, expr_node, expected))
|
||||
if (!ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, expr_node, expected))
|
||||
return false;
|
||||
|
||||
/// Convert to regexp replace function call
|
||||
@ -440,33 +533,24 @@ namespace
|
||||
auto pattern_list_args = std::make_shared<ASTExpressionList>();
|
||||
if (trim_left && trim_right)
|
||||
{
|
||||
pattern_list_args->children = {
|
||||
std::make_shared<ASTLiteral>("^["),
|
||||
to_remove,
|
||||
std::make_shared<ASTLiteral>("]+|["),
|
||||
to_remove,
|
||||
std::make_shared<ASTLiteral>("]+$")
|
||||
};
|
||||
pattern_list_args->children
|
||||
= {std::make_shared<ASTLiteral>("^["),
|
||||
to_remove,
|
||||
std::make_shared<ASTLiteral>("]+|["),
|
||||
to_remove,
|
||||
std::make_shared<ASTLiteral>("]+$")};
|
||||
func_name = "replaceRegexpAll";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (trim_left)
|
||||
{
|
||||
pattern_list_args->children = {
|
||||
std::make_shared<ASTLiteral>("^["),
|
||||
to_remove,
|
||||
std::make_shared<ASTLiteral>("]+")
|
||||
};
|
||||
pattern_list_args->children = {std::make_shared<ASTLiteral>("^["), to_remove, std::make_shared<ASTLiteral>("]+")};
|
||||
}
|
||||
else
|
||||
{
|
||||
/// trim_right == false not possible
|
||||
pattern_list_args->children = {
|
||||
std::make_shared<ASTLiteral>("["),
|
||||
to_remove,
|
||||
std::make_shared<ASTLiteral>("]+$")
|
||||
};
|
||||
pattern_list_args->children = {std::make_shared<ASTLiteral>("["), to_remove, std::make_shared<ASTLiteral>("]+$")};
|
||||
}
|
||||
func_name = "replaceRegexpOne";
|
||||
}
|
||||
@ -506,6 +590,9 @@ namespace
|
||||
|
||||
bool parseExtract(IParser::Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
/// First try to match with date extract operator EXTRACT(part FROM date)
|
||||
/// Then with function extract(haystack, pattern)
|
||||
|
||||
IParser::Pos begin = pos;
|
||||
IntervalKind interval_kind;
|
||||
|
||||
@ -514,7 +601,7 @@ namespace
|
||||
ASTPtr expr;
|
||||
|
||||
ParserKeyword s_from("FROM");
|
||||
ParserExpression elem_parser;
|
||||
ParserExpressionWithOptionalAlias elem_parser(true /*allow_alias_without_as_keyword*/);
|
||||
|
||||
if (s_from.ignore(pos, expected) && elem_parser.parse(pos, expr, expected))
|
||||
{
|
||||
@ -526,7 +613,7 @@ namespace
|
||||
pos = begin;
|
||||
|
||||
ASTPtr expr_list;
|
||||
if (!ParserExpressionList(false, false).parse(pos, expr_list, expected))
|
||||
if (!ParserExpressionList(true /*allow_alias_without_as_keyword*/).parse(pos, expr_list, expected))
|
||||
return false;
|
||||
|
||||
auto res = std::make_shared<ASTFunction>();
|
||||
@ -539,28 +626,57 @@ namespace
|
||||
|
||||
bool parsePosition(IParser::Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
ASTPtr expr_list_node;
|
||||
if (!ParserExpressionList(false, false).parse(pos, expr_list_node, expected))
|
||||
return false;
|
||||
/// First try to match with position(needle IN haystack)
|
||||
/// Then with position(haystack, needle[, start_pos])
|
||||
|
||||
ASTExpressionList * expr_list = typeid_cast<ASTExpressionList *>(expr_list_node.get());
|
||||
if (expr_list && expr_list->children.size() == 1)
|
||||
ParserExpressionWithOptionalAlias expr_parser(true /*allow_alias_without_as_keyword*/);
|
||||
|
||||
ASTPtr first_arg_expr_node;
|
||||
if (!expr_parser.parse(pos, first_arg_expr_node, expected))
|
||||
{
|
||||
ASTFunction * func_in = typeid_cast<ASTFunction *>(expr_list->children[0].get());
|
||||
if (func_in && func_in->name == "in")
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTFunction * func_in = typeid_cast<ASTFunction *>(first_arg_expr_node.get());
|
||||
if (func_in && func_in->name == "in")
|
||||
{
|
||||
ASTExpressionList * in_args = typeid_cast<ASTExpressionList *>(func_in->arguments.get());
|
||||
if (in_args && in_args->children.size() == 2)
|
||||
{
|
||||
ASTExpressionList * in_args = typeid_cast<ASTExpressionList *>(func_in->arguments.get());
|
||||
if (in_args && in_args->children.size() == 2)
|
||||
{
|
||||
node = makeASTFunction("position", in_args->children[1], in_args->children[0]);
|
||||
return true;
|
||||
}
|
||||
node = makeASTFunction("position", in_args->children[1], in_args->children[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos->type != TokenType::Comma)
|
||||
return false;
|
||||
++pos;
|
||||
|
||||
ASTPtr second_arg_expr_node;
|
||||
if (!expr_parser.parse(pos, second_arg_expr_node, expected))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTPtr start_pos_expr_node;
|
||||
if (pos->type == TokenType::Comma)
|
||||
{
|
||||
++pos;
|
||||
|
||||
if (!expr_parser.parse(pos, start_pos_expr_node, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
auto arguments = std::make_shared<ASTExpressionList>();
|
||||
arguments->children.push_back(std::move(first_arg_expr_node));
|
||||
arguments->children.push_back(std::move(second_arg_expr_node));
|
||||
|
||||
if (start_pos_expr_node)
|
||||
arguments->children.push_back(std::move(start_pos_expr_node));
|
||||
|
||||
auto res = std::make_shared<ASTFunction>();
|
||||
res->name = "position";
|
||||
res->arguments = expr_list_node;
|
||||
res->arguments = std::move(arguments);
|
||||
res->children.push_back(res->arguments);
|
||||
node = std::move(res);
|
||||
return true;
|
||||
@ -568,6 +684,9 @@ namespace
|
||||
|
||||
bool parseDateAdd(const char * function_name, IParser::Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
/// First to match with function(unit, offset, timestamp)
|
||||
/// Then with function(offset, timestamp)
|
||||
|
||||
ASTPtr timestamp_node;
|
||||
ASTPtr offset_node;
|
||||
|
||||
@ -575,19 +694,18 @@ namespace
|
||||
ASTPtr interval_func_node;
|
||||
if (parseIntervalKind(pos, expected, interval_kind))
|
||||
{
|
||||
/// function(unit, offset, timestamp)
|
||||
if (pos->type != TokenType::Comma)
|
||||
return false;
|
||||
++pos;
|
||||
|
||||
if (!ParserExpression().parse(pos, offset_node, expected))
|
||||
if (!ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, offset_node, expected))
|
||||
return false;
|
||||
|
||||
if (pos->type != TokenType::Comma)
|
||||
return false;
|
||||
++pos;
|
||||
|
||||
if (!ParserExpression().parse(pos, timestamp_node, expected))
|
||||
if (!ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, timestamp_node, expected))
|
||||
return false;
|
||||
auto interval_expr_list_args = std::make_shared<ASTExpressionList>();
|
||||
interval_expr_list_args->children = {offset_node};
|
||||
@ -600,7 +718,7 @@ namespace
|
||||
else
|
||||
{
|
||||
ASTPtr expr_list;
|
||||
if (!ParserExpressionList(false, false).parse(pos, expr_list, expected))
|
||||
if (!ParserExpressionList(true /*allow_alias_without_as_keyword*/).parse(pos, expr_list, expected))
|
||||
return false;
|
||||
|
||||
auto res = std::make_shared<ASTFunction>();
|
||||
@ -617,39 +735,59 @@ namespace
|
||||
|
||||
bool parseDateDiff(IParser::Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
/// First to match with dateDiff(unit, startdate, enddate, [timezone])
|
||||
/// Then with dateDiff('unit', startdate, enddate, [timezone])
|
||||
|
||||
ASTPtr left_node;
|
||||
ASTPtr right_node;
|
||||
|
||||
IntervalKind interval_kind;
|
||||
if (!parseIntervalKind(pos, expected, interval_kind))
|
||||
if (parseIntervalKind(pos, expected, interval_kind))
|
||||
{
|
||||
ASTPtr expr_list;
|
||||
if (!ParserExpressionList(false, false).parse(pos, expr_list, expected))
|
||||
if (pos->type != TokenType::Comma)
|
||||
return false;
|
||||
++pos;
|
||||
|
||||
if (!ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, left_node, expected))
|
||||
return false;
|
||||
|
||||
auto res = std::make_shared<ASTFunction>();
|
||||
res->name = "dateDiff";
|
||||
res->arguments = expr_list;
|
||||
res->children.push_back(res->arguments);
|
||||
node = std::move(res);
|
||||
if (pos->type != TokenType::Comma)
|
||||
return false;
|
||||
++pos;
|
||||
|
||||
if (!ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, right_node, expected))
|
||||
return false;
|
||||
|
||||
ASTPtr timezone_node;
|
||||
|
||||
if (pos->type == TokenType::Comma)
|
||||
{
|
||||
/// Optional timezone
|
||||
++pos;
|
||||
|
||||
if (!ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, timezone_node, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
auto interval_literal = std::make_shared<ASTLiteral>(interval_kind.toDateDiffUnit());
|
||||
if (timezone_node)
|
||||
node = makeASTFunction("dateDiff", std::move(interval_literal), std::move(left_node), std::move(right_node), std::move(timezone_node));
|
||||
else
|
||||
node = makeASTFunction("dateDiff", std::move(interval_literal), std::move(left_node), std::move(right_node));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pos->type != TokenType::Comma)
|
||||
return false;
|
||||
++pos;
|
||||
|
||||
if (!ParserExpression().parse(pos, left_node, expected))
|
||||
ASTPtr expr_list;
|
||||
if (!ParserExpressionList(true /*allow_alias_without_as_keyword*/).parse(pos, expr_list, expected))
|
||||
return false;
|
||||
|
||||
if (pos->type != TokenType::Comma)
|
||||
return false;
|
||||
++pos;
|
||||
auto res = std::make_shared<ASTFunction>();
|
||||
res->name = "dateDiff";
|
||||
res->arguments = expr_list;
|
||||
res->children.push_back(res->arguments);
|
||||
node = std::move(res);
|
||||
|
||||
if (!ParserExpression().parse(pos, right_node, expected))
|
||||
return false;
|
||||
|
||||
node = makeASTFunction("dateDiff", std::make_shared<ASTLiteral>(interval_kind.toDateDiffUnit()), left_node, right_node);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -12,14 +12,14 @@ echo 'SELECT '"$(perl -e 'print "CAST(" x 100')"'a, b'"$(perl -e 'print ")" x 10
|
||||
echo 'SELECT '"$(perl -e 'print "CAST(" x 100')"'a AS b'"$(perl -e 'print ")" x 100')" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'Syntax error'
|
||||
echo 'SELECT '"$(perl -e 'print "CAST(" x 100')"'1'"$(perl -e 'print ", '"'UInt8'"')" x 100')" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000
|
||||
echo 'SELECT '"$(perl -e 'print "CAST(" x 100')"'1'"$(perl -e 'print " AS UInt8)" x 100')" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000
|
||||
|
||||
echo "SELECT fo,22222?LUTAY(SELECT(NOT CAUTAY(SELECT(NOT CAST(NOTT(NOT CAST(NOT NOT LEfT(NOT coARRAYlumnsFLuTAY(SELECT(NO0?LUTAY(SELECT(NOT CAUTAY(SELECT(NOT CAST(NOTT(NOT CAST(NOT NOT LEfT(NOT coARRAYlumnsFLuTAY(SELECT(NOTAYTAY(SELECT(NOTAYEFAULT(fo,22222?LUTAY(%SELECT(NOT CAST(NOT NOTAYTAY(SELECT(NOTAYEFAULT(fo,22222?LUTAY(SELECT(NOT CAST(NOT NOT (NOe)))))))))))))))))))))))))))))))))" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'Syntax error'
|
||||
echo "SELECT position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(a b))))))))))))))))))))" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'Syntax error'
|
||||
echo "SELECT position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(a, b))))))))))))))))))))" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'UNKNOWN_IDENTIFIER'
|
||||
echo "SELECT position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(a, b, c))))))))))))))))))))" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'UNKNOWN_IDENTIFIER'
|
||||
|
||||
echo 'SELECT '"$(perl -e 'print "position(" x 100')"'x'"$(perl -e 'print ")" x 100')" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'UNKNOWN_IDENTIFIER'
|
||||
echo "SELECT position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(a b))))))))))))))))))))" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'Syntax error'
|
||||
echo "SELECT position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(a, b))))))))))))))))))))" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'Syntax error'
|
||||
echo "SELECT position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(position(a, b, c))))))))))))))))))))" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'Syntax error'
|
||||
|
||||
echo 'SELECT '"$(perl -e 'print "position(" x 100')"'x'"$(perl -e 'print ")" x 100')" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'Syntax error'
|
||||
echo 'SELECT '"$(perl -e 'print "position(" x 100')"'x y'"$(perl -e 'print ")" x 100')" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'Syntax error'
|
||||
echo 'SELECT '"$(perl -e 'print "position(" x 100')"'x IN y'"$(perl -e 'print ")" x 100')" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'UNKNOWN_IDENTIFIER'
|
||||
echo 'SELECT '"$(perl -e 'print "position(" x 100')"'x IN y'"$(perl -e 'print ")" x 100')" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'Syntax error'
|
||||
echo 'SELECT '"$(perl -e 'print "position(" x 100')"'x'"$(perl -e 'print " IN x)" x 100')" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'UNKNOWN_IDENTIFIER'
|
||||
echo 'SELECT '"$(perl -e 'print "position(" x 100')"'x'"$(perl -e 'print ", x)" x 100')" | ${CLICKHOUSE_LOCAL} --max_parser_depth 10000 2>&1 | grep -cF 'UNKNOWN_IDENTIFIER'
|
||||
|
@ -0,0 +1,60 @@
|
||||
1234
|
||||
1234 1234
|
||||
1234 1234
|
||||
1234 1234
|
||||
1234 1234
|
||||
1234 1234
|
||||
1234
|
||||
1234 1234
|
||||
1234 1234
|
||||
1234 UInt32
|
||||
1234 UInt32
|
||||
1234 1234 UInt32
|
||||
1234 1234 UInt32
|
||||
234
|
||||
234 1234
|
||||
234 1234
|
||||
234 2
|
||||
234 2
|
||||
234 1234 2
|
||||
234 1234 2
|
||||
234 1234 2
|
||||
23
|
||||
23 2
|
||||
23 2
|
||||
234 1234 2 3
|
||||
234 1234 2 3
|
||||
bca a abca
|
||||
bca a abca
|
||||
bca abca
|
||||
bca abca
|
||||
bca a
|
||||
bca a
|
||||
bca
|
||||
abc a abca
|
||||
abc a abca
|
||||
bc a abca
|
||||
bc a abca
|
||||
5 2019-05-05
|
||||
5 2019-05-05
|
||||
123 1234 123
|
||||
123 1234 123
|
||||
1 123 1234
|
||||
0 123 1234
|
||||
0 123 1234
|
||||
2019-05-06 1 2019-05-05
|
||||
2019-05-06 1 2019-05-05
|
||||
2019-05-06 1 2019-05-05
|
||||
2019-05-06 1 2019-05-05
|
||||
2019-05-04 1 2019-05-05
|
||||
2019-05-04 1 2019-05-05
|
||||
2019-05-04 1 2019-05-05
|
||||
2019-05-04 1 2019-05-05
|
||||
1 2019-05-05 2019-05-06
|
||||
1 2019-05-05 2019-05-06
|
||||
1 2019-05-05 2019-05-06
|
||||
1 2019-05-05 2019-05-06
|
||||
1 2019-05-05 2019-05-06
|
||||
1 2019-05-05 2019-05-06
|
||||
1 2019-05-05 2019-05-06
|
||||
1 2019-05-05 2019-05-06
|
@ -0,0 +1,121 @@
|
||||
-- CAST expression
|
||||
|
||||
-- cast(expr [[AS] alias_1] AS Type)
|
||||
|
||||
SELECT cast('1234' AS UInt32);
|
||||
SELECT cast('1234' AS lhs AS UInt32), lhs;
|
||||
SELECT cast('1234' lhs AS UInt32), lhs;
|
||||
SELECT cast(('1234' AS lhs) AS UInt32), lhs;
|
||||
SELECT cast(('1234' AS lhs) rhs AS UInt32), rhs;
|
||||
SELECT cast(('1234' AS lhs) AS rhs AS UInt32), rhs;
|
||||
|
||||
-- cast(expr [[AS] alias_1], type_expr [[as] alias_2])
|
||||
|
||||
SELECT cast('1234', 'UInt32');
|
||||
SELECT cast('1234' AS lhs, 'UInt32'), lhs;
|
||||
SELECT cast('1234' lhs, 'UInt32'), lhs;
|
||||
SELECT cast('1234', 'UInt32' AS rhs), rhs;
|
||||
SELECT cast('1234', 'UInt32' rhs), rhs;
|
||||
SELECT cast('1234' AS lhs, 'UInt32' AS rhs), lhs, rhs;
|
||||
SELECT cast('1234' lhs, 'UInt32' rhs), lhs, rhs;
|
||||
|
||||
-- SUBSTRING expression
|
||||
|
||||
-- SUBSTRING(expr FROM start)
|
||||
|
||||
SELECT substring('1234' FROM 2);
|
||||
SELECT substring('1234' AS lhs FROM 2), lhs;
|
||||
SELECT substring('1234' lhs FROM 2), lhs;
|
||||
SELECT substring('1234' FROM 2 AS rhs), rhs;
|
||||
SELECT substring('1234' FROM 2 rhs), rhs;
|
||||
SELECT substring('1234' AS lhs FROM 2 AS rhs), lhs, rhs;
|
||||
SELECT substring('1234' lhs FROM 2 rhs), lhs, rhs;
|
||||
SELECT substring(('1234' AS lhs) FROM (2 AS rhs)), lhs, rhs;
|
||||
|
||||
-- SUBSTRING(expr FROM start FOR length)
|
||||
|
||||
SELECT substring('1234' FROM 2 FOR 2);
|
||||
SELECT substring('1234' FROM 2 FOR 2 AS lhs), lhs;
|
||||
SELECT substring('1234' FROM 2 FOR 2 lhs), lhs;
|
||||
|
||||
-- SUBSTRING(expr, start, length)
|
||||
|
||||
SELECT substring('1234' AS arg_1, 2 AS arg_2, 3 AS arg_3), arg_1, arg_2, arg_3;
|
||||
SELECT substring('1234' arg_1, 2 arg_2, 3 arg_3), arg_1, arg_2, arg_3;
|
||||
|
||||
-- -- TRIM expression ([[LEADING|TRAILING|BOTH] trim_character FROM] input_string)
|
||||
|
||||
SELECT trim(LEADING 'a' AS arg_1 FROM 'abca' AS arg_2), arg_1, arg_2;
|
||||
SELECT trim(LEADING 'a' arg_1 FROM 'abca' arg_2), arg_1, arg_2;
|
||||
SELECT trim(LEADING 'a' FROM 'abca' AS arg_2), arg_2;
|
||||
SELECT trim(LEADING 'a' FROM 'abca' arg_2), arg_2;
|
||||
SELECT trim(LEADING 'a' AS arg_1 FROM 'abca'), arg_1;
|
||||
SELECT trim(LEADING 'a' arg_1 FROM 'abca'), arg_1;
|
||||
SELECT trim(LEADING 'a' FROM 'abca');
|
||||
|
||||
SELECT trim(TRAILING 'a' AS arg_1 FROM 'abca' AS arg_2), arg_1, arg_2;
|
||||
SELECT trim(TRAILING 'a' arg_1 FROM 'abca' arg_2), arg_1, arg_2;
|
||||
|
||||
SELECT trim(BOTH 'a' AS arg_1 FROM 'abca' AS arg_2), arg_1, arg_2;
|
||||
SELECT trim(BOTH 'a' arg_1 FROM 'abca' arg_2), arg_1, arg_2;
|
||||
|
||||
-- EXTRACT expression
|
||||
|
||||
-- EXTRACT(part FROM date)
|
||||
|
||||
SELECT EXTRACT(DAY FROM toDate('2019-05-05') as arg_1), arg_1;
|
||||
SELECT EXTRACT(DAY FROM toDate('2019-05-05') arg_1), arg_1;
|
||||
|
||||
-- Function extract(haystack, pattern)
|
||||
|
||||
SELECT extract('1234' AS arg_1, '123' AS arg_2), arg_1, arg_2;
|
||||
SELECT extract('1234' arg_1, '123' arg_2), arg_1, arg_2;
|
||||
|
||||
-- POSITION expression
|
||||
|
||||
-- position(needle IN haystack)
|
||||
|
||||
SELECT position(('123' AS arg_1) IN ('1234' AS arg_2)), arg_1, arg_2;
|
||||
|
||||
-- position(haystack, needle[, start_pos])
|
||||
|
||||
SELECT position('123' AS arg_1, '1234' AS arg_2), arg_1, arg_2;
|
||||
SELECT position('123' arg_1, '1234' arg_2), arg_1, arg_2;
|
||||
|
||||
-- dateAdd, dateSub expressions
|
||||
|
||||
-- function(unit, offset, timestamp)
|
||||
|
||||
SELECT dateAdd(DAY, 1 AS arg_1, toDate('2019-05-05') AS arg_2), arg_1, arg_2;
|
||||
SELECT dateAdd(DAY, 1 arg_1, toDate('2019-05-05') arg_2), arg_1, arg_2;
|
||||
|
||||
-- function(offset, timestamp)
|
||||
|
||||
SELECT dateAdd(DAY, 1 AS arg_1, toDate('2019-05-05') AS arg_2), arg_1, arg_2;
|
||||
SELECT dateAdd(DAY, 1 arg_1, toDate('2019-05-05') arg_2), arg_1, arg_2;
|
||||
|
||||
-- function(unit, offset, timestamp)
|
||||
|
||||
SELECT dateSub(DAY, 1 AS arg_1, toDate('2019-05-05') AS arg_2), arg_1, arg_2;
|
||||
SELECT dateSub(DAY, 1 arg_1, toDate('2019-05-05') arg_2), arg_1, arg_2;
|
||||
|
||||
-- function(offset, timestamp)
|
||||
|
||||
SELECT dateSub(DAY, 1 AS arg_1, toDate('2019-05-05') AS arg_2), arg_1, arg_2;
|
||||
SELECT dateSub(DAY, 1 arg_1, toDate('2019-05-05') arg_2), arg_1, arg_2;
|
||||
|
||||
-- dateDiff expression
|
||||
|
||||
-- dateDiff(unit, startdate, enddate, [timezone])
|
||||
|
||||
SELECT dateDiff(DAY, toDate('2019-05-05') AS arg_1, toDate('2019-05-06') AS arg_2), arg_1, arg_2;
|
||||
SELECT dateDiff(DAY, toDate('2019-05-05') arg_1, toDate('2019-05-06') arg_2), arg_1, arg_2;
|
||||
SELECT dateDiff(DAY, toDate('2019-05-05') AS arg_1, toDate('2019-05-06') AS arg_2, 'UTC'), arg_1, arg_2;
|
||||
SELECT dateDiff(DAY, toDate('2019-05-05') arg_1, toDate('2019-05-06') arg_2, 'UTC'), arg_1, arg_2;
|
||||
|
||||
-- dateDiff('unit', startdate, enddate, [timezone])
|
||||
|
||||
SELECT dateDiff('DAY', toDate('2019-05-05') AS arg_1, toDate('2019-05-06') AS arg_2), arg_1, arg_2;
|
||||
SELECT dateDiff('DAY', toDate('2019-05-05') arg_1, toDate('2019-05-06') arg_2), arg_1, arg_2;
|
||||
SELECT dateDiff('DAY', toDate('2019-05-05') AS arg_1, toDate('2019-05-06') AS arg_2, 'UTC'), arg_1, arg_2;
|
||||
SELECT dateDiff('DAY', toDate('2019-05-05') arg_1, toDate('2019-05-06') arg_2, 'UTC'), arg_1, arg_2;
|
Loading…
Reference in New Issue
Block a user