Re: Rethinking plpgsql's assignment implementation

From: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: Chapman Flack <chap(at)anastigmatix(dot)net>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: Rethinking plpgsql's assignment implementation
Date: 2020-12-14 06:57:21
Message-ID: CAFj8pRDi-WT2VaR+DpyAe+H3Pf9xgAozSj+SzhrZYuFSZ3u_Jw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

ne 13. 12. 2020 v 22:41 odesílatel Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> napsal:

> I wrote:
> > So my idea here is to add a parsing-mode option to raw_parser(),
> > which would be an enum with values like "normal SQL statement",
> > "expression only", "type name", "plpgsql assignment statement".
>
> Here's a fleshed-out patch series that attacks things that way.
> I'm a lot better pleased with this than with my original approach.
>
> 0001 creates the basic infrastructure for "raw parse modes", and as
> proof of concept simplifies typeStringToTypeName(). There's a minor
> functional improvement there, which is that we can now use the core
> parser's error cursor position, so instead of
>
> regression=# do $$ declare x int[23/] ; begin end $$;
> ERROR: syntax error at or near "/"
> LINE 1: do $$ declare x int[23/] ; begin end $$;
> ^
> CONTEXT: invalid type name "int[23/] "
>
> you get
>
> regression=# do $$ declare x int[23/] ; begin end $$;
> ERROR: syntax error at or near "/"
> LINE 1: do $$ declare x int[23/] ; begin end $$;
> ^
> CONTEXT: invalid type name "int[23/] "
>
> It's possible we could dispense with the error context callback
> in typeStringToTypeName altogether, but I've not experimented much.
>
>
> 0002 tackles the next problem, which is to make this feature accessible
> through SPI. There are a couple of possibly-controversial choices here.
>
> Following the principle that we should avoid changing documented SPI
> interfaces, we need a new version of SPI_prepare to pass RawParseMode
> through. This'll be the fourth one :-(, so I decided it was time to
> try to make a definition that can stay API-compatible through future
> changes. So it takes a struct of options, and I added a promise that
> zeroing the struct is enough to guarantee forward compatibility
> through future additions.
>
> This leaves both of the previous iterations, SPI_prepare_cursor
> and SPI_prepare_params, unused anywhere in the core code.
> I suppose we can't kill them (codesearch.debian.net knows of some
> external uses) but I propose to mark them deprecated, with an eye
> to at least removing their documentation someday.
>
> I did not want to add a RawParseMode parameter to pg_parse_query(),
> because that would have affected a larger number of unrelated modules,
> and it would not have been great from a header-inclusion footprint
> standpoint either. So I chose to pass down the mode from SPI by
> having it just call raw_parser() directly instead of going through
> pg_parse_query(). Perhaps this is a modularity violation, or perhaps
> there's somebody who really wants the extra tracing overhead in
> pg_parse_query() to apply to SPI queries. I'm open to discussing
> whether this should be done differently.
>
> (However, having made these two patches, I'm now wondering whether
> there is any rhyme or reason to the existing state of affairs
> with some callers going through pg_parse_query() while others use
> raw_parser() directly. It's hard to knock making a different
> choice in spi.c unless we have a coherent policy about which to
> use where.)
>
>
> Next, 0003 invents a raw parse mode for plpgsql expressions (which,
> in some contexts, can be pretty nearly whole SELECT statements),
> and uses that to get plpgsql out of the business of prefixing
> "SELECT " to user-written text. I would not have bothered with this
> as a standalone fix, but I think it does make for less-confusing
> error messages --- we've definitely had novices ask "where'd this
> SELECT come from?" in the past. (I cheated a bit on PERFORM, though.
> Unlike other places, it needs to allow UNION, so it can't use the
> same restricted syntax.)
>
> 0004 then reimplements plpgsql assignment. This is essentially the same
> patch I submitted before, but redesigned to work with the infrastructure
> from 0001-0003.
>
> 0005 adds documentation and test cases. It also fixes a couple
> of pre-existing problems that the plpgsql parser had with assigning
> to sub-fields of record fields, which I discovered while making the
> tests.
>
> Finally, 0006 removes plpgsql's ARRAYELEM datum type, on the grounds
> that we don't need it anymore. This might be a little controversial
> too, because there was still one way to reach the code: GET DIAGNOSTICS
> with an array element as target would do so. However, that seems like
> a pretty weird corner case. Reviewing the git history, I find that
> I added support for that in commit 55caaaeba; but a check of the
> associated discussion shows that there was no actual user request for
> that, I'd just done it because it was easy and seemed more symmetric.
> The amount of code involved here seems way more than is justified by
> that one case, so I think we should just take it out and lose the
> "feature". (I did think about whether GET DIAGNOSTICS could be
> reimplemented on top of the new infrastructure, but it wouldn't be
> easy because we don't have a SQL-expression representation of the
> GET DIAGNOSTICS values. Moreover, going in that direction would add
> an expression evaluation, making GET DIAGNOSTICS slower. So I think
> we should just drop it.)
>
>
It is a really great patch. I did fast check and I didn't find any
functionality issue

--
-- Name: footype; Type: TYPE; Schema: public; Owner: pavel
--

CREATE TYPE public.footype AS (
a integer,
b integer
);

ALTER TYPE public.footype OWNER TO pavel;

--
-- Name: bootype; Type: TYPE; Schema: public; Owner: pavel
--

CREATE TYPE public.bootype AS (
a integer,
f public.footype
);

ALTER TYPE public.bootype OWNER TO pavel;

--
-- Name: cootype; Type: TYPE; Schema: public; Owner: pavel
--

CREATE TYPE public.cootype AS (
a integer,
b integer[]
);

ALTER TYPE public.cootype OWNER TO pavel;

--
-- Name: dootype; Type: TYPE; Schema: public; Owner: pavel
--

CREATE TYPE public.dootype AS (
a integer,
b public.footype,
c public.footype[]
);

ALTER TYPE public.dootype OWNER TO pavel;

--
-- PostgreSQL database dump complete
--

postgres=# do $$
<<lab>>
declare
a footype[];
b bootype;
ba bootype[];
c cootype[];
d dootype[];
x int default 1;
begin
a[10] := row(10,20);
a[11] := (30,40);
a[3] := (0,0);
a[3].a := 100;
raise notice '%', a;
b.a := 100;
b.f.a := 1000;
raise notice '%', b;
ba[0] := b;

ba[0].a = 33; ba[0].f := row(33,33);
lab.ba[0].f.a := 1000000;
raise notice '%', ba;
c[0].a := 10000;
c[0].b := ARRAY[1,2,4];
lab.c[0].b[1] := 10000;
raise notice '% %', c, c[0].b[x];

d[0].a := 100;
d[0].b.a := 101;
d[0].c[x+1].a := 102;
raise notice '%', d;
end;
$$;
NOTICE:
[3:11]={"(100,0)",NULL,NULL,NULL,NULL,NULL,NULL,"(10,20)","(30,40)"}
NOTICE: (100,"(1000,)")
NOTICE: [0:0]={"(33,\"(1000000,33)\")"}
NOTICE: [0:0]={"(10000,\"{10000,2,4}\")"} 10000
NOTICE: [0:0]={"(100,\"(101,)\",\"[2:2]={\"\"(102,)\"\"}\")"}
DO

Regards

Pavel

> regards, tom lane
>
>

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Joel Mariadasan (jomariad) 2020-12-14 06:58:04 RE: pg_ctl.exe file deleted automatically
Previous Message Andrey Borodin 2020-12-14 06:31:32 Re: MultiXact\SLRU buffers configuration