← Back to Overview

src/backend/optimizer/plan/planner.c

Coverage: 11/11 lines (100.0%)
Total Lines
11
modified
Covered
11
100.0%
Uncovered
0
0.0%
Keyboard navigation
subquery_planner() lines 776-1414
Modified Lines Coverage: 4/4 lines (100.0%)
LineHitsSourceCommit
776 - subquery_planner(PlannerGlobal *glob, Query *parse, char *plan_name, -
777 - PlannerInfo *parent_root, PlannerInfo *alternative_root, -
778 - bool hasRecursion, double tuple_fraction, -
779 - SetOperationStmt *setops) -
780 - { -
781 - PlannerInfo *root; -
782 - List *newWithCheckOptions; -
783 - List *newHaving; -
784 - Bitmapset *havingCollationConflicts; -
785 - int havingIdx; -
786 - bool hasOuterJoins; -
787 - bool hasResultRTEs; -
788 - RelOptInfo *final_rel; -
789 - ListCell *l; -
790 - -
791 - /* Create a PlannerInfo data structure for this subquery */ -
792 - root = makeNode(PlannerInfo); -
793 - root->parse = parse; -
794 - root->glob = glob; -
795 - root->query_level = parent_root ? parent_root->query_level + 1 : 1; -
796 - root->plan_name = plan_name; -
797 - if (alternative_root != NULL) -
798 - root->alternative_plan_name = alternative_root->plan_name; -
799 - else -
800 - root->alternative_plan_name = plan_name; -
801 - root->parent_root = parent_root; -
802 - root->plan_params = NIL; -
803 - root->outer_params = NULL; -
804 - root->planner_cxt = CurrentMemoryContext; -
805 - root->init_plans = NIL; -
806 - root->cte_plan_ids = NIL; -
807 - root->multiexpr_params = NIL; -
808 - root->join_domains = NIL; -
809 - root->eq_classes = NIL; -
810 - root->ec_merging_done = false; -
811 - root->last_rinfo_serial = 0; -
812 - root->all_result_relids = -
813 - parse->resultRelation ? bms_make_singleton(parse->resultRelation) : NULL; -
814 - root->leaf_result_relids = NULL; /* we'll find out leaf-ness later */ -
815 - root->append_rel_list = NIL; -
816 - root->row_identity_vars = NIL; -
817 - root->rowMarks = NIL; -
818 - memset(root->upper_rels, 0, sizeof(root->upper_rels)); -
819 - memset(root->upper_targets, 0, sizeof(root->upper_targets)); -
820 - root->processed_groupClause = NIL; -
821 - root->processed_distinctClause = NIL; -
822 - root->processed_tlist = NIL; -
823 - root->update_colnos = NIL; -
824 - root->grouping_map = NULL; -
825 - root->minmax_aggs = NIL; -
826 - root->qual_security_level = 0; -
827 - root->hasPseudoConstantQuals = false; -
828 - root->hasAlternativeSubPlans = false; -
829 - root->placeholdersFrozen = false; -
830 - root->hasRecursion = hasRecursion; -
831 - root->assumeReplanning = false; -
832 - if (hasRecursion) -
833 - root->wt_param_id = assign_special_exec_param(root); -
834 - else -
835 - root->wt_param_id = -1; -
836 - root->non_recursive_path = NULL; -
837 - -
838 - /* -
839 - * Create the top-level join domain. This won't have valid contents until -
840 - * deconstruct_jointree fills it in, but the node needs to exist before -
841 - * that so we can build EquivalenceClasses referencing it. -
842 - */ -
843 - root->join_domains = list_make1(makeNode(JoinDomain)); -
844 - -
845 - /* -
846 - * If there is a WITH list, process each WITH query and either convert it -
847 - * to RTE_SUBQUERY RTE(s) or build an initplan SubPlan structure for it. -
848 - */ -
849 - if (parse->cteList) -
850 - SS_process_ctes(root); -
851 - -
852 - /* -
853 - * If it's a MERGE command, transform the joinlist as appropriate. -
854 - */ -
855 - transform_MERGE_to_join(parse); -
856 - -
857 - /* -
858 - * Scan the rangetable for relation RTEs and retrieve the necessary -
859 - * catalog information for each relation. Using this information, clear -
860 - * the inh flag for any relation that has no children, collect not-null -
861 - * attribute numbers for any relation that has column not-null -
862 - * constraints, and expand virtual generated columns for any relation that -
863 - * contains them. Note that this step does not descend into sublinks and -
864 - * subqueries; if we pull up any sublinks or subqueries below, their -
865 - * relation RTEs are processed just before pulling them up. -
866 - */ -
867 - parse = root->parse = preprocess_relation_rtes(root); -
868 - -
869 - /* -
870 - * If the FROM clause is empty, replace it with a dummy RTE_RESULT RTE, so -
871 - * that we don't need so many special cases to deal with that situation. -
872 - */ -
873 - replace_empty_jointree(parse); -
874 - -
875 - /* -
876 - * Look for ANY and EXISTS SubLinks in WHERE and JOIN/ON clauses, and try -
877 - * to transform them into joins. Note that this step does not descend -
878 - * into subqueries; if we pull up any subqueries below, their SubLinks are -
879 - * processed just before pulling them up. -
880 - */ -
881 - if (parse->hasSubLinks) -
882 - pull_up_sublinks(root); -
883 - -
884 - /* -
885 - * Scan the rangetable for function RTEs, do const-simplification on them, -
886 - * and then inline them if possible (producing subqueries that might get -
887 - * pulled up next). Recursion issues here are handled in the same way as -
888 - * for SubLinks. -
889 - */ -
890 - preprocess_function_rtes(root); -
891 - -
892 - /* -
893 - * Check to see if any subqueries in the jointree can be merged into this -
894 - * query. -
895 - */ -
896 - pull_up_subqueries(root); -
897 - -
898 - /* -
899 - * If this is a simple UNION ALL query, flatten it into an appendrel. We -
900 - * do this now because it requires applying pull_up_subqueries to the leaf -
901 - * queries of the UNION ALL, which weren't touched above because they -
902 - * weren't referenced by the jointree (they will be after we do this). -
903 - */ -
904 - if (parse->setOperations) -
905 - flatten_simple_union_all(root); -
906 - -
907 - /* -
908 - * Survey the rangetable to see what kinds of entries are present. We can -
909 - * skip some later processing if relevant SQL features are not used; for -
910 - * example if there are no JOIN RTEs we can avoid the expense of doing -
911 - * flatten_join_alias_vars(). This must be done after we have finished -
912 - * adding rangetable entries, of course. (Note: actually, processing of -
913 - * inherited or partitioned rels can cause RTEs for their child tables to -
914 - * get added later; but those must all be RTE_RELATION entries, so they -
915 - * don't invalidate the conclusions drawn here.) -
916 - */ -
917 - root->hasJoinRTEs = false; -
918 - root->hasLateralRTEs = false; -
919 - root->group_rtindex = 0; -
920 - hasOuterJoins = false; -
921 - hasResultRTEs = false; -
922 - foreach(l, parse->rtable) -
923 - { -
924 - RangeTblEntry *rte = lfirst_node(RangeTblEntry, l); -
925 - -
926 - switch (rte->rtekind) -
927 - { -
928 - case RTE_JOIN: -
929 - root->hasJoinRTEs = true; -
930 - if (IS_OUTER_JOIN(rte->jointype)) -
931 - hasOuterJoins = true; -
932 - break; -
933 - case RTE_RESULT: -
934 - hasResultRTEs = true; -
935 - break; -
936 - case RTE_GROUP: -
937 - Assert(parse->hasGroupRTE); -
938 - root->group_rtindex = list_cell_number(parse->rtable, l) + 1; -
939 - break; -
940 - default: -
941 - /* No work here for other RTE types */ -
942 - break; -
943 - } -
944 - -
945 - if (rte->lateral) -
946 - root->hasLateralRTEs = true; -
947 - -
948 - /* -
949 - * We can also determine the maximum security level required for any -
950 - * securityQuals now. Addition of inheritance-child RTEs won't affect -
951 - * this, because child tables don't have their own securityQuals; see -
952 - * expand_single_inheritance_child(). -
953 - */ -
954 - if (rte->securityQuals) -
955 - root->qual_security_level = Max(root->qual_security_level, -
956 - list_length(rte->securityQuals)); -
957 - } -
958 - -
959 - /* -
960 - * If we have now verified that the query target relation is -
961 - * non-inheriting, mark it as a leaf target. -
962 - */ -
963 - if (parse->resultRelation) -
964 - { -
965 - RangeTblEntry *rte = rt_fetch(parse->resultRelation, parse->rtable); -
966 - -
967 - if (!rte->inh) -
968 - root->leaf_result_relids = -
969 - bms_make_singleton(parse->resultRelation); -
970 - } -
971 - -
972 - /* -
973 - * This would be a convenient time to check access permissions for all -
974 - * relations mentioned in the query, since it would be better to fail now, -
975 - * before doing any detailed planning. However, for historical reasons, -
976 - * we leave this to be done at executor startup. -
977 - * -
978 - * Note, however, that we do need to check access permissions for any view -
979 - * relations mentioned in the query, in order to prevent information being -
980 - * leaked by selectivity estimation functions, which only check view owner -
981 - * permissions on underlying tables (see all_rows_selectable() and its -
982 - * callers). This is a little ugly, because it means that access -
983 - * permissions for views will be checked twice, which is another reason -
984 - * why it would be better to do all the ACL checks here. -
985 - */ -
986 - foreach(l, parse->rtable) -
987 - { -
988 - RangeTblEntry *rte = lfirst_node(RangeTblEntry, l); -
989 - -
990 - if (rte->perminfoindex != 0 && -
991 - rte->relkind == RELKIND_VIEW) -
992 - { -
993 - RTEPermissionInfo *perminfo; -
994 - bool result; -
995 - -
996 - perminfo = getRTEPermissionInfo(parse->rteperminfos, rte); -
997 - result = ExecCheckOneRelPerms(perminfo); -
998 - if (!result) -
999 - aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_VIEW, -
1000 - get_rel_name(perminfo->relid)); -
1001 - } -
1002 - } -
1003 - -
1004 - /* -
1005 - * Preprocess RowMark information. We need to do this after subquery -
1006 - * pullup, so that all base relations are present. -
1007 - */ -
1008 - preprocess_rowmarks(root); -
1009 - -
1010 - /* -
1011 - * Set hasHavingQual to remember if HAVING clause is present. Needed -
1012 - * because preprocess_expression will reduce a constant-true condition to -
1013 - * an empty qual list ... but "HAVING TRUE" is not a semantic no-op. -
1014 - */ -
1015 - root->hasHavingQual = (parse->havingQual != NULL); -
1016 - -
1017 - /* -
1018 - * Do expression preprocessing on targetlist and quals, as well as other -
1019 - * random expressions in the querytree. Note that we do not need to -
1020 - * handle sort/group expressions explicitly, because they are actually -
1021 - * part of the targetlist. -
1022 - */ -
1023 - parse->targetList = (List *) -
1024 - preprocess_expression(root, (Node *) parse->targetList, -
1025 - EXPRKIND_TARGET); -
1026 - -
1027 - newWithCheckOptions = NIL; -
1028 - foreach(l, parse->withCheckOptions) -
1029 - { -
1030 - WithCheckOption *wco = lfirst_node(WithCheckOption, l); -
1031 - -
1032 - wco->qual = preprocess_expression(root, wco->qual, -
1033 - EXPRKIND_QUAL); -
1034 - if (wco->qual != NULL) -
1035 - newWithCheckOptions = lappend(newWithCheckOptions, wco); -
1036 - } -
1037 - parse->withCheckOptions = newWithCheckOptions; -
1038 - -
1039 - parse->returningList = (List *) -
1040 - preprocess_expression(root, (Node *) parse->returningList, -
1041 - EXPRKIND_TARGET); -
1042 - -
1043 - preprocess_qual_conditions(root, (Node *) parse->jointree); -
1044 - -
1045 - parse->havingQual = preprocess_expression(root, parse->havingQual, -
1046 - EXPRKIND_QUAL); -
1047 - -
1048 - foreach(l, parse->windowClause) -
1049 - { -
1050 - WindowClause *wc = lfirst_node(WindowClause, l); -
1051 - -
1052 - /* 7521a30Row pattern recognition patch (planner).
1053 - * Reject volatile functions (and sequence operations) in an RPR 7521a30Row pattern recognition patch (planner).
1054 - * DEFINE clause. This is done here, not during parse analysis, to 7521a30Row pattern recognition patch (planner).
1055 - * follow the convention of not checking expression volatility while 7521a30Row pattern recognition patch (planner).
1056 - * parsing; debug_query_string still lets us report the offending 7521a30Row pattern recognition patch (planner).
1057 - * location. Every window clause is visited, including ones not used 7521a30Row pattern recognition patch (planner).
1058 - * by any OVER, so the check does not depend on the window surviving 7521a30Row pattern recognition patch (planner).
1059 - * select_active_windows(). 7521a30Row pattern recognition patch (planner).
1060 - */ 7521a30Row pattern recognition patch (planner).
1061 6270 if (wc->rpPattern && wc->defineClause) 7521a30Row pattern recognition patch (planner).
1062 3753 validate_rpr_define_volatility(wc->defineClause); 7521a30Row pattern recognition patch (planner).
1063 - 7521a30Row pattern recognition patch (planner).
1064 - /* partitionClause/orderClause are sort/group expressions */ -
1065 - wc->startOffset = preprocess_expression(root, wc->startOffset, -
1066 - EXPRKIND_LIMIT); -
1067 - wc->endOffset = preprocess_expression(root, wc->endOffset, -
1068 - EXPRKIND_LIMIT); -
1069 6246 wc->defineClause = (List *) preprocess_expression(root, 7521a30Row pattern recognition patch (planner).
1070 6246 (Node *) wc->defineClause, 7521a30Row pattern recognition patch (planner).
1071 - EXPRKIND_TARGET); 7521a30Row pattern recognition patch (planner).
1072 - } -
1073 - -
1074 - parse->limitOffset = preprocess_expression(root, parse->limitOffset, -
1075 - EXPRKIND_LIMIT); -
1076 - parse->limitCount = preprocess_expression(root, parse->limitCount, -
1077 - EXPRKIND_LIMIT); -
1078 - -
1079 - if (parse->onConflict) -
1080 - { -
1081 - parse->onConflict->arbiterElems = (List *) -
1082 - preprocess_expression(root, -
1083 - (Node *) parse->onConflict->arbiterElems, -
1084 - EXPRKIND_ARBITER_ELEM); -
1085 - parse->onConflict->arbiterWhere = -
1086 - preprocess_expression(root, -
1087 - parse->onConflict->arbiterWhere, -
1088 - EXPRKIND_QUAL); -
1089 - parse->onConflict->onConflictSet = (List *) -
1090 - preprocess_expression(root, -
1091 - (Node *) parse->onConflict->onConflictSet, -
1092 - EXPRKIND_TARGET); -
1093 - parse->onConflict->onConflictWhere = -
1094 - preprocess_expression(root, -
1095 - parse->onConflict->onConflictWhere, -
1096 - EXPRKIND_QUAL); -
1097 - /* exclRelTlist contains only Vars, so no preprocessing needed */ -
1098 - } -
1099 - -
1100 - foreach(l, parse->mergeActionList) -
1101 - { -
1102 - MergeAction *action = (MergeAction *) lfirst(l); -
1103 - -
1104 - action->targetList = (List *) -
1105 - preprocess_expression(root, -
1106 - (Node *) action->targetList, -
1107 - EXPRKIND_TARGET); -
1108 - action->qual = -
1109 - preprocess_expression(root, -
1110 - (Node *) action->qual, -
1111 - EXPRKIND_QUAL); -
1112 - } -
1113 - -
1114 - parse->mergeJoinCondition = -
1115 - preprocess_expression(root, parse->mergeJoinCondition, EXPRKIND_QUAL); -
1116 - -
1117 - root->append_rel_list = (List *) -
1118 - preprocess_expression(root, (Node *) root->append_rel_list, -
1119 - EXPRKIND_APPINFO); -
1120 - -
1121 - /* Also need to preprocess expressions within RTEs */ -
1122 - foreach(l, parse->rtable) -
1123 - { -
1124 - RangeTblEntry *rte = lfirst_node(RangeTblEntry, l); -
1125 - int kind; -
1126 - ListCell *lcsq; -
1127 - -
1128 - if (rte->rtekind == RTE_RELATION) -
1129 - { -
1130 - if (rte->tablesample) -
1131 - rte->tablesample = (TableSampleClause *) -
1132 - preprocess_expression(root, -
1133 - (Node *) rte->tablesample, -
1134 - EXPRKIND_TABLESAMPLE); -
1135 - } -
1136 - else if (rte->rtekind == RTE_SUBQUERY) -
1137 - { -
1138 - /* -
1139 - * We don't want to do all preprocessing yet on the subquery's -
1140 - * expressions, since that will happen when we plan it. But if it -
1141 - * contains any join aliases of our level, those have to get -
1142 - * expanded now, because planning of the subquery won't do it. -
1143 - * That's only possible if the subquery is LATERAL. -
1144 - */ -
1145 - if (rte->lateral && root->hasJoinRTEs) -
1146 - rte->subquery = (Query *) -
1147 - flatten_join_alias_vars(root, root->parse, -
1148 - (Node *) rte->subquery); -
1149 - } -
1150 - else if (rte->rtekind == RTE_FUNCTION) -
1151 - { -
1152 - /* Preprocess the function expression(s) fully */ -
1153 - kind = rte->lateral ? EXPRKIND_RTFUNC_LATERAL : EXPRKIND_RTFUNC; -
1154 - rte->functions = (List *) -
1155 - preprocess_expression(root, (Node *) rte->functions, kind); -
1156 - } -
1157 - else if (rte->rtekind == RTE_TABLEFUNC) -
1158 - { -
1159 - /* Preprocess the function expression(s) fully */ -
1160 - kind = rte->lateral ? EXPRKIND_TABLEFUNC_LATERAL : EXPRKIND_TABLEFUNC; -
1161 - rte->tablefunc = (TableFunc *) -
1162 - preprocess_expression(root, (Node *) rte->tablefunc, kind); -
1163 - } -
1164 - else if (rte->rtekind == RTE_VALUES) -
1165 - { -
1166 - /* Preprocess the values lists fully */ -
1167 - kind = rte->lateral ? EXPRKIND_VALUES_LATERAL : EXPRKIND_VALUES; -
1168 - rte->values_lists = (List *) -
1169 - preprocess_expression(root, (Node *) rte->values_lists, kind); -
1170 - } -
1171 - else if (rte->rtekind == RTE_GROUP) -
1172 - { -
1173 - /* Preprocess the groupexprs list fully */ -
1174 - rte->groupexprs = (List *) -
1175 - preprocess_expression(root, (Node *) rte->groupexprs, -
1176 - EXPRKIND_GROUPEXPR); -
1177 - } -
1178 - -
1179 - /* -
1180 - * Process each element of the securityQuals list as if it were a -
1181 - * separate qual expression (as indeed it is). We need to do it this -
1182 - * way to get proper canonicalization of AND/OR structure. Note that -
1183 - * this converts each element into an implicit-AND sublist. -
1184 - */ -
1185 - foreach(lcsq, rte->securityQuals) -
1186 - { -
1187 - lfirst(lcsq) = preprocess_expression(root, -
1188 - (Node *) lfirst(lcsq), -
1189 - EXPRKIND_QUAL); -
1190 - } -
1191 - } -
1192 - -
1193 - /* -
1194 - * Now that we are done preprocessing expressions, and in particular done -
1195 - * flattening join alias variables, get rid of the joinaliasvars lists. -
1196 - * They no longer match what expressions in the rest of the tree look -
1197 - * like, because we have not preprocessed expressions in those lists (and -
1198 - * do not want to; for example, expanding a SubLink there would result in -
1199 - * a useless unreferenced subplan). Leaving them in place simply creates -
1200 - * a hazard for later scans of the tree. We could try to prevent that by -
1201 - * using QTW_IGNORE_JOINALIASES in every tree scan done after this point, -
1202 - * but that doesn't sound very reliable. -
1203 - */ -
1204 - if (root->hasJoinRTEs) -
1205 - { -
1206 - foreach(l, parse->rtable) -
1207 - { -
1208 - RangeTblEntry *rte = lfirst_node(RangeTblEntry, l); -
1209 - -
1210 - rte->joinaliasvars = NIL; -
1211 - } -
1212 - } -
1213 - -
1214 - /* -
1215 - * Before we flatten GROUP Vars, check which HAVING clauses have collation -
1216 - * conflicts. When GROUP BY uses a nondeterministic collation, values -
1217 - * that are "equal" for grouping may be distinguishable under a different -
1218 - * collation. If such a HAVING clause were moved to WHERE, it would -
1219 - * filter individual rows before grouping, potentially eliminating some -
1220 - * members of a group and thereby changing aggregate results. -
1221 - * -
1222 - * We do this check before flatten_group_exprs because we can easily -
1223 - * identify grouping expressions by checking whether a Var references -
1224 - * RTE_GROUP, and such Vars directly carry the GROUP BY collation as their -
1225 - * varcollid. After flattening, these Vars are replaced by the underlying -
1226 - * expressions, and we would have to match expressions in the HAVING -
1227 - * clause back to grouping expressions, which is much more complex. -
1228 - */ -
1229 - if (parse->hasGroupRTE) -
1230 - havingCollationConflicts = -
1231 - find_having_collation_conflicts(parse, root->group_rtindex); -
1232 - else -
1233 - havingCollationConflicts = NULL; -
1234 - -
1235 - /* -
1236 - * Replace any Vars in the subquery's targetlist and havingQual that -
1237 - * reference GROUP outputs with the underlying grouping expressions. -
1238 - * -
1239 - * Note that we need to perform this replacement after we've preprocessed -
1240 - * the grouping expressions. This is to ensure that there is only one -
1241 - * instance of SubPlan for each SubLink contained within the grouping -
1242 - * expressions. -
1243 - */ -
1244 - if (parse->hasGroupRTE) -
1245 - { -
1246 - parse->targetList = (List *) -
1247 - flatten_group_exprs(root, root->parse, (Node *) parse->targetList); -
1248 - parse->havingQual = -
1249 - flatten_group_exprs(root, root->parse, parse->havingQual); -
1250 - } -
1251 - -
1252 - /* Constant-folding might have removed all set-returning functions */ -
1253 - if (parse->hasTargetSRFs) -
1254 - parse->hasTargetSRFs = expression_returns_set((Node *) parse->targetList); -
1255 - -
1256 - /* -
1257 - * If we have grouping sets, expand the groupingSets tree of this query to -
1258 - * a flat list of grouping sets. We need to do this before optimizing -
1259 - * HAVING, since we can't easily tell if there's an empty grouping set -
1260 - * until we have this representation. -
1261 - */ -
1262 - if (parse->groupingSets) -
1263 - { -
1264 - parse->groupingSets = -
1265 - expand_grouping_sets(parse->groupingSets, parse->groupDistinct, -1); -
1266 - } -
1267 - -
1268 - /* -
1269 - * In some cases we may want to transfer a HAVING clause into WHERE. We -
1270 - * cannot do so if the HAVING clause contains aggregates (obviously) or -
1271 - * volatile functions (since a HAVING clause is supposed to be executed -
1272 - * only once per group). We also can't do this if there are any grouping -
1273 - * sets and the clause references any columns that are nullable by the -
1274 - * grouping sets; the nulled values of those columns are not available -
1275 - * before the grouping step. (The test on groupClause might seem wrong, -
1276 - * but it's okay: it's just an optimization to avoid running pull_varnos -
1277 - * when there cannot be any Vars in the HAVING clause.) -
1278 - * -
1279 - * We also cannot do this if the HAVING clause uses a different collation -
1280 - * than the GROUP BY for any grouping expression whose GROUP BY collation -
1281 - * is nondeterministic. This is detected before flatten_group_exprs (see -
1282 - * find_having_collation_conflicts above) and recorded in the -
1283 - * havingCollationConflicts bitmapset. The bitmapset indexes remain valid -
1284 - * here because flatten_group_exprs uses expression_tree_mutator, which -
1285 - * preserves the list length and ordering of havingQual. -
1286 - * -
1287 - * Also, it may be that the clause is so expensive to execute that we're -
1288 - * better off doing it only once per group, despite the loss of -
1289 - * selectivity. This is hard to estimate short of doing the entire -
1290 - * planning process twice, so we use a heuristic: clauses containing -
1291 - * subplans are left in HAVING. Otherwise, we move or copy the HAVING -
1292 - * clause into WHERE, in hopes of eliminating tuples before aggregation -
1293 - * instead of after. -
1294 - * -
1295 - * If the query has no empty grouping set then we can simply move such a -
1296 - * clause into WHERE; any group that fails the clause will not be in the -
1297 - * output because none of its tuples will reach the grouping or -
1298 - * aggregation stage. Otherwise we have to keep the clause in HAVING to -
1299 - * ensure that we don't emit a bogus aggregated row. But then the HAVING -
1300 - * clause must be degenerate (variable-free), so we can copy it into WHERE -
1301 - * so that query_planner() can use it in a gating Result node. (This could -
1302 - * be done better, but it seems not worth optimizing.) -
1303 - * -
1304 - * Note that a HAVING clause may contain expressions that are not fully -
1305 - * preprocessed. This can happen if these expressions are part of -
1306 - * grouping items. In such cases, they are replaced with GROUP Vars in -
1307 - * the parser and then replaced back after we're done with expression -
1308 - * preprocessing on havingQual. This is not an issue if the clause -
1309 - * remains in HAVING, because these expressions will be matched to lower -
1310 - * target items in setrefs.c. However, if the clause is moved or copied -
1311 - * into WHERE, we need to ensure that these expressions are fully -
1312 - * preprocessed. -
1313 - * -
1314 - * Note that both havingQual and parse->jointree->quals are in -
1315 - * implicitly-ANDed-list form at this point, even though they are declared -
1316 - * as Node *. -
1317 - */ -
1318 - newHaving = NIL; -
1319 - havingIdx = 0; -
1320 - foreach(l, (List *) parse->havingQual) -
1321 - { -
1322 - Node *havingclause = (Node *) lfirst(l); -
1323 - -
1324 - if (contain_agg_clause(havingclause) || -
1325 - contain_volatile_functions(havingclause) || -
1326 - contain_subplans(havingclause) || -
1327 - bms_is_member(havingIdx, havingCollationConflicts) || -
1328 - (parse->groupClause && parse->groupingSets && -
1329 - bms_is_member(root->group_rtindex, pull_varnos(root, havingclause)))) -
1330 - { -
1331 - /* keep it in HAVING */ -
1332 - newHaving = lappend(newHaving, havingclause); -
1333 - } -
1334 - else if (parse->groupClause && -
1335 - (parse->groupingSets == NIL || -
1336 - (List *) linitial(parse->groupingSets) != NIL)) -
1337 - { -
1338 - /* There is GROUP BY, but no empty grouping set */ -
1339 - Node *whereclause; -
1340 - -
1341 - /* Preprocess the HAVING clause fully */ -
1342 - whereclause = preprocess_expression(root, havingclause, -
1343 - EXPRKIND_QUAL); -
1344 - /* ... and move it to WHERE */ -
1345 - parse->jointree->quals = (Node *) -
1346 - list_concat((List *) parse->jointree->quals, -
1347 - (List *) whereclause); -
1348 - } -
1349 - else -
1350 - { -
1351 - /* There is an empty grouping set (perhaps implicitly) */ -
1352 - Node *whereclause; -
1353 - -
1354 - /* Preprocess the HAVING clause fully */ -
1355 - whereclause = preprocess_expression(root, copyObject(havingclause), -
1356 - EXPRKIND_QUAL); -
1357 - /* ... and put a copy in WHERE */ -
1358 - parse->jointree->quals = (Node *) -
1359 - list_concat((List *) parse->jointree->quals, -
1360 - (List *) whereclause); -
1361 - /* ... and also keep it in HAVING */ -
1362 - newHaving = lappend(newHaving, havingclause); -
1363 - } -
1364 - -
1365 - havingIdx++; -
1366 - } -
1367 - parse->havingQual = (Node *) newHaving; -
1368 - -
1369 - /* -
1370 - * If we have any outer joins, try to reduce them to plain inner joins. -
1371 - * This step is most easily done after we've done expression -
1372 - * preprocessing. -
1373 - */ -
1374 - if (hasOuterJoins) -
1375 - reduce_outer_joins(root); -
1376 - -
1377 - /* -
1378 - * If we have any RTE_RESULT relations, see if they can be deleted from -
1379 - * the jointree. We also rely on this processing to flatten single-child -
1380 - * FromExprs underneath outer joins. This step is most effectively done -
1381 - * after we've done expression preprocessing and outer join reduction. -
1382 - */ -
1383 - if (hasResultRTEs || hasOuterJoins) -
1384 - remove_useless_result_rtes(root); -
1385 - -
1386 - /* -
1387 - * Do the main planning. -
1388 - */ -
1389 - grouping_planner(root, tuple_fraction, setops); -
1390 - -
1391 - /* -
1392 - * Capture the set of outer-level param IDs we have access to, for use in -
1393 - * extParam/allParam calculations later. -
1394 - */ -
1395 - SS_identify_outer_params(root); -
1396 - -
1397 - /* -
1398 - * If any initPlans were created in this query level, adjust the surviving -
1399 - * Paths' costs and parallel-safety flags to account for them. The -
1400 - * initPlans won't actually get attached to the plan tree till -
1401 - * create_plan() runs, but we must include their effects now. -
1402 - */ -
1403 - final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL); -
1404 - SS_charge_for_initplans(root, final_rel); -
1405 - -
1406 - /* -
1407 - * Make sure we've identified the cheapest Path for the final rel. (By -
1408 - * doing this here not in grouping_planner, we include initPlan costs in -
1409 - * the decision, though it's unlikely that will change anything.) -
1410 - */ -
1411 - set_cheapest(final_rel); -
1412 - -
1413 - return root; -
1414 - } -
optimize_window_clauses() lines 6168-6315
Modified Lines Coverage: 7/7 lines (100.0%)
LineHitsSourceCommit
6168 - optimize_window_clauses(PlannerInfo *root, WindowFuncLists *wflists) -
6169 - { -
6170 - List *windowClause = root->parse->windowClause; -
6171 - ListCell *lc; -
6172 - -
6173 - foreach(lc, windowClause) -
6174 - { -
6175 - WindowClause *wc = lfirst_node(WindowClause, lc); -
6176 - ListCell *lc2; -
6177 - int optimizedFrameOptions = 0; -
6178 - -
6179 - Assert(wc->winref <= wflists->maxWinRef); -
6180 - -
6181 - /* skip any WindowClauses that have no WindowFuncs */ -
6182 - if (wflists->windowFuncs[wc->winref] == NIL) -
6183 - continue; -
6184 - -
6185 - /* 7521a30Row pattern recognition patch (planner).
6186 - * If a DEFINE clause exists, do not let support functions replace the 7521a30Row pattern recognition patch (planner).
6187 - * frame with a non-RPR-compatible one. RPR windows require ROWS 7521a30Row pattern recognition patch (planner).
6188 - * BETWEEN CURRENT ROW AND ... 7521a30Row pattern recognition patch (planner).
6189 - */ 7521a30Row pattern recognition patch (planner).
6190 6216 if (wc->defineClause != NIL) 7521a30Row pattern recognition patch (planner).
6191 3729 continue; 7521a30Row pattern recognition patch (planner).
6192 - 7521a30Row pattern recognition patch (planner).
6193 - foreach(lc2, wflists->windowFuncs[wc->winref]) -
6194 - { -
6195 - SupportRequestOptimizeWindowClause req; -
6196 - SupportRequestOptimizeWindowClause *res; -
6197 - WindowFunc *wfunc = lfirst_node(WindowFunc, lc2); -
6198 - Oid prosupport; -
6199 - -
6200 - prosupport = get_func_support(wfunc->winfnoid); -
6201 - -
6202 - /* Check if there's a support function for 'wfunc' */ -
6203 - if (!OidIsValid(prosupport)) -
6204 - break; /* can't optimize this WindowClause */ -
6205 - -
6206 - req.type = T_SupportRequestOptimizeWindowClause; -
6207 - req.window_clause = wc; -
6208 - req.window_func = wfunc; -
6209 - req.frameOptions = wc->frameOptions; -
6210 - -
6211 - /* call the support function */ -
6212 - res = (SupportRequestOptimizeWindowClause *) -
6213 - DatumGetPointer(OidFunctionCall1(prosupport, -
6214 - PointerGetDatum(&req))); -
6215 - -
6216 - /* -
6217 - * Skip to next WindowClause if the support function does not -
6218 - * support this request type. -
6219 - */ -
6220 - if (res == NULL) -
6221 - break; -
6222 - -
6223 - /* -
6224 - * Save these frameOptions for the first WindowFunc for this -
6225 - * WindowClause. -
6226 - */ -
6227 - if (foreach_current_index(lc2) == 0) -
6228 - optimizedFrameOptions = res->frameOptions; -
6229 - -
6230 - /* -
6231 - * On subsequent WindowFuncs, if the frameOptions are not the same -
6232 - * then we're unable to optimize the frameOptions for this -
6233 - * WindowClause. -
6234 - */ -
6235 - else if (optimizedFrameOptions != res->frameOptions) -
6236 - break; /* skip to the next WindowClause, if any */ -
6237 - } -
6238 - -
6239 - /* adjust the frameOptions if all WindowFunc's agree that it's ok */ -
6240 - if (lc2 == NULL && wc->frameOptions != optimizedFrameOptions) -
6241 - { -
6242 - ListCell *lc3; -
6243 - -
6244 - /* apply the new frame options */ -
6245 - wc->frameOptions = optimizedFrameOptions; -
6246 - -
6247 - /* -
6248 - * We now check to see if changing the frameOptions has caused -
6249 - * this WindowClause to be a duplicate of some other WindowClause. -
6250 - * This can only happen if we have multiple WindowClauses, so -
6251 - * don't bother if there's only 1. -
6252 - */ -
6253 - if (list_length(windowClause) == 1) -
6254 - continue; -
6255 - -
6256 - /* -
6257 - * Do the duplicate check and reuse the existing WindowClause if -
6258 - * we find a duplicate. -
6259 - */ -
6260 - foreach(lc3, windowClause) -
6261 - { -
6262 - WindowClause *existing_wc = lfirst_node(WindowClause, lc3); -
6263 - -
6264 - /* skip over the WindowClause we're currently editing */ -
6265 - if (existing_wc == wc) -
6266 - continue; -
6267 - -
6268 - /* -
6269 - * Perform the same duplicate check that is done in -
6270 - * transformWindowFuncCall. wc is never an RPR clause here 7521a30Row pattern recognition patch (planner).
6271 - * (those are skipped above), and an RPR existing_wc differs 7521a30Row pattern recognition patch (planner).
6272 - * in its frame options anyway, so the RPR-related comparisons 7521a30Row pattern recognition patch (planner).
6273 - * are a defensive backstop for parity. 7521a30Row pattern recognition patch (planner).
6274 - */ -
6275 - if (equal(wc->partitionClause, existing_wc->partitionClause) && -
6276 - equal(wc->orderClause, existing_wc->orderClause) && -
6277 - wc->frameOptions == existing_wc->frameOptions && -
6278 - equal(wc->startOffset, existing_wc->startOffset) && -
6279 30 equal(wc->endOffset, existing_wc->endOffset) && 7521a30Row pattern recognition patch (planner).
6280 30 wc->rpSkipTo == existing_wc->rpSkipTo && 7521a30Row pattern recognition patch (planner).
6281 30 wc->initial == existing_wc->initial && 7521a30Row pattern recognition patch (planner).
6282 60 equal(wc->defineClause, existing_wc->defineClause) && 7521a30Row pattern recognition patch (planner).
6283 30 equal(wc->rpPattern, existing_wc->rpPattern)) 7521a30Row pattern recognition patch (planner).
6284 - { -
6285 - ListCell *lc4; -
6286 - -
6287 - /* -
6288 - * Now move each WindowFunc in 'wc' into 'existing_wc'. -
6289 - * This required adjusting each WindowFunc's winref and -
6290 - * moving the WindowFuncs in 'wc' to the list of -
6291 - * WindowFuncs in 'existing_wc'. -
6292 - */ -
6293 - foreach(lc4, wflists->windowFuncs[wc->winref]) -
6294 - { -
6295 - WindowFunc *wfunc = lfirst_node(WindowFunc, lc4); -
6296 - -
6297 - wfunc->winref = existing_wc->winref; -
6298 - } -
6299 - -
6300 - /* move list items */ -
6301 - wflists->windowFuncs[existing_wc->winref] = list_concat(wflists->windowFuncs[existing_wc->winref], -
6302 - wflists->windowFuncs[wc->winref]); -
6303 - wflists->windowFuncs[wc->winref] = NIL; -
6304 - -
6305 - /* -
6306 - * transformWindowFuncCall() should have made sure there -
6307 - * are no other duplicates, so we needn't bother looking -
6308 - * any further. -
6309 - */ -
6310 - break; -
6311 - } -
6312 - } -
6313 - } -
6314 - } -
6315 - } -