mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
fold constant expressions in storage engine arguments
This commit is contained in:
parent
3e0b76a077
commit
c492ee93d9
@ -16,6 +16,7 @@
|
||||
#include <TableFunctions/TableFunctionFactory.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <Interpreters/ReplaceQueryParameterVisitor.h>
|
||||
#include <Poco/Util/AbstractConfiguration.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -25,6 +26,7 @@ namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
extern const int BAD_ARGUMENTS;
|
||||
extern const int UNKNOWN_DATABASE;
|
||||
}
|
||||
|
||||
|
||||
@ -67,6 +69,7 @@ ASTPtr evaluateConstantExpressionAsLiteral(const ASTPtr & node, const Context &
|
||||
return node;
|
||||
|
||||
/// Skip table functions.
|
||||
///FIXME it's very surprising that function which evaluates smth as literal may return ASTFunction instead of ASTLiteral
|
||||
if (const auto * table_func_ptr = node->as<ASTFunction>())
|
||||
if (TableFunctionFactory::instance().isTableFunctionName(table_func_ptr->name))
|
||||
return node;
|
||||
@ -82,6 +85,25 @@ ASTPtr evaluateConstantExpressionOrIdentifierAsLiteral(const ASTPtr & node, cons
|
||||
return evaluateConstantExpressionAsLiteral(node, context);
|
||||
}
|
||||
|
||||
ASTPtr evaluateConstantExpressionForDatabaseName(const ASTPtr & node, const Context & context)
|
||||
{
|
||||
ASTPtr res = evaluateConstantExpressionOrIdentifierAsLiteral(node, context);
|
||||
auto & literal = res->as<ASTLiteral &>();
|
||||
if (literal.value.safeGet<String>().empty())
|
||||
{
|
||||
String current_database = context.getCurrentDatabase();
|
||||
if (current_database.empty())
|
||||
{
|
||||
/// Table was created on older version of ClickHouse and CREATE contains not folded expression.
|
||||
/// Current database is not set yet during server startup, so we cannot evaluate it correctly.
|
||||
literal.value = context.getConfigRef().getString("default_database", "default");
|
||||
}
|
||||
else
|
||||
literal.value = current_database;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using Conjunction = ColumnsWithTypeAndName;
|
||||
|
@ -37,6 +37,12 @@ ASTPtr evaluateConstantExpressionAsLiteral(const ASTPtr & node, const Context &
|
||||
*/
|
||||
ASTPtr evaluateConstantExpressionOrIdentifierAsLiteral(const ASTPtr & node, const Context & context);
|
||||
|
||||
/** The same as evaluateConstantExpressionOrIdentifierAsLiteral(...),
|
||||
* but if result is an empty string, replace it with current database name
|
||||
* or default database name.
|
||||
*/
|
||||
ASTPtr evaluateConstantExpressionForDatabaseName(const ASTPtr & node, const Context & context);
|
||||
|
||||
/** Try to fold condition to countable set of constant values.
|
||||
* @param condition a condition that we try to fold.
|
||||
* @param target_expr expression evaluated over a set of constants.
|
||||
|
@ -788,7 +788,7 @@ void registerStorageBuffer(StorageFactory & factory)
|
||||
" destination_database, destination_table, num_buckets, min_time, max_time, min_rows, max_rows, min_bytes, max_bytes.",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
|
||||
engine_args[0] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[0], args.local_context);
|
||||
engine_args[0] = evaluateConstantExpressionForDatabaseName(engine_args[0], args.local_context);
|
||||
engine_args[1] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[1], args.local_context);
|
||||
|
||||
String destination_database = engine_args[0]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
|
@ -253,6 +253,10 @@ StorageDistributed::StorageDistributed(
|
||||
if (num_local_shards && remote_database == id_.database_name && remote_table == id_.table_name)
|
||||
throw Exception("Distributed table " + id_.table_name + " looks at itself", ErrorCodes::INFINITE_LOOP);
|
||||
}
|
||||
if (remote_database.empty())
|
||||
{
|
||||
LOG_WARNING(log, "Name of remote database is empty. Default database will be used implicitly.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,9 +49,10 @@ StoragePtr StorageFactory::get(
|
||||
bool has_force_restore_data_flag) const
|
||||
{
|
||||
String name;
|
||||
ASTs args;
|
||||
ASTStorage * storage_def = query.storage;
|
||||
|
||||
bool has_engine_args = false;
|
||||
|
||||
if (query.is_view)
|
||||
{
|
||||
if (query.storage)
|
||||
@ -89,7 +90,7 @@ StoragePtr StorageFactory::get(
|
||||
"Engine definition cannot take the form of a parametric function", ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS);
|
||||
|
||||
if (engine_def.arguments)
|
||||
args = engine_def.arguments->children;
|
||||
has_engine_args = true;
|
||||
|
||||
name = engine_def.name;
|
||||
|
||||
@ -162,10 +163,11 @@ StoragePtr StorageFactory::get(
|
||||
}
|
||||
}
|
||||
|
||||
ASTs empty_engine_args;
|
||||
Arguments arguments
|
||||
{
|
||||
.engine_name = name,
|
||||
.engine_args = args,
|
||||
.engine_args = has_engine_args ? storage_def->engine->arguments->children : empty_engine_args,
|
||||
.storage_def = storage_def,
|
||||
.query = query,
|
||||
.relative_data_path = relative_data_path,
|
||||
|
@ -509,7 +509,7 @@ void registerStorageMerge(StorageFactory & factory)
|
||||
" - name of source database and regexp for table names.",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
|
||||
engine_args[0] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[0], args.local_context);
|
||||
engine_args[0] = evaluateConstantExpressionForDatabaseName(engine_args[0], args.local_context);
|
||||
engine_args[1] = evaluateConstantExpressionAsLiteral(engine_args[1], args.local_context);
|
||||
|
||||
String source_database = engine_args[0]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <TableFunctions/TableFunctionMerge.h>
|
||||
#include <TableFunctions/TableFunctionFactory.h>
|
||||
#include "registerTableFunctions.h"
|
||||
#include <TableFunctions/registerTableFunctions.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -62,7 +62,7 @@ StoragePtr TableFunctionMerge::executeImpl(const ASTPtr & ast_function, const Co
|
||||
" - name of source database and regexp for table names.",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
|
||||
args[0] = evaluateConstantExpressionOrIdentifierAsLiteral(args[0], context);
|
||||
args[0] = evaluateConstantExpressionForDatabaseName(args[0], context);
|
||||
args[1] = evaluateConstantExpressionAsLiteral(args[1], context);
|
||||
|
||||
String source_database = args[0]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
|
@ -65,8 +65,8 @@ StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const C
|
||||
|
||||
if (is_cluster_function)
|
||||
{
|
||||
ASTPtr ast_name = evaluateConstantExpressionOrIdentifierAsLiteral(args[arg_num], context);
|
||||
cluster_name = ast_name->as<ASTLiteral &>().value.safeGet<const String &>();
|
||||
args[arg_num] = evaluateConstantExpressionOrIdentifierAsLiteral(args[arg_num], context);
|
||||
cluster_name = args[arg_num]->as<ASTLiteral &>().value.safeGet<const String &>();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1,13 +1,18 @@
|
||||
DROP TABLE IF EXISTS distr0;
|
||||
DROP TABLE IF EXISTS distr1;
|
||||
DROP TABLE IF EXISTS distr2;
|
||||
|
||||
CREATE TABLE distr (x UInt8) ENGINE = Distributed(test_shard_localhost, currentDatabase(), distr); -- { serverError 269 }
|
||||
|
||||
CREATE TABLE distr0 (x UInt8) ENGINE = Distributed(test_shard_localhost, '', distr0);
|
||||
SELECT * FROM distr0; -- { serverError 306 }
|
||||
|
||||
CREATE TABLE distr1 (x UInt8) ENGINE = Distributed(test_shard_localhost, currentDatabase(), distr2);
|
||||
CREATE TABLE distr2 (x UInt8) ENGINE = Distributed(test_shard_localhost, currentDatabase(), distr1);
|
||||
|
||||
SELECT * FROM distr1; -- { serverError 306 }
|
||||
SELECT * FROM distr2; -- { serverError 306 }
|
||||
|
||||
DROP TABLE distr0;
|
||||
DROP TABLE distr1;
|
||||
DROP TABLE distr2;
|
||||
|
@ -0,0 +1,6 @@
|
||||
CREATE TABLE test_01083.file (`n` Int8) ENGINE = File(\'TSVWithNamesAndTypes\')
|
||||
CREATE TABLE test_01083.buffer (`n` Int8) ENGINE = Buffer(\'test_01083\', \'file\', 16, 10, 200, 10000, 1000000, 10000000, 1000000000)
|
||||
CREATE TABLE test_01083.merge (`n` Int8) ENGINE = Merge(\'test_01083\', \'file\')
|
||||
CREATE TABLE test_01083.merge_tf AS merge(\'test_01083\', \'.*\')
|
||||
CREATE TABLE test_01083.distributed (`n` Int8) ENGINE = Distributed(test_cluster, \'test_01083\', \'file\')
|
||||
CREATE TABLE test_01083.distributed_tf AS cluster(\'test_cluster\', \'test_01083\', \'file\')
|
@ -0,0 +1,19 @@
|
||||
DROP DATABASE IF EXISTS test_01083;
|
||||
CREATE DATABASE test_01083;
|
||||
USE test_01083;
|
||||
|
||||
CREATE TABLE file (n Int8) ENGINE = File(upper('tsv') || 'WithNames' || 'AndTypes');
|
||||
CREATE TABLE buffer (n Int8) ENGINE = Buffer(currentDatabase(), file, 16, 10, 200, 10000, 1000000, 10000000, 1000000000);
|
||||
CREATE TABLE merge (n Int8) ENGINE = Merge('', lower('FILE'));
|
||||
CREATE TABLE merge_tf as merge(currentDatabase(), '.*');
|
||||
CREATE TABLE distributed (n Int8) ENGINE = Distributed(test_cluster, currentDatabase(), 'fi' || 'le');
|
||||
CREATE TABLE distributed_tf as cluster('test' || '_' || 'cluster', currentDatabase(), 'fi' || 'le');
|
||||
|
||||
SHOW CREATE file;
|
||||
SHOW CREATE buffer;
|
||||
SHOW CREATE merge;
|
||||
SHOW CREATE merge_tf;
|
||||
SHOW CREATE distributed;
|
||||
SHOW CREATE distributed_tf;
|
||||
|
||||
DROP DATABASE test_01083;
|
Loading…
Reference in New Issue
Block a user