File Coverage

blib/lib/DBI/Shell/SQLMinus.pm
Criterion Covered Total %
statement 180 404 44.5
branch 88 278 31.6
condition 9 29 31.0
subroutine 15 35 42.8
pod 0 13 0.0
total 292 759 38.4


line stmt bran cond sub pod time code
1             #!perl -w
2             # vim:ts=4:sw=4:aw:ai:nowrapscan
3             #
4             #
5              
6             package DBI::Shell::SQLMinus;
7              
8             our $VERSION = '11.97'; # VERSION
9              
10 4     4   31 use strict;
  4         9  
  4         131  
11 4     4   21 use Text::Abbrev ();
  4         10  
  4         80  
12 4     4   2057 use Text::ParseWords;
  4         5525  
  4         299  
13 4     4   1944 use Text::Wrap;
  4         11039  
  4         262  
14 4     4   29 use IO::File;
  4         8  
  4         641  
15 4     4   28 use IO::Tee;
  4         8  
  4         127  
16 4     4   22 use Carp;
  4         8  
  4         24117  
17              
18             sub init {
19 4     4 0 16 my ($class, $sh, @args) = @_;
20 4   33     55 $class = ref $class || $class;
21 4         609 my $sqlminus = {
22             archive => {
23             log => undef,
24             },
25             'breaks' => {
26             skip => [ qw{text} ],
27             skip_page => [ qw{text} ],
28             dup => [ qw{text} ],
29             nodup => [ qw{text} ],
30             },
31             break_current => {
32             },
33             'clear' => {
34             break => undef,
35             buffer => undef,
36             columns => undef,
37             computes => undef,
38             screen => undef,
39             sql => undef,
40             timing => undef,
41             },
42             db => undef,
43             dbh => undef,
44             column => {
45             column_name => [ qw{text} ],
46             alias => [ qw{text} ],
47             clear => [ qw{command} ],
48             fold_after => [ qw{text} ],
49             fold_before => [ qw{text} ],
50             format => [ qw{text} ],
51             heading => [ qw{text} ],
52             justify => [ qw{c l r f} ],
53             like => [ qw{text} ],
54             'length' => [ qw{text} ],
55             newline => [ qw{text} ],
56             new_value => [ qw{text} ],
57             noprint => [ qw{on off} ],
58             'print' => [ qw{on off} ],
59             null => [ qw{text} ],
60             on => 1,
61             off => 0,
62             truncated => [ qw{on off} ],
63             type => [ qw{text} ],
64             wordwrapped => [ qw{on off} ],
65             wrapped => [ qw{on off} ],
66             column_format => undef,
67             format_function => undef,
68             precision => undef,
69             scale => undef,
70             },
71             # hash ref contains formats for code.
72             column_format => {
73             },
74             # Hash ref contains the formats for the column headers.
75             column_header_format => {
76             },
77             commands => {
78             '@' => undef,
79             'accept'=> undef,
80             append => undef,
81             attribute => undef,
82             break => undef,
83             btitle => undef,
84             change => undef,
85             clear => undef,
86             copy => undef,
87             column => undef,
88             compute => undef,
89             define => undef,
90             edit => undef,
91             'exec' => undef,
92             get => undef,
93             pause => undef,
94             prompt => undef,
95             repheader=> undef,
96             repfooter=> undef,
97             run => undef,
98             save => undef,
99             set => undef,
100             show => undef,
101             start => undef,
102             ttitle => undef,
103             undefine=> undef,
104             },
105             set_current => {
106             appinfo => undef,
107             arraysize => undef,
108             autocommit => undef,
109             autoprint => undef,
110             autorecovery=> undef,
111             autotrace => undef,
112             blockterminator=> undef,
113             buffer => undef,
114             closecursor => undef,
115             cmdsep => undef,
116             compatibility=> undef,
117             concat => undef,
118             copycommit => undef,
119             copytypecheck=> undef,
120             define => undef,
121             document => undef,
122             echo => undef,
123             editfile => undef,
124             embedded => undef,
125             escape => undef,
126             feedback => undef,
127             flagger => undef,
128             flush => undef,
129             heading => 1,
130             headsep => ' ',
131             instance => undef,
132             linesize => 72,
133             limit => undef,
134             loboffset => undef,
135             logsource => undef,
136             long => undef,
137             longchunksize => undef,
138             maxdata => undef,
139             newpage => undef,
140             null => undef,
141             numwidth => undef,
142             pagesize => undef,
143             pause => undef,
144             recsep => 1,
145             recsepchar => ' ',
146             scan => qq{obsolete command: use 'set define' instead},
147             serveroutput=> undef,
148             shiftinout => undef,
149             showmode => undef,
150             space => qq{obsolete command: use 'set define' instead},
151             sqlblanklines=> undef,
152             sqlcase => undef,
153             sqlcontinue => undef,
154             sqlnumber => undef,
155             sqlprefix => undef,
156             sqlprompt => undef,
157             sqlterminator=> undef,
158             suffix => undef,
159             tab => undef,
160             termout => undef,
161             'time' => undef,
162             'timing' => undef,
163             trimout => undef,
164             trimspool => undef,
165             'truncate' => undef,
166             underline => '-',
167             verify => undef,
168             wrap => undef,
169             },
170             # Each set command may call a custom function. Included are
171             # currently defined sets. For simple set/get, the value is
172             # stored set_current.
173             set_commands => {
174              
175             appinfo => ['_unimp'],
176             arraysize => ['_unimp'],
177             autocommit => ['_unimp'],
178             autoprint => ['_unimp'],
179             autorecovery => ['_unimp'],
180             autotrace => ['_unimp'],
181              
182             blockterminator => ['_unimp'],
183             buffer => ['_unimp'],
184              
185             closecursor => ['_unimp'],
186             cmdsep => ['_unimp'],
187             compatibility => ['_unimp'],
188             concat => ['_unimp'],
189             copycommit => ['_unimp'],
190             copytypecheck => ['_unimp'],
191              
192             define => ['_unimp'],
193             document => ['_unimp'],
194              
195             echo => ['_set_get'],
196             editfile => ['_unimp'],
197             embedded => ['_unimp'],
198             escape => ['_unimp'],
199              
200             feedback => ['_unimp'],
201             flagger => ['_unimp'],
202             flush => ['_unimp'],
203              
204             heading => ['_set_get'],
205             headsep => ['_set_get'],
206              
207             instance => ['_unimp'],
208              
209             linesize => ['_set_get'],
210             limit => ['_set_get'],
211             loboffset => ['_unimp'],
212             logsource => ['_unimp'],
213             long => ['_unimp'],
214             longchunksize => ['_unimp'],
215              
216             maxdata => ['_unimp'],
217              
218             newpage => ['_unimp'],
219             null => ['_set_get'],
220             numwidth => ['_unimp'],
221              
222             pagesize => ['_set_get'],
223             pause => ['_unimp'],
224              
225             recsep => ['_set_get'],
226             recsepchar => ['_set_get'],
227              
228             scan => ['_print_buffer',
229             qq{obsolete command: use 'set define' instead}],
230             serveroutput => ['_unimp'],
231             shiftinout => ['_unimp'],
232             showmode => ['_unimp'],
233             space => ['_print_buffer',
234             qq{obsolete command: use 'set define' instead}],
235             sqlblanklines => ['_unimp'],
236             sqlcase => ['_unimp'],
237             sqlcontinue => ['_unimp'],
238             sqlnumber => ['_unimp'],
239             sqlprefix => ['_unimp'],
240             sqlprompt => ['_unimp'],
241             sqlterminator => ['_unimp'],
242             suffix => ['_unimp'],
243              
244             tab => ['_unimp'],
245             termout => ['_unimp'],
246             'time' => ['_unimp'],
247             'timing' => ['_unimp'],
248             trimout => ['_unimp'],
249             trimspool => ['_unimp'],
250             'truncate' => ['_unimp'],
251              
252             underline => ['_set_get'],
253              
254             verify => ['_unimp'],
255              
256             wrap => ['_unimp'],
257             },
258             show => {
259             all => ['_all'],
260              
261             btitle => ['_unimp'],
262              
263             catalogs => ['_unimp'],
264             columns => ['_unimp'],
265              
266             errors => ['_unimp'],
267              
268             grants => ['_unimp'],
269              
270             help => ['_help'],
271             hints => ['_hints'],
272              
273             lno => ['_hints'],
274              
275             me => ['_me'],
276              
277             objects => ['_unimp'],
278              
279             packages => ['_unimp'],
280             parameters => ['_unimp'],
281             password => ['_print_buffer', qq{I don\'t think so!}],
282             pno => ['_unimp'],
283              
284             release => ['_unimp'],
285             repfooter => ['_unimp'],
286             repheader => ['_unimp'],
287             roles => ['_unimp'],
288              
289             schemas => ['_schemas'],
290             sga => ['_unimp'],
291             show => ['_show_all_commands'],
292             spool => ['_spool'],
293             sqlcode => ['_sqlcode'],
294              
295             ttitle => ['_unimp'],
296             tables => ['_tables'],
297             types => ['_types'],
298              
299             users => ['_unimp'],
300              
301             views => ['_views'],
302             },
303             sql => {
304             pno => undef,
305             lno => undef,
306             release => undef,
307             user => undef,
308             },
309             };
310              
311 4         29 my $pi = bless $sqlminus, $class;
312              
313             # add the sqlminus object to the plugin list for reference later.
314 4         27 $sh->{plugin}->{sqlminus} = $pi;
315              
316 4         31 $pi->{dbh} = \$sh->{dbh};
317              
318 4         10 my $com_ref = $sh->{commands};
319              
320 4         9 foreach (sort keys %{$pi->{commands}}) {
  4         59  
321 104         295 $com_ref->{$_} = {
322             hint => "SQLMinus: $_",
323             };
324             }
325 4         25 return $pi;
326             }
327             # 'btittle' => {
328             # off => undef,
329             # on => undef,
330             # col => undef,
331             # skip => undef,
332             # tab => undef,
333             # left => undef,
334             # center => undef,
335             # right => undef,
336             # bold => undef,
337             # format => undef,
338             # text => undef,
339             # variable => undef,
340             # },
341             #
342             # break.
343             #
344             # BRE[AK] [ON report_element [action [action]]] ...
345             #
346             # where:
347             #
348             # report_element
349             #
350             # Requires the following syntax:
351             #
352             # {column|expr|ROW|REPORT}
353             #
354             # action
355             #
356             # Requires the following syntax:
357             #
358             # [SKI[P] n|[SKI[P]] PAGE][NODUP[LICATES]|DUP[LICATES]]
359             #
360             sub do_break {
361 0     0 0 0 my ($self, $command, @args) = @_;
362              
363             # print "break command:\n";
364              
365 0         0 my $breaks = $self->{plugin}->{sqlminus}->{breaks};
366 0         0 my $cbreaks = $self->{plugin}->{sqlminus}->{break_current};
367              
368 0 0       0 unless( $command ) {
369 0         0 my $maxlen = 0;
370 0         0 foreach (keys %$cbreaks ) {
371 0 0       0 $maxlen = (length $_ > $maxlen? length $_ : $maxlen );
372             }
373 0         0 my $format = sprintf("%%-%ds", $maxlen );
374 0         0 foreach my $col_name (sort keys %$cbreaks) {
375 0         0 $self->log( sprintf( $format, $col_name ));
376 0         0 foreach my $col (sort keys %$breaks) {
377 0 0       0 next unless $cbreaks->{$col_name}->{$col};
378             $self->print_buffer_nop(sprintf( "\t%-15s %s\n", $col,
379 0   0     0 ($cbreaks->{$col_name}->{$col}||'undef') ));
380             }
381             }
382 0         0 return;
383             }
384              
385 0         0 my @words = quotewords('\s+', 0, join( " ", @args));
386              
387             WORD:
388 0         0 while(@words) {
389 0         0 my $val = shift @words;
390              
391 0 0       0 if ($val =~ m/row/i ) {
    0          
    0          
392             } elsif ($val =~ m/report/i ) {
393             } elsif ($val =~ m/on/i ) { # Skip on
394 0         0 next WORD;
395             } else {
396             # Handle a column.
397 0 0       0 if (exists $cbreaks->{$val}) {
398 0         0 delete $cbreaks->{$val};
399             }
400 0         0 $cbreaks->{$val} = {
401             skip => undef
402             , nodup => undef
403             }; # Create the column in the break group.
404              
405             ACTION:
406 0         0 while(@words) {
407 0         0 my $action = shift @words;
408 0         0 $self->print_buffer_nop( "actin $action" );
409 0 0       0 last unless $action =~ m/\bskip|\bpage|\bnodup|\bdup/i;
410            
411             # These are the accepted action given to a break.
412 0 0       0 if ($action =~ m/\bskip/i ) {
    0          
    0          
    0          
413             # Skip consumes the next value, either page or a number.
414 0 0       0 my $skip_val = shift @words if (@words);
415 0 0       0 unless ($skip_val) {
416 0         0 $self->print_buffer(
417             qq{break: action $action number lines|page} );
418 0         0 last;
419             }
420              
421 0         0 $self->print_buffer_nop( "action $action $skip_val" );
422 0 0       0 if ($skip_val =~ m/(\d+)/) {
423 0         0 $cbreaks->{$val}->{skip} = $skip_val;
424             delete $cbreaks->{$val}->{skip_page}
425 0 0       0 if (exists $cbreaks->{$val}->{skip_page});
426             } else {
427 0         0 $cbreaks->{$val}->{skip_page} = 1;
428             delete $cbreaks->{$val}->{skip}
429 0 0       0 if (exists $cbreaks->{$val}->{skip});
430             }
431             # Default value, if nodup/dup is not defined, add.
432 0         0 unshift @words, 'nodup';
433             unshift @words, 'nodup' unless (exists
434             $cbreaks->{$val}->{dup} or exists
435 0 0 0     0 $cbreaks->{$val}->{nodup});
436              
437             } elsif ($action =~ m/\bnodup/i ) {
438 0         0 $cbreaks->{$val}->{nodup} = 1;
439             delete $cbreaks->{$val}->{dup}
440 0 0       0 if (exists $cbreaks->{$val}->{dup});
441             } elsif ($action =~ m/\bdup/i ) {
442 0         0 $cbreaks->{$val}->{dup} = 1;
443             delete $cbreaks->{$val}->{nodup}
444 0 0       0 if (exists $cbreaks->{$val}->{nodup});
445             } elsif ($action =~ m/\bpage/i ) {
446             # Put skip in front of the value and let the skip command handle it.
447 0         0 unshift @words, 'skip', $action;
448             } else {
449 0         0 $self->print_buffer(
450             qq{break: action $action unknown, ambiguous, or not supported.} );
451 0         0 last;
452             }
453             }
454             }
455 0         0 return;
456             }
457              
458             return
459 0         0 $self->print_buffer(
460             qq{break: $command unknown, ambiguous, or not supported.} );
461             }
462              
463             #
464             # set
465             #
466             sub do_set {
467 24     24 0 83 my ($self, $command, @args) = @_;
468              
469              
470             # print "set command:\n";
471              
472 24         64 my $set = $self->{plugin}->{sqlminus}->{set_current};
473              
474 24 50       73 unless( $command ) {
475 0         0 my $maxlen = 0;
476 0         0 foreach (keys %$set ) {
477 0 0       0 $maxlen = (length $_ > $maxlen? length $_ : $maxlen );
478             }
479 0         0 my $format = sprintf("%%-%ds %%s", $maxlen );
480 0         0 foreach (sort keys %$set) {
481             $self->log(
482 0   0     0 sprintf( $format, $_, $set->{$_} || 'undef' )
483             );
484             }
485 0         0 return;
486             }
487              
488 24         263 my $options = Text::Abbrev::abbrev(keys %$set);
489              
490 24         53582 my $ref = $self->{plugin}->{sqlminus};
491              
492 24 50       90 if (my $c = $options->{$command}) {
493 24         169 $self->log( "command: $command " . ref $c . "" );
494 24 50       170 if (my $c = $options->{$command}) {
495 24         50 my ($cmd, @cargs) = @{$ref->{set_commands}->{$c}};
  24         98  
496 24 50       64 push(@args, @cargs) if @cargs;
497 24         132 return $self->{plugin}->{sqlminus}->$cmd(\$self,$c,@args);
498             }
499             }
500 0         0 my %l;
501 0 0       0 foreach (keys %$options) { $l{$options->{$_}}++ if m/^$command/ }
  0         0  
502 0         0 my $sug = wrap( "\t(", "\t\t", sort keys %l );
503 0 0       0 $sug = "\n$sug)" if defined $sug;
504 0 0       0 $sug = q{} unless defined $sug;
505             return
506 0         0 $self->print_buffer(
507             qq{set: $command unknown, ambiguous, or not supported.$sug} );
508             }
509              
510             # show
511             sub do_show {
512 1     1 0 5 my ($self, $command, @args) = @_;
513              
514 1 50       4 return unless $command;
515              
516 1         4 my $show = $self->{plugin}->{sqlminus}->{show};
517 1         3 my $ref = $self->{plugin}->{sqlminus};
518              
519 1         13 my $options = Text::Abbrev::abbrev(keys %$show);
520 1 50       810 if (my $c = $options->{$command}) {
521 1         3 my ($cmd, @cargs) = @{$ref->{show}->{$c}};
  1         6  
522 1 50       3 push(@args, @cargs) if @cargs;
523 1         7 return $self->{plugin}->{sqlminus}->$cmd(\$self,@args);
524             }
525 0         0 my %l;
526 0 0       0 foreach (keys %$options) { $l{$options->{$_}}++ if m/^$command/ }
  0         0  
527 0         0 my $sug = wrap( "\t(", "\t\t", sort keys %l );
528 0 0       0 $sug = "\n$sug)" if defined $sug;
529 0 0       0 $sug = q{} unless defined $sug; # rid warnings
530             return
531 0         0 $self->print_buffer(
532             qq{show: $command unknown, ambiguous, or not supported.$sug} );
533             }
534              
535             #
536             # Attempt to allow the user to define format string for query results.
537             #
538              
539              
540             sub do_column {
541 53     53 0 185 my ($self, $command, @args) = @_;
542              
543             # print "column command:\n" if $self->{debug};
544              
545             # my $set = $column_format;
546 53         131 my $ref = $self->{plugin}->{sqlminus};
547 53         116 my $column = $ref->{column};
548 53         100 my $column_format = $ref->{column_format};
549 53         93 my $column_header_format = $ref->{column_header_format};
550              
551             # If just the format command is issued, print all the current formatted
552             # columns. Currently, only the column name is printed.
553 53 100       160 unless( $command ) {
554 11         16 my $maxlen = 0;
555 11         37 foreach (keys %$column_format ) {
556 15 100       50 $maxlen = (length $_ > $maxlen? length $_ : $maxlen );
557             }
558 11         57 my $format = sprintf("%%-%ds", $maxlen );
559 11         42 foreach my $col_name (sort keys %$column_format) {
560 15         79 $self->log( sprintf( $format, $col_name ));
561 15         194 foreach my $col (sort keys %$column) {
562 375 100       835 next unless $column_format->{$col_name}->{$col};
563             $self->print_buffer_nop(sprintf( "\t%-15s %s\n", $col,
564 87   50     467 ($column_format->{$col_name}->{$col}||'undef') ));
565             }
566             }
567 11         65 return;
568             }
569              
570 42 100       176 if ( $command =~ m/clear/i ) {
571             # clear the format for either one or all columns.
572 6 50       26 if (@args) {
573             # Next argument column to clear.
574 0         0 my $f = shift @args;
575             # Format defined?
576 0         0 $self->_clear_format( \$column_format, $f );
577             } else {
578             # remove all column formats.
579              
580 6         24 foreach my $column (keys %$column_format) {
581             # warn "Removing format for : $column :\n";
582 8         40 $self->_clear_format( \$column_format, $column );
583             }
584              
585             # map { delete $column_format->{$_} } keys %$column_format
586             # if exists $ref->{column_format};
587             # map { delete $column_header_format->{$_} }
588             # keys %$column_header_format
589             # if exists $ref->{column_header_format};
590             }
591              
592 6         27 return $self->log( "format cleared" );
593             }
594              
595             #
596             # If column called with only a column name, display the current format.
597             #
598              
599 36 100       97 unless( @args ) {
600             return $self->log( "$command: no column format defined." )
601 3 100       30 unless exists $column_format->{$command};
602              
603 1         7 $self->log( "column $command format: " );
604 1         4 foreach my $col (sort keys %{$column_format->{$command}}) {
  1         18  
605 25 100       60 next unless $column_format->{$command}->{$col};
606             $self->print_buffer_nop(sprintf( "\t%-15s %s"
607             , $col
608 6   50     34 , ($column_format->{$command}->{$col}||'undef') ));
609             }
610 1         8 return;
611             }
612              
613             # print "column: $command ", join( " ", @args) , "\n" if $self->{debug};
614              
615             #
616             # column: column name.
617             #
618              
619             # Builds a structure of attributes supported in column formats.
620 33         68 my ($col, $col_head);
621 33 100       99 unless ( exists $column_format->{$command} ) {
622 8         19 my $struct = {};
623 8         54 foreach (keys %$column) {
624 200         313 $struct->{$_} = undef;
625             }
626 8         25 $column_format->{$command} = $struct;
627              
628 8         17 $col = $column_format->{$command};
629              
630 8         14 $col->{on} = 1;
631 8         17 $col->{off} = 0;
632             }
633              
634 33 100       95 $col = $column_format->{$command} unless $col;
635 33 50       81 $col_head = $column_header_format->{$command} unless $col_head;
636              
637              
638 33         233 my $options = Text::Abbrev::abbrev(keys %$column);
639              
640             # Handle quoted words or phrases.
641 33         27945 my @words = quotewords('\s+', 0, join( " ", @args));
642              
643             print "column: $command ", join( " ", @words) , "\n"
644 33 50       5025 if $self->{debug};
645              
646 33         85 while(@words) {
647 71         116 my ( $text, $on, $off, $justify );
648 71         124 my $argv = shift @words;
649 71 50       195 my $c = exists $options->{$argv} ? $options->{$argv} : undef;
650             # determine if the current argument is part of the format
651             # string or a value.
652 71 50       191 if ($c) {
653 71 50       457 if ( $c =~ m/alias/i ) {
    50          
    50          
    50          
    100          
    100          
    100          
    50          
    50          
    50          
    100          
    100          
    50          
    50          
    50          
    0          
    0          
    0          
654             ########################################################
655             # Alias
656             ########################################################
657 0         0 $col->{$c} = shift @words;
658             $self->log( "setting alias ... $col->{$c} ..." )
659 0 0       0 if $self->{debug};
660             } elsif ( $c =~ m/clear/i ) {
661             ########################################################
662             # Clear: syntax column column_name clear
663             ########################################################
664 0         0 $self->_clear_format( \$column_format, $command );
665 0         0 return $self->log( "format cleared" );
666             } elsif ( $c =~ m/fold_after/i ) {
667             ########################################################
668             # Fold After
669             ########################################################
670             } elsif ( $c =~ m/fold_before/i ) {
671             ########################################################
672             # Fold Before
673             ########################################################
674             } elsif ( $c =~ m/format/i ) {
675             ########################################################
676             # Format
677             ########################################################
678             # Begin with format of A# strings, 9 numeric.
679 27         62 my $f = shift @words;
680 27 50       59 return $self->column_usage( {format => 'undef'} )
681             unless $f;
682              
683 27         111 $self->_determine_format( $f, \$col );
684              
685             } elsif ( $c =~ m/heading/i ) {
686             ########################################################
687             # Heading
688             ########################################################
689 22         49 $col->{$c} = shift @words;
690             $self->log( "setting heading ... $col->{$c} ..." )
691 22 50       89 if $self->{debug};
692             } elsif ( $c =~ m/justify/i ) {
693             ########################################################
694             # Justify
695             ########################################################
696             # unset current justification.
697 17         28 my $f = shift @words;
698             # Handle special conditions.
699 17 100       48 if ($f =~ m/(?:of(?:f)?)/) {
700 3         6 $col->{$c} = undef;
701             $self->log( "justify cleared ... $f ..." ) if
702 3 50       136 $self->{debug};
703 3         11 next;
704             }
705              
706 14         21 $col->{$c} = undef;
707              
708 14         23 foreach my $just (@{$column->{$c}}) {
  14         41  
709             #$self->log( "\ttesting $f $just" ) if $self->{debug};
710 38 100       450 if ($f =~ m/^($just)/i) {
711             #$self->log( "\tmatch $f and $just" ) if $self->{debug};
712 10         27 $col->{$c} = $1;
713 10         23 last;
714             }
715             }
716             return $self->log( "invalid justification $f" ) unless
717 14 100       51 $col->{$c};
718             $self->log( "setting justify ... $col->{$c} $f ..." )
719 10 50       38 if $self->{debug};
720             } elsif ( $c =~ m/like/i ) {
721             ########################################################
722             # Like
723             ########################################################
724 0         0 $col->{$c} = shift @words;
725             } elsif ( $c =~ m/newline/i ) {
726             ########################################################
727             # Newline
728             ########################################################
729             } elsif ( $c =~ m/new_value/i ) {
730             ########################################################
731             # New Value
732             ########################################################
733             } elsif ( $c =~ m/noprint/i ) {
734             ########################################################
735             # No Print
736             ########################################################
737 2         6 $col->{$c} = 1;
738 2         6 $col->{'print'} = 0;
739             $self->log( "setting noprint ... $col->{$c} ..." )
740 2 50       9 if $self->{debug};
741             } elsif ( $c =~ m/print/i ) {
742             ########################################################
743             # Print
744             ########################################################
745 2         8 $col->{$c} = 1;
746 2         6 $col->{'noprint'} = 0;
747             $self->log( "setting print ... $col->{$c} ..." )
748 2 50       9 if $self->{debug};
749             } elsif ( $c =~ m/null/i ) {
750             ########################################################
751             # Null
752             ########################################################
753 0         0 $col->{$c} = shift @words;
754             $self->log( "setting null text ... $col->{$c} ..." )
755 0 0       0 if $self->{debug};
756             } elsif ( $c =~ m/on/i ) {
757             ########################################################
758             # On
759             ########################################################
760 0         0 $col->{$c} = 1;
761 0         0 $col->{off} = 0;
762             $self->log( "setting format on ... $col->{$c} ..." )
763 0 0       0 if $self->{debug};
764             } elsif ( $c =~ m/off/i ) {
765             ########################################################
766             # Off
767             ########################################################
768 1         4 $col->{$c} = 1;
769 1         3 $col->{on} = 0;
770             $self->log( "setting format off ... $col->{$c} ..." )
771 1 50       6 if $self->{debug};
772             } elsif ( $c =~ m/truncated/i ) {
773             ########################################################
774             # Truncated
775             ########################################################
776 0         0 $col->{$c} = 1;
777 0         0 $col->{'wrapped'} = 0;
778             $self->log( "setting truncated ... $col->{$c} ..." )
779 0 0       0 if $self->{debug};
780             } elsif ( $c =~ m/wordwrapped/i ) {
781             ########################################################
782             # Word Wrapped
783             ########################################################
784             $self->log( "setting wordwrapped ... $col->{$c} ..." )
785 0 0       0 if $self->{debug};
786             } elsif ( $c =~ m/wrapped/i ) {
787             ########################################################
788             # Wrapped
789             ########################################################
790 0         0 $col->{$c} = 1;
791 0         0 $col->{'truncated'} = 0;
792             $self->log( "setting wrapped ... $col->{$c} ..." )
793 0 0       0 if $self->{debug};
794             } else {
795             ########################################################
796             # Unknown
797             ########################################################
798             $self->log( "column unknown option: ... $c ..." )
799 0 0       0 if $self->{debug};
800             }
801              
802             }
803             }
804             #
805             # At this point the format is defined for the current column, now build
806             # the format string.
807             #
808             {
809             # Default justify is left.
810 29         59 my $justify = '<';
  29         57  
811              
812             $self->log ("Truncated and Warpped both set for this column: $col->{name}" )
813             if (exists $col->{truncated} and
814             exists $col->{wrapped} and
815             $col->{truncated} and
816             $col->{wrapped}
817 29 0 33     189 );
      33        
      33        
818              
819 29 50       76 $justify = '<' if defined $col->{truncated};
820 29 50       60 $justify = '[' if defined $col->{wrapped};
821              
822 29 100       60 if (defined $col->{'justify'}) {
823 10 100       46 if ($col->{'justify'} eq 'l') {
    100          
    50          
824             $justify =
825 2 50       9 (defined $col->{wrapped} ? '[' : '<');
826             } elsif ( $col->{'justify'} eq 'r' ) {
827             $justify =
828 5 50       13 (defined $col->{wrapped} ? ']' : '>');
829             } elsif ( $col->{'justify'} eq 'c' ) {
830             $justify =
831 3 50       8 (defined $col->{wrapped} ? '|' : '^');
832             } else {
833             $self->log( "unknown justify $col->{'justify'}" )
834 0 0       0 if $self->{debug};
835 0         0 $justify = '<';
836             }
837             }
838              
839             # warn "build format for column: " . $command . "\n";
840              
841 29 50       66 unless (defined $col->{'length'}) {
842 0         0 $col->{'length'} = length $command;
843             }
844              
845             # Allow for head and column format differences.
846 29         126 $col_head->{'format'} = $justify x $col->{'length'};
847 29         79 $col->{'format'} = $justify x $col->{'length'};
848              
849             # foreach my $col (sort keys %{$column_format->{$command}}) {
850             # next unless $column_format->{$command}->{$col};
851             # printf( "\t%-15s %s\n", $col, ($column_format->{$command}->{$col}||'undef') );
852             # }
853              
854             }
855              
856 29         580 return;
857             }
858              
859             sub column_usage {
860 0     0 0 0 my ($self, $error ) = @_;
861             return $self->print_buffer(
862             join( " ",
863             qq{usage column: },
864 0         0 (map { "$_ is $error->{$_}" } keys %$error ),
  0         0  
865             )
866             );
867             }
868              
869             sub _clear_format {
870 8     8   21 my ($self, $column_formats, $column) = @_;
871              
872             # warn "Removing format for : $column :\n";
873              
874 8 50       29 if (exists $$column_formats->{$column}) {
875             # Out of here!
876 8         55 delete $$column_formats->{$column};
877             # delete $$column_header_format->{$column};
878             } else {
879             # Can clear it, not defined.
880 0         0 $self->alert( "column clear $column: format not defined." );
881             }
882              
883             }
884              
885              
886             sub _determine_format {
887 27     27   98 my ($self, $format_requested, $mycol) = @_;
888              
889 27         52 my $col = ${$mycol};
  27         50  
890 27         50 my $numeric = ();
891              
892             # Determine what type of format?
893              
894 27 50       92 if ( $format_requested =~ m/a(\d+)/i ) { # Character
    0          
    0          
895 27         75 $col->{'length'} = $1;
896 27         51 $col->{'type'} = 'char';
897 27         54 $col->{'format_function'} = undef;
898             } elsif ( $format_requested =~ m/^date$/ ) { # Date
899 0         0 $col->{'length'} = 8;
900 0         0 $col->{'type'} = 'date';
901 0         0 $col->{'format_function'} = undef;
902             } elsif ( $format_requested =~ m/(\d+)/ ) { # Numeric 9's
903             # 999.99
904             # ^^^^^^^^^ ^^^^^
905             # PRECISION SCALE
906              
907 0         0 $col->{'format_function'} = undef;
908              
909 0         0 $col->{'type'} = 'numeric';
910              
911 0         0 my $len = $format_requested =~ tr /[0-9]/[0-9]/;
912 0         0 $len++ while($format_requested =~ m/[BSVG\.\$]|MI/ig);
913 0         0 $len += $format_requested =~ tr/,/,/;
914              
915             # Length is defined as total length of the formatted results.
916 0         0 $col->{'length'} = $len;
917              
918             # Determine precision and scale:
919 0         0 my ($p,$s) = (0,0);
920 0         0 my ($p1,$s1) = split(/\./, $format_requested);
921 0 0       0 $p = $p1 =~ tr /[0-9]/[0-9]/ if $p1;
922 0 0       0 $s = $s1 =~ tr /[0-9]/[0-9]/ if $s1;
923              
924             # warn "$format_requested/precision($p)/scale($s)/length($len)\n";
925              
926 0         0 $col->{'precision'} = $p;
927 0         0 $col->{'scale'} = $s;
928              
929             # default the commify to NO.
930 0         0 $col->{'commify'} = 0;
931              
932             # $ $9999
933 0 0       0 if ($format_requested =~ m/\$/) {
934             # warn "adding function dollarsign\n";
935 0         0 $col->{'format_function'} = \&dollarsign;
936             }
937              
938             # B B9999
939 0 0       0 $numeric->{B}++ if $format_requested =~ m/B/i;
940             # MI 9999MI
941 0 0       0 $numeric->{MI}++ if $format_requested =~ m/MI/i;
942             # S S9999
943 0 0       0 $numeric->{S}++ if $format_requested =~ m/S/i;
944             # PR 9999PR
945 0 0       0 $numeric->{PR}++ if $format_requested =~ m/PR/i;
946             # D 99D99
947 0 0       0 $numeric->{D}++ if $format_requested =~ m/D/i;
948             # G 9G999
949 0 0       0 $numeric->{G}++ if $format_requested =~ m/G/i;
950             # C C999
951 0 0       0 $numeric->{C}++ if $format_requested =~ m/C/i;
952             # L L999
953 0 0       0 $numeric->{L}++ if $format_requested =~ m/L/i;
954             # . (period) 99.99
955 0 0       0 $numeric->{period}++ if $format_requested =~ m/\./;
956             # V 999V99
957 0 0       0 $numeric->{V}++ if $format_requested =~ m/V/i;
958             # EEEE 9.999EEEE
959 0 0       0 $numeric->{EEEE}++ if $format_requested =~ m/EEEE/i;
960              
961             # , (comma) 9,999
962 0 0       0 if ($format_requested =~ m/\,/) {
963 0         0 $col->{'commify'} = 1;
964             }
965             } else {
966 0         0 return $self->column_usage( {format => "$format_requested invalid" });
967             }
968             # Save orignal format value.
969 27         52 $col->{'column_format'} = $format_requested;
970              
971             $self->log( "setting format ... $col->{'length'} $col->{'type'} ..." )
972 27 50       66 if $self->{debug};
973              
974 27         83 return;
975             }
976              
977             # Document from Oracle 9i SQL*Plus reference.
978             #
979             # FOR[MAT] format
980             #
981             # Specifies the display format of the column. The format specification
982             # must be a text constant such as A10 or $9,999--not a variable.
983             #
984             # Character Columns The default width of CHAR, NCHAR, VARCHAR2 (VARCHAR)
985             # and NVARCHAR2 (NCHAR VARYING) columns is the width of the column in
986             # the database. SQL*Plus formats these datatypes left-justified. If a
987             # value does not fit within the column width, SQL*Plus wraps or
988             # truncates the character string depending on the setting of SET WRAP.
989             #
990             # A LONG, CLOB or NCLOB column's width defaults to the value of SET
991             # LONGCHUNKSIZE or SET LONG, whichever one is smaller.
992             #
993             # To change the width of a datatype to n, use FORMAT An. (A stands for
994             # alphanumeric.) If you specify a width shorter than the column heading,
995             # SQL*Plus truncates the heading. If you specify a width for a LONG,
996             # CLOB, or NCLOB column, SQL*Plus uses the LONGCHUNKSIZE or the
997             # specified width, whichever is smaller, as the column width.
998             #
999             # DATE Columns The default width and format of unformatted DATE columns
1000             # in SQL*Plus is derived from the NLS parameters in effect. Otherwise,
1001             # the default width is A9. In Oracle9i, the NLS parameters may be set in
1002             # your database parameter file or may be environment variables or an
1003             # equivalent platform-specific mechanism. They may also be specified for
1004             # each session with the ALTER SESSION command. (See the documentation
1005             # for Oracle9i for a complete description of the NLS parameters).
1006             #
1007             # You can change the format of any DATE column using the SQL function
1008             # TO_CHAR in your SQL SELECT statement. You may also wish to use an
1009             # explicit COLUMN FORMAT command to adjust the column width.
1010             #
1011             # When you use SQL functions like TO_CHAR, Oracle automatically allows
1012             # for a very wide column.
1013             #
1014             # To change the width of a DATE column to n, use the COLUMN command with
1015             # FORMAT An. If you specify a width shorter than the column heading, the
1016             # heading is truncated.
1017             #
1018             # NUMBER Columns To change a NUMBER column's width, use FORMAT followed
1019             # by an element as specified in Table 8-1.
1020             #
1021             # Table 8-1 Number Formats
1022             # Element Examples Description
1023             # 9 9999
1024             #
1025             # Number of "9"s specifies number of significant digits returned.
1026             # Blanks are displayed for leading zeroes. A zero (0) is displayed for
1027             # a value of zero.
1028             #
1029             # 0 0999 9990
1030             #
1031             # Displays a leading zero or a value of zero in this position as 0.
1032             #
1033             # $ $9999
1034             #
1035             # Prefixes value with dollar sign.
1036             #
1037             # B B9999
1038             #
1039             # Displays a zero value as blank, regardless of "0"s in the format model.
1040             #
1041             # MI 9999MI
1042             #
1043             # Displays "-" after a negative value. For a positive value, a trailing space is displayed.
1044             #
1045             # S S9999
1046             #
1047             # Returns "+" for positive values and "-" for negative values in this position.
1048             #
1049             # PR 9999PR
1050             #
1051             # Displays a negative value in . For a positive value,
1052             # a leading and trailing space is displayed.
1053             #
1054             # D 99D99
1055             #
1056             # Displays the decimal character in this position, separating the
1057             # integral and fractional parts of a number.
1058             #
1059             # G 9G999
1060             #
1061             # Displays the group separator in this position.
1062             #
1063             # C C999
1064             #
1065             # Displays the ISO currency symbol in this position.
1066             #
1067             # L L999
1068             #
1069             # Displays the local currency symbol in this position.
1070             #
1071             # , (comma) 9,999
1072             #
1073             # Displays a comma in this position.
1074             #
1075             # . (period) 99.99
1076             #
1077             # Displays a period (decimal point) in this position, separating the
1078             # integral and fractional parts of a number.
1079             #
1080             # V 999V99
1081             #
1082             # Multiplies value by 10n, where n is number of "9"s after "V".
1083             #
1084             # EEEE 9.999EEEE
1085             #
1086             # Displays value in scientific notation (format must contain exactly four "E"s).
1087             #
1088             # RN or rn RN
1089             #
1090             # Displays upper- or lowercase Roman numerals. Value can be an integer between 1 and 3999.
1091             #
1092             # DATE DATE
1093             #
1094             # Displays value as a date in MM/DD/YY format; used to format NUMBER
1095             # columns that represent Julian dates.
1096             #
1097             #
1098             #
1099             # The MI and PR format elements can only appear in the last position of
1100             # a number format model. The S format element can only appear in the
1101             # first or last position.
1102             #
1103             # If a number format model does not contain the MI, S or PR format
1104             # elements, negative return values automatically contain a leading
1105             # negative sign and positive values automatically contain a
1106             # leading space.
1107             #
1108             # A number format model can contain only a single decimal character (D)
1109             # or period (.), but it can contain multiple group separators (G) or
1110             # commas (,). A group separator or comma cannot appear to the right of a
1111             # decimal character or period in a number format model.
1112             #
1113             # SQL*Plus formats NUMBER data right-justified. A NUMBER column's width
1114             # equals the width of the heading or the width of the FORMAT plus one
1115             # space for the sign, whichever is greater. If you do not explicitly use
1116             # FORMAT, then the column's width will always be at least the value of
1117             # SET NUMWIDTH.
1118             #
1119             # SQL*Plus may round your NUMBER data to fit your format or field width.
1120             #
1121             # If a value cannot fit within the column width, SQL*Plus indicates
1122             # overflow by displaying a pound sign (#) in place of each digit the
1123             # width allows.
1124             #
1125             # If a positive value is extremely large and a numeric overflow occurs
1126             # when rounding a number, then the infinity sign (~) replaces the value.
1127             # Likewise, if a negative value is extremely small and a numeric
1128             # overflow occurs when rounding a number, then the negative infinity
1129             # sign replaces the value (-~).
1130              
1131             # Commify used from the Perl CookBook
1132             sub commify($) {
1133 0     0 0 0 my $num = reverse $_[0];
1134 0         0 $num =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
1135 0         0 return scalar reverse $num;
1136             }
1137              
1138             sub dollarsign($$$$) {
1139 0     0 0 0 my ($num, $fmtnum, $dlen, $commify) = @_;
1140 0         0 my $formatted = sprintf "\$%${fmtnum}.${dlen}lf", $num;
1141 0 0       0 return ($commify ? commify($formatted) : $formatted);
1142             }
1143              
1144             sub zerofill($$$$) {
1145 0     0 0 0 my ($num, $fmtnum, $dlen, $commify) = @_;
1146 0         0 my $formatted = sprintf "%0${fmtnum}.${dlen}lf", $num;
1147 0 0       0 return ($commify ? commify($formatted) : $formatted);
1148             }
1149              
1150             sub signednum($$$$) {
1151 0     0 0 0 my ($num, $fmtnum, $dlen, $commify) = @_;
1152 0         0 my $formatted = sprintf "%+${fmtnum}.${dlen}lf", $num;
1153 0 0       0 return ($commify ? commify($formatted) : $formatted);
1154             }
1155              
1156             sub leadsign($$$$) {
1157 0     0 0 0 my ($num, $fmtnum, $dlen, $commify) = @_;
1158 0         0 my $formatted = sprintf "%+${fmtnum}.${dlen}lf", $num;
1159 0 0       0 return ($commify ? commify($formatted) : $formatted);
1160             }
1161              
1162             sub trailsign($$$$) {
1163 0     0 0 0 my ($num, $fmtnum, $dlen, $commify) = @_;
1164 0         0 $dlen--;
1165 0         0 my $formatted = sprintf "%${fmtnum}.${dlen}lf", abs($num);
1166 0 0       0 $formatted .= ($num > 0 ? '+' : '-');
1167 0 0       0 return ($commify ? commify($formatted) : $formatted);
1168             }
1169              
1170             sub ltgtsign($$$$) {
1171 0     0 0 0 my ($num, $fmtnum, $dlen, $commify) = @_;
1172 0         0 $dlen--;
1173 0 0       0 my $formatted = sprintf "%s%${fmtnum}.${dlen}lf%s"
    0          
1174             ,($num > 0 ? '' : '<')
1175             ,abs($num),
1176             ,($num > 0 ? '' : '>');
1177 0 0       0 return ($commify ? commify($formatted) : $formatted);
1178             }
1179              
1180             #
1181             # Private methods.
1182             #
1183              
1184             sub _me {
1185 0     0   0 my $pi = shift;
1186 0         0 my $self = shift;
1187 0 0       0 return ${$self}->print_buffer("show me what???")
  0         0  
1188             unless @_;
1189 0         0 return ${$self}->do_show(@_);
  0         0  
1190             }
1191              
1192             sub _all {
1193 0     0   0 my $pi = shift;
1194 0         0 my $self = shift;
1195 0 0       0 return ${$self}->print_buffer("show all of what???")
  0         0  
1196             unless @_;
1197 0         0 return ${$self}->do_show(@_);
  0         0  
1198             }
1199              
1200             sub _show_all_commands {
1201 0     0   0 my $pi = shift;
1202 0         0 my $self = shift;
1203             return
1204 0         0 ${$self}->print_buffer("Show supports the following commands:\n\t" .
1205 0         0 join( "\n\t", keys %{$pi->{show}}));
  0         0  
1206             }
1207              
1208             sub _unimp {
1209 0     0   0 my $pi = shift;
1210 0         0 my $self = shift;
1211 0         0 return ${$self}->print_buffer("unimplemented");
  0         0  
1212             }
1213              
1214             sub _obsolete {
1215 0     0   0 my $pi = shift;
1216 0         0 my $self = shift;
1217 0         0 return ${$self}->print_buffer("obsolete: use " . join( " ", @_) );
  0         0  
1218             }
1219              
1220             sub _print_buffer {
1221 0     0   0 my $pi = shift;
1222 0         0 my $self = shift;
1223 0         0 return ${$self}->print_buffer(@_);
  0         0  
1224             }
1225              
1226             sub _set_get {
1227 24     24   48 my $pi = shift;
1228 24         40 my $self = shift;
1229 24         35 my $command = shift;
1230              
1231 24 50 0     59 carp "command undefined: " and return unless defined $command;
1232              
1233             # Use the off to undefine/null a value.
1234 24 100       55 if (@_) {
1235 21         35 my $val = shift;
1236 21 100       84 if ($val =~ m/off/i) {
1237 6         16 $pi->{set_current}->{$command} = undef;
1238             } else {
1239 15         39 $pi->{set_current}->{$command} = $val
1240             }
1241              
1242             }
1243 24         180 ${$self}->print_buffer(
1244 24   100     38 qq{$command: } . ($pi->{set_current}->{$command}||
1245             'null')
1246             );
1247 24         1224 return $pi->{set_current}->{$command};
1248             }
1249              
1250             #------------------------------------------------------------------
1251             #
1252             # Display a list of all schemas.
1253             #
1254             #------------------------------------------------------------------
1255             sub _schemas {
1256 0     0   0 my ($pi, $sh, @args) = @_;
1257             #
1258             # Allow types to accept a list of types to display.
1259             #
1260 0         0 my $sth;
1261              
1262 0         0 my $dbh = ${$sh}->{dbh};
  0         0  
1263 0         0 $sth = $dbh->table_info('', '%', '', '');
1264              
1265 0 0       0 unless(ref $sth) {
1266 0         0 ${$sh}->log( "Advance table_info not supported\n");
  0         0  
1267 0         0 return;
1268             }
1269 0         0 return ${$sh}->sth_go($sth, 0, 0);
  0         0  
1270             }
1271              
1272             #------------------------------------------------------------------
1273             #
1274             # Display the last sql code, error, and error string.
1275             #
1276             #------------------------------------------------------------------
1277             sub _sqlcode {
1278 1     1   3 my ($pi, $sh, @args) = @_;
1279              
1280 1         3 my $dbh = ${$sh}->{dbh};
  1         2  
1281              
1282 1         2 my $codes;
1283            
1284 1 50       18 $codes .= "last dbi error : " . $dbh->err . "\n" if $dbh->err;
1285 1 50       15 $codes .= "last dbi error string : " . $dbh->errstr . "\n" if $dbh->err;
1286 1 50       13 $codes .= "last dbi error state : " . $dbh->state . "\n" if $dbh->err;
1287              
1288 1 50       3 ${$sh}->print_buffer_nop( $codes ) if defined $codes;
  1         5  
1289              
1290 1   50     33 return $dbh->err||0;
1291             }
1292              
1293             #------------------------------------------------------------------
1294             #
1295             # Display a list of all tables.
1296             #
1297             #------------------------------------------------------------------
1298             sub _tables {
1299 0     0     my ($pi, $sh, @args) = @_;
1300 0           return $pi->_sup_types( $sh, 'TABLE', @args );
1301             }
1302              
1303             #------------------------------------------------------------------
1304             #
1305             # Display a list of all types.
1306             #
1307             #------------------------------------------------------------------
1308             sub _types {
1309 0     0     my ($pi, $sh, @args) = @_;
1310             #
1311             # Allow types to accept a list of types to display.
1312             #
1313 0           my $sth;
1314 0 0         if (@args) {
1315 0           return $pi->_sup_types( $sh, @args );
1316             }
1317              
1318 0           my $dbh = ${$sh}->{dbh};
  0            
1319 0           $sth = $dbh->table_info('', '', '', '%');
1320              
1321 0 0         unless(ref $sth) {
1322 0           ${$sh}->log( "Advance table_info not supported\n" );
  0            
1323 0           return;
1324             }
1325 0           return ${$sh}->sth_go($sth, 0, 0);
  0            
1326             }
1327              
1328             #------------------------------------------------------------------
1329             #
1330             # Display a list of all views.
1331             #
1332             #------------------------------------------------------------------
1333             sub _views {
1334 0     0     my ($pi, $sh, @args) = @_;
1335              
1336 0           return $pi->_sup_types( $sh, 'VIEW', @args );
1337             }
1338              
1339             #------------------------------------------------------------------
1340             #
1341             # Handle different types.
1342             #
1343             #------------------------------------------------------------------
1344             sub _sup_types {
1345 0     0     my ($pi, $sh, $type, @args) = @_;
1346              
1347 0           $sh = ${$sh}; # Need to dereference the shell object.
  0            
1348              
1349 0           my $dbh = $sh->{dbh};
1350              
1351 0 0         return unless (defined $type);
1352              
1353 0           my $sth;
1354 0 0         if (@args) {
1355 0           my $tbl = join( ",", @args );
1356 0           $sth = $dbh->table_info(undef, undef, $tbl, $type);
1357             } else {
1358 0           $sth = $dbh->table_info(undef, undef, undef, $type);
1359             }
1360              
1361 0 0         unless (ref $sth) {
1362 0           ${$sh}->log( "Advance table_info not supported\n" );
  0            
1363 0           return;
1364             }
1365              
1366 0           return $sh->sth_go($sth, 0, 0);
1367             }
1368              
1369             1;
1370              
1371