#!/usr/bin/perl -l use strict; use warnings; use PSQL::Query::Handle; use IO::Handle; use Getopt::Long; our ( $fmt_oppr, $fmt_info, $dom_char ); my $result = GetOptions ( 'printf=s' => \$fmt_oppr , 'printf-info=s' => \$fmt_info , 'dom-char=s' => \$dom_char ); $fmt_oppr = '%s' unless $fmt_oppr or $fmt_info; foreach ( $fmt_oppr, $fmt_info ) { next unless defined; s/ \\n / \n /gxo; s/ \\t / \t /gxo; } my $io = IO::Handle->new_from_fd( 'STDIN', "r" ); my $query = PSQL::Query::Handle->new({ handle => $io }); while ( my $row = $query->shift_row ) { if ( $fmt_oppr ) { my $fmt_oppr = $fmt_oppr; ## Source/Name ## Estimate Startup/Total/Rows/Width ## Actual Startup/Total/Rows/Width $fmt_oppr =~ s/ %( [snd] | e[strw] | a[strl] ) / _lookup_oppr( $row, $1 ) /gex ; ## You might not always have something ## Case: user requests ANALYZE and does only EXPLAIN print $fmt_oppr if $fmt_oppr; } if ( $fmt_info ) { while ( my $row = $row->shift_info ) { my $fmt_info = $fmt_info; ## Info Name/Verbose/Src $fmt_info =~ s/ %( [nsv] ) / _lookup_opprInfo( $row, $1 ) /gex ; print $fmt_info; } } } sub _lookup_oppr { my ( $row, $lookup ) = @_; my ( $obj, $modifier ) = split '', $lookup; my $return = { ## ## Row ## n => sub { $row->name } , s => sub { $row->src } , d => sub { $dom_char ? $dom_char x $row->dom_level : $row->dom_level } , e => sub { my $t = $row->cost; return sub { +{ s => sub { $t->startup } , t => sub { $t->total } , r => sub { $t->rows } , w => sub { $t->width } } }; } , a => sub { my $t = $row->time; return sub { +{ s => sub { $t->startup } , t => sub { $t->total } , r => sub { $t->rows } , l => sub { $t->loops } } } } }; ## returns form func if the user request analyze info ## and has only explain info return if $obj eq 'a' and not $row->has_time; $modifier ? $return->{$obj}->()->()->{$modifier}->() : $return->{$obj}->() ; } sub _lookup_opprInfo { my ( $row, $obj ) = @_; my $return = { n => sub { $row->name } , v => sub { $row->verbose } , s => sub { $row->src } }; $return->{$obj}->(); } 1; __END__ =head1 NAME psql-plus - Utility to enhance the functionality of psql =head1 SYNOPSIS echo EXPLAIN SELECT * FROM | psql -d | psql-plus --printf "%n" psql -d database \o|psql-plus --printf "%n" EXPLAIN SELECT * FROM
EXPLAIN SELECT * FROM ^D psql-plus --dom-char x --printf "%d" =head1 DESCRIPTION =head2 Arguments =over 5 =item --dom-char ( graphic char for dom-level '%d' representation ) =item --printf ( Operation Row ) %n = name %s = src %d = dom_level ( see notes below ) %e* explain/estimate %a* actual %es = Estimate startup %et = Estimate total %er = Estimate rows %ew = Estimate width %as = Actual (time) Startup %at = Actual (time) Total %ar = Actual Rows %al = Actual Loops * dom_level: If you run an explain this is the whitespace significant portion from the left-margin to the first \S. =item --printf-info ( OperationInfo Row ) %n = Info name %v = Info verbose (not currently further parsed) %s = Source (unmodified) =back =head2 PSQL::Query This is currently just a script for the L library. All of the voodoo happens there. =head2 Not-yet-implimented --lookforward-to Roadmap to .01: =over 5 =item * automatic opt-in posting to pastbins (DWIM). syn: C<--pastbin [rafb|sial|pastbin]> =item * the ability to return a url only when posting to a pastbin. syn: C<--url-only> =item * XML exportation syn: C<--format=XML> / syntax highlighting (tentative) =back Roadmap to .02: =over 5 =item * expansion of PSQL:: to encompass more postgres-specific functionality, the use of a new lib other than L =back =head1 BUGS Email me they will get fixed in .05 seconds, or you can sue someone else. =head1 CAVEATS Currently limited to "Enhancing" only the functionality of EXPLAIN and EXPLAIN ANALYZE =head1 COPYRIGHT Artistic or GPL, like 99.9% of CPAN-distributed stuff. =head1 AVAILABILITY CPAN L =head1 AUTHOR Evan Carroll =cut