functions: Remote mode for hasColumnInTable. [#CHEBOTAREV-9]

This commit is contained in:
Vladimir Chebotarev 2017-07-20 00:01:57 +03:00 committed by alexey-milovidov
parent dd0905e906
commit 7254478fde
5 changed files with 71 additions and 20 deletions

View File

@ -16,10 +16,12 @@
#include <DataTypes/DataTypeTuple.h>
#include <DataTypes/DataTypesNumber.h>
#include <Functions/FunctionFactory.h>
#include <Interpreters/Cluster.h>
#include <Interpreters/Context.h>
#include <Interpreters/Set.h>
#include <Storages/IStorage.h>
#include <Common/typeid_cast.h>
#include <TableFunctions/getStructureOfRemoteTable.h>
namespace DB
@ -1666,18 +1668,12 @@ public:
/** Usage:
* hasColumnInTable('database', 'table', 'column')
* hasColumnInTable(['hostname'[, 'username'[, 'password']],] 'database', 'table', 'column')
*/
class FunctionHasColumnInTable : public IFunction
{
public:
static constexpr auto name = "hasColumnInTable";
size_t getNumberOfArguments() const override
{
return 3;
}
static FunctionPtr create(const Context & context)
{
return std::make_shared<FunctionHasColumnInTable>(context.getGlobalContext());
@ -1687,6 +1683,15 @@ public:
{
}
bool isVariadic() const override
{
return true;
}
size_t getNumberOfArguments() const override
{
return 0;
}
String getName() const override
{
return name;
@ -1743,8 +1748,12 @@ void FunctionVisibleWidth::executeImpl(Block & block, const ColumnNumbers & argu
void FunctionHasColumnInTable::getReturnTypeAndPrerequisitesImpl(
const ColumnsWithTypeAndName & arguments, DataTypePtr & out_return_type, ExpressionActions::Actions & out_prerequisites)
{
static const std::string arg_pos_description[] = {"First", "Second", "Third"};
for (size_t i = 0; i < getNumberOfArguments(); ++i)
if (arguments.size() < 3 || arguments.size() > 6)
throw Exception{"Invalid number of arguments for function " + getName(),
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH};
static const std::string arg_pos_description[] = {"First", "Second", "Third", "Fourth", "Fifth", "Sixth"};
for (size_t i = 0; i < arguments.size(); ++i)
{
const ColumnWithTypeAndName & argument = arguments[i];
@ -1768,12 +1777,40 @@ void FunctionHasColumnInTable::executeImpl(Block & block, const ColumnNumbers &
return const_column->getData();
};
const String & database_name = get_string_from_block(arguments[0]);
const String & table_name = get_string_from_block(arguments[1]);
const String & column_name = get_string_from_block(arguments[2]);
size_t arg = 0;
const String * host_name = nullptr;
const String * user_name = nullptr;
const String * password = nullptr;
if (arguments.size() > 3)
{
host_name = &get_string_from_block(arguments[arg++]);
}
if (arguments.size() > 4)
{
user_name = &get_string_from_block(arguments[arg++]);
}
if (arguments.size() > 5)
{
password = &get_string_from_block(arguments[arg++]);
}
const String & database_name = get_string_from_block(arguments[arg++]);
const String & table_name = get_string_from_block(arguments[arg++]);
const String & column_name = get_string_from_block(arguments[arg++]);
const StoragePtr & table = global_context.getTable(database_name, table_name);
const bool has_column = table->hasColumn(column_name);
bool has_column;
if (host_name == nullptr)
{
const StoragePtr & table = global_context.getTable(database_name, table_name);
has_column = table->hasColumn(column_name);
}
else
{
std::vector<std::vector<String>> host_names = {{ *host_name }};
auto cluster = std::make_shared<Cluster>(global_context.getSettings(), host_names, user_name != nullptr ? *user_name : "default", password != nullptr ? *password : "");
auto names_and_types_list = std::make_shared<NamesAndTypesList>(getStructureOfRemoteTable(*cluster, database_name, table_name, global_context));
const auto & names = names_and_types_list->getNames();
has_column = std::find(names.begin(), names.end(), column_name) != names.end();
}
block.safeGetByPosition(result).column = std::make_shared<ColumnConstUInt8>(block.rows(), has_column);
}

View File

@ -2,6 +2,13 @@
1
1
1
1
1
1
1
0
0
0
0
0
0

View File

@ -4,13 +4,20 @@ CREATE TABLE test.has_column_in_table (i Int64, s String, nest Nested(x UInt8, y
/* existing column */
SELECT hasColumnInTable('test', 'has_column_in_table', 'i');
SELECT hasColumnInTable('localhost', 'test', 'has_column_in_table', 'i');
SELECT hasColumnInTable('test', 'has_column_in_table', 's');
SELECT hasColumnInTable('localhost', 'test', 'has_column_in_table', 's');
SELECT hasColumnInTable('test', 'has_column_in_table', 'nest.x');
SELECT hasColumnInTable('localhost', 'test', 'has_column_in_table', 'nest.x');
SELECT hasColumnInTable('test', 'has_column_in_table', 'nest.y');
SELECT hasColumnInTable('localhost', 'test', 'has_column_in_table', 'nest.y');
/* not existing column */
SELECT hasColumnInTable('test', 'has_column_in_table', 'nest');
SELECT hasColumnInTable('localhost', 'test', 'has_column_in_table', 'nest');
SELECT hasColumnInTable('test', 'has_column_in_table', 'nest.not_existing');
SELECT hasColumnInTable('localhost', 'test', 'has_column_in_table', 'nest.not_existing');
SELECT hasColumnInTable('test', 'has_column_in_table', 'not_existing');
SELECT hasColumnInTable('localhost', 'test', 'has_column_in_table', 'not_existing');
DROP TABLE test.has_column_in_table;

View File

@ -50,10 +50,10 @@ isNaN(x)
~~~~~~~~
Accepts Float32 and Float64 and returns UInt8 equal to 1 if the argument is a NaN, otherwise 0.
hasColumnInTable('database', 'table', 'column')
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
hasColumnInTable(['hostname'[, 'username'[, 'password']],] 'database', 'table', 'column')
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Accepts constant String columns - database name, table name and column name. Returns constant UInt8 value, equal to 1 if column exists,
otherwise 0.
otherwise 0. If hostname is specified, the check will proceed on remote host.
If table doesn't exist than exception is thrown.
For elements of nested data structure function checks existence of column. For nested data structure 0 is returned.

View File

@ -50,10 +50,10 @@ isNaN(x)
~~~~~~~~
Принимает Float32 или Float64 и возвращает UInt8, равный 1, если аргумент является NaN, иначе 0.
hasColumnInTable('database', 'table', 'column')
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
hasColumnInTable(['hostname'[, 'username'[, 'password']],] 'database', 'table', 'column')
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Принимает константные строки - имя базы данных, имя таблицы и название столбца. Возвращает константное выражение типа UInt8, равное 1,
если есть столбец, иначе 0.
если есть столбец, иначе 0. Если задан параметр hostname, проверка будет выполнена на удалённом сервере.
Функция кидает исключение, если таблица не существует.
Для элементов вложенной структуры данных функция проверяет существование столбца. Для самой же вложенной структуры данных функция возвращает 0.