line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 NAME |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Module::Build::Database::PostgreSQL - PostgreSQL implementation for MBD |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 SYNOPSIS |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
In Build.PL : |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
my $builder = Module::Build::Database->new( |
10
|
|
|
|
|
|
|
database_type => "PostgreSQL", |
11
|
|
|
|
|
|
|
database_options => { |
12
|
|
|
|
|
|
|
name => "my_database_name", |
13
|
|
|
|
|
|
|
schema => "my_schema_name", |
14
|
|
|
|
|
|
|
# Extra items for scratch databases : |
15
|
|
|
|
|
|
|
append_to_conf => "text to add to postgresql.conf", |
16
|
|
|
|
|
|
|
after_create => q[create schema audit;], |
17
|
|
|
|
|
|
|
}, |
18
|
|
|
|
|
|
|
database_extensions => { |
19
|
|
|
|
|
|
|
postgis => { schema => "public", }, |
20
|
|
|
|
|
|
|
# directory with postgis.sql and spatial_ref_sys.sql |
21
|
|
|
|
|
|
|
postgis_base => '/usr/local/share/postgresql/contrib' |
22
|
|
|
|
|
|
|
}, |
23
|
|
|
|
|
|
|
); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head1 DESCRIPTION |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
Postgres driver for L. |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 OPTIONS |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
All of the options above may be changed via the Module::Build option |
32
|
|
|
|
|
|
|
handling, e.g. |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
perl Build.PL --database_options name=my_name |
35
|
|
|
|
|
|
|
perl Build.PL --postgis_base=/usr/local/share/postgresql/contrib |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
The options are as follows ; |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=over 4 |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=item database_options |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=over 4 |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=item name |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
the name of the database (i.e. 'create database $name') |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=item schema |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
the name of the schema to be managed by MBD |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=item append_to_conf |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
extra options to append to C before starting test instances of postgres |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=item after_create |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
extra SQL to run after running a 'create database' statement. Note that this will be run in several |
60
|
|
|
|
|
|
|
different situations : |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=over 4 |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=item 1. |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
during a L (creating a test db) |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=item 2. |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
during a L (also creating a test db) |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=item 3. |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
during an initial L; when the target database does not yet exist. |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=back |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
An example of using the after_create statement would be to create a second schema which |
79
|
|
|
|
|
|
|
will not be managed by MBD, but on which the MBD-managed schema depends. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=back |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=item database_extension |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
To specify a server side procedural language you can use the C -E C |
86
|
|
|
|
|
|
|
option, like so: |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
my $builder = Module::Build::Database->new( |
89
|
|
|
|
|
|
|
database_extension => { |
90
|
|
|
|
|
|
|
languages => [ 'plperl', 'pltcl' ], |
91
|
|
|
|
|
|
|
}, |
92
|
|
|
|
|
|
|
); |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
Trying to create languages to a patch will not work because they not stored in the main schema and will |
95
|
|
|
|
|
|
|
not be included in C when you run C. |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
This is also similar to |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
after_create => 'create extension ...', |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
except it is executed on B L meaning you can use this to add extensions to |
102
|
|
|
|
|
|
|
existing database deployments. |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=item postgis_base |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
Specify the directory containing postgis.sql and spatial_ref_sys.sql. If specified these SQL files will be loaded so that |
107
|
|
|
|
|
|
|
you can use PostGIS in your database. |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=item leave_running |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
If set to true, and if you are not using a persistent scratch database (see next option), then the scratch database will |
112
|
|
|
|
|
|
|
not be stopped and torn down after running C or C. |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=item scratch_database |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
You can use this option to specify the connection settings for a persistent scratch or temporary database instance, used by |
117
|
|
|
|
|
|
|
the C and C to test schema. B: the C and C |
118
|
|
|
|
|
|
|
will drop and re-create databases on the scratch instance with the same name as the database on your production instance so |
119
|
|
|
|
|
|
|
it is I important that if you use a persistent scratch database that it be dedicated to that task. |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
my $builder = Module::Build::Database->new( |
122
|
|
|
|
|
|
|
scratch_database => { |
123
|
|
|
|
|
|
|
PGHOST => 'databasehost', |
124
|
|
|
|
|
|
|
PGPORT => '5555', |
125
|
|
|
|
|
|
|
PGUSER => 'dbuser', |
126
|
|
|
|
|
|
|
}, |
127
|
|
|
|
|
|
|
); |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
If you specify any one of these keys for this option (C, C, C) then MBD will use a persistent |
130
|
|
|
|
|
|
|
scratch database. Any missing values will use the default. |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
You can also specify these settings using environment variables: |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
% export MBD_SCRATCH_PGHOST=databasehost |
135
|
|
|
|
|
|
|
% export MBD_SCRATCH_PGPORT=5555 |
136
|
|
|
|
|
|
|
% export MBD_SCRATCH_PGUSER=dbuser |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
By default this module will create its own scratch PostgreSQL instance that uses unix domain sockets for communication |
139
|
|
|
|
|
|
|
each time it needs one when you use the C or C commands. Situations where you might |
140
|
|
|
|
|
|
|
need to use a persistent scratch database: |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=over 4 |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=item 1. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
The server and server binaries are hosted on a system different to the one that you are doing development |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=item 2. |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
You are using MBD on Windows where unix domain sockets are not available |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=back |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=back |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head1 NOTES |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
The environment variables understood by C: |
159
|
|
|
|
|
|
|
C, C and C will be used when |
160
|
|
|
|
|
|
|
connecting to a live database (for L and |
161
|
|
|
|
|
|
|
L). C will be ignored; |
162
|
|
|
|
|
|
|
the name of the database should be specified in |
163
|
|
|
|
|
|
|
Build.PL instead. |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=cut |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
package Module::Build::Database::PostgreSQL; |
168
|
4
|
|
|
4
|
|
123887
|
use base 'Module::Build::Database'; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
2010
|
|
169
|
4
|
|
|
4
|
|
32
|
use File::Temp qw/tempdir/; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
246
|
|
170
|
4
|
|
|
4
|
|
18
|
use File::Path qw/rmtree/; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
153
|
|
171
|
4
|
|
|
4
|
|
19
|
use File::Basename qw/dirname/; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
148
|
|
172
|
4
|
|
|
4
|
|
2137
|
use File::Copy::Recursive qw/fcopy dirmove/; |
|
4
|
|
|
|
|
8702
|
|
|
4
|
|
|
|
|
264
|
|
173
|
4
|
|
|
4
|
|
25
|
use Path::Class qw/file/; |
|
4
|
|
|
|
|
5
|
|
|
4
|
|
|
|
|
134
|
|
174
|
4
|
|
|
4
|
|
16
|
use IO::File; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
448
|
|
175
|
4
|
|
|
4
|
|
18
|
use File::Which qw( which ); |
|
4
|
|
|
|
|
4
|
|
|
4
|
|
|
|
|
126
|
|
176
|
|
|
|
|
|
|
|
177
|
4
|
|
|
4
|
|
2386
|
use Module::Build::Database::PostgreSQL::Templates; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
118
|
|
178
|
4
|
|
|
4
|
|
17
|
use Module::Build::Database::Helpers qw/do_system verify_bin info debug/; |
|
4
|
|
|
|
|
5
|
|
|
4
|
|
|
|
|
36
|
|
179
|
4
|
|
|
4
|
|
1476
|
use strict; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
97
|
|
180
|
4
|
|
|
4
|
|
15
|
use warnings; |
|
4
|
|
|
|
|
5
|
|
|
4
|
|
|
|
|
11093
|
|
181
|
|
|
|
|
|
|
our $VERSION = '0.57'; |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
__PACKAGE__->add_property(database_options => default => { name => "foo", schema => "bar" }); |
184
|
|
|
|
|
|
|
__PACKAGE__->add_property(database_extensions => default => { postgis => 0 } ); |
185
|
|
|
|
|
|
|
__PACKAGE__->add_property(postgis_base => default => "/usr/local/share/postgis" ); |
186
|
|
|
|
|
|
|
__PACKAGE__->add_property(_tmp_db_dir => default => "" ); |
187
|
|
|
|
|
|
|
__PACKAGE__->add_property(leave_running => default => 0 ); # leave running after dbtest? |
188
|
|
|
|
|
|
|
__PACKAGE__->add_property(scratch_database => default => { map {; "PG$_" => $ENV{"MBD_SCRATCH_PG$_"} } |
189
|
|
|
|
|
|
|
grep { defined $ENV{"MBD_SCRATCH_PG$_"} } |
190
|
|
|
|
|
|
|
qw( HOST PORT USER ) } ); |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# Binaries used by this module. They should be in $ENV{PATH}. |
193
|
|
|
|
|
|
|
our %Bin = ( |
194
|
|
|
|
|
|
|
Psql => 'psql', |
195
|
|
|
|
|
|
|
Pgctl => 'pg_ctl', |
196
|
|
|
|
|
|
|
Postgres => 'postgres', |
197
|
|
|
|
|
|
|
Initdb => 'initdb', |
198
|
|
|
|
|
|
|
Createdb => 'createdb', |
199
|
|
|
|
|
|
|
Dropdb => 'dropdb', |
200
|
|
|
|
|
|
|
Pgdump => 'pg_dump', |
201
|
|
|
|
|
|
|
Pgdoc => [ qw/pg_autodoc postgresql_autodoc/ ], |
202
|
|
|
|
|
|
|
); |
203
|
|
|
|
|
|
|
my $server_bin_dir; |
204
|
|
|
|
|
|
|
if(my $pg_config = which 'pg_config') |
205
|
|
|
|
|
|
|
{ |
206
|
|
|
|
|
|
|
$pg_config = Win32::GetShortPathName($pg_config) if $^O eq 'MSWin32' && $pg_config =~ /\s/; |
207
|
|
|
|
|
|
|
$server_bin_dir = `$pg_config --bindir`; |
208
|
|
|
|
|
|
|
chomp $server_bin_dir; |
209
|
|
|
|
|
|
|
$server_bin_dir = Win32::GetShortPathName($server_bin_dir) if $^O eq 'MSWin32' && $server_bin_dir =~ /\s/; |
210
|
|
|
|
|
|
|
undef $server_bin_dir unless -d $server_bin_dir; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
verify_bin(\%Bin, $server_bin_dir); |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
sub _do_psql { |
215
|
0
|
|
|
0
|
|
|
my $self = shift; |
216
|
0
|
|
|
|
|
|
my $sql = shift; |
217
|
0
|
|
|
|
|
|
my $database_name = $self->database_options('name'); |
218
|
0
|
|
|
|
|
|
my $tmp = File::Temp->new(TEMPLATE => "tmp_db_XXXX", SUFFIX => '.sql'); |
219
|
0
|
|
|
|
|
|
print $tmp $sql; |
220
|
0
|
|
|
|
|
|
$tmp->close; |
221
|
|
|
|
|
|
|
# -q: quiet, ON_ERROR_STOP: throw exceptions |
222
|
0
|
|
|
|
|
|
local $ENV{PERL5LIB}; |
223
|
0
|
|
|
|
|
|
my $ret = do_system( $Bin{Psql}, "-q", "-vON_ERROR_STOP=1", "-f", "$tmp", $database_name ); |
224
|
0
|
|
|
|
|
|
$tmp->unlink_on_destroy($ret); |
225
|
0
|
|
|
|
|
|
$ret; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
sub _do_psql_out { |
228
|
0
|
|
|
0
|
|
|
my $self = shift; |
229
|
0
|
|
|
|
|
|
my $sql = shift; |
230
|
0
|
|
|
|
|
|
my $database_name = $self->database_options('name'); |
231
|
|
|
|
|
|
|
# -F field separator, -x extended output, -A: unaligned |
232
|
0
|
|
|
|
|
|
local $ENV{PERL5LIB}; |
233
|
0
|
|
|
|
|
|
do_system( $Bin{Psql}, "-q", "-vON_ERROR_STOP=1", "-A", "-F ' : '", "-x", "-c", qq["$sql"], $database_name ); |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
sub _do_psql_file { |
236
|
0
|
|
|
0
|
|
|
my $self = shift; |
237
|
0
|
|
|
|
|
|
my $filename = shift; |
238
|
0
|
0
|
|
|
|
|
unless (-e $filename) { |
239
|
0
|
|
|
|
|
|
warn "could not open file $filename"; |
240
|
0
|
|
|
|
|
|
return 0; |
241
|
|
|
|
|
|
|
} |
242
|
0
|
0
|
|
|
|
|
unless (-s $filename) { |
243
|
0
|
|
|
|
|
|
warn "file $filename is empty"; |
244
|
0
|
|
|
|
|
|
return 0; |
245
|
|
|
|
|
|
|
} |
246
|
0
|
|
|
|
|
|
my $database_name = $self->database_options('name'); |
247
|
|
|
|
|
|
|
# -q: quiet, ON_ERROR_STOP: throw exceptions |
248
|
0
|
|
|
|
|
|
local $ENV{PERL5LIB}; |
249
|
0
|
|
|
|
|
|
do_system($Bin{Psql},"-q","-vON_ERROR_STOP=1","-f",$filename, $database_name); |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
sub _do_psql_into_file { |
252
|
0
|
|
|
0
|
|
|
my $self = shift; |
253
|
0
|
|
|
|
|
|
my $filename = shift; |
254
|
0
|
|
|
|
|
|
my $sql = shift; |
255
|
0
|
|
|
|
|
|
my $database_name = $self->database_options('name'); |
256
|
|
|
|
|
|
|
# -A: unaligned, -F: field separator, -t: tuples only, ON_ERROR_STOP: throw exceptions |
257
|
0
|
|
|
|
|
|
local $ENV{PERL5LIB}; |
258
|
0
|
0
|
|
|
|
|
my $q = $^O eq 'MSWin32' ? '"' : "'"; |
259
|
0
|
|
|
|
|
|
do_system( $Bin{Psql}, "-q", "-vON_ERROR_STOP=1", "-A", "-F $q\t$q", "-t", "-c", qq["$sql"], $database_name, ">", "$filename" ); |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
sub _do_psql_capture { |
262
|
0
|
|
|
0
|
|
|
my $self = shift; |
263
|
0
|
|
|
|
|
|
my $sql = shift; |
264
|
0
|
|
|
|
|
|
my $database_name = $self->database_options('name'); |
265
|
0
|
|
|
|
|
|
local $ENV{PERL5LIB}; |
266
|
0
|
|
|
|
|
|
return qx[$Bin{Psql} -c "$sql" $database_name]; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
sub _cleanup_old_dbs { |
270
|
0
|
|
|
0
|
|
|
my $self = shift; |
271
|
0
|
|
|
|
|
|
my %args = @_; # pass all => 1 to clean up the current one too |
272
|
|
|
|
|
|
|
|
273
|
0
|
|
|
|
|
|
my $glob; |
274
|
|
|
|
|
|
|
{ |
275
|
0
|
|
|
|
|
|
my $tmpdir = tempdir("mbdtest_XXXXXX", TMPDIR => 1); |
|
0
|
|
|
|
|
|
|
276
|
0
|
|
|
|
|
|
$glob = "$tmpdir"; |
277
|
0
|
|
|
|
|
|
rmtree($tmpdir); |
278
|
|
|
|
|
|
|
} |
279
|
0
|
|
|
|
|
|
$glob =~ s/mbdtest_.*$/mbdtest_*/; |
280
|
0
|
|
|
|
|
|
for my $thisdir (glob $glob) { |
281
|
0
|
0
|
0
|
|
|
|
next unless -d $thisdir && -w $thisdir; |
282
|
0
|
|
|
|
|
|
debug "cleaning up old tmp instance : $thisdir"; |
283
|
0
|
|
|
|
|
|
$self->_stop_db("$thisdir/db"); |
284
|
0
|
|
|
|
|
|
rmtree($thisdir); |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
sub _start_new_db { |
289
|
0
|
|
|
0
|
|
|
my $self = shift; |
290
|
|
|
|
|
|
|
# Start a new database and return the host on which it was started. |
291
|
|
|
|
|
|
|
|
292
|
0
|
|
|
|
|
|
my $database_name = $self->database_options('name'); |
293
|
0
|
|
|
|
|
|
$ENV{PGDATABASE} = $database_name; |
294
|
|
|
|
|
|
|
|
295
|
0
|
0
|
|
|
|
|
if(%{ $self->scratch_database }) { |
|
0
|
|
|
|
|
|
|
296
|
0
|
|
|
|
|
|
delete @ENV{qw( PGHOST PGUSER PGPORT )}; |
297
|
0
|
|
|
|
|
|
%ENV = (%ENV, %{ $self->scratch_database }); |
|
0
|
|
|
|
|
|
|
298
|
0
|
|
|
|
|
|
do_system("_silent", $Bin{Dropdb}, $database_name); |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
} else { |
301
|
|
|
|
|
|
|
|
302
|
0
|
|
|
|
|
|
$self->_cleanup_old_dbs(); |
303
|
|
|
|
|
|
|
|
304
|
0
|
|
|
|
|
|
my $tmpdir = tempdir("mbdtest_XXXXXX", TMPDIR => 1); |
305
|
0
|
|
|
|
|
|
my $dbdir = $tmpdir."/db"; |
306
|
0
|
|
|
|
|
|
my $initlog = "$tmpdir/postgres.log"; |
307
|
0
|
|
|
|
|
|
$self->_tmp_db_dir($dbdir); |
308
|
|
|
|
|
|
|
|
309
|
0
|
|
|
|
|
|
$ENV{PGHOST} = "$dbdir"; # makes psql use a socket, not a tcp port |
310
|
0
|
|
|
|
|
|
delete $ENV{PGUSER}; |
311
|
0
|
|
|
|
|
|
delete $ENV{PGPORT}; |
312
|
|
|
|
|
|
|
|
313
|
0
|
|
|
|
|
|
debug "initializing database (log: $initlog)"; |
314
|
|
|
|
|
|
|
|
315
|
0
|
0
|
|
|
|
|
do_system($Bin{Initdb}, "-D", "$dbdir", ">>", "$initlog", "2>&1") or do { |
316
|
0
|
|
|
|
|
|
my $log = ''; |
317
|
0
|
0
|
|
|
|
|
$log = file($initlog)->slurp if -e $initlog; |
318
|
0
|
|
|
|
|
|
die "could not initdb ($Bin{Initdb})\n$log\n"; |
319
|
|
|
|
|
|
|
}; |
320
|
|
|
|
|
|
|
|
321
|
0
|
0
|
|
|
|
|
if (my $conf_append = $self->database_options('append_to_conf')) { |
322
|
0
|
0
|
|
|
|
|
die "cannot find postgresql.conf" unless -e "$dbdir/postgresql.conf"; |
323
|
0
|
0
|
|
|
|
|
open my $fp, ">> $dbdir/postgresql.conf" or die "could not open postgresql.conf : $!"; |
324
|
0
|
|
|
|
|
|
print $fp $conf_append; |
325
|
0
|
|
|
|
|
|
close $fp; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
0
|
|
|
|
|
|
my $pmopts = qq[-k $dbdir -h '' -p 5432]; |
329
|
|
|
|
|
|
|
|
330
|
0
|
|
|
|
|
|
debug "# starting postgres in $dbdir"; |
331
|
0
|
0
|
|
|
|
|
do_system($Bin{Pgctl}, qq[-o "$pmopts"], "-w", "-t", 120, "-D", "$dbdir", "-l", "postmaster.log", "start") or do { |
332
|
0
|
|
|
|
|
|
my $log; |
333
|
0
|
0
|
|
|
|
|
if (-e "$dbdir/postmaster.log") { |
334
|
0
|
|
|
|
|
|
$log = file("$dbdir/postmaster.log")->slurp; |
335
|
|
|
|
|
|
|
} else { |
336
|
0
|
|
|
|
|
|
$log = "no log file : $dbdir/postmaster.log"; |
337
|
|
|
|
|
|
|
} |
338
|
0
|
|
|
|
|
|
die "could not start postgres\n$log\n "; |
339
|
|
|
|
|
|
|
}; |
340
|
|
|
|
|
|
|
|
341
|
0
|
|
|
|
|
|
my $domain = $dbdir.'/.s.PGSQL.5432'; |
342
|
0
|
0
|
|
|
|
|
-e $domain or die "could not find $domain"; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
0
|
|
|
|
|
|
$self->_create_database(); |
346
|
|
|
|
|
|
|
|
347
|
0
|
|
|
|
|
|
return $self->_dbhost; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
sub _remove_db { |
351
|
0
|
|
|
0
|
|
|
my $self = shift; |
352
|
0
|
0
|
0
|
|
|
|
return if $ENV{MBD_DONT_STOP_TEST_DB} || %{ $self->scratch_database }; |
|
0
|
|
|
|
|
|
|
353
|
0
|
|
0
|
|
|
|
my $dbdir = shift || $self->_tmp_db_dir(); |
354
|
0
|
|
|
|
|
|
$dbdir =~ s/\/db$//; |
355
|
0
|
|
|
|
|
|
rmtree $dbdir; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub _stop_db { |
359
|
0
|
|
|
0
|
|
|
my $self = shift; |
360
|
0
|
0
|
0
|
|
|
|
return if $ENV{MBD_DONT_STOP_TEST_DB} || %{ $self->scratch_database }; |
|
0
|
|
|
|
|
|
|
361
|
0
|
|
0
|
|
|
|
my $dbdir = shift || $self->_tmp_db_dir(); |
362
|
0
|
|
|
|
|
|
my $pid_file = "$dbdir/postmaster.pid"; |
363
|
0
|
0
|
|
|
|
|
unless (-e $pid_file) { |
364
|
0
|
|
|
|
|
|
debug "no pid file ($pid_file), not stopping db"; |
365
|
0
|
|
|
|
|
|
return; |
366
|
|
|
|
|
|
|
} |
367
|
0
|
|
|
|
|
|
my ($pid) = IO::File->new("<$pid_file")->getlines; |
368
|
0
|
|
|
|
|
|
chomp $pid; |
369
|
0
|
|
|
|
|
|
kill "TERM", $pid; |
370
|
0
|
|
|
|
|
|
sleep 1; |
371
|
0
|
0
|
|
|
|
|
return unless kill 0, $pid; |
372
|
0
|
0
|
|
|
|
|
kill 9, $pid or info "could not send signal to $pid"; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
sub _apply_base_sql { |
376
|
0
|
|
|
0
|
|
|
my $self = shift; |
377
|
0
|
|
0
|
|
|
|
my $filename = shift || $self->base_dir."/db/dist/base.sql"; |
378
|
0
|
0
|
|
|
|
|
return unless -e $filename; |
379
|
0
|
|
|
|
|
|
info "applying base.sql"; |
380
|
0
|
|
|
|
|
|
$self->_do_psql_file($filename); |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub _apply_base_data { |
384
|
0
|
|
|
0
|
|
|
my $self = shift; |
385
|
0
|
|
0
|
|
|
|
my $filename = shift || $self->base_dir."/db/dist/base_data.sql"; |
386
|
0
|
0
|
|
|
|
|
return 1 unless -e $filename; |
387
|
0
|
|
|
|
|
|
info "applying base_data.sql"; |
388
|
0
|
|
|
|
|
|
$self->_do_psql_file($filename); |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
sub _dump_base_sql { |
392
|
|
|
|
|
|
|
# Optional parameter "outfile" gives the name of the file into which to dump the schema. |
393
|
|
|
|
|
|
|
# If the parameter is omitted, dump and atomically rename to db/dist/base.sql. |
394
|
0
|
|
|
0
|
|
|
my $self = shift; |
395
|
0
|
|
|
|
|
|
my %args = @_; |
396
|
0
|
|
0
|
|
|
|
my $outfile = $args{outfile} || $self->base_dir. "/db/dist/base.sql"; |
397
|
|
|
|
|
|
|
|
398
|
0
|
|
|
|
|
|
my $tmpfile = file( tempdir( CLEANUP => 1 ), 'dump.sql'); |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
# -x : no privileges, -O : no owner, -s : schema only, -n : only this schema |
401
|
0
|
|
|
|
|
|
my $database_schema = $self->database_options('schema'); |
402
|
0
|
|
|
|
|
|
my $database_name = $self->database_options('name'); |
403
|
0
|
|
|
|
|
|
local $ENV{PERL5LIB}; |
404
|
|
|
|
|
|
|
do_system( $Bin{Pgdump}, "-xOs", "-E", "utf8", "-n", $database_schema, $database_name, ">", $tmpfile ) |
405
|
0
|
0
|
|
|
|
|
or do { |
406
|
0
|
|
|
|
|
|
info "Error running pgdump"; |
407
|
0
|
|
|
|
|
|
die "Error running pgdump : $! ${^CHILD_ERROR_NATIVE}"; |
408
|
0
|
|
|
|
|
|
return 0; |
409
|
|
|
|
|
|
|
}; |
410
|
|
|
|
|
|
|
|
411
|
0
|
|
|
|
|
|
my @lines = $tmpfile->slurp(); |
412
|
0
|
0
|
|
|
|
|
unless (@lines) { |
413
|
0
|
|
|
|
|
|
die "# Could not run pgdump and write to $tmpfile"; |
414
|
|
|
|
|
|
|
} |
415
|
0
|
|
0
|
|
|
|
@lines = grep { |
416
|
0
|
|
|
|
|
|
$_ !~ /^--/ |
417
|
|
|
|
|
|
|
and $_ !~ /^CREATE SCHEMA $database_schema;$/ |
418
|
|
|
|
|
|
|
and $_ !~ /^SET (search_path|lock_timeout)/ |
419
|
|
|
|
|
|
|
} @lines; |
420
|
0
|
|
|
|
|
|
for (@lines) { |
421
|
0
|
0
|
|
|
|
|
/alter table/i and s/$database_schema\.//; |
422
|
|
|
|
|
|
|
} |
423
|
0
|
|
|
|
|
|
file($outfile)->spew(join '', @lines); |
424
|
0
|
0
|
0
|
|
|
|
if (@lines > 0 && !-s $outfile) { |
425
|
0
|
|
|
|
|
|
die "# Unable to write to $outfile"; |
426
|
|
|
|
|
|
|
} |
427
|
0
|
|
|
|
|
|
return 1; |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
sub _dump_base_data { |
431
|
|
|
|
|
|
|
# Optional parameter "outfile, defaults to db/dist/base_data.sql |
432
|
0
|
|
|
0
|
|
|
my $self = shift; |
433
|
0
|
|
|
|
|
|
my %args = @_; |
434
|
0
|
|
0
|
|
|
|
my $outfile = $args{outfile} || $self->base_dir. "/db/dist/base_data.sql"; |
435
|
|
|
|
|
|
|
|
436
|
0
|
|
|
|
|
|
my $tmpfile = File::Temp->new( |
437
|
|
|
|
|
|
|
TEMPLATE => (dirname $outfile)."/dump_XXXXXX", |
438
|
|
|
|
|
|
|
UNLINK => 0 |
439
|
|
|
|
|
|
|
); |
440
|
0
|
|
|
|
|
|
$tmpfile->close; |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
# -x : no privileges, -O : no owner, -s : schema only, -n : only this schema |
443
|
0
|
|
|
|
|
|
my $database_schema = $self->database_options('schema'); |
444
|
0
|
|
|
|
|
|
my $database_name = $self->database_options('name'); |
445
|
0
|
|
|
|
|
|
local $ENV{PERL5LIB}; |
446
|
0
|
0
|
|
|
|
|
do_system( $Bin{Pgdump}, "--data-only", "-xO", "-E", "utf8", "-n", $database_schema, $database_name, |
447
|
|
|
|
|
|
|
"|", "egrep -v '^SET (lock_timeout|search_path)'", |
448
|
|
|
|
|
|
|
">", "$tmpfile" ) |
449
|
|
|
|
|
|
|
or return 0; |
450
|
0
|
0
|
|
|
|
|
rename "$tmpfile", $outfile or die "rename failed: $!"; |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
sub _apply_patch { |
454
|
0
|
|
|
0
|
|
|
my $self = shift; |
455
|
0
|
|
|
|
|
|
my $patch_file = shift; |
456
|
|
|
|
|
|
|
|
457
|
0
|
|
|
|
|
|
return $self->_do_psql_file($self->base_dir."/db/patches/$patch_file"); |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
sub _is_fresh_install { |
461
|
0
|
|
|
0
|
|
|
my $self = shift; |
462
|
|
|
|
|
|
|
|
463
|
0
|
|
|
|
|
|
my $database_name = $self->database_options('name'); |
464
|
0
|
0
|
|
|
|
|
unless ($self->_database_exists) { |
465
|
0
|
|
|
|
|
|
info "database $database_name does not exist"; |
466
|
0
|
|
|
|
|
|
return 1; |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
|
469
|
0
|
|
|
|
|
|
my $file = File::Temp->new(); $file->close; |
|
0
|
|
|
|
|
|
|
470
|
0
|
|
|
|
|
|
my $database_schema = $self->database_options('schema'); |
471
|
0
|
|
|
|
|
|
$self->_do_psql_into_file("$file","\\dn $database_schema"); |
472
|
0
|
|
|
|
|
|
return !do_system("_silent","grep -q $database_schema $file"); |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
sub _show_live_db { |
476
|
|
|
|
|
|
|
# Display the connection information |
477
|
0
|
|
|
0
|
|
|
my $self = shift; |
478
|
|
|
|
|
|
|
|
479
|
0
|
|
0
|
|
|
|
info "PGUSER : " . ( $ENV{PGUSER} || "" ); |
480
|
0
|
|
0
|
|
|
|
info "PGHOST : " . ( $ENV{PGHOST} || "" ); |
481
|
0
|
|
0
|
|
|
|
info "PGPORT : " . ( $ENV{PGPORT} || "" ); |
482
|
|
|
|
|
|
|
|
483
|
0
|
|
0
|
|
|
|
my $database_name = shift || $self->database_options('name'); |
484
|
0
|
|
|
|
|
|
info "database : $database_name"; |
485
|
|
|
|
|
|
|
|
486
|
0
|
0
|
|
|
|
|
return unless $self->_database_exists; |
487
|
0
|
|
|
|
|
|
$self->_do_psql_out("select current_database(),session_user,version();"); |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
sub _patch_table_exists { |
491
|
|
|
|
|
|
|
# returns true or false |
492
|
0
|
|
|
0
|
|
|
my $self = shift; |
493
|
0
|
|
|
|
|
|
my $file = File::Temp->new(); $file->close; |
|
0
|
|
|
|
|
|
|
494
|
0
|
|
|
|
|
|
my $database_schema = $self->database_options('schema'); |
495
|
0
|
|
|
|
|
|
$self->_do_psql_into_file("$file","select tablename from pg_tables where tablename='patches_applied' and schemaname = '$database_schema'"); |
496
|
0
|
|
|
|
|
|
return do_system("_silent","grep -q patches_applied $file"); |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
sub _dump_patch_table { |
500
|
|
|
|
|
|
|
# Dump the patch table in an existing db into a flat file, that |
501
|
|
|
|
|
|
|
# will be in the same format as patches_applied.txt. |
502
|
0
|
|
|
0
|
|
|
my $self = shift; |
503
|
0
|
|
|
|
|
|
my %args = @_; |
504
|
0
|
0
|
|
|
|
|
my $filename = $args{outfile} or Carp::confess "need a filename"; |
505
|
0
|
|
|
|
|
|
my $database_schema = $self->database_options('schema'); |
506
|
0
|
|
|
|
|
|
$self->_do_psql_into_file($filename,"select patch_name,patch_md5 from $database_schema.patches_applied order by patch_name"); |
507
|
|
|
|
|
|
|
} |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
sub _create_patch_table { |
510
|
0
|
|
|
0
|
|
|
my $self = shift; |
511
|
|
|
|
|
|
|
# create a new patch table |
512
|
0
|
|
|
|
|
|
my $database_schema = $self->database_options('schema'); |
513
|
0
|
|
|
|
|
|
my $sql = <
|
514
|
|
|
|
|
|
|
CREATE TABLE $database_schema.patches_applied ( |
515
|
|
|
|
|
|
|
patch_name varchar(255) primary key, |
516
|
|
|
|
|
|
|
patch_md5 varchar(255), |
517
|
|
|
|
|
|
|
when_applied timestamp ); |
518
|
|
|
|
|
|
|
EOSQL |
519
|
0
|
|
|
|
|
|
$self->_do_psql($sql); |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
sub _insert_patch_record { |
523
|
0
|
|
|
0
|
|
|
my $self = shift; |
524
|
0
|
|
|
|
|
|
my $record = shift; |
525
|
0
|
|
|
|
|
|
my ($name,$md5) = @$record; |
526
|
0
|
|
|
|
|
|
my $database_schema = $self->database_options('schema'); |
527
|
0
|
|
|
|
|
|
$self->_do_psql("insert into $database_schema.patches_applied (patch_name, patch_md5, when_applied) ". |
528
|
|
|
|
|
|
|
" values ('$name','$md5',now()) "); |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
sub _database_exists { |
532
|
0
|
|
|
0
|
|
|
my $self = shift; |
533
|
0
|
|
0
|
|
|
|
my $database_name = shift || $self->database_options('name'); |
534
|
0
|
|
|
|
|
|
local $ENV{PERL5LIB}; |
535
|
0
|
|
|
|
|
|
scalar grep /^$database_name$/, map { [split /:/]->[0] } `psql -Alt -F:`; |
|
0
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
sub _create_language_extensions { |
539
|
0
|
|
|
0
|
|
|
my $self = shift; |
540
|
0
|
|
|
|
|
|
my $list = $self->database_extensions('languages'); |
541
|
0
|
0
|
|
|
|
|
return unless $list; |
542
|
0
|
|
|
|
|
|
foreach my $lang (@$list) { |
543
|
0
|
0
|
|
|
|
|
$self->_do_psql("create extension if not exists $lang") || die "error creating language: $lang"; |
544
|
|
|
|
|
|
|
} |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
sub _create_database { |
548
|
0
|
|
|
0
|
|
|
my $self = shift; |
549
|
|
|
|
|
|
|
|
550
|
0
|
|
|
|
|
|
my $database_name = $self->database_options('name'); |
551
|
0
|
|
|
|
|
|
my $database_schema = $self->database_options('schema'); |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
# create the database if necessary |
554
|
0
|
0
|
|
|
|
|
unless ($self->_database_exists($database_name)) { |
555
|
0
|
|
|
|
|
|
local $ENV{PERL5LIB}; |
556
|
0
|
0
|
|
|
|
|
do_system($Bin{Createdb}, $database_name) or die "could not createdb"; |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
# Create a fresh schema in the database. |
560
|
0
|
0
|
|
|
|
|
$self->_do_psql("create schema $database_schema") unless $database_schema eq 'public'; |
561
|
|
|
|
|
|
|
|
562
|
0
|
|
|
|
|
|
$self->_do_psql("alter database $database_name set client_min_messages to ERROR"); |
563
|
|
|
|
|
|
|
|
564
|
0
|
|
|
|
|
|
$self->_do_psql("alter database $database_name set search_path to $database_schema;"); |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
# stolen from http://wiki.postgresql.org/wiki/CREATE_OR_REPLACE_LANGUAGE |
567
|
0
|
|
|
|
|
|
$self->_do_psql(<<'SAFE_MAKE_PLPGSQL'); |
568
|
|
|
|
|
|
|
CREATE OR REPLACE FUNCTION make_plpgsql() |
569
|
|
|
|
|
|
|
RETURNS VOID |
570
|
|
|
|
|
|
|
LANGUAGE SQL |
571
|
|
|
|
|
|
|
AS $$ |
572
|
|
|
|
|
|
|
CREATE LANGUAGE plpgsql; |
573
|
|
|
|
|
|
|
$$; |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
SELECT |
576
|
|
|
|
|
|
|
CASE |
577
|
|
|
|
|
|
|
WHEN EXISTS( |
578
|
|
|
|
|
|
|
SELECT 1 |
579
|
|
|
|
|
|
|
FROM pg_catalog.pg_language |
580
|
|
|
|
|
|
|
WHERE lanname='plpgsql' |
581
|
|
|
|
|
|
|
) |
582
|
|
|
|
|
|
|
THEN NULL |
583
|
|
|
|
|
|
|
ELSE make_plpgsql() END; |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
DROP FUNCTION make_plpgsql(); |
586
|
|
|
|
|
|
|
SAFE_MAKE_PLPGSQL |
587
|
|
|
|
|
|
|
|
588
|
0
|
0
|
|
|
|
|
if (my $postgis = $self->database_extensions('postgis')) { |
589
|
0
|
|
|
|
|
|
info "applying postgis extension"; |
590
|
0
|
0
|
|
|
|
|
my $postgis_schema = $postgis->{schema} or die "No schema given for postgis"; |
591
|
0
|
0
|
|
|
|
|
$self->_do_psql("create schema $postgis_schema") unless $postgis_schema eq 'public'; |
592
|
0
|
|
|
|
|
|
$self->_do_psql("alter database $database_name set search_path to $postgis_schema;"); |
593
|
|
|
|
|
|
|
# We need to run "createlang plpgsql" first. |
594
|
0
|
0
|
|
|
|
|
$self->_do_psql_file($self->postgis_base. "/postgis.sql") or die "could not do postgis.sql"; |
595
|
0
|
0
|
|
|
|
|
$self->_do_psql_file($self->postgis_base. "/spatial_ref_sys.sql") or die "could not do spatial_ref_sys.sql"; |
596
|
0
|
|
|
|
|
|
$self->_do_psql("alter database $database_name set search_path to $database_schema, $postgis_schema"); |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
|
599
|
0
|
0
|
|
|
|
|
if (my $sql = $self->database_options('post_initdb')) { |
600
|
0
|
|
|
|
|
|
info "applying post_initdb (nb: this option has been renamed to 'after_create')"; |
601
|
0
|
|
|
|
|
|
$self->_do_psql($sql); |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
|
604
|
0
|
0
|
|
|
|
|
if (my $sql = $self->database_options('after_create')) { |
605
|
0
|
|
|
|
|
|
info "applying after_create"; |
606
|
0
|
|
|
|
|
|
$self->_do_psql($sql); |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
|
609
|
0
|
|
|
|
|
|
1; |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
sub _remove_patches_applied_table { |
613
|
0
|
|
|
0
|
|
|
my $self = shift; |
614
|
0
|
|
|
|
|
|
my $database_schema = $self->database_options('schema'); |
615
|
0
|
|
|
|
|
|
$self->_do_psql("drop table if exists $database_schema.patches_applied;"); |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
sub _generate_docs { |
619
|
0
|
|
|
0
|
|
|
my $self = shift; |
620
|
0
|
|
|
|
|
|
my %args = @_; |
621
|
0
|
0
|
|
|
|
|
my $dir = $args{dir} or die "missing dir"; |
622
|
0
|
|
|
|
|
|
my $tmpdir = tempdir; |
623
|
0
|
|
|
|
|
|
my $tc = "Module::Build::Database::PostgreSQL::Templates"; |
624
|
0
|
|
|
|
|
|
my $database_name = $self->database_options('name'); |
625
|
0
|
|
|
|
|
|
my $database_schema = $self->database_options('schema'); |
626
|
|
|
|
|
|
|
|
627
|
0
|
|
|
|
|
|
$self->_start_new_db(); |
628
|
0
|
|
|
|
|
|
$self->_apply_base_sql(); |
629
|
|
|
|
|
|
|
|
630
|
0
|
|
|
|
|
|
chdir $tmpdir; |
631
|
0
|
|
|
|
|
|
for my $filename ($tc->filenames) { |
632
|
0
|
0
|
|
|
|
|
open my $fp, ">$filename" or die $!; |
633
|
0
|
|
|
|
|
|
print ${fp} $tc->file_contents($filename); |
634
|
0
|
|
|
|
|
|
close $fp; |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
# http://perlmonks.org/?node_id=821413 |
638
|
0
|
|
|
|
|
|
do_system( $Bin{Pgdoc}, "-d", $database_name, "-s", $database_schema, "-l .", "-t pod" ); |
639
|
0
|
|
|
|
|
|
do_system( $Bin{Pgdoc}, "-d", $database_name, "-s", $database_schema, "-l .", "-t html" ); |
640
|
0
|
|
|
|
|
|
do_system( $Bin{Pgdoc}, "-d", $database_name, "-s", $database_schema, "-l .", "-t dot" ); |
641
|
|
|
|
|
|
|
|
642
|
0
|
|
|
|
|
|
for my $type (qw(pod html)) { |
643
|
0
|
0
|
|
|
|
|
my $fp = IO::File->new("<$database_name.$type") or die $!; |
644
|
0
|
0
|
|
|
|
|
mkdir $type or die $!; |
645
|
0
|
|
|
|
|
|
my $outfp; |
646
|
0
|
|
|
|
|
|
while (<$fp>) { |
647
|
0
|
0
|
|
|
|
|
s/^_CUT: (.*)$// and do { $outfp = IO::File->new(">$type/$1") or die $!; }; |
|
0
|
0
|
|
|
|
|
|
648
|
0
|
0
|
|
|
|
|
s/^_DB: (.*)$// and do { $_ = $self->_do_psql_capture($1); s/^/ /gm; }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
649
|
0
|
0
|
|
|
|
|
print ${outfp} $_ if defined($outfp); |
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
} |
652
|
0
|
|
|
|
|
|
dirmove "$tmpdir/pod", "$dir/pod"; |
653
|
0
|
|
|
|
|
|
info "Generated $dir/pod"; |
654
|
0
|
|
|
|
|
|
dirmove "$tmpdir/html", "$dir/html"; |
655
|
0
|
|
|
|
|
|
info "Generated $dir/html"; |
656
|
0
|
|
|
|
|
|
fcopy "$tmpdir/$database_name.dot", "$dir"; |
657
|
0
|
|
|
|
|
|
info "Generated $dir/$database_name.dot"; |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
|
660
|
0
|
|
|
0
|
0
|
|
sub ACTION_dbtest { shift->SUPER::ACTION_dbtest(@_); } |
661
|
0
|
|
|
0
|
0
|
|
sub ACTION_dbclean { shift->SUPER::ACTION_dbclean(@_); } |
662
|
0
|
|
|
0
|
0
|
|
sub ACTION_dbdist { shift->SUPER::ACTION_dbdist(@_); } |
663
|
0
|
|
|
0
|
0
|
|
sub ACTION_dbdocs { shift->SUPER::ACTION_dbdocs(@_); } |
664
|
0
|
|
|
0
|
0
|
|
sub ACTION_dbinstall { shift->SUPER::ACTION_dbinstall(@_); } |
665
|
0
|
|
|
0
|
0
|
|
sub ACTION_dbfakeinstall { shift->SUPER::ACTION_dbfakeinstall(@_); } |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
sub _dbhost { |
668
|
0
|
|
0
|
0
|
|
|
return $ENV{PGHOST} || 'localhost'; |
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
1; |
672
|
|
|
|
|
|
|
|