ClickHouse/dbms/TableFunctions/TableFunctionValues.cpp

107 lines
3.8 KiB
C++
Raw Normal View History

2019-07-29 13:50:13 +00:00
#include <Common/typeid_cast.h>
#include <Common/Exception.h>
2019-07-29 16:20:17 +00:00
#include <Core/Block.h>
2019-07-29 13:50:13 +00:00
#include <Storages/StorageValues.h>
#include <DataTypes/DataTypeTuple.h>
2019-07-29 13:50:13 +00:00
#include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTFunction.h>
#include <TableFunctions/ITableFunction.h>
#include <TableFunctions/TableFunctionValues.h>
#include <TableFunctions/TableFunctionFactory.h>
#include <TableFunctions/parseColumnsListForTableFunction.h>
2019-07-29 16:20:17 +00:00
#include <Access/AccessFlags.h>
2019-07-29 16:20:17 +00:00
#include <Interpreters/convertFieldToType.h>
2019-07-29 13:50:13 +00:00
#include <Interpreters/evaluateConstantExpression.h>
#include <Interpreters/Context.h>
2019-12-15 06:34:43 +00:00
#include "registerTableFunctions.h"
2019-07-29 16:20:17 +00:00
2019-07-29 13:50:13 +00:00
namespace DB
{
namespace ErrorCodes
{
2020-02-25 18:02:41 +00:00
extern const int LOGICAL_ERROR;
2019-07-29 13:50:13 +00:00
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
}
2019-07-29 16:20:17 +00:00
static void parseAndInsertValues(MutableColumns & res_columns, const ASTs & args, const Block & sample_block, const Context & context)
{
if (res_columns.size() == 1) /// Parsing arguments as Fields
{
for (size_t i = 1; i < args.size(); ++i)
{
const auto & [value_field, value_type_ptr] = evaluateConstantExpression(args[i], context);
2019-09-16 15:47:13 +00:00
2019-07-29 16:20:17 +00:00
Field value = convertFieldToType(value_field, *sample_block.getByPosition(0).type, value_type_ptr.get());
res_columns[0]->insert(value);
}
}
else /// Parsing arguments as Tuples
{
for (size_t i = 1; i < args.size(); ++i)
{
const auto & [value_field, value_type_ptr] = evaluateConstantExpression(args[i], context);
const DataTypes & value_types_tuple = typeid_cast<const DataTypeTuple *>(value_type_ptr.get())->getElements();
const Tuple & value_tuple = value_field.safeGet<Tuple>();
2019-07-29 16:20:17 +00:00
if (value_tuple.size() != sample_block.columns())
throw Exception("Values size should match with number of columns", ErrorCodes::LOGICAL_ERROR);
for (size_t j = 0; j < value_tuple.size(); ++j)
{
Field value = convertFieldToType(value_tuple[j], *sample_block.getByPosition(j).type, value_types_tuple[j].get());
2019-07-29 16:20:17 +00:00
res_columns[j]->insert(value);
}
}
}
}
2019-07-29 13:50:13 +00:00
StoragePtr TableFunctionValues::executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const
{
ASTs & args_func = ast_function->children;
if (args_func.size() != 1)
throw Exception("Table function '" + getName() + "' must have arguments.", ErrorCodes::LOGICAL_ERROR);
ASTs & args = args_func.at(0)->children;
if (args.size() < 2)
throw Exception("Table function '" + getName() + "' requires 2 or more arguments: structure and values.",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
2020-01-24 16:20:36 +00:00
context.checkAccess(AccessType::values);
/// Parsing first argument as table structure and creating a sample block
2019-07-29 13:50:13 +00:00
std::string structure = args[0]->as<ASTLiteral &>().value.safeGet<String>();
2019-08-01 01:53:38 +00:00
ColumnsDescription columns = parseColumnsListFromString(structure, context);
Block sample_block;
2019-08-01 01:53:38 +00:00
for (const auto & name_type : columns.getOrdinary())
sample_block.insert({ name_type.type->createColumn(), name_type.type, name_type.name });
2019-07-29 13:50:13 +00:00
MutableColumns res_columns = sample_block.cloneEmptyColumns();
/// Parsing other arguments as values and inserting them into columns
2019-07-29 16:20:17 +00:00
parseAndInsertValues(res_columns, args, sample_block, context);
2019-07-29 13:50:13 +00:00
Block res_block = sample_block.cloneWithColumns(std::move(res_columns));
2019-12-04 16:06:55 +00:00
auto res = StorageValues::create(StorageID(getDatabaseName(), table_name), columns, res_block);
2019-07-29 13:50:13 +00:00
res->startup();
return res;
}
void registerTableFunctionValues(TableFunctionFactory & factory)
{
factory.registerFunction<TableFunctionValues>(TableFunctionFactory::CaseInsensitive);
}
}