mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 00:30:49 +00:00
Do not check parent scope for group_by_use_nulls outside of subquery.
This commit is contained in:
parent
60c0957abd
commit
861dcbbffb
@ -11,9 +11,10 @@ namespace ErrorCodes
|
|||||||
extern const int LOGICAL_ERROR;
|
extern const int LOGICAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentifierResolveScope::IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_)
|
IdentifierResolveScope::IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_, bool is_query_)
|
||||||
: scope_node(std::move(scope_node_))
|
: scope_node(std::move(scope_node_))
|
||||||
, parent_scope(parent_scope_)
|
, parent_scope(parent_scope_)
|
||||||
|
, is_query(is_query_)
|
||||||
{
|
{
|
||||||
if (parent_scope)
|
if (parent_scope)
|
||||||
{
|
{
|
||||||
|
@ -128,7 +128,7 @@ constexpr auto PROJECTION_NAME_PLACEHOLDER = "__projection_name_placeholder";
|
|||||||
struct IdentifierResolveScope
|
struct IdentifierResolveScope
|
||||||
{
|
{
|
||||||
/// Construct identifier resolve scope using scope node, and parent scope
|
/// Construct identifier resolve scope using scope node, and parent scope
|
||||||
IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_);
|
IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_, bool is_query_);
|
||||||
|
|
||||||
QueryTreeNodePtr scope_node;
|
QueryTreeNodePtr scope_node;
|
||||||
|
|
||||||
@ -188,6 +188,8 @@ struct IdentifierResolveScope
|
|||||||
/// Join retutns NULLs instead of default values
|
/// Join retutns NULLs instead of default values
|
||||||
bool join_use_nulls = false;
|
bool join_use_nulls = false;
|
||||||
|
|
||||||
|
bool is_query;
|
||||||
|
|
||||||
/// JOINs count
|
/// JOINs count
|
||||||
size_t joins_count = 0;
|
size_t joins_count = 0;
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ QueryAnalyzer::~QueryAnalyzer() = default;
|
|||||||
|
|
||||||
void QueryAnalyzer::resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context)
|
void QueryAnalyzer::resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context)
|
||||||
{
|
{
|
||||||
IdentifierResolveScope scope(node, nullptr /*parent_scope*/);
|
IdentifierResolveScope scope(node, nullptr /*parent_scope*/, true /*is_query*/);
|
||||||
|
|
||||||
if (!scope.context)
|
if (!scope.context)
|
||||||
scope.context = context;
|
scope.context = context;
|
||||||
@ -509,7 +509,7 @@ void QueryAnalyzer::evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & node, Iden
|
|||||||
/// exception with this settings enabled(https://github.com/ClickHouse/ClickHouse/issues/52494).
|
/// exception with this settings enabled(https://github.com/ClickHouse/ClickHouse/issues/52494).
|
||||||
subquery_context->setSetting("use_structure_from_insertion_table_in_table_functions", false);
|
subquery_context->setSetting("use_structure_from_insertion_table_in_table_functions", false);
|
||||||
|
|
||||||
auto options = SelectQueryOptions(QueryProcessingStage::Complete, scope.subquery_depth, true /*is_subquery*/);
|
auto options = SelectQueryOptions(QueryProcessingStage::Complete, scope.subquery_depth, true /*is_query*/);
|
||||||
options.only_analyze = only_analyze;
|
options.only_analyze = only_analyze;
|
||||||
auto interpreter = std::make_unique<InterpreterSelectQueryAnalyzer>(node->toAST(), subquery_context, subquery_context->getViewSource(), options);
|
auto interpreter = std::make_unique<InterpreterSelectQueryAnalyzer>(node->toAST(), subquery_context, subquery_context->getViewSource(), options);
|
||||||
|
|
||||||
@ -2163,7 +2163,7 @@ ProjectionNames QueryAnalyzer::resolveMatcher(QueryTreeNodePtr & matcher_node, I
|
|||||||
if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::LAMBDA)
|
if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::LAMBDA)
|
||||||
{
|
{
|
||||||
auto lambda_expression_to_resolve = expression_node->clone();
|
auto lambda_expression_to_resolve = expression_node->clone();
|
||||||
IdentifierResolveScope lambda_scope(expression_node, &scope /*parent_scope*/);
|
IdentifierResolveScope lambda_scope(expression_node, &scope /*parent_scope*/, false /*is_query*/);
|
||||||
node_projection_names = resolveLambda(expression_node, lambda_expression_to_resolve, {node}, lambda_scope);
|
node_projection_names = resolveLambda(expression_node, lambda_expression_to_resolve, {node}, lambda_scope);
|
||||||
auto & lambda_expression_to_resolve_typed = lambda_expression_to_resolve->as<LambdaNode &>();
|
auto & lambda_expression_to_resolve_typed = lambda_expression_to_resolve->as<LambdaNode &>();
|
||||||
node = lambda_expression_to_resolve_typed.getExpression();
|
node = lambda_expression_to_resolve_typed.getExpression();
|
||||||
@ -3036,7 +3036,7 @@ ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, Identifi
|
|||||||
|
|
||||||
auto lambda_expression_clone = lambda_expression_untyped->clone();
|
auto lambda_expression_clone = lambda_expression_untyped->clone();
|
||||||
|
|
||||||
IdentifierResolveScope lambda_scope(lambda_expression_clone, &scope /*parent_scope*/);
|
IdentifierResolveScope lambda_scope(lambda_expression_clone, &scope /*parent_scope*/, false /*is_query*/);
|
||||||
ProjectionNames lambda_projection_names = resolveLambda(lambda_expression_untyped, lambda_expression_clone, function_arguments, lambda_scope);
|
ProjectionNames lambda_projection_names = resolveLambda(lambda_expression_untyped, lambda_expression_clone, function_arguments, lambda_scope);
|
||||||
|
|
||||||
auto & resolved_lambda = lambda_expression_clone->as<LambdaNode &>();
|
auto & resolved_lambda = lambda_expression_clone->as<LambdaNode &>();
|
||||||
@ -3291,7 +3291,7 @@ ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, Identifi
|
|||||||
lambda_arguments.push_back(std::make_shared<ColumnNode>(std::move(column_name_and_type), lambda_to_resolve));
|
lambda_arguments.push_back(std::make_shared<ColumnNode>(std::move(column_name_and_type), lambda_to_resolve));
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentifierResolveScope lambda_scope(lambda_to_resolve, &scope /*parent_scope*/);
|
IdentifierResolveScope lambda_scope(lambda_to_resolve, &scope /*parent_scope*/, false /*is_query*/);
|
||||||
lambda_projection_names = resolveLambda(lambda_argument, lambda_to_resolve, lambda_arguments, lambda_scope);
|
lambda_projection_names = resolveLambda(lambda_argument, lambda_to_resolve, lambda_arguments, lambda_scope);
|
||||||
|
|
||||||
if (auto * lambda_list_node_result = lambda_to_resolve_typed.getExpression()->as<ListNode>())
|
if (auto * lambda_list_node_result = lambda_to_resolve_typed.getExpression()->as<ListNode>())
|
||||||
@ -3512,7 +3512,7 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(
|
|||||||
auto node_type = node->getNodeType();
|
auto node_type = node->getNodeType();
|
||||||
if (!allow_table_expression && (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION))
|
if (!allow_table_expression && (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION))
|
||||||
{
|
{
|
||||||
IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/);
|
IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/, false /*is_query*/);
|
||||||
subquery_scope.subquery_depth = scope.subquery_depth + 1;
|
subquery_scope.subquery_depth = scope.subquery_depth + 1;
|
||||||
|
|
||||||
evaluateScalarSubqueryIfNeeded(node, subquery_scope);
|
evaluateScalarSubqueryIfNeeded(node, subquery_scope);
|
||||||
@ -3619,7 +3619,7 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(
|
|||||||
else
|
else
|
||||||
union_node->setIsCTE(false);
|
union_node->setIsCTE(false);
|
||||||
|
|
||||||
IdentifierResolveScope subquery_scope(resolved_identifier_node, &scope /*parent_scope*/);
|
IdentifierResolveScope subquery_scope(resolved_identifier_node, &scope /*parent_scope*/, true /*is_query*/);
|
||||||
subquery_scope.subquery_depth = scope.subquery_depth + 1;
|
subquery_scope.subquery_depth = scope.subquery_depth + 1;
|
||||||
|
|
||||||
/// CTE is being resolved, it's required to forbid to resolve to it again
|
/// CTE is being resolved, it's required to forbid to resolve to it again
|
||||||
@ -3752,7 +3752,7 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(
|
|||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case QueryTreeNodeType::UNION:
|
case QueryTreeNodeType::UNION:
|
||||||
{
|
{
|
||||||
IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/);
|
IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/, true /*is_query*/);
|
||||||
subquery_scope.subquery_depth = scope.subquery_depth + 1;
|
subquery_scope.subquery_depth = scope.subquery_depth + 1;
|
||||||
|
|
||||||
std::string projection_name = "_subquery_" + std::to_string(subquery_counter);
|
std::string projection_name = "_subquery_" + std::to_string(subquery_counter);
|
||||||
@ -3826,6 +3826,10 @@ ProjectionNames QueryAnalyzer::resolveExpressionNode(
|
|||||||
node->convertToNullable();
|
node->convertToNullable();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check parent scopes until find current query scope.
|
||||||
|
if (scope_ptr->is_query)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4112,7 +4116,7 @@ void QueryAnalyzer::resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpo
|
|||||||
bool is_column_constant = interpolate_node_typed.getExpression()->getNodeType() == QueryTreeNodeType::CONSTANT;
|
bool is_column_constant = interpolate_node_typed.getExpression()->getNodeType() == QueryTreeNodeType::CONSTANT;
|
||||||
|
|
||||||
auto & interpolation_to_resolve = interpolate_node_typed.getInterpolateExpression();
|
auto & interpolation_to_resolve = interpolate_node_typed.getInterpolateExpression();
|
||||||
IdentifierResolveScope interpolate_scope(interpolation_to_resolve, &scope /*parent_scope*/);
|
IdentifierResolveScope interpolate_scope(interpolation_to_resolve, &scope /*parent_scope*/, false /*is_query*/);
|
||||||
|
|
||||||
auto fake_column_node = std::make_shared<ColumnNode>(NameAndTypePair(column_to_interpolate_name, interpolate_node_typed.getExpression()->getResultType()), interpolate_node_typed.getExpression());
|
auto fake_column_node = std::make_shared<ColumnNode>(NameAndTypePair(column_to_interpolate_name, interpolate_node_typed.getExpression()->getResultType()), interpolate_node_typed.getExpression());
|
||||||
if (is_column_constant)
|
if (is_column_constant)
|
||||||
@ -4410,7 +4414,7 @@ void QueryAnalyzer::initializeTableExpressionData(const QueryTreeNodePtr & table
|
|||||||
*/
|
*/
|
||||||
alias_column_to_resolve = column_name_to_column_node[alias_column_to_resolve_name];
|
alias_column_to_resolve = column_name_to_column_node[alias_column_to_resolve_name];
|
||||||
|
|
||||||
IdentifierResolveScope alias_column_resolve_scope(alias_column_to_resolve, nullptr /*parent_scope*/);
|
IdentifierResolveScope alias_column_resolve_scope(alias_column_to_resolve, nullptr /*parent_scope*/, false /*is_query*/);
|
||||||
alias_column_resolve_scope.column_name_to_column_node = std::move(column_name_to_column_node);
|
alias_column_resolve_scope.column_name_to_column_node = std::move(column_name_to_column_node);
|
||||||
alias_column_resolve_scope.context = scope.context;
|
alias_column_resolve_scope.context = scope.context;
|
||||||
|
|
||||||
@ -5003,7 +5007,7 @@ void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveS
|
|||||||
left_subquery->getProjection().getNodes().push_back(projection_node->clone());
|
left_subquery->getProjection().getNodes().push_back(projection_node->clone());
|
||||||
left_subquery->getJoinTree() = left_table_expression;
|
left_subquery->getJoinTree() = left_table_expression;
|
||||||
|
|
||||||
IdentifierResolveScope left_subquery_scope(left_subquery, nullptr /*parent_scope*/);
|
IdentifierResolveScope left_subquery_scope(left_subquery, nullptr /*parent_scope*/, true /*is_query*/);
|
||||||
resolveQuery(left_subquery, left_subquery_scope);
|
resolveQuery(left_subquery, left_subquery_scope);
|
||||||
|
|
||||||
const auto & resolved_nodes = left_subquery->getProjection().getNodes();
|
const auto & resolved_nodes = left_subquery->getProjection().getNodes();
|
||||||
@ -5612,7 +5616,7 @@ void QueryAnalyzer::resolveUnion(const QueryTreeNodePtr & union_node, Identifier
|
|||||||
auto & non_recursive_query_mutable_context = non_recursive_query_is_query_node ? non_recursive_query->as<QueryNode &>().getMutableContext()
|
auto & non_recursive_query_mutable_context = non_recursive_query_is_query_node ? non_recursive_query->as<QueryNode &>().getMutableContext()
|
||||||
: non_recursive_query->as<UnionNode &>().getMutableContext();
|
: non_recursive_query->as<UnionNode &>().getMutableContext();
|
||||||
|
|
||||||
IdentifierResolveScope non_recursive_subquery_scope(non_recursive_query, &scope /*parent_scope*/);
|
IdentifierResolveScope non_recursive_subquery_scope(non_recursive_query, &scope /*parent_scope*/, true /*is_query*/);
|
||||||
non_recursive_subquery_scope.subquery_depth = scope.subquery_depth + 1;
|
non_recursive_subquery_scope.subquery_depth = scope.subquery_depth + 1;
|
||||||
|
|
||||||
if (non_recursive_query_is_query_node)
|
if (non_recursive_query_is_query_node)
|
||||||
@ -5643,7 +5647,7 @@ void QueryAnalyzer::resolveUnion(const QueryTreeNodePtr & union_node, Identifier
|
|||||||
{
|
{
|
||||||
auto & query_node = queries_nodes[i];
|
auto & query_node = queries_nodes[i];
|
||||||
|
|
||||||
IdentifierResolveScope subquery_scope(query_node, &scope /*parent_scope*/);
|
IdentifierResolveScope subquery_scope(query_node, &scope /*parent_scope*/, true /*is_subquery*/);
|
||||||
|
|
||||||
if (recursive_cte_table_node)
|
if (recursive_cte_table_node)
|
||||||
subquery_scope.expression_argument_name_to_node[union_node_typed.getCTEName()] = recursive_cte_table_node;
|
subquery_scope.expression_argument_name_to_node[union_node_typed.getCTEName()] = recursive_cte_table_node;
|
||||||
|
@ -264,3 +264,44 @@ SETTINGS group_by_use_nulls = 1, max_bytes_before_external_sort=10;
|
|||||||
9 \N 9
|
9 \N 9
|
||||||
\N 0 20
|
\N 0 20
|
||||||
\N 1 25
|
\N 1 25
|
||||||
|
CREATE TABLE test
|
||||||
|
ENGINE = ReplacingMergeTree
|
||||||
|
PRIMARY KEY id
|
||||||
|
AS SELECT number AS id FROM numbers(100);
|
||||||
|
SELECT id
|
||||||
|
FROM test
|
||||||
|
GROUP BY id
|
||||||
|
WITH CUBE
|
||||||
|
HAVING id IN (
|
||||||
|
SELECT id
|
||||||
|
FROM test
|
||||||
|
)
|
||||||
|
FORMAT `NUll`
|
||||||
|
SETTINGS allow_experimental_analyzer = 1, group_by_use_nulls = true;
|
||||||
|
SELECT id
|
||||||
|
FROM test
|
||||||
|
FINAL
|
||||||
|
GROUP BY id
|
||||||
|
WITH CUBE
|
||||||
|
HAVING id IN (
|
||||||
|
SELECT DISTINCT id
|
||||||
|
FROM test
|
||||||
|
FINAL
|
||||||
|
)
|
||||||
|
FORMAT `NUll`
|
||||||
|
SETTINGS allow_experimental_analyzer = 1, group_by_use_nulls = true;
|
||||||
|
SELECT id
|
||||||
|
FROM test
|
||||||
|
FINAL
|
||||||
|
GROUP BY
|
||||||
|
GROUPING SETS ((id))
|
||||||
|
ORDER BY
|
||||||
|
id IN (
|
||||||
|
SELECT DISTINCT id
|
||||||
|
FROM test
|
||||||
|
FINAL
|
||||||
|
LIMIT 4
|
||||||
|
) ASC
|
||||||
|
LIMIT 256 BY id
|
||||||
|
FORMAT `NUll`
|
||||||
|
SETTINGS allow_experimental_analyzer = 1, group_by_use_nulls=true;
|
||||||
|
@ -83,3 +83,48 @@ GROUP BY
|
|||||||
)
|
)
|
||||||
ORDER BY 1, tuple(val)
|
ORDER BY 1, tuple(val)
|
||||||
SETTINGS group_by_use_nulls = 1, max_bytes_before_external_sort=10;
|
SETTINGS group_by_use_nulls = 1, max_bytes_before_external_sort=10;
|
||||||
|
|
||||||
|
CREATE TABLE test
|
||||||
|
ENGINE = ReplacingMergeTree
|
||||||
|
PRIMARY KEY id
|
||||||
|
AS SELECT number AS id FROM numbers(100);
|
||||||
|
|
||||||
|
SELECT id
|
||||||
|
FROM test
|
||||||
|
GROUP BY id
|
||||||
|
WITH CUBE
|
||||||
|
HAVING id IN (
|
||||||
|
SELECT id
|
||||||
|
FROM test
|
||||||
|
)
|
||||||
|
FORMAT `NUll`
|
||||||
|
SETTINGS allow_experimental_analyzer = 1, group_by_use_nulls = true;
|
||||||
|
|
||||||
|
SELECT id
|
||||||
|
FROM test
|
||||||
|
FINAL
|
||||||
|
GROUP BY id
|
||||||
|
WITH CUBE
|
||||||
|
HAVING id IN (
|
||||||
|
SELECT DISTINCT id
|
||||||
|
FROM test
|
||||||
|
FINAL
|
||||||
|
)
|
||||||
|
FORMAT `NUll`
|
||||||
|
SETTINGS allow_experimental_analyzer = 1, group_by_use_nulls = true;
|
||||||
|
|
||||||
|
SELECT id
|
||||||
|
FROM test
|
||||||
|
FINAL
|
||||||
|
GROUP BY
|
||||||
|
GROUPING SETS ((id))
|
||||||
|
ORDER BY
|
||||||
|
id IN (
|
||||||
|
SELECT DISTINCT id
|
||||||
|
FROM test
|
||||||
|
FINAL
|
||||||
|
LIMIT 4
|
||||||
|
) ASC
|
||||||
|
LIMIT 256 BY id
|
||||||
|
FORMAT `NUll`
|
||||||
|
SETTINGS allow_experimental_analyzer = 1, group_by_use_nulls=true;
|
||||||
|
Loading…
Reference in New Issue
Block a user