line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test::Environment::Plugin::PostgreSQL; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Test::Environment::Plugin::PostgreSQL - PostreSQL psql function for testing |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use Test::Environment qw{ |
10
|
|
|
|
|
|
|
PostgreSQL |
11
|
|
|
|
|
|
|
}; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# set database credentials |
14
|
|
|
|
|
|
|
psql( |
15
|
|
|
|
|
|
|
'database' => $config->{'db'}->{'database'}, |
16
|
|
|
|
|
|
|
'hostname' => $config->{'db'}->{'hostname'}, |
17
|
|
|
|
|
|
|
'username' => $config->{'db'}->{'username'}, |
18
|
|
|
|
|
|
|
'password' => $config->{'db'}->{'password'}, |
19
|
|
|
|
|
|
|
# or skip hostname and database and set them via |
20
|
|
|
|
|
|
|
#'dbi_dsn' => 'dbi:Pg:dbname=dsn_test;host=localhost', |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# execute sql query |
25
|
|
|
|
|
|
|
my @output = psql( |
26
|
|
|
|
|
|
|
'switches' => '--expanded', |
27
|
|
|
|
|
|
|
'command' => 'SELECT * FROM Table', |
28
|
|
|
|
|
|
|
# ..., see psql function description for more |
29
|
|
|
|
|
|
|
) |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=head1 DESCRIPTION |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
This plugin will export 'psql' function that can be used to execute PostreSQL psql command |
35
|
|
|
|
|
|
|
with lot of options for testing. |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
Module will prepare %ENV for postgres: |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
'username' => 'PGUSER', |
40
|
|
|
|
|
|
|
'password' => 'PGPASSWORD', |
41
|
|
|
|
|
|
|
'database' => 'PGDATABASE', |
42
|
|
|
|
|
|
|
'hostname' => 'PGHOST', |
43
|
|
|
|
|
|
|
'port' => 'PGPORT', |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
Any postgres connection settings not listed or undef will be deleted from the %ENV hash. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=cut |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
|
50
|
1
|
|
|
1
|
|
9
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
49
|
|
51
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
53
|
|
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
our $VERSION = 0.03; |
54
|
|
|
|
|
|
|
|
55
|
1
|
|
|
1
|
|
6
|
use base qw{ Exporter }; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
145
|
|
56
|
|
|
|
|
|
|
our @EXPORT = qw{ |
57
|
|
|
|
|
|
|
psql |
58
|
|
|
|
|
|
|
}; |
59
|
|
|
|
|
|
|
our $debug = 0; |
60
|
|
|
|
|
|
|
|
61
|
1
|
|
|
1
|
|
6
|
use Carp::Clan; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
7
|
|
62
|
1
|
|
|
1
|
|
1145
|
use String::ShellQuote; |
|
1
|
|
|
|
|
968
|
|
|
1
|
|
|
|
|
76
|
|
63
|
1
|
|
|
1
|
|
3822
|
use List::MoreUtils 'any'; |
|
1
|
|
|
|
|
2698
|
|
|
1
|
|
|
|
|
107
|
|
64
|
1
|
|
|
1
|
|
339173
|
use DBI; |
|
1
|
|
|
|
|
73570
|
|
|
1
|
|
|
|
|
868
|
|
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=head1 FUNCTIONS |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head2 import |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
All functions are exported 2 levels up. That is to the use Test::Environment caller. |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=cut |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub import { |
75
|
1
|
|
|
1
|
|
2
|
my $package = shift; |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# export symbols two levels up - to the Test::Environment caller |
78
|
1
|
|
|
|
|
496
|
__PACKAGE__->export_to_level(2, $package, @EXPORT); |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=head2 psql() |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
psql command executed easily. Here is the list of options that can be used. |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
Option related to the connection to the database. |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
username |
89
|
|
|
|
|
|
|
password |
90
|
|
|
|
|
|
|
database |
91
|
|
|
|
|
|
|
hostname |
92
|
|
|
|
|
|
|
port |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
By setting this PostreSQL %ENV variables will be set. So for psql command to the |
95
|
|
|
|
|
|
|
same databse you need to set them only once. |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
The rest of the option related to the psql command. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
command - scalar or array ref of sql commands |
100
|
|
|
|
|
|
|
switches - scalar or array of additional psql switches |
101
|
|
|
|
|
|
|
output_filename - the output will be written to this file (-o) |
102
|
|
|
|
|
|
|
execution_path - before executing psql change to that folder |
103
|
|
|
|
|
|
|
stderr_redirect - will redirect stderr to stdout so that also error appears in the return value |
104
|
|
|
|
|
|
|
debug - turn on debug mode, it can be also done globaly by setting "$ENV{'IN_DEBUG_MODE'} = 1" |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=cut |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub psql { |
109
|
5
|
|
|
5
|
1
|
30191
|
my %arg = @_; |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# deparse dbi_dsn if passed |
112
|
5
|
100
|
|
|
|
34
|
if (defined $arg{'dbi_dsn'}) { |
113
|
2
|
|
|
|
|
36
|
my($scheme, $driver, $attr_string, $attr_hash, $driver_dsn) |
114
|
|
|
|
|
|
|
= DBI->parse_dsn($arg{'dbi_dsn'}); |
115
|
|
|
|
|
|
|
|
116
|
2
|
50
|
33
|
|
|
87
|
croak 'not a Pg dbi dsn "'.$arg{'dbi_dsn'}.'"' |
117
|
|
|
|
|
|
|
if (($scheme ne 'dbi') or ($driver ne 'Pg')); |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# contruct hash out of "dbname=dsn_test;host=localhost;port=123" |
120
|
2
|
|
|
|
|
13
|
my %dsn_options = map { split '=', $_ } split(';',$driver_dsn); |
|
5
|
|
|
|
|
23
|
|
121
|
|
|
|
|
|
|
|
122
|
2
|
50
|
|
|
|
150
|
$arg{'database'} = $dsn_options{'dbname'} |
123
|
|
|
|
|
|
|
if exists $dsn_options{'dbname'}; |
124
|
2
|
50
|
|
|
|
17
|
$arg{'hostname'} = $dsn_options{'host'} |
125
|
|
|
|
|
|
|
if exists $dsn_options{'host'}; |
126
|
2
|
100
|
|
|
|
13
|
$arg{'port'} = $dsn_options{'port'} |
127
|
|
|
|
|
|
|
if exists $dsn_options{'port'}; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
5
|
|
|
|
|
37
|
my %pg_settings_names = ( |
131
|
|
|
|
|
|
|
'username' => 'PGUSER', |
132
|
|
|
|
|
|
|
'password' => 'PGPASSWORD', |
133
|
|
|
|
|
|
|
'database' => 'PGDATABASE', |
134
|
|
|
|
|
|
|
'hostname' => 'PGHOST', |
135
|
|
|
|
|
|
|
'port' => 'PGPORT', |
136
|
|
|
|
|
|
|
); |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# change %ENV only if at least one pg connection setting set |
139
|
5
|
100
|
|
8
|
|
96
|
if (any { $pg_settings_names{$_} } keys %arg) { |
|
8
|
|
|
|
|
34
|
|
140
|
|
|
|
|
|
|
# set/delete postgres ENV variables |
141
|
4
|
|
|
|
|
17
|
foreach my $arg_name (keys %pg_settings_names) { |
142
|
20
|
|
|
|
|
36
|
my $env_name = $pg_settings_names{$arg_name}; |
143
|
20
|
100
|
|
|
|
136
|
( defined $arg{$arg_name} |
144
|
|
|
|
|
|
|
? $ENV{$env_name} = $arg{$arg_name} |
145
|
|
|
|
|
|
|
: delete $ENV{$env_name} |
146
|
|
|
|
|
|
|
); |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# function paramaters |
151
|
5
|
|
|
|
|
27
|
my $command = $arg{'command'}; |
152
|
5
|
|
|
|
|
12
|
my $output_filename = $arg{'output_filename'}; |
153
|
5
|
|
|
|
|
10
|
my $execution_path = $arg{'execution_path'}; |
154
|
5
|
|
|
|
|
10
|
my $stderr_redirect = $arg{'stderr_redirect'}; |
155
|
|
|
|
|
|
|
|
156
|
5
|
50
|
|
|
|
23
|
my @switches = (ref $arg{'switches'} eq 'ARRAY' ? @{$arg{'switches'}} : $arg{'switches'} ) |
|
0
|
100
|
|
|
|
0
|
|
157
|
|
|
|
|
|
|
if exists $arg{'switches'}; |
158
|
|
|
|
|
|
|
|
159
|
5
|
50
|
33
|
|
|
39
|
local $debug = 1 if ($arg{'debug'} or $ENV{'IN_DEBUG_MODE'}); |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# if there is no command return nothink to do more |
162
|
5
|
100
|
|
|
|
31
|
return if not defined $command; |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# if more commands then join them together |
165
|
1
|
50
|
|
|
|
6
|
if (ref $command eq 'ARRAY') { |
166
|
0
|
|
|
|
|
0
|
$command = join '; ', @{$command}; |
|
0
|
|
|
|
|
0
|
|
167
|
|
|
|
|
|
|
} |
168
|
1
|
50
|
|
|
|
8
|
$command .= ';' if ($command !~ m{;\s*$}xms); |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
|
171
|
1
|
50
|
|
|
|
9
|
if (defined $output_filename) { |
172
|
1
|
|
|
|
|
5
|
push(@switches, '-o', '"'.$output_filename.'"') |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# redirect stderr to stdout |
176
|
1
|
50
|
|
|
|
5
|
open(STDERR, ">&STDOUT") if (defined $stderr_redirect); |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# chdir if needed |
179
|
1
|
50
|
|
|
|
5
|
if (defined $execution_path) { |
180
|
1
|
50
|
|
|
|
5
|
print STDERR '+ cd ', $execution_path, "\n" if $debug; |
181
|
1
|
|
|
|
|
1510
|
chdir($execution_path); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
1
|
|
|
|
|
25
|
my @ret = execute( |
185
|
|
|
|
|
|
|
'psql', |
186
|
|
|
|
|
|
|
@switches, |
187
|
|
|
|
|
|
|
'-c', |
188
|
|
|
|
|
|
|
$command, |
189
|
|
|
|
|
|
|
); |
190
|
|
|
|
|
|
|
|
191
|
1
|
50
|
|
|
|
103
|
return @ret if defined wantarray; |
192
|
0
|
|
|
|
|
|
return join('', @ret); |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=head2 execute |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
Executes command as system and return output. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
In debug mode prints command to stderr. |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=cut |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
sub execute { |
205
|
|
|
|
|
|
|
my $cmd = shell_quote @_; |
206
|
|
|
|
|
|
|
print STDERR '+ ', $cmd, "\n" if $debug; |
207
|
|
|
|
|
|
|
my @ret = `$cmd`; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
1; |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head1 SEE ALSO |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
Test::Environment L |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head1 AUTHOR |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
Jozef Kutej - Ejozef@kutej.netE |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=cut |