9
9
*
10
10
*
11
11
* IDENTIFICATION
12
- * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.168 2005/03/01 00:24:52 tgl Exp $
12
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.169 2005/03/02 04:10:53 tgl Exp $
13
13
*
14
14
*-------------------------------------------------------------------------
15
15
*/
@@ -64,9 +64,7 @@ static bool match_join_clause_to_indexcol(RelOptInfo *rel, IndexOptInfo *index,
64
64
RestrictInfo * rinfo );
65
65
static Oid indexable_operator (Expr * clause , Oid opclass ,
66
66
bool indexkey_on_left );
67
- static bool pred_test_restrict_list (Expr * predicate , List * restrictinfo_list );
68
- static bool pred_test_recurse_restrict (Expr * predicate , Node * clause );
69
- static bool pred_test_recurse_pred (Expr * predicate , Node * clause );
67
+ static bool pred_test_recurse (Node * clause , Node * predicate );
70
68
static bool pred_test_simple_clause (Expr * predicate , Node * clause );
71
69
static Relids indexable_outerrelids (RelOptInfo * rel , IndexOptInfo * index );
72
70
static Path * make_innerjoin_index_path (Query * root ,
@@ -749,30 +747,17 @@ check_partial_indexes(Query *root, RelOptInfo *rel)
749
747
* Recursively checks whether the clauses in restrictinfo_list imply
750
748
* that the given predicate is true.
751
749
*
752
- * This routine (together with the routines it calls) iterates over
753
- * ANDs in the predicate first, then breaks down the restriction list
754
- * to its constituent AND/OR elements, and iterates over ORs
755
- * in the predicate last. This order is important to make the test
756
- * succeed whenever possible. --Nels, Jan '93
757
- *
758
- * For example, a restriction (a OR b) certainly implies a predicate
759
- * (a OR b OR c), but no one element of the predicate is individually
760
- * implied by the restriction. By expanding the predicate ORs last
761
- * we are able to prove that the whole predicate is implied by each arm
762
- * of the restriction. Conversely consider predicate (a AND b) with
763
- * restriction (a AND b AND c). This should be implied but we will
764
- * fail to prove it if we dissect the restriction first.
765
- *
766
750
* The top-level List structure of each list corresponds to an AND list.
767
- * We assume that canonicalize_qual() has been applied and so there
768
- * are no explicit ANDs immediately below the top-level List structure.
769
- * (If this is not true we might fail to prove an implication that is
770
- * valid, but no worse consequences will ensue.)
751
+ * We assume that canonicalize_qual() has been applied and so there are
752
+ * no un-flattened ANDs or ORs (e.g., no AND immediately within an AND,
753
+ * including AND just below the top-level List structure).
754
+ * If this is not true we might fail to prove an implication that is
755
+ * valid, but no worse consequences will ensue.
771
756
*/
772
757
bool
773
758
pred_test (List * predicate_list , List * restrictinfo_list )
774
759
{
775
- ListCell * pred ;
760
+ ListCell * item ;
776
761
777
762
/*
778
763
* Note: if Postgres tried to optimize queries by forming equivalence
@@ -793,133 +778,189 @@ pred_test(List *predicate_list, List *restrictinfo_list)
793
778
return false; /* no restriction clauses: the test must
794
779
* fail */
795
780
796
- /* Take care of the AND semantics of the top-level predicate list */
797
- foreach (pred , predicate_list )
781
+ /*
782
+ * In all cases where the predicate is an AND-clause, pred_test_recurse()
783
+ * will prefer to iterate over the predicate's components. So we can
784
+ * just do that to start with here, and eliminate the need for
785
+ * pred_test_recurse() to handle a bare List on the predicate side.
786
+ *
787
+ * Logic is: restriction must imply each of the AND'ed predicate items.
788
+ */
789
+ foreach (item , predicate_list )
798
790
{
799
- /*
800
- * if any clause is not implied, the whole predicate is not
801
- * implied.
802
- */
803
- if (!pred_test_restrict_list (lfirst (pred ), restrictinfo_list ))
791
+ if (!pred_test_recurse ((Node * ) restrictinfo_list , lfirst (item )))
804
792
return false;
805
793
}
806
794
return true;
807
795
}
808
796
809
797
810
- /*
811
- * pred_test_restrict_list
812
- * Does the "predicate inclusion test" for one AND clause of a predicate
813
- * expression. Here we take care of the AND semantics of the top-level
814
- * restrictinfo list.
815
- */
816
- static bool
817
- pred_test_restrict_list (Expr * predicate , List * restrictinfo_list )
818
- {
819
- ListCell * item ;
820
-
821
- foreach (item , restrictinfo_list )
822
- {
823
- /* if any clause implies the predicate, return true */
824
- if (pred_test_recurse_restrict (predicate ,
825
- (Node * ) lfirst (item )))
826
- return true;
827
- }
828
- return false;
829
- }
830
-
831
-
832
- /*
833
- * pred_test_recurse_restrict
834
- * Does the "predicate inclusion test" for one AND clause of a predicate
835
- * expression. Here we recursively deal with the possibility that the
836
- * restriction-list element is itself an AND or OR structure; also,
837
- * we strip off RestrictInfo nodes to find bare qualifier expressions.
798
+ /*----------
799
+ * pred_test_recurse
800
+ * Does the "predicate inclusion test" for non-NULL restriction and
801
+ * predicate clauses.
802
+ *
803
+ * The logic followed here is ("=>" means "implies"):
804
+ * atom A => atom B iff: pred_test_simple_clause says so
805
+ * atom A => AND-expr B iff: A => each of B's components
806
+ * atom A => OR-expr B iff: A => any of B's components
807
+ * AND-expr A => atom B iff: any of A's components => B
808
+ * AND-expr A => AND-expr B iff: A => each of B's components
809
+ * AND-expr A => OR-expr B iff: A => any of B's components,
810
+ * *or* any of A's components => B
811
+ * OR-expr A => atom B iff: each of A's components => B
812
+ * OR-expr A => AND-expr B iff: A => each of B's components
813
+ * OR-expr A => OR-expr B iff: each of A's components => any of B's
814
+ *
815
+ * An "atom" is anything other than an AND or OR node. Notice that we don't
816
+ * have any special logic to handle NOT nodes; these should have been pushed
817
+ * down or eliminated where feasible by prepqual.c.
818
+ *
819
+ * We can't recursively expand either side first, but have to interleave
820
+ * the expansions per the above rules, to be sure we handle all of these
821
+ * examples:
822
+ * (x OR y) => (x OR y OR z)
823
+ * (x AND y AND z) => (x AND y)
824
+ * (x AND y) => ((x AND y) OR z)
825
+ * ((x OR y) AND z) => (x OR y)
826
+ * This is still not an exhaustive test, but it handles most normal cases
827
+ * under the assumption that both inputs have been AND/OR flattened.
828
+ *
829
+ * A bare List node on the restriction side is interpreted as an AND clause,
830
+ * in order to handle the top-level restriction List properly. However we
831
+ * need not consider a List on the predicate side since pred_test() already
832
+ * expanded it.
833
+ *
834
+ * We have to be prepared to handle RestrictInfo nodes in the restrictinfo
835
+ * tree, though not in the predicate tree.
836
+ *----------
838
837
*/
839
838
static bool
840
- pred_test_recurse_restrict ( Expr * predicate , Node * clause )
839
+ pred_test_recurse ( Node * clause , Node * predicate )
841
840
{
842
- List * items ;
843
841
ListCell * item ;
844
842
845
843
Assert (clause != NULL );
844
+ /* skip through RestrictInfo */
846
845
if (IsA (clause , RestrictInfo ))
847
846
{
848
- RestrictInfo * restrictinfo = (RestrictInfo * ) clause ;
849
-
850
- return pred_test_recurse_restrict (predicate ,
851
- (Node * ) restrictinfo -> clause );
847
+ clause = (Node * ) ((RestrictInfo * ) clause )-> clause ;
848
+ Assert (clause != NULL );
849
+ Assert (!IsA (clause , RestrictInfo ));
852
850
}
853
- else if (or_clause (clause ))
851
+ Assert (predicate != NULL );
852
+
853
+ /*
854
+ * Since a restriction List clause is handled the same as an AND clause,
855
+ * we can avoid duplicate code like this:
856
+ */
857
+ if (and_clause (clause ))
858
+ clause = (Node * ) ((BoolExpr * ) clause )-> args ;
859
+
860
+ if (IsA (clause , List ))
854
861
{
855
- items = ((BoolExpr * ) clause )-> args ;
856
- foreach (item , items )
862
+ if (and_clause (predicate ))
857
863
{
858
- /* if any OR item doesn't imply the predicate, clause doesn't */
859
- if (!pred_test_recurse_restrict (predicate , lfirst (item )))
860
- return false;
864
+ /* AND-clause => AND-clause if A implies each of B's items */
865
+ foreach (item , ((BoolExpr * ) predicate )-> args )
866
+ {
867
+ if (!pred_test_recurse (clause , lfirst (item )))
868
+ return false;
869
+ }
870
+ return true;
871
+ }
872
+ else if (or_clause (predicate ))
873
+ {
874
+ /* AND-clause => OR-clause if A implies any of B's items */
875
+ /* Needed to handle (x AND y) => ((x AND y) OR z) */
876
+ foreach (item , ((BoolExpr * ) predicate )-> args )
877
+ {
878
+ if (pred_test_recurse (clause , lfirst (item )))
879
+ return true;
880
+ }
881
+ /* Also check if any of A's items implies B */
882
+ /* Needed to handle ((x OR y) AND z) => (x OR y) */
883
+ foreach (item , (List * ) clause )
884
+ {
885
+ if (pred_test_recurse (lfirst (item ), predicate ))
886
+ return true;
887
+ }
888
+ return false;
889
+ }
890
+ else
891
+ {
892
+ /* AND-clause => atom if any of A's items implies B */
893
+ foreach (item , (List * ) clause )
894
+ {
895
+ if (pred_test_recurse (lfirst (item ), predicate ))
896
+ return true;
897
+ }
898
+ return false;
861
899
}
862
- return true;
863
900
}
864
- else if (and_clause (clause ))
901
+ else if (or_clause (clause ))
865
902
{
866
- items = ((BoolExpr * ) clause )-> args ;
867
- foreach (item , items )
903
+ if (or_clause (predicate ))
868
904
{
869
905
/*
870
- * if any AND item implies the predicate, the whole clause
871
- * does
906
+ * OR-clause => OR-clause if each of A's items implies any of
907
+ * B's items. Messy but can't do it any more simply.
872
908
*/
873
- if (pred_test_recurse_restrict (predicate , lfirst (item )))
874
- return true;
909
+ foreach (item , ((BoolExpr * ) clause )-> args )
910
+ {
911
+ Node * citem = lfirst (item );
912
+ ListCell * item2 ;
913
+
914
+ foreach (item2 , ((BoolExpr * ) predicate )-> args )
915
+ {
916
+ if (pred_test_recurse (citem , lfirst (item2 )))
917
+ break ;
918
+ }
919
+ if (item2 == NULL )
920
+ return false; /* doesn't imply any of B's */
921
+ }
922
+ return true;
923
+ }
924
+ else
925
+ {
926
+ /* OR-clause => AND-clause if each of A's items implies B */
927
+ /* OR-clause => atom if each of A's items implies B */
928
+ foreach (item , ((BoolExpr * ) clause )-> args )
929
+ {
930
+ if (!pred_test_recurse (lfirst (item ), predicate ))
931
+ return false;
932
+ }
933
+ return true;
875
934
}
876
- return false;
877
935
}
878
936
else
879
- return pred_test_recurse_pred (predicate , clause );
880
- }
881
-
882
-
883
- /*
884
- * pred_test_recurse_pred
885
- * Does the "predicate inclusion test" for one conjunct of a predicate
886
- * expression. Here we recursively deal with the possibility that the
887
- * predicate conjunct is itself an AND or OR structure.
888
- */
889
- static bool
890
- pred_test_recurse_pred (Expr * predicate , Node * clause )
891
- {
892
- List * items ;
893
- ListCell * item ;
894
-
895
- Assert (predicate != NULL );
896
- if (or_clause ((Node * ) predicate ))
897
937
{
898
- items = ((BoolExpr * ) predicate )-> args ;
899
- foreach (item , items )
938
+ if (and_clause (predicate ))
900
939
{
901
- /* if any item is implied, the whole predicate is implied */
902
- if (pred_test_recurse_pred (lfirst (item ), clause ))
903
- return true;
940
+ /* atom => AND-clause if A implies each of B's items */
941
+ foreach (item , ((BoolExpr * ) predicate )-> args )
942
+ {
943
+ if (!pred_test_recurse (clause , lfirst (item )))
944
+ return false;
945
+ }
946
+ return true;
904
947
}
905
- return false;
906
- }
907
- else if (and_clause ((Node * ) predicate ))
908
- {
909
- items = ((BoolExpr * ) predicate )-> args ;
910
- foreach (item , items )
948
+ else if (or_clause (predicate ))
911
949
{
912
- /*
913
- * if any item is not implied, the whole predicate is not
914
- * implied
915
- */
916
- if (!pred_test_recurse_pred (lfirst (item ), clause ))
917
- return false;
950
+ /* atom => OR-clause if A implies any of B's items */
951
+ foreach (item , ((BoolExpr * ) predicate )-> args )
952
+ {
953
+ if (pred_test_recurse (clause , lfirst (item )))
954
+ return true;
955
+ }
956
+ return false;
957
+ }
958
+ else
959
+ {
960
+ /* atom => atom is the base case */
961
+ return pred_test_simple_clause ((Expr * ) predicate , clause );
918
962
}
919
- return true;
920
963
}
921
- else
922
- return pred_test_simple_clause (predicate , clause );
923
964
}
924
965
925
966
0 commit comments