line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MySQL::Diff::Database; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
MySQL::Diff::Database - Database Definition Class |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use MySQL::Diff::Database; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
my $db = MySQL::Diff::Database->new(%options); |
12
|
|
|
|
|
|
|
my $source = $db->source_type(); |
13
|
|
|
|
|
|
|
my $summary = $db->summary(); |
14
|
|
|
|
|
|
|
my $name = $db->name(); |
15
|
|
|
|
|
|
|
my @tables = $db->tables(); |
16
|
|
|
|
|
|
|
my $table_def = $db->table_by_name($table); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
my @dbs = MySQL::Diff::Database::available_dbs(); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 DESCRIPTION |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
Parses a database definition into component parts. |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=cut |
25
|
|
|
|
|
|
|
|
26
|
3
|
|
|
3
|
|
707
|
use warnings; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
375
|
|
27
|
3
|
|
|
3
|
|
10
|
use strict; |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
57
|
|
28
|
3
|
|
|
3
|
|
1234
|
use String::ShellQuote qw(shell_quote); |
|
3
|
|
|
|
|
1969
|
|
|
3
|
|
|
|
|
258
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
our $VERSION = '0.50'; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------ |
33
|
|
|
|
|
|
|
# Libraries |
34
|
|
|
|
|
|
|
|
35
|
3
|
|
|
3
|
|
14
|
use Carp qw(:DEFAULT); |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
396
|
|
36
|
3
|
|
|
3
|
|
1404
|
use File::Slurp; |
|
3
|
|
|
|
|
30828
|
|
|
3
|
|
|
|
|
199
|
|
37
|
3
|
|
|
3
|
|
1471
|
use IO::File; |
|
3
|
|
|
|
|
19660
|
|
|
3
|
|
|
|
|
323
|
|
38
|
|
|
|
|
|
|
|
39
|
3
|
|
|
3
|
|
1151
|
use MySQL::Diff::Utils qw(debug); |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
130
|
|
40
|
3
|
|
|
3
|
|
1007
|
use MySQL::Diff::Table; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
4248
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------ |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head1 METHODS |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=head2 Constructor |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=over 4 |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=item new( %options ) |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
Instantiate the objects, providing the command line options for database |
53
|
|
|
|
|
|
|
access and process requirements. |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=back |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=cut |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub new { |
60
|
0
|
|
|
0
|
1
|
|
my $class = shift; |
61
|
0
|
|
|
|
|
|
my %p = @_; |
62
|
0
|
|
|
|
|
|
my $self = {}; |
63
|
0
|
|
0
|
|
|
|
bless $self, ref $class || $class; |
64
|
|
|
|
|
|
|
|
65
|
0
|
|
|
|
|
|
debug(3,"\nconstructing new MySQL::Diff::Database"); |
66
|
|
|
|
|
|
|
|
67
|
0
|
|
|
|
|
|
my $auth_ref = _auth_args_string(%{$p{auth}}); |
|
0
|
|
|
|
|
|
|
68
|
0
|
|
|
|
|
|
my $string = shell_quote @$auth_ref; |
69
|
0
|
|
|
|
|
|
debug(3,"auth args: $string"); |
70
|
0
|
|
|
|
|
|
$self->{_source}{auth} = $string; |
71
|
0
|
0
|
|
|
|
|
$self->{_source}{dbh} = $p{dbh} if $p{dbh}; |
72
|
0
|
|
|
|
|
|
$self->{'single-transaction'} = $p{'single-transaction'}; |
73
|
0
|
|
|
|
|
|
$self->{'table-re'} = $p{'table-re'}; |
74
|
|
|
|
|
|
|
|
75
|
0
|
0
|
|
|
|
|
if ($p{file}) { |
|
|
0
|
|
|
|
|
|
76
|
0
|
|
|
|
|
|
$self->_canonicalise_file($p{file}); |
77
|
|
|
|
|
|
|
} elsif ($p{db}) { |
78
|
0
|
|
|
|
|
|
$self->_read_db($p{db}); |
79
|
|
|
|
|
|
|
} else { |
80
|
0
|
|
|
|
|
|
confess "MySQL::Diff::Database::new called without db or file params"; |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
0
|
|
|
|
|
|
$self->_parse_defs(); |
84
|
0
|
|
|
|
|
|
return $self; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=head2 Public Methods |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=over 4 |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=item * source_type() |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
Returns 'file' if the data source is a text file, and 'db' if connected |
94
|
|
|
|
|
|
|
directly to a database. |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=cut |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub source_type { |
99
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
100
|
0
|
0
|
|
|
|
|
return 'file' if $self->{_source}{file}; |
101
|
0
|
0
|
|
|
|
|
return 'db' if $self->{_source}{db}; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=item * summary() |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
Provides a summary of the database. |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=cut |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub summary { |
111
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
112
|
|
|
|
|
|
|
|
113
|
0
|
0
|
|
|
|
|
if ($self->{_source}{file}) { |
|
|
0
|
|
|
|
|
|
114
|
0
|
|
|
|
|
|
return "file: " . $self->{_source}{file}; |
115
|
|
|
|
|
|
|
} elsif ($self->{_source}{db}) { |
116
|
0
|
|
|
|
|
|
my $args = $self->{_source}{auth}; |
117
|
0
|
|
|
|
|
|
$args =~ tr/-//d; |
118
|
0
|
|
|
|
|
|
$args =~ s/\bpassword=\S+//; |
119
|
0
|
|
|
|
|
|
$args =~ s/^\s*(.*?)\s*$/$1/; |
120
|
0
|
|
|
|
|
|
my $summary = " db: " . $self->{_source}{db}; |
121
|
0
|
0
|
|
|
|
|
$summary .= " ($args)" if $args; |
122
|
0
|
|
|
|
|
|
return $summary; |
123
|
|
|
|
|
|
|
} else { |
124
|
0
|
|
|
|
|
|
return 'unknown'; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=item * name() |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Returns the name of the database. |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=cut |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub name { |
135
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
136
|
0
|
|
0
|
|
|
|
return $self->{_source}{file} || $self->{_source}{db}; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=item * tables() |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
Returns a list of tables for the current database. |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=cut |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub tables { |
146
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
147
|
0
|
|
|
|
|
|
return @{$self->{_tables}}; |
|
0
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=item * table_by_name( $name ) |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
Returns the table definition (see L) for the given table. |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=cut |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
sub table_by_name { |
157
|
0
|
|
|
0
|
1
|
|
my ($self,$name) = @_; |
158
|
0
|
|
|
|
|
|
return $self->{_by_name}{$name}; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=back |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=head1 FUNCTIONS |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=head2 Public Functions |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=over 4 |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=item * available_dbs() |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
Returns a list of the available databases. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Note that is used as a function call, not a method call. |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=cut |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub available_dbs { |
178
|
0
|
|
|
0
|
1
|
|
my %auth = @_; |
179
|
0
|
|
|
|
|
|
my $args_ref = _auth_args_string(%auth); |
180
|
0
|
|
|
|
|
|
unshift @$args_ref, q{mysqlshow}; |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# evil but we don't use DBI because I don't want to implement -p properly |
183
|
|
|
|
|
|
|
# not that this works with -p anyway ... |
184
|
0
|
|
|
|
|
|
my $command = shell_quote @$args_ref; |
185
|
0
|
0
|
|
|
|
|
my $fh = IO::File->new("$command |") or die "Couldn't execute '$command': $!\n"; |
186
|
0
|
|
|
|
|
|
my $dbs_ref = _parse_mysqlshow_from_fh_into_arrayref($fh); |
187
|
0
|
0
|
|
|
|
|
$fh->close() or die "$command failed: $!"; |
188
|
|
|
|
|
|
|
|
189
|
0
|
|
|
|
|
|
return map { $_ => 1 } @{$dbs_ref}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=back |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=cut |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------ |
197
|
|
|
|
|
|
|
# Private Methods |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub auth_args { |
200
|
0
|
|
|
0
|
0
|
|
return _auth_args_string(); |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub _canonicalise_file { |
204
|
0
|
|
|
0
|
|
|
my ($self, $file) = @_; |
205
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
|
$self->{_source}{file} = $file; |
207
|
0
|
|
|
|
|
|
debug(2,"fetching table defs from file $file"); |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
# FIXME: option to avoid create-and-dump bit |
210
|
|
|
|
|
|
|
# create a temporary database using defs from file ... |
211
|
|
|
|
|
|
|
# hopefully the temp db is unique! |
212
|
0
|
|
|
|
|
|
my $temp_db = sprintf "test_mysqldiff-temp-%d_%d_%d", time(), $$, rand(); |
213
|
0
|
|
|
|
|
|
debug(3,"creating temporary database $temp_db"); |
214
|
|
|
|
|
|
|
|
215
|
0
|
|
|
|
|
|
my $defs = read_file($file); |
216
|
0
|
0
|
|
|
|
|
die "$file contains dangerous command '$1'; aborting.\n" |
217
|
|
|
|
|
|
|
if $defs =~ /;\s*(use|((drop|create)\s+database))\b/i; |
218
|
|
|
|
|
|
|
|
219
|
0
|
|
|
|
|
|
my $args = $self->{_source}{auth}; |
220
|
0
|
0
|
|
|
|
|
my $fh = IO::File->new("| mysql $args") or die "Couldn't execute 'mysql$args': $!\n"; |
221
|
0
|
|
|
|
|
|
print $fh "\nCREATE DATABASE \`$temp_db\`;\nUSE \`$temp_db\`;\n"; |
222
|
0
|
|
|
|
|
|
print $fh $defs; |
223
|
0
|
|
|
|
|
|
$fh->close; |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
# ... and then retrieve defs from mysqldump. Hence we've used |
226
|
|
|
|
|
|
|
# MySQL to massage the defs file into canonical form. |
227
|
0
|
|
|
|
|
|
$self->_get_defs($temp_db); |
228
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
|
debug(3,"dropping temporary database $temp_db"); |
230
|
0
|
0
|
|
|
|
|
$fh = IO::File->new("| mysql $args") or die "Couldn't execute 'mysql$args': $!\n"; |
231
|
0
|
|
|
|
|
|
print $fh "DROP DATABASE \`$temp_db\`;\n"; |
232
|
0
|
|
|
|
|
|
$fh->close; |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub _read_db { |
236
|
0
|
|
|
0
|
|
|
my ($self, $db) = @_; |
237
|
0
|
|
|
|
|
|
$self->{_source}{db} = $db; |
238
|
0
|
|
|
|
|
|
debug(3, "fetching table defs from db $db"); |
239
|
0
|
|
|
|
|
|
$self->_get_defs($db); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub _get_tables_to_dump { |
243
|
0
|
|
|
0
|
|
|
my ( $self, $db ) = @_; |
244
|
|
|
|
|
|
|
|
245
|
0
|
|
|
|
|
|
my $tables_ref = $self->_get_tables_in_db($db); |
246
|
|
|
|
|
|
|
|
247
|
0
|
|
|
|
|
|
my $compiled_table_re = qr/$self->{'table-re'}/; |
248
|
|
|
|
|
|
|
|
249
|
0
|
|
|
|
|
|
my @matching_tables = grep { $_ =~ $compiled_table_re } @{$tables_ref}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
|
251
|
0
|
|
|
|
|
|
return join( ' ', @matching_tables ); |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub _get_tables_in_db { |
255
|
0
|
|
|
0
|
|
|
my ( $self, $db ) = @_; |
256
|
|
|
|
|
|
|
|
257
|
0
|
|
|
|
|
|
my $args = $self->{_source}{auth}; |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
# evil but we don't use DBI because I don't want to implement -p properly |
260
|
|
|
|
|
|
|
# not that this works with -p anyway ... |
261
|
0
|
0
|
|
|
|
|
my $fh = IO::File->new("mysqlshow $args $db|") |
262
|
|
|
|
|
|
|
or die "Couldn't execute 'mysqlshow $args $db': $!\n"; |
263
|
0
|
|
|
|
|
|
my $tables_ref = _parse_mysqlshow_from_fh_into_arrayref($fh); |
264
|
0
|
0
|
|
|
|
|
$fh->close() or die "mysqlshow $args $db failed: $!"; |
265
|
|
|
|
|
|
|
|
266
|
0
|
|
|
|
|
|
return $tables_ref; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# Note that is used as a function call, not a method call. |
270
|
|
|
|
|
|
|
sub _parse_mysqlshow_from_fh_into_arrayref { |
271
|
0
|
|
|
0
|
|
|
my ($fh) = @_; |
272
|
|
|
|
|
|
|
|
273
|
0
|
|
|
|
|
|
my @items; |
274
|
0
|
|
|
|
|
|
while (<$fh>) { |
275
|
0
|
0
|
|
|
|
|
next unless /^\| ([\w-]+)/; |
276
|
0
|
|
|
|
|
|
push @items, $1; |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
|
return \@items; |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
sub _get_defs { |
283
|
0
|
|
|
0
|
|
|
my ( $self, $db ) = @_; |
284
|
|
|
|
|
|
|
|
285
|
0
|
|
|
|
|
|
my $args = $self->{_source}{auth}; |
286
|
0
|
0
|
|
|
|
|
my $single_transaction = $self->{'single-transaction'} ? "--single-transaction" : ""; |
287
|
0
|
|
|
|
|
|
my $tables = ''; #dump all tables by default |
288
|
0
|
0
|
|
|
|
|
if ( my $table_re = $self->{'table-re'} ) { |
289
|
0
|
|
|
|
|
|
$tables = $self->_get_tables_to_dump($db); |
290
|
0
|
0
|
|
|
|
|
if ( !length $tables ) { # No tables to dump |
291
|
0
|
|
|
|
|
|
$self->{_defs} = []; |
292
|
0
|
|
|
|
|
|
return; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
|
296
|
0
|
0
|
|
|
|
|
my $fh = IO::File->new("mysqldump -d $single_transaction $args $db $tables 2>&1 |") |
297
|
|
|
|
|
|
|
or die "Couldn't read ${db}'s table defs via mysqldump: $!\n"; |
298
|
|
|
|
|
|
|
|
299
|
0
|
|
|
|
|
|
debug( 3, "running mysqldump -d $single_transaction $args $db $tables" ); |
300
|
0
|
|
|
|
|
|
my $defs = $self->{_defs} = [<$fh>]; |
301
|
0
|
|
|
|
|
|
$fh->close; |
302
|
0
|
|
|
|
|
|
my $exit_status = $? >> 8; |
303
|
|
|
|
|
|
|
|
304
|
0
|
0
|
|
|
|
|
if ( grep /mysqldump: Got error: .*: Unknown database/, @$defs ) { |
|
|
0
|
|
|
|
|
|
305
|
0
|
|
|
|
|
|
die <
|
306
|
|
|
|
|
|
|
Failed to create temporary database $db |
307
|
|
|
|
|
|
|
during canonicalization. Make sure that your mysql.db table has a row |
308
|
|
|
|
|
|
|
authorizing full access to all databases matching 'test\\_%', and that |
309
|
|
|
|
|
|
|
the database doesn't already exist. |
310
|
|
|
|
|
|
|
EOF |
311
|
|
|
|
|
|
|
} elsif ($exit_status) { |
312
|
|
|
|
|
|
|
# If mysqldump exited with a non-zero status, then |
313
|
|
|
|
|
|
|
# we can not reliably make a diff, so better to die and bubble that error up. |
314
|
0
|
|
|
|
|
|
die "mysqldump failed. Exit status: $exit_status:\n" . join( "\n", @{$defs} ); |
|
0
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
} |
316
|
0
|
|
|
|
|
|
return; |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
sub _parse_defs { |
320
|
0
|
|
|
0
|
|
|
my $self = shift; |
321
|
|
|
|
|
|
|
|
322
|
0
|
0
|
|
|
|
|
return if $self->{_tables}; |
323
|
|
|
|
|
|
|
|
324
|
0
|
|
|
|
|
|
debug(2, "parsing table defs"); |
325
|
0
|
|
|
|
|
|
my $defs = join '', grep ! /^\s*(\#|--|SET|\/\*)/, @{$self->{_defs}}; |
|
0
|
|
|
|
|
|
|
326
|
0
|
|
|
|
|
|
$defs =~ s/`//sg; |
327
|
0
|
|
|
|
|
|
my @tables = split /(?=^\s*(?:create|alter|drop)\s+table\s+)/im, $defs; |
328
|
0
|
|
|
|
|
|
$self->{_tables} = []; |
329
|
0
|
|
|
|
|
|
for my $table (@tables) { |
330
|
0
|
|
|
|
|
|
debug(4, " table def [$table]"); |
331
|
0
|
0
|
|
|
|
|
if($table =~ /create\s+table/i) { |
332
|
0
|
|
|
|
|
|
my $obj = MySQL::Diff::Table->new(source => $self->{_source}, def => $table); |
333
|
0
|
|
|
|
|
|
push @{$self->{_tables}}, $obj; |
|
0
|
|
|
|
|
|
|
334
|
0
|
|
|
|
|
|
$self->{_by_name}{$obj->name()} = $obj; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub _auth_args_string { |
340
|
0
|
|
|
0
|
|
|
my %auth = @_; |
341
|
0
|
|
|
|
|
|
my $args = []; |
342
|
0
|
|
|
|
|
|
for my $arg (qw/host port user password socket/) { |
343
|
0
|
0
|
|
|
|
|
push @$args, qq/--$arg=$auth{$arg}/ if $auth{$arg}; |
344
|
|
|
|
|
|
|
} |
345
|
0
|
|
|
|
|
|
return $args; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
1; |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
__END__ |