line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package DBI::Shell; |
2
|
|
|
|
|
|
|
# vim:ts=4:sw=4:ai:aw:nowrapscan |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
=head1 NAME |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
DBI::Shell - Interactive command shell for the DBI |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 SYNOPSIS |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
perl -MDBI::Shell -e shell [ [ []]] |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
or |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
dbish [ [ []]] |
15
|
|
|
|
|
|
|
dbish --debug [ [ []]] |
16
|
|
|
|
|
|
|
dbish --batch [ [ []]] < batch file |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 DESCRIPTION |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
The DBI::Shell module (and dbish command, if installed) provide a |
21
|
|
|
|
|
|
|
simple but effective command line interface for the Perl L module. |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=cut |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
### |
26
|
|
|
|
|
|
|
### See TO DO section in the docs at the end. |
27
|
|
|
|
|
|
|
### |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
30
|
7
|
|
|
7
|
|
557802
|
BEGIN { require 5.004 } |
31
|
7
|
|
|
7
|
|
216
|
BEGIN { $^W = 1 } |
32
|
|
|
|
|
|
|
|
33
|
7
|
|
|
7
|
|
39
|
use strict; |
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
199
|
|
34
|
7
|
|
|
7
|
|
41
|
use vars qw(@ISA @EXPORT $VERSION $SHELL); |
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
497
|
|
35
|
7
|
|
|
7
|
|
77
|
use Exporter (); |
|
7
|
|
|
|
|
20
|
|
|
7
|
|
|
|
|
162
|
|
36
|
7
|
|
|
7
|
|
45
|
use Carp; |
|
7
|
|
|
|
|
13
|
|
|
7
|
|
|
|
|
3070
|
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
@ISA = qw(Exporter DBI::Shell::Std); |
39
|
|
|
|
|
|
|
@EXPORT = qw(shell); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
our $VERSION = '11.96_03'; # TRIAL VERSION |
42
|
|
|
|
|
|
|
$VERSION = eval $VERSION; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub new { |
45
|
5
|
|
|
5
|
0
|
2929
|
my $class = shift; |
46
|
5
|
50
|
|
|
|
81
|
my @args = @_ ? @_ : @ARGV; |
47
|
|
|
|
|
|
|
#my $sh = bless {}, $class; |
48
|
5
|
|
|
|
|
66
|
my $sh = $class->SUPER::new(@args); |
49
|
|
|
|
|
|
|
# Load configuration files, system and user. The user configuration may |
50
|
|
|
|
|
|
|
# over ride the system configuration. |
51
|
5
|
|
|
|
|
43
|
my $myconfig = $sh->configuration; |
52
|
|
|
|
|
|
|
# Save the configuration file for this instance. |
53
|
5
|
|
|
|
|
15
|
$sh->{myconfig} = $myconfig; |
54
|
|
|
|
|
|
|
# Pre-init plugins. |
55
|
5
|
|
|
|
|
61
|
$sh->load_plugins($myconfig->{'plug-ins'}->{'pre-init'}); |
56
|
|
|
|
|
|
|
# Post-init plugins. |
57
|
|
|
|
|
|
|
#$sh->SUPER::init(@args); |
58
|
5
|
|
|
|
|
26
|
$sh->load_plugins($myconfig->{'plug-ins'}->{'post-init'}); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# do_format is already run in DBI::Shell::Base::new, but that is |
61
|
|
|
|
|
|
|
# before the user config is loaded so we need to run it again if |
62
|
|
|
|
|
|
|
# the user overrides the format. |
63
|
5
|
|
|
|
|
42
|
$sh->do_format($sh->{format}); |
64
|
5
|
|
|
|
|
24
|
return $sh; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub shell { |
68
|
0
|
0
|
|
0
|
0
|
0
|
my @args = @_ ? @_ : @ARGV; |
69
|
0
|
|
|
|
|
0
|
$SHELL = DBI::Shell::Std->new(@args); |
70
|
0
|
|
|
|
|
0
|
$SHELL->load_plugins; |
71
|
0
|
|
|
|
|
0
|
$SHELL->run; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub run { |
75
|
0
|
|
|
0
|
1
|
0
|
my $sh = shift; |
76
|
0
|
|
|
|
|
0
|
die "Unrecognised options: @{$sh->{unhandled_options}}\n" |
77
|
0
|
0
|
|
|
|
0
|
if @{$sh->{unhandled_options}}; |
|
0
|
|
|
|
|
0
|
|
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# Use valid "dbi:driver:..." to connect with source. |
80
|
0
|
|
|
|
|
0
|
$sh->do_connect( $sh->{data_source} ); |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# |
83
|
|
|
|
|
|
|
# Main loop |
84
|
|
|
|
|
|
|
# |
85
|
0
|
|
|
|
|
0
|
$sh->{abbrev} = undef; |
86
|
0
|
|
|
|
|
0
|
$sh->{abbrev} = Text::Abbrev::abbrev(keys %{$sh->{commands}}); |
|
0
|
|
|
|
|
0
|
|
87
|
|
|
|
|
|
|
# unless $sh->{batch}; |
88
|
0
|
|
|
|
|
0
|
$sh->{current_buffer} = ''; |
89
|
0
|
|
|
|
|
0
|
$sh->SUPER::run; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# ------------------------------------------------------------- |
95
|
|
|
|
|
|
|
package DBI::Shell::Std; |
96
|
|
|
|
|
|
|
|
97
|
7
|
|
|
7
|
|
54
|
use vars qw(@ISA); |
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
1503
|
|
98
|
|
|
|
|
|
|
@ISA = qw(DBI::Shell::Base); |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# XXX this package might be used to override commands etc. |
101
|
|
|
|
|
|
|
sub do_connect { |
102
|
9
|
|
|
9
|
|
3314
|
my $sh = shift; |
103
|
|
|
|
|
|
|
$sh->load_plugins($sh->{myconfig}->{'plug-ins'}->{'pre-connect'}) |
104
|
9
|
100
|
|
|
|
70
|
if exists $sh->{myconfig}->{'plug-ins'}->{'pre-connect'}; |
105
|
9
|
|
|
|
|
62
|
$sh->SUPER::do_connect(@_); |
106
|
|
|
|
|
|
|
$sh->load_plugins($sh->{myconfig}->{'plug-ins'}->{'post-connect'}) |
107
|
9
|
100
|
|
|
|
45
|
if exists $sh->{myconfig}->{'plug-ins'}->{'post-connect'}; |
108
|
9
|
|
|
|
|
56
|
return; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub init { |
112
|
0
|
|
|
0
|
|
0
|
my $sh = shift; |
113
|
0
|
|
|
|
|
0
|
return; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# ------------------------------------------------------------- |
118
|
|
|
|
|
|
|
package DBI::Shell::Base; |
119
|
|
|
|
|
|
|
|
120
|
7
|
|
|
7
|
|
60
|
use Carp; |
|
7
|
|
|
|
|
22
|
|
|
7
|
|
|
|
|
418
|
|
121
|
7
|
|
|
7
|
|
5574
|
use Text::Abbrev (); |
|
7
|
|
|
|
|
353
|
|
|
7
|
|
|
|
|
184
|
|
122
|
7
|
|
|
7
|
|
3544
|
use Term::ReadLine; |
|
7
|
|
|
|
|
19462
|
|
|
7
|
|
|
|
|
290
|
|
123
|
7
|
|
|
7
|
|
49
|
use Getopt::Long 2.17; # upgrade from CPAN if needed: http://www.perl.com/CPAN |
|
7
|
|
|
|
|
76
|
|
|
7
|
|
|
|
|
241
|
|
124
|
7
|
|
|
7
|
|
4194
|
use IO::File; |
|
7
|
|
|
|
|
53449
|
|
|
7
|
|
|
|
|
829
|
|
125
|
7
|
|
|
7
|
|
61
|
use File::Spec (); |
|
7
|
|
|
|
|
14
|
|
|
7
|
|
|
|
|
121
|
|
126
|
7
|
|
|
7
|
|
3881
|
use File::HomeDir (); |
|
7
|
|
|
|
|
40071
|
|
|
7
|
|
|
|
|
269
|
|
127
|
|
|
|
|
|
|
|
128
|
7
|
|
|
7
|
|
11437
|
use DBI 1.00 qw(:sql_types :utils); |
|
7
|
|
|
|
|
132605
|
|
|
7
|
|
|
|
|
3260
|
|
129
|
7
|
|
|
7
|
|
4111
|
use DBI::Format; |
|
7
|
|
|
|
|
20
|
|
|
7
|
|
|
|
|
264
|
|
130
|
|
|
|
|
|
|
|
131
|
7
|
|
|
7
|
|
3241
|
use DBI::Shell::FindSqlFile; |
|
7
|
|
|
|
|
16
|
|
|
7
|
|
|
|
|
299
|
|
132
|
7
|
|
|
7
|
|
3543
|
use IO::Interactive qw/ is_interactive /; |
|
7
|
|
|
|
|
6584
|
|
|
7
|
|
|
|
|
52
|
|
133
|
|
|
|
|
|
|
|
134
|
7
|
|
|
7
|
|
363
|
use vars qw(@ISA); |
|
7
|
|
|
|
|
15
|
|
|
7
|
|
|
|
|
357
|
|
135
|
|
|
|
|
|
|
@ISA = qw(DBI::Shell::FindSqlFile); |
136
|
|
|
|
|
|
|
|
137
|
7
|
|
|
7
|
|
43
|
use constant ADD_RH => 1; # Add the results, to rhistory. |
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
514
|
|
138
|
7
|
|
|
7
|
|
46
|
use constant NO_RH => 0; # Do not add results, to rhistory. |
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
346
|
|
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# History saving is also provided by DBI::Shell::Completion. |
141
|
7
|
|
|
7
|
|
85
|
use constant HISTORY_FILE => '.dbish-builtin-history'; |
|
7
|
|
|
|
|
16
|
|
|
7
|
|
|
|
|
68913
|
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
my $haveTermReadKey; |
144
|
|
|
|
|
|
|
my $term; |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub usage { |
148
|
0
|
|
|
0
|
|
0
|
warn <
|
149
|
|
|
|
|
|
|
Usage: perl -MDBI::Shell -e shell [ [ []]] |
150
|
|
|
|
|
|
|
USAGE |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub log { |
154
|
168
|
|
|
168
|
|
321
|
my $sh = shift; |
155
|
168
|
50
|
|
|
|
4996
|
return ($sh->{batch}) ? warn @_,"\n" : $sh->print_buffer_nop(@_,"\n"); # XXX maybe |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
sub alert { # XXX not quite sure how alert and err relate |
159
|
|
|
|
|
|
|
# for msgs that would pop-up an alert dialog if this was a Tk app |
160
|
0
|
|
|
0
|
|
0
|
my $sh = shift; |
161
|
0
|
|
|
|
|
0
|
return warn @_,"\n"; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub err { # XXX not quite sure how alert and err relate |
165
|
0
|
|
|
0
|
|
0
|
my ($sh, $msg, $die) = @_; |
166
|
0
|
|
|
|
|
0
|
$msg = "DBI::Shell: $msg\n"; |
167
|
0
|
0
|
|
|
|
0
|
die $msg if $die; |
168
|
0
|
|
|
|
|
0
|
return $sh->alert($msg); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub add_option { |
174
|
222
|
|
|
222
|
|
364
|
my ($sh, $opt, $default) = @_; |
175
|
222
|
|
|
|
|
640
|
(my $opt_name = $opt) =~ s/[|=].*//; |
176
|
|
|
|
|
|
|
croak "Can't add_option '$opt_name', already defined" |
177
|
222
|
100
|
|
|
|
4509
|
if exists $sh->{$opt_name}; |
178
|
202
|
|
|
|
|
381
|
$sh->{options}->{$opt_name} = $opt; |
179
|
202
|
|
|
|
|
404
|
$sh->{$opt_name} = $default; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub load_plugins { |
183
|
22
|
|
|
22
|
|
63
|
my ($sh, @ppi) = @_; |
184
|
|
|
|
|
|
|
# Output must not appear while loading plugins: |
185
|
|
|
|
|
|
|
# It might happen, that batch mode is entered |
186
|
|
|
|
|
|
|
# later! |
187
|
22
|
|
|
|
|
35
|
my @pi; |
188
|
22
|
50
|
|
|
|
57
|
return unless(@ppi); |
189
|
22
|
|
|
|
|
69
|
foreach my $n (0 .. $#ppi) { |
190
|
22
|
100
|
|
|
|
66
|
next unless ($ppi[$n]); |
191
|
12
|
|
|
|
|
26
|
my $pi = $ppi[$n]; |
192
|
|
|
|
|
|
|
|
193
|
12
|
100
|
|
|
|
56
|
if ( ref $pi eq 'HASH' ) { |
|
|
50
|
|
|
|
|
|
194
|
|
|
|
|
|
|
# As we descend down the hash reference, |
195
|
|
|
|
|
|
|
# we're looking for an array of modules to source in. |
196
|
4
|
|
|
|
|
18
|
my @mpi = keys %$pi; |
197
|
4
|
|
|
|
|
15
|
foreach my $opt (@mpi) { |
198
|
|
|
|
|
|
|
#print "Working with $opt\n"; |
199
|
12
|
100
|
|
|
|
98
|
if ($opt =~ /^option/i) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# Call the option handling. |
201
|
4
|
|
|
|
|
11
|
$sh->install_options( @{$pi->{$opt}} ); |
|
4
|
|
|
|
|
53
|
|
202
|
4
|
|
|
|
|
13
|
next; |
203
|
|
|
|
|
|
|
} elsif ( $opt =~ /^database/i ) { |
204
|
|
|
|
|
|
|
# Handle plugs for a named # type of database. |
205
|
4
|
50
|
|
|
|
19
|
next unless $sh->{dbh}; |
206
|
|
|
|
|
|
|
# Determine what type of database connection. |
207
|
4
|
|
|
|
|
56
|
my $db = $sh->{dbh}->{Driver}->{Name}; |
208
|
|
|
|
|
|
|
$sh->load_plugins( $pi->{$opt}->{$db} ) |
209
|
4
|
50
|
|
|
|
108
|
if (exists $pi->{$opt}->{$db}); |
210
|
4
|
|
|
|
|
11
|
next; |
211
|
|
|
|
|
|
|
} elsif ( $opt =~ /^non-database/i ) { |
212
|
4
|
|
|
|
|
29
|
$sh->load_plugins( $pi->{$opt} ); |
213
|
|
|
|
|
|
|
} else { |
214
|
0
|
|
|
|
|
0
|
$sh->load_plugins( $pi->{$opt} ); |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
} elsif ( ref $pi eq 'ARRAY' ) { |
218
|
8
|
|
|
|
|
24
|
@pi = @$pi; |
219
|
|
|
|
|
|
|
} else { |
220
|
0
|
0
|
|
|
|
0
|
next unless $pi; |
221
|
0
|
|
|
|
|
0
|
push(@pi, $pi); |
222
|
|
|
|
|
|
|
} |
223
|
12
|
|
|
|
|
31
|
foreach my $pi (@pi) { |
224
|
16
|
|
|
|
|
33
|
my $mod = $pi; |
225
|
16
|
|
|
|
|
42
|
$mod =~ s/\.pm$//; |
226
|
|
|
|
|
|
|
#print "Module: $mod\n"; |
227
|
16
|
|
|
|
|
535
|
unshift @DBI::Shell::Std::ISA, $mod; |
228
|
16
|
|
|
4
|
|
1310
|
eval qq{ use $pi }; |
|
4
|
|
|
4
|
|
2332
|
|
|
4
|
|
|
4
|
|
14
|
|
|
4
|
|
|
4
|
|
93
|
|
|
4
|
|
|
|
|
2401
|
|
|
4
|
|
|
|
|
13
|
|
|
4
|
|
|
|
|
80
|
|
|
4
|
|
|
|
|
2156
|
|
|
4
|
|
|
|
|
14
|
|
|
4
|
|
|
|
|
85
|
|
|
4
|
|
|
|
|
2745
|
|
|
4
|
|
|
|
|
15
|
|
|
4
|
|
|
|
|
102
|
|
229
|
16
|
50
|
|
|
|
74
|
if ($@) { |
230
|
0
|
|
|
|
|
0
|
warn "Failed: $@"; |
231
|
0
|
|
|
|
|
0
|
shift @DBI::Shell::Std::ISA; |
232
|
0
|
|
|
|
|
0
|
shift @pi; |
233
|
|
|
|
|
|
|
} else { |
234
|
|
|
|
|
|
|
$sh->print_buffer_nop("Loaded plugins $mod\n") |
235
|
16
|
50
|
|
|
|
96
|
unless $sh->{batch}; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
} |
239
|
22
|
|
|
|
|
129
|
local ($|) = 1; |
240
|
|
|
|
|
|
|
# plug-ins should remove options they recognise from (localized) @ARGV |
241
|
|
|
|
|
|
|
# by calling Getopt::Long::GetOptions (which is already in pass_through mode). |
242
|
22
|
|
|
|
|
54
|
foreach my $pi (@pi) { |
243
|
16
|
|
|
|
|
53
|
local *ARGV = $sh->{unhandled_options}; |
244
|
16
|
|
|
|
|
80
|
$pi->init($sh); |
245
|
|
|
|
|
|
|
} |
246
|
22
|
|
|
|
|
93
|
return @pi; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub default_config { |
250
|
7
|
|
|
7
|
|
16
|
my $sh = shift; |
251
|
|
|
|
|
|
|
# |
252
|
|
|
|
|
|
|
# Set default configuration options |
253
|
|
|
|
|
|
|
# |
254
|
7
|
|
50
|
|
|
277
|
foreach my $opt_ref ( |
|
|
|
50
|
|
|
|
|
|
|
|
33
|
|
|
|
|
255
|
|
|
|
|
|
|
[ 'command_prefix_line=s' => '/' ], |
256
|
|
|
|
|
|
|
[ 'command_prefix_end=s' => ';' ], |
257
|
|
|
|
|
|
|
[ 'command_prefix=s' => '[/;]' ], |
258
|
|
|
|
|
|
|
[ 'chistory_size=i' => 50 ], |
259
|
|
|
|
|
|
|
[ 'rhistory_size=i' => 50 ], |
260
|
|
|
|
|
|
|
[ 'rhistory_head=i' => 5 ], |
261
|
|
|
|
|
|
|
[ 'rhistory_tail=i' => 5 ], |
262
|
|
|
|
|
|
|
[ 'user_level=i' => 1 ], |
263
|
|
|
|
|
|
|
[ 'editor|ed=s' => ($ENV{VISUAL} || $ENV{EDITOR} || 'vi') ], |
264
|
|
|
|
|
|
|
[ 'batch' => 0 ], |
265
|
|
|
|
|
|
|
[ 'format=s' => 'neat' ], |
266
|
|
|
|
|
|
|
[ 'prompt=s' => undef ], |
267
|
|
|
|
|
|
|
# defaults for each new database connect: |
268
|
|
|
|
|
|
|
[ 'init_trace|trace=i' => 0 ], |
269
|
|
|
|
|
|
|
[ 'init_autocommit|autocommit=i' => 1 ], |
270
|
|
|
|
|
|
|
[ 'debug|d=i' => ($ENV{DBISH_DEBUG} || 0) ], |
271
|
|
|
|
|
|
|
[ 'seperator|sep=s' => ',' ], |
272
|
|
|
|
|
|
|
[ 'sqlpath|sql=s' => '.' ], |
273
|
|
|
|
|
|
|
[ 'tmp_dir|tmp_d=s' => $ENV{DBISH_TMP} ], |
274
|
|
|
|
|
|
|
[ 'tmp_file|tmp_f=s' => qq{dbish$$.sql} ], |
275
|
|
|
|
|
|
|
[ 'home_dir|home_d=s' => $ENV{HOME} || "$ENV{HOMEDRIVE}$ENV{HOMEPATH}" ], |
276
|
|
|
|
|
|
|
[ 'desc_show_remarks|show_remarks' => 1 ], |
277
|
|
|
|
|
|
|
[ 'desc_show_long|show_long' => 1 ], |
278
|
|
|
|
|
|
|
[ 'desc_format=s' => q{partbox} ], |
279
|
|
|
|
|
|
|
[ 'desc_show_columns=s' => q{COLUMN_NAME,DATA_TYPE,TYPE_NAME,COLUMN_SIZE,PK,NULLABLE,COLUMN_DEF,IS_NULLABLE,REMARKS} ], |
280
|
|
|
|
|
|
|
[ 'null_format=s' => '(NULL)' ], |
281
|
|
|
|
|
|
|
[ 'bool_format=s' => q{Y,N} ], |
282
|
|
|
|
|
|
|
@_, |
283
|
|
|
|
|
|
|
) { |
284
|
182
|
|
|
|
|
338
|
$sh->add_option(@$opt_ref); |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
sub default_commands { |
291
|
7
|
|
|
7
|
|
30
|
my $sh = shift; |
292
|
|
|
|
|
|
|
# |
293
|
|
|
|
|
|
|
# Install default commands |
294
|
|
|
|
|
|
|
# |
295
|
|
|
|
|
|
|
# The sub is passed a reference to the shell and the @ARGV-style |
296
|
|
|
|
|
|
|
# args it was invoked with. |
297
|
|
|
|
|
|
|
# |
298
|
|
|
|
|
|
|
$sh->{commands} = { |
299
|
7
|
|
|
|
|
270
|
'help' => { |
300
|
|
|
|
|
|
|
hint => "display this list of commands", |
301
|
|
|
|
|
|
|
}, |
302
|
|
|
|
|
|
|
'quit' => { |
303
|
|
|
|
|
|
|
hint => "exit", |
304
|
|
|
|
|
|
|
}, |
305
|
|
|
|
|
|
|
'exit' => { |
306
|
|
|
|
|
|
|
hint => "exit", |
307
|
|
|
|
|
|
|
}, |
308
|
|
|
|
|
|
|
'trace' => { |
309
|
|
|
|
|
|
|
hint => "set DBI trace level for current database", |
310
|
|
|
|
|
|
|
}, |
311
|
|
|
|
|
|
|
'connect' => { |
312
|
|
|
|
|
|
|
hint => "connect to another data source/DSN", |
313
|
|
|
|
|
|
|
}, |
314
|
|
|
|
|
|
|
'prompt' => { |
315
|
|
|
|
|
|
|
hint => "change the displayed prompt", |
316
|
|
|
|
|
|
|
}, |
317
|
|
|
|
|
|
|
# --- execute commands |
318
|
|
|
|
|
|
|
'go' => { |
319
|
|
|
|
|
|
|
hint => "execute the current statement", |
320
|
|
|
|
|
|
|
}, |
321
|
|
|
|
|
|
|
'count' => { |
322
|
|
|
|
|
|
|
hint => "execute 'select count(*) from table' (on each table listed).", |
323
|
|
|
|
|
|
|
}, |
324
|
|
|
|
|
|
|
'do' => { |
325
|
|
|
|
|
|
|
hint => "execute the current (non-select) statement", |
326
|
|
|
|
|
|
|
}, |
327
|
|
|
|
|
|
|
'perl' => { |
328
|
|
|
|
|
|
|
hint => "evaluate the current statement as perl code", |
329
|
|
|
|
|
|
|
}, |
330
|
|
|
|
|
|
|
'ping' => { |
331
|
|
|
|
|
|
|
hint => "ping the current connection", |
332
|
|
|
|
|
|
|
}, |
333
|
|
|
|
|
|
|
'commit' => { |
334
|
|
|
|
|
|
|
hint => "commit changes to the database", |
335
|
|
|
|
|
|
|
}, |
336
|
|
|
|
|
|
|
'rollback' => { |
337
|
|
|
|
|
|
|
hint => "rollback changes to the database", |
338
|
|
|
|
|
|
|
}, |
339
|
|
|
|
|
|
|
# --- information commands |
340
|
|
|
|
|
|
|
'primary_key_info' => { |
341
|
|
|
|
|
|
|
hint => "display primary keys that exist in current database", |
342
|
|
|
|
|
|
|
}, |
343
|
|
|
|
|
|
|
'col_info' => { |
344
|
|
|
|
|
|
|
hint => "display columns that exist in current database", |
345
|
|
|
|
|
|
|
}, |
346
|
|
|
|
|
|
|
'table_info' => { |
347
|
|
|
|
|
|
|
hint => "display tables that exist in current database", |
348
|
|
|
|
|
|
|
}, |
349
|
|
|
|
|
|
|
'type_info' => { |
350
|
|
|
|
|
|
|
hint => "display data types supported by current server", |
351
|
|
|
|
|
|
|
}, |
352
|
|
|
|
|
|
|
'drivers' => { |
353
|
|
|
|
|
|
|
hint => "display available DBI drivers", |
354
|
|
|
|
|
|
|
}, |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
# --- statement/history management commands |
357
|
|
|
|
|
|
|
'clear' => { |
358
|
|
|
|
|
|
|
hint => "erase the current statement", |
359
|
|
|
|
|
|
|
}, |
360
|
|
|
|
|
|
|
'redo' => { |
361
|
|
|
|
|
|
|
hint => "re-execute the previously executed statement", |
362
|
|
|
|
|
|
|
}, |
363
|
|
|
|
|
|
|
'get' => { |
364
|
|
|
|
|
|
|
hint => "make a previous statement current again", |
365
|
|
|
|
|
|
|
}, |
366
|
|
|
|
|
|
|
'current' => { |
367
|
|
|
|
|
|
|
hint => "display current statement", |
368
|
|
|
|
|
|
|
}, |
369
|
|
|
|
|
|
|
'edit' => { |
370
|
|
|
|
|
|
|
hint => "edit current statement in an external editor", |
371
|
|
|
|
|
|
|
}, |
372
|
|
|
|
|
|
|
'chistory' => { |
373
|
|
|
|
|
|
|
hint => "display command history", |
374
|
|
|
|
|
|
|
}, |
375
|
|
|
|
|
|
|
'rhistory' => { |
376
|
|
|
|
|
|
|
hint => "display result history", |
377
|
|
|
|
|
|
|
}, |
378
|
|
|
|
|
|
|
'format' => { |
379
|
|
|
|
|
|
|
hint => "set display format for selected data (Neat|Box)", |
380
|
|
|
|
|
|
|
}, |
381
|
|
|
|
|
|
|
'history' => { |
382
|
|
|
|
|
|
|
hint => "display combined command and result history", |
383
|
|
|
|
|
|
|
}, |
384
|
|
|
|
|
|
|
'option' => { |
385
|
|
|
|
|
|
|
hint => "display or set an option value", |
386
|
|
|
|
|
|
|
}, |
387
|
|
|
|
|
|
|
'describe' => { |
388
|
|
|
|
|
|
|
hint => "display information about a table (columns, data types).", |
389
|
|
|
|
|
|
|
}, |
390
|
|
|
|
|
|
|
'load' => { |
391
|
|
|
|
|
|
|
hint => "load a file from disk to the current buffer.", |
392
|
|
|
|
|
|
|
}, |
393
|
|
|
|
|
|
|
'run' => { |
394
|
|
|
|
|
|
|
hint => "load a file from disk to current buffer, then executes.", |
395
|
|
|
|
|
|
|
}, |
396
|
|
|
|
|
|
|
'save' => { |
397
|
|
|
|
|
|
|
hint => "save the current buffer to a disk file.", |
398
|
|
|
|
|
|
|
}, |
399
|
|
|
|
|
|
|
'spool' => { |
400
|
|
|
|
|
|
|
hint => "send all output to a disk file. usage: spool file name or spool off.", |
401
|
|
|
|
|
|
|
}, |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
}; |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
sub default_term { |
408
|
7
|
|
|
7
|
|
21
|
my ($sh, $class) = @_; |
409
|
|
|
|
|
|
|
# |
410
|
|
|
|
|
|
|
# Setup Term |
411
|
|
|
|
|
|
|
# |
412
|
7
|
|
|
|
|
13
|
my $mode; |
413
|
7
|
50
|
|
|
|
42
|
if (!is_interactive()) { |
414
|
7
|
|
|
|
|
151
|
$sh->{batch} = 1; |
415
|
7
|
|
|
|
|
16
|
$mode = "in batch mode"; |
416
|
|
|
|
|
|
|
} else { |
417
|
0
|
|
|
|
|
0
|
$sh->{term} = new Term::ReadLine($class); |
418
|
0
|
0
|
|
|
|
0
|
if ($sh->{term}->Features->{readHistory}) { |
419
|
0
|
|
|
|
|
0
|
$sh->{term}->ReadHistory(File::Spec->catfile(File::HomeDir->my_home, HISTORY_FILE)); |
420
|
|
|
|
|
|
|
} |
421
|
0
|
|
|
|
|
0
|
$mode = ""; |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
|
424
|
7
|
|
|
|
|
20
|
return( $mode ); |
425
|
|
|
|
|
|
|
} |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
sub new { |
428
|
7
|
|
|
7
|
|
148
|
my ($class, @args) = @_; |
429
|
|
|
|
|
|
|
|
430
|
7
|
|
|
|
|
23
|
my $sh = bless {}, $class; |
431
|
|
|
|
|
|
|
|
432
|
7
|
|
|
|
|
47
|
$sh->default_config; |
433
|
7
|
|
|
|
|
72
|
$sh->default_commands; |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
# |
436
|
|
|
|
|
|
|
# Handle command line parameters |
437
|
|
|
|
|
|
|
# |
438
|
|
|
|
|
|
|
# data_source and user command line parameters overrides both |
439
|
|
|
|
|
|
|
# environment and config settings. |
440
|
|
|
|
|
|
|
# |
441
|
|
|
|
|
|
|
|
442
|
7
|
|
|
|
|
29
|
$DB::single = 1; |
443
|
|
|
|
|
|
|
|
444
|
7
|
|
|
|
|
28
|
local (@ARGV) = @args; |
445
|
7
|
|
|
|
|
14
|
my @options = values %{ $sh->{options} }; |
|
7
|
|
|
|
|
53
|
|
446
|
7
|
|
|
|
|
44
|
Getopt::Long::config('pass_through'); # for plug-ins |
447
|
7
|
50
|
|
|
|
673
|
unless (GetOptions($sh, 'help|h', @options)) { |
448
|
0
|
|
|
|
|
0
|
$class->usage; |
449
|
0
|
|
|
|
|
0
|
croak "DBI::Shell aborted.\n"; |
450
|
|
|
|
|
|
|
} |
451
|
7
|
50
|
|
|
|
13226
|
if ($sh->{help}) { |
452
|
0
|
|
|
|
|
0
|
$class->usage; |
453
|
0
|
|
|
|
|
0
|
return; |
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
|
456
|
7
|
|
|
|
|
25
|
$sh->{unhandled_options} = []; |
457
|
7
|
|
|
|
|
29
|
@args = (); |
458
|
7
|
|
|
|
|
21
|
foreach my $arg (@ARGV) { |
459
|
7
|
50
|
|
|
|
26
|
if ($arg =~ /^-/) { # expected to be in "--opt=value" format |
460
|
0
|
|
|
|
|
0
|
push @{$sh->{unhandled_options}}, $arg; |
|
0
|
|
|
|
|
0
|
|
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
else { |
463
|
7
|
|
|
|
|
22
|
push @args, $arg; |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
# This may be obsolete since it is run again in DBI::Shell::new. |
468
|
7
|
|
|
|
|
61
|
$sh->do_format($sh->{format}); |
469
|
|
|
|
|
|
|
|
470
|
7
|
|
0
|
|
|
33
|
$sh->{data_source} = shift(@args) || $ENV{DBI_DSN} || ''; |
471
|
|
|
|
|
|
|
|
472
|
7
|
|
|
|
|
16
|
my $user = shift(@args); |
473
|
7
|
50
|
50
|
|
|
60
|
$sh->{user} = defined $user ? $user : $ENV{DBI_USER} || ''; |
474
|
7
|
|
|
|
|
16
|
my $password = shift(@args); |
475
|
7
|
50
|
50
|
|
|
44
|
$sh->{password} = defined $password ? $password : $ENV{DBI_PASS} || undef; |
476
|
|
|
|
|
|
|
|
477
|
7
|
|
|
|
|
16
|
$sh->{chistory} = []; # command history |
478
|
7
|
|
|
|
|
18
|
$sh->{rhistory} = []; # result history |
479
|
7
|
|
|
|
|
14
|
$sh->{prompt} = $sh->{data_source}; |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
# set the default io handle. |
482
|
7
|
|
|
|
|
18
|
$sh->{out_fh} = \*STDOUT; |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# support for spool command ... |
485
|
7
|
|
|
|
|
15
|
$sh->{spooling} = 0; $sh->{spool_file} = undef; $sh->{spool_fh} = undef; |
|
7
|
|
|
|
|
14
|
|
|
7
|
|
|
|
|
24
|
|
486
|
|
|
|
|
|
|
|
487
|
7
|
|
|
|
|
51
|
my $mode = $sh->default_term($class); |
488
|
|
|
|
|
|
|
|
489
|
7
|
|
|
|
|
129
|
$sh->log("DBI::Shell $DBI::Shell::VERSION using DBI $DBI::VERSION $mode"); |
490
|
7
|
50
|
|
|
|
50
|
$sh->log("DBI::Shell loaded from $INC{'DBI/Shell.pm'}") if $sh->{debug}; |
491
|
|
|
|
|
|
|
|
492
|
7
|
|
|
|
|
38
|
return $sh; |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
# Used to install, configure, or change an option or command. |
496
|
|
|
|
|
|
|
sub install_options { |
497
|
52
|
|
|
52
|
|
110
|
my ($sh, $options) = @_; |
498
|
|
|
|
|
|
|
|
499
|
52
|
|
|
|
|
72
|
my @po; |
500
|
|
|
|
|
|
|
$sh->log( "reference type: " . ref $options ) |
501
|
52
|
50
|
|
|
|
117
|
if $sh->{debug}; |
502
|
|
|
|
|
|
|
|
503
|
52
|
50
|
|
|
|
117
|
if ( ref $options eq 'ARRAY' ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
504
|
|
|
|
|
|
|
|
505
|
52
|
|
|
|
|
110
|
foreach my $opt_ref ( @$options ) |
506
|
|
|
|
|
|
|
#[ 'debug|d=i' => ($ENV{DBISH_DEBUG} || 0) ], |
507
|
|
|
|
|
|
|
#[ 'seperator|sep=s' => ',' ],) |
508
|
|
|
|
|
|
|
{ |
509
|
116
|
100
|
|
|
|
209
|
if ( ref $opt_ref eq 'ARRAY' ) { |
510
|
36
|
|
|
|
|
86
|
$sh->install_options( $opt_ref ); |
511
|
|
|
|
|
|
|
} else { |
512
|
80
|
|
|
|
|
151
|
push( @po, $opt_ref ); |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
} elsif ( ref $options eq 'HASH' ) { |
516
|
0
|
|
|
|
|
0
|
foreach (keys %{$options}) { |
|
0
|
|
|
|
|
0
|
|
517
|
0
|
|
|
|
|
0
|
push(@po, $_, $options->{$_}); |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
} elsif ( ref $options eq 'SCALAR' ) { |
520
|
0
|
|
|
|
|
0
|
push( @po, $$options ); |
521
|
|
|
|
|
|
|
} else { |
522
|
0
|
0
|
|
|
|
0
|
return unless $options; |
523
|
0
|
|
|
|
|
0
|
push( @po, $options ); |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
|
526
|
52
|
100
|
|
|
|
115
|
return unless @po; |
527
|
|
|
|
|
|
|
|
528
|
40
|
|
|
|
|
72
|
eval{ $sh->add_option(@po) }; |
|
40
|
|
|
|
|
99
|
|
529
|
|
|
|
|
|
|
# Option exists, just change it. |
530
|
40
|
100
|
|
|
|
366
|
if ($@ =~ /add_option/) { |
531
|
20
|
|
|
|
|
126
|
$sh->do_option( join( '=',@po ) ); |
532
|
|
|
|
|
|
|
} else { |
533
|
20
|
50
|
|
|
|
58
|
croak "configuration: $@\n" if $@; |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
sub configuration { |
538
|
5
|
|
|
5
|
|
18
|
my $sh = shift; |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
# Source config file which may override the defaults. |
541
|
|
|
|
|
|
|
# Default is $ENV{HOME}/.dbish_config. |
542
|
|
|
|
|
|
|
# Can be overridden with $ENV{DBISH_CONFIG}. |
543
|
|
|
|
|
|
|
# Make $ENV{DBISH_CONFIG} empty to prevent sourcing config file. |
544
|
|
|
|
|
|
|
# XXX all this will change |
545
|
|
|
|
|
|
|
my $homedir = $ENV{HOME} # unix |
546
|
5
|
|
33
|
|
|
38
|
|| "$ENV{HOMEDRIVE}$ENV{HOMEPATH}"; # NT |
547
|
5
|
|
66
|
|
|
42
|
$sh->{config_file} = $ENV{DBISH_CONFIG} || "$homedir/.dbish_config"; |
548
|
5
|
|
|
|
|
18
|
my $config; |
549
|
5
|
100
|
66
|
|
|
150
|
if ($sh->{config_file} && -f $sh->{config_file}) { |
550
|
4
|
|
|
|
|
224
|
my $full = File::Spec->rel2abs( $sh->{config_file} ); |
551
|
4
|
|
|
|
|
2380
|
$config = require $full; |
552
|
|
|
|
|
|
|
# allow for custom configuration options. |
553
|
4
|
50
|
|
|
|
27
|
if (exists $config->{'options'} ) { |
554
|
4
|
|
|
|
|
52
|
$sh->install_options( $config->{'options'} ); |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
} |
557
|
5
|
|
|
|
|
20
|
return $config; |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
sub run { |
562
|
0
|
|
|
0
|
|
0
|
my $sh = shift; |
563
|
|
|
|
|
|
|
|
564
|
0
|
|
|
|
|
0
|
my $current_line = ''; |
565
|
|
|
|
|
|
|
|
566
|
0
|
|
|
|
|
0
|
while (1) { |
567
|
0
|
|
|
|
|
0
|
my $prefix = $sh->{command_prefix}; |
568
|
|
|
|
|
|
|
|
569
|
0
|
|
|
|
|
0
|
$current_line = $sh->readline($sh->prompt()); |
570
|
0
|
0
|
|
|
|
0
|
$current_line = "/quit" unless defined $current_line; |
571
|
|
|
|
|
|
|
|
572
|
0
|
|
|
|
|
0
|
my $copy_cline = $current_line; my $eat_line = 0; |
|
0
|
|
|
|
|
0
|
|
573
|
|
|
|
|
|
|
# move past command prefix contained within quotes |
574
|
0
|
|
|
|
|
0
|
while( $copy_cline =~ s/(['"][^'"]*(?:$prefix).*?['"])//og ) { |
575
|
0
|
|
|
|
|
0
|
$eat_line = $+[0]; |
576
|
|
|
|
|
|
|
} |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
# What's left to check? |
579
|
0
|
|
|
|
|
0
|
my $line; |
580
|
0
|
0
|
|
|
|
0
|
if ($eat_line > 0) { |
581
|
0
|
|
|
|
|
0
|
$sh->{current_buffer} .= substr( $current_line, 0, $eat_line ) . "\n"; |
582
|
0
|
0
|
|
|
|
0
|
$current_line = substr( $current_line, $eat_line ) |
583
|
|
|
|
|
|
|
if (length($current_line) >= $eat_line ); |
584
|
|
|
|
|
|
|
} else { |
585
|
0
|
|
|
|
|
0
|
$current_line = $copy_cline; |
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
|
589
|
0
|
0
|
|
|
|
0
|
if ( |
|
|
0
|
|
|
|
|
|
590
|
|
|
|
|
|
|
$current_line =~ m/ |
591
|
|
|
|
|
|
|
^(.*?) |
592
|
|
|
|
|
|
|
(?
|
593
|
|
|
|
|
|
|
$prefix |
594
|
|
|
|
|
|
|
(?:(\w*) |
595
|
|
|
|
|
|
|
([^\|><]*))? |
596
|
|
|
|
|
|
|
((?:\||>>?|<).+)? |
597
|
|
|
|
|
|
|
$ |
598
|
|
|
|
|
|
|
/x) { |
599
|
0
|
|
0
|
|
|
0
|
my ($stmt, $cmd, $args_string, $output) = ($1, $2, $3, $4||''); |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
# print "$stmt -- $cmd -- $args_string -- $output\n"; |
602
|
|
|
|
|
|
|
# $sh->{current_buffer} .= "$stmt\n" if length $stmt; |
603
|
0
|
0
|
|
|
|
0
|
if (length $stmt) { |
604
|
0
|
|
|
|
|
0
|
$stmt =~ s/\\$prefix/$prefix/g; |
605
|
0
|
|
|
|
|
0
|
$sh->{current_buffer} .= "$stmt\n"; |
606
|
0
|
0
|
|
|
|
0
|
if ($sh->is_spooling) { print ${$sh->{spool_fh}} ($stmt, "\n\n") } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
|
609
|
0
|
0
|
|
|
|
0
|
$cmd = 'go' if $cmd eq ''; |
610
|
0
|
|
0
|
|
|
0
|
my @args = split ' ', $args_string||''; |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
warn("command='$cmd' args='$args_string' output='$output'") |
613
|
0
|
0
|
|
|
|
0
|
if $sh->{debug}; |
614
|
|
|
|
|
|
|
|
615
|
0
|
|
|
|
|
0
|
my $command; |
616
|
0
|
0
|
|
|
|
0
|
if ($sh->{abbrev}) { |
617
|
0
|
|
|
|
|
0
|
$command = $sh->{abbrev}->{$cmd}; |
618
|
|
|
|
|
|
|
} |
619
|
|
|
|
|
|
|
else { |
620
|
0
|
0
|
|
|
|
0
|
$command = ($sh->{command}->{$cmd}) ? $cmd : undef; |
621
|
|
|
|
|
|
|
} |
622
|
0
|
0
|
|
|
|
0
|
if ($command) { |
623
|
0
|
|
|
|
|
0
|
$sh->run_command($command, $output, @args); |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
else { |
626
|
0
|
0
|
|
|
|
0
|
if ($sh->{batch}) { |
627
|
0
|
|
|
|
|
0
|
die "Command '$cmd' not recognised"; |
628
|
|
|
|
|
|
|
} |
629
|
0
|
|
|
|
|
0
|
$sh->alert("Command '$cmd' not recognised ", |
630
|
|
|
|
|
|
|
"(enter ${prefix}help for help)."); |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
elsif ($current_line ne "") { |
635
|
0
|
0
|
|
|
|
0
|
if ($sh->is_spooling) { print ${$sh->{spool_fh}} ($current_line, "\n") } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
636
|
0
|
|
|
|
|
0
|
$sh->{current_buffer} .= $current_line . "\n"; |
637
|
|
|
|
|
|
|
# print whole buffer here so user can see it as |
638
|
|
|
|
|
|
|
# it grows (and new users might guess that unrecognised |
639
|
|
|
|
|
|
|
# inputs are treated as commands) |
640
|
0
|
0
|
|
|
|
0
|
unless ($sh->{user_level}) { |
641
|
0
|
|
|
|
|
0
|
$sh->run_command('current', undef, |
642
|
|
|
|
|
|
|
"(enter '$prefix' to execute or '${prefix}help' for help)"); |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
} |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
# |
650
|
|
|
|
|
|
|
# Internal methods |
651
|
|
|
|
|
|
|
# |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
sub readline { |
654
|
0
|
|
|
0
|
|
0
|
my ($sh, $prompt) = @_; |
655
|
0
|
|
|
|
|
0
|
my $rv; |
656
|
0
|
0
|
|
|
|
0
|
if ($sh->{term}) { |
657
|
0
|
|
|
|
|
0
|
$rv = $sh->{term}->readline($prompt); |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
else { |
660
|
0
|
|
|
|
|
0
|
chomp($rv = ); |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
|
663
|
0
|
|
|
|
|
0
|
return $rv; |
664
|
|
|
|
|
|
|
} |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
sub run_command { |
668
|
9
|
|
|
9
|
|
41
|
my ($sh, $command, $output, @args) = @_; |
669
|
9
|
50
|
|
|
|
31
|
return unless $command; |
670
|
|
|
|
|
|
|
|
671
|
9
|
|
|
|
|
31
|
my $code = "do_$command"; |
672
|
9
|
50
|
|
|
|
89
|
if ($sh->can("$code")) { |
673
|
9
|
50
|
|
|
|
28
|
local(*STDOUT) if $output; |
674
|
9
|
50
|
|
|
|
24
|
local(*OUTPUT) if $output; |
675
|
9
|
50
|
|
|
|
27
|
if ($output) { |
676
|
0
|
0
|
|
|
|
0
|
if (open(OUTPUT, $output)) { |
677
|
0
|
|
|
|
|
0
|
*STDOUT = *OUTPUT; |
678
|
|
|
|
|
|
|
} else { |
679
|
0
|
|
|
|
|
0
|
$sh->err("Couldn't open output '$output': $!"); |
680
|
0
|
|
|
|
|
0
|
$sh->run_command('current', undef, ''); |
681
|
|
|
|
|
|
|
} |
682
|
|
|
|
|
|
|
} |
683
|
|
|
|
|
|
|
|
684
|
9
|
|
|
|
|
17
|
local $@; |
685
|
|
|
|
|
|
|
|
686
|
9
|
|
|
|
|
21
|
eval { |
687
|
9
|
|
|
|
|
37
|
$sh->$code(@args); |
688
|
|
|
|
|
|
|
}; |
689
|
9
|
50
|
|
|
|
60
|
close OUTPUT if $output; |
690
|
9
|
50
|
|
|
|
30
|
$sh->err("$command failed: $@") if $@; |
691
|
|
|
|
|
|
|
} |
692
|
|
|
|
|
|
|
else { |
693
|
0
|
0
|
|
|
|
0
|
if ($command eq 'spool') { |
694
|
0
|
|
|
|
|
0
|
$sh->err("The DBI::Shell:Spool plug in needs to be installed. See https://rt.cpan.org/Ticket/Display.html?id=24538#txn-813176") |
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
else { |
697
|
0
|
|
|
|
|
0
|
$sh->err("$command does not exist, does a plug-in need to be installed?") |
698
|
|
|
|
|
|
|
} |
699
|
|
|
|
|
|
|
} |
700
|
9
|
|
|
|
|
84
|
return; |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
sub print_list { |
705
|
1
|
|
|
1
|
|
3
|
my ($sh, $list_ref) = @_; |
706
|
1
|
|
|
|
|
5
|
for(my $i = 0; $i < @$list_ref; $i++) { |
707
|
0
|
|
|
|
|
0
|
print ${$sh->{out_fh}} ($i+1,": $$list_ref[$i]\n"); |
|
0
|
|
|
|
|
0
|
|
708
|
|
|
|
|
|
|
} |
709
|
1
|
|
|
|
|
17
|
return; |
710
|
|
|
|
|
|
|
} |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
#------------------------------------------------------------------- |
714
|
|
|
|
|
|
|
# |
715
|
|
|
|
|
|
|
# Print Buffer adding a prompt. |
716
|
|
|
|
|
|
|
# |
717
|
|
|
|
|
|
|
#------------------------------------------------------------------- |
718
|
|
|
|
|
|
|
sub print_buffer { |
719
|
72
|
|
|
72
|
|
120
|
my $sh = shift; |
720
|
|
|
|
|
|
|
{ |
721
|
72
|
|
|
|
|
162
|
local ($,) = q{ }; |
|
72
|
|
|
|
|
161
|
|
722
|
72
|
|
|
|
|
146
|
my @out = @_; |
723
|
72
|
|
|
|
|
163
|
chomp $out[-1]; # Remove any added newline. |
724
|
72
|
|
|
|
|
208
|
return print ($sh->prompt(), @out,"\n"); |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
} |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
#------------------------------------------------------------------- |
729
|
|
|
|
|
|
|
# |
730
|
|
|
|
|
|
|
# Print Buffer without adding a prompt. |
731
|
|
|
|
|
|
|
# |
732
|
|
|
|
|
|
|
#------------------------------------------------------------------- |
733
|
|
|
|
|
|
|
sub print_buffer_nop { |
734
|
98
|
|
|
98
|
|
161
|
my $sh = shift; |
735
|
|
|
|
|
|
|
{ |
736
|
98
|
|
|
|
|
121
|
local ($,) = q{ }; |
|
98
|
|
|
|
|
228
|
|
737
|
98
|
|
|
|
|
163
|
my @out = @_; |
738
|
98
|
|
|
|
|
178
|
chomp $out[-1]; # Remove any added newline. |
739
|
98
|
|
|
|
|
991
|
return print (@out,"\n"); |
740
|
|
|
|
|
|
|
} |
741
|
|
|
|
|
|
|
} |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
sub get_data_source { |
744
|
9
|
|
|
9
|
|
29
|
my ($sh, $dsn, @args) = @_; |
745
|
9
|
|
|
|
|
15
|
my $driver; |
746
|
|
|
|
|
|
|
|
747
|
9
|
50
|
|
|
|
26
|
if ($dsn) { |
748
|
9
|
50
|
|
|
|
74
|
if ($dsn =~ m/^dbi:.*:/i) { # has second colon |
|
|
0
|
|
|
|
|
|
749
|
9
|
|
|
|
|
31
|
return $dsn; # assumed to be full DSN |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
elsif ($dsn =~ m/^dbi:([^:]*)/i) { |
752
|
0
|
|
|
|
|
0
|
$driver = $1 # use DriverName part |
753
|
|
|
|
|
|
|
} |
754
|
|
|
|
|
|
|
else { |
755
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop ("Ignored unrecognised DBI DSN '$dsn'.\n"); |
756
|
|
|
|
|
|
|
} |
757
|
|
|
|
|
|
|
} |
758
|
|
|
|
|
|
|
|
759
|
0
|
0
|
|
|
|
0
|
if ($sh->{batch}) { |
760
|
0
|
|
|
|
|
0
|
die "Missing or unrecognised DBI DSN."; |
761
|
|
|
|
|
|
|
} |
762
|
|
|
|
|
|
|
|
763
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop("\n"); |
764
|
|
|
|
|
|
|
|
765
|
0
|
|
|
|
|
0
|
while (!$driver) { |
766
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop("Available DBI drivers:\n"); |
767
|
0
|
|
|
|
|
0
|
my @drivers = DBI->available_drivers; |
768
|
0
|
|
|
|
|
0
|
for( my $cnt = 0; $cnt <= $#drivers; $cnt++ ) { |
769
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop(sprintf ("%2d: dbi:%s\n", $cnt+1, $drivers[$cnt])); |
770
|
|
|
|
|
|
|
} |
771
|
0
|
|
|
|
|
0
|
$driver = $sh->readline( |
772
|
|
|
|
|
|
|
"Enter driver name or number, or full 'dbi:...:...' DSN: "); |
773
|
0
|
0
|
|
|
|
0
|
exit unless defined $driver; # detect ^D / EOF |
774
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop("\n"); |
775
|
|
|
|
|
|
|
|
776
|
0
|
0
|
|
|
|
0
|
return $driver if $driver =~ /^dbi:.*:/i; # second colon entered |
777
|
|
|
|
|
|
|
|
778
|
0
|
0
|
|
|
|
0
|
if ( $driver =~ /^\s*(\d+)/ ) { |
779
|
0
|
|
|
|
|
0
|
$driver = $drivers[$1-1]; |
780
|
|
|
|
|
|
|
} else { |
781
|
0
|
|
|
|
|
0
|
$driver = $1; |
782
|
0
|
0
|
|
|
|
0
|
$driver =~ s/^dbi://i if $driver # incase they entered 'dbi:Name' |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
# XXX try to install $driver (if true) |
785
|
|
|
|
|
|
|
# unset $driver if install fails. |
786
|
|
|
|
|
|
|
} |
787
|
|
|
|
|
|
|
|
788
|
0
|
|
|
|
|
0
|
my $source; |
789
|
0
|
|
|
|
|
0
|
while (!defined $source) { |
790
|
0
|
|
|
|
|
0
|
my $prompt; |
791
|
0
|
|
|
|
|
0
|
my @data_sources = DBI->data_sources($driver); |
792
|
0
|
0
|
|
|
|
0
|
if (@data_sources) { |
793
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop("Enter data source to connect to: \n"); |
794
|
0
|
|
|
|
|
0
|
for( my $cnt = 0; $cnt <= $#data_sources; $cnt++ ) { |
795
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop(sprintf ("%2d: %s\n", $cnt+1, $data_sources[$cnt])); |
796
|
|
|
|
|
|
|
} |
797
|
0
|
|
|
|
|
0
|
$prompt = "Enter data source or number,"; |
798
|
|
|
|
|
|
|
} |
799
|
|
|
|
|
|
|
else { |
800
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop ("(The data_sources method returned nothing.)\n"); |
801
|
0
|
|
|
|
|
0
|
$prompt = "Enter data source"; |
802
|
|
|
|
|
|
|
} |
803
|
0
|
|
|
|
|
0
|
$source = $sh->readline( |
804
|
|
|
|
|
|
|
"$prompt or full 'dbi:...:...' DSN: "); |
805
|
0
|
0
|
|
|
|
0
|
return if !defined $source; # detect ^D / EOF |
806
|
0
|
0
|
|
|
|
0
|
if ($source =~ /^\s*(\d+)/) { |
|
|
0
|
|
|
|
|
|
807
|
0
|
|
|
|
|
0
|
$source = $data_sources[$1-1] |
808
|
|
|
|
|
|
|
} |
809
|
|
|
|
|
|
|
elsif ($source =~ /^dbi:([^:]+)$/) { # no second colon |
810
|
0
|
|
|
|
|
0
|
$driver = $1; # possibly new driver |
811
|
0
|
|
|
|
|
0
|
$source = undef; |
812
|
|
|
|
|
|
|
} |
813
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop("\n"); |
814
|
|
|
|
|
|
|
} |
815
|
|
|
|
|
|
|
|
816
|
0
|
|
|
|
|
0
|
return $source; |
817
|
|
|
|
|
|
|
} |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
sub prompt_for_password { |
821
|
0
|
|
|
0
|
|
0
|
my ($sh) = @_; |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
# no prompts in batch mode. |
824
|
|
|
|
|
|
|
|
825
|
0
|
0
|
|
|
|
0
|
return if ($sh->{batch}); |
826
|
|
|
|
|
|
|
|
827
|
0
|
0
|
|
|
|
0
|
if (!defined($haveTermReadKey)) { |
828
|
0
|
0
|
|
|
|
0
|
$haveTermReadKey = eval { require Term::ReadKey } ? 1 : 0; |
|
0
|
|
|
|
|
0
|
|
829
|
|
|
|
|
|
|
} |
830
|
0
|
|
|
|
|
0
|
local $| = 1; |
831
|
0
|
0
|
|
|
|
0
|
$sh->print_buffer_nop ("Password for $sh->{user} (", |
832
|
|
|
|
|
|
|
($haveTermReadKey ? "not " : "Warning: "), |
833
|
|
|
|
|
|
|
"echoed to screen): "); |
834
|
0
|
0
|
|
|
|
0
|
if ($haveTermReadKey) { |
835
|
0
|
|
|
|
|
0
|
Term::ReadKey::ReadMode('noecho'); |
836
|
0
|
|
|
|
|
0
|
$sh->{password} = Term::ReadKey::ReadLine(0); |
837
|
0
|
|
|
|
|
0
|
Term::ReadKey::ReadMode('restore'); |
838
|
|
|
|
|
|
|
} else { |
839
|
0
|
|
|
|
|
0
|
$sh->{password} = ; |
840
|
|
|
|
|
|
|
} |
841
|
0
|
|
|
|
|
0
|
chomp $sh->{password}; |
842
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop ("\n"); |
843
|
|
|
|
|
|
|
} |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
sub prompt { |
846
|
72
|
|
|
72
|
|
131
|
my ($sh) = @_; |
847
|
72
|
50
|
|
|
|
1054
|
return "" if $sh->{batch}; |
848
|
0
|
0
|
|
|
|
0
|
return "(not connected)> " unless $sh->{dbh}; |
849
|
|
|
|
|
|
|
|
850
|
0
|
0
|
|
|
|
0
|
if ( ref $sh->{prompt} ) { |
851
|
0
|
|
|
|
|
0
|
foreach (@{$sh->{prompt}} ) { |
|
0
|
|
|
|
|
0
|
|
852
|
0
|
0
|
|
|
|
0
|
if ( ref $_ eq "CODE" ) { |
853
|
0
|
|
|
|
|
0
|
$sh->{prompt} .= &$_; |
854
|
|
|
|
|
|
|
} else { |
855
|
0
|
|
|
|
|
0
|
$sh->{prompt} .= $_; |
856
|
|
|
|
|
|
|
} |
857
|
|
|
|
|
|
|
} |
858
|
0
|
|
|
|
|
0
|
return "$sh->{user}\@$sh->{prompt}> "; |
859
|
|
|
|
|
|
|
} else { |
860
|
0
|
|
|
|
|
0
|
return "$sh->{user}\@$sh->{prompt}> "; |
861
|
|
|
|
|
|
|
} |
862
|
0
|
|
|
|
|
0
|
return; |
863
|
|
|
|
|
|
|
} |
864
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
sub push_chistory { |
867
|
52
|
|
|
52
|
|
144
|
my ($sh, $cmd) = @_; |
868
|
52
|
50
|
|
|
|
159
|
$cmd = $sh->{current_buffer} unless defined $cmd; |
869
|
52
|
|
|
|
|
92
|
$sh->{prev_buffer} = $cmd; |
870
|
52
|
|
|
|
|
123
|
my $chist = $sh->{chistory}; |
871
|
52
|
50
|
|
|
|
170
|
shift @$chist if @$chist >= $sh->{chistory_size}; |
872
|
52
|
|
|
|
|
153
|
push @$chist, $cmd; |
873
|
52
|
|
|
|
|
115
|
return; |
874
|
|
|
|
|
|
|
} |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
# |
878
|
|
|
|
|
|
|
# Command methods |
879
|
|
|
|
|
|
|
# |
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
sub do_help { |
882
|
1
|
|
|
1
|
|
4
|
my ($sh, @args) = @_; |
883
|
|
|
|
|
|
|
|
884
|
1
|
50
|
|
|
|
9
|
return "" if $sh->{batch}; |
885
|
|
|
|
|
|
|
|
886
|
0
|
|
|
|
|
0
|
my $prefix = $sh->{command_prefix}; |
887
|
0
|
|
|
|
|
0
|
my $commands = $sh->{commands}; |
888
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop ("Defined commands, in alphabetical order:\n"); |
889
|
0
|
|
|
|
|
0
|
foreach my $cmd (sort keys %$commands) { |
890
|
0
|
|
0
|
|
|
0
|
my $hint = $commands->{$cmd}->{hint} || ''; |
891
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop(sprintf (" %s%-10s %s\n", $prefix, $cmd, $hint)); |
892
|
|
|
|
|
|
|
} |
893
|
0
|
0
|
|
|
|
0
|
$sh->print_buffer_nop ("Commands can be abbreviated.\n") if $sh->{abbrev}; |
894
|
0
|
|
|
|
|
0
|
return; |
895
|
|
|
|
|
|
|
} |
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
sub do_format { |
899
|
22
|
|
|
22
|
|
1970
|
my ($sh, @args) = @_; |
900
|
22
|
|
50
|
|
|
81
|
my $mode = $args[0] || ''; |
901
|
22
|
|
|
|
|
41
|
my $class = eval { DBI::Format->formatter($mode,1) }; |
|
22
|
|
|
|
|
176
|
|
902
|
22
|
50
|
|
|
|
69
|
unless ($class) { |
903
|
0
|
|
|
|
|
0
|
return $sh->alert("Unable to select '$mode': $@"); |
904
|
|
|
|
|
|
|
} |
905
|
22
|
50
|
|
|
|
74
|
$sh->log("Using formatter class '$class'") if $sh->{debug}; |
906
|
22
|
|
|
|
|
56
|
$sh->{format} = $mode; |
907
|
22
|
|
|
|
|
108
|
return $sh->{display} = $class->new($sh); |
908
|
|
|
|
|
|
|
} |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
sub do_go { |
912
|
52
|
|
|
52
|
|
160
|
my ($sh, @args) = @_; |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
# print "do_go\n"; |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
# Modify go to get the last executed statement if called on an |
917
|
|
|
|
|
|
|
# empty buffer. |
918
|
|
|
|
|
|
|
|
919
|
52
|
100
|
|
|
|
257
|
if ($sh->{current_buffer} eq '') { |
920
|
2
|
|
|
|
|
21
|
$sh->do_get; |
921
|
2
|
50
|
|
|
|
8
|
return if $sh->{current_buffer} eq ''; |
922
|
|
|
|
|
|
|
} |
923
|
|
|
|
|
|
|
|
924
|
52
|
|
|
|
|
139
|
$sh->{prev_buffer} = $sh->{current_buffer}; |
925
|
|
|
|
|
|
|
|
926
|
52
|
|
|
|
|
235
|
$sh->push_chistory; |
927
|
|
|
|
|
|
|
|
928
|
52
|
|
|
|
|
141
|
eval { |
929
|
|
|
|
|
|
|
# Determine if the single quotes are out of balance. |
930
|
52
|
|
|
|
|
173
|
my $count = ($sh->{current_buffer} =~ tr/'/'/); |
931
|
52
|
50
|
|
|
|
194
|
warn "Quotes out of balance: $count" unless (($count % 2) == 0); |
932
|
|
|
|
|
|
|
|
933
|
52
|
|
|
|
|
541
|
my $sth = $sh->{dbh}->prepare($sh->{current_buffer}); |
934
|
|
|
|
|
|
|
|
935
|
51
|
|
|
|
|
7349
|
$sh->sth_go($sth, 1); |
936
|
|
|
|
|
|
|
}; |
937
|
52
|
100
|
|
|
|
254
|
if ($@) { |
938
|
1
|
|
|
|
|
3
|
my $err = $@; |
939
|
|
|
|
|
|
|
$err =~ s: at \S*DBI/Shell.pm line \d+(,.*?chunk \d+)?:: |
940
|
1
|
50
|
33
|
|
|
18
|
if !$sh->{debug} && $err =~ /^DBD::\w+::\w+ \w+/; |
941
|
1
|
|
|
|
|
42
|
print STDERR "$err"; |
942
|
|
|
|
|
|
|
} |
943
|
|
|
|
|
|
|
# There need to be a better way, maybe clearing the |
944
|
|
|
|
|
|
|
# buffer when the next non command is typed. |
945
|
|
|
|
|
|
|
# Or sprinkle <$sh->{current_buffer} ||= $sh->{prev_buffer};> |
946
|
|
|
|
|
|
|
# around in the code. |
947
|
52
|
|
|
|
|
1172
|
return $sh->{current_buffer} = ''; |
948
|
|
|
|
|
|
|
} |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
sub sth_go { |
952
|
53
|
|
|
53
|
|
165
|
my ($sh, $sth, $execute, $rh) = @_; |
953
|
|
|
|
|
|
|
|
954
|
53
|
100
|
|
|
|
161
|
$rh = 1 unless defined $rh; # Add to results history. Default 1, Yes. |
955
|
53
|
|
|
|
|
80
|
my $rv; |
956
|
53
|
50
|
66
|
|
|
182
|
if ($execute || !$sth->{Active}) { |
957
|
53
|
|
|
|
|
110
|
my @params; |
958
|
53
|
|
50
|
|
|
535
|
my $params = $sth->{NUM_OF_PARAMS} || 0; |
959
|
53
|
50
|
|
|
|
219
|
$sh->print_buffer_nop("Statement has $params parameters:\n") if $params; |
960
|
53
|
|
|
|
|
168
|
foreach(1..$params) { |
961
|
0
|
|
|
|
|
0
|
my $val = $sh->readline("Parameter $_ value: "); |
962
|
0
|
|
|
|
|
0
|
push @params, $val; |
963
|
|
|
|
|
|
|
} |
964
|
53
|
|
|
|
|
295
|
$rv = $sth->execute(@params); |
965
|
|
|
|
|
|
|
} |
966
|
|
|
|
|
|
|
|
967
|
53
|
50
|
|
|
|
6352
|
if (!$sth->{'NUM_OF_FIELDS'}) { # not a select statement |
968
|
0
|
|
|
|
|
0
|
local $^W=0; |
969
|
0
|
0
|
|
|
|
0
|
$rv = "undefined number of" unless defined $rv; |
970
|
0
|
0
|
|
|
|
0
|
$rv = "unknown number of" if $rv == -1; |
971
|
0
|
0
|
|
|
|
0
|
$sh->print_buffer_nop ("[$rv row" . ($rv==1 ? "" : "s") . " affected]\n"); |
972
|
0
|
|
|
|
|
0
|
return; |
973
|
|
|
|
|
|
|
} |
974
|
|
|
|
|
|
|
|
975
|
53
|
|
|
|
|
770
|
$sh->{sth} = $sth; |
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
# |
978
|
|
|
|
|
|
|
# Remove oldest result from history if reached limit |
979
|
|
|
|
|
|
|
# |
980
|
53
|
|
|
|
|
125
|
my $rhist = $sh->{rhistory}; |
981
|
53
|
100
|
|
|
|
129
|
if ($rh) { |
982
|
51
|
50
|
|
|
|
167
|
shift @$rhist if @$rhist >= $sh->{rhistory_size}; |
983
|
51
|
|
|
|
|
149
|
push @$rhist, []; |
984
|
|
|
|
|
|
|
} |
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
# |
987
|
|
|
|
|
|
|
# Keep a buffer of $sh->{rhistory_tail} many rows, |
988
|
|
|
|
|
|
|
# when done with result add those to rhistory buffer. |
989
|
|
|
|
|
|
|
# Could use $sth->rows(), but not all DBD's support it. |
990
|
|
|
|
|
|
|
# |
991
|
53
|
|
|
|
|
104
|
my @rtail; |
992
|
53
|
|
|
|
|
83
|
my $i = 0; |
993
|
53
|
|
50
|
|
|
188
|
my $display = $sh->{display} || die "panic: no display set"; |
994
|
53
|
|
50
|
|
|
388
|
$display->header($sth, $sh->{out_fh}||\*STDOUT, $sh->{seperator}); |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
OUT_ROWS: |
997
|
53
|
|
|
|
|
501
|
while (my $rowref = $sth->fetchrow_arrayref()) { |
998
|
519
|
|
|
|
|
33435
|
$i++; |
999
|
|
|
|
|
|
|
|
1000
|
519
|
|
|
|
|
1585
|
my $rslt = $display->row($rowref); |
1001
|
|
|
|
|
|
|
|
1002
|
519
|
100
|
|
|
|
13876
|
if($rh) { |
1003
|
510
|
100
|
|
|
|
1502
|
if ($i <= $sh->{rhistory_head}) { |
1004
|
255
|
|
|
|
|
351
|
push @{$rhist->[-1]}, [@$rowref]; |
|
255
|
|
|
|
|
815
|
|
1005
|
|
|
|
|
|
|
} |
1006
|
|
|
|
|
|
|
else { |
1007
|
255
|
50
|
|
|
|
655
|
shift @rtail if @rtail == $sh->{rhistory_tail}; |
1008
|
255
|
|
|
|
|
704
|
push @rtail, [@$rowref]; |
1009
|
|
|
|
|
|
|
} |
1010
|
|
|
|
|
|
|
} |
1011
|
|
|
|
|
|
|
|
1012
|
519
|
50
|
|
|
|
3226
|
unless(defined $rslt) { |
1013
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop( "row limit reached" ); |
1014
|
0
|
|
|
|
|
0
|
last OUT_ROWS; |
1015
|
|
|
|
|
|
|
} |
1016
|
|
|
|
|
|
|
} |
1017
|
|
|
|
|
|
|
|
1018
|
53
|
|
|
|
|
3034
|
$display->trailer($i); |
1019
|
|
|
|
|
|
|
|
1020
|
53
|
100
|
|
|
|
162
|
if($rh) { |
1021
|
51
|
50
|
|
|
|
132
|
if (@rtail) { |
1022
|
51
|
|
|
|
|
88
|
my $rows = $i; |
1023
|
51
|
|
|
|
|
131
|
my $ommitted = $i - $sh->{rhistory_head} - @rtail; |
1024
|
|
|
|
|
|
|
# Only include the omitted message if results are omitted. |
1025
|
51
|
50
|
|
|
|
130
|
if ($ommitted) { |
1026
|
0
|
|
|
|
|
0
|
push(@{$rhist->[-1]}, |
|
0
|
|
|
|
|
0
|
|
1027
|
|
|
|
|
|
|
[ "[...$ommitted rows out of $rows ommitted...]"]); |
1028
|
|
|
|
|
|
|
} |
1029
|
51
|
|
|
|
|
116
|
foreach my $rowref (@rtail) { |
1030
|
255
|
|
|
|
|
332
|
push @{$rhist->[-1]}, $rowref; |
|
255
|
|
|
|
|
552
|
|
1031
|
|
|
|
|
|
|
} |
1032
|
|
|
|
|
|
|
} |
1033
|
|
|
|
|
|
|
} |
1034
|
|
|
|
|
|
|
|
1035
|
53
|
|
|
|
|
166
|
return; |
1036
|
|
|
|
|
|
|
} |
1037
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
#------------------------------------------------------------------ |
1039
|
|
|
|
|
|
|
# |
1040
|
|
|
|
|
|
|
# Generate a select count(*) from table for each table in list. |
1041
|
|
|
|
|
|
|
# |
1042
|
|
|
|
|
|
|
#------------------------------------------------------------------ |
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
sub do_count { |
1045
|
0
|
|
|
0
|
|
0
|
my ($sh, @args) = @_; |
1046
|
0
|
|
|
|
|
0
|
foreach my $tab (@args) { |
1047
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop ("Counting: $tab\n"); |
1048
|
0
|
|
|
|
|
0
|
$sh->{current_buffer} = "select count(*) as cnt_$tab from $tab"; |
1049
|
0
|
|
|
|
|
0
|
$sh->do_go(); |
1050
|
|
|
|
|
|
|
} |
1051
|
0
|
|
|
|
|
0
|
return $sh->{current_buffer} = ''; |
1052
|
|
|
|
|
|
|
} |
1053
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
sub do_do { |
1055
|
0
|
|
|
0
|
|
0
|
my ($sh, @args) = @_; |
1056
|
0
|
|
|
|
|
0
|
$sh->push_chistory; |
1057
|
0
|
|
|
|
|
0
|
my $rv = $sh->{dbh}->do($sh->{current_buffer}); |
1058
|
0
|
0
|
|
|
|
0
|
$sh->print_buffer_nop ("[$rv row" . ($rv==1 ? "" : "s") . " affected]\n") |
|
|
0
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
if defined $rv; |
1060
|
|
|
|
|
|
|
|
1061
|
|
|
|
|
|
|
# XXX I question setting the buffer to '' here. |
1062
|
|
|
|
|
|
|
# I may want to edit my line without having to scroll back. |
1063
|
0
|
|
|
|
|
0
|
return $sh->{current_buffer} = ''; |
1064
|
|
|
|
|
|
|
} |
1065
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
sub do_disconnect { |
1068
|
9
|
|
|
9
|
|
30
|
my ($sh, @args) = @_; |
1069
|
9
|
50
|
|
|
|
53
|
return unless $sh->{dbh}; |
1070
|
9
|
|
|
|
|
50
|
$sh->log("Disconnecting from $sh->{data_source}."); |
1071
|
9
|
|
|
|
|
37
|
eval { |
1072
|
9
|
100
|
|
|
|
80
|
$sh->{sth}->finish if $sh->{sth}; |
1073
|
9
|
50
|
|
|
|
149
|
$sh->{dbh}->rollback unless $sh->{dbh}->{AutoCommit}; |
1074
|
9
|
|
|
|
|
171
|
$sh->{dbh}->disconnect; |
1075
|
|
|
|
|
|
|
}; |
1076
|
9
|
50
|
|
|
|
177
|
$sh->alert("Error during disconnect: $@") if $@; |
1077
|
9
|
|
|
|
|
73
|
$sh->{sth} = undef; |
1078
|
9
|
|
|
|
|
56
|
$sh->{dbh} = undef; |
1079
|
9
|
|
|
|
|
245
|
return; |
1080
|
|
|
|
|
|
|
} |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
sub do_connect { |
1084
|
9
|
|
|
9
|
|
29
|
my ($sh, $dsn, $user, $pass) = @_; |
1085
|
|
|
|
|
|
|
|
1086
|
9
|
|
|
|
|
62
|
$dsn = $sh->get_data_source($dsn); |
1087
|
9
|
50
|
|
|
|
38
|
return unless $dsn; |
1088
|
|
|
|
|
|
|
|
1089
|
9
|
100
|
|
|
|
50
|
$sh->do_disconnect if $sh->{dbh}; |
1090
|
|
|
|
|
|
|
|
1091
|
|
|
|
|
|
|
# Change from Jeff Zucker, convert literal slash and letter n to newline. |
1092
|
9
|
|
|
|
|
27
|
$dsn =~ s/\\n/\n/g; |
1093
|
9
|
|
|
|
|
20
|
$dsn =~ s/\\t/\t/g; |
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
|
1096
|
9
|
|
|
|
|
23
|
$sh->{data_source} = $dsn; |
1097
|
9
|
50
|
33
|
|
|
44
|
if (defined $user and length $user) { |
1098
|
0
|
|
|
|
|
0
|
$sh->{user} = $user; |
1099
|
0
|
|
|
|
|
0
|
$sh->{password} = undef; # force prompt below |
1100
|
|
|
|
|
|
|
} |
1101
|
|
|
|
|
|
|
|
1102
|
9
|
|
|
|
|
65
|
$sh->log("Connecting to '$sh->{data_source}' as '$sh->{user}'..."); |
1103
|
9
|
50
|
33
|
|
|
56
|
if ($sh->{user} and !defined $sh->{password}) { |
1104
|
0
|
|
|
|
|
0
|
$sh->prompt_for_password(); |
1105
|
|
|
|
|
|
|
} |
1106
|
|
|
|
|
|
|
$sh->{dbh} = DBI->connect( |
1107
|
|
|
|
|
|
|
$sh->{data_source}, $sh->{user}, $sh->{password}, { |
1108
|
|
|
|
|
|
|
AutoCommit => $sh->{init_autocommit}, |
1109
|
9
|
|
|
|
|
114
|
PrintError => 0, |
1110
|
|
|
|
|
|
|
RaiseError => 1, |
1111
|
|
|
|
|
|
|
LongTruncOk => 1, # XXX |
1112
|
|
|
|
|
|
|
}); |
1113
|
9
|
50
|
|
|
|
29960
|
$sh->{dbh}->trace($sh->{init_trace}) if $sh->{init_trace}; |
1114
|
9
|
|
|
|
|
24
|
return; |
1115
|
|
|
|
|
|
|
} |
1116
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
sub do_current { |
1119
|
9
|
|
|
9
|
|
29
|
my ($sh, $msg, @args) = @_; |
1120
|
9
|
50
|
|
|
|
30
|
$msg = $msg ? " $msg" : ""; |
1121
|
|
|
|
|
|
|
return |
1122
|
9
|
|
|
|
|
65
|
$sh->log("Current statement buffer$msg:\n" . $sh->{current_buffer}); |
1123
|
|
|
|
|
|
|
} |
1124
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
sub do_autoflush { |
1126
|
|
|
|
|
|
|
|
1127
|
0
|
|
|
0
|
|
0
|
return; |
1128
|
|
|
|
|
|
|
} |
1129
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
sub do_trace { |
1131
|
0
|
|
|
0
|
|
0
|
return shift->{dbh}->trace(@_); |
1132
|
|
|
|
|
|
|
} |
1133
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
sub do_commit { |
1135
|
1
|
|
|
1
|
|
17
|
return shift->{dbh}->commit(@_); |
1136
|
|
|
|
|
|
|
} |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
sub do_rollback { |
1139
|
1
|
|
|
1
|
|
14
|
return shift->{dbh}->rollback(@_); |
1140
|
|
|
|
|
|
|
} |
1141
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
|
1143
|
|
|
|
|
|
|
sub do_quit { |
1144
|
0
|
|
|
0
|
|
0
|
my ($sh, @args) = @_; |
1145
|
0
|
0
|
|
|
|
0
|
$sh->do_disconnect if $sh->{dbh}; |
1146
|
|
|
|
|
|
|
|
1147
|
0
|
0
|
|
|
|
0
|
if ($sh->{term}) { |
1148
|
0
|
0
|
|
|
|
0
|
if ($sh->{term}->Features()->{writeHistory}) { |
1149
|
0
|
|
|
|
|
0
|
$sh->{term}->WriteHistory(File::Spec->catfile(File::HomeDir->my_home, HISTORY_FILE)); |
1150
|
|
|
|
|
|
|
} |
1151
|
|
|
|
|
|
|
} |
1152
|
|
|
|
|
|
|
|
1153
|
0
|
|
|
|
|
0
|
undef $sh->{term}; |
1154
|
0
|
|
|
|
|
0
|
exit 0; |
1155
|
|
|
|
|
|
|
} |
1156
|
|
|
|
|
|
|
|
1157
|
|
|
|
|
|
|
# Until the alias command is working each command requires definition. |
1158
|
0
|
|
|
0
|
|
0
|
sub do_exit { shift->do_quit(@_); } |
1159
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
sub do_clear { |
1161
|
1
|
|
|
1
|
|
4
|
my ($sh, @args) = @_; |
1162
|
1
|
|
|
|
|
5
|
return $sh->{current_buffer} = ''; |
1163
|
|
|
|
|
|
|
} |
1164
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
|
1166
|
|
|
|
|
|
|
sub do_redo { |
1167
|
0
|
|
|
0
|
|
0
|
my ($sh, @args) = @_; |
1168
|
0
|
|
0
|
|
|
0
|
$sh->{current_buffer} = $sh->{prev_buffer} || ''; |
1169
|
0
|
0
|
|
|
|
0
|
$sh->run_command('go') if $sh->{current_buffer}; |
1170
|
0
|
|
|
|
|
0
|
return; |
1171
|
|
|
|
|
|
|
} |
1172
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
|
1174
|
|
|
|
|
|
|
sub do_chistory { |
1175
|
1
|
|
|
1
|
|
3
|
my ($sh, @args) = @_; |
1176
|
1
|
|
|
|
|
6
|
return $sh->print_list($sh->{chistory}); |
1177
|
|
|
|
|
|
|
} |
1178
|
|
|
|
|
|
|
|
1179
|
|
|
|
|
|
|
sub do_history { |
1180
|
1
|
|
|
1
|
|
3
|
my ($sh, @args) = @_; |
1181
|
1
|
|
|
|
|
3
|
for(my $i = 0; $i < @{$sh->{chistory}}; $i++) { |
|
1
|
|
|
|
|
6
|
|
1182
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop ($i+1, ":\n", $sh->{chistory}->[$i], "--------\n"); |
1183
|
0
|
|
|
|
|
0
|
foreach my $rowref (@{$sh->{rhistory}[$i]}) { |
|
0
|
|
|
|
|
0
|
|
1184
|
0
|
0
|
|
|
|
0
|
$sh->print_buffer_nop(" ", join(", ", map { defined $_ ? $_ : q{undef} }@$rowref), "\n"); |
|
0
|
|
|
|
|
0
|
|
1185
|
|
|
|
|
|
|
} |
1186
|
|
|
|
|
|
|
} |
1187
|
1
|
|
|
|
|
4
|
return; |
1188
|
|
|
|
|
|
|
} |
1189
|
|
|
|
|
|
|
|
1190
|
|
|
|
|
|
|
sub do_rhistory { |
1191
|
1
|
|
|
1
|
|
4
|
my ($sh, @args) = @_; |
1192
|
1
|
|
|
|
|
3
|
for(my $i = 0; $i < @{$sh->{rhistory}}; $i++) { |
|
1
|
|
|
|
|
5
|
|
1193
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop ($i+1, ":\n"); |
1194
|
0
|
|
|
|
|
0
|
foreach my $rowref (@{$sh->{rhistory}[$i]}) { |
|
0
|
|
|
|
|
0
|
|
1195
|
0
|
0
|
|
|
|
0
|
$sh->print_buffer_nop (" ", join(", ", map { defined $_ ? $_ : q{undef} }@$rowref), "\n"); |
|
0
|
|
|
|
|
0
|
|
1196
|
|
|
|
|
|
|
} |
1197
|
|
|
|
|
|
|
} |
1198
|
1
|
|
|
|
|
5
|
return; |
1199
|
|
|
|
|
|
|
} |
1200
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
|
1202
|
|
|
|
|
|
|
sub do_get { |
1203
|
26
|
|
|
26
|
|
372
|
my ($sh, $num, @args) = @_; |
1204
|
|
|
|
|
|
|
# If get is called without a number, retrieve the last command. |
1205
|
26
|
100
|
|
|
|
93
|
unless( $num ) { |
1206
|
23
|
|
|
|
|
35
|
$num = ($#{$sh->{chistory}} + 1); |
|
23
|
|
|
|
|
64
|
|
1207
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
} |
1209
|
|
|
|
|
|
|
# Allow for negative history. If called with -1, get the second |
1210
|
|
|
|
|
|
|
# to last command execute, -2 third to last, ... |
1211
|
26
|
100
|
66
|
|
|
146
|
if ($num and $num =~ /^\-\d+$/) { |
1212
|
2
|
|
|
|
|
32
|
$sh->print_buffer_nop("Negative number $num: \n"); |
1213
|
2
|
|
|
|
|
7
|
$num = ($#{$sh->{chistory}} + 1) + $num; |
|
2
|
|
|
|
|
7
|
|
1214
|
2
|
|
|
|
|
9
|
$sh->print_buffer_nop("Changed number $num: \n"); |
1215
|
|
|
|
|
|
|
} |
1216
|
|
|
|
|
|
|
|
1217
|
26
|
50
|
33
|
|
|
314
|
if (!$num or $num !~ /^\d+$/ or !defined($sh->{chistory}->[$num-1])) { |
|
|
|
33
|
|
|
|
|
1218
|
0
|
|
|
|
|
0
|
return $sh->err("No such command number '$num'. Use /chistory to list previous commands."); |
1219
|
|
|
|
|
|
|
} |
1220
|
26
|
|
|
|
|
75
|
$sh->{current_buffer} = $sh->{chistory}->[$num-1]; |
1221
|
26
|
|
|
|
|
106
|
$sh->print_buffer($sh->{current_buffer}); |
1222
|
26
|
|
|
|
|
172
|
return $num; |
1223
|
|
|
|
|
|
|
} |
1224
|
|
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
sub do_perl { |
1227
|
0
|
|
|
0
|
|
0
|
my ($sh, @args) = @_; |
1228
|
0
|
|
|
|
|
0
|
$DBI::Shell::eval::dbh = $sh->{dbh}; |
1229
|
0
|
|
|
|
|
0
|
eval "package DBI::Shell::eval; $sh->{current_buffer}"; |
1230
|
0
|
0
|
|
|
|
0
|
if ($@) { $sh->err("Perl failed: $@") } |
|
0
|
|
|
|
|
0
|
|
1231
|
0
|
|
|
|
|
0
|
return $sh->run_command('clear'); |
1232
|
|
|
|
|
|
|
} |
1233
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
#------------------------------------------------------------- |
1235
|
|
|
|
|
|
|
# Ping the current database connection. |
1236
|
|
|
|
|
|
|
#------------------------------------------------------------- |
1237
|
|
|
|
|
|
|
sub do_ping { |
1238
|
0
|
|
|
0
|
|
0
|
my ($sh, @args) = @_; |
1239
|
|
|
|
|
|
|
return $sh->print_buffer_nop ( |
1240
|
|
|
|
|
|
|
"Connection " |
1241
|
0
|
0
|
|
|
|
0
|
, $sh->{dbh}->ping() == '0' ? 'Is' : 'Is Not' |
1242
|
|
|
|
|
|
|
, " alive\n" ); |
1243
|
|
|
|
|
|
|
} |
1244
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
sub do_edit { |
1246
|
0
|
|
|
0
|
|
0
|
my ($sh, @args) = @_; |
1247
|
|
|
|
|
|
|
|
1248
|
0
|
0
|
0
|
|
|
0
|
$sh->run_command('get', '', $&) if @args and $args[0] =~ /^\d+$/; |
1249
|
0
|
|
0
|
|
|
0
|
$sh->{current_buffer} ||= $sh->{prev_buffer}; |
1250
|
|
|
|
|
|
|
|
1251
|
|
|
|
|
|
|
# Find an area to write a temp file into. |
1252
|
|
|
|
|
|
|
my $tmp_dir = $sh->{tmp_dir} || |
1253
|
|
|
|
|
|
|
$ENV{DBISH_TMP} || # Give people the choice. |
1254
|
|
|
|
|
|
|
$ENV{TMP} || # Is TMP set? |
1255
|
|
|
|
|
|
|
$ENV{TEMP} || # How about TEMP? |
1256
|
|
|
|
|
|
|
$ENV{HOME} || # Look for HOME? |
1257
|
|
|
|
|
|
|
$ENV{HOMEDRIVE} . $ENV{HOMEPATH} || # Last env checked. |
1258
|
0
|
|
0
|
|
|
0
|
"."; # fallback: try to write in current directory. |
1259
|
|
|
|
|
|
|
|
1260
|
0
|
|
0
|
|
|
0
|
my $tmp_file = "$tmp_dir/" . ($sh->{tmp_file} || qq{dbish$$.sql}); |
1261
|
|
|
|
|
|
|
|
1262
|
0
|
0
|
|
|
|
0
|
$sh->log( "using tmp file: $tmp_file" ) if $sh->{debug}; |
1263
|
|
|
|
|
|
|
|
1264
|
0
|
|
|
|
|
0
|
local (*FH); |
1265
|
0
|
0
|
|
|
|
0
|
open(FH, ">$tmp_file") or |
1266
|
|
|
|
|
|
|
$sh->err("Can't create $tmp_file: $!\n", 1); |
1267
|
0
|
0
|
|
|
|
0
|
print FH $sh->{current_buffer} if defined $sh->{current_buffer}; |
1268
|
0
|
0
|
|
|
|
0
|
close(FH) or $sh->err("Can't write $tmp_file: $!\n", 1); |
1269
|
|
|
|
|
|
|
|
1270
|
0
|
|
|
|
|
0
|
my $command = "$sh->{editor} $tmp_file"; |
1271
|
0
|
|
|
|
|
0
|
system($command); |
1272
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
# Read changes back in (editor may have deleted and rewritten file) |
1274
|
0
|
0
|
|
|
|
0
|
open(FH, "<$tmp_file") or $sh->err("Can't open $tmp_file: $!\n"); |
1275
|
0
|
|
|
|
|
0
|
$sh->{current_buffer} = join "", ; |
1276
|
0
|
0
|
|
|
|
0
|
close(FH) or $sh->err( "Close failed: $tmp_file: $!\n" ); |
1277
|
0
|
|
|
|
|
0
|
unlink $tmp_file; |
1278
|
|
|
|
|
|
|
|
1279
|
0
|
|
|
|
|
0
|
return $sh->run_command('current'); |
1280
|
|
|
|
|
|
|
} |
1281
|
|
|
|
|
|
|
|
1282
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
# |
1284
|
|
|
|
|
|
|
# Load a command/file from disk to the current buffer. Currently this |
1285
|
|
|
|
|
|
|
# overwrites the current buffer with the file loaded. This may change |
1286
|
|
|
|
|
|
|
# in the future. |
1287
|
|
|
|
|
|
|
# |
1288
|
|
|
|
|
|
|
sub do_load { |
1289
|
8
|
|
|
8
|
|
34
|
my ($sh, $ufile, @args) = @_; |
1290
|
|
|
|
|
|
|
|
1291
|
8
|
50
|
|
|
|
33
|
unless( $ufile ) { |
1292
|
0
|
|
|
|
|
0
|
$sh->err ( qq{load what file?} ); |
1293
|
0
|
|
|
|
|
0
|
return; |
1294
|
|
|
|
|
|
|
} |
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
# Load file for from sqlpath. |
1297
|
8
|
|
|
|
|
70
|
my $file = $sh->look_for_file($ufile); |
1298
|
|
|
|
|
|
|
|
1299
|
8
|
50
|
|
|
|
43
|
unless( $file ) { |
1300
|
0
|
|
|
|
|
0
|
$sh->err( qq{Unable to locate file $ufile} ); |
1301
|
0
|
|
|
|
|
0
|
return; |
1302
|
|
|
|
|
|
|
} |
1303
|
|
|
|
|
|
|
|
1304
|
8
|
50
|
|
|
|
116
|
unless( -f $file ) { |
1305
|
0
|
0
|
|
|
|
0
|
$file = q{'undef'} unless $file; |
1306
|
0
|
|
|
|
|
0
|
$sh->err( qq{Can't load $file: $!} ); |
1307
|
0
|
|
|
|
|
0
|
return; |
1308
|
|
|
|
|
|
|
} |
1309
|
|
|
|
|
|
|
|
1310
|
8
|
50
|
|
|
|
74
|
$sh->log("Loading: $ufile : $file") if $sh->{debug}; |
1311
|
8
|
|
|
|
|
35
|
local (*FH); |
1312
|
8
|
50
|
|
|
|
326
|
open(FH, "$file") or $sh->err("Can't open $file: $!"); |
1313
|
8
|
|
|
|
|
274
|
$sh->{current_buffer} = join "", ; |
1314
|
8
|
50
|
|
|
|
116
|
close(FH) or $sh->err( "close$file failed: $!" ); |
1315
|
|
|
|
|
|
|
|
1316
|
8
|
|
|
|
|
149
|
return $sh->run_command('current'); |
1317
|
|
|
|
|
|
|
} |
1318
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
sub do_save { |
1320
|
1
|
|
|
1
|
|
4
|
my ($sh, $file, @args) = @_; |
1321
|
|
|
|
|
|
|
|
1322
|
1
|
50
|
|
|
|
4
|
unless( $file ) { |
1323
|
0
|
|
|
|
|
0
|
$sh->err ( qq{save to what file?} ); |
1324
|
0
|
|
|
|
|
0
|
return; |
1325
|
|
|
|
|
|
|
} |
1326
|
|
|
|
|
|
|
|
1327
|
1
|
50
|
|
|
|
4
|
$sh->log("Saving... ") if $sh->{debug}; |
1328
|
1
|
|
|
|
|
3
|
local (*FH); |
1329
|
1
|
50
|
|
|
|
121
|
open(FH, "> $file") or $sh->err("Can't open $file: $!"); |
1330
|
1
|
|
|
|
|
25
|
print FH $sh->{current_buffer}; |
1331
|
1
|
50
|
|
|
|
13
|
close(FH) or $sh->err( "close$file failed: $!" ); |
1332
|
|
|
|
|
|
|
|
1333
|
1
|
50
|
|
|
|
4
|
$sh->log(" $file") if $sh->{debug}; |
1334
|
1
|
|
|
|
|
4
|
return $sh->run_command('current'); |
1335
|
|
|
|
|
|
|
} |
1336
|
|
|
|
|
|
|
|
1337
|
|
|
|
|
|
|
# |
1338
|
|
|
|
|
|
|
# run: combines load and go. |
1339
|
|
|
|
|
|
|
# |
1340
|
|
|
|
|
|
|
sub do_run { |
1341
|
0
|
|
|
0
|
|
0
|
my ($sh, $file, @args) = @_; |
1342
|
0
|
0
|
|
|
|
0
|
return unless( ! $sh->do_load( $file ) ); |
1343
|
0
|
0
|
|
|
|
0
|
$sh->log( "running $file" ) if $sh->{debug}; |
1344
|
0
|
0
|
|
|
|
0
|
$sh->run_command('go') if $sh->{current_buffer}; |
1345
|
0
|
|
|
|
|
0
|
return; |
1346
|
|
|
|
|
|
|
} |
1347
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
sub do_drivers { |
1349
|
1
|
|
|
1
|
|
4
|
my ($sh, @args) = @_; |
1350
|
1
|
|
|
|
|
3
|
$sh->log("Available drivers:"); |
1351
|
1
|
|
|
|
|
17
|
my @drivers = DBI->available_drivers; |
1352
|
1
|
|
|
|
|
424
|
foreach my $driver (sort @drivers) { |
1353
|
7
|
|
|
|
|
37
|
$sh->log("\t$driver"); |
1354
|
|
|
|
|
|
|
} |
1355
|
1
|
|
|
|
|
8
|
return; |
1356
|
|
|
|
|
|
|
} |
1357
|
|
|
|
|
|
|
|
1358
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
# $sth = $dbh->column_info( $catalog, $schema, $table, $column ); |
1360
|
|
|
|
|
|
|
|
1361
|
|
|
|
|
|
|
sub do_col_info { |
1362
|
0
|
|
|
0
|
|
0
|
my ($sh, @args) = @_; |
1363
|
0
|
|
|
|
|
0
|
my $dbh = $sh->{dbh}; |
1364
|
|
|
|
|
|
|
|
1365
|
0
|
0
|
|
|
|
0
|
$sh->log( "col_info( " . join( " ", @args ) . ")" ) if $sh->{debug}; |
1366
|
|
|
|
|
|
|
|
1367
|
0
|
|
|
|
|
0
|
my $sth = $dbh->column_info(@args); |
1368
|
0
|
0
|
|
|
|
0
|
unless(ref $sth) { |
1369
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop ("Driver has not implemented the column_info() method\n"); |
1370
|
0
|
|
|
|
|
0
|
$sth = undef; |
1371
|
0
|
|
|
|
|
0
|
return; |
1372
|
|
|
|
|
|
|
} |
1373
|
0
|
|
|
|
|
0
|
return $sh->sth_go($sth, 0, NO_RH); |
1374
|
|
|
|
|
|
|
} |
1375
|
|
|
|
|
|
|
|
1376
|
|
|
|
|
|
|
|
1377
|
|
|
|
|
|
|
sub do_type_info { |
1378
|
1
|
|
|
1
|
|
4
|
my ($sh, @args) = @_; |
1379
|
1
|
|
|
|
|
3
|
my $dbh = $sh->{dbh}; |
1380
|
1
|
|
|
|
|
6
|
my $ti = $dbh->type_info_all; |
1381
|
1
|
|
|
|
|
20
|
my $ti_cols = shift @$ti; |
1382
|
1
|
|
|
|
|
7
|
my @names = sort { $ti_cols->{$a} <=> $ti_cols->{$b} } keys %$ti_cols; |
|
41
|
|
|
|
|
69
|
|
1383
|
1
|
|
|
|
|
12
|
my $sth = $sh->prepare_from_data("type_info", $ti, \@names); |
1384
|
1
|
|
|
|
|
6
|
return $sh->sth_go($sth, 0, NO_RH); |
1385
|
|
|
|
|
|
|
} |
1386
|
|
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
sub do_describe { |
1388
|
0
|
|
|
0
|
|
0
|
my ($sh, $tab, @argv) = @_; |
1389
|
0
|
|
|
|
|
0
|
my $dbh = $sh->{dbh}; |
1390
|
|
|
|
|
|
|
|
1391
|
|
|
|
|
|
|
# Table to describe? |
1392
|
0
|
0
|
|
|
|
0
|
return $sh->print_buffer_nop( "Describe what?\n" ) unless (defined $tab); |
1393
|
|
|
|
|
|
|
|
1394
|
|
|
|
|
|
|
# First attempt the advanced describe using column_info |
1395
|
|
|
|
|
|
|
# $sth = $dbh->column_info( $catalog, $schema, $table, $column ); |
1396
|
|
|
|
|
|
|
#$sh->log( "col_info( " . join( " ", @args ) . ")" ) if $sh->{debug}; |
1397
|
|
|
|
|
|
|
|
1398
|
|
|
|
|
|
|
# Need to determine which columns to include with the describe command. |
1399
|
|
|
|
|
|
|
# TABLE_CAT,TABLE_SCHEM,TABLE_NAME,COLUMN_NAME, |
1400
|
|
|
|
|
|
|
# DATA_TYPE,TYPE_NAME,COLUMN_SIZE,BUFFER_LENGTH, |
1401
|
|
|
|
|
|
|
# DECIMAL_DIGITS,NUM_PREC_RADIX,NULLABLE, |
1402
|
|
|
|
|
|
|
# REMARKS,COLUMN_DEF,SQL_DATA_TYPE, |
1403
|
|
|
|
|
|
|
# SQL_DATETIME_SUB,CHAR_OCTET_LENGTH,ORDINAL_POSITION, |
1404
|
|
|
|
|
|
|
# IS_NULLABLE |
1405
|
|
|
|
|
|
|
# |
1406
|
|
|
|
|
|
|
# desc_format: partbox |
1407
|
|
|
|
|
|
|
# desc_show_long: 1 |
1408
|
|
|
|
|
|
|
# desc_show_remarks: 1 |
1409
|
|
|
|
|
|
|
|
1410
|
0
|
|
|
|
|
0
|
my $schema; |
1411
|
0
|
0
|
|
|
|
0
|
if ($tab =~ /^([^.]+)\.([^.]+)$/) { |
1412
|
0
|
|
|
|
|
0
|
$schema = $1; |
1413
|
0
|
|
|
|
|
0
|
$tab = $2; |
1414
|
|
|
|
|
|
|
} |
1415
|
0
|
|
|
|
|
0
|
my @names = (); |
1416
|
|
|
|
|
|
|
|
1417
|
|
|
|
|
|
|
# Determine if the short or long display type is used |
1418
|
0
|
0
|
0
|
|
|
0
|
if (exists $sh->{desc_show_long} and $sh->{desc_show_long} == 1) { |
1419
|
|
|
|
|
|
|
|
1420
|
0
|
0
|
0
|
|
|
0
|
if (exists $sh->{desc_show_columns} and defined |
1421
|
|
|
|
|
|
|
$sh->{desc_show_columns}) { |
1422
|
0
|
0
|
|
|
|
0
|
@names = map { defined $_ ? uc $_ : () } split( /[,\s+]/, $sh->{desc_show_columns}); |
|
0
|
|
|
|
|
0
|
|
1423
|
0
|
0
|
|
|
|
0
|
unless (@names) { # List of columns is empty |
1424
|
0
|
|
|
|
|
0
|
$sh->err ( qq{option desc_show_columns contains an empty list, using default} ); |
1425
|
|
|
|
|
|
|
# set the empty list to undef |
1426
|
0
|
|
|
|
|
0
|
$sh->{desc_show_columns} = undef; |
1427
|
0
|
|
|
|
|
0
|
@names = (); |
1428
|
0
|
|
|
|
|
0
|
push @names, qw/COLUMN_NAME DATA_TYPE TYPE_NAME COLUMN_SIZE PK |
1429
|
|
|
|
|
|
|
NULLABLE COLUMN_DEF IS_NULLABLE/; |
1430
|
|
|
|
|
|
|
} |
1431
|
|
|
|
|
|
|
} else { |
1432
|
0
|
|
|
|
|
0
|
push @names, qw/COLUMN_NAME DATA_TYPE TYPE_NAME COLUMN_SIZE PK |
1433
|
|
|
|
|
|
|
NULLABLE COLUMN_DEF IS_NULLABLE/; |
1434
|
|
|
|
|
|
|
} |
1435
|
|
|
|
|
|
|
} else { |
1436
|
0
|
|
|
|
|
0
|
push @names, qw/COLUMN_NAME TYPE_NAME NULLABLE PK/; |
1437
|
|
|
|
|
|
|
} |
1438
|
|
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
# my @names = qw/COLUMN_NAME DATA_TYPE NULLABLE PK/; |
1440
|
|
|
|
|
|
|
push @names, q{REMARKS} |
1441
|
|
|
|
|
|
|
if (exists $sh->{desc_show_remarks} |
1442
|
|
|
|
|
|
|
and $sh->{desc_show_remarks} == 1 |
1443
|
0
|
0
|
0
|
|
|
0
|
and (not grep { m/REMARK/i } @names)); |
|
0
|
|
0
|
|
|
0
|
|
1444
|
|
|
|
|
|
|
|
1445
|
0
|
|
|
|
|
0
|
my $sth = $dbh->column_info(undef, $schema, $tab, '%'); |
1446
|
|
|
|
|
|
|
|
1447
|
0
|
0
|
|
|
|
0
|
if (ref $sth) { |
1448
|
|
|
|
|
|
|
|
1449
|
|
|
|
|
|
|
# Only attempt the primary_key lookup if using the column_info call. |
1450
|
|
|
|
|
|
|
|
1451
|
0
|
|
|
|
|
0
|
my %pk_cols; |
1452
|
0
|
|
|
|
|
0
|
eval { |
1453
|
0
|
|
|
|
|
0
|
my @key_column_names = $dbh->primary_key( undef, undef, $tab ); |
1454
|
|
|
|
|
|
|
# Convert the column names to lower case for matching |
1455
|
0
|
|
|
|
|
0
|
foreach my $idx (0 ..$#key_column_names) { |
1456
|
0
|
|
|
|
|
0
|
$pk_cols{lc($key_column_names[$idx])} = $idx; |
1457
|
|
|
|
|
|
|
} |
1458
|
|
|
|
|
|
|
}; |
1459
|
|
|
|
|
|
|
|
1460
|
0
|
|
|
|
|
0
|
my @t_data = (); # An array of arrays |
1461
|
|
|
|
|
|
|
|
1462
|
0
|
|
|
|
|
0
|
while (my $row = $sth->fetchrow_hashref() ) { |
1463
|
|
|
|
|
|
|
|
1464
|
0
|
|
|
|
|
0
|
my $col_name = $row->{COLUMN_NAME}; |
1465
|
0
|
|
|
|
|
0
|
my $col_name_lc = lc $col_name; |
1466
|
|
|
|
|
|
|
|
1467
|
|
|
|
|
|
|
# Use the Type name, unless undefined, they use the data type |
1468
|
|
|
|
|
|
|
# value. TODO: Change to resolve the data_type to an ANSI data |
1469
|
|
|
|
|
|
|
# type ... SQL_ |
1470
|
0
|
|
0
|
|
|
0
|
my $type = $row->{TYPE_NAME} || $row->{DATA_TYPE}; |
1471
|
|
|
|
|
|
|
|
1472
|
0
|
0
|
|
|
|
0
|
if (defined $row->{COLUMN_SIZE}) { |
1473
|
0
|
|
|
|
|
0
|
$type .= "(" . $row->{COLUMN_SIZE} . ")"; |
1474
|
|
|
|
|
|
|
} |
1475
|
0
|
0
|
|
|
|
0
|
my $is_pk = $pk_cols{$col_name_lc} if exists $pk_cols{$col_name_lc}; |
1476
|
|
|
|
|
|
|
|
1477
|
0
|
|
|
|
|
0
|
my @out_row; |
1478
|
0
|
|
|
|
|
0
|
foreach my $dcol (@names) { |
1479
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
# Add primary key |
1481
|
0
|
0
|
|
|
|
0
|
if ($dcol eq q{PK}) { |
1482
|
0
|
0
|
|
|
|
0
|
push @out_row, defined $is_pk ? $is_pk : q{}; |
1483
|
0
|
|
|
|
|
0
|
next; |
1484
|
|
|
|
|
|
|
} |
1485
|
0
|
0
|
0
|
|
|
0
|
if ($dcol eq q{TYPE_NAME} and |
|
|
|
0
|
|
|
|
|
1486
|
|
|
|
|
|
|
(exists $sh->{desc_show_long} and $sh->{desc_show_long} == 0)) { |
1487
|
0
|
|
0
|
|
|
0
|
my $type = $row->{TYPE_NAME} || $row->{DATA_TYPE}; |
1488
|
0
|
0
|
|
|
|
0
|
if (defined $row->{COLUMN_SIZE}) { |
1489
|
0
|
|
|
|
|
0
|
$type .= "(" . $row->{COLUMN_SIZE} . ")"; |
1490
|
|
|
|
|
|
|
} |
1491
|
0
|
|
|
|
|
0
|
push @out_row, $type; |
1492
|
0
|
|
|
|
|
0
|
next; |
1493
|
|
|
|
|
|
|
} |
1494
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
# Put a blank if not defined. |
1496
|
0
|
0
|
|
|
|
0
|
push @out_row, defined $row->{$dcol} ? $row->{$dcol} : q{}; |
1497
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
# push(my @out_row |
1499
|
|
|
|
|
|
|
# , $col_name |
1500
|
|
|
|
|
|
|
# , $type |
1501
|
|
|
|
|
|
|
# , sprintf( "%4s", ($row->{NULLABLE} eq 0 ? q{N}: q{Y})) |
1502
|
|
|
|
|
|
|
# ); |
1503
|
|
|
|
|
|
|
|
1504
|
|
|
|
|
|
|
# push @out_row, defined $row->{REMARKS} ? $row->{REMARKS} : q{} |
1505
|
|
|
|
|
|
|
# if (exists $sh->{desc_show_remarks} |
1506
|
|
|
|
|
|
|
# and $sh->{desc_show_remarks} == 1); |
1507
|
|
|
|
|
|
|
} |
1508
|
|
|
|
|
|
|
|
1509
|
0
|
|
|
|
|
0
|
push @t_data, \@out_row; |
1510
|
|
|
|
|
|
|
} |
1511
|
|
|
|
|
|
|
|
1512
|
0
|
|
|
|
|
0
|
$sth->finish; # Complete the handler from column_info |
1513
|
|
|
|
|
|
|
|
1514
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
# Create a new statement handler from the data and names. |
1516
|
0
|
|
|
|
|
0
|
$sth = $sh->prepare_from_data("describe", \@t_data, \@names); |
1517
|
|
|
|
|
|
|
|
1518
|
|
|
|
|
|
|
# Use the built in formatter to handle data. |
1519
|
|
|
|
|
|
|
|
1520
|
0
|
0
|
|
|
|
0
|
my $mode = exists $sh->{desc_format} ? $sh->{desc_format} : 'partbox'; |
1521
|
0
|
|
|
|
|
0
|
my $class = eval { DBI::Format->formatter($mode,1) }; |
|
0
|
|
|
|
|
0
|
|
1522
|
0
|
0
|
|
|
|
0
|
unless ($class) { |
1523
|
0
|
|
|
|
|
0
|
return $sh->alert("Unable to select '$mode': $@"); |
1524
|
|
|
|
|
|
|
} |
1525
|
|
|
|
|
|
|
|
1526
|
0
|
|
|
|
|
0
|
my $display = $class->new($sh); |
1527
|
|
|
|
|
|
|
|
1528
|
0
|
|
0
|
|
|
0
|
$display->header($sth, $sh->{out_fh}||\*STDOUT, $sh->{seperator}); |
1529
|
|
|
|
|
|
|
|
1530
|
0
|
|
|
|
|
0
|
my $i = 0; |
1531
|
|
|
|
|
|
|
OUT_ROWS: |
1532
|
0
|
|
|
|
|
0
|
while (my $rowref = $sth->fetchrow_arrayref()) { |
1533
|
0
|
|
|
|
|
0
|
$i++; |
1534
|
0
|
|
|
|
|
0
|
my $rslt = $display->row($rowref); |
1535
|
|
|
|
|
|
|
} |
1536
|
|
|
|
|
|
|
|
1537
|
0
|
|
|
|
|
0
|
$display->trailer($i); |
1538
|
|
|
|
|
|
|
} |
1539
|
|
|
|
|
|
|
|
1540
|
|
|
|
|
|
|
# |
1541
|
|
|
|
|
|
|
# This is the old method, if the driver doesn't support the DBI column_info |
1542
|
|
|
|
|
|
|
# meta data. |
1543
|
|
|
|
|
|
|
# |
1544
|
0
|
0
|
|
|
|
0
|
$tab = "$schema.$tab" if defined $schema; |
1545
|
0
|
|
|
|
|
0
|
my $sql = qq{select * from $tab where 1 = 0}; |
1546
|
0
|
|
|
|
|
0
|
$sth = $dbh->prepare( $sql ); |
1547
|
0
|
|
|
|
|
0
|
$sth->execute; |
1548
|
0
|
|
|
|
|
0
|
my $cnt = $#{$sth->{NAME}}; # |
|
0
|
|
|
|
|
0
|
|
1549
|
0
|
|
|
|
|
0
|
@names = qw{NAME TYPE NULLABLE}; |
1550
|
0
|
|
|
|
|
0
|
my @ti; |
1551
|
0
|
|
|
|
|
0
|
for ( my $c = 0; $c <= $cnt; $c++ ) { |
1552
|
0
|
|
0
|
|
|
0
|
push( my @j, $sth->{NAME}->[$c] || 0 ); |
1553
|
0
|
|
|
|
|
0
|
my $m = $dbh->type_info($sth->{TYPE}->[$c]); |
1554
|
0
|
|
|
|
|
0
|
my $s; |
1555
|
|
|
|
|
|
|
#print "desc: $c ", $sth->{NAME}->[$c], " ", |
1556
|
|
|
|
|
|
|
#$sth->{TYPE}->[$c], "\n"; |
1557
|
0
|
0
|
|
|
|
0
|
if (ref $m eq 'HASH') { |
|
|
0
|
|
|
|
|
|
1558
|
0
|
|
|
|
|
0
|
$s = $m->{TYPE_NAME}; # . q{ } . $sth->{TYPE}->[$c]; |
1559
|
|
|
|
|
|
|
} elsif (not defined $m) { |
1560
|
|
|
|
|
|
|
# $s = q{undef } . $sth->{TYPE}->[$c]; |
1561
|
0
|
|
|
|
|
0
|
$s = $sth->{TYPE}->[$c]; |
1562
|
|
|
|
|
|
|
} else { |
1563
|
0
|
|
|
|
|
0
|
warn "describe: not good. Not good at all!"; |
1564
|
|
|
|
|
|
|
} |
1565
|
|
|
|
|
|
|
|
1566
|
0
|
0
|
|
|
|
0
|
if (defined $sth->{PRECISION}->[$c]) { |
1567
|
0
|
|
0
|
|
|
0
|
$s .= "(" . $sth->{PRECISION}->[$c] || ''; |
1568
|
|
|
|
|
|
|
$s .= "," . $sth->{SCALE}->[$c] |
1569
|
|
|
|
|
|
|
if ( defined $sth->{SCALE}->[$c] |
1570
|
0
|
0
|
0
|
|
|
0
|
and $sth->{SCALE}->[$c] ne 0); |
1571
|
0
|
|
|
|
|
0
|
$s .= ")"; |
1572
|
|
|
|
|
|
|
} |
1573
|
|
|
|
|
|
|
push(@j, $s, |
1574
|
0
|
0
|
|
|
|
0
|
$sth->{NULLABLE}->[$c] ne 1? qq{N}: qq{Y} ); |
1575
|
0
|
|
|
|
|
0
|
push(@ti,\@j); |
1576
|
|
|
|
|
|
|
} |
1577
|
|
|
|
|
|
|
|
1578
|
0
|
|
|
|
|
0
|
$sth->finish; |
1579
|
0
|
|
|
|
|
0
|
$sth = $sh->prepare_from_data("describe", \@ti, \@names); |
1580
|
0
|
|
|
|
|
0
|
return $sh->sth_go($sth, 0, NO_RH); |
1581
|
|
|
|
|
|
|
} |
1582
|
|
|
|
|
|
|
|
1583
|
|
|
|
|
|
|
|
1584
|
|
|
|
|
|
|
sub prepare_from_data { |
1585
|
1
|
|
|
1
|
|
4
|
my ($sh, $statement, $data, $names, %attr) = @_; |
1586
|
1
|
|
|
|
|
6
|
my $sponge = DBI->connect("dbi:Sponge:","","",{ RaiseError => 1 }); |
1587
|
1
|
|
|
|
|
234
|
my $sth = $sponge->prepare($statement, { rows=>$data, NAME=>$names, %attr }); |
1588
|
1
|
|
|
|
|
128
|
return $sth; |
1589
|
|
|
|
|
|
|
} |
1590
|
|
|
|
|
|
|
|
1591
|
|
|
|
|
|
|
|
1592
|
|
|
|
|
|
|
# Do option: sets or gets an option |
1593
|
|
|
|
|
|
|
sub do_option { |
1594
|
48
|
|
|
48
|
|
4087
|
my ($sh, @args) = @_; |
1595
|
|
|
|
|
|
|
|
1596
|
48
|
|
|
|
|
80
|
my $value; |
1597
|
48
|
100
|
|
|
|
131
|
unless (@args) { |
1598
|
1
|
|
|
|
|
4
|
foreach my $opt (sort keys %{ $sh->{options}}) { |
|
1
|
|
|
|
|
14
|
|
1599
|
26
|
100
|
|
|
|
75
|
$value = (defined $sh->{$opt}) ? $sh->{$opt} : 'undef'; |
1600
|
26
|
|
|
|
|
86
|
$sh->log(sprintf("%20s: %s", $opt, $value)); |
1601
|
|
|
|
|
|
|
} |
1602
|
1
|
|
|
|
|
8
|
return; |
1603
|
|
|
|
|
|
|
} |
1604
|
|
|
|
|
|
|
|
1605
|
47
|
|
|
|
|
71
|
my $options = Text::Abbrev::abbrev(keys %{$sh->{options}}); |
|
47
|
|
|
|
|
401
|
|
1606
|
|
|
|
|
|
|
|
1607
|
|
|
|
|
|
|
# Expecting the form [option=value] [option=] [option] |
1608
|
47
|
|
|
|
|
62458
|
foreach my $opt (@args) { |
1609
|
47
|
|
|
|
|
85
|
my ($opt_name); |
1610
|
47
|
|
|
|
|
342
|
($opt_name, $value) = $opt =~ /^\s*(\w+)(?:=(.*))?/; |
1611
|
47
|
50
|
33
|
|
|
208
|
$opt_name = $options->{$opt_name} || $opt_name if $opt_name; |
1612
|
47
|
50
|
33
|
|
|
281
|
if (!$opt_name || !$sh->{options}->{$opt_name}) { |
1613
|
0
|
|
|
|
|
0
|
$sh->log("Unknown or ambiguous option name '$opt_name'"); |
1614
|
0
|
|
|
|
|
0
|
next; |
1615
|
|
|
|
|
|
|
} |
1616
|
47
|
100
|
|
|
|
149
|
my $crnt = (defined $sh->{$opt_name}) ? $sh->{$opt_name} : 'undef'; |
1617
|
47
|
100
|
|
|
|
164
|
if (not defined $value) { |
1618
|
5
|
|
|
|
|
37
|
$sh->log("/option $opt_name=$crnt"); |
1619
|
5
|
|
|
|
|
32
|
$value = $crnt; |
1620
|
|
|
|
|
|
|
} |
1621
|
|
|
|
|
|
|
else { |
1622
|
|
|
|
|
|
|
# Need to deal with quoted strings. |
1623
|
|
|
|
|
|
|
# 1 while ( $value =~ s/[^\\]?["']//g ); #"' |
1624
|
|
|
|
|
|
|
$sh->log("/option $opt_name=$value (was $crnt)") |
1625
|
42
|
50
|
|
|
|
114
|
unless $sh->{batch}; |
1626
|
42
|
50
|
|
|
|
147
|
$sh->{$opt_name} = ($value eq 'undef' ) ? undef : $value; |
1627
|
|
|
|
|
|
|
} |
1628
|
|
|
|
|
|
|
} |
1629
|
47
|
50
|
|
|
|
1085
|
return (defined $value ? $value : undef); |
1630
|
|
|
|
|
|
|
} |
1631
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
# |
1633
|
|
|
|
|
|
|
# Do prompt: sets or gets a prompt |
1634
|
|
|
|
|
|
|
# |
1635
|
|
|
|
|
|
|
sub do_prompt { |
1636
|
0
|
|
|
0
|
|
0
|
my ($sh, @args) = @_; |
1637
|
|
|
|
|
|
|
|
1638
|
0
|
0
|
|
|
|
0
|
return $sh->log( $sh->{prompt} ) unless (@args); |
1639
|
0
|
|
|
|
|
0
|
return $sh->{prompt} = join( '', @args ); |
1640
|
|
|
|
|
|
|
} |
1641
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
|
1643
|
|
|
|
|
|
|
sub do_table_info { |
1644
|
1
|
|
|
1
|
|
5
|
my ($sh, @args) = @_; |
1645
|
1
|
|
|
|
|
21
|
my $dbh = $sh->{dbh}; |
1646
|
1
|
|
|
|
|
10
|
my $sth = $dbh->table_info(@args); |
1647
|
1
|
50
|
|
|
|
3519
|
unless(ref $sth) { |
1648
|
0
|
|
|
|
|
0
|
$sh->log("Driver has not implemented the table_info() method, ", |
1649
|
|
|
|
|
|
|
"trying tables()\n"); |
1650
|
0
|
|
|
|
|
0
|
my @tables = $dbh->tables(@args); # else try list context |
1651
|
0
|
0
|
|
|
|
0
|
unless (@tables) { |
1652
|
0
|
|
|
|
|
0
|
$sh->print_buffer_nop ("No tables exist ", |
1653
|
|
|
|
|
|
|
"(or driver hasn't implemented the tables method)\n"); |
1654
|
0
|
|
|
|
|
0
|
return; |
1655
|
|
|
|
|
|
|
} |
1656
|
|
|
|
|
|
|
$sth = $sh->prepare_from_data("tables", |
1657
|
0
|
|
|
|
|
0
|
[ map { [ $_ ] } @tables ], |
|
0
|
|
|
|
|
0
|
|
1658
|
|
|
|
|
|
|
[ "TABLE_NAME" ] |
1659
|
|
|
|
|
|
|
); |
1660
|
|
|
|
|
|
|
} |
1661
|
1
|
|
|
|
|
11
|
return $sh->sth_go($sth, 0, NO_RH); |
1662
|
|
|
|
|
|
|
} |
1663
|
|
|
|
|
|
|
|
1664
|
|
|
|
|
|
|
# Support functions. |
1665
|
3
|
|
|
3
|
|
14
|
sub is_spooling ( ) { return shift->{spooling} } |
1666
|
1
|
|
|
1
|
|
4
|
sub spool_on ( ) { return shift->{spooling} = 1 } |
1667
|
1
|
|
|
1
|
|
3
|
sub spool_off ( ) { return shift->{spooling} = 0 } |
1668
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
1; |
1670
|
|
|
|
|
|
|
__END__ |