File Coverage

blib/lib/PGObject/Util/DBAdmin.pm
Criterion Covered Total %
statement 32 182 17.5
branch 0 64 0.0
condition 0 24 0.0
subroutine 11 35 31.4
pod 11 11 100.0
total 54 316 17.0


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