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