On Tue, Apr 19, 2022 at 7:47 PM Julien Rouhaud <rjuju...@gmail.com> wrote:

>
> On Tue, Apr 19, 2022 at 07:21:19PM -0700, David G. Johnston wrote:
> > On Tue, Apr 19, 2022 at 7:07 PM Bryn Llewellyn <b...@yugabyte.com>
> wrote:
> >
>
> > > *alter function s1.f()security invokerset timezone = 'UTC'stable*
> > > *parallel safe*
> > > *;*
> > >
> > > It brings this new status:
> > >
> > >
> > >
> > > * name | type | security |                        proconfig
> > >         | volatility
> > > |  parallel
> ------+------+----------+---------------------------------------------------------+------------+------------
> f
> > >    | func | invoker  | {TimeZone=UTC}
> > >    | stable     | restricted*
> > >
> > > This is the bug.
> > >
> >
> > It has room for improvement from a user experience perspective.
> >
> > While I haven't experimented with this for confirmation, what you are
> > proposing here (set + parallel safe) is an impossible runtime combination
> > (semantic rule) but perfectly valid to write syntactically.  Your
> function
> > must either be restricted or unsafe per the rules for specifying parallel
> > mode.
> >



>
> That's not the problem here though, as you can still end up with the wanted
> result using 2 queries.  Also, the PARALLEL part is entirely ignored, so
> if you
> wanted to mark the function as PARALLEL UNSAFE because you're also doing a
> SET
> that would make it incompatible it would also be ignored, same if you use a
> RESET clause.
>
> AFAICT the problem is that SET / RESET part is messing with the HeapTuple,
> so
> you can't use the procForm reference afterwards.  Simply processing
> parallel_item before set_items fixes the problem, as in the attached.
>

Thank you for the explanation.

Might I suggest the following:

diff --git a/src/backend/commands/functioncmds.c
b/src/backend/commands/functioncmds.c
index 91f02a7eb2..2790c64121 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1416,12 +1416,20 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt
*stmt)
                        elog(ERROR, "option \"%s\" not recognized",
defel->defname);
        }

+       /*
+        * For each action, modify procForm to type-safely set the new
value.
+        * However, because the SET clause is repeatable we handle it
+        * a bit differently, modifying the underlying tuple directly.  So
+        * make sure to leave that conditional block for last.
+        */
        if (volatility_item)
                procForm->provolatile =
interpret_func_volatility(volatility_item);
        if (strict_item)
                procForm->proisstrict = boolVal(strict_item->arg);
        if (security_def_item)
                procForm->prosecdef = boolVal(security_def_item->arg);
+       if (parallel_item)
+               procForm->proparallel =
interpret_func_parallel(parallel_item);
        if (leakproof_item)
        {
                procForm->proleakproof = boolVal(leakproof_item->arg);
@@ -1506,8 +1514,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt
*stmt)
                tup = heap_modify_tuple(tup, RelationGetDescr(rel),
                                                                repl_val,
repl_null, repl_repl);
        }
-       if (parallel_item)
-               procForm->proparallel =
interpret_func_parallel(parallel_item);
+       /* The previous block must come last because it modifies tup
directly instead of via procForm */

        /* Do the update */
        CatalogTupleUpdate(rel, &tup->t_self, tup);

I placed the parallel_item block at the end of the four blocks that all
have single line bodies to keep the consistency of that form.

David J.

Reply via email to