File Coverage

blib/lib/PGObject/Util/DBAdmin.pm
Criterion Covered Total %
statement 32 191 16.7
branch 0 68 0.0
condition 0 26 0.0
subroutine 11 36 30.5
pod 12 12 100.0
total 55 333 16.5


line stmt bran cond sub pod time code
1             package PGObject::Util::DBAdmin;
2              
3 7     7   935878 use 5.010; # Uses // defined-or operator
  7         26  
4 7     7   39 use strict;
  7         13  
  7         195  
5 7     7   47 use warnings FATAL => 'all';
  7         15  
  7         534  
6              
7 7     7   4035 use Capture::Tiny 'capture';
  7         184390  
  7         608  
8 7     7   88 use Carp;
  7         15  
  7         427  
9 7     7   11740 use DBI;
  7         155959  
  7         602  
10 7     7   64 use File::Temp;
  7         16  
  7         607  
11 7     7   5962 use Log::Any;
  7         69159  
  7         47  
12 7     7   3553 use Scope::Guard qw(guard);
  7         3509  
  7         479  
13              
14 7     7   3947 use Moo;
  7         58242  
  7         37  
15 7     7   16512 use namespace::clean;
  7         122880  
  7         50  
16              
17             =head1 NAME
18              
19             PGObject::Util::DBAdmin - PostgreSQL Database Management Facilities for
20             PGObject
21              
22             =head1 VERSION
23              
24             version 1.6.2
25              
26             =cut
27              
28             our $VERSION = '1.6.2';
29              
30              
31             =head1 SYNOPSIS
32              
33             This module provides an interface to the basic Postgres db manipulation
34             utilities.
35              
36             my $db = PGObject::Util::DBAdmin->new(
37             connect_data => {
38             user => 'postgres',
39             password => 'mypassword',
40             host => 'localhost',
41             port => '5432',
42             dbname => 'mydb'
43             }
44             );
45              
46             my @dbnames = $db->list_dbs(); # like psql -l
47              
48             $db->create(); # createdb
49             $db->run_file(file => 'sql/initial_schema.sql'); # psql -f
50              
51             my $filename = $db->backup(format => 'c'); # pg_dump -Fc
52              
53             my $db2 = PGObject::Util::DBAdmin->new($db->export, (dbname => 'otherdb'));
54              
55             my $db3 = PGObject::Util::DBAdmin->new(
56             connect_data => {
57             service => 'zephyr',
58             sslmode => 'require',
59             sslkey => "$HOME/.postgresql/postgresql.key",
60             sslcert => "$HOME/.postgresql/postgresql.crt",
61             sslpassword => 'your-sslpassword',
62             }
63             );
64              
65              
66             =head1 PROPERTIES
67              
68             =head2 connect_data
69              
70             Contains a hash with connection parameters; see L<the PostgreSQL
71             documentation|https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS>
72             for supported parameters.
73              
74             The usual parameters are:
75              
76             =over
77              
78             =item * user
79              
80             =item * password
81              
82             =item * dbname
83              
84             =item * host
85              
86             =item * port
87              
88             =back
89              
90             Please note that the key C<requiressl> is deprecated in favor of
91             C<sslmode> and isn't supported.
92              
93             =cut
94              
95             # Not supported
96             # PGSERVICEFILE: (because no connect string equiv)
97             # PGREQUIRESSL: deprecated
98             my %connkey_env = qw(
99             port PGPORT
100             host PGHOST
101             hostaddr PGHOSTADDR
102             dbname PGDATABASE
103             user PGUSER
104             password PGPASSWORD
105             passfile PGPASSFILE
106             channel_binding PGCHANNELBINDING
107             service PGSERVICE
108             options PGOPTIONS
109             sslmode PGSSLMODE
110             sslcompression PGSSLCOMPRESSION
111             sslcert PGSSLCERT
112             sslkey PGSSLKEY
113             sslrootcert PGSSLROOTCERT
114             sslcrl PGSSLCRL
115             requirepeer PGREQUIREPEER
116             ssl_min_protocol_version PGSSLMINPROTOCOLVERSION
117             ssl_max_protocol_version PGSSLMAXPROTOCOLVERSION
118             gssencmode PGGSSENCMODE
119             krbsrvname PGKRBSRVNAME
120             gsslib PGGSSLIB
121             connect_timeout PGCONNECT_TIMEOUT
122             client_encoding PGCLIENTENCODING
123             target_session_attrs PGTARGETSESSIONATTRS
124             );
125             my @connstr_keys = ((grep { not ($_ eq 'user' or $_ eq 'password') }
126             keys %connkey_env),
127             qw(application_name fallback_application_name
128             keepalives keepalives_idle keepalives_interval
129             keepalives_count tcp_user_timeout replication sslpassword),
130             );
131              
132             sub _connect_data_env {
133 0     0     my ($connect_data) = @_;
134 0           my @keys = grep { exists $connkey_env{$_}
135 0 0         and defined $connect_data->{$_} } keys %$connect_data;
136 0           return map { $connkey_env{$_} => $connect_data->{$_} } @keys;
  0            
137             }
138              
139             sub _connect_data_str {
140 0     0     my ($connect_data) = @_;
141 0           my @keys = grep { defined $connect_data->{$_} } @connstr_keys;
  0            
142             return join(';', map {
143 0           my $val = $connect_data->{$_};
  0            
144 0           $val =~ s/\\/\\\\/g;
145 0           $val =~ s/'/\\'/g;
146 0           "$_='$val'"; } @keys );
147             }
148              
149             has connect_data => (is => 'ro');
150              
151             =head2 username (deprecated)
152              
153             The username used to authenticate with the PostgreSQL server.
154              
155             =cut
156              
157             has username => (is => 'ro');
158              
159             =head2 password (deprecated)
160              
161             The password used to authenticate with the PostgreSQL server.
162              
163             =cut
164              
165             has password => (is => 'ro');
166              
167             =head2 host (deprecated)
168              
169             In PostgreSQL, this can refer to the hostname or the absolute path to the
170             directory where the UNIX sockets are set up.
171              
172             =cut
173              
174             has host => (is => 'ro');
175              
176             =head2 port (deprecated)
177              
178             Default '5432'
179              
180             =cut
181              
182             has port => (is => 'ro');
183              
184             =head2 dbname (deprecated)
185              
186             The database name to create or connect to.
187              
188             =cut
189              
190             has dbname => (is => 'ro');
191              
192             =head2 stderr
193              
194             When applicable, the stderr output captured from any external commands (for
195             example createdb or pg_restore) run during the previous method call. See
196             notes in L</"CAPTURING">.
197              
198             =cut
199              
200             has stderr => (is => 'ro');
201              
202             =head2 stdout
203              
204             When applicable, the stdout output captured from any external commands (for
205             example createdb or pg_restore) run during the previous method call. See
206             notes in L</"CAPTURING">.
207              
208             =cut
209              
210             has stdout => (is => 'ro');
211              
212             =head2 logger
213              
214             Provides a reference to the logger associated with the current instance. The
215             logger uses C<ref $self> as its category, eliminating the need to create
216             new loggers when deriving from this class.
217              
218             If you want to override the logger-instantiation behaviour, please implement
219             the C<_build_logger> builder method in your derived class.
220              
221             =cut
222              
223             has logger => (is => 'ro', lazy => 1, builder => '_build_logger');
224              
225             sub _build_logger {
226 0     0     return Log::Any->get_logger(category => ref $_[0]);
227             }
228              
229              
230             our %helpers =
231             (
232             create => [ qw/createdb/ ],
233             run_file => [ qw/psql/ ],
234             backup => [ qw/pg_dump/ ],
235             backup_globals => [ qw/pg_dumpall/ ],
236             restore => [ qw/pg_restore psql/ ],
237             drop => [ qw/dropdb/ ],
238             is_ready => [ qw/pg_isready/ ],
239             );
240              
241             =head1 GLOBAL VARIABLES
242              
243              
244             =head2 %helper_paths
245              
246             This hash variable contains as its keys the names of the PostgreSQL helper
247             executables C<psql>, C<dropdb>, C<pg_dump>, etc. The values contain the
248             paths at which the executables to be run are located. The default values
249             are the names of the executables only, allowing them to be looked up in
250             C<$PATH>.
251              
252             Modification of the values in this variable are the strict realm of
253             I<applications>. Libraries using this library should defer potential
254             required modifications to the applications based upon them.
255              
256             =cut
257              
258             our %helper_paths =
259             (
260             psql => 'psql',
261             dropdb => 'dropdb',
262             createdb => 'createdb',
263             pg_dump => 'pg_dump',
264             pg_dumpall => 'pg_dumpall',
265             pg_restore => 'pg_restore',
266             pg_isready => 'pg_isready',
267             );
268              
269             sub _run_with_env {
270 0     0     my %args = @_;
271 0           my $env = $args{env};
272              
273             local %ENV = (
274             # Note that we're intentionally *not* passing
275             # PERL5LIB & PERL5OPT into the environment here!
276             # doing so prevents the system settings to be used, which
277             # we *do* want. If we don't, hopefully, that's coded into
278             # the executables themselves.
279             # Before using this whitelisting, coverage tests in LedgerSMB
280             # would break on the bleeding through this caused.
281             HOME => $ENV{HOME},
282             PATH => $ENV{PATH},
283 0   0       %{$env // {}},
  0            
284             );
285              
286 0           return system @{$args{command}};
  0            
287             }
288              
289             sub _run_command {
290 0     0     my ($self, %args) = @_;
291 0           my $exit_code;
292             my %env = (
293             # lowest priority: existing environment variables
294 0 0         (map { $ENV{$_} ? ($_ => $ENV{$_}) : () }
295             qw(PGUSER PGPASSWORD PGHOST PGPORT PGDATABASE PGSERVICE)),
296             # overruled by middle priority: object connection parameters
297             _connect_data_env($self->connect_data),
298             # overruled by highest priority: specified environment
299 0 0         ($args{env} ? %{$args{env}} : ()),
  0            
300             );
301             $self->logger->debugf(
302             sub {
303             return 'Running with environment: '
304 0     0     . join(' ', map { qq|$_="$env{$_}"| } sort keys %env );
  0            
305 0           });
306              
307             # Any files created should be accessible only by the current user
308 0           my $original_umask = umask 0077;
309             {
310 0     0     my $guard = guard { umask $original_umask; };
  0            
  0            
311              
312             ($self->{stdout}, $self->{stderr}, $exit_code) = capture {
313 0     0     _run_with_env(%args, env => \%env);
314 0           };
315 0 0 0       if(defined ($args{errlog} // $args{stdout_log})) {
316 0           $self->_write_log_files(%args);
317             }
318             }
319              
320 0 0         if ($exit_code != 0) {
321 0           for my $filename (@{$args{unlink}}) {
  0            
322 0 0         unlink $filename or carp "error unlinking '$filename': $!";
323             }
324 0           my $command = join( ' ', map { "'$_'" } @{$args{command}} );
  0            
  0            
325 0           my $err;
326 0 0         if ($? == -1) {
    0          
327 0           $err = "$!";
328             }
329             elsif ($? & 127) {
330 0           $err = sprintf('died with signal %d', ($? & 127));
331             }
332             else {
333 0           $err = sprintf('exited with code %d', ($? >> 8));
334             }
335 0           croak "$args{error}; (command: $command): $err";
336             }
337 0           return 1;
338             }
339              
340              
341             sub _generate_output_filename {
342 0     0     my ($self, %args) = @_;
343              
344             # If caller has supplied a file path, use that
345             # rather than generating our own temp file.
346 0 0         defined $args{file} and return $args{file};
347              
348 0           my %file_options = (UNLINK => 0);
349              
350 0 0         if(defined $args{tempdir}) {
351             -d $args{tempdir}
352 0 0         or croak "directory $args{tempdir} does not exist or is not a directory";
353 0           $file_options{DIR} = $args{tempdir};
354             }
355              
356             # File::Temp creates files with permissions 0600
357 0 0         my $fh = File::Temp->new(%file_options)
358             or croak "could not create temp file: $@, $!";
359              
360 0           return $fh->filename;
361             }
362              
363              
364             sub _write_log_files {
365 0     0     my ($self, %args) = @_;
366              
367             defined $args{stdout_log} and $self->_append_to_file(
368             $args{stdout_log},
369             $self->{stdout},
370 0 0         );
371              
372             defined $args{errlog} and $self->_append_to_file(
373             $args{errlog},
374             $self->{stderr},
375 0 0         );
376              
377 0           return;
378             }
379              
380              
381             sub _append_to_file {
382 0     0     my ($self, $filename, $data) = @_;
383              
384 0 0         open(my $fh, '>>', $filename)
385             or croak "couldn't open file $filename for appending $!";
386              
387 0 0 0       print $fh ($data // '')
388             or croak "failed writing to file $!";
389              
390 0 0         close $fh
391             or croak "failed closing file $filename $!";
392              
393 0           return;
394             }
395              
396              
397              
398             =head1 SUBROUTINES/METHODS
399              
400             =head2 new
401              
402             Creates a new db admin object for manipulating databases.
403              
404             =head2 BUILDARGS
405              
406             Compensates for the legacy invocation with the C<username>, C<password>,
407             C<host>, C<port> and C<dbname> parameters.
408              
409             =head2 verify_helpers( [ helpers => [...]], [operations => [...]])
410              
411             Verifies ability to execute (external) helper applications by
412             method name (through the C<operations> argument) or by external helper
413             name (through the C<helpers> argument). Returns a hash ref with each
414             key being the name of a helper application (see C<helpers> below) with
415             the values being a boolean indicating whether or not the helper can be
416             successfully executed.
417              
418             Valid values in the array referenced by the C<operations> parameter are
419             C<create>, C<run_file>, C<backup>, C<backup_globals>, C<restore> and
420             C<drop>; the methods this module implements with the help of external
421             helper programs. (Other values may be passed, but unsupported values
422             aren't included in the return value.)
423              
424             Valid values in the array referenced by the C<helpers> parameter are the
425             names of the PostgreSQL helper programs C<createdb>, C<dropdb>, C<pg_dump>,
426             C<pg_dumpall>, C<pg_restore> and C<psql>. (Other values may be passed, but
427             unsupported values will not be included in the return value.)
428              
429             When no arguments are passed, all helpers will be tested.
430              
431             Note: C<verify_helpers> is a class method, meaning it wants to be called
432             as C<PGObject::Util::DBAdmin->verify_helpers()>.
433              
434             =cut
435              
436             around 'BUILDARGS' => sub {
437             my ($orig, $class, @args) = @_;
438              
439             ## 1.1.0 compatibility code (allow a reference to be passed in)
440             my %args = (@args == 1 and ref $args[0]) ? (%{$args[0]}) : (@args);
441              
442             # deprecated field support code block
443             if (exists $args{connect_data}) {
444             # Work-around for 'export' creating the expectation that
445             # parameters may be overridable; I've observed the pattern
446             # ...->new($db->export, (dbname => 'newdb'))
447             # which we "solve" by hacking the dbname arg into the connect_data
448             # Don't overwrite connect_data, because it may be used elsewhere...
449             $args{connect_data} = {
450             %{$args{connect_data}},
451             dbname => ($args{dbname} // $args{connect_data}->{dbname})
452             };
453              
454             # Now for legacy purposes hack the connection parameters into
455             # connect_data
456             $args{username} = $args{connect_data}->{user};
457             $args{$_} = $args{connect_data}->{$_} for (qw(password dbname
458             host port));
459             }
460             else {
461             $args{connect_data} = {};
462             $args{connect_data}->{user} = $args{username};
463             $args{connect_data}->{password} = $args{password};
464             $args{connect_data}->{dbname} = $args{dbname};
465             $args{connect_data}->{host} = $args{host};
466             $args{connect_data}->{port} = $args{port};
467             }
468             return $class->$orig(%args);
469             };
470              
471              
472              
473              
474             sub _run_capturing_output {
475 0     0     my @args = @_;
476 0     0     my ($stdout, $stderr, $exitcode) = capture { _run_with_env(@args); };
  0            
477              
478 0           return $exitcode;
479             }
480              
481             sub verify_helpers {
482 0     0 1   my ($class, %args) = @_;
483              
484             my @helpers = (
485 0   0       @{$args{helpers} // []},
486 0   0       map { @{$helpers{$_} // []} } @{$args{operations} // []}
  0   0        
  0            
  0            
487             );
488 0 0         if (not @helpers) {
489 0           @helpers = keys %helper_paths;
490             }
491             return {
492             map {
493 0           $_ => not _run_capturing_output(command =>
494 0           [ $helper_paths{$_} , '--help' ])
495             } @helpers
496             };
497             }
498              
499              
500             =head2 export
501              
502             Exports the database parameters as a list so it can be used to create another
503             object.
504              
505             =cut
506              
507             sub export {
508 0     0 1   my $self = shift;
509 0           return ( connect_data => $self->connect_data );
510             }
511              
512             =head2 connect($options)
513              
514             Connects to the database using DBI and returns a database connection.
515              
516             Connection options may be specified in the $options hashref.
517              
518             =cut
519              
520             sub connect {
521 0     0 1   my ($self, $options) = @_;
522              
523 0           my $connect = _connect_data_str($self->connect_data);
524 0           $self->logger->trace(qq|Connecting using connection string "dbi:Pg:$connect"|);
525             my $dbh = DBI->connect(
526             'dbi:Pg:' . $connect,
527             $self->connect_data->{user} // '', # suppress use of DBI_USER
528 0 0 0       $self->connect_data->{password} // '',# suppress use of DBI_PASS
      0        
529             $options
530             )
531             or croak $self->logger->fatal('Could not connect to database: ' . $DBI::errstr);
532              
533 0           return $dbh;
534             }
535              
536             =head2 server_version([$dbname])
537              
538             Returns a version string (like 9.1.4) for PostgreSQL. Croaks on error.
539              
540             When a database name is specified, uses that database to connect to,
541             using the credentials specified in the instance.
542              
543             If no database name is specified, 'template1' is used.
544              
545             =cut
546              
547             sub server_version {
548 0     0 1   my $self = shift @_;
549 0   0       my $dbname = (shift @_) || 'template1';
550             my $version =
551             __PACKAGE__->new($self->export, (dbname => $dbname)
552 0           )->connect->{pg_server_version};
553              
554 0           my $retval = '';
555 0           while (1) {
556 0           $retval = ($version % 100) . $retval;
557 0           $version = int($version / 100);
558              
559 0 0         return $retval unless $version;
560 0           $retval = ".$retval";
561             }
562             }
563              
564              
565             =head2 list_dbs([$dbname])
566              
567             Returns a list of db names.
568              
569             When a database name is specified, uses that database to connect to,
570             using the credentials specified in the instance.
571              
572             If no database name is specified, 'template1' is used.
573              
574             =cut
575              
576             sub list_dbs {
577 0     0 1   my $self = shift;
578 0   0       my $dbname = (shift @_) || 'template1';
579              
580 0           return map { $_->[0] }
581 0           @{ __PACKAGE__->new($self->export, (dbname => $dbname)
  0            
582             )->connect->selectall_arrayref(
583             'SELECT datname from pg_database order by datname'
584             ) };
585             }
586              
587             =head2 create
588              
589             Creates a new database.
590              
591             Croaks on error, returns true on success.
592              
593             Supported arguments:
594              
595             =over
596              
597             =item copy_of
598              
599             Creates the new database as a copy of the specified one (using it as
600             a template). Optional parameter. Default is to create a database
601             without a template.
602              
603             =back
604              
605             =cut
606              
607             sub create {
608 0     0 1   my $self = shift;
609 0           my %args = @_;
610              
611 0           my @command = ($helper_paths{createdb});
612 0 0         defined $args{copy_of} and push(@command, '-T', $args{copy_of});
613             # No need to pass the database name PGDATABASE will be set
614             # if a 'dbname' connection parameter was provided
615              
616 0           $self->_run_command(command => [@command],
617             error => 'error creating database');
618              
619 0           return 1;
620             }
621              
622              
623             =head2 run_file
624              
625             Run the specified file on the db.
626              
627             After calling this method, STDOUT and STDERR output from the external
628             utility which runs the file on the database are available as properties
629             $db->stdout and $db->stderr respectively.
630              
631             Croaks on error. Returns true on success.
632              
633             Recognized arguments are:
634              
635             =over
636              
637             =item file
638              
639             Path to file to be run. This is a mandatory argument.
640              
641             =item vars
642              
643             A hash reference containing C<psql>-variables to be passed to the script
644             being executed. Running:
645              
646             $dbadmin->run_file(file => '/tmp/pg.sql', vars => { schema => 'xyz' });
647              
648             Is equivalent to starting the file C</tmp/pg.sql> with the command
649              
650             \set schema xyz
651              
652             To undefine a variable, associate the variable name (hash key) with the
653             value C<undef>.
654              
655             =item stdout_log
656              
657             Provided for legacy compatibility. Optional argument. The full path of
658             a file to which STDOUT from the external psql utility will be appended.
659              
660             =item errlog
661              
662             Provided for legacy compatibility. Optional argument. The full path of
663             a file to which STDERR from the external psql utility will be appended.
664              
665             =back
666              
667             =cut
668              
669             sub run_file {
670 0     0 1   my ($self, %args) = @_;
671 0   0       my $vars = $args{vars} // {};
672 0           $self->{stderr} = undef;
673 0           $self->{stdout} = undef;
674              
675 0 0         croak 'Must specify file' unless defined $args{file};
676 0 0         croak 'Specified file does not exist' unless -e $args{file};
677              
678             # Build command
679             my @command =
680             ($helper_paths{psql}, '--set=ON_ERROR_STOP=on',
681             (map { ('-v',
682 0 0         defined $vars->{$_} ? "$_=$vars->{$_}" : $_ ) }
683             keys %$vars),
684 0           '-f', $args{file});
685              
686             my $result = $self->_run_command(
687             command => [@command],
688             errlog => $args{errlog},
689             stdout_log => $args{stdout_log},
690 0           error => "error running file '$args{file}'");
691              
692 0           return $result;
693             }
694              
695              
696             =head2 backup
697              
698             Creates a database backup file.
699              
700             After calling this method, STDOUT and STDERR output from the external
701             utility which runs the file on the database are available as properties
702             $db->stdout and $db->stderr respectively.
703              
704             Unlinks the output file and croaks on error.
705              
706             Returns the full path of the file containining the backup.
707              
708             Accepted parameters:
709              
710             =over
711              
712             =item format
713              
714             The specified format, for example c for custom. Defaults to plain text.
715              
716             =item file
717              
718             Full path of the file to which the backup will be written. If the file
719             does not exist, one will be created with umask 0600. If the file exists,
720             it will be overwritten, but its permissions will not be changed.
721              
722             If undefined, a file will be created using File::Temp having umask 0600.
723              
724             =item tempdir
725              
726             The directory in which to write the backup file. Optional parameter. Uses
727             File::Temp default if not defined. Ignored if file parameter is given.
728              
729             =item compress
730              
731             Optional parameter. Specifies the compression level to use and is passed to
732             the underlying pg_dump command. Default is no compression.
733              
734             =back
735              
736             =cut
737              
738             sub backup {
739 0     0 1   my ($self, %args) = @_;
740 0           $self->{stderr} = undef;
741 0           $self->{stdout} = undef;
742              
743 0           my $output_filename = $self->_generate_output_filename(%args);
744              
745 0           my @command = ($helper_paths{pg_dump}, '-f', $output_filename);
746 0 0         defined $args{compress} and push(@command, '-Z', $args{compress});
747 0 0         defined $args{format} and push(@command, "-F$args{format}");
748              
749 0           $self->_run_command(command => [@command],
750             unlink => [$output_filename],
751             error => 'error running pg_dump command');
752              
753 0           return $output_filename;
754             }
755              
756              
757             =head2 backup_globals
758              
759             This creates a file containing a plain text dump of global (inter-db)
760             objects, such as users and tablespaces. It uses pg_dumpall to do this.
761              
762             Being a plain text file, it can be restored using the run_file method.
763              
764             Unlinks the output file and croaks on error.
765              
766             Returns the full path of the file containining the backup.
767              
768             Accepted parameters:
769              
770             =over
771              
772             =item file
773              
774             Full path of the file to which the backup will be written. If the file
775             does not exist, one will be created with umask 0600. If the file exists,
776             it will be overwritten, but its permissions will not be changed.
777              
778             If undefined, a file will be created using File::Temp having umask 0600.
779              
780             =item tempdir
781              
782             The directory in which to write the backup file. Optional parameter. Uses
783             File::Temp default if not defined. Ignored if file parameter is given.
784              
785             =back
786              
787             =cut
788              
789             sub backup_globals {
790 0     0 1   my ($self, %args) = @_;
791 0           $self->{stderr} = undef;
792 0           $self->{stdout} = undef;
793              
794 0 0         local $ENV{PGPASSWORD} = $self->password if defined $self->password;
795 0           my $output_filename = $self->_generate_output_filename(%args);
796              
797 0           my @command = ($helper_paths{pg_dumpall}, '-g', '-f', $output_filename);
798              
799 0           $self->_run_command(command => [@command],
800             unlink => [$output_filename],
801             error => 'error running pg_dumpall command');
802              
803 0           return $output_filename;
804             }
805              
806              
807             =head2 restore
808              
809             Restores from a saved file. Must pass in the file name as a named argument.
810              
811             After calling this method, STDOUT and STDERR output from the external
812             restore utility are available as properties $db->stdout and $db->stderr
813             respectively.
814              
815             Croaks on error. Returns true on success.
816              
817             Recognized arguments are:
818              
819             =over
820              
821             =item file
822              
823             Path to file which will be restored to the database. Required.
824              
825             =item format
826              
827             The file format, for example c for custom. Defaults to plain text.
828              
829             =back
830              
831             =cut
832              
833             sub restore {
834 0     0 1   my ($self, %args) = @_;
835 0           $self->{stderr} = undef;
836 0           $self->{stdout} = undef;
837              
838 0 0         croak 'Must specify file' unless defined $args{file};
839 0 0         croak 'Specified file does not exist' unless -e $args{file};
840              
841             return $self->run_file(%args)
842 0 0 0       if not defined $args{format} or $args{format} eq 'p';
843              
844             # Build command options
845 0           my @command = ($helper_paths{pg_restore}, '--verbose', '--exit-on-error');
846 0 0         defined $args{format} and push(@command, "-F$args{format}");
847             defined $self->connect_data->{dbname} and
848 0 0         push(@command, '-d', $self->connect_data->{dbname});
849 0           push(@command, $args{file});
850              
851 0           $self->_run_command(command => [@command],
852             error => "error restoring from $args{file}");
853              
854 0           return 1;
855             }
856              
857              
858             =head2 drop
859              
860             Drops the database. This is not recoverable. Croaks on error, returns
861             true on success.
862              
863             =cut
864              
865             sub drop {
866 0     0 1   my ($self) = @_;
867              
868 0 0         croak 'No db name of this object' unless $self->dbname;
869              
870 0           my @command = ($helper_paths{dropdb});
871 0           push(@command, $self->connect_data->{dbname});
872              
873 0           $self->_run_command(command => [@command],
874             error => 'error dropping database');
875              
876 0           return 1;
877             }
878              
879              
880             =head2 is_ready
881              
882             Drops the database. This is not recoverable. Croaks on error, returns
883             true on success.
884              
885             =cut
886              
887             sub is_ready {
888 0     0 1   my ($self) = @_;
889              
890 0 0         croak 'No db name of this object' unless $self->dbname;
891              
892 0           my @command = ($helper_paths{pg_isready});
893 0           push(@command, $self->connect_data->{dbname});
894              
895 0           $self->_run_command(command => [@command],
896             error => 'error dropping database');
897              
898 0           return 1;
899             }
900              
901              
902              
903              
904              
905             =head1 CAPTURING
906              
907             This module uses C<Capture::Tiny> to run extenal commands and capture their
908             output, which is made available through the C<stderr> and C<stdout>
909             properties.
910              
911             This capturing does not work if Perl's standard C<STDOUT> or
912             C<STDERR> filehandles have been localized. In this situation, the localized
913             filehandles are captured, but external system calls are not
914             affected by the localization, so their output is sent to the original
915             filehandles and is not captured.
916              
917             See the C<Capture::Tiny> documentation for more details.
918              
919             =head1 AUTHOR
920              
921             Chris Travers, C<< <chris at efficito.com> >>
922              
923             =head1 BUGS
924              
925             Please report any bugs or feature requests to C<bug-pgobject-util-dbadmin at rt.cpan.org>, or through
926             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=PGObject-Util-DBAdmin>. I will be notified, and then you'll
927             automatically be notified of progress on your bug as I make changes.
928              
929              
930              
931              
932             =head1 SUPPORT
933              
934             You can find documentation for this module with the perldoc command.
935              
936             perldoc PGObject::Util::DBAdmin
937              
938              
939             You can also look for information at:
940              
941             =over 4
942              
943             =item * RT: CPAN's request tracker (report bugs here)
944              
945             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=PGObject-Util-DBAdmin>
946              
947             =item * AnnoCPAN: Annotated CPAN documentation
948              
949             L<http://annocpan.org/dist/PGObject-Util-DBAdmin>
950              
951             =item * CPAN Ratings
952              
953             L<http://cpanratings.perl.org/d/PGObject-Util-DBAdmin>
954              
955             =item * Search CPAN
956              
957             L<http://search.cpan.org/dist/PGObject-Util-DBAdmin/>
958              
959             =back
960              
961              
962             =head1 ACKNOWLEDGEMENTS
963              
964              
965             =head1 LICENSE AND COPYRIGHT
966              
967             Copyright 2014-2020 Chris Travers.
968              
969             This program is distributed under the (Revised) BSD License:
970             L<http://www.opensource.org/licenses/BSD-3-Clause>
971              
972             Redistribution and use in source and binary forms, with or without
973             modification, are permitted provided that the following conditions
974             are met:
975              
976             * Redistributions of source code must retain the above copyright
977             notice, this list of conditions and the following disclaimer.
978              
979             * Redistributions in binary form must reproduce the above copyright
980             notice, this list of conditions and the following disclaimer in the
981             documentation and/or other materials provided with the distribution.
982              
983             * Neither the name of Chris Travers's Organization
984             nor the names of its contributors may be used to endorse or promote
985             products derived from this software without specific prior written
986             permission.
987              
988             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
989             "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
990             LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
991             A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
992             OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
993             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
994             LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
995             DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
996             THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
997             (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
998             OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
999              
1000              
1001             =cut
1002              
1003             1; # End of PGObject::Util::DBAdmin