Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 121e3ce

Browse files
committed
Avoid using INFO elevel for what are fundamentally debug messages.
Commit 6f6b99d stuck an INFO message into the fast path for checking partition constraints, for no very good reason except that it made it easy for the regression tests to verify that that path was taken. Assorted later patches did likewise, increasing the unsuppressable-chatter level from ALTER TABLE even more. This isn't good for the user experience, so let's drop these messages down to DEBUG1 where they belong. So as not to have a loss of test coverage, create a TAP test that runs the relevant queries with client_min_messages = DEBUG1 and greps for the expected messages. This testing method is a bit brute-force --- in particular, it duplicates the execution of a fair amount of the core create_table and alter_table tests. We experimented with other solutions, but running any significant amount of standard testing with client_min_messages = DEBUG1 seems to have a lot of output-stability pitfalls, cf commits bbb96c3 and 5655565. Possibly at some point we'll look into whether we can reduce the amount of test duplication. Backpatch into v12, because some of these messages are new in v12 and we don't really want to ship it that way. Sergei Kornilov Discussion: https://postgr.es/m/81911511895540@web58j.yandex.ru Discussion: https://postgr.es/m/4859321552643736@myt5-02b80404fd9e.qloud-c.yandex.net
1 parent b6a4d04 commit 121e3ce

File tree

10 files changed

+340
-20
lines changed

10 files changed

+340
-20
lines changed

src/backend/commands/tablecmds.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15418,11 +15418,11 @@ QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
1541815418
if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint))
1541915419
{
1542015420
if (!validate_default)
15421-
ereport(INFO,
15421+
ereport(DEBUG1,
1542215422
(errmsg("partition constraint for table \"%s\" is implied by existing constraints",
1542315423
RelationGetRelationName(scanrel))));
1542415424
else
15425-
ereport(INFO,
15425+
ereport(DEBUG1,
1542615426
(errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
1542715427
RelationGetRelationName(scanrel))));
1542815428
return;

src/backend/partitioning/partbounds.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,7 +1253,7 @@ check_default_partition_contents(Relation parent, Relation default_rel,
12531253
*/
12541254
if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
12551255
{
1256-
ereport(INFO,
1256+
ereport(DEBUG1,
12571257
(errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
12581258
RelationGetRelationName(default_rel))));
12591259
return;
@@ -1304,7 +1304,7 @@ check_default_partition_contents(Relation parent, Relation default_rel,
13041304
if (PartConstraintImpliedByRelConstraint(part_rel,
13051305
def_part_constraints))
13061306
{
1307-
ereport(INFO,
1307+
ereport(DEBUG1,
13081308
(errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
13091309
RelationGetRelationName(part_rel))));
13101310

src/test/modules/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ SUBDIRS = \
1313
test_ddl_deparse \
1414
test_extensions \
1515
test_integerset \
16+
test_misc \
1617
test_parser \
1718
test_pg_dump \
1819
test_predtest \

src/test/modules/test_misc/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Generated subdirectories
2+
/log/
3+
/results/
4+
/tmp_check/

src/test/modules/test_misc/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# src/test/modules/test_misc/Makefile
2+
3+
TAP_TESTS = 1
4+
5+
ifdef USE_PGXS
6+
PG_CONFIG = pg_config
7+
PGXS := $(shell $(PG_CONFIG) --pgxs)
8+
include $(PGXS)
9+
else
10+
subdir = src/test/modules/test_misc
11+
top_builddir = ../../../..
12+
include $(top_builddir)/src/Makefile.global
13+
include $(top_srcdir)/contrib/contrib-global.mk
14+
endif

src/test/modules/test_misc/README

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
This directory doesn't actually contain any extension module.
2+
3+
What it is is a home for otherwise-unclassified TAP tests that exercise core
4+
server features. We might equally well have called it, say, src/test/misc.
Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
# Verify that ALTER TABLE optimizes certain operations as expected
2+
3+
use strict;
4+
use warnings;
5+
use PostgresNode;
6+
use TestLib;
7+
use Test::More tests => 42;
8+
9+
# Initialize a test cluster
10+
my $node = get_new_node('master');
11+
$node->init();
12+
# Turn message level up to DEBUG1 so that we get the messages we want to see
13+
$node->append_conf('postgresql.conf', 'client_min_messages = DEBUG1');
14+
$node->start;
15+
16+
# Run a SQL command and return psql's stderr (including debug messages)
17+
sub run_sql_command
18+
{
19+
my $sql = shift;
20+
my $stderr;
21+
22+
$node->psql(
23+
'postgres',
24+
$sql,
25+
stderr => \$stderr,
26+
on_error_die => 1,
27+
on_error_stop => 1);
28+
return $stderr;
29+
}
30+
31+
# Check whether result of run_sql_command shows that we did a verify pass
32+
sub is_table_verified
33+
{
34+
my $output = shift;
35+
return index($output, 'DEBUG: verifying table') != -1;
36+
}
37+
38+
my $output;
39+
40+
note "test alter table set not null";
41+
42+
run_sql_command(
43+
'create table atacc1 (test_a int, test_b int);
44+
insert into atacc1 values (1, 2);');
45+
46+
$output = run_sql_command('alter table atacc1 alter test_a set not null;');
47+
ok(is_table_verified($output),
48+
'column test_a without constraint will scan table');
49+
50+
run_sql_command(
51+
'alter table atacc1 alter test_a drop not null;
52+
alter table atacc1 add constraint atacc1_constr_a_valid
53+
check(test_a is not null);');
54+
55+
# normal run will verify table data
56+
$output = run_sql_command('alter table atacc1 alter test_a set not null;');
57+
ok(!is_table_verified($output), 'with constraint will not scan table');
58+
ok( $output =~
59+
m/existing constraints on column "atacc1"."test_a" are sufficient to prove that it does not contain nulls/,
60+
'test_a proved by constraints');
61+
62+
run_sql_command('alter table atacc1 alter test_a drop not null;');
63+
64+
# we have check only for test_a column, so we need verify table for test_b
65+
$output = run_sql_command(
66+
'alter table atacc1 alter test_b set not null, alter test_a set not null;'
67+
);
68+
ok(is_table_verified($output), 'table was scanned');
69+
# we may miss debug message for test_a constraint because we need verify table due test_b
70+
ok( !( $output =~
71+
m/existing constraints on column "atacc1"."test_b" are sufficient to prove that it does not contain nulls/
72+
),
73+
'test_b not proved by wrong constraints');
74+
run_sql_command(
75+
'alter table atacc1 alter test_a drop not null, alter test_b drop not null;'
76+
);
77+
78+
# test with both columns having check constraints
79+
run_sql_command(
80+
'alter table atacc1 add constraint atacc1_constr_b_valid check(test_b is not null);'
81+
);
82+
$output = run_sql_command(
83+
'alter table atacc1 alter test_b set not null, alter test_a set not null;'
84+
);
85+
ok(!is_table_verified($output), 'table was not scanned for both columns');
86+
ok( $output =~
87+
m/existing constraints on column "atacc1"."test_a" are sufficient to prove that it does not contain nulls/,
88+
'test_a proved by constraints');
89+
ok( $output =~
90+
m/existing constraints on column "atacc1"."test_b" are sufficient to prove that it does not contain nulls/,
91+
'test_b proved by constraints');
92+
run_sql_command('drop table atacc1;');
93+
94+
note "test alter table attach partition";
95+
96+
run_sql_command(
97+
'CREATE TABLE list_parted2 (
98+
a int,
99+
b char
100+
) PARTITION BY LIST (a);
101+
CREATE TABLE part_3_4 (
102+
LIKE list_parted2,
103+
CONSTRAINT check_a CHECK (a IN (3)));');
104+
105+
# need NOT NULL to skip table scan
106+
$output = run_sql_command(
107+
'ALTER TABLE list_parted2 ATTACH PARTITION part_3_4 FOR VALUES IN (3, 4);'
108+
);
109+
ok(is_table_verified($output), 'table part_3_4 scanned');
110+
111+
run_sql_command(
112+
'ALTER TABLE list_parted2 DETACH PARTITION part_3_4;
113+
ALTER TABLE part_3_4 ALTER a SET NOT NULL;');
114+
115+
$output = run_sql_command(
116+
'ALTER TABLE list_parted2 ATTACH PARTITION part_3_4 FOR VALUES IN (3, 4);'
117+
);
118+
ok(!is_table_verified($output), 'table part_3_4 not scanned');
119+
ok( $output =~
120+
m/partition constraint for table "part_3_4" is implied by existing constraints/,
121+
'part_3_4 verified by existing constraints');
122+
123+
# test attach default partition
124+
run_sql_command(
125+
'CREATE TABLE list_parted2_def (
126+
LIKE list_parted2,
127+
CONSTRAINT check_a CHECK (a IN (5, 6)));');
128+
$output = run_sql_command(
129+
'ALTER TABLE list_parted2 ATTACH PARTITION list_parted2_def default;');
130+
ok(!is_table_verified($output), 'table list_parted2_def not scanned');
131+
ok( $output =~
132+
m/partition constraint for table "list_parted2_def" is implied by existing constraints/,
133+
'list_parted2_def verified by existing constraints');
134+
135+
$output = run_sql_command(
136+
'CREATE TABLE part_55_66 PARTITION OF list_parted2 FOR VALUES IN (55, 66);'
137+
);
138+
ok(!is_table_verified($output), 'table list_parted2_def not scanned');
139+
ok( $output =~
140+
m/updated partition constraint for default partition "list_parted2_def" is implied by existing constraints/,
141+
'updated partition constraint for default partition list_parted2_def');
142+
143+
# test attach another partitioned table
144+
run_sql_command(
145+
'CREATE TABLE part_5 (
146+
LIKE list_parted2
147+
) PARTITION BY LIST (b);
148+
CREATE TABLE part_5_a PARTITION OF part_5 FOR VALUES IN (\'a\');
149+
ALTER TABLE part_5 ADD CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 5);'
150+
);
151+
$output = run_sql_command(
152+
'ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5);');
153+
ok(!($output =~ m/verifying table "part_5"/), 'table part_5 not scanned');
154+
ok($output =~ m/verifying table "list_parted2_def"/,
155+
'list_parted2_def scanned');
156+
ok( $output =~
157+
m/partition constraint for table "part_5" is implied by existing constraints/,
158+
'part_5 verified by existing constraints');
159+
160+
run_sql_command(
161+
'ALTER TABLE list_parted2 DETACH PARTITION part_5;
162+
ALTER TABLE part_5 DROP CONSTRAINT check_a;');
163+
164+
# scan should again be skipped, even though NOT NULL is now a column property
165+
run_sql_command(
166+
'ALTER TABLE part_5 ADD CONSTRAINT check_a CHECK (a IN (5)),
167+
ALTER a SET NOT NULL;'
168+
);
169+
$output = run_sql_command(
170+
'ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5);');
171+
ok(!($output =~ m/verifying table "part_5"/), 'table part_5 not scanned');
172+
ok($output =~ m/verifying table "list_parted2_def"/,
173+
'list_parted2_def scanned');
174+
ok( $output =~
175+
m/partition constraint for table "part_5" is implied by existing constraints/,
176+
'part_5 verified by existing constraints');
177+
178+
# Check the case where attnos of the partitioning columns in the table being
179+
# attached differs from the parent. It should not affect the constraint-
180+
# checking logic that allows to skip the scan.
181+
run_sql_command(
182+
'CREATE TABLE part_6 (
183+
c int,
184+
LIKE list_parted2,
185+
CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 6)
186+
);
187+
ALTER TABLE part_6 DROP c;');
188+
$output = run_sql_command(
189+
'ALTER TABLE list_parted2 ATTACH PARTITION part_6 FOR VALUES IN (6);');
190+
ok(!($output =~ m/verifying table "part_6"/), 'table part_6 not scanned');
191+
ok($output =~ m/verifying table "list_parted2_def"/,
192+
'list_parted2_def scanned');
193+
ok( $output =~
194+
m/partition constraint for table "part_6" is implied by existing constraints/,
195+
'part_6 verified by existing constraints');
196+
197+
# Similar to above, but the table being attached is a partitioned table
198+
# whose partition has still different attnos for the root partitioning
199+
# columns.
200+
run_sql_command(
201+
'CREATE TABLE part_7 (
202+
LIKE list_parted2,
203+
CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 7)
204+
) PARTITION BY LIST (b);
205+
CREATE TABLE part_7_a_null (
206+
c int,
207+
d int,
208+
e int,
209+
LIKE list_parted2, -- a will have attnum = 4
210+
CONSTRAINT check_b CHECK (b IS NULL OR b = \'a\'),
211+
CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 7)
212+
);
213+
ALTER TABLE part_7_a_null DROP c, DROP d, DROP e;');
214+
215+
$output = run_sql_command(
216+
'ALTER TABLE part_7 ATTACH PARTITION part_7_a_null FOR VALUES IN (\'a\', null);'
217+
);
218+
ok(!is_table_verified($output), 'table not scanned');
219+
ok( $output =~
220+
m/partition constraint for table "part_7_a_null" is implied by existing constraints/,
221+
'part_7_a_null verified by existing constraints');
222+
$output = run_sql_command(
223+
'ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7);');
224+
ok(!is_table_verified($output), 'tables not scanned');
225+
ok( $output =~
226+
m/partition constraint for table "part_7" is implied by existing constraints/,
227+
'part_7 verified by existing constraints');
228+
ok( $output =~
229+
m/updated partition constraint for default partition "list_parted2_def" is implied by existing constraints/,
230+
'updated partition constraint for default partition list_parted2_def');
231+
232+
run_sql_command(
233+
'CREATE TABLE range_parted (
234+
a int,
235+
b int
236+
) PARTITION BY RANGE (a, b);
237+
CREATE TABLE range_part1 (
238+
a int NOT NULL CHECK (a = 1),
239+
b int NOT NULL);');
240+
241+
$output = run_sql_command(
242+
'ALTER TABLE range_parted ATTACH PARTITION range_part1 FOR VALUES FROM (1, 1) TO (1, 10);'
243+
);
244+
ok(is_table_verified($output), 'table range_part1 scanned');
245+
ok( !( $output =~
246+
m/partition constraint for table "range_part1" is implied by existing constraints/
247+
),
248+
'range_part1 not verified by existing constraints');
249+
250+
run_sql_command(
251+
'CREATE TABLE range_part2 (
252+
a int NOT NULL CHECK (a = 1),
253+
b int NOT NULL CHECK (b >= 10 and b < 18)
254+
);');
255+
$output = run_sql_command(
256+
'ALTER TABLE range_parted ATTACH PARTITION range_part2 FOR VALUES FROM (1, 10) TO (1, 20);'
257+
);
258+
ok(!is_table_verified($output), 'table range_part2 not scanned');
259+
ok( $output =~
260+
m/partition constraint for table "range_part2" is implied by existing constraints/,
261+
'range_part2 verified by existing constraints');
262+
263+
# If a partitioned table being created or an existing table being attached
264+
# as a partition does not have a constraint that would allow validation scan
265+
# to be skipped, but an individual partition does, then the partition's
266+
# validation scan is skipped.
267+
run_sql_command(
268+
'CREATE TABLE quuux (a int, b text) PARTITION BY LIST (a);
269+
CREATE TABLE quuux_default PARTITION OF quuux DEFAULT PARTITION BY LIST (b);
270+
CREATE TABLE quuux_default1 PARTITION OF quuux_default (
271+
CONSTRAINT check_1 CHECK (a IS NOT NULL AND a = 1)
272+
) FOR VALUES IN (\'b\');
273+
CREATE TABLE quuux1 (a int, b text);');
274+
275+
$output = run_sql_command(
276+
'ALTER TABLE quuux ATTACH PARTITION quuux1 FOR VALUES IN (1);');
277+
ok(is_table_verified($output), 'quuux1 table scanned');
278+
ok( !( $output =~
279+
m/partition constraint for table "quuux1" is implied by existing constraints/
280+
),
281+
'quuux1 verified by existing constraints');
282+
283+
run_sql_command('CREATE TABLE quuux2 (a int, b text);');
284+
$output = run_sql_command(
285+
'ALTER TABLE quuux ATTACH PARTITION quuux2 FOR VALUES IN (2);');
286+
ok(!($output =~ m/verifying table "quuux_default1"/),
287+
'quuux_default1 not scanned');
288+
ok($output =~ m/verifying table "quuux2"/, 'quuux2 scanned');
289+
ok( $output =~
290+
m/updated partition constraint for default partition "quuux_default1" is implied by existing constraints/,
291+
'updated partition constraint for default partition quuux_default1');
292+
run_sql_command('DROP TABLE quuux1, quuux2;');
293+
294+
# should validate for quuux1, but not for quuux2
295+
$output = run_sql_command(
296+
'CREATE TABLE quuux1 PARTITION OF quuux FOR VALUES IN (1);');
297+
ok(!is_table_verified($output), 'tables not scanned');
298+
ok( !( $output =~
299+
m/partition constraint for table "quuux1" is implied by existing constraints/
300+
),
301+
'quuux1 verified by existing constraints');
302+
$output = run_sql_command(
303+
'CREATE TABLE quuux2 PARTITION OF quuux FOR VALUES IN (2);');
304+
ok(!is_table_verified($output), 'tables not scanned');
305+
ok( $output =~
306+
m/updated partition constraint for default partition "quuux_default1" is implied by existing constraints/,
307+
'updated partition constraint for default partition quuux_default1');
308+
run_sql_command('DROP TABLE quuux;');
309+
310+
$node->stop('fast');

0 commit comments

Comments
 (0)