diff --git a/src/Functions/FunctionsConversion.h b/src/Functions/FunctionsConversion.h index e7dff43131b..589bd4cc16e 100644 --- a/src/Functions/FunctionsConversion.h +++ b/src/Functions/FunctionsConversion.h @@ -2523,7 +2523,7 @@ private: if (!from_type) { throw Exception(ErrorCodes::TYPE_MISMATCH, - "CAST AS Array can only be perforamed between same-dimensional Array or String types"); + "CAST AS Array can only be performed between same-dimensional Array or String types"); } DataTypePtr from_nested_type = from_type->getNestedType(); @@ -2533,7 +2533,7 @@ private: if (from_type->getNumberOfDimensions() != to_type.getNumberOfDimensions() && !from_empty_array) throw Exception(ErrorCodes::TYPE_MISMATCH, - "CAST AS Array can only be perforamed between same-dimensional array types"); + "CAST AS Array can only be performed between same-dimensional array types"); const DataTypePtr & to_nested_type = to_type.getNestedType(); diff --git a/src/Parsers/ExpressionElementParsers.cpp b/src/Parsers/ExpressionElementParsers.cpp index 9c20cfd0327..cde75396180 100644 --- a/src/Parsers/ExpressionElementParsers.cpp +++ b/src/Parsers/ExpressionElementParsers.cpp @@ -824,34 +824,48 @@ bool ParserCastOperator::parseImpl(Pos & pos, ASTPtr & node, Expected & expected /// Parse numbers (including decimals), strings and arrays of them. const char * data_begin = pos->begin; + const char * data_end = pos->end; bool is_string_literal = pos->type == TokenType::StringLiteral; if (pos->type == TokenType::Number || is_string_literal) { ++pos; } - else if (pos->type == TokenType::OpeningSquareBracket) + else if (isOneOf(pos->type)) { TokenType last_token = TokenType::OpeningSquareBracket; + std::vector stack; while (pos.isValid()) { - if (pos->type == TokenType::OpeningSquareBracket) + if (isOneOf(pos->type)) { - if (!isOneOf(last_token)) + stack.push_back(pos->type); + if (!isOneOf(last_token)) return false; } else if (pos->type == TokenType::ClosingSquareBracket) { - if (last_token == TokenType::Comma) + if (isOneOf(last_token)) return false; + if (stack.empty() || stack.back() != TokenType::OpeningSquareBracket) + return false; + stack.pop_back(); + } + else if (pos->type == TokenType::ClosingRoundBracket) + { + if (isOneOf(last_token)) + return false; + if (stack.empty() || stack.back() != TokenType::OpeningRoundBracket) + return false; + stack.pop_back(); } else if (pos->type == TokenType::Comma) { - if (isOneOf(last_token)) + if (isOneOf(last_token)) return false; } else if (isOneOf(pos->type)) { - if (!isOneOf(last_token)) + if (!isOneOf(last_token)) return false; } else @@ -859,14 +873,18 @@ bool ParserCastOperator::parseImpl(Pos & pos, ASTPtr & node, Expected & expected break; } + /// Update data_end on every iteration to avoid appearances of extra trailing + /// whitespaces into data. Whitespaces are skipped at operator '++' of Pos. + data_end = pos->end; last_token = pos->type; ++pos; } + + if (!stack.empty()) + return false; } ASTPtr type_ast; - const char * data_end = pos->begin; - if (ParserToken(TokenType::DoubleColon).ignore(pos, expected) && ParserDataType().parse(pos, type_ast, expected)) { diff --git a/tests/queries/0_stateless/01852_cast_operator_2.reference b/tests/queries/0_stateless/01852_cast_operator_2.reference new file mode 100644 index 00000000000..438eabda142 --- /dev/null +++ b/tests/queries/0_stateless/01852_cast_operator_2.reference @@ -0,0 +1,13 @@ +(0.1000000000000000000000000000000000000000000000000000000000000000000000,0.2000000000000000000000000000000000000000000000000000000000000000000000) +SELECT CAST(\'(0.1, 0.2)\', \'Tuple(Decimal(75, 70), Decimal(75, 70))\') +0.1000 +SELECT CAST(\'0.1\', \'Decimal(4, 4)\') +[1,2,3] +SELECT CAST(\'[1, 2, 3]\', \'Array(Int32)\') +[1,2] +SELECT CAST([CAST(\'1\', \'UInt32\'), CAST(\'2\', \'UInt32\')], \'Array(UInt64)\') +[[1,2],[3]] +SELECT CAST([CAST(\'[1, 2]\', \'Array(UInt32)\'), [3]], \'Array(Array(UInt64))\') +[[1,2],[3]] +SELECT CAST([CAST([CAST(\'1\', \'UInt16\'), CAST(\'2\', \'UInt16\')], \'Array(UInt32)\'), [3]], \'Array(Array(UInt64))\') +[(1,'a'),(3,'b')] Nested(u UInt8, s String) diff --git a/tests/queries/0_stateless/01852_cast_operator_2.sql b/tests/queries/0_stateless/01852_cast_operator_2.sql new file mode 100644 index 00000000000..859d33a381a --- /dev/null +++ b/tests/queries/0_stateless/01852_cast_operator_2.sql @@ -0,0 +1,19 @@ +SELECT (0.1, 0.2)::Tuple(Decimal(75, 70), Decimal(75, 70)); +EXPLAIN SYNTAX SELECT (0.1, 0.2)::Tuple(Decimal(75, 70), Decimal(75, 70)); + +SELECT 0.1 :: Decimal(4, 4); +EXPLAIN SYNTAX SELECT 0.1 :: Decimal(4, 4); + +SELECT [1, 2, 3] :: Array(Int32); +EXPLAIN SYNTAX SELECT [1, 2, 3] :: Array(Int32); + +SELECT [1::UInt32, 2::UInt32]::Array(UInt64); +EXPLAIN SYNTAX SELECT [1::UInt32, 2::UInt32]::Array(UInt64); + +SELECT [[1, 2]::Array(UInt32), [3]]::Array(Array(UInt64)); +EXPLAIN SYNTAX SELECT [[1, 2]::Array(UInt32), [3]]::Array(Array(UInt64)); + +SELECT [[1::UInt16, 2::UInt16]::Array(UInt32), [3]]::Array(Array(UInt64)); +EXPLAIN SYNTAX SELECT [[1::UInt16, 2::UInt16]::Array(UInt32), [3]]::Array(Array(UInt64)); + +SELECT [(1, 'a'), (3, 'b')]::Nested(u UInt8, s String) AS t, toTypeName(t);