mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-18 21:51:57 +00:00
Added variations of Maps, Arrays and Tuples
This commit is contained in:
parent
89a2431cdd
commit
f1b172d43b
@ -1095,6 +1095,147 @@ bool ParserCollectionOfLiterals<Collection>::parseImpl(Pos & pos, ASTPtr & node,
|
||||
template bool ParserCollectionOfLiterals<Array>::parseImpl(Pos & pos, ASTPtr & node, Expected & expected);
|
||||
template bool ParserCollectionOfLiterals<Tuple>::parseImpl(Pos & pos, ASTPtr & node, Expected & expected);
|
||||
|
||||
|
||||
class ICollection;
|
||||
using Collections = std::vector<std::unique_ptr<ICollection>>;
|
||||
|
||||
class ICollection
|
||||
{
|
||||
public:
|
||||
virtual ~ICollection() = default;
|
||||
virtual bool parse(IParser::Pos & pos, Collections & collections, ASTPtr & node, Expected & expected) = 0;
|
||||
};
|
||||
|
||||
template <class Container, TokenType end_token>
|
||||
class CommonCollection : public ICollection
|
||||
{
|
||||
public:
|
||||
bool parse(IParser::Pos & pos, Collections & collections, ASTPtr & node, Expected & expected) override;
|
||||
|
||||
private:
|
||||
Container container;
|
||||
};
|
||||
|
||||
class MapCollection : public ICollection
|
||||
{
|
||||
public:
|
||||
bool parse(IParser::Pos & pos, Collections & collections, ASTPtr & node, Expected & expected) override;
|
||||
|
||||
private:
|
||||
Map container;
|
||||
};
|
||||
|
||||
bool parseAllCollectionsStart(IParser::Pos & pos, Collections & collections, Expected & /*expected*/)
|
||||
{
|
||||
if (pos->type == TokenType::OpeningCurlyBrace)
|
||||
collections.push_back(std::make_unique<MapCollection>());
|
||||
else if (pos->type == TokenType::OpeningRoundBracket)
|
||||
collections.push_back(std::make_unique<CommonCollection<Tuple, TokenType::ClosingRoundBracket>>());
|
||||
else if (pos->type == TokenType::OpeningSquareBracket)
|
||||
collections.push_back(std::make_unique<CommonCollection<Array, TokenType::ClosingSquareBracket>>());
|
||||
else
|
||||
return false;
|
||||
|
||||
++pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Container, TokenType end_token>
|
||||
bool CommonCollection<Container, end_token>::parse(IParser::Pos & pos, Collections & collections, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
if (node)
|
||||
{
|
||||
container.push_back(std::move(node->as<ASTLiteral &>().value));
|
||||
node.reset();
|
||||
}
|
||||
|
||||
ASTPtr literal;
|
||||
ParserLiteral literal_p;
|
||||
ParserToken comma_p(TokenType::Comma);
|
||||
ParserToken end_p(end_token);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (end_p.ignore(pos, expected))
|
||||
{
|
||||
node = std::make_shared<ASTLiteral>(std::move(container));
|
||||
break;
|
||||
}
|
||||
|
||||
if (!container.empty() && !comma_p.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
if (literal_p.parse(pos, literal, expected))
|
||||
container.push_back(std::move(literal->as<ASTLiteral &>().value));
|
||||
else
|
||||
return parseAllCollectionsStart(pos, collections, expected);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MapCollection::parse(IParser::Pos & pos, Collections & collections, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
if (node)
|
||||
{
|
||||
container.push_back(std::move(node->as<ASTLiteral &>().value));
|
||||
node.reset();
|
||||
}
|
||||
|
||||
ASTPtr literal;
|
||||
ParserLiteral literal_p;
|
||||
ParserToken comma_p(TokenType::Comma);
|
||||
ParserToken colon_p(TokenType::Colon);
|
||||
ParserToken end_p(TokenType::ClosingCurlyBrace);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (end_p.ignore(pos, expected))
|
||||
{
|
||||
node = std::make_shared<ASTLiteral>(std::move(container));
|
||||
break;
|
||||
}
|
||||
|
||||
if (!container.empty() && !comma_p.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
if (!literal_p.parse(pos, literal, expected))
|
||||
return false;
|
||||
|
||||
if (!colon_p.parse(pos, literal, expected))
|
||||
return false;
|
||||
|
||||
container.push_back(std::move(literal->as<ASTLiteral &>().value));
|
||||
|
||||
if (literal_p.parse(pos, literal, expected))
|
||||
container.push_back(std::move(literal->as<ASTLiteral &>().value));
|
||||
else
|
||||
return parseAllCollectionsStart(pos, collections, expected);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserAllCollectionsOfLiterals::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
Collections collections;
|
||||
|
||||
if (!parseAllCollectionsStart(pos, collections, expected))
|
||||
return false;
|
||||
|
||||
while (!collections.empty())
|
||||
{
|
||||
if (!collections.back()->parse(pos, collections, node, expected))
|
||||
return false;
|
||||
|
||||
if (node)
|
||||
collections.pop_back();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ParserLiteral::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
ParserNull null_p;
|
||||
|
@ -301,6 +301,17 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
/** Parses all collections of literals and their various combinations
|
||||
* Used in parsing parameters for SET query
|
||||
*/
|
||||
class ParserAllCollectionsOfLiterals : public IParserBase
|
||||
{
|
||||
public:
|
||||
protected:
|
||||
const char * getName() const override { return "combination of maps, arrays, tuples"; }
|
||||
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
||||
};
|
||||
|
||||
|
||||
/** The literal is one of: NULL, UInt64, Int64, Float64, String.
|
||||
*/
|
||||
|
@ -8,7 +8,9 @@
|
||||
|
||||
#include <Core/Names.h>
|
||||
#include <IO/ReadBufferFromString.h>
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/Operators.h>
|
||||
#include <Common/FieldVisitorToString.h>
|
||||
#include <Common/SettingsChanges.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
@ -22,6 +24,76 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
class ParameterFieldVisitorToString : public StaticVisitor<String>
|
||||
{
|
||||
public:
|
||||
template <class T>
|
||||
String operator() (const T & x) const
|
||||
{
|
||||
FieldVisitorToString visitor;
|
||||
return visitor(x);
|
||||
}
|
||||
|
||||
String operator() (const Array & x) const
|
||||
{
|
||||
WriteBufferFromOwnString wb;
|
||||
|
||||
wb << '[';
|
||||
for (Array::const_iterator it = x.begin(); it != x.end(); ++it)
|
||||
{
|
||||
if (it != x.begin())
|
||||
wb.write(", ", 2);
|
||||
wb << applyVisitor(*this, *it);
|
||||
}
|
||||
wb << ']';
|
||||
|
||||
return wb.str();
|
||||
}
|
||||
|
||||
String operator() (const Map & x) const
|
||||
{
|
||||
WriteBufferFromOwnString wb;
|
||||
|
||||
wb << '{';
|
||||
|
||||
auto it = x.begin();
|
||||
while (it != x.end())
|
||||
{
|
||||
if (it != x.begin())
|
||||
wb << ", ";
|
||||
wb << applyVisitor(*this, *it);
|
||||
++it;
|
||||
|
||||
if (it != x.end())
|
||||
{
|
||||
wb << ':';
|
||||
wb << applyVisitor(*this, *it);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
wb << '}';
|
||||
|
||||
return wb.str();
|
||||
}
|
||||
|
||||
String operator() (const Tuple & x) const
|
||||
{
|
||||
WriteBufferFromOwnString wb;
|
||||
|
||||
wb << '(';
|
||||
for (auto it = x.begin(); it != x.end(); ++it)
|
||||
{
|
||||
if (it != x.begin())
|
||||
wb << ", ";
|
||||
wb << applyVisitor(*this, *it);
|
||||
}
|
||||
wb << ')';
|
||||
|
||||
return wb.str();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ParserLiteralOrMap : public IParserBase
|
||||
{
|
||||
public:
|
||||
@ -74,13 +146,12 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
/// Parse Literal, Array/Tuple/Map of literals, Identifier
|
||||
/// Parse Identifier, Literal, Array/Tuple/Map of literals
|
||||
bool parseParameterValueIntoString(IParser::Pos & pos, String & value, Expected & expected)
|
||||
{
|
||||
ASTPtr node;
|
||||
|
||||
/// Identifier
|
||||
|
||||
/// 1. Identifier
|
||||
ParserCompoundIdentifier identifier_p;
|
||||
|
||||
if (identifier_p.parse(pos, node, expected))
|
||||
@ -89,17 +160,10 @@ bool parseParameterValueIntoString(IParser::Pos & pos, String & value, Expected
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Literal, Array/Tuple of literals
|
||||
|
||||
/// 2. Literal
|
||||
ParserLiteral literal_p;
|
||||
ParserArrayOfLiterals array_p;
|
||||
ParserTupleOfLiterals tuple_p;
|
||||
|
||||
if (literal_p.parse(pos, node, expected) ||
|
||||
array_p.parse(pos, node, expected) ||
|
||||
tuple_p.parse(pos, node, expected))
|
||||
if (literal_p.parse(pos, node, expected))
|
||||
{
|
||||
|
||||
value = applyVisitor(FieldVisitorToString(), node->as<ASTLiteral>()->value);
|
||||
|
||||
/// writeQuoted is not always quoted in line with SQL standard https://github.com/ClickHouse/ClickHouse/blob/master/src/IO/WriteHelpers.h
|
||||
@ -112,65 +176,16 @@ bool parseParameterValueIntoString(IParser::Pos & pos, String & value, Expected
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Map of literals
|
||||
/// 3. Map, Array, Tuple of literals and their combination
|
||||
ParserAllCollectionsOfLiterals all_collections_p;
|
||||
|
||||
ParserToken l_br_p(TokenType::OpeningCurlyBrace);
|
||||
ParserToken r_br_p(TokenType::ClosingCurlyBrace);
|
||||
ParserToken comma_p(TokenType::Comma);
|
||||
ParserToken colon_p(TokenType::Colon);
|
||||
|
||||
if (!l_br_p.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
int depth = 1;
|
||||
|
||||
value = '{';
|
||||
|
||||
while (depth > 0)
|
||||
if (all_collections_p.parse(pos, node, expected))
|
||||
{
|
||||
if (r_br_p.ignore(pos, expected))
|
||||
{
|
||||
value += '}';
|
||||
--depth;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value.back() != '{')
|
||||
{
|
||||
if (!comma_p.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
value += ',';
|
||||
}
|
||||
|
||||
ASTPtr key;
|
||||
ASTPtr val;
|
||||
|
||||
if (!literal_p.parse(pos, key, expected))
|
||||
return false;
|
||||
|
||||
if (!colon_p.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
value += applyVisitor(FieldVisitorToString(), key->as<ASTLiteral>()->value);
|
||||
value += ":";
|
||||
|
||||
if (l_br_p.ignore(pos, expected))
|
||||
{
|
||||
value += '{';
|
||||
++depth;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!literal_p.parse(pos, val, expected)
|
||||
&& !array_p.parse(pos, val, expected)
|
||||
&& !tuple_p.parse(pos, val, expected))
|
||||
return false;
|
||||
|
||||
value += applyVisitor(FieldVisitorToString(), val->as<ASTLiteral>()->value);
|
||||
value = applyVisitor(ParameterFieldVisitorToString(), node->as<ASTLiteral>()->value);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Parse `name = value`.
|
||||
|
@ -13,10 +13,4 @@ _CAST(((\'abc\', 22), (\'def\', 33)), \'Map(String, UInt8)\') Map(String, UInt8)
|
||||
_CAST([[4, 5, 6], [7], [8, 9]], \'Array(Array(UInt8))\') Array(Array(UInt8))
|
||||
_CAST(((10, [11, 12]), (13, [14, 15])), \'Map(UInt8, Array(UInt8))\') Map(UInt8, Array(UInt8))
|
||||
_CAST(((\'ghj\', ((\'klm\', [16, 17]))), (\'nop\', ((\'rst\', [18])))), \'Map(String, Map(String, Array(UInt8)))\') Map(String, Map(String, Array(UInt8)))
|
||||
_CAST(42, \'Int64\') Int64
|
||||
_CAST([1, 2, 3], \'Array(UInt8)\') Array(UInt8)
|
||||
_CAST(((\'abc\', 22), (\'def\', 33)), \'Map(String, UInt8)\') Map(String, UInt8)
|
||||
_CAST([[4, 5, 6], [7], [8, 9]], \'Array(Array(UInt8))\') Array(Array(UInt8))
|
||||
_CAST(((10, [11, 12]), (13, [14, 15])), \'Map(UInt8, Array(UInt8))\') Map(UInt8, Array(UInt8))
|
||||
_CAST(((\'ghj\', ((\'klm\', [16, 17]))), (\'nop\', ((\'rst\', [18])))), \'Map(String, Map(String, Array(UInt8)))\') Map(String, Map(String, Array(UInt8)))
|
||||
a Int8
|
||||
|
@ -91,15 +91,4 @@ $CLICKHOUSE_CLIENT \
|
||||
--param_map_map_arr="{'ghj': {'klm': [16, 17]}, 'nop': {'rst': [18]}}" \
|
||||
-q "describe table(select {id: Int64}, {arr: Array(UInt8)}, {map: Map(String, UInt8)}, {mul_arr: Array(Array(UInt8))}, {map_arr: Map(UInt8, Array(UInt8))}, {map_map_arr: Map(String, Map(String, Array(UInt8)))})"
|
||||
|
||||
# parameters can be set without manual string serialisation
|
||||
$CLICKHOUSE_CLIENT -n -q "
|
||||
set param_id = 42;
|
||||
set param_arr = [1, 2, 3];
|
||||
set param_map = {'abc': 22, 'def': 33};
|
||||
set param_mul_arr = [[4, 5, 6], [7], [8, 9]];
|
||||
set param_map_arr = {10: [11, 12], 13: [14, 15]};
|
||||
set param_map_map_arr = {'ghj': {'klm': [16, 17]}, 'nop': {'rst': [18]}};
|
||||
describe table(select {id: Int64}, {arr: Array(UInt8)}, {map: Map(String, UInt8)}, {mul_arr: Array(Array(UInt8))}, {map_arr: Map(UInt8, Array(UInt8))}, {map_map_arr: Map(String, Map(String, Array(UInt8)))});"
|
||||
|
||||
|
||||
$CLICKHOUSE_CLIENT --param_p=42 -q "describe table (select * from (select {p:Int8} as a group by a) order by a)"
|
||||
|
Loading…
Reference in New Issue
Block a user