← Back to Overview

src/backend/optimizer/plan/planner.c

Coverage: 2/2 lines (100.0%)
Total Lines
2
modified
Covered
2
100.0%
Uncovered
0
0.0%
키보드 네비게이션
subquery_planner() lines 693-1279
Modified Lines Coverage: 2/2 lines (100.0%)
LineHitsSourceCommit
693 - subquery_planner(PlannerGlobal *glob, Query *parse, char *plan_name, -
694 - PlannerInfo *parent_root, bool hasRecursion, -
695 - double tuple_fraction, SetOperationStmt *setops) -
696 - { -
697 - PlannerInfo *root; -
698 - List *newWithCheckOptions; -
699 - List *newHaving; -
700 - bool hasOuterJoins; -
701 - bool hasResultRTEs; -
702 - RelOptInfo *final_rel; -
703 - ListCell *l; -
704 - -
705 - /* Create a PlannerInfo data structure for this subquery */ -
706 - root = makeNode(PlannerInfo); -
707 - root->parse = parse; -
708 - root->glob = glob; -
709 - root->query_level = parent_root ? parent_root->query_level + 1 : 1; -
710 - root->plan_name = plan_name; -
711 - root->parent_root = parent_root; -
712 - root->plan_params = NIL; -
713 - root->outer_params = NULL; -
714 - root->planner_cxt = CurrentMemoryContext; -
715 - root->init_plans = NIL; -
716 - root->cte_plan_ids = NIL; -
717 - root->multiexpr_params = NIL; -
718 - root->join_domains = NIL; -
719 - root->eq_classes = NIL; -
720 - root->ec_merging_done = false; -
721 - root->last_rinfo_serial = 0; -
722 - root->all_result_relids = -
723 - parse->resultRelation ? bms_make_singleton(parse->resultRelation) : NULL; -
724 - root->leaf_result_relids = NULL; /* we'll find out leaf-ness later */ -
725 - root->append_rel_list = NIL; -
726 - root->row_identity_vars = NIL; -
727 - root->rowMarks = NIL; -
728 - memset(root->upper_rels, 0, sizeof(root->upper_rels)); -
729 - memset(root->upper_targets, 0, sizeof(root->upper_targets)); -
730 - root->processed_groupClause = NIL; -
731 - root->processed_distinctClause = NIL; -
732 - root->processed_tlist = NIL; -
733 - root->update_colnos = NIL; -
734 - root->grouping_map = NULL; -
735 - root->minmax_aggs = NIL; -
736 - root->qual_security_level = 0; -
737 - root->hasPseudoConstantQuals = false; -
738 - root->hasAlternativeSubPlans = false; -
739 - root->placeholdersFrozen = false; -
740 - root->hasRecursion = hasRecursion; -
741 - root->assumeReplanning = false; -
742 - if (hasRecursion) -
743 - root->wt_param_id = assign_special_exec_param(root); -
744 - else -
745 - root->wt_param_id = -1; -
746 - root->non_recursive_path = NULL; -
747 - -
748 - /* -
749 - * Create the top-level join domain. This won't have valid contents until -
750 - * deconstruct_jointree fills it in, but the node needs to exist before -
751 - * that so we can build EquivalenceClasses referencing it. -
752 - */ -
753 - root->join_domains = list_make1(makeNode(JoinDomain)); -
754 - -
755 - /* -
756 - * If there is a WITH list, process each WITH query and either convert it -
757 - * to RTE_SUBQUERY RTE(s) or build an initplan SubPlan structure for it. -
758 - */ -
759 - if (parse->cteList) -
760 - SS_process_ctes(root); -
761 - -
762 - /* -
763 - * If it's a MERGE command, transform the joinlist as appropriate. -
764 - */ -
765 - transform_MERGE_to_join(parse); -
766 - -
767 - /* -
768 - * Scan the rangetable for relation RTEs and retrieve the necessary -
769 - * catalog information for each relation. Using this information, clear -
770 - * the inh flag for any relation that has no children, collect not-null -
771 - * attribute numbers for any relation that has column not-null -
772 - * constraints, and expand virtual generated columns for any relation that -
773 - * contains them. Note that this step does not descend into sublinks and -
774 - * subqueries; if we pull up any sublinks or subqueries below, their -
775 - * relation RTEs are processed just before pulling them up. -
776 - */ -
777 - parse = root->parse = preprocess_relation_rtes(root); -
778 - -
779 - /* -
780 - * If the FROM clause is empty, replace it with a dummy RTE_RESULT RTE, so -
781 - * that we don't need so many special cases to deal with that situation. -
782 - */ -
783 - replace_empty_jointree(parse); -
784 - -
785 - /* -
786 - * Look for ANY and EXISTS SubLinks in WHERE and JOIN/ON clauses, and try -
787 - * to transform them into joins. Note that this step does not descend -
788 - * into subqueries; if we pull up any subqueries below, their SubLinks are -
789 - * processed just before pulling them up. -
790 - */ -
791 - if (parse->hasSubLinks) -
792 - pull_up_sublinks(root); -
793 - -
794 - /* -
795 - * Scan the rangetable for function RTEs, do const-simplification on them, -
796 - * and then inline them if possible (producing subqueries that might get -
797 - * pulled up next). Recursion issues here are handled in the same way as -
798 - * for SubLinks. -
799 - */ -
800 - preprocess_function_rtes(root); -
801 - -
802 - /* -
803 - * Check to see if any subqueries in the jointree can be merged into this -
804 - * query. -
805 - */ -
806 - pull_up_subqueries(root); -
807 - -
808 - /* -
809 - * If this is a simple UNION ALL query, flatten it into an appendrel. We -
810 - * do this now because it requires applying pull_up_subqueries to the leaf -
811 - * queries of the UNION ALL, which weren't touched above because they -
812 - * weren't referenced by the jointree (they will be after we do this). -
813 - */ -
814 - if (parse->setOperations) -
815 - flatten_simple_union_all(root); -
816 - -
817 - /* -
818 - * Survey the rangetable to see what kinds of entries are present. We can -
819 - * skip some later processing if relevant SQL features are not used; for -
820 - * example if there are no JOIN RTEs we can avoid the expense of doing -
821 - * flatten_join_alias_vars(). This must be done after we have finished -
822 - * adding rangetable entries, of course. (Note: actually, processing of -
823 - * inherited or partitioned rels can cause RTEs for their child tables to -
824 - * get added later; but those must all be RTE_RELATION entries, so they -
825 - * don't invalidate the conclusions drawn here.) -
826 - */ -
827 - root->hasJoinRTEs = false; -
828 - root->hasLateralRTEs = false; -
829 - root->group_rtindex = 0; -
830 - hasOuterJoins = false; -
831 - hasResultRTEs = false; -
832 - foreach(l, parse->rtable) -
833 - { -
834 - RangeTblEntry *rte = lfirst_node(RangeTblEntry, l); -
835 - -
836 - switch (rte->rtekind) -
837 - { -
838 - case RTE_JOIN: -
839 - root->hasJoinRTEs = true; -
840 - if (IS_OUTER_JOIN(rte->jointype)) -
841 - hasOuterJoins = true; -
842 - break; -
843 - case RTE_RESULT: -
844 - hasResultRTEs = true; -
845 - break; -
846 - case RTE_GROUP: -
847 - Assert(parse->hasGroupRTE); -
848 - root->group_rtindex = list_cell_number(parse->rtable, l) + 1; -
849 - break; -
850 - default: -
851 - /* No work here for other RTE types */ -
852 - break; -
853 - } -
854 - -
855 - if (rte->lateral) -
856 - root->hasLateralRTEs = true; -
857 - -
858 - /* -
859 - * We can also determine the maximum security level required for any -
860 - * securityQuals now. Addition of inheritance-child RTEs won't affect -
861 - * this, because child tables don't have their own securityQuals; see -
862 - * expand_single_inheritance_child(). -
863 - */ -
864 - if (rte->securityQuals) -
865 - root->qual_security_level = Max(root->qual_security_level, -
866 - list_length(rte->securityQuals)); -
867 - } -
868 - -
869 - /* -
870 - * If we have now verified that the query target relation is -
871 - * non-inheriting, mark it as a leaf target. -
872 - */ -
873 - if (parse->resultRelation) -
874 - { -
875 - RangeTblEntry *rte = rt_fetch(parse->resultRelation, parse->rtable); -
876 - -
877 - if (!rte->inh) -
878 - root->leaf_result_relids = -
879 - bms_make_singleton(parse->resultRelation); -
880 - } -
881 - -
882 - /* -
883 - * This would be a convenient time to check access permissions for all -
884 - * relations mentioned in the query, since it would be better to fail now, -
885 - * before doing any detailed planning. However, for historical reasons, -
886 - * we leave this to be done at executor startup. -
887 - * -
888 - * Note, however, that we do need to check access permissions for any view -
889 - * relations mentioned in the query, in order to prevent information being -
890 - * leaked by selectivity estimation functions, which only check view owner -
891 - * permissions on underlying tables (see all_rows_selectable() and its -
892 - * callers). This is a little ugly, because it means that access -
893 - * permissions for views will be checked twice, which is another reason -
894 - * why it would be better to do all the ACL checks here. -
895 - */ -
896 - foreach(l, parse->rtable) -
897 - { -
898 - RangeTblEntry *rte = lfirst_node(RangeTblEntry, l); -
899 - -
900 - if (rte->perminfoindex != 0 && -
901 - rte->relkind == RELKIND_VIEW) -
902 - { -
903 - RTEPermissionInfo *perminfo; -
904 - bool result; -
905 - -
906 - perminfo = getRTEPermissionInfo(parse->rteperminfos, rte); -
907 - result = ExecCheckOneRelPerms(perminfo); -
908 - if (!result) -
909 - aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_VIEW, -
910 - get_rel_name(perminfo->relid)); -
911 - } -
912 - } -
913 - -
914 - /* -
915 - * Preprocess RowMark information. We need to do this after subquery -
916 - * pullup, so that all base relations are present. -
917 - */ -
918 - preprocess_rowmarks(root); -
919 - -
920 - /* -
921 - * Set hasHavingQual to remember if HAVING clause is present. Needed -
922 - * because preprocess_expression will reduce a constant-true condition to -
923 - * an empty qual list ... but "HAVING TRUE" is not a semantic no-op. -
924 - */ -
925 - root->hasHavingQual = (parse->havingQual != NULL); -
926 - -
927 - /* -
928 - * Do expression preprocessing on targetlist and quals, as well as other -
929 - * random expressions in the querytree. Note that we do not need to -
930 - * handle sort/group expressions explicitly, because they are actually -
931 - * part of the targetlist. -
932 - */ -
933 - parse->targetList = (List *) -
934 - preprocess_expression(root, (Node *) parse->targetList, -
935 - EXPRKIND_TARGET); -
936 - -
937 - newWithCheckOptions = NIL; -
938 - foreach(l, parse->withCheckOptions) -
939 - { -
940 - WithCheckOption *wco = lfirst_node(WithCheckOption, l); -
941 - -
942 - wco->qual = preprocess_expression(root, wco->qual, -
943 - EXPRKIND_QUAL); -
944 - if (wco->qual != NULL) -
945 - newWithCheckOptions = lappend(newWithCheckOptions, wco); -
946 - } -
947 - parse->withCheckOptions = newWithCheckOptions; -
948 - -
949 - parse->returningList = (List *) -
950 - preprocess_expression(root, (Node *) parse->returningList, -
951 - EXPRKIND_TARGET); -
952 - -
953 - preprocess_qual_conditions(root, (Node *) parse->jointree); -
954 - -
955 - parse->havingQual = preprocess_expression(root, parse->havingQual, -
956 - EXPRKIND_QUAL); -
957 - -
958 - foreach(l, parse->windowClause) -
959 - { -
960 - WindowClause *wc = lfirst_node(WindowClause, l); -
961 - -
962 - /* partitionClause/orderClause are sort/group expressions */ -
963 - wc->startOffset = preprocess_expression(root, wc->startOffset, -
964 - EXPRKIND_LIMIT); -
965 - wc->endOffset = preprocess_expression(root, wc->endOffset, -
966 - EXPRKIND_LIMIT); -
967 1489 wc->defineClause = (List *) preprocess_expression(root, e33632aRow pattern recognition patch (planner).
968 1489 (Node *) wc->defineClause, e33632aRow pattern recognition patch (planner).
969 - EXPRKIND_TARGET); e33632aRow pattern recognition patch (planner).
970 - } -
971 - -
972 - parse->limitOffset = preprocess_expression(root, parse->limitOffset, -
973 - EXPRKIND_LIMIT); -
974 - parse->limitCount = preprocess_expression(root, parse->limitCount, -
975 - EXPRKIND_LIMIT); -
976 - -
977 - if (parse->onConflict) -
978 - { -
979 - parse->onConflict->arbiterElems = (List *) -
980 - preprocess_expression(root, -
981 - (Node *) parse->onConflict->arbiterElems, -
982 - EXPRKIND_ARBITER_ELEM); -
983 - parse->onConflict->arbiterWhere = -
984 - preprocess_expression(root, -
985 - parse->onConflict->arbiterWhere, -
986 - EXPRKIND_QUAL); -
987 - parse->onConflict->onConflictSet = (List *) -
988 - preprocess_expression(root, -
989 - (Node *) parse->onConflict->onConflictSet, -
990 - EXPRKIND_TARGET); -
991 - parse->onConflict->onConflictWhere = -
992 - preprocess_expression(root, -
993 - parse->onConflict->onConflictWhere, -
994 - EXPRKIND_QUAL); -
995 - /* exclRelTlist contains only Vars, so no preprocessing needed */ -
996 - } -
997 - -
998 - foreach(l, parse->mergeActionList) -
999 - { -
1000 - MergeAction *action = (MergeAction *) lfirst(l); -
1001 - -
1002 - action->targetList = (List *) -
1003 - preprocess_expression(root, -
1004 - (Node *) action->targetList, -
1005 - EXPRKIND_TARGET); -
1006 - action->qual = -
1007 - preprocess_expression(root, -
1008 - (Node *) action->qual, -
1009 - EXPRKIND_QUAL); -
1010 - } -
1011 - -
1012 - parse->mergeJoinCondition = -
1013 - preprocess_expression(root, parse->mergeJoinCondition, EXPRKIND_QUAL); -
1014 - -
1015 - root->append_rel_list = (List *) -
1016 - preprocess_expression(root, (Node *) root->append_rel_list, -
1017 - EXPRKIND_APPINFO); -
1018 - -
1019 - /* Also need to preprocess expressions within RTEs */ -
1020 - foreach(l, parse->rtable) -
1021 - { -
1022 - RangeTblEntry *rte = lfirst_node(RangeTblEntry, l); -
1023 - int kind; -
1024 - ListCell *lcsq; -
1025 - -
1026 - if (rte->rtekind == RTE_RELATION) -
1027 - { -
1028 - if (rte->tablesample) -
1029 - rte->tablesample = (TableSampleClause *) -
1030 - preprocess_expression(root, -
1031 - (Node *) rte->tablesample, -
1032 - EXPRKIND_TABLESAMPLE); -
1033 - } -
1034 - else if (rte->rtekind == RTE_SUBQUERY) -
1035 - { -
1036 - /* -
1037 - * We don't want to do all preprocessing yet on the subquery's -
1038 - * expressions, since that will happen when we plan it. But if it -
1039 - * contains any join aliases of our level, those have to get -
1040 - * expanded now, because planning of the subquery won't do it. -
1041 - * That's only possible if the subquery is LATERAL. -
1042 - */ -
1043 - if (rte->lateral && root->hasJoinRTEs) -
1044 - rte->subquery = (Query *) -
1045 - flatten_join_alias_vars(root, root->parse, -
1046 - (Node *) rte->subquery); -
1047 - } -
1048 - else if (rte->rtekind == RTE_FUNCTION) -
1049 - { -
1050 - /* Preprocess the function expression(s) fully */ -
1051 - kind = rte->lateral ? EXPRKIND_RTFUNC_LATERAL : EXPRKIND_RTFUNC; -
1052 - rte->functions = (List *) -
1053 - preprocess_expression(root, (Node *) rte->functions, kind); -
1054 - } -
1055 - else if (rte->rtekind == RTE_TABLEFUNC) -
1056 - { -
1057 - /* Preprocess the function expression(s) fully */ -
1058 - kind = rte->lateral ? EXPRKIND_TABLEFUNC_LATERAL : EXPRKIND_TABLEFUNC; -
1059 - rte->tablefunc = (TableFunc *) -
1060 - preprocess_expression(root, (Node *) rte->tablefunc, kind); -
1061 - } -
1062 - else if (rte->rtekind == RTE_VALUES) -
1063 - { -
1064 - /* Preprocess the values lists fully */ -
1065 - kind = rte->lateral ? EXPRKIND_VALUES_LATERAL : EXPRKIND_VALUES; -
1066 - rte->values_lists = (List *) -
1067 - preprocess_expression(root, (Node *) rte->values_lists, kind); -
1068 - } -
1069 - else if (rte->rtekind == RTE_GROUP) -
1070 - { -
1071 - /* Preprocess the groupexprs list fully */ -
1072 - rte->groupexprs = (List *) -
1073 - preprocess_expression(root, (Node *) rte->groupexprs, -
1074 - EXPRKIND_GROUPEXPR); -
1075 - } -
1076 - -
1077 - /* -
1078 - * Process each element of the securityQuals list as if it were a -
1079 - * separate qual expression (as indeed it is). We need to do it this -
1080 - * way to get proper canonicalization of AND/OR structure. Note that -
1081 - * this converts each element into an implicit-AND sublist. -
1082 - */ -
1083 - foreach(lcsq, rte->securityQuals) -
1084 - { -
1085 - lfirst(lcsq) = preprocess_expression(root, -
1086 - (Node *) lfirst(lcsq), -
1087 - EXPRKIND_QUAL); -
1088 - } -
1089 - } -
1090 - -
1091 - /* -
1092 - * Now that we are done preprocessing expressions, and in particular done -
1093 - * flattening join alias variables, get rid of the joinaliasvars lists. -
1094 - * They no longer match what expressions in the rest of the tree look -
1095 - * like, because we have not preprocessed expressions in those lists (and -
1096 - * do not want to; for example, expanding a SubLink there would result in -
1097 - * a useless unreferenced subplan). Leaving them in place simply creates -
1098 - * a hazard for later scans of the tree. We could try to prevent that by -
1099 - * using QTW_IGNORE_JOINALIASES in every tree scan done after this point, -
1100 - * but that doesn't sound very reliable. -
1101 - */ -
1102 - if (root->hasJoinRTEs) -
1103 - { -
1104 - foreach(l, parse->rtable) -
1105 - { -
1106 - RangeTblEntry *rte = lfirst_node(RangeTblEntry, l); -
1107 - -
1108 - rte->joinaliasvars = NIL; -
1109 - } -
1110 - } -
1111 - -
1112 - /* -
1113 - * Replace any Vars in the subquery's targetlist and havingQual that -
1114 - * reference GROUP outputs with the underlying grouping expressions. -
1115 - * -
1116 - * Note that we need to perform this replacement after we've preprocessed -
1117 - * the grouping expressions. This is to ensure that there is only one -
1118 - * instance of SubPlan for each SubLink contained within the grouping -
1119 - * expressions. -
1120 - */ -
1121 - if (parse->hasGroupRTE) -
1122 - { -
1123 - parse->targetList = (List *) -
1124 - flatten_group_exprs(root, root->parse, (Node *) parse->targetList); -
1125 - parse->havingQual = -
1126 - flatten_group_exprs(root, root->parse, parse->havingQual); -
1127 - } -
1128 - -
1129 - /* Constant-folding might have removed all set-returning functions */ -
1130 - if (parse->hasTargetSRFs) -
1131 - parse->hasTargetSRFs = expression_returns_set((Node *) parse->targetList); -
1132 - -
1133 - /* -
1134 - * If we have grouping sets, expand the groupingSets tree of this query to -
1135 - * a flat list of grouping sets. We need to do this before optimizing -
1136 - * HAVING, since we can't easily tell if there's an empty grouping set -
1137 - * until we have this representation. -
1138 - */ -
1139 - if (parse->groupingSets) -
1140 - { -
1141 - parse->groupingSets = -
1142 - expand_grouping_sets(parse->groupingSets, parse->groupDistinct, -1); -
1143 - } -
1144 - -
1145 - /* -
1146 - * In some cases we may want to transfer a HAVING clause into WHERE. We -
1147 - * cannot do so if the HAVING clause contains aggregates (obviously) or -
1148 - * volatile functions (since a HAVING clause is supposed to be executed -
1149 - * only once per group). We also can't do this if there are any grouping -
1150 - * sets and the clause references any columns that are nullable by the -
1151 - * grouping sets; the nulled values of those columns are not available -
1152 - * before the grouping step. (The test on groupClause might seem wrong, -
1153 - * but it's okay: it's just an optimization to avoid running pull_varnos -
1154 - * when there cannot be any Vars in the HAVING clause.) -
1155 - * -
1156 - * Also, it may be that the clause is so expensive to execute that we're -
1157 - * better off doing it only once per group, despite the loss of -
1158 - * selectivity. This is hard to estimate short of doing the entire -
1159 - * planning process twice, so we use a heuristic: clauses containing -
1160 - * subplans are left in HAVING. Otherwise, we move or copy the HAVING -
1161 - * clause into WHERE, in hopes of eliminating tuples before aggregation -
1162 - * instead of after. -
1163 - * -
1164 - * If the query has no empty grouping set then we can simply move such a -
1165 - * clause into WHERE; any group that fails the clause will not be in the -
1166 - * output because none of its tuples will reach the grouping or -
1167 - * aggregation stage. Otherwise we have to keep the clause in HAVING to -
1168 - * ensure that we don't emit a bogus aggregated row. But then the HAVING -
1169 - * clause must be degenerate (variable-free), so we can copy it into WHERE -
1170 - * so that query_planner() can use it in a gating Result node. (This could -
1171 - * be done better, but it seems not worth optimizing.) -
1172 - * -
1173 - * Note that a HAVING clause may contain expressions that are not fully -
1174 - * preprocessed. This can happen if these expressions are part of -
1175 - * grouping items. In such cases, they are replaced with GROUP Vars in -
1176 - * the parser and then replaced back after we're done with expression -
1177 - * preprocessing on havingQual. This is not an issue if the clause -
1178 - * remains in HAVING, because these expressions will be matched to lower -
1179 - * target items in setrefs.c. However, if the clause is moved or copied -
1180 - * into WHERE, we need to ensure that these expressions are fully -
1181 - * preprocessed. -
1182 - * -
1183 - * Note that both havingQual and parse->jointree->quals are in -
1184 - * implicitly-ANDed-list form at this point, even though they are declared -
1185 - * as Node *. -
1186 - */ -
1187 - newHaving = NIL; -
1188 - foreach(l, (List *) parse->havingQual) -
1189 - { -
1190 - Node *havingclause = (Node *) lfirst(l); -
1191 - -
1192 - if (contain_agg_clause(havingclause) || -
1193 - contain_volatile_functions(havingclause) || -
1194 - contain_subplans(havingclause) || -
1195 - (parse->groupClause && parse->groupingSets && -
1196 - bms_is_member(root->group_rtindex, pull_varnos(root, havingclause)))) -
1197 - { -
1198 - /* keep it in HAVING */ -
1199 - newHaving = lappend(newHaving, havingclause); -
1200 - } -
1201 - else if (parse->groupClause && -
1202 - (parse->groupingSets == NIL || -
1203 - (List *) linitial(parse->groupingSets) != NIL)) -
1204 - { -
1205 - /* There is GROUP BY, but no empty grouping set */ -
1206 - Node *whereclause; -
1207 - -
1208 - /* Preprocess the HAVING clause fully */ -
1209 - whereclause = preprocess_expression(root, havingclause, -
1210 - EXPRKIND_QUAL); -
1211 - /* ... and move it to WHERE */ -
1212 - parse->jointree->quals = (Node *) -
1213 - list_concat((List *) parse->jointree->quals, -
1214 - (List *) whereclause); -
1215 - } -
1216 - else -
1217 - { -
1218 - /* There is an empty grouping set (perhaps implicitly) */ -
1219 - Node *whereclause; -
1220 - -
1221 - /* Preprocess the HAVING clause fully */ -
1222 - whereclause = preprocess_expression(root, copyObject(havingclause), -
1223 - EXPRKIND_QUAL); -
1224 - /* ... and put a copy in WHERE */ -
1225 - parse->jointree->quals = (Node *) -
1226 - list_concat((List *) parse->jointree->quals, -
1227 - (List *) whereclause); -
1228 - /* ... and also keep it in HAVING */ -
1229 - newHaving = lappend(newHaving, havingclause); -
1230 - } -
1231 - } -
1232 - parse->havingQual = (Node *) newHaving; -
1233 - -
1234 - /* -
1235 - * If we have any outer joins, try to reduce them to plain inner joins. -
1236 - * This step is most easily done after we've done expression -
1237 - * preprocessing. -
1238 - */ -
1239 - if (hasOuterJoins) -
1240 - reduce_outer_joins(root); -
1241 - -
1242 - /* -
1243 - * If we have any RTE_RESULT relations, see if they can be deleted from -
1244 - * the jointree. We also rely on this processing to flatten single-child -
1245 - * FromExprs underneath outer joins. This step is most effectively done -
1246 - * after we've done expression preprocessing and outer join reduction. -
1247 - */ -
1248 - if (hasResultRTEs || hasOuterJoins) -
1249 - remove_useless_result_rtes(root); -
1250 - -
1251 - /* -
1252 - * Do the main planning. -
1253 - */ -
1254 - grouping_planner(root, tuple_fraction, setops); -
1255 - -
1256 - /* -
1257 - * Capture the set of outer-level param IDs we have access to, for use in -
1258 - * extParam/allParam calculations later. -
1259 - */ -
1260 - SS_identify_outer_params(root); -
1261 - -
1262 - /* -
1263 - * If any initPlans were created in this query level, adjust the surviving -
1264 - * Paths' costs and parallel-safety flags to account for them. The -
1265 - * initPlans won't actually get attached to the plan tree till -
1266 - * create_plan() runs, but we must include their effects now. -
1267 - */ -
1268 - final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL); -
1269 - SS_charge_for_initplans(root, final_rel); -
1270 - -
1271 - /* -
1272 - * Make sure we've identified the cheapest Path for the final rel. (By -
1273 - * doing this here not in grouping_planner, we include initPlan costs in -
1274 - * the decision, though it's unlikely that will change anything.) -
1275 - */ -
1276 - set_cheapest(final_rel); -
1277 - -
1278 - return root; -
1279 - } -