summaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/TableFunctions/TableFunctionValues.cpp
diff options
context:
space:
mode:
authorvitalyisaev <[email protected]>2023-11-14 09:58:56 +0300
committervitalyisaev <[email protected]>2023-11-14 10:20:20 +0300
commitc2b2dfd9827a400a8495e172a56343462e3ceb82 (patch)
treecd4e4f597d01bede4c82dffeb2d780d0a9046bd0 /contrib/clickhouse/src/TableFunctions/TableFunctionValues.cpp
parentd4ae8f119e67808cb0cf776ba6e0cf95296f2df7 (diff)
YQ Connector: move tests from yql to ydb (OSS)
Перенос папки с тестами на Коннектор из папки yql в папку ydb (синхронизируется с github).
Diffstat (limited to 'contrib/clickhouse/src/TableFunctions/TableFunctionValues.cpp')
-rw-r--r--contrib/clickhouse/src/TableFunctions/TableFunctionValues.cpp154
1 files changed, 154 insertions, 0 deletions
diff --git a/contrib/clickhouse/src/TableFunctions/TableFunctionValues.cpp b/contrib/clickhouse/src/TableFunctions/TableFunctionValues.cpp
new file mode 100644
index 00000000000..42a19874704
--- /dev/null
+++ b/contrib/clickhouse/src/TableFunctions/TableFunctionValues.cpp
@@ -0,0 +1,154 @@
+#include <Common/typeid_cast.h>
+#include <Common/Exception.h>
+
+#include <Core/Block.h>
+#include <Storages/StorageValues.h>
+#include <DataTypes/DataTypeTuple.h>
+#include <DataTypes/getLeastSupertype.h>
+
+#include <Parsers/ASTExpressionList.h>
+#include <Parsers/ASTLiteral.h>
+
+#include <TableFunctions/TableFunctionValues.h>
+#include <TableFunctions/TableFunctionFactory.h>
+#include <Interpreters/parseColumnsListForTableFunction.h>
+
+#include <Interpreters/convertFieldToType.h>
+#include <Interpreters/evaluateConstantExpression.h>
+#include <Interpreters/Context.h>
+#include "registerTableFunctions.h"
+
+
+namespace DB
+{
+
+namespace ErrorCodes
+{
+ extern const int BAD_ARGUMENTS;
+ extern const int LOGICAL_ERROR;
+ extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
+ extern const int CANNOT_EXTRACT_TABLE_STRUCTURE;
+}
+
+static void parseAndInsertValues(MutableColumns & res_columns, const ASTs & args, const Block & sample_block, size_t start, ContextPtr context)
+{
+ if (res_columns.size() == 1) /// Parsing arguments as Fields
+ {
+ for (size_t i = start; i < args.size(); ++i)
+ {
+ const auto & [value_field, value_type_ptr] = evaluateConstantExpression(args[i], context);
+
+ Field value = convertFieldToTypeOrThrow(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 = start; i < args.size(); ++i)
+ {
+ const auto & [value_field, value_type_ptr] = evaluateConstantExpression(args[i], context);
+
+ const DataTypeTuple * type_tuple = typeid_cast<const DataTypeTuple *>(value_type_ptr.get());
+ if (!type_tuple)
+ throw Exception(ErrorCodes::BAD_ARGUMENTS,
+ "Table function VALUES requires all but first argument (rows specification) to be either tuples or single values");
+
+ const Tuple & value_tuple = value_field.safeGet<Tuple>();
+
+ if (value_tuple.size() != sample_block.columns())
+ throw Exception(ErrorCodes::BAD_ARGUMENTS, "Values size should match with number of columns");
+
+ const DataTypes & value_types_tuple = type_tuple->getElements();
+ for (size_t j = 0; j < value_tuple.size(); ++j)
+ {
+ Field value = convertFieldToTypeOrThrow(value_tuple[j], *sample_block.getByPosition(j).type, value_types_tuple[j].get());
+ res_columns[j]->insert(value);
+ }
+ }
+ }
+}
+
+DataTypes TableFunctionValues::getTypesFromArgument(const ASTPtr & arg, ContextPtr context)
+{
+ const auto & [value_field, value_type_ptr] = evaluateConstantExpression(arg, context);
+ DataTypes types;
+ if (const DataTypeTuple * type_tuple = typeid_cast<const DataTypeTuple *>(value_type_ptr.get()))
+ return type_tuple->getElements();
+
+ return {value_type_ptr};
+}
+
+void TableFunctionValues::parseArguments(const ASTPtr & ast_function, ContextPtr context)
+{
+ ASTs & args_func = ast_function->children;
+
+ if (args_func.size() != 1)
+ throw Exception(ErrorCodes::LOGICAL_ERROR, "Table function '{}' must have arguments", getName());
+
+ ASTs & args = args_func.at(0)->children;
+
+ if (args.empty())
+ throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Table function '{}' requires at least 1 argument", getName());
+
+ const auto & literal = args[0]->as<const ASTLiteral>();
+ String value;
+ String error;
+ if (args.size() > 1 && literal && literal->value.tryGet(value) && tryParseColumnsListFromString(value, structure, context, error))
+ {
+ has_structure_in_arguments = true;
+ return;
+ }
+
+ has_structure_in_arguments = false;
+ DataTypes data_types = getTypesFromArgument(args[0], context);
+ for (size_t i = 1; i < args.size(); ++i)
+ {
+ auto arg_types = getTypesFromArgument(args[i], context);
+ if (data_types.size() != arg_types.size())
+ throw Exception(
+ ErrorCodes::CANNOT_EXTRACT_TABLE_STRUCTURE,
+ "Cannot determine common structure for {} function arguments: the amount of columns is differ for different arguments",
+ getName());
+ for (size_t j = 0; j != arg_types.size(); ++j)
+ data_types[j] = getLeastSupertype(DataTypes{data_types[j], arg_types[j]});
+ }
+
+ NamesAndTypesList names_and_types;
+ for (size_t i = 0; i != data_types.size(); ++i)
+ names_and_types.emplace_back("c" + std::to_string(i + 1), data_types[i]);
+ structure = ColumnsDescription(names_and_types);
+}
+
+ColumnsDescription TableFunctionValues::getActualTableStructure(ContextPtr /*context*/, bool /*is_insert_query*/) const
+{
+ return structure;
+}
+
+StoragePtr TableFunctionValues::executeImpl(const ASTPtr & ast_function, ContextPtr context, const std::string & table_name, ColumnsDescription /*cached_columns*/, bool is_insert_query) const
+{
+ auto columns = getActualTableStructure(context, is_insert_query);
+
+ Block sample_block;
+ for (const auto & name_type : columns.getOrdinary())
+ sample_block.insert({ name_type.type->createColumn(), name_type.type, name_type.name });
+
+ MutableColumns res_columns = sample_block.cloneEmptyColumns();
+
+ ASTs & args = ast_function->children.at(0)->children;
+
+ /// Parsing other arguments as values and inserting them into columns
+ parseAndInsertValues(res_columns, args, sample_block, has_structure_in_arguments ? 1 : 0, context);
+
+ Block res_block = sample_block.cloneWithColumns(std::move(res_columns));
+
+ auto res = std::make_shared<StorageValues>(StorageID(getDatabaseName(), table_name), columns, res_block);
+ res->startup();
+ return res;
+}
+
+void registerTableFunctionValues(TableFunctionFactory & factory)
+{
+ factory.registerFunction<TableFunctionValues>({.documentation = {}, .allow_readonly = true}, TableFunctionFactory::CaseInsensitive);
+}
+
+}