diff --git a/src/backend/distributed/planner/multi_logical_optimizer.c b/src/backend/distributed/planner/multi_logical_optimizer.c index 77914f4ec..a7af90c9e 100644 --- a/src/backend/distributed/planner/multi_logical_optimizer.c +++ b/src/backend/distributed/planner/multi_logical_optimizer.c @@ -814,7 +814,12 @@ SelectClauseTableIdList(List *selectClauseList) Var *selectColumn = NULL; int selectColumnTableId = 0; - Assert(list_length(selectColumnList) > 0); + if (list_length(selectColumnList) == 0) + { + /* filter is a constant, e.g. false or 1=0 */ + continue; + } + selectColumn = (Var *) linitial(selectColumnList); selectColumnTableId = (int) selectColumn->varno; @@ -944,16 +949,24 @@ TableIdListSelectClauses(List *tableIdList, List *selectClauseList) foreach(selectClauseCell, selectClauseList) { Node *selectClause = (Node *) lfirst(selectClauseCell); + List *selectColumnList = pull_var_clause_default(selectClause); - - Var *selectColumn = (Var *) linitial(selectColumnList); - int selectClauseTableId = (int) selectColumn->varno; - - bool tableIdListMember = list_member_int(tableIdList, selectClauseTableId); - if (tableIdListMember) + if (list_length(selectColumnList) == 0) { + /* filter is a constant, e.g. false or 1=0, always include it */ tableSelectClauseList = lappend(tableSelectClauseList, selectClause); } + else + { + Var *selectColumn = (Var *) linitial(selectColumnList); + int selectClauseTableId = (int) selectColumn->varno; + + bool tableIdListMember = list_member_int(tableIdList, selectClauseTableId); + if (tableIdListMember) + { + tableSelectClauseList = lappend(tableSelectClauseList, selectClause); + } + } } return tableSelectClauseList; diff --git a/src/backend/distributed/planner/multi_physical_planner.c b/src/backend/distributed/planner/multi_physical_planner.c index a3d88acf8..8481386ec 100644 --- a/src/backend/distributed/planner/multi_physical_planner.c +++ b/src/backend/distributed/planner/multi_physical_planner.c @@ -2515,6 +2515,12 @@ PruneShardList(Oid relationId, Index tableId, List *whereClauseList, Var *partitionColumn = PartitionColumn(relationId, tableId); char partitionMethod = PartitionMethod(relationId); + if (ContainsFalseClause(whereClauseList)) + { + /* always return empty result if WHERE clause is of the form: false (AND ..) */ + return NIL; + } + /* build the filter clause list for the partition method */ if (partitionMethod == DISTRIBUTE_BY_HASH) { @@ -2569,6 +2575,35 @@ PruneShardList(Oid relationId, Index tableId, List *whereClauseList, } +/* + * ContainsFalseClause returns whether the flattened where clause list + * contains false as a clause. + */ +bool +ContainsFalseClause(List *whereClauseList) +{ + bool containsFalseClause = false; + ListCell *clauseCell = NULL; + + foreach(clauseCell, whereClauseList) + { + Node *clause = (Node *) lfirst(clauseCell); + + if (IsA(clause, Const)) + { + Const *constant = (Const *) clause; + if (constant->consttype == BOOLOID && !DatumGetBool(constant->constvalue)) + { + containsFalseClause = true; + break; + } + } + } + + return containsFalseClause; +} + + /* * BuildBaseConstraint builds and returns a base constraint. This constraint * implements an expression in the form of (column <= max && column >= min), diff --git a/src/include/distributed/multi_physical_planner.h b/src/include/distributed/multi_physical_planner.h index a23083590..b0204f83d 100644 --- a/src/include/distributed/multi_physical_planner.h +++ b/src/include/distributed/multi_physical_planner.h @@ -231,6 +231,7 @@ extern StringInfo ShardFetchQueryString(uint64 shardId); /* Function declarations for shard pruning */ extern List * PruneShardList(Oid relationId, Index tableId, List *whereClauseList, List *shardList); +extern bool ContainsFalseClause(List *whereClauseList); extern OpExpr * MakeOpExpression(Var *variable, int16 strategyNumber); /* diff --git a/src/test/regress/expected/multi_complex_expressions.out b/src/test/regress/expected/multi_complex_expressions.out index 2a46f4ea7..092e7f0cb 100644 --- a/src/test/regress/expected/multi_complex_expressions.out +++ b/src/test/regress/expected/multi_complex_expressions.out @@ -224,7 +224,7 @@ SELECT count(*) FROM lineitem WHERE 0 != 0; count ------- - 0 + (1 row) -- distinct expressions can be pushed down diff --git a/src/test/regress/expected/multi_join_pruning.out b/src/test/regress/expected/multi_join_pruning.out index d1ca33a89..9e2fd914e 100644 --- a/src/test/regress/expected/multi_join_pruning.out +++ b/src/test/regress/expected/multi_join_pruning.out @@ -75,6 +75,22 @@ DEBUG: join prunable for intervals [13473,14947] and [1,5986] | (1 row) +-- Make sure that we can handle filters without a column +SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders + WHERE l_orderkey = o_orderkey AND false; + sum | avg +-----+----- + | +(1 row) + +SELECT sum(l_linenumber), avg(l_linenumber) + FROM lineitem INNER JOIN orders ON (l_orderkey = o_orderkey) + WHERE false; + sum | avg +-----+----- + | +(1 row) + -- These tests check that we can do join pruning for tables partitioned over -- different type of columns including varchar, array types, composite types -- etc. This is in response to a bug we had where we were not able to resolve @@ -110,4 +126,3 @@ DEBUG: join prunable for intervals [BA1000U2AMO4ZGX,BZZXSP27F21T6] and [AA1000U explain statements for distributed queries are not enabled (1 row) -SET client_min_messages TO NOTICE; diff --git a/src/test/regress/expected/multi_large_table_pruning.out b/src/test/regress/expected/multi_large_table_pruning.out index 492261a6b..27fc84854 100644 --- a/src/test/regress/expected/multi_large_table_pruning.out +++ b/src/test/regress/expected/multi_large_table_pruning.out @@ -130,5 +130,42 @@ DEBUG: predicate pruning for shardId 290007 (1 row) --- Reset client logging level to its previous value -SET client_min_messages TO NOTICE; +-- Test cases with false in the WHERE clause +SELECT + o_orderkey +FROM + orders INNER JOIN customer ON (o_custkey = c_custkey) +WHERE + false; + o_orderkey +------------ +(0 rows) + +SELECT + o_orderkey +FROM + orders INNER JOIN customer ON (o_custkey = c_custkey) +WHERE + 1=0 AND c_custkey < 0; + o_orderkey +------------ +(0 rows) + +SELECT + o_orderkey +FROM + orders INNER JOIN customer ON (o_custkey = c_custkey AND false); + o_orderkey +------------ +(0 rows) + +SELECT + o_orderkey +FROM + orders, customer +WHERE + o_custkey = c_custkey AND false; + o_orderkey +------------ +(0 rows) + diff --git a/src/test/regress/sql/multi_join_pruning.sql b/src/test/regress/sql/multi_join_pruning.sql index 17c9bc6e1..5d2edfbb8 100644 --- a/src/test/regress/sql/multi_join_pruning.sql +++ b/src/test/regress/sql/multi_join_pruning.sql @@ -36,6 +36,14 @@ SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders WHERE l_orderkey = o_orderkey AND l_orderkey > 6000 AND o_orderkey < 6000; +-- Make sure that we can handle filters without a column +SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders + WHERE l_orderkey = o_orderkey AND false; + +SELECT sum(l_linenumber), avg(l_linenumber) + FROM lineitem INNER JOIN orders ON (l_orderkey = o_orderkey) + WHERE false; + -- These tests check that we can do join pruning for tables partitioned over -- different type of columns including varchar, array types, composite types -- etc. This is in response to a bug we had where we were not able to resolve @@ -54,5 +62,3 @@ EXPLAIN SELECT count(*) EXPLAIN SELECT count(*) FROM varchar_partitioned_table table1, varchar_partitioned_table table2 WHERE table1.varchar_column = table2.varchar_column; - -SET client_min_messages TO NOTICE; diff --git a/src/test/regress/sql/multi_large_table_pruning.sql b/src/test/regress/sql/multi_large_table_pruning.sql index 5a1f80c8c..fd947f689 100644 --- a/src/test/regress/sql/multi_large_table_pruning.sql +++ b/src/test/regress/sql/multi_large_table_pruning.sql @@ -67,6 +67,29 @@ WHERE l_partkey = c_nationkey AND l_orderkey < 0; --- Reset client logging level to its previous value +-- Test cases with false in the WHERE clause +SELECT + o_orderkey +FROM + orders INNER JOIN customer ON (o_custkey = c_custkey) +WHERE + false; -SET client_min_messages TO NOTICE; +SELECT + o_orderkey +FROM + orders INNER JOIN customer ON (o_custkey = c_custkey) +WHERE + 1=0 AND c_custkey < 0; + +SELECT + o_orderkey +FROM + orders INNER JOIN customer ON (o_custkey = c_custkey AND false); + +SELECT + o_orderkey +FROM + orders, customer +WHERE + o_custkey = c_custkey AND false;