Re: Adding OLD/NEW support to RETURNING

From: Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com>
To: jian he <jian(dot)universality(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-08-16 10:39:46
Message-ID: CAEZATCVi-Zf8LgAzyWSDmKPGxca4mJbvBCz5tBj17w+aeOP4Sw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Mon, 12 Aug 2024 at 07:51, jian he <jian(dot)universality(at)gmail(dot)com> wrote:
>
> took me a while to understand how the returning clause Var nodes
> correctly reference the relations RT index.
> mainly in set_plan_references, set_plan_refs and
> set_returning_clause_references.
>
> do you think we need do something in
> set_returning_clause_references->build_tlist_index_other_vars
> to make sure that
> if the topplan->targetlist associated Var's varreturningtype is not default,
> then the var->varno must equal to resultRelation.
> because set_plan_references is almost at the end of standard_planner,
> before that things may change.

Hmm, well actually the check has to go in fix_join_expr_mutator().
It's really a "shouldn't happen" error, a little similar to other
checks in setrefs.c that elog errors, so I guess it's probably worth
double-checking this too.

> /*
> * Tell ExecProject whether or not the OLD/NEW rows exist (needed for any
> * ReturningExpr nodes and ExecEvalSysVar).
> */
> if (oldSlot == NULL)
> projectReturning->pi_state.flags |= EEO_FLAG_OLD_IS_NULL;
> else
> projectReturning->pi_state.flags &= ~EEO_FLAG_OLD_IS_NULL;
> if (newSlot == NULL)
> projectReturning->pi_state.flags |= EEO_FLAG_NEW_IS_NULL;
> else
> projectReturning->pi_state.flags &= ~EEO_FLAG_NEW_IS_NULL;
>
> ExecEvalWholeRowVar also uses this information, comment needs to be
> slightly adjusted?

Ah, yes.

> simialr to
> https://git.postgresql.org/cgit/postgresql.git/commit/?id=2bb969f3998489e5dc4fe9f2a61185b43581975d
> do you think it's necessary to
> errmsg("%s cannot be specified multiple times", "NEW"),
> errmsg("%s cannot be specified multiple times", "OLD"),

OK, I guess so.

> + /*
> + * Add the OLD and NEW aliases to the query namespace, for use in
> + * expressions in the RETURNING list.
> + */
>
> the only case we don't do addNSItemForReturning is when there is
> really a RTE called "new" or "old".
> Even if the returning list doesn't specify "new" or "old", like
> "returning 1", we still do addNSItemForReturning.
> Do you think it's necessary in ReturningClause add two booleans
> "hasold", "hasnew".
> so if becomes
> + if (qry->returningOld && hasold)
> + addNSItemForReturning(pstate, qry->returningOld, VAR_RETURNING_OLD);
> + if (qry->returningNew && hasnew)
> + addNSItemForReturning(pstate, qry->returningNew, VAR_RETURNING_NEW);
>
> that means in gram.y
> returning_clause:
> RETURNING returning_with_clause target_list
> {
> ReturningClause *n = makeNode(ReturningClause);
>
> n->options = $2;
> n->exprs = $3;
> $$ = n;
> }
>
> n->exprs will have 3 branches: NEW.expr, OLD.expr, expr.
> I guess overall we can save some cycles?

No, I think that would add a whole lot of unnecessary extra
complication, because n->exprs can contain any arbitrary expressions,
including subqueries, which would make it very hard for gram.y to tell
if there really was a Var referencing old/new at a particular query
level, and it would probably end up adding more cycles than it saved
later on, as well as being quite error-prone.

Regards,
Dean

Attachment Content-Type Size
support-returning-old-new-v17.patch text/x-patch 238.7 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Heikki Linnakangas 2024-08-16 11:05:50 Re: refactor the CopyOneRowTo
Previous Message Yugo Nagata 2024-08-16 10:32:24 Re: [PATCH] Add get_bytes() and set_bytes() functions