pgsql: Change SQL-language functions to use the plan cache.

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: pgsql-committers(at)lists(dot)postgresql(dot)org
Subject: pgsql: Change SQL-language functions to use the plan cache.
Date: 2025-04-02 18:06:23
Message-ID: E1u02Tn-002Kp0-0Q@gemulon.postgresql.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-committers

Change SQL-language functions to use the plan cache.

In the historical implementation of SQL functions (if they don't get
inlined), we built plans for all the contained queries at first call
within an outer query, and then re-used those plans for the duration
of the outer query, and then forgot everything. This was not ideal,
not least because the plans could not be customized to specific values
of the function's parameters. Our plancache infrastructure seems
mature enough to be used here. That will solve both the problem with
not being able to build custom plans and the problem with not being
able to share work across successive outer queries.

Aside from those performance concerns, this change fixes a
longstanding bugaboo with SQL functions: you could not write DDL that
would affect later statements in the same function. That's mostly
still true with new-style SQL functions, since the results of parse
analysis are baked into the stored query trees (and protected by
dependency records). But for old-style SQL functions, it will now
work much as it does with PL/pgSQL functions, because we delay parse
analysis and planning of each query until we're ready to run it.
Some edge cases that require replanning are now handled better too;
see for example the new rowsecurity test, where we now detect an RLS
context change that was previously missed.

One other edge-case change that might be worthy of a release note
is that we now insist that a SQL function's result be generated
by the physically-last query within it. Previously, if the last
original query was deleted by a DO INSTEAD NOTHING rule, we'd be
willing to take the result from the preceding query instead.
This behavior was undocumented except in source-code comments,
and it seems hard to believe that anyone's relying on it.

Along the way to this feature, we needed a few infrastructure changes:

* The plancache can now take either a raw parse tree or an
analyzed-but-not-rewritten Query as the starting point for a
CachedPlanSource. If given a Query, it is caller's responsibility
that nothing will happen to invalidate that form of the query.
We use this for new-style SQL functions, where what's in pg_proc is
serialized Query(s) and we trust the dependency mechanism to disallow
DDL that would break those.

* The plancache now offers a way to invoke a post-rewrite callback
to examine/modify the rewritten parse tree when it is rebuilding
the parse trees after a cache invalidation. We need this because
SQL functions sometimes adjust the parse tree to make its output
exactly match the declared result type; if the plan gets rebuilt,
that has to be re-done.

* There is a new backend module utils/cache/funccache.c that
abstracts the idea of caching data about a specific function
usage (a particular function and set of input data types).
The code in it is moved almost verbatim from PL/pgSQL, which
has done that for a long time. We use that logic now for
SQL-language functions too, and maybe other PLs will have use
for it in the future.

Author: Alexander Pyhalov <a(dot)pyhalov(at)postgrespro(dot)ru>
Co-authored-by: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Reviewed-by: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
Discussion: https://postgr.es/m/8216639.NyiUUSuA9g@aivenlaptop

Branch
------
master

Details
-------
https://git.postgresql.org/pg/commitdiff/0dca5d68d7bebf2c1036fd84875533afef6df992

Modified Files
--------------
doc/src/sgml/xfunc.sgml | 15 -
src/backend/catalog/pg_proc.c | 2 +-
src/backend/executor/functions.c | 1391 +++++++++++++-------
src/backend/optimizer/util/clauses.c | 4 +-
src/backend/parser/analyze.c | 39 +
src/backend/utils/cache/Makefile | 1 +
src/backend/utils/cache/funccache.c | 612 +++++++++
src/backend/utils/cache/meson.build | 1 +
src/backend/utils/cache/plancache.c | 191 ++-
src/include/executor/functions.h | 3 +-
src/include/parser/analyze.h | 1 +
src/include/utils/funccache.h | 134 ++
src/include/utils/plancache.h | 31 +-
src/pl/plpgsql/src/pl_comp.c | 429 +-----
src/pl/plpgsql/src/pl_funcs.c | 9 +-
src/pl/plpgsql/src/pl_handler.c | 15 +-
src/pl/plpgsql/src/plpgsql.h | 45 +-
.../test_extensions/expected/test_extensions.out | 2 +-
src/test/regress/expected/create_function_sql.out | 57 +-
src/test/regress/expected/rangefuncs.out | 2 +-
src/test/regress/expected/rowsecurity.out | 51 +
src/test/regress/sql/create_function_sql.sql | 34 +
src/test/regress/sql/rowsecurity.sql | 44 +
src/tools/pgindent/typedefs.list | 8 +
24 files changed, 2132 insertions(+), 989 deletions(-)

Browse pgsql-committers by date

  From Date Subject
Next Message Andres Freund 2025-04-02 19:35:39 pgsql: Remove HeapBitmapScan's skip_fetch optimization
Previous Message Heikki Linnakangas 2025-04-02 17:18:25 pgsql: Add GiST and btree sortsupport routines for range types