st 29. 6. 2022 v 6:28 odesĂ­latel Bryn Llewellyn <b...@yugabyte.com> napsal:

> *david.g.johns...@gmail.com <david.g.johns...@gmail.com> wrote:*
>
>
> *x...@thebuild.com <o...@thebuild.com> wrote:*
>
> b...@yugabyte.com wrote:
>
> Should I simply understand that when I have such a dynamic dependency
> chain of "immutable" functions, and should I drop and re-create the
> function at the start of the chain, then all bets are off until I drop and
> re-create every function along the rest of the chain?
>
>
> Yes.
>
> You don't have to drop and recreate the functions, though. DISCARD PLANS
> handles it as well:
>
>
> Specifically:
>
>
>
>
>
> *select f1(), f2(), f3(); f1  | f2  | f3  -----+-----+----- cat | cat |
> cat*
>
> The pl/pgsql plan cache now contains the following:
>
> SELECT f1() => 'cat'
> SELECT f2() => 'cat'
>
>
> *drop function f1();*
> Now the cache only contains:
>
> SELECT f2() => 'cat'
>
> The f1 plan has been invalidated due to the drop/replace action on the f1
> function
>
>
> *create function f1() returns text as $$ begin return 'dog'; end $$
> language plpgsql immutable;*
>
>
>
> *select f1(), f2(), f3(); f1  | f2  | f3  -----+-----+----- dog | dog |
> cat*
>
>
> And so f3()'s invocation of "SELECT f2()" yields 'cat' from the cache
> since that one hasn't been invalidated. While f2() replans its f1()
> invocation and thus returns 'dog'
>
> The fundamental limitation here is that there really is no attempt being
> made to deal with inter-functional dependencies. Their bodies are
> blackboxes (...wonders how this resolves in the new SQL Standard
> Function Bodies implementation...) and no explicit dependency information
> is recorded either. So we don't know that the saved plan for f2() depends
> on a specific version of f1() and thus if f1() is changed plans involving
> f2() should be invalidated along with plans involving f1(). Nor is there
> sufficient recognized benefit to doing so.
>
>
> DISCARD PLANS is unsafe in a multi-user concurrent scenario. The doc says
> explicitly that its scope is just the single session. And it's easy to show
> the danger by using my testcase manually, step by appropriate step, with
> two concurrent sessions.
>
> However, you said (indirectly) that the session-duration caching is a red
> herring—and that the real danger comes with an expression-based index that
> involves a PL/pgSQL function. I agree.
>
> PG's lack of dependency tracking shows up with just a "worker" function
> f1() and a "jacket" function f2() when you base the index on f2(). You can
> happily drop and recreate f1() with a new implementation while the index
> lives on. (For the reasons that we've mentioned, the "2BP01: cannot drop
> function... because other objects depend on it" error doesn't occur.)
>
> *I've concluded that the only practical practice for "immutable" is to
> reserve its use for functions that don't mention even a single user-created
> artifact*.
>
> Moreover, this "hermetic" property of a to-be-immutable function can be
> established only by human analysis of the function's source code.
>

Our immutable functions are more tolerant than they should be - for real
immutable functions we should disallow SQL inside functions (and everything
that is not immutable (plpgsql_check raises warning in this case)), but it
is allowed.  On the second hand, it allows some very dirty tricks with the
planner.

Regards

Pavel

Reply via email to