@@ -96,7 +96,12 @@ static WindowClause *findWindowClause(List *wclist, const char *name);
96
96
static Node * transformFrameOffset (ParseState * pstate , int frameOptions ,
97
97
Oid rangeopfamily , Oid rangeopcintype , Oid * inRangeFunc ,
98
98
Node * clause );
99
-
99
+ static void transformRPR (ParseState * pstate , WindowClause * wc , WindowDef * windef ,
100
+ List * * targetlist );
101
+ static List * transformDefineClause (ParseState * pstate , WindowClause * wc , WindowDef * windef ,
102
+ List * * targetlist );
103
+ static void transformPatternClause (ParseState * pstate , WindowClause * wc ,
104
+ WindowDef * windef );
100
105
101
106
/*
102
107
* transformFromClause -
@@ -2956,6 +2961,10 @@ transformWindowDefinitions(ParseState *pstate,
2956
2961
rangeopfamily , rangeopcintype ,
2957
2962
& wc -> endInRangeFunc ,
2958
2963
windef -> endOffset );
2964
+
2965
+ /* Process Row Pattern Recognition related clauses */
2966
+ transformRPR (pstate , wc , windef , targetlist );
2967
+
2959
2968
wc -> winref = winref ;
2960
2969
2961
2970
result = lappend (result , wc );
@@ -3823,3 +3832,262 @@ transformFrameOffset(ParseState *pstate, int frameOptions,
3823
3832
3824
3833
return node ;
3825
3834
}
3835
+
3836
+ /*
3837
+ * transformRPR
3838
+ * Process Row Pattern Recognition related clauses
3839
+ */
3840
+ static void
3841
+ transformRPR (ParseState * pstate , WindowClause * wc , WindowDef * windef ,
3842
+ List * * targetlist )
3843
+ {
3844
+ /*
3845
+ * Window definition exists?
3846
+ */
3847
+ if (windef == NULL )
3848
+ return ;
3849
+
3850
+ /*
3851
+ * Row Pattern Common Syntax clause exists?
3852
+ */
3853
+ if (windef -> rpCommonSyntax == NULL )
3854
+ return ;
3855
+
3856
+ /* Check Frame option. Frame must start at current row */
3857
+ if ((wc -> frameOptions & FRAMEOPTION_START_CURRENT_ROW ) == 0 )
3858
+ ereport (ERROR ,
3859
+ (errcode (ERRCODE_SYNTAX_ERROR ),
3860
+ errmsg ("FRAME must start at current row when row patttern recognition is used" )));
3861
+
3862
+ /* Transform AFTER MACH SKIP TO clause */
3863
+ wc -> rpSkipTo = windef -> rpCommonSyntax -> rpSkipTo ;
3864
+
3865
+ /* Transform SEEK or INITIAL clause */
3866
+ wc -> initial = windef -> rpCommonSyntax -> initial ;
3867
+
3868
+ /* Transform DEFINE clause into list of TargetEntry's */
3869
+ wc -> defineClause = transformDefineClause (pstate , wc , windef , targetlist );
3870
+
3871
+ /* Check PATTERN clause and copy to patternClause */
3872
+ transformPatternClause (pstate , wc , windef );
3873
+ }
3874
+
3875
+ /*
3876
+ * transformDefineClause
3877
+ * Process DEFINE clause and transform ResTarget into list of
3878
+ * TargetEntry.
3879
+ *
3880
+ * XXX we only support column reference in row pattern definition search
3881
+ * condition, e.g. "price". <row pattern definition variable name>.<column
3882
+ * reference> is not supported, e.g. "A.price".
3883
+ */
3884
+ static List *
3885
+ transformDefineClause (ParseState * pstate , WindowClause * wc , WindowDef * windef ,
3886
+ List * * targetlist )
3887
+ {
3888
+ /* DEFINE variable name initials */
3889
+ static char * defineVariableInitials = "abcdefghijklmnopqrstuvwxyz" ;
3890
+
3891
+ ListCell * lc ,
3892
+ * l ;
3893
+ ResTarget * restarget ,
3894
+ * r ;
3895
+ List * restargets ;
3896
+ List * defineClause ;
3897
+ char * name ;
3898
+ int initialLen ;
3899
+ int i ;
3900
+
3901
+ /*
3902
+ * If Row Definition Common Syntax exists, DEFINE clause must exist. (the
3903
+ * raw parser should have already checked it.)
3904
+ */
3905
+ Assert (windef -> rpCommonSyntax -> rpDefs != NULL );
3906
+
3907
+ /*
3908
+ * Check and add "A AS A IS TRUE" if pattern variable is missing in DEFINE
3909
+ * per the SQL standard.
3910
+ */
3911
+ restargets = NIL ;
3912
+ foreach (lc , windef -> rpCommonSyntax -> rpPatterns )
3913
+ {
3914
+ A_Expr * a ;
3915
+ bool found = false;
3916
+
3917
+ if (!IsA (lfirst (lc ), A_Expr ))
3918
+ ereport (ERROR ,
3919
+ errmsg ("node type is not A_Expr" ));
3920
+
3921
+ a = (A_Expr * ) lfirst (lc );
3922
+ name = strVal (a -> lexpr );
3923
+
3924
+ foreach (l , windef -> rpCommonSyntax -> rpDefs )
3925
+ {
3926
+ restarget = (ResTarget * ) lfirst (l );
3927
+
3928
+ if (!strcmp (restarget -> name , name ))
3929
+ {
3930
+ found = true;
3931
+ break ;
3932
+ }
3933
+ }
3934
+
3935
+ if (!found )
3936
+ {
3937
+ /*
3938
+ * "name" is missing. So create "name AS name IS TRUE" ResTarget
3939
+ * node and add it to the temporary list.
3940
+ */
3941
+ A_Const * n ;
3942
+
3943
+ restarget = makeNode (ResTarget );
3944
+ n = makeNode (A_Const );
3945
+ n -> val .boolval .type = T_Boolean ;
3946
+ n -> val .boolval .boolval = true;
3947
+ n -> location = -1 ;
3948
+ restarget -> name = pstrdup (name );
3949
+ restarget -> indirection = NIL ;
3950
+ restarget -> val = (Node * ) n ;
3951
+ restarget -> location = -1 ;
3952
+ restargets = lappend ((List * ) restargets , restarget );
3953
+ }
3954
+ }
3955
+
3956
+ if (list_length (restargets ) >= 1 )
3957
+ {
3958
+ /* add missing DEFINEs */
3959
+ windef -> rpCommonSyntax -> rpDefs =
3960
+ list_concat (windef -> rpCommonSyntax -> rpDefs , restargets );
3961
+ list_free (restargets );
3962
+ }
3963
+
3964
+ /*
3965
+ * Check for duplicate row pattern definition variables. The standard
3966
+ * requires that no two row pattern definition variable names shall be
3967
+ * equivalent.
3968
+ */
3969
+ restargets = NIL ;
3970
+ foreach (lc , windef -> rpCommonSyntax -> rpDefs )
3971
+ {
3972
+ restarget = (ResTarget * ) lfirst (lc );
3973
+ name = restarget -> name ;
3974
+
3975
+ /*
3976
+ * Add DEFINE expression (Restarget->val) to the targetlist as a
3977
+ * TargetEntry if it does not exist yet. Planner will add the column
3978
+ * ref var node to the outer plan's target list later on. This makes
3979
+ * DEFINE expression could access the outer tuple while evaluating
3980
+ * PATTERN.
3981
+ *
3982
+ * XXX: adding whole expressions of DEFINE to the plan.targetlist is
3983
+ * not so good, because it's not necessary to evalute the expression
3984
+ * in the target list while running the plan. We should extract the
3985
+ * var nodes only then add them to the plan.targetlist.
3986
+ */
3987
+ findTargetlistEntrySQL99 (pstate , (Node * ) restarget -> val ,
3988
+ targetlist , EXPR_KIND_RPR_DEFINE );
3989
+
3990
+ /*
3991
+ * Make sure that the row pattern definition search condition is a
3992
+ * boolean expression.
3993
+ */
3994
+ transformWhereClause (pstate , restarget -> val ,
3995
+ EXPR_KIND_RPR_DEFINE , "DEFINE" );
3996
+
3997
+ foreach (l , restargets )
3998
+ {
3999
+ char * n ;
4000
+
4001
+ r = (ResTarget * ) lfirst (l );
4002
+ n = r -> name ;
4003
+
4004
+ if (!strcmp (n , name ))
4005
+ ereport (ERROR ,
4006
+ (errcode (ERRCODE_SYNTAX_ERROR ),
4007
+ errmsg ("row pattern definition variable name \"%s\" appears more than once in DEFINE clause" ,
4008
+ name ),
4009
+ parser_errposition (pstate , exprLocation ((Node * ) r ))));
4010
+ }
4011
+ restargets = lappend (restargets , restarget );
4012
+ }
4013
+ list_free (restargets );
4014
+
4015
+ /*
4016
+ * Create list of row pattern DEFINE variable name's initial. We assign
4017
+ * [a-z] to them (up to 26 variable names are allowed).
4018
+ */
4019
+ restargets = NIL ;
4020
+ i = 0 ;
4021
+ initialLen = strlen (defineVariableInitials );
4022
+
4023
+ foreach (lc , windef -> rpCommonSyntax -> rpDefs )
4024
+ {
4025
+ char initial [2 ];
4026
+
4027
+ restarget = (ResTarget * ) lfirst (lc );
4028
+ name = restarget -> name ;
4029
+
4030
+ if (i >= initialLen )
4031
+ {
4032
+ ereport (ERROR ,
4033
+ (errcode (ERRCODE_SYNTAX_ERROR ),
4034
+ errmsg ("number of row pattern definition variable names exceeds %d" ,
4035
+ initialLen ),
4036
+ parser_errposition (pstate ,
4037
+ exprLocation ((Node * ) restarget ))));
4038
+ }
4039
+ initial [0 ] = defineVariableInitials [i ++ ];
4040
+ initial [1 ] = '\0' ;
4041
+ wc -> defineInitial = lappend (wc -> defineInitial ,
4042
+ makeString (pstrdup (initial )));
4043
+ }
4044
+
4045
+ defineClause = transformTargetList (pstate , windef -> rpCommonSyntax -> rpDefs ,
4046
+ EXPR_KIND_RPR_DEFINE );
4047
+
4048
+ /* mark column origins */
4049
+ markTargetListOrigins (pstate , defineClause );
4050
+
4051
+ /* mark all nodes in the DEFINE clause tree with collation information */
4052
+ assign_expr_collations (pstate , (Node * ) defineClause );
4053
+
4054
+ return defineClause ;
4055
+ }
4056
+
4057
+ /*
4058
+ * transformPatternClause
4059
+ * Process PATTERN clause and return PATTERN clause in the raw parse tree
4060
+ */
4061
+ static void
4062
+ transformPatternClause (ParseState * pstate , WindowClause * wc ,
4063
+ WindowDef * windef )
4064
+ {
4065
+ ListCell * lc ;
4066
+
4067
+ /*
4068
+ * Row Pattern Common Syntax clause exists?
4069
+ */
4070
+ if (windef -> rpCommonSyntax == NULL )
4071
+ return ;
4072
+
4073
+ wc -> patternVariable = NIL ;
4074
+ wc -> patternRegexp = NIL ;
4075
+ foreach (lc , windef -> rpCommonSyntax -> rpPatterns )
4076
+ {
4077
+ A_Expr * a ;
4078
+ char * name ;
4079
+ char * regexp ;
4080
+
4081
+ if (!IsA (lfirst (lc ), A_Expr ))
4082
+ ereport (ERROR ,
4083
+ errmsg ("node type is not A_Expr" ));
4084
+
4085
+ a = (A_Expr * ) lfirst (lc );
4086
+ name = strVal (a -> lexpr );
4087
+
4088
+ wc -> patternVariable = lappend (wc -> patternVariable , makeString (pstrdup (name )));
4089
+ regexp = strVal (lfirst (list_head (a -> name )));
4090
+
4091
+ wc -> patternRegexp = lappend (wc -> patternRegexp , makeString (pstrdup (regexp )));
4092
+ }
4093
+ }
0 commit comments