Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error

Lists: Postg토토 핫SQL : Postg토토 핫SQL 메일 링리스트 : 2024-06-02 이후 PGSQL-BUGS 15:42
From: Mor Lehr <mor(dot)lehr(at)deel(dot)com>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2024-06-02 11:24:28
Message-ID: CALyvM2bp_CXMH_Gyq87pmHJRuZDEhV40u9VP8rX=CAnEt2wUXg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-bugs

Hi,

I would like to report a potential bug in postgres 15.4, also reproduced on
15.6.

*The exact sequence of steps:*
Connect to a postgres 15.4 database and run the following statements:

CREATE TABLE foo3(id serial PRIMARY key, txt text);

INSERT INTO foo3 (txt) VALUES ('aaa'),('bbb');

DO $$

DECLARE

l_cnt int;

BEGIN

l_cnt := 1

DELETE FROM foo3 WHERE id=1;

END; $$;

*The output you got:*

1. The script passes (no error message) even though there's a missing
semicolon (;) after "l_cnt := 1"
2. The script doesn't actually delete the record from foo3

This caused us a production issue where we thought changes were applied
(script passed successfully) but changes weren't actually applied.

If I move the line "l_cnt := 1" to after the DELETE statement like so:

DO $$

DECLARE

l_cnt int;

BEGIN

DELETE FROM foo3 WHERE id=1;

l_cnt := 1

END; $$;

I get the error - as expected:

SQL Error [42601]: ERROR: syntax error at end of input
Position: 89

Furthermore, replacing the DELETE statement with an UPDATE statement in the
original code does raise an error:

DO $$

DECLARE

l_cnt int;

BEGIN

l_cnt := 1

UPDATE foo3 SET txt='ccc' WHERE id=1;

END; $$;

SQL Error [42601]: ERROR: syntax error at or near "foo3"
Position: 62

But adding the semicolon - it works correctly with either UPDATE or DELETE.

I ran the original code using the following clients to make sure it's not a
client problem:

1. psql

2. DBeaver using standard JDBC drivers

3. Flyway using JDBC drivers

*Versions:*

PostgreSQL 15.6 (Homebrew) on x86_64-apple-darwin23.2.0, compiled by Apple
clang version 15.0.0 (clang-1500.1.0.2.5), 64-bit l - running locally on my
MacBook

PostgreSQL 15.4 on aarch64-unknown-linux-gnu, compiled by
aarch64-unknown-linux-gnu-gcc (GCC) 9.5.0, 64-bit - running on AWS RDS
Aurora

*Installed Extensions (On AWS RDS):*

oid |extname
|extowner|extnamespace|extrelocatable|extversion|extconfig |extcondition|
----------+-------------------------+--------+------------+--------------+----------+------------+------------+
16463|btree_gist | 10| 2200|true
|1.7 |NULL |NULL |
1463651797|deel_password_check_rules| 16399| 2200|false
|1.0 |NULL |NULL |
16464|fuzzystrmatch | 10| 2200|true
|1.1 |NULL |NULL |
958297705|pg_repack | 10| 2200|false
|1.4.8 |NULL |NULL |
16465|pg_stat_statements | 10| 2200|true
|1.9 |NULL |NULL |
1463506085|pg_tle | 10| 1463506084|false
|1.1.1 |{1463506117}|{""} |
16467|pg_trgm | 10| 2200|true
|1.6 |NULL |NULL |
16468|pgcrypto | 10| 2200|true
|1.3 |NULL |NULL |
14498|plpgsql | 10| 11|false
|1.0 |NULL |NULL |
16469|postgres_fdw | 10| 2200|true
|1.1 |NULL |NULL |
16470|tablefunc | 10| 2200|true
|1.0 |NULL |NULL |
16471|unaccent | 10| 2200|true
|1.1 |NULL |NULL |
16472|uuid-ossp | 10| 2200|true
|1.1 |NULL |NULL |

Please let me know what other information I can provide.

Thanks,

Mor


From: "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>
To: Mor Lehr <mor(dot)lehr(at)deel(dot)com>
Cc: "pgsql-bugs(at)lists(dot)postgresql(dot)org" <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2024-06-02 15:19:12
Message-ID: CAKFQuwZJUc8pqt402u9VjAEgGEMR-Rbu2b5nieeJ_bUzQChrXA@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-bugs

On Sunday, June 2, 2024, Mor Lehr <mor(dot)lehr(at)deel(dot)com> wrote:

> Hi,
>
> I would like to report a potential bug in postgres 15.4, also reproduced
> on 15.6.
>
> *The exact sequence of steps:*
> Connect to a postgres 15.4 database and run the following statements:
>
> CREATE TABLE foo3(id serial PRIMARY key, txt text);
>
> INSERT INTO foo3 (txt) VALUES ('aaa'),('bbb');
>
> DO $$
>
> DECLARE
>
> l_cnt int;
>
> BEGIN
>
> l_cnt := 1
>
> DELETE FROM foo3 WHERE id=1;
>
> END; $$;
>
>
> *The output you got:*
>
> 1. The script passes (no error message) even though there's a missing
> semicolon (;) after "l_cnt := 1"
> 2. The script doesn't actually delete the record from foo3
>
>
>
I think you just wrote the equivalent of:

l_cnt := (select 1 as delete from foo3 where id=1);

Which is a valid query.

David J.


From: Mor Lehr <mor(dot)lehr(at)deel(dot)com>
To: "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>
Cc: pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2024-06-02 15:26:41
Message-ID: CALyvM2ZJytKx+HfayNkvdJ3YcfeCkp0nc8H0gL0bYfFNPBF4Yw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-bugs

Thanks for the prompt reply.
Can you please refer me to the section in the documentation that describes
this behavior?
This (automatically interperting 1 as select 1) is totally an unexpected
behavior for me.

Thanks again.
-Mor.

On Sun, Jun 2, 2024, 18:19 David G. Johnston <david(dot)g(dot)johnston(at)gmail(dot)com>
wrote:

> On Sunday, June 2, 2024, Mor Lehr <mor(dot)lehr(at)deel(dot)com> wrote:
>
>> Hi,
>>
>> I would like to report a potential bug in postgres 15.4, also reproduced
>> on 15.6.
>>
>> *The exact sequence of steps:*
>> Connect to a postgres 15.4 database and run the following statements:
>>
>> CREATE TABLE foo3(id serial PRIMARY key, txt text);
>>
>> INSERT INTO foo3 (txt) VALUES ('aaa'),('bbb');
>>
>> DO $$
>>
>> DECLARE
>>
>> l_cnt int;
>>
>> BEGIN
>>
>> l_cnt := 1
>>
>> DELETE FROM foo3 WHERE id=1;
>>
>> END; $$;
>>
>>
>> *The output you got:*
>>
>> 1. The script passes (no error message) even though there's a missing
>> semicolon (;) after "l_cnt := 1"
>> 2. The script doesn't actually delete the record from foo3
>>
>>
>>
> I think you just wrote the equivalent of:
>
> l_cnt := (select 1 as delete from foo3 where id=1);
>
> Which is a valid query.
>
> David J.
>
>
>


From: "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>
To: Mor Lehr <mor(dot)lehr(at)deel(dot)com>
Cc: "pgsql-bugs(at)lists(dot)postgresql(dot)org" <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2024-06-02 15:31:42
Message-ID: CAKFQuwaSrWcvZTWEMfzTRLTKkhVJMCqS1Ebibk7U6QRQJPLa3w@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-bugs

On Sunday, June 2, 2024, Mor Lehr <mor(dot)lehr(at)deel(dot)com> wrote:

> Thanks for the prompt reply.
> Can you please refer me to the section in the documentation that describes
> this behavior?
> This (automatically interperting 1 as select 1) is totally an unexpected
> behavior for me.
>

/docs/current/plpgsql-statements.html#PLPGSQL-STATEMENTS-ASSIGNMENT

“As explained previously, the expression in such a statement is evaluated
by means of an SQL SELECT command sent to the main database engine.”

David J.


From: Mor Lehr <mor(dot)lehr(at)deel(dot)com>
To: "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>
Cc: pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2024-06-02 15:42:38
Message-ID: CALyvM2ZcywTKdxgYZhAXjmdxTuBT2RyW+cn0XwwHxXbfvXMBEA@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: Postg토토 핫SQL : Postg토토 핫SQL 메일 링리스트 : 2024-06-02 이후 PGSQL-BUGS 15:42

Thanks for the reference.
We learn new stuff every day.

You can close the case.
Thanks, Mor

On Sun, Jun 2, 2024, 18:31 David G. Johnston <david(dot)g(dot)johnston(at)gmail(dot)com>
wrote:

> On Sunday, June 2, 2024, Mor Lehr <mor(dot)lehr(at)deel(dot)com> wrote:
>
>> Thanks for the prompt reply.
>> Can you please refer me to the section in the documentation that
>> describes this behavior?
>> This (automatically interperting 1 as select 1) is totally an unexpected
>> behavior for me.
>>
>
>
> /docs/current/plpgsql-statements.html#PLPGSQL-STATEMENTS-ASSIGNMENT
>
> “As explained previously, the expression in such a statement is evaluated
> by means of an SQL SELECT command sent to the main database engine.”
>
> David J.
>
>


From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>
Cc: Mor Lehr <mor(dot)lehr(at)deel(dot)com>, "pgsql-bugs(at)lists(dot)postgresql(dot)org" <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2024-06-02 22:18:51
Message-ID: 2365647.1717366731@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-bugs

"David G. Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com> writes:
> I think you just wrote the equivalent of:
> l_cnt := (select 1 as delete from foo3 where id=1);
> Which is a valid query.

Still another example of the folly of letting AS be optional.
I don't suppose we can ever undo that though.

regards, tom lane


From: Erik Wienhold <ewie(at)ewie(dot)name>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>, Mor Lehr <mor(dot)lehr(at)deel(dot)com>, "pgsql-bugs(at)lists(dot)postgresql(dot)org" <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2024-06-03 16:45:54
Message-ID: 30ebb5a3-ca61-4b74-bb98-7c2dc0622e52@ewie.name
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-bugs

On 2024-06-03 00:18 +0200, Tom Lane wrote:
> "David G. Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com> writes:
> > I think you just wrote the equivalent of:
> > l_cnt := (select 1 as delete from foo3 where id=1);
> > Which is a valid query.
>
> Still another example of the folly of letting AS be optional.
> I don't suppose we can ever undo that though.

How about inventing an opt-in strict mode (like in Perl or JavaScript)
that prevents certain footguns? For example, disallowing bare column
labels.

That could be enabled for the current session or transaction:

SET strict_parsing = { on | off };

Or just for individual routines:

CREATE PROCEDURE myproc()
SET strict_parsing = { on | off }
LANGUAGE plpgsql ...

--
Erik


From: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
To: Erik Wienhold <ewie(at)ewie(dot)name>
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>, Mor Lehr <mor(dot)lehr(at)deel(dot)com>, "pgsql-bugs(at)lists(dot)postgresql(dot)org" <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2024-06-03 18:11:40
Message-ID: CAFj8pRDm=bqd7HBbi9omLxjvC+DLKezrZooQs=96GGsCxRdiYg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-bugs

po 3. 6. 2024 v 18:46 odesílatel Erik Wienhold <ewie(at)ewie(dot)name> napsal:

> On 2024-06-03 00:18 +0200, Tom Lane wrote:
> > "David G. Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com> writes:
> > > I think you just wrote the equivalent of:
> > > l_cnt := (select 1 as delete from foo3 where id=1);
> > > Which is a valid query.
> >
> > Still another example of the folly of letting AS be optional.
> > I don't suppose we can ever undo that though.
>
> How about inventing an opt-in strict mode (like in Perl or JavaScript)
> that prevents certain footguns? For example, disallowing bare column
> labels.
>
> That could be enabled for the current session or transaction:
>
> SET strict_parsing = { on | off };
>
> Or just for individual routines:
>
> CREATE PROCEDURE myproc()
> SET strict_parsing = { on | off }
> LANGUAGE plpgsql ...
>
>
Probably it is not bad idea - it can be generally useful

But I think it is better to introduce a new entry for plpgsql expressions
in gram.y.

Unfortunately it is not a compatible change. Years ago was popular to use a
pattern

a := tab.a FROM tab

instead correct

a := (SELECT tab.a FROM tab)

or

SELECT tab.a FROM tab INTO a;

Regards

Pavel

> --
> Erik
>
>
>


From: Mor Lehr <mor(dot)lehr(at)deel(dot)com>
To: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
Cc: Erik Wienhold <ewie(at)ewie(dot)name>, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>, "pgsql-bugs(at)lists(dot)postgresql(dot)org" <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2024-06-04 06:39:09
Message-ID: CALyvM2bE8j-E-dPRtXzpLXVccBFJn6F-GUhsJnaoFdRq_jU7UQ@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-bugs

>
> How about inventing an opt-in strict mode

That can be useful at the session level, because we use anonymous blocks
quite often.
I assume if such a setting existed - we would have used it in the original
scenario.

Thanks again,
-Mor

On Mon, Jun 3, 2024 at 9:12 PM Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
wrote:

>
>
> po 3. 6. 2024 v 18:46 odesílatel Erik Wienhold <ewie(at)ewie(dot)name> napsal:
>
>> On 2024-06-03 00:18 +0200, Tom Lane wrote:
>> > "David G. Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com> writes:
>> > > I think you just wrote the equivalent of:
>> > > l_cnt := (select 1 as delete from foo3 where id=1);
>> > > Which is a valid query.
>> >
>> > Still another example of the folly of letting AS be optional.
>> > I don't suppose we can ever undo that though.
>>
>> How about inventing an opt-in strict mode (like in Perl or JavaScript)
>> that prevents certain footguns? For example, disallowing bare column
>> labels.
>>
>> That could be enabled for the current session or transaction:
>>
>> SET strict_parsing = { on | off };
>>
>> Or just for individual routines:
>>
>> CREATE PROCEDURE myproc()
>> SET strict_parsing = { on | off }
>> LANGUAGE plpgsql ...
>>
>>
> Probably it is not bad idea - it can be generally useful
>
> But I think it is better to introduce a new entry for plpgsql expressions
> in gram.y.
>
> Unfortunately it is not a compatible change. Years ago was popular to use
> a pattern
>
> a := tab.a FROM tab
>
> instead correct
>
> a := (SELECT tab.a FROM tab)
>
> or
>
> SELECT tab.a FROM tab INTO a;
>
> Regards
>
> Pavel
>
>
>
>> --
>> Erik
>>
>>
>>


From: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
To: Mor Lehr <mor(dot)lehr(at)deel(dot)com>
Cc: Erik Wienhold <ewie(at)ewie(dot)name>, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>, "pgsql-bugs(at)lists(dot)postgresql(dot)org" <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2024-06-10 11:56:23
Message-ID: CAFj8pRCiLPNyYrWwyDbYfsMKwtzXMmpY4xoS57XvqwXpRnFB4g@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-bugs

Hi

út 4. 6. 2024 v 8:39 odesílatel Mor Lehr <mor(dot)lehr(at)deel(dot)com> napsal:

> How about inventing an opt-in strict mode
>
>
> That can be useful at the session level, because we use anonymous blocks
> quite often.
> I assume if such a setting existed - we would have used it in the original
> scenario.
>
> Thanks again,
> -Mor
>
> On Mon, Jun 3, 2024 at 9:12 PM Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
> wrote:
>
>>
>>
>> po 3. 6. 2024 v 18:46 odesílatel Erik Wienhold <ewie(at)ewie(dot)name> napsal:
>>
>>> On 2024-06-03 00:18 +0200, Tom Lane wrote:
>>> > "David G. Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com> writes:
>>> > > I think you just wrote the equivalent of:
>>> > > l_cnt := (select 1 as delete from foo3 where id=1);
>>> > > Which is a valid query.
>>> >
>>> > Still another example of the folly of letting AS be optional.
>>> > I don't suppose we can ever undo that though.
>>>
>>> How about inventing an opt-in strict mode (like in Perl or JavaScript)
>>> that prevents certain footguns? For example, disallowing bare column
>>> labels.
>>>
>>> That could be enabled for the current session or transaction:
>>>
>>> SET strict_parsing = { on | off };
>>>
>>> Or just for individual routines:
>>>
>>> CREATE PROCEDURE myproc()
>>> SET strict_parsing = { on | off }
>>> LANGUAGE plpgsql ...
>>>
>>>
>> Probably it is not bad idea - it can be generally useful
>>
>> But I think it is better to introduce a new entry for plpgsql expressions
>> in gram.y.
>>
>> Unfortunately it is not a compatible change. Years ago was popular to use
>> a pattern
>>
>> a := tab.a FROM tab
>>
>> instead correct
>>
>> a := (SELECT tab.a FROM tab)
>>
>> or
>>
>> SELECT tab.a FROM tab INTO a;
>>
>> Regards
>>
>> Pavel
>>
>
I wrote an experimental patch that enforces strict syntax for PL/pgSQL
expressions. This patch is a proof concept and shows impacts of the change
(check-world tests passed)

Unfortunately it introduces break compatibility - with this patch the odd
syntax (that is undocumented) is not supported. Something like

DECLARE _x int := x FROM foo WHERE id = _arg;

should not be written in strict mode;

This patch very well fix reported issue:

(2024-06-10 12:06:43) postgres=# CREATE TABLE foo3(id serial PRIMARY key,
txt text);
CREATE TABLE
(2024-06-10 12:07:13) postgres=# INSERT INTO foo3 (txt) VALUES
('aaa'),('bbb');
INSERT 0 2
(2024-06-10 12:07:33) postgres=# DO $$
DECLARE
l_cnt int;
BEGIN
l_cnt := 1
DELETE FROM foo3 WHERE id=1;
END; $$;
ERROR: syntax error at or near "DELETE"
LINE 11: DELETE FROM foo3 WHERE id=1;
^

Personally, I think it can be a strong step forward (we can use deeper
integration of plpgsql with SQL parser which was not possible before).

Because it introduces a compatibility break I don't propose to use it by
default. I see two possible ways, how this check can be used:

1. we can use plpgsql.extra_errors (
/docs/current/plpgsql-development-tips.html#PLPGSQL-EXTRA-CHECKS
) and introduce a check named (maybe) strict_expr_syntax. Because in this
case the warning cannot be raised, then this check cannot be used in
plpgsql.extra_warnings. I think it can work nicely.

2. if @1 will not be possible, the minimalist implementation can be based
on a new public entry to SQL parser. In this case, I can do the proposed
check at least from plpgsql_check.

Do you see any other possibilities?

This patch is just a proof concept. I didn't implement any mechanism to
switch from default mode to strict mode (I don't propose strict mode as
default) now.

I think it can increase the robustness of plpgsql, on the other hand it
introduces compatibility breaks and I understand related problems.

The change of definition of PLpgSQL_Expr has an impact on OPEN and CASE
PLpgSQL statements that use multicolumn results.

Regards

Pavel

>
>>
>>
>>> --
>>> Erik
>>>
>>>
>>>

Attachment Content-Type Size
plpgsql-strict-expr.patch text/x-patch 26.4 KB

From: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
To: Mor Lehr <mor(dot)lehr(at)deel(dot)com>
Cc: Erik Wienhold <ewie(at)ewie(dot)name>, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>, "pgsql-bugs(at)lists(dot)postgresql(dot)org" <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2024-06-10 15:00:41
Message-ID: CAFj8pRCEenYWkRb0toQOOhMVmVni3bz-wmVMFWsbHa__YLXRHg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-bugs

po 10. 6. 2024 v 13:56 odesílatel Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
napsal:

> Hi
>
> út 4. 6. 2024 v 8:39 odesílatel Mor Lehr <mor(dot)lehr(at)deel(dot)com> napsal:
>
>> How about inventing an opt-in strict mode
>>
>>
>> That can be useful at the session level, because we use anonymous blocks
>> quite often.
>> I assume if such a setting existed - we would have used it in the
>> original scenario.
>>
>> Thanks again,
>> -Mor
>>
>> On Mon, Jun 3, 2024 at 9:12 PM Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
>> wrote:
>>
>>>
>>>
>>> po 3. 6. 2024 v 18:46 odesílatel Erik Wienhold <ewie(at)ewie(dot)name> napsal:
>>>
>>>> On 2024-06-03 00:18 +0200, Tom Lane wrote:
>>>> > "David G. Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com> writes:
>>>> > > I think you just wrote the equivalent of:
>>>> > > l_cnt := (select 1 as delete from foo3 where id=1);
>>>> > > Which is a valid query.
>>>> >
>>>> > Still another example of the folly of letting AS be optional.
>>>> > I don't suppose we can ever undo that though.
>>>>
>>>> How about inventing an opt-in strict mode (like in Perl or JavaScript)
>>>> that prevents certain footguns? For example, disallowing bare column
>>>> labels.
>>>>
>>>> That could be enabled for the current session or transaction:
>>>>
>>>> SET strict_parsing = { on | off };
>>>>
>>>> Or just for individual routines:
>>>>
>>>> CREATE PROCEDURE myproc()
>>>> SET strict_parsing = { on | off }
>>>> LANGUAGE plpgsql ...
>>>>
>>>>
>>> Probably it is not bad idea - it can be generally useful
>>>
>>> But I think it is better to introduce a new entry for plpgsql
>>> expressions in gram.y.
>>>
>>> Unfortunately it is not a compatible change. Years ago was popular to
>>> use a pattern
>>>
>>> a := tab.a FROM tab
>>>
>>> instead correct
>>>
>>> a := (SELECT tab.a FROM tab)
>>>
>>> or
>>>
>>> SELECT tab.a FROM tab INTO a;
>>>
>>> Regards
>>>
>>> Pavel
>>>
>>
> I wrote an experimental patch that enforces strict syntax for PL/pgSQL
> expressions. This patch is a proof concept and shows impacts of the change
> (check-world tests passed)
>
> Unfortunately it introduces break compatibility - with this patch the odd
> syntax (that is undocumented) is not supported. Something like
>
> DECLARE _x int := x FROM foo WHERE id = _arg;
>
> should not be written in strict mode;
>
> This patch very well fix reported issue:
>
> (2024-06-10 12:06:43) postgres=# CREATE TABLE foo3(id serial PRIMARY key,
> txt text);
> CREATE TABLE
> (2024-06-10 12:07:13) postgres=# INSERT INTO foo3 (txt) VALUES
> ('aaa'),('bbb');
> INSERT 0 2
> (2024-06-10 12:07:33) postgres=# DO $$
> DECLARE
> l_cnt int;
> BEGIN
> l_cnt := 1
> DELETE FROM foo3 WHERE id=1;
> END; $$;
> ERROR: syntax error at or near "DELETE"
> LINE 11: DELETE FROM foo3 WHERE id=1;
> ^
>
> Personally, I think it can be a strong step forward (we can use deeper
> integration of plpgsql with SQL parser which was not possible before).
>
> Because it introduces a compatibility break I don't propose to use it by
> default. I see two possible ways, how this check can be used:
>
> 1. we can use plpgsql.extra_errors (
> /docs/current/plpgsql-development-tips.html#PLPGSQL-EXTRA-CHECKS
> ) and introduce a check named (maybe) strict_expr_syntax. Because in this
> case the warning cannot be raised, then this check cannot be used in
> plpgsql.extra_warnings. I think it can work nicely.
>
> 2. if @1 will not be possible, the minimalist implementation can be based
> on a new public entry to SQL parser. In this case, I can do the proposed
> check at least from plpgsql_check.
>
> Do you see any other possibilities?
>
> This patch is just a proof concept. I didn't implement any mechanism to
> switch from default mode to strict mode (I don't propose strict mode as
> default) now.
>
> I think it can increase the robustness of plpgsql, on the other hand it
> introduces compatibility breaks and I understand related problems.
>
> The change of definition of PLpgSQL_Expr has an impact on OPEN and CASE
> PLpgSQL statements that use multicolumn results.
>

Note - the SQL/PSM standard allow syntax

SET var = (SELECT col FROM tab)

as shorter variant of

SELECT col INTO var FROM tab ;

so

var := (SELECT col FROM tab)

is +/- ANSI/SQL syntax. It is not my invention. The subquery is used as a
guard against returning multiple rows.

The proprietary Postgre syntax is a little bit faster - 80us x 95 us,
doesn't raise an exception when returning more rows (I am not sure if this
is any benefit or not - it is possibly dangerous, but it can reduce the
necessity of subtransaction in some patterns). Instead of proprietary
syntax, SELECT INTO can be used for these cases.

Regards

Pavel

> Regards
>
> Pavel
>
>
>>
>>>
>>>
>>>> --
>>>> Erik
>>>>
>>>>
>>>>


From: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
To: Mor Lehr <mor(dot)lehr(at)deel(dot)com>
Cc: "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>, pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2025-02-06 06:47:35
Message-ID: CAFj8pRBWPVU9yMCAcb24pGNrdP3YCwbUjy3pnZtn2zWqqdkrRw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-bugs

Hi

ne 2. 6. 2024 v 18:25 odesílatel Mor Lehr <mor(dot)lehr(at)deel(dot)com> napsal:

> Thanks for the reference.
> We learn new stuff every day.
>
> You can close the case.
> Thanks, Mor
>
>
plpgsql_check can now detect this issue

https://okbob.blogspot.com/2025/02/plpgsqlcheck-raise-warning-when-syntax.html

Regards

Pavel

> On Sun, Jun 2, 2024, 18:31 David G. Johnston <david(dot)g(dot)johnston(at)gmail(dot)com>
> wrote:
>
>> On Sunday, June 2, 2024, Mor Lehr <mor(dot)lehr(at)deel(dot)com> wrote:
>>
>>> Thanks for the prompt reply.
>>> Can you please refer me to the section in the documentation that
>>> describes this behavior?
>>> This (automatically interperting 1 as select 1) is totally an unexpected
>>> behavior for me.
>>>
>>
>>
>> /docs/current/plpgsql-statements.html#PLPGSQL-STATEMENTS-ASSIGNMENT
>>
>> “As explained previously, the expression in such a statement is evaluated
>> by means of an SQL SELECT command sent to the main database engine.”
>>
>> David J.
>>
>>


From: Mor Lehr <mor(dot)lehr(at)deel(dot)com>
To: Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
Cc: "David G(dot) Johnston" <david(dot)g(dot)johnston(at)gmail(dot)com>, pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Re: Missing semicolumn in anonymous plpgsql block does not raise syntax error
Date: 2025-02-06 10:10:26
Message-ID: CALyvM2b+5ERWeUK5av2udxMzGk18eaUitzrrAAM7h9ZTz=yMRg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-bugs

Thanks for not letting this be forgotten :)
Unfortunately, plpgsql_check does not help me because it's not supported on
AWS.
I also saw you wrote a patch which is still pending, I will probably have
to wait for that.

Thanks again,
Mor

On Thu, Feb 6, 2025 at 7:48 AM Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>
wrote:

> Hi
>
> ne 2. 6. 2024 v 18:25 odesílatel Mor Lehr <mor(dot)lehr(at)deel(dot)com> napsal:
>
>> Thanks for the reference.
>> We learn new stuff every day.
>>
>> You can close the case.
>> Thanks, Mor
>>
>>
> plpgsql_check can now detect this issue
>
>
> https://okbob.blogspot.com/2025/02/plpgsqlcheck-raise-warning-when-syntax.html
>
> Regards
>
> Pavel
>
>
>> On Sun, Jun 2, 2024, 18:31 David G. Johnston <david(dot)g(dot)johnston(at)gmail(dot)com>
>> wrote:
>>
>>> On Sunday, June 2, 2024, Mor Lehr <mor(dot)lehr(at)deel(dot)com> wrote:
>>>
>>>> Thanks for the prompt reply.
>>>> Can you please refer me to the section in the documentation that
>>>> describes this behavior?
>>>> This (automatically interperting 1 as select 1) is totally an
>>>> unexpected behavior for me.
>>>>
>>>
>>>
>>> /docs/current/plpgsql-statements.html#PLPGSQL-STATEMENTS-ASSIGNMENT
>>>
>>> “As explained previously, the expression in such a statement is
>>> evaluated by means of an SQL SELECT command sent to the main database
>>> engine.”
>>>
>>> David J.
>>>
>>>