File Coverage

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


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