commit c2ab637f8a1094bd9a9dde5b1957a231e388534a Author: jcoleman Date: Wed Nov 14 16:49:52 2018 +0000 Prove IS NOT NULL inference for large arrays For the purposes of predicate proof testing we limit ScalarArrayOpExpr decomposition to arrays with <= MAX_SAOP_ARRAY_SIZE items (currently 100 items). However all scalar array ops IS NOT NULL can be inferred trivially without decomposing into AND/OR chains. We teach predtest to check for strict operators in ScalarArrayOpExpr nodes instead of relying on checking strictness of operators in AND/OR chains. This allows the planner to use partial indexes of the form "WHERE foo IS NOT NULL" when the query's WHERE clause involves a scalar array op like "foo IN (1,2,...101)". diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index 3d5ef6922c..18be276d74 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -1340,6 +1340,19 @@ clause_is_strict_for(Node *clause, Node *subexpr) } return false; } + /* + * Since we limit decomposing ScalarArrayOpExpr nodes into AND/OR quals + * to arrays with at most MAX_SAOP_ARRAY_SIZE items, we need to handle + * scalar array ops separately (this case will occur when the array has + * more than MAX_SAOP_ARRAY_SIZE items). + */ + if (IsA(clause, ScalarArrayOpExpr)) + { + ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; + if (op_strict(saop->opno) && + clause_is_strict_for((Node *) linitial(saop->args), subexpr)) + return true; + } if (is_funcclause(clause) && func_strict(((FuncExpr *) clause)->funcid)) { diff --git a/src/test/modules/test_predtest/expected/test_predtest.out b/src/test/modules/test_predtest/expected/test_predtest.out index 5574e03204..a0010f05cc 100644 --- a/src/test/modules/test_predtest/expected/test_predtest.out +++ b/src/test/modules/test_predtest/expected/test_predtest.out @@ -837,3 +837,45 @@ w_i_holds | f s_r_holds | f w_r_holds | f +-- For the next few tests, We want to test an array longer than +-- MAX_SAOP_ARRAY_SIZE so that we're not relying on predtest turning +-- the array op into set of OR quals. We also need to include at least +-- one null value to demonstrate strict operators are checked properly. +select * from test_predtest($$ +select x is not null, x = any(array[ + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28, + 29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53, + 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78, + 79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,null +]) +from integers +$$); +-[ RECORD 1 ]-----+-- +strong_implied_by | t +weak_implied_by | f +strong_refuted_by | f +weak_refuted_by | f +s_i_holds | t +w_i_holds | f +s_r_holds | f +w_r_holds | f + +select * from test_predtest($$ +select y is not null, x = any(array[ + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28, + 29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53, + 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78, + 79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,null +]) +from integers +$$); +-[ RECORD 1 ]-----+-- +strong_implied_by | f +weak_implied_by | f +strong_refuted_by | f +weak_refuted_by | f +s_i_holds | f +w_i_holds | f +s_r_holds | f +w_r_holds | f + diff --git a/src/test/modules/test_predtest/sql/test_predtest.sql b/src/test/modules/test_predtest/sql/test_predtest.sql index 2734735843..13ef296b34 100644 --- a/src/test/modules/test_predtest/sql/test_predtest.sql +++ b/src/test/modules/test_predtest/sql/test_predtest.sql @@ -325,3 +325,27 @@ select * from test_predtest($$ select x <= y, x = any(array[1,3,y]) from integers $$); + +-- For the next few tests, We want to test an array longer than +-- MAX_SAOP_ARRAY_SIZE so that we're not relying on predtest turning +-- the array op into set of OR quals. We also need to include at least +-- one null value to demonstrate strict operators are checked properly. +select * from test_predtest($$ +select x is not null, x = any(array[ + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28, + 29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53, + 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78, + 79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,null +]) +from integers +$$); + +select * from test_predtest($$ +select y is not null, x = any(array[ + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28, + 29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53, + 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78, + 79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,null +]) +from integers +$$);