mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-03 13:02:00 +00:00
Fixed review comments and updated FunctionParameterValuesVisitor to use visitFunction - 40907 Parameterized views as table functions
This commit is contained in:
parent
5001cf9fa2
commit
a6f860f24e
@ -510,9 +510,10 @@ InterpreterSelectQuery::InterpreterSelectQuery(
|
|||||||
if (view)
|
if (view)
|
||||||
{
|
{
|
||||||
query_info.is_parameterized_view = view->isParameterizedView();
|
query_info.is_parameterized_view = view->isParameterizedView();
|
||||||
/// We need to fetch the parameters set for SELECT parameterized view before the query is replaced.
|
/// We need to fetch the parameters set for SELECT ... FROM parameterized_view(<params>) before the query is replaced.
|
||||||
/// replaceWithSubquery replaces the function child and adds the subquery in its place.
|
/// replaceWithSubquery replaces the function child and adds the subquery in its place.
|
||||||
/// the parameters are children of function child, if function is replaced the parameters are also gone from tree
|
/// the parameters are children of function child, if function (which corresponds to parametrised view and has
|
||||||
|
/// parameters in its arguments: `parametrised_view(<params>)`) is replaced the parameters are also gone from tree
|
||||||
/// So we need to get the parameters before they are removed from the tree
|
/// So we need to get the parameters before they are removed from the tree
|
||||||
/// and after query is replaced, we use these parameters to substitute in the parameterized view query
|
/// and after query is replaced, we use these parameters to substitute in the parameterized view query
|
||||||
if (query_info.is_parameterized_view)
|
if (query_info.is_parameterized_view)
|
||||||
|
@ -27,8 +27,8 @@ public:
|
|||||||
|
|
||||||
void visit(const ASTPtr & ast)
|
void visit(const ASTPtr & ast)
|
||||||
{
|
{
|
||||||
if (const auto * expression = ast->as<ASTExpressionList>())
|
if (const auto * function = ast->as<ASTFunction>())
|
||||||
visitExpressionList(*expression);
|
visitFunction(*function);
|
||||||
for (const auto & child : ast->children)
|
for (const auto & child : ast->children)
|
||||||
visit(child);
|
visit(child);
|
||||||
}
|
}
|
||||||
@ -36,18 +36,23 @@ public:
|
|||||||
private:
|
private:
|
||||||
NameToNameMap & parameter_values;
|
NameToNameMap & parameter_values;
|
||||||
|
|
||||||
void visitExpressionList(const ASTExpressionList & expression_list)
|
void visitFunction(const ASTFunction & parameter_function)
|
||||||
{
|
{
|
||||||
if (expression_list.children.size() != 2)
|
if (parameter_function.name != "equals" && parameter_function.children.size() != 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (const auto * identifier = expression_list.children[0]->as<ASTIdentifier>())
|
const auto * expression_list = parameter_function.children[0]->as<ASTExpressionList>();
|
||||||
|
|
||||||
|
if (expression_list && expression_list->children.size() != 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (const auto * identifier = expression_list->children[0]->as<ASTIdentifier>())
|
||||||
{
|
{
|
||||||
if (const auto * literal = expression_list.children[1]->as<ASTLiteral>())
|
if (const auto * literal = expression_list->children[1]->as<ASTLiteral>())
|
||||||
{
|
{
|
||||||
parameter_values[identifier->name()] = convertFieldToString(literal->value);
|
parameter_values[identifier->name()] = convertFieldToString(literal->value);
|
||||||
}
|
}
|
||||||
else if (const auto * function = expression_list.children[1]->as<ASTFunction>())
|
else if (const auto * function = expression_list->children[1]->as<ASTFunction>())
|
||||||
{
|
{
|
||||||
if (isFunctionCast(function))
|
if (isFunctionCast(function))
|
||||||
{
|
{
|
||||||
|
@ -117,10 +117,11 @@ Block StorageSnapshot::getSampleBlockForColumns(const Names & column_names,const
|
|||||||
Block res;
|
Block res;
|
||||||
|
|
||||||
const auto & columns = getMetadataForQuery()->getColumns();
|
const auto & columns = getMetadataForQuery()->getColumns();
|
||||||
for (const auto & name : column_names)
|
for (const auto & column_name : column_names)
|
||||||
{
|
{
|
||||||
const std::string & column_name = name;
|
/// substituted_column_name is used for parameterized view (which are created using query parameters
|
||||||
std::string substituted_column_name = name;
|
/// and SELECT is used with substitution of these query parameters )
|
||||||
|
std::string substituted_column_name = column_name;
|
||||||
std::string::size_type pos = 0u;
|
std::string::size_type pos = 0u;
|
||||||
for (const auto & parameter : parameter_values)
|
for (const auto & parameter : parameter_values)
|
||||||
{
|
{
|
||||||
@ -141,17 +142,17 @@ Block StorageSnapshot::getSampleBlockForColumns(const Names & column_names,const
|
|||||||
{
|
{
|
||||||
res.insert({object_column->type->createColumn(), object_column->type, column_name});
|
res.insert({object_column->type->createColumn(), object_column->type, column_name});
|
||||||
}
|
}
|
||||||
else if (auto it = virtual_columns.find(name); it != virtual_columns.end())
|
else if (auto it = virtual_columns.find(column_name); it != virtual_columns.end())
|
||||||
{
|
{
|
||||||
/// Virtual columns must be appended after ordinary, because user can
|
/// Virtual columns must be appended after ordinary, because user can
|
||||||
/// override them.
|
/// override them.
|
||||||
const auto & type = it->second;
|
const auto & type = it->second;
|
||||||
res.insert({type->createColumn(), type, name});
|
res.insert({type->createColumn(), type, column_name});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw Exception(ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK,
|
throw Exception(ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK,
|
||||||
"Column {} not found in table {}", backQuote(name), storage.getStorageID().getNameForLogs());
|
"Column {} not found in table {}", backQuote(substituted_column_name), storage.getStorageID().getNameForLogs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
Loading…
Reference in New Issue
Block a user