1
2# Copyright (c) 2021, PostgreSQL Global Development Group
3
4use strict;
5use warnings;
6
7use PostgresNode;
8use TestLib;
9use Test::More tests => 76;
10
11# Test set-up
12my ($node, $port);
13$node = get_new_node('test');
14$node->init;
15$node->start;
16$port = $node->port;
17
18# Load the amcheck extension, upon which pg_amcheck depends
19$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
20
21#########################################
22# Test non-existent databases
23
24# Failing to connect to the initial database is an error.
25$node->command_checks_all(
26	[ 'pg_amcheck', 'qqq' ],
27	1, [qr/^$/],
28	[qr/FATAL:  database "qqq" does not exist/],
29	'checking a non-existent database');
30
31# Failing to resolve a database pattern is an error by default.
32$node->command_checks_all(
33	[ 'pg_amcheck', '-d', 'qqq', '-d', 'postgres' ],
34	1,
35	[qr/^$/],
36	[qr/pg_amcheck: error: no connectable databases to check matching "qqq"/],
37	'checking an unresolvable database pattern');
38
39# But only a warning under --no-strict-names
40$node->command_checks_all(
41	[ 'pg_amcheck', '--no-strict-names', '-d', 'qqq', '-d', 'postgres' ],
42	0,
43	[qr/^$/],
44	[
45		qr/pg_amcheck: warning: no connectable databases to check matching "qqq"/
46	],
47	'checking an unresolvable database pattern under --no-strict-names');
48
49# Check that a substring of an existent database name does not get interpreted
50# as a matching pattern.
51$node->command_checks_all(
52	[ 'pg_amcheck', '-d', 'post', '-d', 'postgres' ],
53	1,
54	[qr/^$/],
55	[
56		qr/pg_amcheck: error: no connectable databases to check matching "post"/
57	],
58	'checking an unresolvable database pattern (substring of existent database)'
59);
60
61# Check that a superstring of an existent database name does not get interpreted
62# as a matching pattern.
63$node->command_checks_all(
64	[ 'pg_amcheck', '-d', 'postgresql', '-d', 'postgres' ],
65	1,
66	[qr/^$/],
67	[
68		qr/pg_amcheck: error: no connectable databases to check matching "postgresql"/
69	],
70	'checking an unresolvable database pattern (superstring of existent database)'
71);
72
73#########################################
74# Test connecting with a non-existent user
75
76# Failing to connect to the initial database due to bad username is an error.
77$node->command_checks_all([ 'pg_amcheck', '-U', 'no_such_user', 'postgres' ],
78	1, [qr/^$/], [], 'checking with a non-existent user');
79
80#########################################
81# Test checking databases without amcheck installed
82
83# Attempting to check a database by name where amcheck is not installed should
84# raise a warning.  If all databases are skipped, having no relations to check
85# raises an error.
86$node->command_checks_all(
87	[ 'pg_amcheck', 'template1' ],
88	1,
89	[qr/^$/],
90	[
91		qr/pg_amcheck: warning: skipping database "template1": amcheck is not installed/,
92		qr/pg_amcheck: error: no relations to check/
93	],
94	'checking a database by name without amcheck installed, no other databases'
95);
96
97# Again, but this time with another database to check, so no error is raised.
98$node->command_checks_all(
99	[ 'pg_amcheck', '-d', 'template1', '-d', 'postgres' ],
100	0,
101	[qr/^$/],
102	[
103		qr/pg_amcheck: warning: skipping database "template1": amcheck is not installed/
104	],
105	'checking a database by name without amcheck installed, with other databases'
106);
107
108# Again, but by way of checking all databases
109$node->command_checks_all(
110	[ 'pg_amcheck', '--all' ],
111	0,
112	[qr/^$/],
113	[
114		qr/pg_amcheck: warning: skipping database "template1": amcheck is not installed/
115	],
116	'checking a database by pattern without amcheck installed, with other databases'
117);
118
119#########################################
120# Test unreasonable patterns
121
122# Check three-part unreasonable pattern that has zero-length names
123$node->command_checks_all(
124	[ 'pg_amcheck', '-d', 'postgres', '-t', '..' ],
125	1,
126	[qr/^$/],
127	[
128		qr/pg_amcheck: error: no connectable databases to check matching "\.\."/
129	],
130	'checking table pattern ".."');
131
132# Again, but with non-trivial schema and relation parts
133$node->command_checks_all(
134	[ 'pg_amcheck', '-d', 'postgres', '-t', '.foo.bar' ],
135	1,
136	[qr/^$/],
137	[
138		qr/pg_amcheck: error: no connectable databases to check matching "\.foo\.bar"/
139	],
140	'checking table pattern ".foo.bar"');
141
142# Check two-part unreasonable pattern that has zero-length names
143$node->command_checks_all(
144	[ 'pg_amcheck', '-d', 'postgres', '-t', '.' ],
145	1,
146	[qr/^$/],
147	[qr/pg_amcheck: error: no heap tables to check matching "\."/],
148	'checking table pattern "."');
149
150#########################################
151# Test checking non-existent databases, schemas, tables, and indexes
152
153# Use --no-strict-names and a single existent table so we only get warnings
154# about the failed pattern matches
155$node->command_checks_all(
156	[
157		'pg_amcheck', '--no-strict-names',
158		'-t',         'no_such_table',
159		'-t',         'no*such*table',
160		'-i',         'no_such_index',
161		'-i',         'no*such*index',
162		'-r',         'no_such_relation',
163		'-r',         'no*such*relation',
164		'-d',         'no_such_database',
165		'-d',         'no*such*database',
166		'-r',         'none.none',
167		'-r',         'none.none.none',
168		'-r',         'this.is.a.really.long.dotted.string',
169		'-r',         'postgres.none.none',
170		'-r',         'postgres.long.dotted.string',
171		'-r',         'postgres.pg_catalog.none',
172		'-r',         'postgres.none.pg_class',
173		'-t',         'postgres.pg_catalog.pg_class',          # This exists
174	],
175	0,
176	[qr/^$/],
177	[
178		qr/pg_amcheck: warning: no heap tables to check matching "no_such_table"/,
179		qr/pg_amcheck: warning: no heap tables to check matching "no\*such\*table"/,
180		qr/pg_amcheck: warning: no btree indexes to check matching "no_such_index"/,
181		qr/pg_amcheck: warning: no btree indexes to check matching "no\*such\*index"/,
182		qr/pg_amcheck: warning: no relations to check matching "no_such_relation"/,
183		qr/pg_amcheck: warning: no relations to check matching "no\*such\*relation"/,
184		qr/pg_amcheck: warning: no heap tables to check matching "no\*such\*table"/,
185		qr/pg_amcheck: warning: no connectable databases to check matching "no_such_database"/,
186		qr/pg_amcheck: warning: no connectable databases to check matching "no\*such\*database"/,
187		qr/pg_amcheck: warning: no relations to check matching "none\.none"/,
188		qr/pg_amcheck: warning: no connectable databases to check matching "none\.none\.none"/,
189		qr/pg_amcheck: warning: no connectable databases to check matching "this\.is\.a\.really\.long\.dotted\.string"/,
190		qr/pg_amcheck: warning: no relations to check matching "postgres\.none\.none"/,
191		qr/pg_amcheck: warning: no relations to check matching "postgres\.long\.dotted\.string"/,
192		qr/pg_amcheck: warning: no relations to check matching "postgres\.pg_catalog\.none"/,
193		qr/pg_amcheck: warning: no relations to check matching "postgres\.none\.pg_class"/,
194		qr/pg_amcheck: warning: no connectable databases to check matching "no_such_database"/,
195		qr/pg_amcheck: warning: no connectable databases to check matching "no\*such\*database"/,
196		qr/pg_amcheck: warning: no connectable databases to check matching "none\.none\.none"/,
197		qr/pg_amcheck: warning: no connectable databases to check matching "this\.is\.a\.really\.long\.dotted\.string"/,
198	],
199	'many unmatched patterns and one matched pattern under --no-strict-names'
200);
201
202#########################################
203# Test checking otherwise existent objects but in databases where they do not exist
204
205$node->safe_psql(
206	'postgres', q(
207	CREATE TABLE public.foo (f integer);
208	CREATE INDEX foo_idx ON foo(f);
209));
210$node->safe_psql('postgres', q(CREATE DATABASE another_db));
211
212$node->command_checks_all(
213	[
214		'pg_amcheck', '-d',
215		'postgres',   '--no-strict-names',
216		'-t',         'template1.public.foo',
217		'-t',         'another_db.public.foo',
218		'-t',         'no_such_database.public.foo',
219		'-i',         'template1.public.foo_idx',
220		'-i',         'another_db.public.foo_idx',
221		'-i',         'no_such_database.public.foo_idx',
222	],
223	1,
224	[qr/^$/],
225	[
226		qr/pg_amcheck: warning: skipping database "template1": amcheck is not installed/,
227		qr/pg_amcheck: warning: no heap tables to check matching "template1\.public\.foo"/,
228		qr/pg_amcheck: warning: no heap tables to check matching "another_db\.public\.foo"/,
229		qr/pg_amcheck: warning: no connectable databases to check matching "no_such_database\.public\.foo"/,
230		qr/pg_amcheck: warning: no btree indexes to check matching "template1\.public\.foo_idx"/,
231		qr/pg_amcheck: warning: no btree indexes to check matching "another_db\.public\.foo_idx"/,
232		qr/pg_amcheck: warning: no connectable databases to check matching "no_such_database\.public\.foo_idx"/,
233		qr/pg_amcheck: error: no relations to check/,
234	],
235	'checking otherwise existent objets in the wrong databases');
236
237
238#########################################
239# Test schema exclusion patterns
240
241# Check with only schema exclusion patterns
242$node->command_checks_all(
243	[
244		'pg_amcheck', '--all', '--no-strict-names', '-S',
245		'public',     '-S',    'pg_catalog',        '-S',
246		'pg_toast',   '-S',    'information_schema',
247	],
248	1,
249	[qr/^$/],
250	[
251		qr/pg_amcheck: warning: skipping database "template1": amcheck is not installed/,
252		qr/pg_amcheck: error: no relations to check/
253	],
254	'schema exclusion patterns exclude all relations');
255
256# Check with schema exclusion patterns overriding relation and schema inclusion patterns
257$node->command_checks_all(
258	[
259		'pg_amcheck',          '--all', '--no-strict-names',  '-s',
260		'public',              '-s',    'pg_catalog',         '-s',
261		'pg_toast',            '-s',    'information_schema', '-t',
262		'pg_catalog.pg_class', '-S*'
263	],
264	1,
265	[qr/^$/],
266	[
267		qr/pg_amcheck: warning: skipping database "template1": amcheck is not installed/,
268		qr/pg_amcheck: error: no relations to check/
269	],
270	'schema exclusion pattern overrides all inclusion patterns');
271