1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
# Copyright (c) 2024-2025, PostgreSQL Global Development Group
# Tests to cross-check the consistency of GUC parameters with
# postgresql.conf.sample.
use strict;
use warnings FATAL => 'all';
use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;
my $node = PostgreSQL::Test::Cluster->new('main');
$node->init;
$node->start;
# Grab the names of all the parameters that can be listed in the
# configuration sample file. config_file is an exception, it is not
# in postgresql.conf.sample but is part of the lists from guc_tables.c.
# Custom GUCs loaded by extensions are excluded.
my $all_params = $node->safe_psql(
'postgres',
"SELECT name
FROM pg_settings
WHERE NOT 'NOT_IN_SAMPLE' = ANY (pg_settings_get_flags(name)) AND
name <> 'config_file' AND category <> 'Customized Options'
ORDER BY 1");
# Note the lower-case conversion, for consistency.
my @all_params_array = split("\n", lc($all_params));
# Grab the names of all parameters marked as NOT_IN_SAMPLE.
my $not_in_sample = $node->safe_psql(
'postgres',
"SELECT name
FROM pg_settings
WHERE 'NOT_IN_SAMPLE' = ANY (pg_settings_get_flags(name))
ORDER BY 1");
my @not_in_sample_array = split("\n", lc($not_in_sample));
# use the sample file from the temp install
my $share_dir = $node->config_data('--sharedir');
my $sample_file = "$share_dir/postgresql.conf.sample";
# List of all the GUCs found in the sample file.
my @gucs_in_file;
# List of all lines with tabs in the sample file.
my @lines_with_tabs;
# Read the sample file line-by-line, checking its contents to build a list
# of everything known as a GUC.
my $num_tests = 0;
my $line_num = 0;
open(my $contents, '<', $sample_file)
|| die "Could not open $sample_file: $!";
while (my $line = <$contents>)
{
$line_num++;
push @lines_with_tabs, $line_num
if $line =~ /\t/;
# Check if this line matches a GUC parameter:
# - Each parameter is preceded by "#", but not "# " in the sample
# file.
# - Valid configuration options are followed immediately by " = ",
# with one space before and after the equal sign.
if ($line =~ m/^#([_[:alnum:]]+) = .*/)
{
# Lower-case conversion matters for some of the GUCs.
my $param_name = lc($1);
# Ignore some exceptions.
next if $param_name eq "include";
next if $param_name eq "include_dir";
next if $param_name eq "include_if_exists";
# Update the list of GUCs found in the sample file, for the
# follow-up tests.
push @gucs_in_file, $param_name;
next;
}
# Make sure each line starts with either a # or whitespace
fail("$line missing initial # in postgresql.conf.sample")
if $line =~ /^\s*[^#\s]/;
}
close $contents;
# Cross-check that all the GUCs found in the sample file match the ones
# fetched above. This maps the arrays to a hash, making the creation of
# each exclude and intersection list easier.
my %gucs_in_file_hash = map { $_ => 1 } @gucs_in_file;
my %all_params_hash = map { $_ => 1 } @all_params_array;
my %not_in_sample_hash = map { $_ => 1 } @not_in_sample_array;
my @missing_from_file = grep(!$gucs_in_file_hash{$_}, @all_params_array);
is(scalar(@missing_from_file),
0, "no parameters missing from postgresql.conf.sample");
my @missing_from_list = grep(!$all_params_hash{$_}, @gucs_in_file);
is(scalar(@missing_from_list), 0, "no parameters missing from guc_tables.c");
my @sample_intersect = grep($not_in_sample_hash{$_}, @gucs_in_file);
is(scalar(@sample_intersect),
0, "no parameters marked as NOT_IN_SAMPLE in postgresql.conf.sample");
is(scalar(@lines_with_tabs), 0, "no lines with tabs in postgresql.conf.sample");
# These would log some information only on errors.
foreach my $param (@missing_from_file)
{
print(
"found GUC $param in guc_tables.c, missing from postgresql.conf.sample\n"
);
}
foreach my $param (@missing_from_list)
{
print(
"found GUC $param in postgresql.conf.sample, with incorrect info in guc_tables.c\n"
);
}
foreach my $param (@sample_intersect)
{
print(
"found GUC $param in postgresql.conf.sample, marked as NOT_IN_SAMPLE\n"
);
}
foreach my $param (@lines_with_tabs)
{
print("found tab in line $param in postgresql.conf.sample\n");
}
done_testing();
|