1+ #include < algorithm>
12#include < memory>
23#include < Core/NamesAndTypes.h>
34#include < Core/TypeId.h>
@@ -81,14 +82,33 @@ bool extractFunctions(const ASTPtr & expression, const std::function<bool(const
8182 }
8283 else if (function->name == " or" )
8384 {
84- bool ret = true ;
85+ bool ret = false ;
8586 ASTs or_args;
8687 for (const auto & child : function->arguments ->children )
87- ret &= extractFunctions (child, is_constant, or_args);
88- // / We can keep condition only if it still OR condition (i.e. we
89- // / have dependent conditions for columns at both sides)
90- if (or_args.size () == 2 )
88+ ret |= extractFunctions (child, is_constant, or_args);
89+
90+ if (!or_args.empty ())
91+ {
92+ // / In case of there are less number of arguments for which
93+ // / is_constant() == true, we need to add always-true
94+ // / implicitly to avoid breaking AND invariant.
95+ // /
96+ // / Consider the following:
97+ // /
98+ // / ((value = 10) OR (_table = 'v2')) AND ((_table = 'v1') OR (value = 20))
99+ // /
100+ // / Without implicit always-true:
101+ // /
102+ // / (_table = 'v2') AND (_table = 'v1')
103+ // /
104+ // / With:
105+ // /
106+ // / (_table = 'v2' OR 1) AND (_table = 'v1' OR 1) -> (_table = 'v2') OR (_table = 'v1')
107+ // /
108+ if (or_args.size () != function->arguments ->children .size ())
109+ or_args.push_back (std::make_shared<ASTLiteral>(Field (1 )));
91110 result.push_back (makeASTForLogicalOr (std::move (or_args)));
111+ }
92112 return ret;
93113 }
94114 }
@@ -165,8 +185,10 @@ bool prepareFilterBlockWithQuery(const ASTPtr & query, ContextPtr context, Block
165185 if (!select.where () && !select.prewhere ())
166186 return unmodified;
167187
168- // Provide input columns as constant columns to check if an expression is constant.
169- std::function<bool (const ASTPtr &)> is_constant = [&block, &context](const ASTPtr & node)
188+ // Provide input columns as constant columns to check if an expression is
189+ // constant and depends on the columns from provided block (the last is
190+ // required to allow skipping some conditions for handling OR).
191+ std::function<bool (const ASTPtr &)> is_constant = [&block, &context](const ASTPtr & expr)
170192 {
171193 auto actions = std::make_shared<ActionsDAG>(block.getColumnsWithTypeAndName ());
172194 PreparedSetsPtr prepared_sets = std::make_shared<PreparedSets>();
@@ -178,13 +200,26 @@ bool prepareFilterBlockWithQuery(const ASTPtr & query, ContextPtr context, Block
178200 context, SizeLimits{}, 1 , source_columns, std::move (actions), prepared_sets, true , true , true ,
179201 { aggregation_keys, grouping_set_keys, GroupByKind::NONE });
180202
181- ActionsVisitor (visitor_data).visit (node );
203+ ActionsVisitor (visitor_data).visit (expr );
182204 actions = visitor_data.getActions ();
205+ auto expr_column_name = expr->getColumnName ();
206+
207+ const auto * expr_const_node = actions->tryFindInOutputs (expr_column_name);
208+ if (!expr_const_node)
209+ return false ;
210+ auto filter_actions = ActionsDAG::buildFilterActionsDAG ({expr_const_node}, {}, context);
211+ const auto & nodes = filter_actions->getNodes ();
212+ bool has_dependent_columns = std::any_of (nodes.begin (), nodes.end (), [&](const auto & node)
213+ {
214+ return block.has (node.result_name );
215+ });
216+ if (!has_dependent_columns)
217+ return false ;
218+
183219 auto expression_actions = std::make_shared<ExpressionActions>(actions);
184220 auto block_with_constants = block;
185221 expression_actions->execute (block_with_constants);
186- auto column_name = node->getColumnName ();
187- return block_with_constants.has (column_name) && isColumnConst (*block_with_constants.getByName (column_name).column );
222+ return block_with_constants.has (expr_column_name) && isColumnConst (*block_with_constants.getByName (expr_column_name).column );
188223 };
189224
190225 // / Create an expression that evaluates the expressions in WHERE and PREWHERE, depending only on the existing columns.
0 commit comments