diff --git a/src/Parsers/ExpressionElementParsers.cpp b/src/Parsers/ExpressionElementParsers.cpp index 29c7846283e..417f7501c4e 100644 --- a/src/Parsers/ExpressionElementParsers.cpp +++ b/src/Parsers/ExpressionElementParsers.cpp @@ -303,7 +303,7 @@ namespace ASTPtr expr_node; ASTPtr type_node; - if (ParserExpression().parse(pos, expr_node, expected)) + if (ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, expr_node, expected)) { if (ParserKeyword("AS").ignore(pos, expected)) { @@ -315,7 +315,7 @@ namespace } else if (ParserToken(TokenType::Comma).ignore(pos, expected)) { - if (ParserExpression().parse(pos, type_node, expected)) + if (ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, type_node, expected)) { node = makeASTFunction("CAST", expr_node, type_node); return true; @@ -335,7 +335,7 @@ namespace ASTPtr start_node; ASTPtr length_node; - if (!ParserExpression().parse(pos, expr_node, expected)) + if (!ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, expr_node, expected)) return false; if (pos->type != TokenType::Comma) @@ -348,7 +348,7 @@ namespace ++pos; } - if (!ParserExpression().parse(pos, start_node, expected)) + if (!ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, start_node, expected)) return false; if (pos->type != TokenType::ClosingRoundBracket) @@ -363,7 +363,7 @@ namespace ++pos; } - if (!ParserExpression().parse(pos, length_node, expected)) + if (!ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, length_node, expected)) return false; } @@ -378,7 +378,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; @@ -412,7 +412,7 @@ namespace if (char_override) { - if (!ParserExpression().parse(pos, to_remove, expected)) + if (!ParserExpressionWithOptionalAlias(true /*allow_alias_without_as_keyword*/).parse(pos, to_remove, expected)) return false; if (!ParserKeyword("FROM").ignore(pos, expected)) return false; @@ -429,7 +429,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 @@ -506,6 +506,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 +517,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 +529,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(); @@ -539,8 +542,11 @@ namespace bool parsePosition(IParser::Pos & pos, ASTPtr & node, Expected & expected) { + /// First try to match with position(needle IN haystack) + /// Then with position(haystack, needle[, start_pos]) + ASTPtr expr_list_node; - if (!ParserExpressionList(false, false).parse(pos, expr_list_node, expected)) + if (!ParserExpressionList(true /*allow_alias_without_as_keyword*/).parse(pos, expr_list_node, expected)) return false; ASTExpressionList * expr_list = typeid_cast(expr_list_node.get()); @@ -568,6 +574,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 +584,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(); interval_expr_list_args->children = {offset_node}; @@ -600,7 +608,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(); @@ -617,39 +625,44 @@ 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(); - 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; + + node = makeASTFunction("dateDiff", std::make_shared(interval_kind.toDateDiffUnit()), left_node, 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(); + 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(interval_kind.toDateDiffUnit()), left_node, right_node); return true; } diff --git a/tests/queries/0_stateless/02267_special_operator_parse_alias_check.reference b/tests/queries/0_stateless/02267_special_operator_parse_alias_check.reference new file mode 100644 index 00000000000..de389bc6382 --- /dev/null +++ b/tests/queries/0_stateless/02267_special_operator_parse_alias_check.reference @@ -0,0 +1,35 @@ +1234 1234 UInt32 +1234 1234 UInt32 +1234 1234 +1234 1234 +234 1234 2 3 +234 1234 2 3 +234 1234 2 +234 1234 2 +234 1234 2 3 +234 1234 2 3 +bca a abca +bca a abca +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 diff --git a/tests/queries/0_stateless/02267_special_operator_parse_alias_check.sql b/tests/queries/0_stateless/02267_special_operator_parse_alias_check.sql new file mode 100644 index 00000000000..27fb3d22197 --- /dev/null +++ b/tests/queries/0_stateless/02267_special_operator_parse_alias_check.sql @@ -0,0 +1,92 @@ +-- CAST expression + +SELECT cast('1234' AS lhs, 'UInt32' AS rhs), lhs, rhs; +SELECT cast('1234' lhs, 'UInt32' rhs), lhs, rhs; +SELECT cast('1234' lhs AS UInt32), lhs; +SELECT cast('1234' AS lhs AS UInt32), lhs; + +-- SUBSTRING expression + +-- 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; + +-- SUBSTRING(expr FROM start) + +SELECT substring('1234' AS arg_1 FROM 2 AS arg_2), arg_1, arg_2; +SELECT substring('1234' arg_1 FROM 2 arg_2), arg_1, arg_2; + +-- SUBSTRING(expr FROM start FOR length) + +SELECT substring('1234' AS arg_1 FROM 2 AS arg_2 FOR 3 AS arg_3), arg_1, arg_2, arg_3; +SELECT substring('1234' arg_1 FROM 2 arg_2 FOR 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(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; + +-- 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;