mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-21 09:10:48 +00:00
clickhouse: added parsing of lambda-expressions [#CONV-7444].
This commit is contained in:
parent
897f03017e
commit
48c5dedb42
32
dbms/include/DB/Columns/ColumnExpression.h
Normal file
32
dbms/include/DB/Columns/ColumnExpression.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <DB/Columns/IColumnDummy.h>
|
||||
#include <DB/Interpreters/Expression.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Столбец, содержащий лямбда-выражение.
|
||||
* Ведёт себя как столбец-константа. Содержит выражение, но не входные или выходные данные.
|
||||
*/
|
||||
class ColumnExpression : public IColumnDummy
|
||||
{
|
||||
public:
|
||||
ColumnExpression(size_t s_, ExpressionPtr expression_, const NamesAndTypes & arguments_, DataTypePtr return_type_)
|
||||
: IColumnDummy(s_), expression(expression_), arguments(arguments_), return_type(return_type_) {}
|
||||
|
||||
std::string getName() const { return "ColumnExpression"; }
|
||||
ColumnPtr cloneDummy(size_t s_) const { return new ColumnExpression(s_, expression, arguments, return_type); }
|
||||
|
||||
ExpressionPtr & getExpression() { return expression; }
|
||||
const NamesAndTypes & getArguments() const { return arguments; }
|
||||
const DataTypePtr & getReturnType() const { return return_type; }
|
||||
|
||||
private:
|
||||
ExpressionPtr expression;
|
||||
NamesAndTypes arguments;
|
||||
DataTypePtr return_type;
|
||||
};
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <DB/Columns/ColumnConst.h>
|
||||
#include <DB/Columns/IColumnDummy.h>
|
||||
#include <DB/Interpreters/Set.h>
|
||||
|
||||
|
||||
@ -11,68 +11,18 @@ namespace DB
|
||||
* Ведёт себя как столбец-константа (так как множество одно, а не своё на каждую строку).
|
||||
* Значение у этого столбца нестандартное, поэтому его невозможно получить через обычный интерфейс.
|
||||
*/
|
||||
class ColumnSet : public IColumn
|
||||
class ColumnSet : public IColumnDummy
|
||||
{
|
||||
public:
|
||||
ColumnSet(size_t s_, SetPtr data_) : s(s_), data(data_) {}
|
||||
ColumnSet(size_t s_, SetPtr data_) : IColumnDummy(s_), data(data_) {}
|
||||
|
||||
std::string getName() const { return "ColumnSet"; }
|
||||
ColumnPtr cloneEmpty() const { return new ColumnSet(0, NULL); }
|
||||
size_t size() const { return s; }
|
||||
Field operator[](size_t n) const { throw Exception("Cannot get value from ColumnSet", ErrorCodes::NOT_IMPLEMENTED); }
|
||||
void get(size_t n, Field & res) const { throw Exception("Cannot get value from ColumnSet", ErrorCodes::NOT_IMPLEMENTED); };
|
||||
void insert(const Field & x) { throw Exception("Cannot insert element into ColumnSet", ErrorCodes::NOT_IMPLEMENTED); }
|
||||
void insertDefault() { ++s; }
|
||||
size_t byteSize() const { return 0; }
|
||||
int compareAt(size_t n, size_t m, const IColumn & rhs_) const { return 0; }
|
||||
StringRef getDataAt(size_t n) const { throw Exception("Method getDataAt is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED); }
|
||||
void insertData(const char * pos, size_t length) { throw Exception("Method insertData is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED); }
|
||||
|
||||
ColumnPtr cut(size_t start, size_t length) const
|
||||
{
|
||||
return new ColumnSet(length, data);
|
||||
}
|
||||
|
||||
ColumnPtr filter(const Filter & filt) const
|
||||
{
|
||||
size_t new_size = 0;
|
||||
for (Filter::const_iterator it = filt.begin(); it != filt.end(); ++it)
|
||||
if (*it)
|
||||
++new_size;
|
||||
|
||||
return new ColumnSet(new_size, data);
|
||||
}
|
||||
|
||||
ColumnPtr permute(const Permutation & perm) const
|
||||
{
|
||||
if (s != perm.size())
|
||||
throw Exception("Size of permutation doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
return new ColumnSet(s, data);
|
||||
}
|
||||
|
||||
Permutation getPermutation() const
|
||||
{
|
||||
Permutation res(s);
|
||||
for (size_t i = 0; i < s; ++i)
|
||||
res[i] = i;
|
||||
return res;
|
||||
}
|
||||
|
||||
ColumnPtr replicate(const Offsets_t & offsets) const
|
||||
{
|
||||
if (s != offsets.size())
|
||||
throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
return new ColumnSet(offsets.back(), data);
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr cloneDummy(size_t s_) const { return new ColumnSet(s_, data); }
|
||||
|
||||
SetPtr & getData() { return data; }
|
||||
const SetPtr & getData() const { return data; }
|
||||
|
||||
private:
|
||||
size_t s;
|
||||
SetPtr data;
|
||||
};
|
||||
|
||||
|
@ -17,5 +17,6 @@ using Poco::SharedPtr;
|
||||
typedef std::pair<std::string, DataTypePtr> NameAndTypePair;
|
||||
typedef std::list<NameAndTypePair> NamesAndTypesList;
|
||||
typedef SharedPtr<NamesAndTypesList> NamesAndTypesListPtr;
|
||||
typedef std::vector<NameAndTypePair> NamesAndTypes;
|
||||
|
||||
}
|
||||
|
59
dbms/include/DB/DataTypes/DataTypeExpression.h
Normal file
59
dbms/include/DB/DataTypes/DataTypeExpression.h
Normal file
@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <DB/DataTypes/IDataTypeDummy.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/**
|
||||
* Лямбда-выражение.
|
||||
*/
|
||||
class DataTypeExpression : public IDataTypeDummy
|
||||
{
|
||||
private:
|
||||
DataTypes argument_types;
|
||||
DataTypePtr return_type;
|
||||
|
||||
public:
|
||||
/// Некоторые типы могут быть еще не известны.
|
||||
DataTypeExpression(DataTypes argument_types_ = DataTypes(), DataTypePtr return_type_ = NULL)
|
||||
: argument_types(argument_types_), return_type(return_type_) {}
|
||||
|
||||
std::string getName() const
|
||||
{
|
||||
std::string res = "Expression(";
|
||||
if (argument_types.size() > 1)
|
||||
res += "(";
|
||||
for (size_t i = 0; i < argument_types.size(); ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
res += ", ";
|
||||
DataTypePtr & type = argument_types[i];
|
||||
res += type ? type->getName() : "?";
|
||||
}
|
||||
if (argument_types.size() > 1)
|
||||
res += ")";
|
||||
res += " -> ";
|
||||
res += return_type ? return_type->getName() : "?";
|
||||
res += ")";
|
||||
return res;
|
||||
}
|
||||
|
||||
DataTypePtr clone() const
|
||||
{
|
||||
return new DataTypeExpression(argument_types, return_type);
|
||||
}
|
||||
|
||||
const DataTypes & getArgumentTypes() const
|
||||
{
|
||||
return argument_types;
|
||||
}
|
||||
|
||||
const DataTypePtr & getReturnType() const
|
||||
{
|
||||
return return_type;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -32,6 +32,13 @@ public:
|
||||
|
||||
/// Получить тип результата по типам аргументов. Если функция неприменима для данных аргументов - кинуть исключение.
|
||||
virtual DataTypePtr getReturnType(const DataTypes & arguments) const = 0;
|
||||
|
||||
/// Вызывается, если хоть один агрумент функции - лямбда-выражение.
|
||||
/// Для аргументов-лямбда-выражений определяет типы аргументов этих выражений.
|
||||
virtual void getLambdaArgumentTypes(DataTypes & arguments) const
|
||||
{
|
||||
throw Exception("Function " + getName() + " can't have lambda-expressions as arguments", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
}
|
||||
|
||||
/// Выполнить функцию над блоком. Замечание: может вызываться одновременно из нескольких потоков, для одного объекта.
|
||||
virtual void execute(Block & block, const ColumnNumbers & arguments, size_t result) = 0;
|
||||
|
@ -29,10 +29,10 @@ public:
|
||||
FunctionPtr function;
|
||||
/// или агрегатная функция
|
||||
AggregateFunctionPtr aggregate_function;
|
||||
/// или лямбда-выражение (ColumnExpression)
|
||||
ColumnPtr column_expression;
|
||||
/// тип возвращаемого значения
|
||||
DataTypePtr return_type;
|
||||
/// номер столбца возвращаемого значения
|
||||
size_t return_column_number;
|
||||
|
||||
ASTFunction() {}
|
||||
ASTFunction(StringRange range_) : IAST(range_) {}
|
||||
|
@ -296,6 +296,24 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
class ParserLambdaExpression : public IParserBase
|
||||
{
|
||||
private:
|
||||
ParserPtr elem_parser;
|
||||
|
||||
public:
|
||||
ParserLambdaExpression()
|
||||
: elem_parser(new ParserTernaryOperatorExpression)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
String getName() { return "lambda expression"; }
|
||||
|
||||
bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected);
|
||||
};
|
||||
|
||||
|
||||
class ParserExpressionWithOptionalAlias : public IParserBase
|
||||
{
|
||||
public:
|
||||
|
@ -201,6 +201,69 @@ bool ParserTernaryOperatorExpression::parseImpl(Pos & pos, Pos end, ASTPtr & nod
|
||||
}
|
||||
|
||||
|
||||
bool ParserLambdaExpression::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected)
|
||||
{
|
||||
ParserWhiteSpaceOrComments ws;
|
||||
ParserString arrow("->");
|
||||
ParserString open("(");
|
||||
ParserString close(")");
|
||||
|
||||
Pos begin = pos;
|
||||
|
||||
do
|
||||
{
|
||||
ASTPtr inner_arguments;
|
||||
ASTPtr expression;
|
||||
|
||||
if (!open.ignore(pos, end, expected))
|
||||
break;
|
||||
ws.ignore(pos, end, expected);
|
||||
|
||||
if (!ParserList(new ParserIdentifier, new ParserString(",")).parse(pos, end, inner_arguments, expected))
|
||||
break;
|
||||
ws.ignore(pos, end, expected);
|
||||
|
||||
if (!close.ignore(pos, end, expected))
|
||||
break;
|
||||
ws.ignore(pos, end, expected);
|
||||
|
||||
if (!arrow.ignore(pos, end, expected))
|
||||
break;
|
||||
ws.ignore(pos, end, expected);
|
||||
|
||||
if (!elem_parser->parse(pos, end, expression, expected))
|
||||
{
|
||||
pos = begin;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// lambda(tuple(inner_arguments), expression)
|
||||
|
||||
ASTFunction * lambda = new ASTFunction;
|
||||
node = lambda;
|
||||
lambda->name = "lambda";
|
||||
|
||||
ASTExpressionList * outer_arguments = new ASTExpressionList;
|
||||
lambda->arguments = outer_arguments;
|
||||
lambda->children.push_back(outer_arguments);
|
||||
|
||||
ASTFunction * tuple = new ASTFunction;
|
||||
outer_arguments->children.push_back(tuple);
|
||||
tuple->name = "tuple";
|
||||
tuple->arguments = inner_arguments;
|
||||
tuple->children.push_back(inner_arguments);
|
||||
|
||||
outer_arguments->children.push_back(expression);
|
||||
|
||||
return true;
|
||||
}
|
||||
while (false);
|
||||
|
||||
pos = begin;
|
||||
return elem_parser->parse(pos, end, node, expected);
|
||||
}
|
||||
|
||||
|
||||
bool ParserPrefixUnaryOperatorExpression::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected)
|
||||
{
|
||||
ParserWhiteSpaceOrComments ws;
|
||||
|
Loading…
Reference in New Issue
Block a user