77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
99 * IDENTIFICATION
10- * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.133 2008/08/14 18:47:59 tgl Exp $
10+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.134 2008/08/17 01:20:00 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -725,18 +725,31 @@ hash_ok_operator(OpExpr *expr)
725725/*
726726 * convert_ANY_sublink_to_join: can we convert an ANY SubLink to a join?
727727 *
728- * The caller has found an ANY SubLink at the top level of WHERE, but has not
729- * checked the properties of the SubLink further. Decide whether it is
730- * appropriate to process this SubLink in join style. If not, return NULL.
731- * If so, build the qual clause(s) to replace the SubLink, and return them.
732- * The qual clauses are wrapped in a FlattenedSubLink node to help later
733- * processing place them properly.
728+ * The caller has found an ANY SubLink at the top level of one of the query's
729+ * qual clauses, but has not checked the properties of the SubLink further.
730+ * Decide whether it is appropriate to process this SubLink in join style.
731+ * Return TRUE if so, FALSE if the SubLink cannot be converted.
732+ *
733+ * The only non-obvious input parameter is available_rels: this is the set
734+ * of query rels that can safely be referenced in the sublink expression.
735+ * (We must restrict this to avoid changing the semantics when a sublink
736+ * is present in an outer join's ON qual.) The conversion must fail if
737+ * the converted qual would reference any but these parent-query relids.
738+ *
739+ * On success, two output parameters are returned:
740+ **new_qual is set to the qual tree that should replace the SubLink in
741+ *the parent query's qual tree. The qual clauses are wrapped in a
742+ *FlattenedSubLink node to help later processing place them properly.
743+ **fromlist is set to a list of pulled-up jointree item(s) that must be
744+ *added at the proper spot in the parent query's jointree.
734745 *
735746 * Side effects of a successful conversion include adding the SubLink's
736747 * subselect to the query's rangetable.
737748 */
738- Node *
739- convert_ANY_sublink_to_join (PlannerInfo * root ,SubLink * sublink )
749+ bool
750+ convert_ANY_sublink_to_join (PlannerInfo * root ,SubLink * sublink ,
751+ Relids available_rels ,
752+ Node * * new_qual ,List * * fromlist )
740753{
741754Query * parse = root -> parse ;
742755Query * subselect = (Query * )sublink -> subselect ;
@@ -755,7 +768,7 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink)
755768 * higher levels should be okay, though.)
756769 */
757770if (contain_vars_of_level ((Node * )subselect ,1 ))
758- return NULL ;
771+ return false ;
759772
760773/*
761774 * The test expression must contain some Vars of the current query,
@@ -764,16 +777,22 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink)
764777 */
765778left_varnos = pull_varnos (sublink -> testexpr );
766779if (bms_is_empty (left_varnos ))
767- return NULL ;
780+ return false;
781+
782+ /*
783+ * However, it can't refer to anything outside available_rels.
784+ */
785+ if (!bms_is_subset (left_varnos ,available_rels ))
786+ return false;
768787
769788/*
770789 * The combining operators and left-hand expressions mustn't be volatile.
771790 */
772791if (contain_volatile_functions (sublink -> testexpr ))
773- return NULL ;
792+ return false ;
774793
775794/*
776- * Okay, pull up the sub-select intotop range table and jointree .
795+ * Okay, pull up the sub-select intoupper range table.
777796 *
778797 * We rely here on the assumption that the outer query has no references
779798 * to the inner (necessarily true, other than the Vars that we build
@@ -786,16 +805,15 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink)
786805false);
787806parse -> rtable = lappend (parse -> rtable ,rte );
788807rtindex = list_length (parse -> rtable );
789- rtr = makeNode (RangeTblRef );
790- rtr -> rtindex = rtindex ;
791808
792809/*
793- * We assume it's okay to add the pulled-up subquery to the topmost FROM
794- * list. This should be all right for ANY clauses appearing in WHERE
795- * or in upper-level plain JOIN/ON clauses. ANYs appearing below any
796- * outer joins couldn't be placed there, however.
810+ * Form a RangeTblRef for the pulled-up sub-select. This must be added
811+ * to the upper jointree, but it is caller's responsibility to figure
812+ * out where.
797813 */
798- parse -> jointree -> fromlist = lappend (parse -> jointree -> fromlist ,rtr );
814+ rtr = makeNode (RangeTblRef );
815+ rtr -> rtindex = rtindex ;
816+ * fromlist = list_make1 (rtr );
799817
800818/*
801819 * Build a list of Vars representing the subselect outputs.
@@ -805,22 +823,24 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink)
805823rtindex );
806824
807825/*
808- * Build theresult qual expression, replacing Params with these Vars.
826+ * Build thereplacement qual expression, replacing Params with these Vars.
809827 */
810828quals = (Expr * )convert_testexpr (root ,
811829sublink -> testexpr ,
812830subquery_vars );
813831
814832/*
815- *Now build the FlattenedSubLink node.
833+ *And finally, build the FlattenedSubLink node.
816834 */
817835fslink = makeNode (FlattenedSubLink );
818836fslink -> jointype = JOIN_SEMI ;
819837fslink -> lefthand = left_varnos ;
820838fslink -> righthand = bms_make_singleton (rtindex );
821839fslink -> quals = quals ;
822840
823- return (Node * )fslink ;
841+ * new_qual = (Node * )fslink ;
842+
843+ return true;
824844}
825845
826846/*
@@ -883,20 +903,15 @@ simplify_EXISTS_query(Query *query)
883903/*
884904 * convert_EXISTS_sublink_to_join: can we convert an EXISTS SubLink to a join?
885905 *
886- * The caller has found an EXISTS SubLink at the top level of WHERE, or just
887- * underneath a NOT, but has not checked the properties of the SubLink
888- * further. Decide whether it is appropriate to process this SubLink in join
889- * style. If not, return NULL. If so, build the qual clause(s) to replace
890- * the SubLink, and return them. (In the NOT case, the returned clauses are
891- * intended to replace the NOT as well.) The qual clauses are wrapped in a
892- * FlattenedSubLink node to help later processing place them properly.
893- *
894- * Side effects of a successful conversion include adding the SubLink's
895- * subselect to the query's rangetable.
906+ * The API of this function is identical to convert_ANY_sublink_to_join's,
907+ * except that we also support the case where the caller has found NOT EXISTS,
908+ * so we need an additional input parameter "under_not".
896909 */
897- Node *
910+ bool
898911convert_EXISTS_sublink_to_join (PlannerInfo * root ,SubLink * sublink ,
899- bool under_not )
912+ bool under_not ,
913+ Relids available_rels ,
914+ Node * * new_qual ,List * * fromlist )
900915{
901916Query * parse = root -> parse ;
902917Query * subselect = (Query * )sublink -> subselect ;
@@ -924,7 +939,7 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
924939 * us with noplace to evaluate the targetlist.
925940 */
926941if (!simplify_EXISTS_query (subselect ))
927- return NULL ;
942+ return false ;
928943
929944/*
930945 * Separate out the WHERE clause. (We could theoretically also remove
@@ -939,31 +954,31 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
939954 * query. (Vars of higher levels should be okay, though.)
940955 */
941956if (contain_vars_of_level ((Node * )subselect ,1 ))
942- return NULL ;
957+ return false ;
943958
944959/*
945960 * On the other hand, the WHERE clause must contain some Vars of the
946961 * parent query, else it's not gonna be a join.
947962 */
948963if (!contain_vars_of_level (whereClause ,1 ))
949- return NULL ;
964+ return false ;
950965
951966/*
952967 * We don't risk optimizing if the WHERE clause is volatile, either.
953968 */
954969if (contain_volatile_functions (whereClause ))
955- return NULL ;
970+ return false ;
956971
957972/*
958973 * Also disallow SubLinks within the WHERE clause. (XXX this could
959974 * probably be supported, but it would complicate the transformation
960975 * below, and it doesn't seem worth worrying about in a first pass.)
961976 */
962977if (contain_subplans (whereClause ))
963- return NULL ;
978+ return false ;
964979
965980/*
966- *Okay, pull up the sub-select into top range table and jointree .
981+ *Prepare to pull up the sub-select into top range table.
967982 *
968983 * We rely here on the assumption that the outer query has no references
969984 * to the inner (necessarily true). Therefore this is a lot easier than
@@ -973,7 +988,7 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
973988 * to do. The machinations of simplify_EXISTS_query ensured that there
974989 * is nothing interesting in the subquery except an rtable and jointree,
975990 * and even the jointree FromExpr no longer has quals. So we can just
976- * append the rtable to our own andappend the fromlist to our own.
991+ * append the rtable to our own andattach the fromlist to our own.
977992 * But first, adjust all level-zero varnos in the subquery to account
978993 * for the rtable merger.
979994 */
@@ -1007,32 +1022,39 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
10071022bms_free (clause_varnos );
10081023Assert (!bms_is_empty (left_varnos ));
10091024
1010- /* Also identify all the rels syntactically within the subselect */
1011- subselect_varnos = get_relids_in_jointree ((Node * )subselect -> jointree );
1025+ /*
1026+ * Now that we've got the set of upper-level varnos, we can make the
1027+ * last check: only available_rels can be referenced.
1028+ */
1029+ if (!bms_is_subset (left_varnos ,available_rels ))
1030+ return false;
1031+
1032+ /* Identify all the rels syntactically within the subselect */
1033+ subselect_varnos = get_relids_in_jointree ((Node * )subselect -> jointree ,
1034+ true);
10121035Assert (bms_is_subset (right_varnos ,subselect_varnos ));
10131036
10141037/* Now we can attach the modified subquery rtable to the parent */
10151038parse -> rtable = list_concat (parse -> rtable ,subselect -> rtable );
10161039
10171040/*
1018- * We assume it's okay to add the pulled-up subquery to the topmost FROM
1019- * list. This should be all right for EXISTS clauses appearing in WHERE
1020- * or in upper-level plain JOIN/ON clauses. EXISTS appearing below any
1021- * outer joins couldn't be placed there, however.
1041+ * Pass back the subquery fromlist to be attached to upper jointree
1042+ * in a suitable place.
10221043 */
1023- parse -> jointree -> fromlist = list_concat (parse -> jointree -> fromlist ,
1024- subselect -> jointree -> fromlist );
1044+ * fromlist = subselect -> jointree -> fromlist ;
10251045
10261046/*
1027- *Now build the FlattenedSubLink node.
1047+ *And finally, build the FlattenedSubLink node.
10281048 */
10291049fslink = makeNode (FlattenedSubLink );
10301050fslink -> jointype = under_not ?JOIN_ANTI :JOIN_SEMI ;
10311051fslink -> lefthand = left_varnos ;
10321052fslink -> righthand = subselect_varnos ;
10331053fslink -> quals = (Expr * )whereClause ;
10341054
1035- return (Node * )fslink ;
1055+ * new_qual = (Node * )fslink ;
1056+
1057+ return true;
10361058}
10371059
10381060/*