mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Merge pull request #10603 from ClickHouse/fix-mv-scalars
Fix mv scalars
This commit is contained in:
commit
afd0938b99
@ -88,32 +88,54 @@ void ExecuteScalarSubqueriesMatcher::visit(const ASTSubquery & subquery, ASTPtr
|
||||
subquery_context.setSettings(subquery_settings);
|
||||
|
||||
ASTPtr subquery_select = subquery.children.at(0);
|
||||
BlockIO res = InterpreterSelectWithUnionQuery(
|
||||
subquery_select, subquery_context, SelectQueryOptions(QueryProcessingStage::Complete, data.subquery_depth + 1)).execute();
|
||||
|
||||
auto options = SelectQueryOptions(QueryProcessingStage::Complete, data.subquery_depth + 1);
|
||||
options.analyze(data.only_analyze);
|
||||
|
||||
auto interpreter = InterpreterSelectWithUnionQuery(subquery_select, subquery_context, options);
|
||||
Block block;
|
||||
try
|
||||
{
|
||||
block = res.in->read();
|
||||
|
||||
if (!block)
|
||||
if (data.only_analyze)
|
||||
{
|
||||
/// If query is only analyzed, then constants are not correct.
|
||||
block = interpreter.getSampleBlock();
|
||||
for (auto & column : block)
|
||||
{
|
||||
/// Interpret subquery with empty result as Null literal
|
||||
auto ast_new = std::make_unique<ASTLiteral>(Null());
|
||||
ast_new->setAlias(ast->tryGetAlias());
|
||||
ast = std::move(ast_new);
|
||||
return;
|
||||
if (column.column->empty())
|
||||
{
|
||||
auto mut_col = column.column->cloneEmpty();
|
||||
mut_col->insertDefault();
|
||||
column.column = std::move(mut_col);
|
||||
}
|
||||
}
|
||||
|
||||
if (block.rows() != 1 || res.in->read())
|
||||
throw Exception("Scalar subquery returned more than one row", ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY);
|
||||
}
|
||||
catch (const Exception & e)
|
||||
else
|
||||
{
|
||||
if (e.code() == ErrorCodes::TOO_MANY_ROWS)
|
||||
throw Exception("Scalar subquery returned more than one row", ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY);
|
||||
else
|
||||
throw;
|
||||
BlockIO res = interpreter.execute();
|
||||
|
||||
try
|
||||
{
|
||||
block = res.in->read();
|
||||
|
||||
if (!block)
|
||||
{
|
||||
/// Interpret subquery with empty result as Null literal
|
||||
auto ast_new = std::make_unique<ASTLiteral>(Null());
|
||||
ast_new->setAlias(ast->tryGetAlias());
|
||||
ast = std::move(ast_new);
|
||||
return;
|
||||
}
|
||||
|
||||
if (block.rows() != 1 || res.in->read())
|
||||
throw Exception("Scalar subquery returned more than one row", ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY);
|
||||
}
|
||||
catch (const Exception & e)
|
||||
{
|
||||
if (e.code() == ErrorCodes::TOO_MANY_ROWS)
|
||||
throw Exception("Scalar subquery returned more than one row", ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY);
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
block = materializeBlock(block);
|
||||
@ -134,7 +156,7 @@ void ExecuteScalarSubqueriesMatcher::visit(const ASTSubquery & subquery, ASTPtr
|
||||
const Settings & settings = data.context.getSettingsRef();
|
||||
|
||||
// Always convert to literals when there is no query context.
|
||||
if (!settings.enable_scalar_subquery_optimization || worthConvertingToLiteral(scalar) || !data.context.hasQueryContext())
|
||||
if (data.only_analyze || !settings.enable_scalar_subquery_optimization || worthConvertingToLiteral(scalar) || !data.context.hasQueryContext())
|
||||
{
|
||||
auto lit = std::make_unique<ASTLiteral>((*scalar.safeGetByPosition(0).column)[0]);
|
||||
lit->alias = subquery.alias;
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
const Context & context;
|
||||
size_t subquery_depth;
|
||||
Scalars & scalars;
|
||||
bool only_analyze;
|
||||
};
|
||||
|
||||
static bool needChildVisit(ASTPtr & node, const ASTPtr &);
|
||||
|
@ -314,7 +314,7 @@ InterpreterSelectQuery::InterpreterSelectQuery(
|
||||
options, joined_tables.tablesWithColumns(), required_result_column_names, table_join);
|
||||
|
||||
/// Save scalar sub queries's results in the query context
|
||||
if (context->hasQueryContext())
|
||||
if (!options.only_analyze && context->hasQueryContext())
|
||||
for (const auto & it : syntax_analyzer_result->getScalars())
|
||||
context->getQueryContext().addScalar(it.first, it.second);
|
||||
|
||||
|
@ -209,10 +209,10 @@ void removeUnneededColumnsFromSelectClause(const ASTSelectQuery * select_query,
|
||||
}
|
||||
|
||||
/// Replacing scalar subqueries with constant values.
|
||||
void executeScalarSubqueries(ASTPtr & query, const Context & context, size_t subquery_depth, Scalars & scalars)
|
||||
void executeScalarSubqueries(ASTPtr & query, const Context & context, size_t subquery_depth, Scalars & scalars, bool only_analyze)
|
||||
{
|
||||
LogAST log;
|
||||
ExecuteScalarSubqueriesVisitor::Data visitor_data{context, subquery_depth, scalars};
|
||||
ExecuteScalarSubqueriesVisitor::Data visitor_data{context, subquery_depth, scalars, only_analyze};
|
||||
ExecuteScalarSubqueriesVisitor(visitor_data, log.stream()).visit(query);
|
||||
}
|
||||
|
||||
@ -801,7 +801,7 @@ SyntaxAnalyzerResultPtr SyntaxAnalyzer::analyzeSelect(
|
||||
removeUnneededColumnsFromSelectClause(select_query, required_result_columns, remove_duplicates);
|
||||
|
||||
/// Executing scalar subqueries - replacing them with constant values.
|
||||
executeScalarSubqueries(query, context, subquery_depth, result.scalars);
|
||||
executeScalarSubqueries(query, context, subquery_depth, result.scalars, select_options.only_analyze);
|
||||
|
||||
{
|
||||
optimizeIf(query, result.aliases, settings.optimize_if_chain_to_miltiif);
|
||||
@ -846,7 +846,7 @@ SyntaxAnalyzerResultPtr SyntaxAnalyzer::analyze(ASTPtr & query, const NamesAndTy
|
||||
normalize(query, result.aliases, settings);
|
||||
|
||||
/// Executing scalar subqueries. Column defaults could be a scalar subquery.
|
||||
executeScalarSubqueries(query, context, 0, result.scalars);
|
||||
executeScalarSubqueries(query, context, 0, result.scalars, false);
|
||||
|
||||
optimizeIf(query, result.aliases, settings.optimize_if_chain_to_miltiif);
|
||||
|
||||
|
21
tests/queries/0_stateless/01268_mv_scalars.reference
Normal file
21
tests/queries/0_stateless/01268_mv_scalars.reference
Normal file
@ -0,0 +1,21 @@
|
||||
0 2
|
||||
0 2
|
||||
0 2
|
||||
1 2
|
||||
1 2
|
||||
1 2
|
||||
the rows get inserted
|
||||
2020-01-01 0 0
|
||||
2020-01-01 0 2
|
||||
2020-01-01 0 4
|
||||
no new rows
|
||||
2020-01-01 0 0
|
||||
2020-01-01 0 2
|
||||
2020-01-01 0 4
|
||||
the rows get inserted
|
||||
2020-01-01 0 0
|
||||
2020-01-01 0 2
|
||||
2020-01-01 0 4
|
||||
2020-01-06 5 0
|
||||
2020-01-06 5 2
|
||||
2020-01-06 5 4
|
33
tests/queries/0_stateless/01268_mv_scalars.sql
Normal file
33
tests/queries/0_stateless/01268_mv_scalars.sql
Normal file
@ -0,0 +1,33 @@
|
||||
DROP TABLE IF EXISTS src_table;
|
||||
|
||||
create table src_table Engine=Memory as system.numbers;
|
||||
CREATE MATERIALIZED VIEW dst_mv Engine=Memory as select *, (SELECT count() FROM src_table) AS cnt FROM src_table;
|
||||
insert into src_table select * from numbers(2);
|
||||
insert into src_table select * from numbers(2);
|
||||
insert into src_table select * from numbers(2);
|
||||
select * from dst_mv order by number;
|
||||
|
||||
CREATE TABLE dest_table (`Date` Date, `Id` UInt64, `Units` Float32) ENGINE = Memory;
|
||||
create table left_table as dest_table;
|
||||
create table right_table as dest_table;
|
||||
insert into right_table select toDate('2020-01-01') + number, number, number / 2 from numbers(10);
|
||||
|
||||
CREATE MATERIALIZED VIEW dest_table_mv TO dest_table as select * FROM (SELECT * FROM left_table) AS t1 INNER JOIN (WITH (SELECT DISTINCT Date FROM left_table LIMIT 1) AS dt SELECT * FROM right_table WHERE Date = dt) AS t2 USING (Date, Id);
|
||||
|
||||
insert into left_table select toDate('2020-01-01'), 0, number * 2 from numbers(3);
|
||||
select 'the rows get inserted';
|
||||
select * from dest_table;
|
||||
|
||||
insert into left_table select toDate('2020-01-01'), 5, number * 2 from numbers(3);
|
||||
select 'no new rows';
|
||||
select * from dest_table;
|
||||
|
||||
truncate table left_table;
|
||||
insert into left_table select toDate('2020-01-01') + 5, 5, number * 2 from numbers(3);
|
||||
select 'the rows get inserted';
|
||||
select * from dest_table;
|
||||
|
||||
drop table dest_table_mv;
|
||||
drop table left_table;
|
||||
drop table right_table;
|
||||
drop table dest_table;
|
Loading…
Reference in New Issue
Block a user