99 *
1010 *
1111 * IDENTIFICATION
12- * $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.20 2008/08/25 22:42:33 tgl Exp $
12+ * $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.21 2008/11/12 23:08:37 tgl Exp $
1313 *
1414 *-------------------------------------------------------------------------
1515 */
1919#include "catalog/pg_proc.h"
2020#include "catalog/pg_type.h"
2121#include "executor/executor.h"
22+ #include "miscadmin.h"
2223#include "nodes/nodeFuncs.h"
2324#include "optimizer/clauses.h"
2425#include "optimizer/predtest.h"
2728#include "utils/syscache.h"
2829
2930
31+ /*
32+ * Proof attempts involving many AND or OR branches are likely to require
33+ * O(N^2) time, and more often than not fail anyway. So we set an arbitrary
34+ * limit on the number of branches that we will allow at any one level of
35+ * clause. (Note that this is only effective because the trees have been
36+ * AND/OR flattened!) XXX is it worth exposing this as a GUC knob?
37+ */
38+ #define MAX_BRANCHES_TO_TEST 100
39+
3040/*
3141 * To avoid redundant coding in predicate_implied_by_recurse and
3242 * predicate_refuted_by_recurse, we need to abstract out the notion of
@@ -686,6 +696,13 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate)
686696 *
687697 * If the expression is classified as AND- or OR-type, then *info is filled
688698 * in with the functions needed to iterate over its components.
699+ *
700+ * This function also implements enforcement of MAX_BRANCHES_TO_TEST: if an
701+ * AND/OR expression has too many branches, we just classify it as an atom.
702+ * (This will result in its being passed as-is to the simple_clause functions,
703+ * which will fail to prove anything about it.) Note that we cannot just stop
704+ * after considering MAX_BRANCHES_TO_TEST branches; in general that would
705+ * result in wrong proofs rather than failing to prove anything.
689706 */
690707static PredClass
691708predicate_classify (Node * clause ,PredIterInfo info )
@@ -698,7 +715,8 @@ predicate_classify(Node *clause, PredIterInfo info)
698715 * If we see a List, assume it's an implicit-AND list; this is the correct
699716 * semantics for lists of RestrictInfo nodes.
700717 */
701- if (IsA (clause ,List ))
718+ if (IsA (clause ,List )&&
719+ list_length ((List * )clause ) <=MAX_BRANCHES_TO_TEST )
702720{
703721info -> startup_fn = list_startup_fn ;
704722info -> next_fn = list_next_fn ;
@@ -707,14 +725,16 @@ predicate_classify(Node *clause, PredIterInfo info)
707725}
708726
709727/* Handle normal AND and OR boolean clauses */
710- if (and_clause (clause ))
728+ if (and_clause (clause )&&
729+ list_length (((BoolExpr * )clause )-> args ) <=MAX_BRANCHES_TO_TEST )
711730{
712731info -> startup_fn = boolexpr_startup_fn ;
713732info -> next_fn = list_next_fn ;
714733info -> cleanup_fn = list_cleanup_fn ;
715734return CLASS_AND ;
716735}
717- if (or_clause (clause ))
736+ if (or_clause (clause )&&
737+ list_length (((BoolExpr * )clause )-> args ) <=MAX_BRANCHES_TO_TEST )
718738{
719739info -> startup_fn = boolexpr_startup_fn ;
720740info -> next_fn = list_next_fn ;
@@ -737,13 +757,22 @@ predicate_classify(Node *clause, PredIterInfo info)
737757if (arraynode && IsA (arraynode ,Const )&&
738758!((Const * )arraynode )-> constisnull )
739759{
740- info -> startup_fn = arrayconst_startup_fn ;
741- info -> next_fn = arrayconst_next_fn ;
742- info -> cleanup_fn = arrayconst_cleanup_fn ;
743- return saop -> useOr ?CLASS_OR :CLASS_AND ;
760+ ArrayType * arrayval ;
761+ int nelems ;
762+
763+ arrayval = DatumGetArrayTypeP (((Const * )arraynode )-> constvalue );
764+ nelems = ArrayGetNItems (ARR_NDIM (arrayval ),ARR_DIMS (arrayval ));
765+ if (nelems <=MAX_BRANCHES_TO_TEST )
766+ {
767+ info -> startup_fn = arrayconst_startup_fn ;
768+ info -> next_fn = arrayconst_next_fn ;
769+ info -> cleanup_fn = arrayconst_cleanup_fn ;
770+ return saop -> useOr ?CLASS_OR :CLASS_AND ;
771+ }
744772}
745- if (arraynode && IsA (arraynode ,ArrayExpr )&&
746- !((ArrayExpr * )arraynode )-> multidims )
773+ else if (arraynode && IsA (arraynode ,ArrayExpr )&&
774+ !((ArrayExpr * )arraynode )-> multidims &&
775+ list_length (((ArrayExpr * )arraynode )-> elements ) <=MAX_BRANCHES_TO_TEST )
747776{
748777info -> startup_fn = arrayexpr_startup_fn ;
749778info -> next_fn = arrayexpr_next_fn ;
@@ -964,6 +993,9 @@ arrayexpr_cleanup_fn(PredIterInfo info)
964993static bool
965994predicate_implied_by_simple_clause (Expr * predicate ,Node * clause )
966995{
996+ /* Allow interrupting long proof attempts */
997+ CHECK_FOR_INTERRUPTS ();
998+
967999/* First try the equal() test */
9681000if (equal ((Node * )predicate ,clause ))
9691001return true;
@@ -1019,6 +1051,9 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause)
10191051static bool
10201052predicate_refuted_by_simple_clause (Expr * predicate ,Node * clause )
10211053{
1054+ /* Allow interrupting long proof attempts */
1055+ CHECK_FOR_INTERRUPTS ();
1056+
10221057/* A simple clause can't refute itself */
10231058/* Worth checking because of relation_excluded_by_constraints() */
10241059if ((Node * )predicate == clause )