Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 123c3cf

Browse files
tatsuo-ishiiCommitfest Bot
authored and
Commitfest Bot
committed
Row pattern recognition patch (parse/analysis).
1 parent 90e5085 commit 123c3cf

File tree

4 files changed

+285
-1
lines changed

4 files changed

+285
-1
lines changed

src/backend/parser/parse_agg.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,10 @@ check_agglevels_and_constraints(ParseState *pstate, Node *expr)
580580
errkind = true;
581581
break;
582582

583+
case EXPR_KIND_RPR_DEFINE:
584+
errkind = true;
585+
break;
586+
583587
/*
584588
* There is intentionally no default: case here, so that the
585589
* compiler will warn if we add a new ParseExprKind without
@@ -970,6 +974,9 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
970974
case EXPR_KIND_CYCLE_MARK:
971975
errkind = true;
972976
break;
977+
case EXPR_KIND_RPR_DEFINE:
978+
errkind = true;
979+
break;
973980

974981
/*
975982
* There is intentionally no default: case here, so that the

src/backend/parser/parse_clause.c

Lines changed: 269 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,12 @@ static WindowClause *findWindowClause(List *wclist, const char *name);
9696
static Node *transformFrameOffset(ParseState *pstate, int frameOptions,
9797
Oid rangeopfamily, Oid rangeopcintype, Oid *inRangeFunc,
9898
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);
100105

101106
/*
102107
* transformFromClause -
@@ -2956,6 +2961,10 @@ transformWindowDefinitions(ParseState *pstate,
29562961
rangeopfamily, rangeopcintype,
29572962
&wc->endInRangeFunc,
29582963
windef->endOffset);
2964+
2965+
/* Process Row Pattern Recognition related clauses */
2966+
transformRPR(pstate, wc, windef, targetlist);
2967+
29592968
wc->winref = winref;
29602969

29612970
result = lappend(result, wc);
@@ -3823,3 +3832,262 @@ transformFrameOffset(ParseState *pstate, int frameOptions,
38233832

38243833
return node;
38253834
}
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+
}

src/backend/parser/parse_expr.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
575575
case EXPR_KIND_COPY_WHERE:
576576
case EXPR_KIND_GENERATED_COLUMN:
577577
case EXPR_KIND_CYCLE_MARK:
578+
case EXPR_KIND_RPR_DEFINE:
578579
/* okay */
579580
break;
580581

@@ -1858,6 +1859,9 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
18581859
case EXPR_KIND_GENERATED_COLUMN:
18591860
err = _("cannot use subquery in column generation expression");
18601861
break;
1862+
case EXPR_KIND_RPR_DEFINE:
1863+
err = _("cannot use subquery in DEFINE expression");
1864+
break;
18611865

18621866
/*
18631867
* There is intentionally no default: case here, so that the
@@ -3215,6 +3219,8 @@ ParseExprKindName(ParseExprKind exprKind)
32153219
return "GENERATED AS";
32163220
case EXPR_KIND_CYCLE_MARK:
32173221
return "CYCLE";
3222+
case EXPR_KIND_RPR_DEFINE:
3223+
return "DEFINE";
32183224

32193225
/*
32203226
* There is intentionally no default: case here, so that the

src/backend/parser/parse_func.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2658,6 +2658,9 @@ check_srf_call_placement(ParseState *pstate, Node *last_srf, int location)
26582658
case EXPR_KIND_CYCLE_MARK:
26592659
errkind = true;
26602660
break;
2661+
case EXPR_KIND_RPR_DEFINE:
2662+
errkind = true;
2663+
break;
26612664

26622665
/*
26632666
* There is intentionally no default: case here, so that the

0 commit comments

Comments
 (0)