public inbox for [email protected]help / color / mirror / Atom feed
[PATCH v3 2/7] Row pattern recognition patch (parse/analysis). 3+ messages / 2 participants [nested] [flat]
* [PATCH v3 2/7] Row pattern recognition patch (parse/analysis). @ 2023-07-26 10:49 Tatsuo Ishii <[email protected]> 0 siblings, 0 replies; 3+ messages in thread From: Tatsuo Ishii @ 2023-07-26 10:49 UTC (permalink / raw) --- src/backend/parser/parse_agg.c | 7 ++ src/backend/parser/parse_clause.c | 190 +++++++++++++++++++++++++++++- src/backend/parser/parse_expr.c | 4 + src/backend/parser/parse_func.c | 3 + 4 files changed, 203 insertions(+), 1 deletion(-) diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index 85cd47b7ae..aa7a1cee80 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -564,6 +564,10 @@ check_agglevels_and_constraints(ParseState *pstate, Node *expr) errkind = true; break; + case EXPR_KIND_RPR_DEFINE: + errkind = true; + break; + /* * There is intentionally no default: case here, so that the * compiler will warn if we add a new ParseExprKind without @@ -953,6 +957,9 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc, case EXPR_KIND_CYCLE_MARK: errkind = true; break; + case EXPR_KIND_RPR_DEFINE: + errkind = true; + break; /* * There is intentionally no default: case here, so that the diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 334b9b42bd..ea2decc579 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -100,7 +100,10 @@ static WindowClause *findWindowClause(List *wclist, const char *name); static Node *transformFrameOffset(ParseState *pstate, int frameOptions, Oid rangeopfamily, Oid rangeopcintype, Oid *inRangeFunc, Node *clause); - +static void transformRPR(ParseState *pstate, WindowClause *wc, WindowDef *windef); +static List *transformDefineClause(ParseState *pstate, WindowClause *wc, WindowDef *windef); +static void transformPatternClause(ParseState *pstate, WindowClause *wc, WindowDef *windef); +static List *transformMeasureClause(ParseState *pstate, WindowClause *wc, WindowDef *windef); /* * transformFromClause - @@ -2950,6 +2953,10 @@ transformWindowDefinitions(ParseState *pstate, rangeopfamily, rangeopcintype, &wc->endInRangeFunc, windef->endOffset); + + /* Process Row Pattern Recognition related clauses */ + transformRPR(pstate, wc, windef); + wc->runCondition = NIL; wc->winref = winref; @@ -3815,3 +3822,184 @@ transformFrameOffset(ParseState *pstate, int frameOptions, return node; } + +/* + * transformRPR + * Process Row Pattern Recognition related clauses + */ +static void +transformRPR(ParseState *pstate, WindowClause *wc, WindowDef *windef) +{ + /* Check Frame option. Frame must start at current row */ + + /* + * Window definition exists? + */ + if (windef == NULL) + return; + + /* + * Row Pattern Common Syntax clause exists? + */ + if (windef->rpCommonSyntax == NULL) + return; + + if ((wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW) == 0) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("FRAME must start at current row when row patttern recognition is used"))); + + /* Transform AFTER MACH SKIP TO clause */ + wc->rpSkipTo = windef->rpCommonSyntax->rpSkipTo; + + /* Transform SEEK or INITIAL clause */ + wc->initial = windef->rpCommonSyntax->initial; + + /* Transform DEFINE clause into list of TargetEntry's */ + wc->defineClause = transformDefineClause(pstate, wc, windef); + + /* Check PATTERN clause and copy to patternClause */ + transformPatternClause(pstate, wc, windef); + + /* Transform MEASURE clause */ + transformMeasureClause(pstate, wc, windef); +} + +/* + * transformDefineClause Process DEFINE clause and transform ResTarget into + * list of TargetEntry. + * + * XXX we only support column reference in row pattern definition search + * condition, e.g. "price". <row pattern definition variable name>.<column + * reference> is not supported, e.g. "A.price". + */ +static List * +transformDefineClause(ParseState *pstate, WindowClause *wc, WindowDef *windef) +{ + ListCell *lc; + ResTarget *restarget, *r; + List *restargets; + + + /* + * If Row Definition Common Syntax exists, DEFINE clause must exist. + * (the raw parser should have already checked it.) + */ + Assert(windef->rpCommonSyntax->rpDefs != NULL); + + /* + * Check for duplicate row pattern definition variables. The standard + * requires that no two row pattern definition variable names shall be + * equivalent. + */ + restargets = NIL; + foreach(lc, windef->rpCommonSyntax->rpDefs) + { + char *name; + ListCell *l; + + restarget = (ResTarget *)lfirst(lc); + name = restarget->name; + + /* + * Make sure that row pattern definition search condition is a boolean + * expression. + */ + transformWhereClause(pstate, restarget->val, + EXPR_KIND_RPR_DEFINE, "DEFINE"); + + foreach(l, restargets) + { + char *n; + + r = (ResTarget *) lfirst(l); + n = r->name; + + if (!strcmp(n, name)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("row pattern definition variable name \"%s\" appears more than once in DEFINE clause", + name), + parser_errposition(pstate, exprLocation((Node *)r)))); + } + restargets = lappend(restargets, restarget); + } + list_free(restargets); + + return transformTargetList(pstate, windef->rpCommonSyntax->rpDefs, + EXPR_KIND_RPR_DEFINE); +} + +/* + * transformPatternClause + * Process PATTERN clause and return PATTERN clause in the raw parse tree + */ +static void +transformPatternClause(ParseState *pstate, WindowClause *wc, WindowDef *windef) +{ + ListCell *lc, *l; + + /* + * Row Pattern Common Syntax clause exists? + */ + if (windef->rpCommonSyntax == NULL) + return; + + /* + * Primary row pattern variable names in PATTERN clause must appear in + * DEFINE clause as row pattern definition variable names. + */ + wc->patternVariable = NIL; + wc->patternRegexp = NIL; + foreach(lc, windef->rpCommonSyntax->rpPatterns) + { + A_Expr *a; + char *name; + char *regexp; + bool found = false; + + if (!IsA(lfirst(lc), A_Expr)) + ereport(ERROR, + errmsg("node type is not A_Expr")); + + a = (A_Expr *)lfirst(lc); + name = strVal(a->lexpr); + + foreach(l, windef->rpCommonSyntax->rpDefs) + { + ResTarget *restarget = (ResTarget *)lfirst(l); + + if (!strcmp(restarget->name, name)) + { + found = true; + break; + } + } + + if (!found) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("primary row pattern variable name \"%s\" does not appear in DEFINE clause", + name), + parser_errposition(pstate, exprLocation((Node *)a)))); + wc->patternVariable = lappend(wc->patternVariable, makeString(pstrdup(name))); + regexp = strVal(lfirst(list_head(a->name))); + wc->patternRegexp = lappend(wc->patternRegexp, makeString(pstrdup(regexp))); + } +} + +/* + * transformMeasureClause + * Process MEASURE clause + */ +static List * +transformMeasureClause(ParseState *pstate, WindowClause *wc, WindowDef *windef) +{ + if (windef->rowPatternMeasures == NIL) + return NIL; + + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("%s","MEASURE clause is not supported yet"), + parser_errposition(pstate, exprLocation((Node *)windef->rowPatternMeasures)))); +} diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index fed8e4d089..8921b7ae01 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -557,6 +557,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) case EXPR_KIND_COPY_WHERE: case EXPR_KIND_GENERATED_COLUMN: case EXPR_KIND_CYCLE_MARK: + case EXPR_KIND_RPR_DEFINE: /* okay */ break; @@ -1770,6 +1771,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink) case EXPR_KIND_VALUES: case EXPR_KIND_VALUES_SINGLE: case EXPR_KIND_CYCLE_MARK: + case EXPR_KIND_RPR_DEFINE: /* okay */ break; case EXPR_KIND_CHECK_CONSTRAINT: @@ -3149,6 +3151,8 @@ ParseExprKindName(ParseExprKind exprKind) return "GENERATED AS"; case EXPR_KIND_CYCLE_MARK: return "CYCLE"; + case EXPR_KIND_RPR_DEFINE: + return "DEFINE"; /* * There is intentionally no default: case here, so that the diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index b3f0b6a137..2ff3699538 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -2656,6 +2656,9 @@ check_srf_call_placement(ParseState *pstate, Node *last_srf, int location) case EXPR_KIND_CYCLE_MARK: errkind = true; break; + case EXPR_KIND_RPR_DEFINE: + errkind = true; + break; /* * There is intentionally no default: case here, so that the -- 2.25.1 ----Next_Part(Wed_Jul_26_21_21_34_2023_317)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="v3-0003-Row-pattern-recognition-patch-planner.patch" ^ permalink raw reply [nested|flat] 3+ messages in thread
* Re: Possibilities on code change to implement pseudodatatypes @ 2024-09-30 09:19 Vinícius Abrahão <[email protected]> 0 siblings, 1 reply; 3+ messages in thread From: Vinícius Abrahão @ 2024-09-30 09:19 UTC (permalink / raw) To: pgsql-hackers On Mon, Sep 30, 2024 at 9:01 AM Vinícius Abrahão <[email protected]> wrote: > Greetings > > I understand the complexity of implementing a pseudo data type when > passing it over parameters, or using it when creating an object. > vide: git grep pseudo | egrep -v -e "po|out|sgml|sql" | more > > My initial problem was saving history (for backup to be used during > troubleshoot analysis) of plan changing and so on.. of the pg_statistic > table/object. > > I was surprised - in a good way - to observe so much effort when handling > it for that specific purpose. I started to wonder if/when I want to create > an object of other *pseudatatypes *or pass it through a function > parameter that the same level of effort during code implementation would be > the same. > > I understand this would be much more a code architecture discretion rather > than a punctual question. > > I have posted in pgsql-admin a question which is "simple problem" when > creating a table using anyarray and indeed the problem is simple - the > solution might not be. > > What folks, more experienced in this subject, would recommend as a > starting point to achieve that objective? > > Kind regards, > > Bazana Schmidt, Vinícius > > PS.: apologize in advance for the HTML email. > Complementing - Under this optics below: [vinnix@vesuvio postgres]$ git grep CheckAttributeType src/backend/catalog/heap.c: * flags controls which datatypes are allowed, cf CheckAttributeType. src/backend/catalog/heap.c: CheckAttributeType(NameStr(TupleDescAttr(tupdesc, i)->attname), src/backend/catalog/heap.c: * CheckAttributeType src/backend/catalog/heap.c:CheckAttributeType(const char *attname, src/backend/catalog/heap.c: CheckAttributeType(attname, getBaseType(atttypid), attcollation, src/backend/catalog/heap.c: CheckAttributeType(NameStr(attr->attname), src/backend/catalog/heap.c: CheckAttributeType(attname, get_range_subtype(atttypid), src/backend/catalog/heap.c: CheckAttributeType(attname, att_typelem, attcollation, src/backend/catalog/index.c: CheckAttributeType(NameStr(to->attname), src/backend/commands/tablecmds.c: CheckAttributeType(NameStr(attribute->attname), attribute->atttypid, attribute->attcollation, src/backend/commands/tablecmds.c: CheckAttributeType(colName, targettype, targetcollid, src/backend/commands/tablecmds.c: CheckAttributeType(partattname, src/include/catalog/heap.h:/* flag bits for CheckAttributeType/CheckAttributeNamesTypes */ src/include/catalog/heap.h:extern void CheckAttributeType(const char *attname, and this line: https://github.com/postgres/postgres/blob/master/src/backend/catalog/heap.c#L562 if (att_typtype == TYPTYPE_PSEUDO) { /* * We disallow pseudo-type columns, with the exception of ANYARRAY," <<== What WE are missing? WHY? How could we make this state true for creating table commands? I will try to find time to keep researching about it - if you folks have any insights please let me know. ^ permalink raw reply [nested|flat] 3+ messages in thread
* Re: Possibilities on code change to implement pseudodatatypes @ 2024-10-03 11:21 Vinícius Abrahão <[email protected]> parent: Vinícius Abrahão <[email protected]> 0 siblings, 0 replies; 3+ messages in thread From: Vinícius Abrahão @ 2024-10-03 11:21 UTC (permalink / raw) To: pgsql-hackers On Mon, Sep 30, 2024 at 10:19 AM Vinícius Abrahão <[email protected]> wrote: > On Mon, Sep 30, 2024 at 9:01 AM Vinícius Abrahão <[email protected]> > wrote: > >> Greetings >> >> I understand the complexity of implementing a pseudo data type when >> passing it over parameters, or using it when creating an object. >> vide: git grep pseudo | egrep -v -e "po|out|sgml|sql" | more >> >> My initial problem was saving history (for backup to be used during >> troubleshoot analysis) of plan changing and so on.. of the pg_statistic >> table/object. >> >> I was surprised - in a good way - to observe so much effort when handling >> it for that specific purpose. I started to wonder if/when I want to create >> an object of other *pseudatatypes *or pass it through a function >> parameter that the same level of effort during code implementation would be >> the same. >> >> I understand this would be much more a code architecture discretion >> rather than a punctual question. >> >> I have posted in pgsql-admin a question which is "simple problem" when >> creating a table using anyarray and indeed the problem is simple - the >> solution might not be. >> >> What folks, more experienced in this subject, would recommend as a >> starting point to achieve that objective? >> >> Kind regards, >> >> Bazana Schmidt, Vinícius >> >> PS.: apologize in advance for the HTML email. >> > > Complementing - > > Under this optics below: > > [vinnix@vesuvio postgres]$ git grep CheckAttributeType > src/backend/catalog/heap.c: * flags controls which datatypes are > allowed, cf CheckAttributeType. > src/backend/catalog/heap.c: > CheckAttributeType(NameStr(TupleDescAttr(tupdesc, i)->attname), > src/backend/catalog/heap.c: * CheckAttributeType > src/backend/catalog/heap.c:CheckAttributeType(const char *attname, > src/backend/catalog/heap.c: CheckAttributeType(attname, > getBaseType(atttypid), attcollation, > src/backend/catalog/heap.c: > CheckAttributeType(NameStr(attr->attname), > src/backend/catalog/heap.c: CheckAttributeType(attname, > get_range_subtype(atttypid), > src/backend/catalog/heap.c: CheckAttributeType(attname, > att_typelem, attcollation, > src/backend/catalog/index.c: > CheckAttributeType(NameStr(to->attname), > src/backend/commands/tablecmds.c: > CheckAttributeType(NameStr(attribute->attname), attribute->atttypid, > attribute->attcollation, > src/backend/commands/tablecmds.c: CheckAttributeType(colName, > targettype, targetcollid, > src/backend/commands/tablecmds.c: > CheckAttributeType(partattname, > src/include/catalog/heap.h:/* flag bits for > CheckAttributeType/CheckAttributeNamesTypes */ > src/include/catalog/heap.h:extern void CheckAttributeType(const char > *attname, > > and this line: > > https://github.com/postgres/postgres/blob/master/src/backend/catalog/heap.c#L562 > > if (att_typtype == TYPTYPE_PSEUDO) > { > /* > * We disallow pseudo-type columns, with the exception of ANYARRAY," > <<== > > > What WE are missing? WHY? How could we make this state true for creating > table commands? > I will try to find time to keep researching about it - if you folks have > any insights please let me know. > I see now how to workaround it based on the parameter below. However, it's expected this will never work for a regular user/role. postgres=# set allow_system_table_mods to on; SET Time: 5.190 ms postgres=# create table a(a anyarray) ; CREATE TABLE Time: 132.959 ms This is verified at heap_create_with_catalog(...) function. Cheers, -- vinnix aka: Vinícius Abrahão Bazana Schmidt twitter.com/vischmidt linkedin.com/in/vischmidt ^ permalink raw reply [nested|flat] 3+ messages in thread
end of thread, other threads:[~2024-10-03 11:21 UTC | newest] Thread overview: 3+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2023-07-26 10:49 [PATCH v3 2/7] Row pattern recognition patch (parse/analysis). Tatsuo Ishii <[email protected]> 2024-09-30 09:19 Re: Possibilities on code change to implement pseudodatatypes Vinícius Abrahão <[email protected]> 2024-10-03 11:21 ` Re: Possibilities on code change to implement pseudodatatypes Vinícius Abrahão <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox