From bcab1a8364979dce146b36e31865e9b670bd892b Mon Sep 17 00:00:00 2001 From: Dmitrii Dolgov <9erthalion6@gmail.com> Date: Thu, 8 May 2025 16:41:01 +0200 Subject: [PATCH v1 1/2] Introduce LocationExpr Add LocationExpr wrapper node to capture start and end location of an expression in a query. Use it in to wrap expr_list in in_expr and convery location information to ArrayExpr. --- src/backend/nodes/nodeFuncs.c | 36 ++++++++++++++++++++++++++++++++ src/backend/parser/gram.y | 11 +++++++++- src/backend/parser/parse_expr.c | 28 ++++++++++++++++++++++++- src/include/nodes/parsenodes.h | 15 +++++++++++++ src/include/nodes/primnodes.h | 2 ++ src/tools/pgindent/typedefs.list | 1 + 6 files changed, 91 insertions(+), 2 deletions(-) diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 7bc823507f1..6f6a7079d55 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -284,6 +284,12 @@ exprType(const Node *expr) case T_PlaceHolderVar: type = exprType((Node *) ((const PlaceHolderVar *) expr)->phexpr); break; + case T_LocationExpr: + { + const LocationExpr *n = (const LocationExpr *) expr; + type = exprType((Node *) n->expr); + } + break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); type = InvalidOid; /* keep compiler quiet */ @@ -536,6 +542,11 @@ exprTypmod(const Node *expr) return exprTypmod((Node *) ((const ReturningExpr *) expr)->retexpr); case T_PlaceHolderVar: return exprTypmod((Node *) ((const PlaceHolderVar *) expr)->phexpr); + case T_LocationExpr: + { + const LocationExpr *n = (const LocationExpr *) expr; + return exprTypmod((Node *) n->expr); + } default: break; } @@ -1058,6 +1069,9 @@ exprCollation(const Node *expr) case T_PlaceHolderVar: coll = exprCollation((Node *) ((const PlaceHolderVar *) expr)->phexpr); break; + case T_LocationExpr: + coll = exprCollation((Node *) ((const LocationExpr *) expr)->expr); + break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); coll = InvalidOid; /* keep compiler quiet */ @@ -1306,6 +1320,10 @@ exprSetCollation(Node *expr, Oid collation) /* NextValueExpr's result is an integer type ... */ Assert(!OidIsValid(collation)); /* ... so never set a collation */ break; + case T_LocationExpr: + exprSetCollation((Node *) ((LocationExpr *) expr)->expr, + collation); + break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); break; @@ -1803,6 +1821,9 @@ exprLocation(const Node *expr) case T_PartitionRangeDatum: loc = ((const PartitionRangeDatum *) expr)->location; break; + case T_LocationExpr: + loc = ((const LocationExpr *) expr)->start_location; + break; default: /* for any other node type it's just unknown... */ loc = -1; @@ -2668,6 +2689,8 @@ expression_tree_walker_impl(Node *node, return true; } break; + case T_LocationExpr: + return WALK(((LocationExpr *) node)->expr); default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); @@ -3744,6 +3767,17 @@ expression_tree_mutator_impl(Node *node, return (Node *) newnode; } break; + case T_LocationExpr: + { + LocationExpr *expr = (LocationExpr *) node; + LocationExpr *newnode; + + FLATCOPY(newnode, expr, LocationExpr); + MUTATE(newnode->expr, expr->expr, Node *); + + return (Node *) newnode; + } + break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); @@ -4705,6 +4739,8 @@ raw_expression_tree_walker_impl(Node *node, return true; } break; + case T_LocationExpr: + return WALK(((LocationExpr *) node)->expr); default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3c4268b271a..3ffa5335f4e 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -16895,7 +16895,16 @@ in_expr: select_with_parens /* other fields will be filled later */ $$ = (Node *) n; } - | '(' expr_list ')' { $$ = (Node *) $2; } + | '(' expr_list ')' + { + LocationExpr *n = makeNode(LocationExpr); + + n->expr = (Node *) $2; + n->start_location = @1 + 1; + n->end_location = @3 - 1; + + $$ = (Node *) n; + } ; /* diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 1f8e2d54673..30d52c801eb 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -370,6 +370,22 @@ transformExprRecurse(ParseState *pstate, Node *expr) result = transformJsonFuncExpr(pstate, (JsonFuncExpr *) expr); break; + case T_LocationExpr: + { + LocationExpr *loc = (LocationExpr *) expr; + if (IsA(loc->expr, ArrayExpr)) + { + ArrayExpr *arr = (ArrayExpr *) loc->expr; + arr->loc_range = list_make2_int(loc->start_location, + loc->end_location); + + result = (Node *) arr; + } + else + result = (Node *) loc->expr; + } + break; + default: /* should not reach here */ elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); @@ -1125,6 +1141,7 @@ transformAExprIn(ParseState *pstate, A_Expr *a) { Node *result = NULL; Node *lexpr; + LocationExpr *location = NULL; List *rexprs; List *rvars; List *rnonvars; @@ -1139,6 +1156,9 @@ transformAExprIn(ParseState *pstate, A_Expr *a) else useOr = true; + if (IsA(a->rexpr, LocationExpr)) + location = (LocationExpr *) a->rexpr; + /* * We try to generate a ScalarArrayOpExpr from IN/NOT IN, but this is only * possible if there is a suitable array type available. If not, we fall @@ -1152,7 +1172,7 @@ transformAExprIn(ParseState *pstate, A_Expr *a) */ lexpr = transformExprRecurse(pstate, a->lexpr); rexprs = rvars = rnonvars = NIL; - foreach(l, (List *) a->rexpr) + foreach(l, (List *) transformExprRecurse(pstate, a->rexpr)) { Node *rexpr = transformExprRecurse(pstate, lfirst(l)); @@ -1224,6 +1244,12 @@ transformAExprIn(ParseState *pstate, A_Expr *a) newa->elements = aexprs; newa->multidims = false; newa->location = -1; + if (location) + newa->loc_range = list_make2_int(location->start_location, + location->end_location); + else + newa->loc_range = NIL; + result = (Node *) make_scalar_array_op(pstate, a->name, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 4610fc61293..5107bfad9a6 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -504,6 +504,21 @@ typedef struct A_ArrayExpr ParseLoc location; /* token location, or -1 if unknown */ } A_ArrayExpr; +/* + * A wrapper expression to record start and end location + */ +typedef struct LocationExpr +{ + NodeTag type; + + /* the node to be wrapped */ + Node *expr; + /* token location, or -1 if unknown */ + ParseLoc start_location; + /* token location, or -1 if unknown */ + ParseLoc end_location; +} LocationExpr; + /* * ResTarget - * result target (used in target list of pre-transformed parse trees) diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 7d3b4198f26..ffee0f7768f 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -1399,6 +1399,8 @@ typedef struct ArrayExpr bool multidims pg_node_attr(query_jumble_ignore); /* token location, or -1 if unknown */ ParseLoc location; + + List *loc_range pg_node_attr(query_jumble_ignore); } ArrayExpr; /* diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index e5879e00dff..e6fcba24396 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1501,6 +1501,7 @@ LOCALLOCK LOCALLOCKOWNER LOCALLOCKTAG LOCALPREDICATELOCK +LocationExpr LOCK LOCKMASK LOCKMETHODID base-commit: b0635bfda0535a7fc36cd11d10eecec4e2a96330 -- 2.45.1