src/backend/parser/parse_clause.c - Coverage Report

← Back to Overview

# src/backend/parser/parse_clause.c

Coverage: 2/2 lines (100.0%)
Total Lines
2
modified
Covered
2
100.0%
Uncovered
0
0.0%
Keyboard navigation
transformWindowDefinitions() lines 2972-3179
Modified Lines Coverage: 2/2 lines (100.0%)

Line | Hits | Source | Commit
--- | --- | --- | ---
2972 | - | transformWindowDefinitions(ParseState *pstate, | -
2973 | - | List *windowdefs, | -
2974 | - | List **targetlist) | -
2975 | - | { | -
2976 | - | List *result = NIL; | -
2977 | - | Index winref = 0; | -
2978 | - | ListCell *lc; | -
2979 | - |  | -
2980 | - | foreach(lc, windowdefs) | -
2981 | - | { | -
2982 | - | WindowDef *windef = (WindowDef *) lfirst(lc); | -
2983 | - | WindowClause *refwc = NULL; | -
2984 | - | List *partitionClause; | -
2985 | - | List *orderClause; | -
2986 | - | Oid rangeopfamily = InvalidOid; | -
2987 | - | Oid rangeopcintype = InvalidOid; | -
2988 | - | WindowClause *wc; | -
2989 | - |  | -
2990 | - | winref++; | -
2991 | - |  | -
2992 | - | /* | -
2993 | - | * Check for duplicate window names. | -
2994 | - | */ | -
2995 | - | if (windef->name && | -
2996 | - | findWindowClause(result, windef->name) != NULL) | -
2997 | - | ereport(ERROR, | -
2998 | - | (errcode(ERRCODE_WINDOWING_ERROR), | -
2999 | - | errmsg("window \"%s\" is already defined", windef->name), | -
3000 | - | parser_errposition(pstate, windef->location))); | -
3001 | - |  | -
3002 | - | /* | -
3003 | - | * If it references a previous window, look that up. | -
3004 | - | */ | -
3005 | - | if (windef->refname) | -
3006 | - | { | -
3007 | - | refwc = findWindowClause(result, windef->refname); | -
3008 | - | if (refwc == NULL) | -
3009 | - | ereport(ERROR, | -
3010 | - | (errcode(ERRCODE_UNDEFINED_OBJECT), | -
3011 | - | errmsg("window \"%s\" does not exist", | -
3012 | - | windef->refname), | -
3013 | - | parser_errposition(pstate, windef->location))); | -
3014 | - | } | -
3015 | - |  | -
3016 | - | /* | -
3017 | - | * Transform PARTITION and ORDER specs, if any. These are treated | -
3018 | - | * almost exactly like top-level GROUP BY and ORDER BY clauses, | -
3019 | - | * including the special handling of nondefault operator semantics. | -
3020 | - | */ | -
3021 | - | orderClause = transformSortClause(pstate, | -
3022 | - | windef->orderClause, | -
3023 | - | targetlist, | -
3024 | - | EXPR_KIND_WINDOW_ORDER, | -
3025 | - | true /* force SQL99 rules */ ); | -
3026 | - | partitionClause = transformGroupClause(pstate, | -
3027 | - | windef->partitionClause, | -
3028 | - | false /* not GROUP BY ALL */ , | -
3029 | - | NULL, | -
3030 | - | targetlist, | -
3031 | - | orderClause, | -
3032 | - | EXPR_KIND_WINDOW_PARTITION, | -
3033 | - | true /* force SQL99 rules */ ); | -
3034 | - |  | -
3035 | - | /* | -
3036 | - | * And prepare the new WindowClause. | -
3037 | - | */ | -
3038 | - | wc = makeNode(WindowClause); | -
3039 | 6295 | wc->rpSkipTo = ST_NONE; /* ST_NONE marks this as a non-RPR window; | c54ba27Row pattern recognition patch (parse/analysis).
3040 | - | * overridden by transformRPR() if RPR is used */ | c54ba27Row pattern recognition patch (parse/analysis).
3041 | - | wc->name = windef->name; | -
3042 | - | wc->refname = windef->refname; | -
3043 | - |  | -
3044 | - | /* | -
3045 | - | * Per spec, a windowdef that references a previous one copies the | -
3046 | - | * previous partition clause (and mustn't specify its own). It can | -
3047 | - | * specify its own ordering clause, but only if the previous one had | -
3048 | - | * none. It always specifies its own frame clause, and the previous | -
3049 | - | * one must not have a frame clause. Yeah, it's bizarre that each of | -
3050 | - | * these cases works differently, but SQL:2008 says so; see 7.11 | -
3051 | - | * <window clause> syntax rule 10 and general rule 1. The frame | -
3052 | - | * clause rule is especially bizarre because it makes "OVER foo" | -
3053 | - | * different from "OVER (foo)", and requires the latter to throw an | -
3054 | - | * error if foo has a nondefault frame clause. Well, ours not to | -
3055 | - | * reason why, but we do go out of our way to throw a useful error | -
3056 | - | * message for such cases. | -
3057 | - | */ | -
3058 | - | if (refwc) | -
3059 | - | { | -
3060 | - | if (partitionClause) | -
3061 | - | ereport(ERROR, | -
3062 | - | (errcode(ERRCODE_WINDOWING_ERROR), | -
3063 | - | errmsg("cannot override PARTITION BY clause of window \"%s\"", | -
3064 | - | windef->refname), | -
3065 | - | parser_errposition(pstate, windef->location))); | -
3066 | - | wc->partitionClause = copyObject(refwc->partitionClause); | -
3067 | - | } | -
3068 | - | else | -
3069 | - | wc->partitionClause = partitionClause; | -
3070 | - | if (refwc) | -
3071 | - | { | -
3072 | - | if (orderClause && refwc->orderClause) | -
3073 | - | ereport(ERROR, | -
3074 | - | (errcode(ERRCODE_WINDOWING_ERROR), | -
3075 | - | errmsg("cannot override ORDER BY clause of window \"%s\"", | -
3076 | - | windef->refname), | -
3077 | - | parser_errposition(pstate, windef->location))); | -
3078 | - | if (orderClause) | -
3079 | - | { | -
3080 | - | wc->orderClause = orderClause; | -
3081 | - | wc->copiedOrder = false; | -
3082 | - | } | -
3083 | - | else | -
3084 | - | { | -
3085 | - | wc->orderClause = copyObject(refwc->orderClause); | -
3086 | - | wc->copiedOrder = true; | -
3087 | - | } | -
3088 | - | } | -
3089 | - | else | -
3090 | - | { | -
3091 | - | wc->orderClause = orderClause; | -
3092 | - | wc->copiedOrder = false; | -
3093 | - | } | -
3094 | - | if (refwc && refwc->frameOptions != FRAMEOPTION_DEFAULTS) | -
3095 | - | { | -
3096 | - | /* | -
3097 | - | * Use this message if this is a WINDOW clause, or if it's an OVER | -
3098 | - | * clause that includes ORDER BY or framing clauses. (We already | -
3099 | - | * rejected PARTITION BY above, so no need to check that.) | -
3100 | - | */ | -
3101 | - | if (windef->name || | -
3102 | - | orderClause || windef->frameOptions != FRAMEOPTION_DEFAULTS) | -
3103 | - | ereport(ERROR, | -
3104 | - | (errcode(ERRCODE_WINDOWING_ERROR), | -
3105 | - | errmsg("cannot copy window \"%s\" because it has a frame clause", | -
3106 | - | windef->refname), | -
3107 | - | parser_errposition(pstate, windef->location))); | -
3108 | - | /* Else this clause is just OVER (foo), so say this: */ | -
3109 | - | ereport(ERROR, | -
3110 | - | (errcode(ERRCODE_WINDOWING_ERROR), | -
3111 | - | errmsg("cannot copy window \"%s\" because it has a frame clause", | -
3112 | - | windef->refname), | -
3113 | - | errhint("Omit the parentheses in this OVER clause."), | -
3114 | - | parser_errposition(pstate, windef->location))); | -
3115 | - | } | -
3116 | - | wc->frameOptions = windef->frameOptions; | -
3117 | - |  | -
3118 | - | /* | -
3119 | - | * RANGE offset PRECEDING/FOLLOWING requires exactly one ORDER BY | -
3120 | - | * column; check that and get its sort opfamily info. | -
3121 | - | */ | -
3122 | - | if ((wc->frameOptions & FRAMEOPTION_RANGE) && | -
3123 | - | (wc->frameOptions & (FRAMEOPTION_START_OFFSET | | -
3124 | - | FRAMEOPTION_END_OFFSET))) | -
3125 | - | { | -
3126 | - | SortGroupClause *sortcl; | -
3127 | - | Node *sortkey; | -
3128 | - | CompareType rangecmptype; | -
3129 | - |  | -
3130 | - | if (list_length(wc->orderClause) != 1) | -
3131 | - | ereport(ERROR, | -
3132 | - | (errcode(ERRCODE_WINDOWING_ERROR), | -
3133 | - | errmsg("RANGE with offset PRECEDING/FOLLOWING requires exactly one ORDER BY column"), | -
3134 | - | parser_errposition(pstate, windef->location))); | -
3135 | - | sortcl = linitial_node(SortGroupClause, wc->orderClause); | -
3136 | - | sortkey = get_sortgroupclause_expr(sortcl, *targetlist); | -
3137 | - | /* Find the sort operator in pg_amop */ | -
3138 | - | if (!get_ordering_op_properties(sortcl->sortop, | -
3139 | - | &rangeopfamily, | -
3140 | - | &rangeopcintype, | -
3141 | - | &rangecmptype)) | -
3142 | - | elog(ERROR, "operator %u is not a valid ordering operator", | -
3143 | - | sortcl->sortop); | -
3144 | - | /* Record properties of sort ordering */ | -
3145 | - | wc->inRangeColl = exprCollation(sortkey); | -
3146 | - | wc->inRangeAsc = !sortcl->reverse_sort; | -
3147 | - | wc->inRangeNullsFirst = sortcl->nulls_first; | -
3148 | - | } | -
3149 | - |  | -
3150 | - | /* Per spec, GROUPS mode requires an ORDER BY clause */ | -
3151 | - | if (wc->frameOptions & FRAMEOPTION_GROUPS) | -
3152 | - | { | -
3153 | - | if (wc->orderClause == NIL) | -
3154 | - | ereport(ERROR, | -
3155 | - | (errcode(ERRCODE_WINDOWING_ERROR), | -
3156 | - | errmsg("GROUPS mode requires an ORDER BY clause"), | -
3157 | - | parser_errposition(pstate, windef->location))); | -
3158 | - | } | -
3159 | - |  | -
3160 | - | /* Process frame offset expressions */ | -
3161 | - | wc->startOffset = transformFrameOffset(pstate, wc->frameOptions, | -
3162 | - | rangeopfamily, rangeopcintype, | -
3163 | - | &wc->startInRangeFunc, | -
3164 | - | windef->startOffset); | -
3165 | - | wc->endOffset = transformFrameOffset(pstate, wc->frameOptions, | -
3166 | - | rangeopfamily, rangeopcintype, | -
3167 | - | &wc->endInRangeFunc, | -
3168 | - | windef->endOffset); | -
3169 | - |  | c54ba27Row pattern recognition patch (parse/analysis).
3170 | - | /* Process Row Pattern Recognition related clauses */ | c54ba27Row pattern recognition patch (parse/analysis).
3171 | 6259 | transformRPR(pstate, wc, windef, targetlist); | c54ba27Row pattern recognition patch (parse/analysis).
3172 | - |  | c54ba27Row pattern recognition patch (parse/analysis).
3173 | - | wc->winref = winref; | -
3174 | - |  | -
3175 | - | result = lappend(result, wc); | -
3176 | - | } | -
3177 | - |  | -
3178 | - | return result; | -
3179 | - | } | -