v4-0001-Add-tracking-for-expression-boundaries.patch
application/x-patch
Filename: v4-0001-Add-tracking-for-expression-boundaries.patch
Type: application/x-patch
Part: 2
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v4-0001
Subject: Add tracking for expression boundaries
| File | + | − |
|---|---|---|
| src/backend/parser/gram.y | 67 | 27 |
| src/backend/parser/parse_expr.c | 4 | 0 |
| src/include/nodes/parsenodes.h | 4 | 0 |
| src/include/nodes/primnodes.h | 4 | 0 |
From 0af27d235ca6fd1db12d81c657d8b349f3b29316 Mon Sep 17 00:00:00 2001
From: Ubuntu <ubuntu@ip-172-31-38-230.ec2.internal>
Date: Wed, 21 May 2025 17:25:02 +0000
Subject: [PATCH v4 1/3] Add tracking for expression boundaries
This adds the ability to track the locations of the start and
end of a list of elements such as those in an 'IN' list of an
Array expression to support squashing of values for query
normalization purposes. This corrects various normalization
issues that are a result of 62d712ec.
Discussion: https://www.postgresql.org/message-id/flat/202505021256.4yaa24s3sytm%40alvherre.pgsql#1195a340edca50cc3b7389a2ba8b0467
---
src/backend/parser/gram.y | 94 +++++++++++++++++++++++----------
src/backend/parser/parse_expr.c | 4 ++
src/include/nodes/parsenodes.h | 4 ++
src/include/nodes/primnodes.h | 4 ++
4 files changed, 79 insertions(+), 27 deletions(-)
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0b5652071d1..0cd5f794db3 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -136,6 +136,17 @@ typedef struct KeyActions
KeyAction *deleteAction;
} KeyActions;
+/*
+ * Track the start and end of a list in an expression, such as an 'IN' list
+ * or Array Expression
+ */
+typedef struct ListWithBoundary
+{
+ Node *expr;
+ ParseLoc start;
+ ParseLoc end;
+} ListWithBoundary;
+
/* ConstraintAttributeSpec yields an integer bitmask of these flags: */
#define CAS_NOT_DEFERRABLE 0x01
#define CAS_DEFERRABLE 0x02
@@ -184,7 +195,7 @@ static void doNegateFloat(Float *v);
static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location);
static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location);
static Node *makeNotExpr(Node *expr, int location);
-static Node *makeAArrayExpr(List *elements, int location);
+static Node *makeAArrayExpr(List *elements, int location, int end_location);
static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod,
int location);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
@@ -269,6 +280,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
struct KeyAction *keyaction;
ReturningClause *retclause;
ReturningOptionKind retoptionkind;
+ struct ListWithBoundary *listwithboundary;
}
%type <node> stmt toplevel_stmt schema_stmt routine_body_stmt
@@ -523,8 +535,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <defelt> def_elem reloption_elem old_aggr_elem operator_def_elem
%type <node> def_arg columnElem where_clause where_or_current_clause
a_expr b_expr c_expr AexprConst indirection_el opt_slice_bound
- columnref in_expr having_clause func_table xmltable array_expr
+ columnref having_clause func_table xmltable array_expr
OptWhereClause operator_def_arg
+%type <listwithboundary> in_expr
%type <list> opt_column_and_period_list
%type <list> rowsfrom_item rowsfrom_list opt_col_def_list
%type <boolean> opt_ordinality opt_without_overlaps
@@ -15289,46 +15302,58 @@ a_expr: c_expr { $$ = $1; }
}
| a_expr IN_P in_expr
{
+ ListWithBoundary *n = $3;
+
/* in_expr returns a SubLink or a list of a_exprs */
- if (IsA($3, SubLink))
+ if (IsA(n->expr, SubLink))
{
/* generate foo = ANY (subquery) */
- SubLink *n = (SubLink *) $3;
-
- n->subLinkType = ANY_SUBLINK;
- n->subLinkId = 0;
- n->testexpr = $1;
- n->operName = NIL; /* show it's IN not = ANY */
- n->location = @2;
- $$ = (Node *) n;
+ SubLink *n2 = (SubLink *) n->expr;
+
+ n2->subLinkType = ANY_SUBLINK;
+ n2->subLinkId = 0;
+ n2->testexpr = $1;
+ n2->operName = NIL; /* show it's IN not = ANY */
+ n2->location = @2;
+ $$ = (Node *) n2;
}
else
{
/* generate scalar IN expression */
- $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2);
+ A_Expr *n2 = makeSimpleA_Expr(AEXPR_IN, "=", $1, n->expr, @2);
+
+ n2->rexpr_list_start = $3->start;
+ n2->rexpr_list_end = $3->end;
+ $$ = (Node *) n2;
}
}
| a_expr NOT_LA IN_P in_expr %prec NOT_LA
{
+ ListWithBoundary *n = $4;
+
/* in_expr returns a SubLink or a list of a_exprs */
- if (IsA($4, SubLink))
+ if (IsA(n->expr, SubLink))
{
/* generate NOT (foo = ANY (subquery)) */
/* Make an = ANY node */
- SubLink *n = (SubLink *) $4;
+ SubLink *n2 = (SubLink *) n->expr;
- n->subLinkType = ANY_SUBLINK;
- n->subLinkId = 0;
- n->testexpr = $1;
- n->operName = NIL; /* show it's IN not = ANY */
- n->location = @2;
+ n2->subLinkType = ANY_SUBLINK;
+ n2->subLinkId = 0;
+ n2->testexpr = $1;
+ n2->operName = NIL; /* show it's IN not = ANY */
+ n2->location = @2;
/* Stick a NOT on top; must have same parse location */
- $$ = makeNotExpr((Node *) n, @2);
+ $$ = makeNotExpr((Node *) n2, @2);
}
else
{
/* generate scalar NOT IN expression */
- $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4, @2);
+ A_Expr *n2 = makeSimpleA_Expr(AEXPR_IN, "<>", $1, n->expr, @2);
+
+ n2->rexpr_list_start = $4->start;
+ n2->rexpr_list_end = $4->end;
+ $$ = (Node *) n2;
}
}
| a_expr subquery_Op sub_type select_with_parens %prec Op
@@ -16764,15 +16789,15 @@ type_list: Typename { $$ = list_make1($1); }
array_expr: '[' expr_list ']'
{
- $$ = makeAArrayExpr($2, @1);
+ $$ = makeAArrayExpr($2, @1, @3);
}
| '[' array_expr_list ']'
{
- $$ = makeAArrayExpr($2, @1);
+ $$ = makeAArrayExpr($2, @1, @3);
}
| '[' ']'
{
- $$ = makeAArrayExpr(NIL, @1);
+ $$ = makeAArrayExpr(NIL, @1, @2);
}
;
@@ -16897,12 +16922,25 @@ trim_list: a_expr FROM expr_list { $$ = lappend($3, $1); }
in_expr: select_with_parens
{
SubLink *n = makeNode(SubLink);
+ ListWithBoundary *n2 = palloc(sizeof(ListWithBoundary));
n->subselect = $1;
/* other fields will be filled later */
- $$ = (Node *) n;
+
+ n2->expr = (Node *) n;
+ n2->start = -1;
+ n2->end = -1;
+ $$ = n2;
+ }
+ | '(' expr_list ')'
+ {
+ ListWithBoundary *n = palloc(sizeof(ListWithBoundary));
+
+ n->expr = (Node *) $2;
+ n->start = @1;
+ n->end = @3;
+ $$ = n;
}
- | '(' expr_list ')' { $$ = (Node *) $2; }
;
/*
@@ -19300,12 +19338,14 @@ makeNotExpr(Node *expr, int location)
}
static Node *
-makeAArrayExpr(List *elements, int location)
+makeAArrayExpr(List *elements, int location, int location_end)
{
A_ArrayExpr *n = makeNode(A_ArrayExpr);
n->elements = elements;
n->location = location;
+ n->list_start = location;
+ n->list_end = location_end;
return (Node *) n;
}
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 1f8e2d54673..7347c989e11 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -1224,6 +1224,8 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
newa->elements = aexprs;
newa->multidims = false;
newa->location = -1;
+ newa->list_start = a->rexpr_list_start;
+ newa->list_end = a->rexpr_list_end;
result = (Node *) make_scalar_array_op(pstate,
a->name,
@@ -2166,6 +2168,8 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
newa->element_typeid = element_type;
newa->elements = newcoercedelems;
newa->location = a->location;
+ newa->list_start = a->list_start;
+ newa->list_end = a->list_end;
return (Node *) newa;
}
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 4610fc61293..2f078887d06 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -347,6 +347,8 @@ typedef struct A_Expr
Node *lexpr; /* left argument, or NULL if none */
Node *rexpr; /* right argument, or NULL if none */
ParseLoc location; /* token location, or -1 if unknown */
+ ParseLoc rexpr_list_start; /* location of the start of a rexpr list */
+ ParseLoc rexpr_list_end; /* location of the end of a rexpr list */
} A_Expr;
/*
@@ -502,6 +504,8 @@ typedef struct A_ArrayExpr
NodeTag type;
List *elements; /* array element expressions */
ParseLoc location; /* token location, or -1 if unknown */
+ ParseLoc list_start; /* location of the start of the elements list */
+ ParseLoc list_end; /* location of the end of the elements list */
} A_ArrayExpr;
/*
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 7d3b4198f26..773cdd880aa 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1399,6 +1399,10 @@ typedef struct ArrayExpr
bool multidims pg_node_attr(query_jumble_ignore);
/* token location, or -1 if unknown */
ParseLoc location;
+ /* location of the start of the elements list */
+ ParseLoc list_start;
+ /* location of the end of the elements list */
+ ParseLoc list_end;
} ArrayExpr;
/*
--
2.39.5 (Apple Git-154)