Re: Adding OLD/NEW support to RETURNING

From: jian he <jian(dot)universality(at)gmail(dot)com>
To: Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com>
Cc: Jeff Davis <pgsql(at)j-davis(dot)com>, Tomas Vondra <tomas(dot)vondra(at)enterprisedb(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: Adding OLD/NEW support to RETURNING
Date: 2024-07-19 00:11:00
Message-ID: CACJufxHLkHOv_p-5fH9z+VrPzTpTrfs-WektxJGBaX5ya8BiHg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Sat, Jul 13, 2024 at 1:22 AM Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com> wrote:
>
> On Wed, 26 Jun 2024 at 12:18, Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com> wrote:
> >
> > I've added a new elog() error check to
> > adjust_appendrel_attrs_mutator(), similar to the existing one for
> > varnullingrels, to report if we ever attempt to apply a non-default
> > varreturningtype to a non-Var, which should never be possible, but
> > seems worth checking. (non-Var expressions should only occur if we've
> > flattened a UNION ALL query, so shouldn't apply to the target relation
> > of a data-modifying query with RETURNING.)
> >
>
> New version attached, updating an earlier comment in
> adjust_appendrel_attrs_mutator() that I had missed.
>

hi.
I have some minor questions, but overall it just works.

@@ -4884,6 +5167,18 @@ ExecEvalSysVar(ExprState *state, ExprEva
{
Datum d;

+ /* if OLD/NEW row doesn't exist, OLD/NEW system attribute is NULL */
+ if ((op->d.var.varreturningtype == VAR_RETURNING_OLD &&
+ state->flags & EEO_FLAG_OLD_IS_NULL) ||
+ (op->d.var.varreturningtype == VAR_RETURNING_NEW &&
+ state->flags & EEO_FLAG_NEW_IS_NULL))
+ {
+ *op->resvalue = (Datum) 0;
+ *op->resnull = true;
+
+ return;
+ }
+
in ExecEvalSysVar, we can add Asserts
Assert(state->flags & EEO_FLAG_HAS_OLD || state->flags & EEO_FLAG_HAS_NEW);
if I understand it correctly.

in make_modifytable,
contain_vars_returning_old_or_new((Node *) root->parse->returningList))
this don't need to go through the loop
```
foreach(lc, resultRelations)
```

+ * In addition, the caller must provide result_relation, the index of the
+ * target relation for an INSERT/UPDATE/DELETE/MERGE. This is needed to
+ * handle any OLD/NEW RETURNING list Vars referencing target_varno. When such
+ * Vars are expanded, varreturningtype is copied onto any replacement Vars
+ * that reference result_relation. In addition, if the replacement expression
+ * from the targetlist is not simply a Var referencing result_relation, we
+ * wrap it in a ReturningExpr node, to force it to be NULL if the OLD/NEW row
+ * doesn't exist.
+ *
* outer_hasSubLinks works the same as for replace_rte_variables().
*/
@@ -1657,6 +1736,7 @@ typedef struct
{
RangeTblEntry *target_rte;
List *targetlist;
+ int result_relation;
ReplaceVarsNoMatchOption nomatch_option;
int nomatch_varno;
} ReplaceVarsFromTargetList_context;

"to force it to be NULL if the OLD/NEW row doesn't exist."
I am slightly confused.
i think you mean: "to force it to be NULL if the OLD/NEW row will be
resulting null."
For INSERT, the old row is all null, for DELETE, the new row is all null.

in sql-update.html
"An unqualified column name or * causes new values to be returned. The
same applies to columns qualified using the target table name or
alias. "
"The same", I think, refers "causes new values to be returned", but I
i am not so sure.
(apply to sql-insert.sql-delete, sql-merge).

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Michael Paquier 2024-07-19 00:13:11 Re: Correctly propagate queryId for utility stmt in function
Previous Message Noah Misch 2024-07-18 23:39:08 Re: Built-in CTYPE provider