1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-31 22:04:40 +03:00

Re-implement pl/pgsql's expression and assignment parsing.

Invent new RawParseModes that allow the core grammar to handle
pl/pgsql expressions and assignments directly, and thereby get rid
of a lot of hackery in pl/pgsql's parser.  This moves a good deal
of knowledge about pl/pgsql into the core code: notably, we have to
invent a CoercionContext that matches pl/pgsql's (rather dubious)
historical behavior for assignment coercions.  That's getting away
from the original idea of pl/pgsql as an arm's-length extension of
the core, but really we crossed that bridge a long time ago.

The main advantage of doing this is that we can now use the core
parser to generate FieldStore and/or SubscriptingRef nodes to handle
assignments to pl/pgsql variables that are records or arrays.  That
fixes a number of cases that had never been implemented in pl/pgsql
assignment, such as nested records and array slicing, and it allows
pl/pgsql assignment to support the datatype-specific subscripting
behaviors introduced in commit c7aba7c14.

There are cosmetic benefits too: when a syntax error occurs in a
pl/pgsql expression, the error report no longer includes the confusing
"SELECT" keyword that used to get prefixed to the expression text.
Also, there seem to be some small speed gains.

Discussion: https://postgr.es/m/4165684.1607707277@sss.pgh.pa.us
This commit is contained in:
Tom Lane
2021-01-04 11:52:00 -05:00
parent 844fe9f159
commit c9d5298485
32 changed files with 1081 additions and 159 deletions

View File

@ -946,8 +946,8 @@ PREPARE <replaceable>statement_name</replaceable>(integer, integer) AS SELECT $1
database engine. The expression must yield a single value (possibly
a row value, if the variable is a row or record variable). The target
variable can be a simple variable (optionally qualified with a block
name), a field of a row or record variable, or an element of an array
that is a simple variable or field. Equal (<literal>=</literal>) can be
name), a field of a row or record target, or an element or slice of
an array target. Equal (<literal>=</literal>) can be
used instead of PL/SQL-compliant <literal>:=</literal>.
</para>
@ -968,8 +968,25 @@ PREPARE <replaceable>statement_name</replaceable>(integer, integer) AS SELECT $1
<programlisting>
tax := subtotal * 0.06;
my_record.user_id := 20;
my_array[j] := 20;
my_array[1:3] := array[1,2,3];
complex_array[n].realpart = 12.3;
</programlisting>
</para>
<para>
It's useful to know that what follows the assignment operator is
essentially treated as a <literal>SELECT</literal> command; as long
as it returns a single row and column, it will work. Thus for example
one can write something like
<programlisting>
total_sales := sum(quantity) from sales;
</programlisting>
This provides an effect similar to the single-row <literal>SELECT
... INTO</literal> syntax described in
<xref linkend="plpgsql-statements-sql-onerow"/>. However, that syntax
is more portable.
</para>
</sect2>
<sect2 id="plpgsql-statements-sql-noresult">