StoragePtr TableFunctionShardByHash::execute(ASTPtr ast_function, Context & context) const { ASTs & args_func = typeid_cast<ASTFunction &>(*ast_function).children; const char * err = "Table function 'shardByHash' requires 4 parameters: " "cluster name, key string to hash, name of remote database, name of remote table."; if (args_func.size() != 1) throw Exception(err, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); ASTs & args = typeid_cast<ASTExpressionList &>(*args_func.at(0)).children; if (args.size() != 4) throw Exception(err, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); String cluster_name; String key; String remote_database; String remote_table; auto getStringLiteral = [](const IAST & node, const char * description) { const ASTLiteral * lit = typeid_cast<const ASTLiteral *>(&node); if (!lit) throw Exception(description + String(" must be string literal (in single quotes)."), ErrorCodes::BAD_ARGUMENTS); if (lit->value.getType() != Field::Types::String) throw Exception(description + String(" must be string literal (in single quotes)."), ErrorCodes::BAD_ARGUMENTS); return safeGet<const String &>(lit->value); }; cluster_name = getClusterName(*args[0]); key = getStringLiteral(*args[1], "Key to hash"); args[2] = evaluateConstantExpressionOrIdentidierAsLiteral(args[2], context); args[3] = evaluateConstantExpressionOrIdentidierAsLiteral(args[3], context); remote_database = static_cast<const ASTLiteral &>(*args[2]).value.safeGet<String>(); remote_table = static_cast<const ASTLiteral &>(*args[3]).value.safeGet<String>(); /// Аналогично другим TableFunctions. for (auto & arg : args) if (ASTIdentifier * id = typeid_cast<ASTIdentifier *>(arg.get())) id->kind = ASTIdentifier::Table; const Cluster & cluster = context.getCluster(cluster_name); size_t shard_index = sipHash64(key) % cluster.getShardCount(); std::shared_ptr<Cluster> shard(cluster.getClusterWithSingleShard(shard_index).release()); return StorageDistributed::create( getName(), std::make_shared<NamesAndTypesList>(getStructureOfRemoteTable(*shard, remote_database, remote_table, context)), remote_database, remote_table, shard, context); }
void FunctionHasColumnInTable::executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) { auto get_string_from_block = [&](size_t column_pos) -> String { ColumnPtr column = block.getByPosition(column_pos).column; const ColumnConst * const_column = checkAndGetColumnConst<ColumnString>(column.get()); return const_column->getValue<String>(); }; size_t arg = 0; String host_name; String user_name; String password; 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++]); String database_name = get_string_from_block(arguments[arg++]); String table_name = get_string_from_block(arguments[arg++]); String column_name = get_string_from_block(arguments[arg++]); bool has_column; if (host_name.empty()) { 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.empty() ? user_name : "default", password, global_context.getTCPPort(), false); auto remote_columns = getStructureOfRemoteTable(*cluster, database_name, table_name, global_context); has_column = remote_columns.hasPhysical(column_name); } block.getByPosition(result).column = DataTypeUInt8().createColumnConst(input_rows_count, has_column); }
StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const Context & context) const { ASTs & args_func = typeid_cast<ASTFunction &>(*ast_function).children; if (args_func.size() != 1) throw Exception(help_message, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); ASTs & args = typeid_cast<ASTExpressionList &>(*args_func.at(0)).children; const size_t max_args = is_cluster_function ? 3 : 5; if (args.size() < 2 || args.size() > max_args) throw Exception(help_message, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); String cluster_name; String cluster_description; String remote_database; String remote_table; String username; String password; size_t arg_num = 0; auto getStringLiteral = [](const IAST & node, const char * description) { const ASTLiteral * lit = typeid_cast<const ASTLiteral *>(&node); if (!lit) throw Exception(description + String(" must be string literal (in single quotes)."), ErrorCodes::BAD_ARGUMENTS); if (lit->value.getType() != Field::Types::String) throw Exception(description + String(" must be string literal (in single quotes)."), ErrorCodes::BAD_ARGUMENTS); return safeGet<const String &>(lit->value); }; if (is_cluster_function) { ASTPtr ast_name = evaluateConstantExpressionOrIdentifierAsLiteral(args[arg_num], context); cluster_name = static_cast<const ASTLiteral &>(*ast_name).value.safeGet<const String &>(); } else { if (auto ast_cluster = typeid_cast<const ASTIdentifier *>(args[arg_num].get())) cluster_name = ast_cluster->name; else cluster_description = getStringLiteral(*args[arg_num], "Hosts pattern"); } ++arg_num; args[arg_num] = evaluateConstantExpressionOrIdentifierAsLiteral(args[arg_num], context); remote_database = static_cast<const ASTLiteral &>(*args[arg_num]).value.safeGet<String>(); ++arg_num; size_t dot = remote_database.find('.'); if (dot != String::npos) { /// NOTE Bad - do not support identifiers in backquotes. remote_table = remote_database.substr(dot + 1); remote_database = remote_database.substr(0, dot); } else { if (arg_num >= args.size()) throw Exception(help_message, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); args[arg_num] = evaluateConstantExpressionOrIdentifierAsLiteral(args[arg_num], context); remote_table = static_cast<const ASTLiteral &>(*args[arg_num]).value.safeGet<String>(); ++arg_num; } /// Username and password parameters are prohibited in cluster version of the function if (!is_cluster_function) { if (arg_num < args.size()) { username = getStringLiteral(*args[arg_num], "Username"); ++arg_num; } else username = "******"; if (arg_num < args.size()) { password = getStringLiteral(*args[arg_num], "Password"); ++arg_num; } } if (arg_num < args.size()) throw Exception(help_message, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); /// ExpressionAnalyzer will be created in InterpreterSelectQuery that will meet these `Identifier` when processing the request. /// We need to mark them as the name of the database or table, because the default value is column. for (auto & arg : args) if (ASTIdentifier * id = typeid_cast<ASTIdentifier *>(arg.get())) id->kind = ASTIdentifier::Table; ClusterPtr cluster; if (!cluster_name.empty()) { /// Use an existing cluster from the main config cluster = context.getCluster(cluster_name); } else { /// Create new cluster from the scratch size_t max_addresses = context.getSettingsRef().table_function_remote_max_addresses; std::vector<String> shards = parseDescription(cluster_description, 0, cluster_description.size(), ',', max_addresses); std::vector<std::vector<String>> names; for (size_t i = 0; i < shards.size(); ++i) names.push_back(parseDescription(shards[i], 0, shards[i].size(), '|', max_addresses)); if (names.empty()) throw Exception("Shard list is empty after parsing first argument", ErrorCodes::BAD_ARGUMENTS); cluster = std::make_shared<Cluster>(context.getSettings(), names, username, password, context.getTCPPort(), false); } auto res = StorageDistributed::createWithOwnCluster( getName(), getStructureOfRemoteTable(*cluster, remote_database, remote_table, context), remote_database, remote_table, cluster, context); res->startup(); return res; }
StoragePtr TableFunctionRemote::execute(const ASTPtr & ast_function, const Context & context) const { ASTs & args_func = typeid_cast<ASTFunction &>(*ast_function).children; const char * err = "Table function 'remote' requires from 2 to 5 parameters: " "addresses pattern, name of remote database, name of remote table, [username, [password]]."; if (args_func.size() != 1) throw Exception(err, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); ASTs & args = typeid_cast<ASTExpressionList &>(*args_func.at(0)).children; if (args.size() < 2 || args.size() > 5) throw Exception(err, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); String description; String remote_database; String remote_table; String username; String password; size_t arg_num = 0; auto getStringLiteral = [](const IAST & node, const char * description) { const ASTLiteral * lit = typeid_cast<const ASTLiteral *>(&node); if (!lit) throw Exception(description + String(" must be string literal (in single quotes)."), ErrorCodes::BAD_ARGUMENTS); if (lit->value.getType() != Field::Types::String) throw Exception(description + String(" must be string literal (in single quotes)."), ErrorCodes::BAD_ARGUMENTS); return safeGet<const String &>(lit->value); }; description = getStringLiteral(*args[arg_num], "Hosts pattern"); ++arg_num; args[arg_num] = evaluateConstantExpressionOrIdentidierAsLiteral(args[arg_num], context); remote_database = static_cast<const ASTLiteral &>(*args[arg_num]).value.safeGet<String>(); ++arg_num; size_t dot = remote_database.find('.'); if (dot != String::npos) { /// NOTE Bad - do not support identifiers in backquotes. remote_table = remote_database.substr(dot + 1); remote_database = remote_database.substr(0, dot); } else { if (arg_num >= args.size()) throw Exception(err, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); args[arg_num] = evaluateConstantExpressionOrIdentidierAsLiteral(args[arg_num], context); remote_table = static_cast<const ASTLiteral &>(*args[arg_num]).value.safeGet<String>(); ++arg_num; } if (arg_num < args.size()) { username = getStringLiteral(*args[arg_num], "Username"); ++arg_num; } else username = "******"; if (arg_num < args.size()) { password = getStringLiteral(*args[arg_num], "Password"); ++arg_num; } if (arg_num < args.size()) throw Exception(err, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); /// ExpressionAnalyzer will be created in InterpreterSelectQuery that will meet these `Identifier` when processing the request. /// We need to mark them as the name of the database or table, because the default value is column. for (auto & arg : args) if (ASTIdentifier * id = typeid_cast<ASTIdentifier *>(arg.get())) id->kind = ASTIdentifier::Table; size_t max_addresses = context.getSettingsRef().table_function_remote_max_addresses; std::vector<std::vector<String>> names; std::vector<String> shards = parseDescription(description, 0, description.size(), ',', max_addresses); for (size_t i = 0; i < shards.size(); ++i) names.push_back(parseDescription(shards[i], 0, shards[i].size(), '|', max_addresses)); if (names.empty()) throw Exception("Shard list is empty after parsing first argument", ErrorCodes::BAD_ARGUMENTS); auto cluster = std::make_shared<Cluster>(context.getSettings(), names, username, password); return StorageDistributed::create( getName(), std::make_shared<NamesAndTypesList>(getStructureOfRemoteTable(*cluster, remote_database, remote_table, context)), remote_database, remote_table, cluster, context); }