From 6a9eec5d7a0df7deaf2b94c52af0377b6577cca2 Mon Sep 17 00:00:00 2001 From: Nikita Glukhov Date: Sat, 1 Apr 2023 16:21:20 +0300 Subject: [PATCH v10 5/7] Enable String node as field accessors in generic subscripting Now that we are allowing container generic subscripting to take dot notation in the list of indirections, and it is transformed as a String node. For jsonb, we want to represent field accessors as String nodes in refupperexprs for distinguishing from ordinary text subscripts which can be needed for correct EXPLAIN. Strings node is no longer a valid expression nodes, so added special handling for them in walkers in nodeFuncs etc. --- src/backend/executor/execExpr.c | 24 +++++++--- src/backend/nodes/nodeFuncs.c | 73 ++++++++++++++++++++++++++---- src/backend/parser/parse_collate.c | 22 +++++++-- src/backend/utils/adt/ruleutils.c | 29 ++++++++---- 4 files changed, 121 insertions(+), 27 deletions(-) diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 03566c4d181..be4213455e5 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -3328,9 +3328,15 @@ ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref, { sbsrefstate->upperprovided[i] = true; /* Each subscript is evaluated into appropriate array entry */ - ExecInitExprRec(e, state, - &sbsrefstate->upperindex[i], - &sbsrefstate->upperindexnull[i]); + if (IsA(e, String)) + { + sbsrefstate->upperindex[i] = CStringGetTextDatum(strVal(e)); + sbsrefstate->upperindexnull[i] = false; + } + else + ExecInitExprRec(e, state, + &sbsrefstate->upperindex[i], + &sbsrefstate->upperindexnull[i]); } i++; } @@ -3351,9 +3357,15 @@ ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref, { sbsrefstate->lowerprovided[i] = true; /* Each subscript is evaluated into appropriate array entry */ - ExecInitExprRec(e, state, - &sbsrefstate->lowerindex[i], - &sbsrefstate->lowerindexnull[i]); + if (IsA(e, String)) + { + sbsrefstate->lowerindex[i] = CStringGetTextDatum(strVal(e)); + sbsrefstate->lowerindexnull[i] = false; + } + else + ExecInitExprRec(e, state, + &sbsrefstate->lowerindex[i], + &sbsrefstate->lowerindexnull[i]); } i++; } diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 7bc823507f1..a9c29ab8f29 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -2182,12 +2182,28 @@ expression_tree_walker_impl(Node *node, case T_SubscriptingRef: { SubscriptingRef *sbsref = (SubscriptingRef *) node; + ListCell *lc; + + /* + * Recurse directly for upper/lower container index lists, + * skipping String subscripts used for dot notation. + */ + foreach(lc, sbsref->refupperindexpr) + { + Node *expr = lfirst(lc); + + if (expr && !IsA(expr, String) && WALK(expr)) + return true; + } + + foreach(lc, sbsref->reflowerindexpr) + { + Node *expr = lfirst(lc); + + if (expr && !IsA(expr, String) && WALK(expr)) + return true; + } - /* recurse directly for upper/lower container index lists */ - if (LIST_WALK(sbsref->refupperindexpr)) - return true; - if (LIST_WALK(sbsref->reflowerindexpr)) - return true; /* walker must see the refexpr and refassgnexpr, however */ if (WALK(sbsref->refexpr)) return true; @@ -3082,12 +3098,51 @@ expression_tree_mutator_impl(Node *node, { SubscriptingRef *sbsref = (SubscriptingRef *) node; SubscriptingRef *newnode; + ListCell *lc; + List *exprs = NIL; FLATCOPY(newnode, sbsref, SubscriptingRef); - MUTATE(newnode->refupperindexpr, sbsref->refupperindexpr, - List *); - MUTATE(newnode->reflowerindexpr, sbsref->reflowerindexpr, - List *); + + foreach(lc, sbsref->refupperindexpr) + { + Node *expr = lfirst(lc); + + if (expr && IsA(expr, String)) + { + String *str; + + FLATCOPY(str, expr, String); + expr = (Node *) str; + } + else + expr = mutator(expr, context); + + exprs = lappend(exprs, expr); + } + + newnode->refupperindexpr = exprs; + + exprs = NIL; + + foreach(lc, sbsref->reflowerindexpr) + { + Node *expr = lfirst(lc); + + if (expr && IsA(expr, String)) + { + String *str; + + FLATCOPY(str, expr, String); + expr = (Node *) str; + } + else + expr = mutator(expr, context); + + exprs = lappend(exprs, expr); + } + + newnode->reflowerindexpr = exprs; + MUTATE(newnode->refexpr, sbsref->refexpr, Expr *); MUTATE(newnode->refassgnexpr, sbsref->refassgnexpr, diff --git a/src/backend/parser/parse_collate.c b/src/backend/parser/parse_collate.c index d2e218353f3..be6dea6ffd2 100644 --- a/src/backend/parser/parse_collate.c +++ b/src/backend/parser/parse_collate.c @@ -680,11 +680,25 @@ assign_collations_walker(Node *node, assign_collations_context *context) * contribute anything.) */ SubscriptingRef *sbsref = (SubscriptingRef *) node; + ListCell *lc; + + /* skip String subscripts used for dot notation */ + foreach(lc, sbsref->refupperindexpr) + { + Node *expr = lfirst(lc); + + if (expr && !IsA(expr, String)) + assign_expr_collations(context->pstate, expr); + } + + foreach(lc, sbsref->reflowerindexpr) + { + Node *expr = lfirst(lc); + + if (expr && !IsA(expr, String)) + assign_expr_collations(context->pstate, expr); + } - assign_expr_collations(context->pstate, - (Node *) sbsref->refupperindexpr); - assign_expr_collations(context->pstate, - (Node *) sbsref->reflowerindexpr); (void) assign_collations_walker((Node *) sbsref->refexpr, &loccontext); (void) assign_collations_walker((Node *) sbsref->refassgnexpr, diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index d11a8a20eea..cfae8159a76 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -47,6 +47,7 @@ #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "nodes/pathnodes.h" +#include "nodes/subscripting.h" #include "optimizer/optimizer.h" #include "parser/parse_agg.h" #include "parser/parse_func.h" @@ -12923,17 +12924,29 @@ printSubscripts(SubscriptingRef *sbsref, deparse_context *context) lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */ foreach(uplist_item, sbsref->refupperindexpr) { - appendStringInfoChar(buf, '['); - if (lowlist_item) + Node *up = (Node *) lfirst(uplist_item); + + if (IsA(up, String)) + { + appendStringInfoChar(buf, '.'); + appendStringInfoString(buf, quote_identifier(strVal(up))); + } + else { + appendStringInfoChar(buf, '['); + if (lowlist_item) + { + /* If subexpression is NULL, get_rule_expr prints nothing */ + get_rule_expr((Node *) lfirst(lowlist_item), context, false); + appendStringInfoChar(buf, ':'); + } /* If subexpression is NULL, get_rule_expr prints nothing */ - get_rule_expr((Node *) lfirst(lowlist_item), context, false); - appendStringInfoChar(buf, ':'); - lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item); + get_rule_expr((Node *) lfirst(uplist_item), context, false); + appendStringInfoChar(buf, ']'); } - /* If subexpression is NULL, get_rule_expr prints nothing */ - get_rule_expr((Node *) lfirst(uplist_item), context, false); - appendStringInfoChar(buf, ']'); + + if (lowlist_item) + lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item); } } -- 2.39.5 (Apple Git-154)