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