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