Unexpected result from ALTER FUNCTION— looks like a bug

From: Bryn Llewellyn <bryn(at)yugabyte(dot)com>
To: pgsql-general list <pgsql-general(at)lists(dot)postgresql(dot)org>
Subject: Unexpected result from ALTER FUNCTION— looks like a bug
Date: 2022-04-20 02:07:30
Message-ID: 8AC9A37F-99BD-446F-A2F7-B89AD0022774@yugabyte.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

SUMMARY

This part of the syntax diagram for "alter function":

ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] action [ … ]

says that the first "action" can be followed (without punctuation) by zero, one, or many other actions. A semantic rule says that no particular action can be specified more than once. My tests used these possible actions:

SECURITY { INVOKER | DEFINER }
SET configuration_parameter TO value
IMMUTABLE | STABLE | VOLATILE
PARALLEL { UNSAFE | RESTRICTED | SAFE }

The values of the properties set this way can be seen with a suitable query against "pg_catalog.pg_proc". (See the complete testcase below.) Suppose that the history of events shows this status for the function s1.f():

name | type | security | proconfig | volatility | parallel
------+------+----------+---------------------------------------------------------+------------+------------
f | func | invoker | | volatile | unsafe

This statement:

alter function s1.f()
security definer
immutable
parallel restricted;

brings this new status:

name | type | security | proconfig | volatility | parallel
------+------+----------+---------------------------------------------------------+------------+------------
f | func | definer | | immutable | restricted

confirming that the three specified changes have been made using just a single "alter function" statement.

However, when "SET configuration_parameter" is specified along with other changes, then the "parallel" specification (but only this) is ignored. The other three specifications are honored.

alter function s1.f()
security invoker
set 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.

Notice that with "alter procedure", the semantic difference between a procedure and a function means that you cannot specify "parallel" here, and so you can't demonstrate the bug here.

SELF-CONTAINED, RE-RUNNABLE TESTCASE tested using PG Version 14.1

--------------------------------------------------------------------------------
-- demo.sql
-----------

\o spool.txt

\c postgres postgres
set client_min_messages = warning;
drop database if exists db;
create database db owner postgres;

\c db postgres
set client_min_messages = warning;
drop schema if exists public cascade;
create schema s1 authorization postgres;

\i prepare-qry.sql

create function s1.f()
returns int
language plpgsql
as $body$
begin
return 0;
end;
$body$;

\t off
execute qry;

alter function s1.f()
security definer
immutable
parallel restricted;

\t on
execute qry;

-- Here is the bug. The test is meaningful only for a function.
alter function s1.f()
security invoker
set timezone = 'UTC'
stable
parallel safe;

execute qry;

\o

--------------------------------------------------------------------------------
-- prepare-qry.sql
------------------

drop view if exists s1.subprograms cascade;
create view s1.subprograms(
name,
pronamespace,
type,
security,
proconfig,
volatility,
parallel)
as
select
proname::text as name,
pronamespace::regnamespace::text,
case prokind
when 'a' then 'agg'
when 'w' then 'window'
when 'p' then 'proc'
else 'func'
end,
case
when prosecdef then 'definer'
else 'invoker'
end,
coalesce(proconfig::text, '') as proconfig,
case
when provolatile = 'i' then 'immutable'
when provolatile = 's' then 'stable'
when provolatile = 'v' then 'volatile'
end,
case
when proparallel = 'r' then 'restricted'
when proparallel = 's' then 'safe'
when proparallel = 'u' then 'unsafe'
end
from pg_catalog.pg_proc
where
proowner::regrole::text = 'postgres' and
pronamespace::regnamespace::text = 's1' and
pronargs = 0;

prepare qry as
select
rpad(name, 4) as name,
rpad(type, 4) as type,
rpad(security, 8) as security,
rpad(proconfig, 55) as proconfig,
rpad(volatility, 10) as volatility,
rpad(parallel, 10) as parallel
from s1.subprograms
where type in ('func', 'proc')
and pronamespace::regnamespace::text = 's1'
order by name;

--------------------------------------------------------------------------------
spool.txt
---------

name | type | security | proconfig | volatility | parallel
------+------+----------+---------------------------------------------------------+------------+------------
f | func | invoker | | volatile | unsafe

f | func | definer | | immutable | restricted

f | func | invoker | {TimeZone=UTC} | stable | restricted

Responses

Browse pgsql-general by date

  From Date Subject
Next Message David G. Johnston 2022-04-20 02:21:19 Re: Unexpected result from ALTER FUNCTION— looks like a bug
Previous Message Michael Lewis 2022-04-19 20:48:33 LwLocks contention