On 18.04.21 23:33, Tom Lane wrote:
... BTW, a dependency loop is also possible without using this feature,
by abusing default-value expressions:
create function f1(x int, y int) returns int language sql
as 'select $1 + $2';
create function f2(x int, y int default f1(1,2)) returns int language sql
as 'select $1 + $2';
create or replace function f1(x int, y int default f2(11,12)) returns int
language sql
as 'select $1 + $2';
The actual use-case for that seems pretty thin, so we never bothered
to worry about it before. But if we're going to build loop-breaking
logic to handle function body dependencies, it should deal with this
too. I think that all that's required is for the initial dummy
function declaration to omit defaults as well as providing a dummy
body.
I have studied this a bit. I'm not sure where the dummy function
declaration should be created. The current dependency-breaking logic in
pg_dump_sort.c doesn't appear to support injecting additional objects
into the set of dumpable objects. So we would need to create it perhaps
in dumpFunc() and then later set flags that indicate whether it will be
required.
Another option would be that we disallow this at creation time. It
seems we could detect dependency loops using findDependentObjects(), so
this might not be so difficult. The use case for recursive SQL
functions is probably low, at least with the current limited set of
control flow options in SQL. (And you can always use a quoted body to
work around it.)