src/backend/optimizer/plan/planner.c - Coverage Report

← 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%)

Line | Hits | Source | Commit
--- | --- | --- | ---
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%)

Line | Hits | Source | Commit
--- | --- | --- | ---
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 | - | } | -