clickhouse: added parsing of lambda-expressions [#CONV-7444].

This commit is contained in:
Michael Kolupaev 2013-05-08 09:52:02 +00:00
parent 897f03017e
commit 48c5dedb42
8 changed files with 187 additions and 57 deletions

View 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;
};
}

View File

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

View File

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

View 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;
}
};
}

View File

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

View File

@ -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_) {}

View File

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

View File

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