ne 13. 12. 2020 v 22:41 odesílatel Tom Lane <t...@sss.pgh.pa.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
>
>

Reply via email to