Added variations of Maps, Arrays and Tuples

This commit is contained in:
Nikolay Degterinsky 2022-11-08 00:19:01 +00:00
parent 89a2431cdd
commit f1b172d43b
5 changed files with 234 additions and 84 deletions

View File

@ -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;

View File

@ -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.
*/

View File

@ -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`.

View File

@ -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

View File

@ -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)"