2019-05-08 01:41:05 +00:00
|
|
|
|
2019-05-18 03:21:39 +00:00
|
|
|
#include <Columns/ColumnConst.h>
|
2019-05-08 01:41:05 +00:00
|
|
|
#include <DataTypes/DataTypeFactory.h>
|
|
|
|
#include <Formats/BlockInputStreamFromRowInputStream.h>
|
|
|
|
#include <Interpreters/ExpressionAnalyzer.h>
|
|
|
|
#include <Interpreters/SyntaxAnalyzer.h>
|
|
|
|
#include <IO/ReadHelpers.h>
|
|
|
|
#include <Parsers/ASTExpressionList.h>
|
|
|
|
#include <Parsers/ASTFunction.h>
|
|
|
|
#include <Parsers/ASTLiteral.h>
|
|
|
|
#include <Formats/ConstantExpressionTemplate.h>
|
|
|
|
#include <Parsers/ExpressionElementParsers.h>
|
|
|
|
#include <Parsers/ExpressionListParsers.h>
|
|
|
|
#include <DataTypes/DataTypesNumber.h>
|
2019-05-18 03:21:39 +00:00
|
|
|
#include <DataTypes/DataTypeNullable.h>
|
|
|
|
#include <DataTypes/DataTypeString.h>
|
2019-05-18 17:25:21 +00:00
|
|
|
#include <DataTypes/FieldToDataType.h>
|
2019-05-22 03:29:32 +00:00
|
|
|
#include <Interpreters/InDepthNodeVisitor.h>
|
|
|
|
#include <Parsers/ASTIdentifier.h>
|
2019-05-08 01:41:05 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int CANNOT_CREATE_EXPRESSION_TEMPLATE;
|
|
|
|
extern const int CANNOT_PARSE_EXPRESSION_USING_TEMPLATE;
|
|
|
|
extern const int CANNOT_EVALUATE_EXPRESSION_TEMPLATE;
|
|
|
|
}
|
|
|
|
|
2019-05-22 03:29:32 +00:00
|
|
|
class ReplaceLiteralsMatcher
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
using Visitor = InDepthNodeVisitor<ReplaceLiteralsMatcher, true>;
|
|
|
|
|
|
|
|
struct LiteralInfo
|
|
|
|
{
|
|
|
|
typedef std::shared_ptr<ASTLiteral> ASTLiteralPtr;
|
|
|
|
LiteralInfo(const ASTLiteralPtr & literal_, const String & column_name_) : literal(literal_), dummy_column_name(column_name_) { }
|
|
|
|
ASTLiteralPtr literal;
|
|
|
|
String dummy_column_name;
|
|
|
|
};
|
|
|
|
|
|
|
|
using Data = std::vector<LiteralInfo>;
|
|
|
|
|
|
|
|
static void visit(ASTPtr & ast, Data & data)
|
|
|
|
{
|
2019-05-22 19:59:18 +00:00
|
|
|
auto literal = std::dynamic_pointer_cast<ASTLiteral>(ast);
|
|
|
|
if (!literal || !literal->begin || !literal->end)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// TODO don't replace constant arguments of functions such as CAST(x, 'type')
|
|
|
|
// TODO ensure column_name is unique (there was no _dummy_x identifier in expression)
|
|
|
|
String column_name = "_dummy_" + std::to_string(data.size());
|
|
|
|
data.emplace_back(literal, column_name);
|
|
|
|
ast = std::make_shared<ASTIdentifier>(column_name);
|
2019-05-22 03:29:32 +00:00
|
|
|
}
|
2019-05-22 19:59:18 +00:00
|
|
|
static bool needChildVisit(ASTPtr & node, const ASTPtr &) { return !node->as<ASTLiteral>(); }
|
2019-05-22 03:29:32 +00:00
|
|
|
};
|
2019-05-08 01:41:05 +00:00
|
|
|
|
2019-05-22 03:29:32 +00:00
|
|
|
using ReplaceLiteralsVisitor = ReplaceLiteralsMatcher::Visitor;
|
|
|
|
using LiteralInfo = ReplaceLiteralsMatcher::LiteralInfo;
|
|
|
|
|
|
|
|
|
|
|
|
ConstantExpressionTemplate::ConstantExpressionTemplate(const IDataType & result_column_type,
|
|
|
|
TokenIterator expression_begin, TokenIterator expression_end,
|
|
|
|
const ASTPtr & expression_, const Context & context)
|
2019-05-08 01:41:05 +00:00
|
|
|
{
|
2019-05-22 03:29:32 +00:00
|
|
|
ASTPtr expression = expression_->clone();
|
|
|
|
addNodesToCastResult(result_column_type, expression);
|
|
|
|
ReplaceLiteralsVisitor::Data replaced_literals;
|
|
|
|
ReplaceLiteralsVisitor(replaced_literals).visit(expression);
|
|
|
|
|
2019-05-22 19:59:18 +00:00
|
|
|
token_after_literal_idx.reserve(replaced_literals.size());
|
|
|
|
need_special_parser.resize(replaced_literals.size(), true);
|
|
|
|
|
2019-05-22 03:29:32 +00:00
|
|
|
std::sort(replaced_literals.begin(), replaced_literals.end(), [](const LiteralInfo & a, const LiteralInfo & b)
|
|
|
|
{
|
|
|
|
return a.literal->begin.value() < b.literal->begin.value();
|
|
|
|
});
|
|
|
|
|
|
|
|
bool allow_nulls = result_column_type.isNullable();
|
|
|
|
TokenIterator prev_end = expression_begin;
|
2019-05-22 19:59:18 +00:00
|
|
|
for (size_t i = 0; i < replaced_literals.size(); ++i)
|
2019-05-22 03:29:32 +00:00
|
|
|
{
|
2019-05-22 19:59:18 +00:00
|
|
|
const LiteralInfo & info = replaced_literals[i];
|
2019-05-22 03:29:32 +00:00
|
|
|
if (info.literal->begin.value() < prev_end)
|
|
|
|
throw Exception("Cannot replace literals", ErrorCodes::CANNOT_CREATE_EXPRESSION_TEMPLATE);
|
|
|
|
|
|
|
|
while (prev_end < info.literal->begin.value())
|
|
|
|
{
|
|
|
|
tokens.emplace_back(prev_end->begin, prev_end->size());
|
|
|
|
++prev_end;
|
|
|
|
}
|
|
|
|
token_after_literal_idx.push_back(tokens.size());
|
|
|
|
|
|
|
|
DataTypePtr type = applyVisitor(FieldToDataType(), info.literal->value);
|
2019-05-22 19:59:18 +00:00
|
|
|
|
|
|
|
WhichDataType type_info(type);
|
|
|
|
if (type_info.isNativeInt())
|
|
|
|
type = std::make_shared<DataTypeInt64>();
|
|
|
|
else if (type_info.isNativeUInt())
|
|
|
|
type = std::make_shared<DataTypeUInt64>();
|
|
|
|
else
|
|
|
|
need_special_parser[i] = false;
|
|
|
|
|
2019-05-22 03:29:32 +00:00
|
|
|
/// Allow literal to be NULL, if result column has nullable type
|
|
|
|
// TODO also allow NULL literals inside functions, which return not NULL for NULL arguments,
|
|
|
|
// even if result_column_type is not nullable
|
2019-05-22 19:59:18 +00:00
|
|
|
if (allow_nulls && type->canBeInsideNullable())
|
2019-05-22 03:29:32 +00:00
|
|
|
type = makeNullable(type);
|
|
|
|
|
|
|
|
literals.insert({nullptr, type, info.dummy_column_name});
|
|
|
|
|
|
|
|
prev_end = info.literal->end.value();
|
|
|
|
}
|
2019-05-08 01:41:05 +00:00
|
|
|
|
2019-05-22 03:29:32 +00:00
|
|
|
while (prev_end < expression_end)
|
|
|
|
{
|
|
|
|
tokens.emplace_back(prev_end->begin, prev_end->size());
|
|
|
|
++prev_end;
|
|
|
|
}
|
2019-05-08 01:41:05 +00:00
|
|
|
|
2019-05-22 03:29:32 +00:00
|
|
|
columns = literals.cloneEmptyColumns();
|
2019-05-08 01:41:05 +00:00
|
|
|
|
2019-05-22 03:29:32 +00:00
|
|
|
result_column_name = expression->getColumnName();
|
2019-05-08 01:41:05 +00:00
|
|
|
|
2019-05-18 03:21:39 +00:00
|
|
|
// TODO convert SyntaxAnalyzer and ExpressionAnalyzer exceptions to CANNOT_CREATE_EXPRESSION_TEMPLATE
|
2019-05-22 03:29:32 +00:00
|
|
|
auto syntax_result = SyntaxAnalyzer(context).analyze(expression, literals.getNamesAndTypesList());
|
2019-05-08 01:41:05 +00:00
|
|
|
|
2019-05-22 03:29:32 +00:00
|
|
|
actions_on_literals = ExpressionAnalyzer(expression, syntax_result, context).getActions(false);
|
2019-05-08 01:41:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ConstantExpressionTemplate::parseExpression(ReadBuffer & istr, const FormatSettings & settings)
|
|
|
|
{
|
|
|
|
size_t cur_column = 0;
|
|
|
|
try
|
|
|
|
{
|
2019-05-22 19:59:18 +00:00
|
|
|
ParserNumber parser;
|
2019-05-08 01:41:05 +00:00
|
|
|
size_t cur_token = 0;
|
|
|
|
while (cur_column < literals.columns())
|
|
|
|
{
|
|
|
|
size_t skip_tokens_until = token_after_literal_idx[cur_column];
|
|
|
|
while (cur_token < skip_tokens_until)
|
|
|
|
{
|
|
|
|
// TODO skip comments
|
|
|
|
skipWhitespaceIfAny(istr);
|
|
|
|
assertString(tokens[cur_token++], istr);
|
|
|
|
}
|
|
|
|
skipWhitespaceIfAny(istr);
|
2019-05-22 19:59:18 +00:00
|
|
|
|
2019-05-08 01:41:05 +00:00
|
|
|
const IDataType & type = *literals.getByPosition(cur_column).type;
|
2019-05-22 19:59:18 +00:00
|
|
|
if (need_special_parser[cur_column])
|
|
|
|
{
|
|
|
|
Tokens tokens_number(istr.position(), istr.buffer().end());
|
|
|
|
TokenIterator iterator(tokens_number);
|
|
|
|
Expected expected;
|
|
|
|
ASTPtr ast;
|
|
|
|
if (!parser.parse(iterator, ast, expected))
|
|
|
|
throw DB::Exception("Cannot parse literal", ErrorCodes::CANNOT_PARSE_EXPRESSION_USING_TEMPLATE);
|
|
|
|
istr.position() = const_cast<char *>(iterator->begin);
|
|
|
|
Field number = ast->as<ASTLiteral&>().value;
|
|
|
|
|
|
|
|
WhichDataType type_info(type);
|
2019-05-24 01:31:11 +00:00
|
|
|
if (type_info.isNullable())
|
|
|
|
type_info = WhichDataType(dynamic_cast<const DataTypeNullable &>(type).getNestedType());
|
|
|
|
// TODO also check type of Array(T), if T is arithmetic
|
2019-05-23 01:30:00 +00:00
|
|
|
if ((number.getType() == Field::Types::UInt64 && type_info.isUInt64())
|
|
|
|
|| (number.getType() == Field::Types::Int64 && type_info.isInt64())
|
2019-05-22 19:59:18 +00:00
|
|
|
|| (number.getType() == Field::Types::Float64 && type_info.isFloat64()))
|
|
|
|
{
|
|
|
|
columns[cur_column]->insert(number);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
throw DB::Exception("Cannot parse literal", ErrorCodes::CANNOT_PARSE_EXPRESSION_USING_TEMPLATE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
type.deserializeAsTextQuoted(*columns[cur_column], istr, settings);
|
|
|
|
}
|
|
|
|
|
2019-05-08 01:41:05 +00:00
|
|
|
++cur_column;
|
|
|
|
}
|
|
|
|
while (cur_token < tokens.size())
|
|
|
|
{
|
|
|
|
skipWhitespaceIfAny(istr);
|
|
|
|
assertString(tokens[cur_token++], istr);
|
|
|
|
}
|
2019-05-18 03:21:39 +00:00
|
|
|
++rows_count;
|
2019-05-12 03:15:08 +00:00
|
|
|
}
|
|
|
|
catch (DB::Exception & e)
|
2019-05-08 01:41:05 +00:00
|
|
|
{
|
|
|
|
for (size_t i = 0; i < cur_column; ++i)
|
|
|
|
columns[i]->popBack(1);
|
|
|
|
|
|
|
|
if (!isParseError(e.code()))
|
|
|
|
throw;
|
2019-05-12 03:15:08 +00:00
|
|
|
|
|
|
|
throw DB::Exception("Cannot parse expression using template", ErrorCodes::CANNOT_PARSE_EXPRESSION_USING_TEMPLATE);
|
2019-05-08 01:41:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ColumnPtr ConstantExpressionTemplate::evaluateAll()
|
|
|
|
{
|
|
|
|
Block evaluated = literals.cloneWithColumns(std::move(columns));
|
|
|
|
columns = literals.cloneEmptyColumns();
|
2019-05-18 03:21:39 +00:00
|
|
|
if (!literals.columns())
|
|
|
|
evaluated.insert({ColumnConst::create(ColumnUInt8::create(1, 0), rows_count), std::make_shared<DataTypeUInt8>(), "_dummy"});
|
2019-05-08 01:41:05 +00:00
|
|
|
actions_on_literals->execute(evaluated);
|
|
|
|
|
|
|
|
if (!evaluated || evaluated.rows() == 0)
|
|
|
|
throw Exception("Logical error: empty block after evaluation of batch of constant expressions",
|
|
|
|
ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
|
|
if (!evaluated.has(result_column_name))
|
|
|
|
throw Exception("Cannot evaluate template " + result_column_name + ", block structure:\n" + evaluated.dumpStructure(),
|
|
|
|
ErrorCodes::CANNOT_EVALUATE_EXPRESSION_TEMPLATE);
|
|
|
|
|
2019-05-23 03:07:49 +00:00
|
|
|
rows_count = 0;
|
2019-05-18 17:25:21 +00:00
|
|
|
return evaluated.getByName(result_column_name).column->convertToFullColumnIfConst();
|
2019-05-08 01:41:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ConstantExpressionTemplate::addNodesToCastResult(const IDataType & result_column_type, ASTPtr & expr)
|
|
|
|
{
|
|
|
|
auto result_type = std::make_shared<ASTLiteral>(result_column_type.getName());
|
|
|
|
|
|
|
|
auto arguments = std::make_shared<ASTExpressionList>();
|
|
|
|
arguments->children.push_back(std::move(expr));
|
|
|
|
arguments->children.push_back(std::move(result_type));
|
|
|
|
|
|
|
|
auto cast = std::make_shared<ASTFunction>();
|
|
|
|
cast->name = "CAST";
|
|
|
|
cast->arguments = std::move(arguments);
|
|
|
|
cast->children.push_back(cast->arguments);
|
|
|
|
|
|
|
|
expr = std::move(cast);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|