pg_stat_statements: use spaces to indent in upgrade scripts

2024-09-23 Thread Karina Litskevich
Hi hackers,

I just noticed that all indents in upgrade scripts of pg_stat_statemets are
made using spaces, except for "CREATE FUNCTION pg_stat_statements_reset"
statement in pg_stat_statements--1.6--1.7.sql and
pg_stat_statements--1.10--1.11.sql.

I made a patch to fix it in pg_stat_statements--1.10--1.11.sql if it's not
too late for PostgreSQL 17 yet.

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/
From 2273e72e35fe2d4ff500a2127413121b1709be17 Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Mon, 23 Sep 2024 16:06:25 +0300
Subject: [PATCH v1] pg_stat_statements: use spaces to indent in upgrade
 scripts

---
 .../pg_stat_statements/pg_stat_statements--1.10--1.11.sql   | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/contrib/pg_stat_statements/pg_stat_statements--1.10--1.11.sql b/contrib/pg_stat_statements/pg_stat_statements--1.10--1.11.sql
index 0bb2c39771..86769184a3 100644
--- a/contrib/pg_stat_statements/pg_stat_statements--1.10--1.11.sql
+++ b/contrib/pg_stat_statements/pg_stat_statements--1.10--1.11.sql
@@ -70,9 +70,9 @@ CREATE VIEW pg_stat_statements AS
 GRANT SELECT ON pg_stat_statements TO PUBLIC;
 
 CREATE FUNCTION pg_stat_statements_reset(IN userid Oid DEFAULT 0,
-	IN dbid Oid DEFAULT 0,
-	IN queryid bigint DEFAULT 0,
-	IN minmax_only boolean DEFAULT false
+IN dbid Oid DEFAULT 0,
+IN queryid bigint DEFAULT 0,
+IN minmax_only boolean DEFAULT false
 )
 RETURNS timestamp with time zone
 AS 'MODULE_PATHNAME', 'pg_stat_statements_reset_1_11'
-- 
2.34.1



Re: Invalid "trailing junk" error message when non-English letters are used

2024-09-05 Thread Karina Litskevich
On Thu, Sep 5, 2024 at 6:07 PM Karina Litskevich
 wrote:
> In v3 of the patch I grouped all the *_junk rules together and included
> the suggested comment with a little added something.

Oops, I forgot to attach the patch, here it is.


Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/
From b993d45d34c0bff676bf439e75dfd8f58244f8ed Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Wed, 28 Aug 2024 11:52:25 +0300
Subject: [PATCH v3] Improve error message for rejecting trailing junk after
 numeric literals

Rejecting trailing junk after numeric literals was introduced in
commit 2549f066 to prevent scanning a number immediately followed
by an identifier without whitespace as number and identifier.
Unfortunately, all the tokens made to catch such numeric literals
followed by non-digits match a numeric literal and the next byte. The
lexemes found by these tokens are broken in case the next symbol after
a numeric literal is presented by several bytes as only the first byte
of the symbol gets to the lexeme. When this lexeme is then printed as
a part of an error message that message became broken too along with
the whole log file where it goes.

This commit fixes the problem by using tokens that match a numeric
literal immediately followed by an identifier, not only one byte. This
also improves error messages in cases with English letters. For 123abc
the error message now will say that the error appeared at or near
"123abc" instead of "123a".

Since anything that matches hexinteger, octinteger or bininteger
followed by identifier also matches decinteger followed by identifier,
use one common rule for that.
---
 src/backend/parser/scan.l| 43 
 src/fe_utils/psqlscan.l  | 40 --
 src/interfaces/ecpg/preproc/pgc.l| 40 --
 src/test/regress/expected/numerology.out | 14 +---
 src/test/regress/sql/numerology.sql  |  1 +
 5 files changed, 76 insertions(+), 62 deletions(-)

diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index f74059e7b0..1a7c9b9d8f 100644
--- a/src/backend/parser/scan.l
+++ b/src/backend/parser/scan.l
@@ -412,16 +412,29 @@ numericfail		{decinteger}\.\.
 real			({decinteger}|{numeric})[Ee][-+]?{decinteger}
 realfail		({decinteger}|{numeric})[Ee][-+]
 
-decinteger_junk	{decinteger}{ident_start}
-hexinteger_junk	{hexinteger}{ident_start}
-octinteger_junk	{octinteger}{ident_start}
-bininteger_junk	{bininteger}{ident_start}
-numeric_junk	{numeric}{ident_start}
-real_junk		{real}{ident_start}
-
 /* Positional parameters don't accept underscores. */
 param			\${decdigit}+
-param_junk		\${decdigit}+{ident_start}
+
+/*
+ * An identifier immediately following a numeric literal is disallowed because
+ * in some cases it's ambiguous what is meant: for example, 0x1234 could be
+ * either a hexinteger or a decinteger "0" and an identifier "x1234".  We can
+ * detect such problems by seeing if integer_junk matches a longer substring
+ * than any of the XXXinteger patterns (decinteger, hexinteger, octinteger,
+ * and bininteger). One "junk" pattern is sufficient because
+ * {decinteger}{identifier} will match all the same strings we'd match with
+ * {hexinteger}{identifier} etc.
+ *
+ * Note that the rule for integer_junk must appear after the ones for
+ * XXXinteger to make this work correctly.
+ *
+ * Also disallow strings matched by numeric_junk, real_junk and param_junk for
+ * consistency.
+ */
+integer_junk	{decinteger}{identifier}
+numeric_junk	{numeric}{identifier}
+real_junk		{real}{identifier}
+param_junk		\${decdigit}+{identifier}
 
 other			.
 
@@ -1055,19 +1068,7 @@ other			.
 	SET_YYLLOC();
 	yyerror("trailing junk after numeric literal");
 }
-{decinteger_junk}	{
-	SET_YYLLOC();
-	yyerror("trailing junk after numeric literal");
-}
-{hexinteger_junk}	{
-	SET_YYLLOC();
-	yyerror("trailing junk after numeric literal");
-}
-{octinteger_junk}	{
-	SET_YYLLOC();
-	yyerror("trailing junk after numeric literal");
-}
-{bininteger_junk}	{
+{integer_junk}	{
 	SET_YYLLOC();
 	yyerror("trailing junk after numeric literal");
 }
diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l
index ddc4658b92..f1c24d505b 100644
--- a/src/fe_utils/psqlscan.l
+++ b/src/fe_utils/psqlscan.l
@@ -348,16 +348,29 @@ numericfail		{decinteger}\.\.
 real			({decinteger}|{numeric})[Ee][-+]?{decinteger}
 realfail		({decinteger}|{numeric})[Ee][-+]
 
-decinteger_junk	{decinteger}{ident_start}
-hexinteger_junk	{hexinteger}{ident_start}
-octinteger_junk	{octinteger}{ident_start}
-bininteger_junk	{bininteger}{ident_start}
-numeric_junk	{numeric}{ident_start}
-real_junk		{real}{ident_start}
-
 /* Positional parameters don't accept underscores. */
 param			\${decdigit}+
-param_junk		\${decdig

Re: Invalid "trailing junk" error message when non-English letters are used

2024-09-05 Thread Karina Litskevich
On Thu, Sep 5, 2024 at 1:52 AM Tom Lane  wrote:
> Karina Litskevich  writes:
> > I see the two solutions here: either move the rule for decinteger_junk
> > below the rules for hexinteger_junk, octinteger_junk and
bininteger_junk,
> > or just use a single rule decinteger_junk for all these cases, since the
> > error message is the same anyway. I implemented the latter in the second
> > version of the patch, also renamed this common rule to integer_junk.
>
> That seems reasonable, but IMO this code was unacceptably
> undercommented before and what you've done has made it worse.
> We really need a comment block associated with the flex macros,
> perhaps along the lines of
>
> /*
>  * An identifier immediately following a numeric literal is disallowed
>  * because in some cases it's ambiguous what is meant: for example,
>  * 0x1234 could be either a hexinteger or a decinteger "0" and an
>  * identifier "x1234".  We can detect such problems by seeing if
>  * integer_junk matches a longer substring than any of the XXXinteger
>  * patterns.  (One "junk" pattern is sufficient because this will match
>  * all the same strings we'd match with {hexinteger}{identifier} etc.)
>  * Note that the rule for integer_junk must appear after the ones for
>  * XXXinteger to make this work correctly.
>  */

Thank you, this piece of code definitely needs a comment.

> (Hmm, actually, is that last sentence true?  My flex is a bit rusty.)

Yes, the rule for integer_junk must appear after the ones for XXXinteger.
Here is a quote from
https://ftp.gnu.org/old-gnu/Manuals/flex-2.5.4/html_mono/flex.html
"If it finds more than one match, it takes the one matching the most text
(...). If it finds two or more matches of the same length, the rule listed
first in the flex input file is chosen."
For example, 0x123 is matched by both integer_junk and hexinteger, and we
want the rule for hexinteger to be chosen, so we should place it before
the rule for integer_junk.

> param_junk really needs a similar comment, or maybe we could put
> all the XXX_junk macros together and use one comment for all.

In v3 of the patch I grouped all the *_junk rules together and included
the suggested comment with a little added something.


Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/


Re: Invalid "trailing junk" error message when non-English letters are used

2024-08-28 Thread Karina Litskevich
On Wed, Aug 28, 2024 at 12:06 AM Pavel Borisov 
wrote:

> I see the following compile time warnings:
> scan.l:1062: warning, rule cannot be matched
> scan.l:1066: warning, rule cannot be matched
> scan.l:1070: warning, rule cannot be matched
> pgc.l:1030: warning, rule cannot be matched
> pgc.l:1033: warning, rule cannot be matched
> pgc.l:1036: warning, rule cannot be matched
> psqlscan.l:905: warning, rule cannot be matched
> psqlscan.l:908: warning, rule cannot be matched
> psqlscan.l:911: warning, rule cannot be matched
>

Thanks for the feedback!

I somehow missed these warnings, my bad. The problem is with queries like
"select 0x12junk;". In master "0x" matches decinteger_junk token and
"0x12j" matches hexinteger_junk token and flex chooses the longest match,
no conflict. But with the patch "0x12junk" matches both decinteger_junk
(decinteger "0" + identifier "x12junk") and hexinteger_junk (hexinteger
"0x12" + identifier "junk"). Since any match to hexinteger_junk also
matches decinteger_junk, and the rule for hexinteger_junk is below the
rule for decinteger_junk, it's never reached.

I see the two solutions here: either move the rule for decinteger_junk
below the rules for hexinteger_junk, octinteger_junk and bininteger_junk,
or just use a single rule decinteger_junk for all these cases, since the
error message is the same anyway. I implemented the latter in the second
version of the patch, also renamed this common rule to integer_junk.


Additionally, I noticed that this patch is going to change error messages
in some cases, though I don't think it's a big deal. Example:

Without patch:
postgres=# select 0xyz;
ERROR:  invalid hexadecimal integer at or near "0x"

With patch:
postgres=# select 0xyz;
ERROR:  trailing junk after numeric literal at or near "0xyz"



> FWIW output of the whole string in the error message doesnt' look nice to
> me, but other places of code do this anyway e.g:
> select ('1'||repeat('p',100))::integer;
> This may be worth fixing.
>

 That's interesting. I didn't know we could do that to create a long error
message. At first I thought that it's not a problem for error messages
from the scanner, since its "at or near" string cannot be longer than the
query typed in psql or written in a script file so it won't be enormously
big. But that's just not true, because we can send a generated query.
Something like that:

With patch:
postgres=# select 'select '||'1'||repeat('p',100) \gexec
ERROR:  trailing junk after numeric literal at or near "1ppp"

And another query that leads to this without patch:
postgres=# select 'select 1'||repeat('@',100)||'1' \gexec
ERROR:  operator too long at or near "@@@"

It would be nice to prevent such long strings in error messages. Maybe a
GUC variable to set the maximum length for such strings could work. But
how do we determine all places where it is needed?


Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/
From e0d49c4e81054e5c66be1f78cb57ad2ae87fa02d Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Wed, 28 Aug 2024 11:52:25 +0300
Subject: [PATCH v2] Improve error message for rejecting trailing junk after
 numeric literals

Rejecting trailing junk after numeric literals was introduced in
commit 2549f066 to prevent scanning a number immediately followed
by an identifier without whitespace as number and identifier.
Unfortunately, all the tokens made to catch such numeric literals
followed by non-digits match a numeric literal and the next byte. The
lexemes found by these tokens are broken in case the next symbol after
a numeric literal is presented by several bytes as only the first byte
of the symbol gets to the lexeme. When this lexeme is then printed as
a part of an error message that message became broken too along with
the whole log file where it goes.

This commit fixes the problem by using tokens that match a numeric
literal immediately followed by an identifier, not only one byte. This
also improves error messages in cases with English letters. For 123abc
the error message now will say that the error appeared at or near
"123abc" instead of "123a".

Since anything that matches hexinteger, octinteger or bininteger
followed by identifier also matches decinteger followed by identifier,
use one common token for that.
---
 src/backend/parser/scan.l| 25 +---
 src/fe_utils/psqlscan.l  | 22 +
 src/interfaces/ecpg/preproc/pgc.l| 22 +
 src/test/regress/expected/numerology.out | 14 -
 src/test/regress/sql/numerology.sql  |  1 +
 5 files changed, 25 insertions(+), 59 de

Invalid "trailing junk" error message when non-English letters are used

2024-08-27 Thread Karina Litskevich
Hi hackers,

When error "trailing junk after numeric literal" occurs at a number
followed by a symbol that is presented by more than one byte, that symbol
in the error message is not displayed correctly. Instead of that symbol
there is only its first byte. That makes the error message an invalid
UTF-8 (or whatever encoding is set). The whole log file where this error
message goes also becomes invalid. That could lead to problems with
reading logs. You can see an invalid message by trying "SELECT 123ä;".

Rejecting trailing junk after numeric literals was introduced in commit
2549f066 to prevent scanning a number immediately followed by an
identifier without whitespace as number and identifier. All the tokens
that made to catch such cases match a numeric literal and the next byte,
and that is where the problem comes from. I thought that it could be fixed
just by using tokens that match a numeric literal immediately followed by
an identifier, not only one byte. This also improves error messages in
cases with English letters. After these changes, for "SELECT 123abc;" the
error message will say that the error appeared at or near "123abc" instead
of "123a".

I've attached the patch. Are there any pitfalls I can't see? It just keeps
bothering me why wasn't it done from the beginning. Matching the whole
identifier after a numeric literal just seems more obvious to me than
matching its first byte.

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/
From 281303312471b4ef831f57d124208ce1699aed54 Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Tue, 27 Aug 2024 17:01:49 +0300
Subject: [PATCH v1] Improve error message for rejecting trailing junk after
 numeric literals

Rejecting trailing junk after numeric literals was introduced in
commit 2549f066 to prevent scanning a number immediately followed
by an identifier without whitespace as number and identifier.
Unfortunately, all the tokens made to catch such numeric literals
followed by non-digits match a numeric literal and the next byte. The
lexemes found by these tokens are broken in case the next symbol after
a numeric literal is presented by several bytes as only the first byte
of the symbol gets to the lexeme. When this lexeme is then printed as
a part of an error message that message became broken too along with
the whole log file where it goes.

This commit fixes the problem by using tokens that match a numeric
literal immediately followed by an identifier, not only one byte. This
also improves error messages in cases with English letters. For 123abc
the error message now will say that the error appeared at or near
"123abc" instead of "123a".
---
 src/backend/parser/scan.l| 14 +++---
 src/fe_utils/psqlscan.l  | 14 +++---
 src/interfaces/ecpg/preproc/pgc.l| 14 +++---
 src/test/regress/expected/numerology.out | 14 +-
 src/test/regress/sql/numerology.sql  |  1 +
 5 files changed, 31 insertions(+), 26 deletions(-)

diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index f74059e7b0..448f9b5afe 100644
--- a/src/backend/parser/scan.l
+++ b/src/backend/parser/scan.l
@@ -412,16 +412,16 @@ numericfail		{decinteger}\.\.
 real			({decinteger}|{numeric})[Ee][-+]?{decinteger}
 realfail		({decinteger}|{numeric})[Ee][-+]
 
-decinteger_junk	{decinteger}{ident_start}
-hexinteger_junk	{hexinteger}{ident_start}
-octinteger_junk	{octinteger}{ident_start}
-bininteger_junk	{bininteger}{ident_start}
-numeric_junk	{numeric}{ident_start}
-real_junk		{real}{ident_start}
+decinteger_junk	{decinteger}{identifier}
+hexinteger_junk	{hexinteger}{identifier}
+octinteger_junk	{octinteger}{identifier}
+bininteger_junk	{bininteger}{identifier}
+numeric_junk	{numeric}{identifier}
+real_junk		{real}{identifier}
 
 /* Positional parameters don't accept underscores. */
 param			\${decdigit}+
-param_junk		\${decdigit}+{ident_start}
+param_junk		\${decdigit}+{identifier}
 
 other			.
 
diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l
index ddc4658b92..282f117b81 100644
--- a/src/fe_utils/psqlscan.l
+++ b/src/fe_utils/psqlscan.l
@@ -348,16 +348,16 @@ numericfail		{decinteger}\.\.
 real			({decinteger}|{numeric})[Ee][-+]?{decinteger}
 realfail		({decinteger}|{numeric})[Ee][-+]
 
-decinteger_junk	{decinteger}{ident_start}
-hexinteger_junk	{hexinteger}{ident_start}
-octinteger_junk	{octinteger}{ident_start}
-bininteger_junk	{bininteger}{ident_start}
-numeric_junk	{numeric}{ident_start}
-real_junk		{real}{ident_start}
+decinteger_junk	{decinteger}{identifier}
+hexinteger_junk	{hexinteger}{identifier}
+octinteger_junk	{octinteger}{identifier}
+bininteger_junk	{bininteger}{identifier}
+numeric_junk	{numeric}{identifier}
+real_junk		{real}{identifier}
 
 /* Positional parameters don't accept underscores. */
 param			\${decdigit}+
-param_junk		\${decdigit}+{ident_start}
+

Re: Use pgBufferUsage for block reporting in analyze

2024-07-05 Thread Karina Litskevich
I wrote:

>
> I suggest assigning values
> bufferusage.shared_blks_read + bufferusage.local_blks_read
> and
> bufferusage.shared_blks_dirtied + bufferusage.local_blks_dirtied
> to new variables and using them. This would keep the changed lines within
> the 80 symbols limit, and make the code more readable overall.
>

The same applies to
bufferusage.shared_blks_hit + bufferusage.local_blks_hit


Re: Use pgBufferUsage for block reporting in analyze

2024-07-05 Thread Karina Litskevich
Hi Anthonin,

I suggest assigning values
bufferusage.shared_blks_read + bufferusage.local_blks_read
and
bufferusage.shared_blks_dirtied + bufferusage.local_blks_dirtied
to new variables and using them. This would keep the changed lines within
the 80 symbols limit, and make the code more readable overall.

I also believe that changing "misses" to "reads" should belong to 0001
patch since we only change it because we replace AnalyzePageMiss with
bufferusage.shared_blks_read + bufferusage.local_blks_read in 0001.

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/

>


Re: [PATCH] Improve amcheck to also check UNIQUE constraint in btree index.

2024-04-25 Thread Karina Litskevich
Hi, hackers!

On Thu, Apr 25, 2024 at 4:00 PM Pavel Borisov 
wrote:

> 0005: Rename checkunique parameter to more user friendly as proposed by
> Peter Eisentraut and Alexander Korotkov
>

I'm not sure renaming checkunique is a good idea. Other arguments of
bt_index_check and bt_index_parent_check functions (heapallindexed and
rootdescend) don't have underscore character in them. Corresponding
pg_amcheck options (--heapallindexed and --rootdescend) are also written
in one piece. check_unique and --check-unique stand out. Making arguments
and options in different styles doesn't seem user friendly to me.

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/


Correct the documentation of extension building infrastructure

2023-12-19 Thread Karina Litskevich
Hi hackers,

I noticed that the documentation of extension building infrastructure [1]
has a paragraph about isolation tests since v12, but they actually can be
run since v14 only.

Actual isolation tests support for extensions built with PGXS was added
in [2] and it was agreed there that it should not be backpatched. How
about fixing the documentation for v12 and v13 then?


[1]: https://www.postgresql.org/docs/12/extend-pgxs.html
[2]:
https://www.postgresql.org/message-id/flat/CAMsr%2BYFsCMH3B4uOPFE%2B2qWM6k%3Do%3Dhf9LGiPNCfwqKdUPz_BsQ%40mail.gmail.com


Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/


Re: BufferUsage counters' values have changed

2023-09-15 Thread Karina Litskevich
Nazir, Andres, thank you both for help!

On Wed, Sep 13, 2023 at 10:10 PM Andres Freund  wrote:

> On 2023-09-13 16:04:00 +0300, Nazir Bilal Yavuz wrote:
> > local_blks_read became zero because:
> > 1_ One more cache hit. It was supposed to be local_blks_read but it is
> > local_blks_hit now. This is an assumption, I didn't check this deeply.
> > 2_ Before fcdda1e4b5, there was one local_blks_read coming from
> > buf = ReadBufferExtended(rel, VISIBILITYMAP_FORKNUM, blkno,
> > RBM_ZERO_ON_ERROR, NULL) in freespace.c -> ReadBuffer_common() ->
> > pgBufferUsage.local_blks_read++.
> > But buf = ReadBufferExtended(rel, VISIBILITYMAP_FORKNUM, blkno,
> > RBM_ZERO_ON_ERROR, NULL) is moved into the else case, so it didn't
> > called and local_blks_read isn't incremented.
>
> That imo is a legitimate difference / improvement. The read we previously
> did
> here was unnecessary.
>
>
> > local_blks_written is greater because of the combination of fcdda1e4b5
> > and 00d1e02be2.
> > In PG_15:
> > RelationGetBufferForTuple() -> ReadBufferBI(P_NEW, RBM_ZERO_AND_LOCK)
> > -> ReadBufferExtended() -> ReadBuffer_common() ->
> > pgBufferUsage.local_blks_written++; (called 5 times) [0]
> > In PG_16:
> > 1_ 5 of the local_blks_written is coming from:
> > RelationGetBufferForTuple() -> RelationAddBlocks() ->
> > ExtendBufferedRelBy() -> ExtendBufferedRelCommon() ->
> > ExtendBufferedRelLocal() -> pgBufferUsage.local_blks_written +=
> > extend_by; (extend_by is 1, this is called 5 times) [1]
> > 2_ 3 of the local_blks_written is coming from:
> > RelationGetBufferForTuple() -> RecordAndGetPageWithFreeSpace() ->
> > fsm_set_and_search() -> fsm_readbuf() -> fsm_extend() ->
> > ExtendBufferedRelTo() -> ExtendBufferedRelCommon() ->
> > ExtendBufferedRelLocal() -> pgBufferUsage.local_blks_written +=
> > extend_by; (extend_by is 3, this is called 1 time) [2]
> >
> > I think [0] is the same path as [1] but [2] is new. 'fsm extends'
> > wasn't counted in local_blks_written in PG_15. Calling
> > ExtendBufferedRelTo() from fsm_extend() caused 'fsm extends' to be
> > counted in local_blks_written. I am not sure which one is correct.
>
> I think it's correct to count the fsm writes here. The pg_stat_statement
> columns aren't specific to the main relation for or such... If anything it
> was
> a bug to not count them before.
>


Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/


Re: BufferUsage counters' values have changed

2023-09-10 Thread Karina Litskevich
On Mon, Sep 11, 2023 at 9:08 AM Karina Litskevich <
litskevichkar...@gmail.com> wrote:

> I found a bug that causes one of the differences. Wrong counter is
> incremented
> in ExtendBufferedRelLocal(). The attached patch fixes it and should be
> applied
> to REL_16_STABLE and master.
>

 I've forgotten to attach the patch. Here it is.
From 999a3d533a9b74c8568cc8a3d715c287de45dd2c Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Thu, 7 Sep 2023 17:44:40 +0300
Subject: [PATCH v1] Fix local_blks_written counter incrementation

---
 src/backend/storage/buffer/localbuf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c
index 1735ec7141..567b8d15ef 100644
--- a/src/backend/storage/buffer/localbuf.c
+++ b/src/backend/storage/buffer/localbuf.c
@@ -431,7 +431,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr,
 
 	*extended_by = extend_by;
 
-	pgBufferUsage.temp_blks_written += extend_by;
+	pgBufferUsage.local_blks_written += extend_by;
 
 	return first_block;
 }
-- 
2.34.1



BufferUsage counters' values have changed

2023-09-10 Thread Karina Litskevich
Hi hackers,

I noticed that BufferUsage counters' values are strangely different for the
same queries on REL_15_STABLE and REL_16_STABLE. For example, I run

CREATE EXTENSION pg_stat_statements;
CREATE TEMP TABLE test(b int);
INSERT INTO test(b) SELECT generate_series(1,1000);
SELECT query, local_blks_hit, local_blks_read, local_blks_written,
   local_blks_dirtied, temp_blks_written FROM pg_stat_statements;

and output on REL_15_STABLE contains

query  | INSERT INTO test(b) SELECT generate_series($1,$2)
local_blks_hit | 1005
local_blks_read| 2
local_blks_written | 5
local_blks_dirtied | 5
temp_blks_written  | 0

while output on REL_16_STABLE contains

query  | INSERT INTO test(b) SELECT generate_series($1,$2)
local_blks_hit | 1006
local_blks_read| 0
local_blks_written | 0
local_blks_dirtied | 5
temp_blks_written  | 8


I found a bug that causes one of the differences. Wrong counter is
incremented
in ExtendBufferedRelLocal(). The attached patch fixes it and should be
applied
to REL_16_STABLE and master. With the patch applied output contains

query  | INSERT INTO test(b) SELECT generate_series($1,$2)
local_blks_hit | 1006
local_blks_read| 0
local_blks_written | 8
local_blks_dirtied | 5
temp_blks_written  | 0


I still wonder why local_blks_written is greater than it was on
REL_15_STABLE,
and why local_blks_read became zero. These changes are caused by fcdda1e4b5.
This code is new to me, and I'm still trying to understand whether it's a
bug
in computing the counters or just changes in how many blocks are
read/written
during the query execution. If anyone can help me, I would be grateful.

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/


Re: Avoid unused value (src/fe_utils/print.c)

2023-07-28 Thread Karina Litskevich
On Tue, Jul 25, 2023 at 1:04 AM Ranier Vilela  wrote:

> Checked today, Coverity does not complain about need_recordsep.
>

Great! Thanks.
So v2 patch makes Coverity happy, and as for me doesn't make the code
less readable. Does anyone have any objections?

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/


Re: Avoid unused value (src/fe_utils/print.c)

2023-07-21 Thread Karina Litskevich
On Wed, Jul 12, 2023 at 1:46 AM Ranier Vilela  wrote:

>  As there is consensus to keep the no-op assignment,
> I will go ahead and reject the patch.
>

In your patch you suggest removing two assignments, and we only have
consensus to keep one of them. The other one is an obvious no-op.

I attached a patch that removes only one assignment. Could you please try
it and check whether Coverity is still complaining about need_recordsep
variable?

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/
From 92c86657181c13c48a4b4176bf4ad1d6221cf9b5 Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Fri, 21 Jul 2023 14:43:44 +0300
Subject: [PATCH v2] Avoid unused value in print.c

---
 src/fe_utils/print.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
index 7af1ccb6b5..d10f33cd9f 100644
--- a/src/fe_utils/print.c
+++ b/src/fe_utils/print.c
@@ -484,10 +484,7 @@ print_unaligned_text(const printTableContent *cont, FILE *fout)
 			for (f = footers; f; f = f->next)
 			{
 if (need_recordsep)
-{
 	print_separator(cont->opt->recordSep, fout);
-	need_recordsep = false;
-}
 fputs(f->data, fout);
 need_recordsep = true;
 			}
-- 
2.34.1



Re: Avoid unused value (src/fe_utils/print.c)

2023-07-06 Thread Karina Litskevich
>
>
>
>> But
>> it's not obvious, so I also have doubts about removing this line. If
>> someday
>> print options are changed, for example to support printing footers and not
>> printing headers, or anything else changes in this function, the output
>> might
>> be unexpected with this line removed.
>
>
> That part I didn't understand.
> How are we going to make this function less readable by removing the
> complicating part.
>

My point is, technically right now you won't see any difference in output
if you remove the line. Because if we get to that line the need_recordsep
is already true. However, understanding why it is true is complicated.
That's
why if you remove the line people who read the code will wonder why we don't
need a separator after "fputs"ing a footer. So keeping that line will make
the code more readable.
Moreover, removing the line will possibly complicate the future maintenance.
As I wrote in the part you just quoted, if the function changes in the way
that need_recordsep is not true right before printing footers any more, then
output will be unexpected.

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/


MarkGUCPrefixReserved() doesn't check all options

2023-07-06 Thread Karina Litskevich
Hi hackers,

Ekaterina Sokolova and I have found a bug in PG 15. Since 88103567cb
MarkGUCPrefixReserved() is supposed not only reporting GUCs that haven't
been
defined by the extension, but also removing them. However, it removes them
in
a wrong way, so that a GUC that goes after the removed GUC is never checked.

To reproduce the bug add the following to the postgresql.conf

shared_preload_libraries = 'pg_stat_statements'
pg_stat_statements.nonexisting_option_1 = on
pg_stat_statements.nonexisting_option_2 = on
pg_stat_statements.nonexisting_option_3 = on
pg_stat_statements.nonexisting_option_4 = on

and start the server. In the logfile you'll see only first and third options
reported invalid and removed.

In master MarkGUCPrefixReserved() iterates a hash table, not an array as in
PG 15. I'm not sure whether it is safe to remove an entry from this hash
table
while iterating it, but at least I can't reproduce the bug on master.

I attached a bugfix for PG 15.

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/
From 5f0e59b225ebb408a0c971bc78e22050b296ae9a Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Thu, 6 Jul 2023 11:00:36 +0300
Subject: [PATCH v1] Fix MarkGUCPrefixReserved() to check all options

---
 src/backend/utils/misc/guc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 915f557c68..c410ba532d 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9723,6 +9723,7 @@ MarkGUCPrefixReserved(const char *className)
 			num_guc_variables--;
 			memmove(&guc_variables[i], &guc_variables[i + 1],
 	(num_guc_variables - i) * sizeof(struct config_generic *));
+			i--;
 		}
 	}
 
-- 
2.25.1



Re: Avoid unncessary always true test (src/backend/storage/buffer/bufmgr.c)

2023-06-30 Thread Karina Litskevich
Hi,

Good catch. Indeed, eb.rel shouldn't be NULL there and the tests should be
unnecessary. However, it doesn't follow from the code of these functions.
>From what I can see eb.rel can be NULL in both of these functions. There is
the following Assert in the beginning of the ExtendBufferedRelTo() function:

Assert((eb.rel != NULL) != (eb.smgr != NULL));

And ExtendBufferedRelShared() is only called from ExtendBufferedRelCommon()
which can be called from ExtendBufferedRelTo() or ExtendBufferedRelBy() that
also has the same Assert(). And none of these functions assigns eb.rel, so
it can be NULL from the very beginning and it stays the same.


And there is the following call in xlogutils.c, which is exactly the case
when
eb.rel is NULL:

buffer = ExtendBufferedRelTo(EB_SMGR(smgr, RELPERSISTENCE_PERMANENT),
 forknum,
 NULL,
 EB_PERFORMING_RECOVERY |
 EB_SKIP_EXTENSION_LOCK,
 blkno + 1,
 mode);


So as for me calling LockRelationForExtension() and
UnlockRelationForExtension()
without testing eb.rel first looks more like a bug here. However, they are
never
actually called with eb.rel=NULL because of the EB_* flags, so there is no
bug
here. I believe we should add Assert checking that when eb.rel is NULL,
flags
are such that we won't use eb.rel. And yes, we can remove unnecessary checks
where the flags value guaranty us that eb.rel is not NULL.


And another minor observation. It seems to me that we don't need a "could
have
been closed while waiting for lock" in ExtendBufferedRelShared(), because I
believe the comment above already explains why updating eb.smgr:

 * Note that another backend might have extended the relation by the time
 * we get the lock.


I attached the new version of the patch as I see it.


Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/
From 7425d5b1b9d30f0da75aabd94e862906f9635a60 Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Fri, 30 Jun 2023 21:26:18 +0300
Subject: [PATCH v4] Remove always true checks

Also add asserts that help understanding these checks are always true
---
 src/backend/storage/buffer/bufmgr.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 3c59bbd04e..7b1e2e1284 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -851,6 +851,8 @@ ExtendBufferedRelBy(ExtendBufferedWhat eb,
 {
 	Assert((eb.rel != NULL) != (eb.smgr != NULL));
 	Assert(eb.smgr == NULL || eb.relpersistence != 0);
+	Assert(eb.rel != NULL || (flags & EB_SKIP_EXTENSION_LOCK) &&
+			!(flags & EB_CREATE_FORK_IF_NEEDED));
 	Assert(extend_by > 0);
 
 	if (eb.smgr == NULL)
@@ -887,6 +889,8 @@ ExtendBufferedRelTo(ExtendBufferedWhat eb,
 
 	Assert((eb.rel != NULL) != (eb.smgr != NULL));
 	Assert(eb.smgr == NULL || eb.relpersistence != 0);
+	Assert(eb.rel != NULL || (flags & EB_SKIP_EXTENSION_LOCK) &&
+			!(flags & EB_CREATE_FORK_IF_NEEDED));
 	Assert(extend_to != InvalidBlockNumber && extend_to > 0);
 
 	if (eb.smgr == NULL)
@@ -908,8 +912,7 @@ ExtendBufferedRelTo(ExtendBufferedWhat eb,
 		LockRelationForExtension(eb.rel, ExclusiveLock);
 
 		/* could have been closed while waiting for lock */
-		if (eb.rel)
-			eb.smgr = RelationGetSmgr(eb.rel);
+		eb.smgr = RelationGetSmgr(eb.rel);
 
 		/* recheck, fork might have been created concurrently */
 		if (!smgrexists(eb.smgr, fork))
@@ -1875,8 +1878,7 @@ ExtendBufferedRelShared(ExtendBufferedWhat eb,
 	if (!(flags & EB_SKIP_EXTENSION_LOCK))
 	{
 		LockRelationForExtension(eb.rel, ExclusiveLock);
-		if (eb.rel)
-			eb.smgr = RelationGetSmgr(eb.rel);
+		eb.smgr = RelationGetSmgr(eb.rel);
 	}
 
 	/*
-- 
2.25.1



Re: Avoid unused value (src/fe_utils/print.c)

2023-06-30 Thread Karina Litskevich
Hi,

Alexander wrote:

> It also aligns the code with print_unaligned_vertical(), but I can't see why
> need_recordsep = true;
> is a no-op here (scan-build dislikes only need_recordsep = false;).
> I suspect that removing that line will change the behaviour in cases when
> need_recordsep = false after the loop "print cells" and the loop
> "for (footers)" is executed.

As I understand cont->cells is supoused to have all cont->ncolumns * cont->nrows
entries filled so the loop "print cells" always assigns need_recordsep = true,
except when there are no cells at all or cancel_pressed == true.
If cancel_pressed == true then footers are not printed. So to have
need_recordsep == false before the loop "for (footers)" table should be empty,
and need_recordsep should be false before the loop "print cells". It can only
be false there when cont->opt->start_table == true and opt_tuples_only == true
so that headers are not printed. But when opt_tuples_only == true footers are
not printed either.

So technically removing "need_recordsep = true;" won't change the outcome. But
it's not obvious, so I also have doubts about removing this line. If someday
print options are changed, for example to support printing footers and not
printing headers, or anything else changes in this function, the output might
be unexpected with this line removed.

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/




Re: Possible false valgrind error reports

2023-02-17 Thread Karina Litskevich
Thank you, I moved comment changes to 0001 and rewrote the fix through Min().

> The first hunk in 0001 doesn't seem quite right yet:
>
>   * old allocation.
>   */
>  #ifdef USE_VALGRIND
> -if (oldsize > chunk->requested_size)
> +if (size > chunk->requested_size && oldsize > chunk->requested_size)
>  VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + 
> chunk->requested_size,
>  oldsize - chunk->requested_size);
>  #endif
>
> If size < oldsize, aren't we still doing the wrong thing?  Seems like
> maybe it has to be like

If size > chunk->requested_size than chksize >= oldsize and so we can mark this
memory without worries. Region from size to chksize will be marked NOACCESS
later anyway:

/* Ensure any padding bytes are marked NOACCESS. */
VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size, chksize - size);

I agree that it's not obvious, so I changed the first hunk like this:

- if (oldsize > chunk->requested_size)
+ if (Min(size, oldsize) > chunk->requested_size)
  VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + chunk->requested_size,
- oldsize - chunk->requested_size);
+ Min(size, oldsize) - chunk->requested_size);

Any ideas on how to make this place easier to understand and comment above it
concise and clear are welcome.

There is another thing about this version. New line
+ Min(size, oldsize) - chunk->requested_size);
is longer than 80 symbols and I don't know what's the best way to avoid this
without making it look weird.

I also noticed that if RANDOMIZE_ALLOCATED_MEMORY is defined then
randomize_mem()
have already marked this memory UNDEFINED. So we only "may need to adjust
trailing bytes" if RANDOMIZE_ALLOCATED_MEMORY isn't defined. I reflected it in
v2 of 0001 too.
From 009ef9bbabcd71e0d5f2b60799c0b71d21fb9767 Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Fri, 17 Feb 2023 15:32:05 +0300
Subject: [PATCH v2 2/2] Change variable name in AllocSetRealloc()

---
 src/backend/utils/mmgr/aset.c | 32 +---
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index ace4907ce9..9584d50b14 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -1112,7 +1112,7 @@ AllocSetRealloc(void *pointer, Size size)
 	AllocBlock	block;
 	AllocSet	set;
 	MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
-	Size		oldsize;
+	Size		oldchksize;
 	int			fidx;
 
 	/* Allow access to private part of chunk header. */
@@ -1140,11 +1140,11 @@ AllocSetRealloc(void *pointer, Size size)
 
 		set = block->aset;
 
-		oldsize = block->endptr - (char *) pointer;
+		oldchksize = block->endptr - (char *) pointer;
 
 #ifdef MEMORY_CONTEXT_CHECKING
 		/* Test for someone scribbling on unused space in chunk */
-		Assert(chunk->requested_size < oldsize);
+		Assert(chunk->requested_size < oldchksize);
 		if (!sentinel_ok(pointer, chunk->requested_size))
 			elog(WARNING, "detected write past chunk end in %s %p",
  set->header.name, chunk);
@@ -1197,15 +1197,15 @@ AllocSetRealloc(void *pointer, Size size)
 #else
 		/*
 		 * If this is an increase, realloc() will have left any newly-allocated
-		 * part (from oldsize to chksize) UNDEFINED, but we may need to adjust
+		 * part (from oldchksize to chksize) UNDEFINED, but we may need to adjust
 		 * trailing bytes from the old allocation (from chunk->requested_size to
-		 * oldsize) as they are marked NOACCESS.  Make sure not to mark extra
-		 * bytes in case chunk->requested_size < size < oldsize.
+		 * oldchksize) as they are marked NOACCESS.  Make sure not to mark extra
+		 * bytes in case chunk->requested_size < size < oldchksize.
 		 */
 #ifdef USE_VALGRIND
-		if (Min(size, oldsize) > chunk->requested_size)
+		if (Min(size, oldchksize) > chunk->requested_size)
 			VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + chunk->requested_size,
-		Min(size, oldsize) - chunk->requested_size);
+		Min(size, oldchksize) - chunk->requested_size);
 #endif
 #endif
 
@@ -1223,7 +1223,7 @@ AllocSetRealloc(void *pointer, Size size)
 		 * portion DEFINED.  Make sure not to mark memory behind the new
 		 * allocation in case it's smaller than old one.
 		 */
-		VALGRIND_MAKE_MEM_DEFINED(pointer, Min(size, oldsize));
+		VALGRIND_MAKE_MEM_DEFINED(pointer, Min(size, oldchksize));
 #endif
 
 		/* Ensure any padding bytes are marked NOACCESS. */
@@ -1248,11 +1248,11 @@ AllocSetRealloc(void *pointer, Size size)
 
 	fidx = MemoryChunkGetValue(chunk);
 	Assert(FreeListIdxIsValid(fidx));
-	oldsize = GetChunkSizeFromFreeListIdx(fidx);
+	oldchksize = GetChunkSizeFromFreeListIdx(fidx);
 
 #ifdef MEMORY_CONTEXT_CHECKING
 	/* Test for someone scribbling on unused 

Possible false valgrind error reports

2023-02-14 Thread Karina Litskevich
Hi hackers,

In 82d0a46ea32 AllocSetRealloc() was changed to allow decreasing size of
external chunks and give memory back to the malloc pool. Two
VALGRIND_MAKE_MEM_UNDEFINED() calls were not changed to work properly in the
case of decreasing size: they can mark memory behind the new allocated
memory
UNDEFINED. If this memory was already allocated and initialized, it's
expected
to be DEFINED. So it can cause false valgrind error reports. I fixed it in
0001
patch.

Also, it took me a while to understand what's going on there, so in 0002
patch
I tried to improve comments and renamed a variable. Its name "oldsize"
confused
me. I first thought "oldsize" and "size" represent the same parameters of
the
old and new chunk. But actually "size" is new "chunk->requested_size" and
"oldsize" is old "chksize". So I believe it's better to rename "oldsize"
into
"oldchksize".

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/
From 9556b7918e6abccb2dc19f20dbf572d41cd35cb4 Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Tue, 14 Feb 2023 17:13:17 +0300
Subject: [PATCH v1 1/2] Fix VALGRIND_MAKE_MEM_DEFINED() calls

---
 src/backend/utils/mmgr/aset.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index 740729b5d0..1ff0bb83cb 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -1199,7 +1199,7 @@ AllocSetRealloc(void *pointer, Size size)
 		 * old allocation.
 		 */
 #ifdef USE_VALGRIND
-		if (oldsize > chunk->requested_size)
+		if (size > chunk->requested_size && oldsize > chunk->requested_size)
 			VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + chunk->requested_size,
 		oldsize - chunk->requested_size);
 #endif
@@ -1215,7 +1215,10 @@ AllocSetRealloc(void *pointer, Size size)
 		 * allocation; it could have been as small as one byte.  We have to be
 		 * conservative and just mark the entire old portion DEFINED.
 		 */
-		VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
+		if (size >= oldsize)
+			VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
+		else
+			VALGRIND_MAKE_MEM_DEFINED(pointer, size);
 #endif
 
 		/* Ensure any padding bytes are marked NOACCESS. */
-- 
2.25.1

From 7cdaee9caaf96564237e4cfa8279699a36942624 Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Tue, 14 Feb 2023 17:18:30 +0300
Subject: [PATCH v1 2/2] Better comments and variable name in AllocSetRealloc()

---
 src/backend/utils/mmgr/aset.c | 46 ---
 1 file changed, 27 insertions(+), 19 deletions(-)

diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index 1ff0bb83cb..35007750a9 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -1112,7 +1112,7 @@ AllocSetRealloc(void *pointer, Size size)
 	AllocBlock	block;
 	AllocSet	set;
 	MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
-	Size		oldsize;
+	Size		oldchksize;
 	int			fidx;
 
 	/* Allow access to private part of chunk header. */
@@ -1140,11 +1140,11 @@ AllocSetRealloc(void *pointer, Size size)
 
 		set = block->aset;
 
-		oldsize = block->endptr - (char *) pointer;
+		oldchksize = block->endptr - (char *) pointer;
 
 #ifdef MEMORY_CONTEXT_CHECKING
 		/* Test for someone scribbling on unused space in chunk */
-		Assert(chunk->requested_size < oldsize);
+		Assert(chunk->requested_size < oldchksize);
 		if (!sentinel_ok(pointer, chunk->requested_size))
 			elog(WARNING, "detected write past chunk end in %s %p",
  set->header.name, chunk);
@@ -1194,14 +1194,17 @@ AllocSetRealloc(void *pointer, Size size)
 #endif
 
 		/*
-		 * realloc() (or randomize_mem()) will have left any newly-allocated
-		 * part UNDEFINED, but we may need to adjust trailing bytes from the
-		 * old allocation.
+		 * If this is an increase, realloc() (or randomize_mem()) will have left
+		 * any newly-allocated part UNDEFINED, but we may need to adjust
+		 * trailing bytes from the old allocation as they are marked NOACCESS.
 		 */
 #ifdef USE_VALGRIND
-		if (size > chunk->requested_size && oldsize > chunk->requested_size)
+		if (size > chunk->requested_size && oldchksize > chunk->requested_size)
+		{
+			Assert(chksize >= oldchksize);
 			VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + chunk->requested_size,
-		oldsize - chunk->requested_size);
+		oldchksize - chunk->requested_size);
+		}
 #endif
 
 		chunk->requested_size = size;
@@ -1211,12 +1214,15 @@ AllocSetRealloc(void *pointer, Size size)
 #else			/* !MEMORY_CONTEXT_CHECKING */
 
 		/*
-		 * We don't know how much of the old chunk size was the actual
-		 * allocation; it could have been as small as one byte.  We have to be
-		 * conservative and just mark the entire ol

Re: Error for WITH options on partitioned tables

2022-11-07 Thread Karina Litskevich
Hi David,

> I am not very clear about why `build_reloptions` is removed in patch
> `v2-0002-better-error-message-for-setting-parameters-for-p.patch`, if
> you can help explain would be great.

"build_reloptions" parses "reloptions" and takes for it a list of allowed
options defined by the 5th argument "relopt_elems" and the 6th argument
"num_relopt_elems", which are NULL and 0 in the removed call. If "validate"
is false, it ignores options, which are not in the list, while parsing. If
"validate" is true, it "elog"s ERROR when it meets option, which is not in
the
allowed list.

As in the deleted call "build_reloptions" is called with an empty list of
allowed options, it does nothing (returns NULL) when "validate" is false,
and
"elog"s ERROR when "validate" is true and "reloptions" is not empty. That is
what the deleted comment above the deleted call about. This call is there
only
for validation. So as I wanted to make a specific error message for the
case of
partitioned tables, I added the validation in "partitioned_table_reloptions"
and saw no reason to call "build_reloptions" any more because it would just
return NULL in other cases.

> This generic error message is reported by
> `errdetail_relkind_not_supported`, and there is a similar error message
> for partitioned tables. Anyone knows if this can be an option for
> reporting this `fillfactor` parameter not supported error.

This error is reported by "ATSimplePermissions" and, as we can see in the
beginning of this function, it makes no difference between regular relations
and partitioned tables now. To make it report errors for partitioned tables
we
should add new "alter table target-type flag" and add it to a mask of each
"AlterTableType" if partitioned table is an allowed target for it (see that
huge switch-case in function "ATPrepCmd"). Then
"partitioned_table_reloptions"
may become useless and we also should check weather some other functions
become
useless. Maybe that is the right way, but it looks much harder than the
existing solutions, so I believe, before anyone began going this way, it's
better to know whether there are any pitfalls there.

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/


Re: Error for WITH options on partitioned tables

2022-10-14 Thread Karina Litskevich
Hi, Simon!

The new error message looks better. But I believe it is better to use
"parameters" instead of "options" as it is called "storage parameters"
in the documentation. I also believe it is better to report error in
partitioned_table_reloptions() (thanks to Japin Li for mentioning this
function) as it also fixes the error message in the following situation:

test=# CREATE TABLE parted_col_comment (a int, b text) PARTITION BY LIST
(a);
CREATE TABLE
test=# ALTER TABLE parted_col_comment SET (fillfactor=100);
ERROR:  unrecognized parameter "fillfactor"

I attached the new versions of patches.

I'm not sure about the errcode. May be it is better to report error with
ERRCODE_INVALID_OBJECT_DEFINITION for CREATE TABLE and with
ERRCODE_WRONG_OBJECT_TYPE for ALTER TABLE (as when you try "ALTER TABLE
partitioned INHERIT nonpartitioned;" an ERROR with ERRCODE_WRONG_OBJECT_TYPE
is reported). Then either the desired code should be passed to
partitioned_table_reloptions() or similar checks and ereport calls should be
placed in two different places. I'm not sure whether it is a good idea to
change the code in one of these ways just to change the error code.

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/
From 6407538f0bfd3eb56f5a4574d8893f9494f2a810 Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Fri, 14 Oct 2022 17:48:27 +0300
Subject: [PATCH v2 2/2] better error message for setting parameters for
 partitioned table

---
 src/backend/access/common/reloptions.c | 13 ++---
 src/test/regress/expected/alter_table.out  |  3 ++-
 src/test/regress/expected/create_table.out |  3 ++-
 3 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 6458a9c276..75d6ff5040 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -1984,13 +1984,12 @@ build_local_reloptions(local_relopts *relopts, Datum options, bool validate)
 bytea *
 partitioned_table_reloptions(Datum reloptions, bool validate)
 {
-	/*
-	 * There are no options for partitioned tables yet, but this is able to do
-	 * some validation.
-	 */
-	return (bytea *) build_reloptions(reloptions, validate,
-	  RELOPT_KIND_PARTITIONED,
-	  0, NULL, 0);
+	if (validate && reloptions)
+		ereport(ERROR,
+errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+errmsg("cannot specify storage parameters for a partitioned table"),
+errhint("specify storage parameters on leaf partitions instead"));
+	return NULL;
 }
 
 /*
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index cec7bfa1f1..a719ef22c7 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -3803,7 +3803,8 @@ ALTER TABLE partitioned ALTER COLUMN b TYPE char(5);
 ERROR:  cannot alter column "b" because it is part of the partition key of relation "partitioned"
 -- specifying storage parameters for partitioned tables is not supported
 ALTER TABLE partitioned SET (fillfactor=100);
-ERROR:  unrecognized parameter "fillfactor"
+ERROR:  cannot specify storage parameters for a partitioned table
+HINT:  specify storage parameters on leaf partitions instead
 -- partitioned table cannot participate in regular inheritance
 CREATE TABLE nonpartitioned (
 	a int,
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index 45c1a0a23e..f16be87729 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -989,7 +989,8 @@ Number of partitions: 0
 DROP TABLE parted_col_comment;
 -- specifying storage parameters for partitioned tables is not supported
 CREATE TABLE parted_col_comment (a int, b text) PARTITION BY LIST (a) WITH (fillfactor=100);
-ERROR:  unrecognized parameter "fillfactor"
+ERROR:  cannot specify storage parameters for a partitioned table
+HINT:  specify storage parameters on leaf partitions instead
 -- list partitioning on array type column
 CREATE TABLE arrlp (a int[]) PARTITION BY LIST (a);
 CREATE TABLE arrlp12 PARTITION OF arrlp FOR VALUES IN ('{1}', '{2}');
-- 
2.25.1

From 580566815bc5abd6193f86ddbd55fac1ac941873 Mon Sep 17 00:00:00 2001
From: Karina Litskevich 
Date: Fri, 14 Oct 2022 16:22:57 +0300
Subject: [PATCH v2 1/2] test parameters for partitioned table

---
 src/test/regress/expected/alter_table.out  | 3 +++
 src/test/regress/expected/create_table.out | 3 +++
 src/test/regress/sql/alter_table.sql   | 3 +++
 src/test/regress/sql/create_table.sql  | 3 +++
 4 files changed, 12 insertions(+)

diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 346f594ad0..cec7bfa1f1 100644
--- a/src/test/regress/expected/alter_t

Re: [PATCH] Improve amcheck to also check UNIQUE constraint in btree index.

2022-09-08 Thread Karina Litskevich
Hi,

I also would like to suggest a cosmetic change.
In v15 a new field checkunique is added after heapallindexed and before
no_btree_expansion fields in struct definition, but in initialisation it is
added after no_btree_expansion:

--- a/src/bin/pg_amcheck/pg_amcheck.c
+++ b/src/bin/pg_amcheck/pg_amcheck.c
@@ -102,6 +102,7 @@ typedef struct AmcheckOptions
  bool parent_check;
  bool rootdescend;
  bool heapallindexed;
+ bool checkunique;

  /* heap and btree hybrid option */
  bool no_btree_expansion;
@@ -132,7 +133,8 @@ static AmcheckOptions opts = {
  .parent_check = false,
  .rootdescend = false,
  .heapallindexed = false,
- .no_btree_expansion = false
+ .no_btree_expansion = false,
+ .checkunique = false
 };

I suggest to add checkunique field between heapallindexed and
no_btree_expansion fields in initialisation as well as in definition:

@@ -132,6 +133,7 @@ static AmcheckOptions opts = {
  .parent_check = false,
  .rootdescend = false,
  .heapallindexed = false,
+ .checkunique = false,
  .no_btree_expansion = false
 };

--
Best regards,
Litskevich Karina
Postgres Professional: http://postgrespro.com/
From 56fe2b608b46c6c97900bbb63b2169e2997bc8cc Mon Sep 17 00:00:00 2001
From: Pavel Borisov 
Date: Wed, 11 May 2022 15:54:13 +0400
Subject: [PATCH v16] Add option for amcheck and pg_amcheck to check unique
 constraint for btree indexes.

Add 'checkunique' argument to bt_index_check() and bt_index_parent_check().
When the flag is specified the procedures will check the unique constraint
violation for unique indexes. Only one heap entry for all equal keys in
the index should be visible (including posting list entries). Report an error
otherwise.

pg_amcheck called with --checkunique option will do the same check for all
the indexes it checks.

Author: Anastasia Lubennikova 
Author: Pavel Borisov 
Author: Maxim Orlov 
Reviewed-by: Mark Dilger 
Reviewed-by: Zhihong Yu 
Reviewed-by: Peter Geoghegan 
Reviewed-by: Aleksander Alekseev 
Discussion: https://postgr.es/m/CALT9ZEHRn5xAM5boga0qnrCmPV52bScEK2QnQ1HmUZDD301JEg%40mail.gmail.com
---
 contrib/amcheck/Makefile  |   2 +-
 contrib/amcheck/amcheck--1.3--1.4.sql |  29 ++
 contrib/amcheck/amcheck.control   |   2 +-
 contrib/amcheck/expected/check_btree.out  |  42 +++
 contrib/amcheck/sql/check_btree.sql   |  14 +
 contrib/amcheck/t/004_verify_nbtree_unique.pl | 235 +
 contrib/amcheck/verify_nbtree.c   | 329 +-
 doc/src/sgml/amcheck.sgml |  14 +-
 doc/src/sgml/ref/pg_amcheck.sgml  |  11 +
 src/bin/pg_amcheck/pg_amcheck.c   |  48 ++-
 src/bin/pg_amcheck/t/003_check.pl |  45 +++
 src/bin/pg_amcheck/t/005_opclass_damage.pl|  65 
 12 files changed, 813 insertions(+), 23 deletions(-)
 create mode 100644 contrib/amcheck/amcheck--1.3--1.4.sql
 create mode 100644 contrib/amcheck/t/004_verify_nbtree_unique.pl

diff --git a/contrib/amcheck/Makefile b/contrib/amcheck/Makefile
index b82f221e50..88271687a3 100644
--- a/contrib/amcheck/Makefile
+++ b/contrib/amcheck/Makefile
@@ -7,7 +7,7 @@ OBJS = \
 	verify_nbtree.o
 
 EXTENSION = amcheck
-DATA = amcheck--1.2--1.3.sql amcheck--1.1--1.2.sql amcheck--1.0--1.1.sql amcheck--1.0.sql
+DATA = amcheck--1.3--1.4.sql amcheck--1.2--1.3.sql amcheck--1.1--1.2.sql amcheck--1.0--1.1.sql amcheck--1.0.sql
 PGFILEDESC = "amcheck - function for verifying relation integrity"
 
 REGRESS = check check_btree check_heap
diff --git a/contrib/amcheck/amcheck--1.3--1.4.sql b/contrib/amcheck/amcheck--1.3--1.4.sql
new file mode 100644
index 00..75574eaa64
--- /dev/null
+++ b/contrib/amcheck/amcheck--1.3--1.4.sql
@@ -0,0 +1,29 @@
+/* contrib/amcheck/amcheck--1.3--1.4.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION amcheck UPDATE TO '1.4'" to load this file. \quit
+
+-- In order to avoid issues with dependencies when updating amcheck to 1.4,
+-- create new, overloaded versions of the 1.2 bt_index_parent_check signature,
+-- and 1.1 bt_index_check signature.
+
+--
+-- bt_index_parent_check()
+--
+CREATE FUNCTION bt_index_parent_check(index regclass,
+heapallindexed boolean, rootdescend boolean, checkunique boolean)
+RETURNS VOID
+AS 'MODULE_PATHNAME', 'bt_index_parent_check'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+--
+-- bt_index_check()
+--
+CREATE FUNCTION bt_index_check(index regclass,
+heapallindexed boolean, checkunique boolean)
+RETURNS VOID
+AS 'MODULE_PATHNAME', 'bt_index_check'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+-- We don't want this to be available to public
+REVOKE ALL ON FUNCTION bt_index_parent_check(regclass, boolean, boolean, boolean) FROM PUBLIC;
+REVOKE ALL ON FUNCTION bt_index_check(regclass, boolean, boolean) FROM PUBLIC;
diff --git a/contrib/amcheck/amcheck.control b/contrib/amcheck/amcheck.control
index ab50931f75..e67ace01c9 100644
--- a/contrib/amcheck/amcheck.control
+++ b/contrib/amcheck/amc