Skip to content

Commit d1029bb

Browse files
committed
Remove dynamic translation of regression test scripts, step 1.
pg_regress has long had provisions for dynamically substituting path names into regression test scripts and result files, but use of that feature has always been a serious pain in the neck, mainly because updating the result files requires tedious manual editing. Let's get rid of that in favor of passing down the paths in environment variables. In addition to being easier to maintain, this way is capable of dealing with path names that require escaping at runtime, for example paths containing single-quote marks. (There are other stumbling blocks in the way of actually building in a path that looks like that, but removing this one seems like a good thing to do.) The key coding rule that makes that possible is to concatenate pieces of a dynamically-variable string using psql's \set command, and then use the :'variable' notation to quote and escape the string for the next level of interpretation. In hopes of making this change more transparent to "git blame", I've split it into two steps. This commit adds the necessary pg_regress.c support and changes all the *.source files in-place so that they no longer require any dynamic translation. The next commit will just "git mv" them into the regular sql/ and expected/ directories. Discussion: https://postgr.es/m/1655733.1639871614@sss.pgh.pa.us
1 parent 33d3eea commit d1029bb

24 files changed

+477
-263
lines changed

contrib/dblink/input/paths.source

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
-- Initialization that requires path substitution.
22

3+
-- directory paths and dlsuffix are passed to us in environment variables
4+
\getenv abs_srcdir PG_ABS_SRCDIR
5+
\getenv libdir PG_LIBDIR
6+
\getenv dlsuffix PG_DLSUFFIX
7+
8+
\set regresslib :libdir '/regress' :dlsuffix
9+
310
CREATE FUNCTION setenv(text, text)
411
RETURNS void
5-
AS '@libdir@/regress@DLSUFFIX@', 'regress_setenv'
12+
AS :'regresslib', 'regress_setenv'
613
LANGUAGE C STRICT;
714

815
CREATE FUNCTION wait_pid(int)
916
RETURNS void
10-
AS '@libdir@/regress@DLSUFFIX@'
17+
AS :'regresslib'
1118
LANGUAGE C STRICT;
1219

20+
\set path :abs_srcdir '/'
21+
\set fnbody 'SELECT setenv(''PGSERVICEFILE'', ' :'path' ' || $1)'
1322
CREATE FUNCTION set_pgservicefile(text) RETURNS void LANGUAGE SQL
14-
AS $$SELECT setenv('PGSERVICEFILE', '@abs_srcdir@/' || $1)$$;
23+
AS :'fnbody';

contrib/dblink/output/paths.source

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
-- Initialization that requires path substitution.
2+
-- directory paths and dlsuffix are passed to us in environment variables
3+
\getenv abs_srcdir PG_ABS_SRCDIR
4+
\getenv libdir PG_LIBDIR
5+
\getenv dlsuffix PG_DLSUFFIX
6+
\set regresslib :libdir '/regress' :dlsuffix
27
CREATE FUNCTION setenv(text, text)
38
RETURNS void
4-
AS '@libdir@/regress@DLSUFFIX@', 'regress_setenv'
9+
AS :'regresslib', 'regress_setenv'
510
LANGUAGE C STRICT;
611
CREATE FUNCTION wait_pid(int)
712
RETURNS void
8-
AS '@libdir@/regress@DLSUFFIX@'
13+
AS :'regresslib'
914
LANGUAGE C STRICT;
15+
\set path :abs_srcdir '/'
16+
\set fnbody 'SELECT setenv(''PGSERVICEFILE'', ' :'path' ' || $1)'
1017
CREATE FUNCTION set_pgservicefile(text) RETURNS void LANGUAGE SQL
11-
AS $$SELECT setenv('PGSERVICEFILE', '@abs_srcdir@/' || $1)$$;
18+
AS :'fnbody';

contrib/file_fdw/input/file_fdw.source

+41-12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
-- Test foreign-data wrapper file_fdw.
33
--
44

5+
-- directory paths are passed to us in environment variables
6+
\getenv abs_srcdir PG_ABS_SRCDIR
7+
58
-- Clean up in case a prior regression run failed
69
SET client_min_messages TO 'warning';
710
DROP ROLE IF EXISTS regress_file_fdw_superuser, regress_file_fdw_user, regress_no_priv_user;
@@ -14,6 +17,22 @@ CREATE ROLE regress_no_priv_user LOGIN; -- has priv but no user
1417
-- Install file_fdw
1518
CREATE EXTENSION file_fdw;
1619

20+
-- create function to filter unstable results of EXPLAIN
21+
CREATE FUNCTION explain_filter(text) RETURNS setof text
22+
LANGUAGE plpgsql AS
23+
$$
24+
declare
25+
ln text;
26+
begin
27+
for ln in execute $1
28+
loop
29+
-- Remove the path portion of foreign file names
30+
ln := regexp_replace(ln, 'Foreign File: .*/([a-z.]+)$', 'Foreign File: .../\1');
31+
return next ln;
32+
end loop;
33+
end;
34+
$$;
35+
1736
-- regress_file_fdw_superuser owns fdw-related objects
1837
SET ROLE regress_file_fdw_superuser;
1938
CREATE SERVER file_server FOREIGN DATA WRAPPER file_fdw;
@@ -61,33 +80,39 @@ CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'csv', null '
6180
'); -- ERROR
6281
CREATE FOREIGN TABLE tbl () SERVER file_server; -- ERROR
6382

83+
\set filename :abs_srcdir '/data/agg.data'
6484
CREATE FOREIGN TABLE agg_text (
6585
a int2 CHECK (a >= 0),
6686
b float4
6787
) SERVER file_server
68-
OPTIONS (format 'text', filename '@abs_srcdir@/data/agg.data', delimiter ' ', null '\N');
88+
OPTIONS (format 'text', filename :'filename', delimiter ' ', null '\N');
6989
GRANT SELECT ON agg_text TO regress_file_fdw_user;
90+
91+
\set filename :abs_srcdir '/data/agg.csv'
7092
CREATE FOREIGN TABLE agg_csv (
7193
a int2,
7294
b float4
7395
) SERVER file_server
74-
OPTIONS (format 'csv', filename '@abs_srcdir@/data/agg.csv', header 'true', delimiter ';', quote '@', escape '"', null '');
96+
OPTIONS (format 'csv', filename :'filename', header 'true', delimiter ';', quote '@', escape '"', null '');
7597
ALTER FOREIGN TABLE agg_csv ADD CHECK (a >= 0);
98+
99+
\set filename :abs_srcdir '/data/agg.bad'
76100
CREATE FOREIGN TABLE agg_bad (
77101
a int2,
78102
b float4
79103
) SERVER file_server
80-
OPTIONS (format 'csv', filename '@abs_srcdir@/data/agg.bad', header 'true', delimiter ';', quote '@', escape '"', null '');
104+
OPTIONS (format 'csv', filename :'filename', header 'true', delimiter ';', quote '@', escape '"', null '');
81105
ALTER FOREIGN TABLE agg_bad ADD CHECK (a >= 0);
82106

83107
-- per-column options tests
108+
\set filename :abs_srcdir '/data/text.csv'
84109
CREATE FOREIGN TABLE text_csv (
85110
word1 text OPTIONS (force_not_null 'true'),
86111
word2 text OPTIONS (force_not_null 'off'),
87112
word3 text OPTIONS (force_null 'true'),
88113
word4 text OPTIONS (force_null 'off')
89114
) SERVER file_server
90-
OPTIONS (format 'text', filename '@abs_srcdir@/data/text.csv', null 'NULL');
115+
OPTIONS (format 'text', filename :'filename', null 'NULL');
91116
SELECT * FROM text_csv; -- ERROR
92117
ALTER FOREIGN TABLE text_csv OPTIONS (SET format 'csv');
93118
\pset null _null_
@@ -119,7 +144,7 @@ SELECT * FROM agg_bad; -- ERROR
119144

120145
-- misc query tests
121146
\t on
122-
EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv;
147+
SELECT explain_filter('EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv');
123148
\t off
124149
PREPARE st(int) AS SELECT * FROM agg_csv WHERE a = $1;
125150
EXECUTE st(100);
@@ -143,12 +168,12 @@ COPY agg_csv FROM STDIN;
143168

144169
-- constraint exclusion tests
145170
\t on
146-
EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv WHERE a < 0;
171+
SELECT explain_filter('EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv WHERE a < 0');
147172
\t off
148173
SELECT * FROM agg_csv WHERE a < 0;
149174
SET constraint_exclusion = 'on';
150175
\t on
151-
EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv WHERE a < 0;
176+
SELECT explain_filter('EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv WHERE a < 0');
152177
\t off
153178
SELECT * FROM agg_csv WHERE a < 0;
154179
RESET constraint_exclusion;
@@ -170,14 +195,17 @@ DROP TABLE agg;
170195
-- declarative partitioning tests
171196
SET ROLE regress_file_fdw_superuser;
172197
CREATE TABLE pt (a int, b text) partition by list (a);
198+
\set filename :abs_srcdir '/data/list1.csv'
173199
CREATE FOREIGN TABLE p1 partition of pt for values in (1) SERVER file_server
174-
OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
200+
OPTIONS (format 'csv', filename :'filename', delimiter ',');
175201
CREATE TABLE p2 partition of pt for values in (2);
176202
SELECT tableoid::regclass, * FROM pt;
177203
SELECT tableoid::regclass, * FROM p1;
178204
SELECT tableoid::regclass, * FROM p2;
179-
COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter ','); -- ERROR
180-
COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
205+
\set filename :abs_srcdir '/data/list2.bad'
206+
COPY pt FROM :'filename' with (format 'csv', delimiter ','); -- ERROR
207+
\set filename :abs_srcdir '/data/list2.csv'
208+
COPY pt FROM :'filename' with (format 'csv', delimiter ',');
181209
SELECT tableoid::regclass, * FROM pt;
182210
SELECT tableoid::regclass, * FROM p1;
183211
SELECT tableoid::regclass, * FROM p2;
@@ -190,8 +218,9 @@ SELECT tableoid::regclass, * FROM p2;
190218
DROP TABLE pt;
191219

192220
-- generated column tests
221+
\set filename :abs_srcdir '/data/list1.csv'
193222
CREATE FOREIGN TABLE gft1 (a int, b text, c text GENERATED ALWAYS AS ('foo') STORED) SERVER file_server
194-
OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
223+
OPTIONS (format 'csv', filename :'filename', delimiter ',');
195224
SELECT a, c FROM gft1;
196225
DROP FOREIGN TABLE gft1;
197226

@@ -204,7 +233,7 @@ SET ROLE regress_no_priv_user;
204233
SELECT * FROM agg_text ORDER BY a; -- ERROR
205234
SET ROLE regress_file_fdw_user;
206235
\t on
207-
EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_text WHERE a > 0;
236+
SELECT explain_filter('EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_text WHERE a > 0');
208237
\t off
209238
-- file FDW allows foreign tables to be accessed without user mapping
210239
DROP USER MAPPING FOR regress_file_fdw_user SERVER file_server;

contrib/file_fdw/output/file_fdw.source

+40-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
--
22
-- Test foreign-data wrapper file_fdw.
33
--
4+
-- directory paths are passed to us in environment variables
5+
\getenv abs_srcdir PG_ABS_SRCDIR
46
-- Clean up in case a prior regression run failed
57
SET client_min_messages TO 'warning';
68
DROP ROLE IF EXISTS regress_file_fdw_superuser, regress_file_fdw_user, regress_no_priv_user;
@@ -10,6 +12,21 @@ CREATE ROLE regress_file_fdw_user LOGIN; -- has priv and user map
1012
CREATE ROLE regress_no_priv_user LOGIN; -- has priv but no user mapping
1113
-- Install file_fdw
1214
CREATE EXTENSION file_fdw;
15+
-- create function to filter unstable results of EXPLAIN
16+
CREATE FUNCTION explain_filter(text) RETURNS setof text
17+
LANGUAGE plpgsql AS
18+
$$
19+
declare
20+
ln text;
21+
begin
22+
for ln in execute $1
23+
loop
24+
-- Remove the path portion of foreign file names
25+
ln := regexp_replace(ln, 'Foreign File: .*/([a-z.]+)$', 'Foreign File: .../\1');
26+
return next ln;
27+
end loop;
28+
end;
29+
$$;
1330
-- regress_file_fdw_superuser owns fdw-related objects
1431
SET ROLE regress_file_fdw_superuser;
1532
CREATE SERVER file_server FOREIGN DATA WRAPPER file_fdw;
@@ -77,32 +94,36 @@ CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'csv', null '
7794
ERROR: COPY null representation cannot use newline or carriage return
7895
CREATE FOREIGN TABLE tbl () SERVER file_server; -- ERROR
7996
ERROR: either filename or program is required for file_fdw foreign tables
97+
\set filename :abs_srcdir '/data/agg.data'
8098
CREATE FOREIGN TABLE agg_text (
8199
a int2 CHECK (a >= 0),
82100
b float4
83101
) SERVER file_server
84-
OPTIONS (format 'text', filename '@abs_srcdir@/data/agg.data', delimiter ' ', null '\N');
102+
OPTIONS (format 'text', filename :'filename', delimiter ' ', null '\N');
85103
GRANT SELECT ON agg_text TO regress_file_fdw_user;
104+
\set filename :abs_srcdir '/data/agg.csv'
86105
CREATE FOREIGN TABLE agg_csv (
87106
a int2,
88107
b float4
89108
) SERVER file_server
90-
OPTIONS (format 'csv', filename '@abs_srcdir@/data/agg.csv', header 'true', delimiter ';', quote '@', escape '"', null '');
109+
OPTIONS (format 'csv', filename :'filename', header 'true', delimiter ';', quote '@', escape '"', null '');
91110
ALTER FOREIGN TABLE agg_csv ADD CHECK (a >= 0);
111+
\set filename :abs_srcdir '/data/agg.bad'
92112
CREATE FOREIGN TABLE agg_bad (
93113
a int2,
94114
b float4
95115
) SERVER file_server
96-
OPTIONS (format 'csv', filename '@abs_srcdir@/data/agg.bad', header 'true', delimiter ';', quote '@', escape '"', null '');
116+
OPTIONS (format 'csv', filename :'filename', header 'true', delimiter ';', quote '@', escape '"', null '');
97117
ALTER FOREIGN TABLE agg_bad ADD CHECK (a >= 0);
98118
-- per-column options tests
119+
\set filename :abs_srcdir '/data/text.csv'
99120
CREATE FOREIGN TABLE text_csv (
100121
word1 text OPTIONS (force_not_null 'true'),
101122
word2 text OPTIONS (force_not_null 'off'),
102123
word3 text OPTIONS (force_null 'true'),
103124
word4 text OPTIONS (force_null 'off')
104125
) SERVER file_server
105-
OPTIONS (format 'text', filename '@abs_srcdir@/data/text.csv', null 'NULL');
126+
OPTIONS (format 'text', filename :'filename', null 'NULL');
106127
SELECT * FROM text_csv; -- ERROR
107128
ERROR: COPY force not null available only in CSV mode
108129
ALTER FOREIGN TABLE text_csv OPTIONS (SET format 'csv');
@@ -176,10 +197,10 @@ ERROR: invalid input syntax for type real: "aaa"
176197
CONTEXT: COPY agg_bad, line 3, column b: "aaa"
177198
-- misc query tests
178199
\t on
179-
EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv;
200+
SELECT explain_filter('EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv');
180201
Foreign Scan on public.agg_csv
181202
Output: a, b
182-
Foreign File: @abs_srcdir@/data/agg.csv
203+
Foreign File: .../agg.csv
183204

184205
\t off
185206
PREPARE st(int) AS SELECT * FROM agg_csv WHERE a = $1;
@@ -226,11 +247,11 @@ COPY agg_csv FROM STDIN;
226247
ERROR: cannot insert into foreign table "agg_csv"
227248
-- constraint exclusion tests
228249
\t on
229-
EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv WHERE a < 0;
250+
SELECT explain_filter('EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv WHERE a < 0');
230251
Foreign Scan on public.agg_csv
231252
Output: a, b
232253
Filter: (agg_csv.a < 0)
233-
Foreign File: @abs_srcdir@/data/agg.csv
254+
Foreign File: .../agg.csv
234255

235256
\t off
236257
SELECT * FROM agg_csv WHERE a < 0;
@@ -240,7 +261,7 @@ SELECT * FROM agg_csv WHERE a < 0;
240261

241262
SET constraint_exclusion = 'on';
242263
\t on
243-
EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv WHERE a < 0;
264+
SELECT explain_filter('EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv WHERE a < 0');
244265
Result
245266
Output: a, b
246267
One-Time Filter: false
@@ -295,8 +316,9 @@ DROP TABLE agg;
295316
-- declarative partitioning tests
296317
SET ROLE regress_file_fdw_superuser;
297318
CREATE TABLE pt (a int, b text) partition by list (a);
319+
\set filename :abs_srcdir '/data/list1.csv'
298320
CREATE FOREIGN TABLE p1 partition of pt for values in (1) SERVER file_server
299-
OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
321+
OPTIONS (format 'csv', filename :'filename', delimiter ',');
300322
CREATE TABLE p2 partition of pt for values in (2);
301323
SELECT tableoid::regclass, * FROM pt;
302324
tableoid | a | b
@@ -317,10 +339,12 @@ SELECT tableoid::regclass, * FROM p2;
317339
----------+---+---
318340
(0 rows)
319341

320-
COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter ','); -- ERROR
342+
\set filename :abs_srcdir '/data/list2.bad'
343+
COPY pt FROM :'filename' with (format 'csv', delimiter ','); -- ERROR
321344
ERROR: cannot insert into foreign table "p1"
322345
CONTEXT: COPY pt, line 2: "1,qux"
323-
COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
346+
\set filename :abs_srcdir '/data/list2.csv'
347+
COPY pt FROM :'filename' with (format 'csv', delimiter ',');
324348
SELECT tableoid::regclass, * FROM pt;
325349
tableoid | a | b
326350
----------+---+-----
@@ -376,8 +400,9 @@ SELECT tableoid::regclass, * FROM p2;
376400

377401
DROP TABLE pt;
378402
-- generated column tests
403+
\set filename :abs_srcdir '/data/list1.csv'
379404
CREATE FOREIGN TABLE gft1 (a int, b text, c text GENERATED ALWAYS AS ('foo') STORED) SERVER file_server
380-
OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
405+
OPTIONS (format 'csv', filename :'filename', delimiter ',');
381406
SELECT a, c FROM gft1;
382407
a | c
383408
---+--------
@@ -412,11 +437,11 @@ SELECT * FROM agg_text ORDER BY a; -- ERROR
412437
ERROR: permission denied for foreign table agg_text
413438
SET ROLE regress_file_fdw_user;
414439
\t on
415-
EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_text WHERE a > 0;
440+
SELECT explain_filter('EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_text WHERE a > 0');
416441
Foreign Scan on public.agg_text
417442
Output: a, b
418443
Filter: (agg_text.a > 0)
419-
Foreign File: @abs_srcdir@/data/agg.data
444+
Foreign File: .../agg.data
420445

421446
\t off
422447
-- file FDW allows foreign tables to be accessed without user mapping

0 commit comments

Comments
 (0)