| Line | Hits | Source | Commit |
| 2825 |
- |
transformWindowDefinitions(ParseState *pstate, |
- |
| 2826 |
- |
List *windowdefs, |
- |
| 2827 |
- |
List **targetlist) |
- |
| 2828 |
- |
{ |
- |
| 2829 |
- |
List *result = NIL; |
- |
| 2830 |
- |
Index winref = 0; |
- |
| 2831 |
- |
ListCell *lc; |
- |
| 2832 |
- |
|
- |
| 2833 |
- |
foreach(lc, windowdefs) |
- |
| 2834 |
- |
{ |
- |
| 2835 |
- |
WindowDef *windef = (WindowDef *) lfirst(lc); |
- |
| 2836 |
- |
WindowClause *refwc = NULL; |
- |
| 2837 |
- |
List *partitionClause; |
- |
| 2838 |
- |
List *orderClause; |
- |
| 2839 |
- |
Oid rangeopfamily = InvalidOid; |
- |
| 2840 |
- |
Oid rangeopcintype = InvalidOid; |
- |
| 2841 |
- |
WindowClause *wc; |
- |
| 2842 |
- |
|
- |
| 2843 |
- |
winref++; |
- |
| 2844 |
- |
|
- |
| 2845 |
- |
/* |
- |
| 2846 |
- |
* Check for duplicate window names. |
- |
| 2847 |
- |
*/ |
- |
| 2848 |
- |
if (windef->name && |
- |
| 2849 |
- |
findWindowClause(result, windef->name) != NULL) |
- |
| 2850 |
- |
ereport(ERROR, |
- |
| 2851 |
- |
(errcode(ERRCODE_WINDOWING_ERROR), |
- |
| 2852 |
- |
errmsg("window \"%s\" is already defined", windef->name), |
- |
| 2853 |
- |
parser_errposition(pstate, windef->location))); |
- |
| 2854 |
- |
|
- |
| 2855 |
- |
/* |
- |
| 2856 |
- |
* If it references a previous window, look that up. |
- |
| 2857 |
- |
*/ |
- |
| 2858 |
- |
if (windef->refname) |
- |
| 2859 |
- |
{ |
- |
| 2860 |
- |
refwc = findWindowClause(result, windef->refname); |
- |
| 2861 |
- |
if (refwc == NULL) |
- |
| 2862 |
- |
ereport(ERROR, |
- |
| 2863 |
- |
(errcode(ERRCODE_UNDEFINED_OBJECT), |
- |
| 2864 |
- |
errmsg("window \"%s\" does not exist", |
- |
| 2865 |
- |
windef->refname), |
- |
| 2866 |
- |
parser_errposition(pstate, windef->location))); |
- |
| 2867 |
- |
} |
- |
| 2868 |
- |
|
- |
| 2869 |
- |
/* |
- |
| 2870 |
- |
* Transform PARTITION and ORDER specs, if any. These are treated |
- |
| 2871 |
- |
* almost exactly like top-level GROUP BY and ORDER BY clauses, |
- |
| 2872 |
- |
* including the special handling of nondefault operator semantics. |
- |
| 2873 |
- |
*/ |
- |
| 2874 |
- |
orderClause = transformSortClause(pstate, |
- |
| 2875 |
- |
windef->orderClause, |
- |
| 2876 |
- |
targetlist, |
- |
| 2877 |
- |
EXPR_KIND_WINDOW_ORDER, |
- |
| 2878 |
- |
true /* force SQL99 rules */ ); |
- |
| 2879 |
- |
partitionClause = transformGroupClause(pstate, |
- |
| 2880 |
- |
windef->partitionClause, |
- |
| 2881 |
- |
false /* not GROUP BY ALL */ , |
- |
| 2882 |
- |
NULL, |
- |
| 2883 |
- |
targetlist, |
- |
| 2884 |
- |
orderClause, |
- |
| 2885 |
- |
EXPR_KIND_WINDOW_PARTITION, |
- |
| 2886 |
- |
true /* force SQL99 rules */ ); |
- |
| 2887 |
- |
|
- |
| 2888 |
- |
/* |
- |
| 2889 |
- |
* And prepare the new WindowClause. |
- |
| 2890 |
- |
*/ |
- |
| 2891 |
- |
wc = makeNode(WindowClause); |
- |
| 2892 |
- |
wc->name = windef->name; |
- |
| 2893 |
- |
wc->refname = windef->refname; |
- |
| 2894 |
- |
|
- |
| 2895 |
- |
/* |
- |
| 2896 |
- |
* Per spec, a windowdef that references a previous one copies the |
- |
| 2897 |
- |
* previous partition clause (and mustn't specify its own). It can |
- |
| 2898 |
- |
* specify its own ordering clause, but only if the previous one had |
- |
| 2899 |
- |
* none. It always specifies its own frame clause, and the previous |
- |
| 2900 |
- |
* one must not have a frame clause. Yeah, it's bizarre that each of |
- |
| 2901 |
- |
* these cases works differently, but SQL:2008 says so; see 7.11 |
- |
| 2902 |
- |
* <window clause> syntax rule 10 and general rule 1. The frame |
- |
| 2903 |
- |
* clause rule is especially bizarre because it makes "OVER foo" |
- |
| 2904 |
- |
* different from "OVER (foo)", and requires the latter to throw an |
- |
| 2905 |
- |
* error if foo has a nondefault frame clause. Well, ours not to |
- |
| 2906 |
- |
* reason why, but we do go out of our way to throw a useful error |
- |
| 2907 |
- |
* message for such cases. |
- |
| 2908 |
- |
*/ |
- |
| 2909 |
- |
if (refwc) |
- |
| 2910 |
- |
{ |
- |
| 2911 |
- |
if (partitionClause) |
- |
| 2912 |
- |
ereport(ERROR, |
- |
| 2913 |
- |
(errcode(ERRCODE_WINDOWING_ERROR), |
- |
| 2914 |
- |
errmsg("cannot override PARTITION BY clause of window \"%s\"", |
- |
| 2915 |
- |
windef->refname), |
- |
| 2916 |
- |
parser_errposition(pstate, windef->location))); |
- |
| 2917 |
- |
wc->partitionClause = copyObject(refwc->partitionClause); |
- |
| 2918 |
- |
} |
- |
| 2919 |
- |
else |
- |
| 2920 |
- |
wc->partitionClause = partitionClause; |
- |
| 2921 |
- |
if (refwc) |
- |
| 2922 |
- |
{ |
- |
| 2923 |
- |
if (orderClause && refwc->orderClause) |
- |
| 2924 |
- |
ereport(ERROR, |
- |
| 2925 |
- |
(errcode(ERRCODE_WINDOWING_ERROR), |
- |
| 2926 |
- |
errmsg("cannot override ORDER BY clause of window \"%s\"", |
- |
| 2927 |
- |
windef->refname), |
- |
| 2928 |
- |
parser_errposition(pstate, windef->location))); |
- |
| 2929 |
- |
if (orderClause) |
- |
| 2930 |
- |
{ |
- |
| 2931 |
- |
wc->orderClause = orderClause; |
- |
| 2932 |
- |
wc->copiedOrder = false; |
- |
| 2933 |
- |
} |
- |
| 2934 |
- |
else |
- |
| 2935 |
- |
{ |
- |
| 2936 |
- |
wc->orderClause = copyObject(refwc->orderClause); |
- |
| 2937 |
- |
wc->copiedOrder = true; |
- |
| 2938 |
- |
} |
- |
| 2939 |
- |
} |
- |
| 2940 |
- |
else |
- |
| 2941 |
- |
{ |
- |
| 2942 |
- |
wc->orderClause = orderClause; |
- |
| 2943 |
- |
wc->copiedOrder = false; |
- |
| 2944 |
- |
} |
- |
| 2945 |
- |
if (refwc && refwc->frameOptions != FRAMEOPTION_DEFAULTS) |
- |
| 2946 |
- |
{ |
- |
| 2947 |
- |
/* |
- |
| 2948 |
- |
* Use this message if this is a WINDOW clause, or if it's an OVER |
- |
| 2949 |
- |
* clause that includes ORDER BY or framing clauses. (We already |
- |
| 2950 |
- |
* rejected PARTITION BY above, so no need to check that.) |
- |
| 2951 |
- |
*/ |
- |
| 2952 |
- |
if (windef->name || |
- |
| 2953 |
- |
orderClause || windef->frameOptions != FRAMEOPTION_DEFAULTS) |
- |
| 2954 |
- |
ereport(ERROR, |
- |
| 2955 |
- |
(errcode(ERRCODE_WINDOWING_ERROR), |
- |
| 2956 |
- |
errmsg("cannot copy window \"%s\" because it has a frame clause", |
- |
| 2957 |
- |
windef->refname), |
- |
| 2958 |
- |
parser_errposition(pstate, windef->location))); |
- |
| 2959 |
- |
/* Else this clause is just OVER (foo), so say this: */ |
- |
| 2960 |
- |
ereport(ERROR, |
- |
| 2961 |
- |
(errcode(ERRCODE_WINDOWING_ERROR), |
- |
| 2962 |
- |
errmsg("cannot copy window \"%s\" because it has a frame clause", |
- |
| 2963 |
- |
windef->refname), |
- |
| 2964 |
- |
errhint("Omit the parentheses in this OVER clause."), |
- |
| 2965 |
- |
parser_errposition(pstate, windef->location))); |
- |
| 2966 |
- |
} |
- |
| 2967 |
- |
wc->frameOptions = windef->frameOptions; |
- |
| 2968 |
- |
|
- |
| 2969 |
- |
/* |
- |
| 2970 |
- |
* RANGE offset PRECEDING/FOLLOWING requires exactly one ORDER BY |
- |
| 2971 |
- |
* column; check that and get its sort opfamily info. |
- |
| 2972 |
- |
*/ |
- |
| 2973 |
- |
if ((wc->frameOptions & FRAMEOPTION_RANGE) && |
- |
| 2974 |
- |
(wc->frameOptions & (FRAMEOPTION_START_OFFSET | |
- |
| 2975 |
- |
FRAMEOPTION_END_OFFSET))) |
- |
| 2976 |
- |
{ |
- |
| 2977 |
- |
SortGroupClause *sortcl; |
- |
| 2978 |
- |
Node *sortkey; |
- |
| 2979 |
- |
CompareType rangecmptype; |
- |
| 2980 |
- |
|
- |
| 2981 |
- |
if (list_length(wc->orderClause) != 1) |
- |
| 2982 |
- |
ereport(ERROR, |
- |
| 2983 |
- |
(errcode(ERRCODE_WINDOWING_ERROR), |
- |
| 2984 |
- |
errmsg("RANGE with offset PRECEDING/FOLLOWING requires exactly one ORDER BY column"), |
- |
| 2985 |
- |
parser_errposition(pstate, windef->location))); |
- |
| 2986 |
- |
sortcl = linitial_node(SortGroupClause, wc->orderClause); |
- |
| 2987 |
- |
sortkey = get_sortgroupclause_expr(sortcl, *targetlist); |
- |
| 2988 |
- |
/* Find the sort operator in pg_amop */ |
- |
| 2989 |
- |
if (!get_ordering_op_properties(sortcl->sortop, |
- |
| 2990 |
- |
&rangeopfamily, |
- |
| 2991 |
- |
&rangeopcintype, |
- |
| 2992 |
- |
&rangecmptype)) |
- |
| 2993 |
- |
elog(ERROR, "operator %u is not a valid ordering operator", |
- |
| 2994 |
- |
sortcl->sortop); |
- |
| 2995 |
- |
/* Record properties of sort ordering */ |
- |
| 2996 |
- |
wc->inRangeColl = exprCollation(sortkey); |
- |
| 2997 |
- |
wc->inRangeAsc = !sortcl->reverse_sort; |
- |
| 2998 |
- |
wc->inRangeNullsFirst = sortcl->nulls_first; |
- |
| 2999 |
- |
} |
- |
| 3000 |
- |
|
- |
| 3001 |
- |
/* Per spec, GROUPS mode requires an ORDER BY clause */ |
- |
| 3002 |
- |
if (wc->frameOptions & FRAMEOPTION_GROUPS) |
- |
| 3003 |
- |
{ |
- |
| 3004 |
- |
if (wc->orderClause == NIL) |
- |
| 3005 |
- |
ereport(ERROR, |
- |
| 3006 |
- |
(errcode(ERRCODE_WINDOWING_ERROR), |
- |
| 3007 |
- |
errmsg("GROUPS mode requires an ORDER BY clause"), |
- |
| 3008 |
- |
parser_errposition(pstate, windef->location))); |
- |
| 3009 |
- |
} |
- |
| 3010 |
- |
|
- |
| 3011 |
- |
/* Process frame offset expressions */ |
- |
| 3012 |
- |
wc->startOffset = transformFrameOffset(pstate, wc->frameOptions, |
- |
| 3013 |
- |
rangeopfamily, rangeopcintype, |
- |
| 3014 |
- |
&wc->startInRangeFunc, |
- |
| 3015 |
- |
windef->startOffset); |
- |
| 3016 |
- |
wc->endOffset = transformFrameOffset(pstate, wc->frameOptions, |
- |
| 3017 |
- |
rangeopfamily, rangeopcintype, |
- |
| 3018 |
- |
&wc->endInRangeFunc, |
- |
| 3019 |
- |
windef->endOffset); |
- |
| 3020 |
- |
|
d23df91Row pattern recognition patch (parse/analysis). |
| 3021 |
- |
/* Process Row Pattern Recognition related clauses */ |
d23df91Row pattern recognition patch (parse/analysis). |
| 3022 |
576 |
transformRPR(pstate, wc, windef, targetlist); |
d23df91Row pattern recognition patch (parse/analysis). |
| 3023 |
- |
|
d23df91Row pattern recognition patch (parse/analysis). |
| 3024 |
- |
wc->winref = winref; |
- |
| 3025 |
- |
|
- |
| 3026 |
- |
result = lappend(result, wc); |
- |
| 3027 |
- |
} |
- |
| 3028 |
- |
|
- |
| 3029 |
- |
return result; |
- |
| 3030 |
- |
} |
- |