mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-19 16:20:50 +00:00
Merge 586182a045
into b94a7167a8
This commit is contained in:
commit
d7ef96e36b
@ -41,15 +41,24 @@ SELECT a, b, c FROM (SELECT ...)
|
|||||||
|
|
||||||
## Parameterized View
|
## Parameterized View
|
||||||
|
|
||||||
Parametrized views are similar to normal views, but can be created with parameters which are not resolved immediately. These views can be used with table functions, which specify the name of the view as function name and the parameter values as its arguments.
|
Parametrized views are similar to normal views, but can be created with parameters which are not resolved immediately.
|
||||||
|
These views can be used with table functions, which specify the name of the view as function name and the parameter values as its arguments.
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
CREATE VIEW view AS SELECT * FROM TABLE WHERE Column1={column1:datatype1} and Column2={column2:datatype2} ...
|
CREATE VIEW param_view AS SELECT * FROM TABLE WHERE Column1={column1:datatype1} and Column2={column2:datatype2} ...
|
||||||
```
|
```
|
||||||
The above creates a view for table which can be used as table function by substituting parameters as shown below.
|
The above creates a view for table which can be used as table function by substituting parameters as shown below.
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
SELECT * FROM view(column1=value1, column2=value2 ...)
|
SELECT * FROM param_view(column1=value1, column2=value2 ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
Since the parameterized view depends on the parameter values, it doesn't have a schema when parameters are not provided.
|
||||||
|
That means there's no information about parameterized views in the `system.columns` table.
|
||||||
|
Also, `DESCRIBE` queries would work only if parameters are provided.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DESCRIBE param_view(column1=value1, column2=value2 ...)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Materialized View
|
## Materialized View
|
||||||
|
@ -4511,20 +4511,7 @@ void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node,
|
|||||||
TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().tryGet(table_function_name, scope_context);
|
TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().tryGet(table_function_name, scope_context);
|
||||||
if (!table_function_ptr)
|
if (!table_function_ptr)
|
||||||
{
|
{
|
||||||
String database_name = scope_context->getCurrentDatabase();
|
auto [database_name, table_name] = extractDatabaseAndTableNameForParametrizedView(table_function_name, scope_context);
|
||||||
String table_name;
|
|
||||||
|
|
||||||
auto function_ast = table_function_node->toAST();
|
|
||||||
Identifier table_identifier{table_function_name};
|
|
||||||
if (table_identifier.getPartsSize() == 1)
|
|
||||||
{
|
|
||||||
table_name = table_identifier[0];
|
|
||||||
}
|
|
||||||
else if (table_identifier.getPartsSize() == 2)
|
|
||||||
{
|
|
||||||
database_name = table_identifier[0];
|
|
||||||
table_name = table_identifier[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Collect parametrized view arguments
|
/// Collect parametrized view arguments
|
||||||
NameToNameMap view_params;
|
NameToNameMap view_params;
|
||||||
@ -4566,9 +4553,9 @@ void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node,
|
|||||||
|
|
||||||
if (parametrized_view_storage)
|
if (parametrized_view_storage)
|
||||||
{
|
{
|
||||||
auto fake_table_node = std::make_shared<TableNode>(parametrized_view_storage, scope_context);
|
std::vector<size_t> skip_analysis_arguments_indexes(table_function_node_typed.getArguments().getNodes().size());
|
||||||
fake_table_node->setAlias(table_function_node->getAlias());
|
std::iota(skip_analysis_arguments_indexes.begin(), skip_analysis_arguments_indexes.end(), 0);
|
||||||
table_function_node = fake_table_node;
|
table_function_node_typed.resolve({}, parametrized_view_storage, scope_context, std::move(skip_analysis_arguments_indexes));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ public:
|
|||||||
/// Returns true, if table function is resolved, false otherwise
|
/// Returns true, if table function is resolved, false otherwise
|
||||||
bool isResolved() const
|
bool isResolved() const
|
||||||
{
|
{
|
||||||
return storage != nullptr && table_function != nullptr;
|
return storage != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get table function, returns nullptr if table function node is not resolved
|
/// Get table function, returns nullptr if table function node is not resolved
|
||||||
|
@ -938,4 +938,23 @@ QueryTreeNodePtr buildSubqueryToReadColumnsFromTableExpression(const QueryTreeNo
|
|||||||
return buildSubqueryToReadColumnsFromTableExpression(columns_to_select, table_node, context);
|
return buildSubqueryToReadColumnsFromTableExpression(columns_to_select, table_node, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<String, String> extractDatabaseAndTableNameForParametrizedView(const String & table_function_name, const ContextPtr & context)
|
||||||
|
{
|
||||||
|
String database_name = context->getCurrentDatabase();
|
||||||
|
String table_name;
|
||||||
|
|
||||||
|
Identifier table_identifier{table_function_name};
|
||||||
|
if (table_identifier.getPartsSize() == 1)
|
||||||
|
{
|
||||||
|
table_name = table_identifier[0];
|
||||||
|
}
|
||||||
|
else if (table_identifier.getPartsSize() == 2)
|
||||||
|
{
|
||||||
|
database_name = table_identifier[0];
|
||||||
|
table_name = table_identifier[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return { database_name, table_name };
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -159,5 +159,6 @@ QueryTreeNodePtr buildSubqueryToReadColumnsFromTableExpression(const NamesAndTyp
|
|||||||
*/
|
*/
|
||||||
QueryTreeNodePtr buildSubqueryToReadColumnsFromTableExpression(const QueryTreeNodePtr & table_node, const ContextPtr & context);
|
QueryTreeNodePtr buildSubqueryToReadColumnsFromTableExpression(const QueryTreeNodePtr & table_node, const ContextPtr & context);
|
||||||
|
|
||||||
|
std::pair<String, String> extractDatabaseAndTableNameForParametrizedView(const String & table_function_name, const ContextPtr & context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,15 @@
|
|||||||
#include <QueryPipeline/BlockIO.h>
|
#include <QueryPipeline/BlockIO.h>
|
||||||
#include <DataTypes/DataTypeString.h>
|
#include <DataTypes/DataTypeString.h>
|
||||||
#include <Parsers/queryToString.h>
|
#include <Parsers/queryToString.h>
|
||||||
|
#include <Parsers/FunctionParameterValuesVisitor.h>
|
||||||
#include <Common/typeid_cast.h>
|
#include <Common/typeid_cast.h>
|
||||||
|
#include <Analyzer/Utils.h>
|
||||||
|
#include <Analyzer/Passes/QueryAnalysisPass.h>
|
||||||
|
#include <Analyzer/QueryTreeBuilder.h>
|
||||||
|
#include <Analyzer/TableFunctionNode.h>
|
||||||
|
#include <Analyzer/TableNode.h>
|
||||||
#include <Core/Settings.h>
|
#include <Core/Settings.h>
|
||||||
|
#include <Storages/StorageView.h>
|
||||||
#include <TableFunctions/ITableFunction.h>
|
#include <TableFunctions/ITableFunction.h>
|
||||||
#include <TableFunctions/TableFunctionFactory.h>
|
#include <TableFunctions/TableFunctionFactory.h>
|
||||||
#include <Interpreters/InterpreterSelectWithUnionQuery.h>
|
#include <Interpreters/InterpreterSelectWithUnionQuery.h>
|
||||||
@ -24,6 +31,14 @@
|
|||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace ErrorCodes
|
||||||
|
{
|
||||||
|
|
||||||
|
extern const int UNSUPPORTED_METHOD;
|
||||||
|
extern const int UNKNOWN_FUNCTION;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
InterpreterDescribeQuery::InterpreterDescribeQuery(const ASTPtr & query_ptr_, ContextPtr context_)
|
InterpreterDescribeQuery::InterpreterDescribeQuery(const ASTPtr & query_ptr_, ContextPtr context_)
|
||||||
: WithContext(context_)
|
: WithContext(context_)
|
||||||
, query_ptr(query_ptr_)
|
, query_ptr(query_ptr_)
|
||||||
@ -125,10 +140,14 @@ BlockIO InterpreterDescribeQuery::execute()
|
|||||||
|
|
||||||
void InterpreterDescribeQuery::fillColumnsFromSubquery(const ASTTableExpression & table_expression)
|
void InterpreterDescribeQuery::fillColumnsFromSubquery(const ASTTableExpression & table_expression)
|
||||||
{
|
{
|
||||||
Block sample_block;
|
|
||||||
auto select_query = table_expression.subquery->children.at(0);
|
auto select_query = table_expression.subquery->children.at(0);
|
||||||
auto current_context = getContext();
|
auto current_context = getContext();
|
||||||
|
fillColumnsFromSubqueryImpl(select_query, current_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterpreterDescribeQuery::fillColumnsFromSubqueryImpl(const ASTPtr & select_query, const ContextPtr & current_context)
|
||||||
|
{
|
||||||
|
Block sample_block;
|
||||||
if (settings.allow_experimental_analyzer)
|
if (settings.allow_experimental_analyzer)
|
||||||
{
|
{
|
||||||
SelectQueryOptions select_query_options;
|
SelectQueryOptions select_query_options;
|
||||||
@ -146,7 +165,39 @@ void InterpreterDescribeQuery::fillColumnsFromSubquery(const ASTTableExpression
|
|||||||
void InterpreterDescribeQuery::fillColumnsFromTableFunction(const ASTTableExpression & table_expression)
|
void InterpreterDescribeQuery::fillColumnsFromTableFunction(const ASTTableExpression & table_expression)
|
||||||
{
|
{
|
||||||
auto current_context = getContext();
|
auto current_context = getContext();
|
||||||
TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().get(table_expression.table_function, current_context);
|
|
||||||
|
auto table_function_name = table_expression.table_function->as<ASTFunction>()->name;
|
||||||
|
TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().tryGet(table_function_name, current_context);
|
||||||
|
|
||||||
|
if (!table_function_ptr)
|
||||||
|
{
|
||||||
|
auto [database_name, table_name] = extractDatabaseAndTableNameForParametrizedView(table_function_name, current_context);
|
||||||
|
auto table_id = getContext()->resolveStorageID({database_name, table_name});
|
||||||
|
getContext()->checkAccess(AccessType::SHOW_COLUMNS, table_id);
|
||||||
|
auto table = DatabaseCatalog::instance().getTable(table_id, getContext());
|
||||||
|
|
||||||
|
if (auto * storage_view = table->as<StorageView>())
|
||||||
|
{
|
||||||
|
if (storage_view->isParameterizedView())
|
||||||
|
{
|
||||||
|
auto query = storage_view->getInMemoryMetadataPtr()->getSelectQuery().inner_query->clone();
|
||||||
|
NameToNameMap parameterized_view_values = analyzeFunctionParamValues(table_expression.table_function, current_context);
|
||||||
|
StorageView::replaceQueryParametersIfParametrizedView(query, parameterized_view_values);
|
||||||
|
fillColumnsFromSubqueryImpl(query, current_context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hints = TableFunctionFactory::instance().getHints(table_function_name);
|
||||||
|
if (!hints.empty())
|
||||||
|
throw Exception(ErrorCodes::UNKNOWN_FUNCTION, "Unknown table function {}. Maybe you meant: {}", table_function_name, toString(hints));
|
||||||
|
else
|
||||||
|
throw Exception(ErrorCodes::UNKNOWN_FUNCTION, "Unknown table function {}", table_function_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
table_function_ptr->parseArguments(table_expression.table_function, current_context);
|
||||||
|
}
|
||||||
|
|
||||||
auto column_descriptions = table_function_ptr->getActualTableStructure(getContext(), /*is_insert_query*/ true);
|
auto column_descriptions = table_function_ptr->getActualTableStructure(getContext(), /*is_insert_query*/ true);
|
||||||
for (const auto & column : column_descriptions)
|
for (const auto & column : column_descriptions)
|
||||||
@ -172,6 +223,14 @@ void InterpreterDescribeQuery::fillColumnsFromTable(const ASTTableExpression & t
|
|||||||
auto table_id = getContext()->resolveStorageID(table_expression.database_and_table_name);
|
auto table_id = getContext()->resolveStorageID(table_expression.database_and_table_name);
|
||||||
getContext()->checkAccess(AccessType::SHOW_COLUMNS, table_id);
|
getContext()->checkAccess(AccessType::SHOW_COLUMNS, table_id);
|
||||||
auto table = DatabaseCatalog::instance().getTable(table_id, getContext());
|
auto table = DatabaseCatalog::instance().getTable(table_id, getContext());
|
||||||
|
|
||||||
|
if (auto * storage_view = table->as<StorageView>())
|
||||||
|
{
|
||||||
|
if (storage_view->isParameterizedView())
|
||||||
|
throw Exception(ErrorCodes::UNSUPPORTED_METHOD,
|
||||||
|
"Cannot infer table schema for the parametrized view when no query parameters are provided");
|
||||||
|
}
|
||||||
|
|
||||||
auto table_lock = table->lockForShare(getContext()->getInitialQueryId(), settings.lock_acquire_timeout);
|
auto table_lock = table->lockForShare(getContext()->getInitialQueryId(), settings.lock_acquire_timeout);
|
||||||
|
|
||||||
auto metadata_snapshot = table->getInMemoryMetadataPtr();
|
auto metadata_snapshot = table->getInMemoryMetadataPtr();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Interpreters/Context_fwd.h>
|
||||||
#include <Interpreters/IInterpreter.h>
|
#include <Interpreters/IInterpreter.h>
|
||||||
#include <Storages/ColumnsDescription.h>
|
#include <Storages/ColumnsDescription.h>
|
||||||
#include <Storages/StorageSnapshot.h>
|
#include <Storages/StorageSnapshot.h>
|
||||||
@ -24,6 +25,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void fillColumnsFromSubquery(const ASTTableExpression & table_expression);
|
void fillColumnsFromSubquery(const ASTTableExpression & table_expression);
|
||||||
|
void fillColumnsFromSubqueryImpl(const ASTPtr & select_query, const ContextPtr & current_context);
|
||||||
void fillColumnsFromTableFunction(const ASTTableExpression & table_expression);
|
void fillColumnsFromTableFunction(const ASTTableExpression & table_expression);
|
||||||
void fillColumnsFromTable(const ASTTableExpression & table_expression);
|
void fillColumnsFromTable(const ASTTableExpression & table_expression);
|
||||||
|
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
number UInt64
|
||||||
|
number UInt64
|
||||||
|
number UInt64
|
||||||
|
\'Biba\' String
|
||||||
|
CAST(dummy, \'Int\') Int32
|
||||||
|
CAST(dummy, \'String\') String
|
||||||
|
0
|
||||||
|
55
|
@ -0,0 +1,19 @@
|
|||||||
|
create view paramview as select * from system.numbers where number <= {top:UInt64};
|
||||||
|
|
||||||
|
describe paramview; -- { serverError UNSUPPORTED_METHOD }
|
||||||
|
describe paramview(top = 10);
|
||||||
|
describe paramview(top = 2 + 2);
|
||||||
|
|
||||||
|
create view p2 as select number, {name:String} from system.numbers where number <= {top:UInt64};
|
||||||
|
describe p2(top = 10); -- { serverError UNKNOWN_QUERY_PARAMETER }
|
||||||
|
describe p2(name = 'Biba', top = 2);
|
||||||
|
|
||||||
|
create view p3 as select CAST(dummy, {t:String});
|
||||||
|
describe p3(t = 'Int');
|
||||||
|
describe p3(t = 'String');
|
||||||
|
|
||||||
|
describe (SELECT * FROM p3(t = 'Int64') union all SELECT * FROM p3(t = 'UInt64')); -- { serverError NO_COMMON_TYPE }
|
||||||
|
|
||||||
|
SELECT * FROM p3(t = 'String');
|
||||||
|
|
||||||
|
select arrayReduce('sum', (select groupArray(number) from paramview(top=10)));
|
Loading…
Reference in New Issue
Block a user