| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package DBIx::Simple::Batch; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
31760
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
29
|
|
|
4
|
1
|
|
|
1
|
|
4
|
use strict; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
32
|
|
|
5
|
1
|
|
|
1
|
|
1023
|
use DBIx::Simple; |
|
|
1
|
|
|
|
|
34425
|
|
|
|
1
|
|
|
|
|
38
|
|
|
6
|
1
|
|
|
1
|
|
1525
|
use SQL::Abstract; |
|
|
1
|
|
|
|
|
12780
|
|
|
|
1
|
|
|
|
|
58
|
|
|
7
|
1
|
|
|
1
|
|
1267
|
use SQL::Interp ':all'; |
|
|
1
|
|
|
|
|
18159
|
|
|
|
1
|
|
|
|
|
10
|
|
|
8
|
1
|
|
|
1
|
|
2166
|
use File::Find::Object; |
|
|
1
|
|
|
|
|
24645
|
|
|
|
1
|
|
|
|
|
2419
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 NAME |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
DBIx::Simple::Batch - An Alternative To ORM and SQL Stored Procedures. |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 VERSION |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
Version 1.69 |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 DOCUMENTATION |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=over 4 |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=item * L |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=item * L |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=back |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=cut |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
our $VERSION = '1.69'; |
|
31
|
|
|
|
|
|
|
our @properties = caller(); |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=head1 METHODS |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head2 new |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
I |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
new B |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=over 3 |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=item L<$path|/"$path"> |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=item L<@connection_string|/"@connection_string"> |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=back |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
new B |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
$db = DBIx::Simple::Batch->new($path); |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
takes 2 arguments |
|
54
|
|
|
|
|
|
|
1st argument - required |
|
55
|
|
|
|
|
|
|
$path - path to folder where sql files are stored |
|
56
|
|
|
|
|
|
|
2nd argument - required |
|
57
|
|
|
|
|
|
|
@connection_string - display help for a specific command |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# Simple Example: |
|
60
|
|
|
|
|
|
|
my $db = DBIx::Simple::Batch->new($path, @connection_string); |
|
61
|
|
|
|
|
|
|
$db->call->folder->file(@parameters); |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
--- |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# Got It? Now lets look at that again in slow-motion |
|
66
|
|
|
|
|
|
|
my $path = '/var/www/app/queries'; |
|
67
|
|
|
|
|
|
|
my @connection_string = ('dbi:SQLite:/var/www/app/foo.db'); |
|
68
|
|
|
|
|
|
|
my $db = DBIx::Simple::Batch->new($path, @connection_string); |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# $path can also take a file pattern which turns on object mapping |
|
71
|
|
|
|
|
|
|
my $path = '/var/www/app/queries/*.sql'; |
|
72
|
|
|
|
|
|
|
my @connection_string = ('dbi:SQLite:/var/www/app/foo.db'); |
|
73
|
|
|
|
|
|
|
my $db = DBIx::Simple::Batch->new($path, @connection_string); |
|
74
|
|
|
|
|
|
|
$db->call->folder->file(...); |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=cut |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub new { |
|
79
|
0
|
|
|
0
|
1
|
|
my ($class, $path, @connect_options) = @_; |
|
80
|
|
|
|
|
|
|
|
|
81
|
0
|
|
|
|
|
|
my $self = {}; |
|
82
|
0
|
|
|
|
|
|
my $file_pattern = ''; |
|
83
|
0
|
|
|
|
|
|
bless $self, $class; |
|
84
|
|
|
|
|
|
|
|
|
85
|
0
|
|
|
|
|
|
$self->{set_names} = {}; |
|
86
|
0
|
|
|
|
|
|
$self->{sets} = []; |
|
87
|
0
|
|
|
|
|
|
$self->{map_key} .= (@{['A'..'Z',0..9]})[rand(36)] |
|
88
|
0
|
|
|
|
|
|
for (1..5); |
|
89
|
|
|
|
|
|
|
|
|
90
|
0
|
0
|
|
|
|
|
if (@connect_options) { |
|
91
|
0
|
0
|
|
|
|
|
$self->{dbix} = DBIx::Simple->connect(@connect_options) |
|
92
|
|
|
|
|
|
|
or die DBIx::Simple->error; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
0
|
|
|
|
|
|
($path, $file_pattern) = $path =~ m/([^\*]+)(\*\.[\w\*]+)?/; |
|
96
|
|
|
|
|
|
|
|
|
97
|
0
|
0
|
0
|
|
|
|
unless (-d $path && -r $path) { |
|
98
|
0
|
|
|
|
|
|
die "The path specified '$path', " . |
|
99
|
|
|
|
|
|
|
"does not exist and/or is not accessible."; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
|
|
102
|
0
|
0
|
|
|
|
|
$self->{path} = $path =~ m/[\\\/]$/ ? $path : "$path/"; |
|
103
|
0
|
|
|
|
|
|
$self->{file_pattern} = $file_pattern; |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# turn-on object mapping |
|
106
|
0
|
0
|
|
|
|
|
if ($self->{file_pattern}) { |
|
107
|
|
|
|
|
|
|
#no warnings 'redefine'; |
|
108
|
|
|
|
|
|
|
#our @package = ("package DBIx::Simple::Batch::Map::$self->{map_key};\n"); |
|
109
|
|
|
|
|
|
|
#our $package_switch = 0; |
|
110
|
|
|
|
|
|
|
#our $new_routine = 'sub new {my $class = shift;my $base = shift;my $self = {};$self->{base} = $base;bless $self, $class;return $self;}'; |
|
111
|
|
|
|
|
|
|
#our $has_folder = 0; |
|
112
|
|
|
|
|
|
|
#find sub { |
|
113
|
|
|
|
|
|
|
# my $file = $_; |
|
114
|
|
|
|
|
|
|
# my $file_path = $File::Find::name; |
|
115
|
|
|
|
|
|
|
# my $directory = $File::Find::dir; |
|
116
|
|
|
|
|
|
|
# my $namespace = 'DBIx::Simple::Batch::Map::' . $self->{map_key} . '::'; |
|
117
|
|
|
|
|
|
|
# |
|
118
|
|
|
|
|
|
|
# # specify package |
|
119
|
|
|
|
|
|
|
# if (-d $file_path) { |
|
120
|
|
|
|
|
|
|
# my $package_name = $file_path; |
|
121
|
|
|
|
|
|
|
# my $prune = $path; $prune =~ s/[\\\/]+$//; |
|
122
|
|
|
|
|
|
|
# $package_name =~ s/^$prune([\\\/])?//; |
|
123
|
|
|
|
|
|
|
# if ($package_name) { |
|
124
|
|
|
|
|
|
|
# $package_name =~ s/[\\\/]/::/g; |
|
125
|
|
|
|
|
|
|
# $package_name =~ s/[^:a-zA-Z0-9]/\_/g; |
|
126
|
|
|
|
|
|
|
# push @package, "$new_routine\n"; |
|
127
|
|
|
|
|
|
|
# my $fqns = "$namespace$package_name"; |
|
128
|
|
|
|
|
|
|
# my $instantiator = "$fqns"."->new(". 'shift->{base}' .")"; |
|
129
|
|
|
|
|
|
|
# my $sub = $package_name; $sub =~ s/.*::([^:]+)$/$1/; |
|
130
|
|
|
|
|
|
|
# push @package, "sub $sub { return $instantiator }\n" . "package $fqns;\n"; |
|
131
|
|
|
|
|
|
|
# $package_switch = 1; |
|
132
|
|
|
|
|
|
|
# $has_folder = 1; |
|
133
|
|
|
|
|
|
|
# } |
|
134
|
|
|
|
|
|
|
# } |
|
135
|
|
|
|
|
|
|
# elsif (-f $file_path) { |
|
136
|
|
|
|
|
|
|
# my $pat = $self->{file_pattern}; |
|
137
|
|
|
|
|
|
|
# if ($pat) { |
|
138
|
|
|
|
|
|
|
# $pat =~ s/^\*\.([\*\w]+)/\.\*\.$1/; |
|
139
|
|
|
|
|
|
|
# } |
|
140
|
|
|
|
|
|
|
# else { |
|
141
|
|
|
|
|
|
|
# $pat = '.*'; |
|
142
|
|
|
|
|
|
|
# } |
|
143
|
|
|
|
|
|
|
# if ($file =~ /$pat/) { |
|
144
|
|
|
|
|
|
|
# my $name = $file; |
|
145
|
|
|
|
|
|
|
# $name =~ s/\.\w+$//g; |
|
146
|
|
|
|
|
|
|
# $name =~ s/\W/\_/g; |
|
147
|
|
|
|
|
|
|
# push(@package, "$new_routine\n") if $package_switch == 1; |
|
148
|
|
|
|
|
|
|
# # |
|
149
|
|
|
|
|
|
|
# $package_switch = 0; |
|
150
|
|
|
|
|
|
|
# push @package, "sub $name ". '{ my $db = shift->{base}; return $db->queue(\''. $file_path .'\')->process(@_); }' ."\n"; |
|
151
|
|
|
|
|
|
|
# } |
|
152
|
|
|
|
|
|
|
# } |
|
153
|
|
|
|
|
|
|
# else { |
|
154
|
|
|
|
|
|
|
# push @package, "$file -> ???\n"; |
|
155
|
|
|
|
|
|
|
# } |
|
156
|
|
|
|
|
|
|
# |
|
157
|
|
|
|
|
|
|
#}, $self->{path}; |
|
158
|
|
|
|
|
|
|
## ugly no folders hack, this whole instantiation should be rewritten |
|
159
|
|
|
|
|
|
|
#unless ($has_folder){ |
|
160
|
|
|
|
|
|
|
# my $package_name = shift(@package); |
|
161
|
|
|
|
|
|
|
# unshift @package, $package_name, $new_routine; |
|
162
|
|
|
|
|
|
|
#} |
|
163
|
0
|
|
|
|
|
|
my $package = "DBIx::Simple::Batch::Map::$self->{map_key}"; |
|
164
|
0
|
|
|
|
|
|
my @objects = (); |
|
165
|
0
|
|
|
|
|
|
my $tree = File::Find::Object->new({}, ($path)); |
|
166
|
0
|
|
|
|
|
|
while (my $o = $tree->next()) { |
|
167
|
0
|
|
|
|
|
|
push @objects, $o; |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
# Build folder objects |
|
170
|
0
|
|
|
|
|
|
foreach my $object (@objects) { |
|
171
|
0
|
0
|
0
|
|
|
|
if (-d $object && -r $object) { |
|
172
|
0
|
|
|
|
|
|
my $base_path = $objects[0]; |
|
173
|
0
|
|
|
|
|
|
my $base_path_re = $base_path; |
|
174
|
0
|
|
|
|
|
|
$base_path_re =~ s/(\W)/\\$1/g; |
|
175
|
0
|
|
|
|
|
|
my $this_path = $object; |
|
176
|
0
|
|
|
|
|
|
my $rel_path = $this_path; |
|
177
|
0
|
|
|
|
|
|
$rel_path =~ s/^$base_path_re//; |
|
178
|
|
|
|
|
|
|
|
|
179
|
0
|
0
|
|
|
|
|
if ($rel_path) { |
|
180
|
0
|
|
|
|
|
|
my $namespace = $rel_path; |
|
181
|
0
|
|
|
|
|
|
$namespace =~ s/[\\\/]/::/g; |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# Build packages |
|
184
|
0
|
0
|
|
|
|
|
eval "package $package$namespace"; die $@ if $@; |
|
|
0
|
|
|
|
|
|
|
|
185
|
0
|
|
|
|
|
|
eval "sub $package$namespace" . '::new { |
|
186
|
|
|
|
|
|
|
my $class = shift; |
|
187
|
|
|
|
|
|
|
my $base = shift; |
|
188
|
|
|
|
|
|
|
my $self = {}; |
|
189
|
|
|
|
|
|
|
$self->{base} = $base; |
|
190
|
|
|
|
|
|
|
bless $self, $class; |
|
191
|
|
|
|
|
|
|
return $self; |
|
192
|
0
|
0
|
|
|
|
|
}'; die $@ if $@; |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
# Build pointers |
|
195
|
0
|
|
|
|
|
|
eval "sub $package$namespace" . ' { |
|
196
|
|
|
|
|
|
|
return ' . "$package$namespace" . '->new(shift->{base}); |
|
197
|
0
|
0
|
|
|
|
|
}'; die $@ if $@; |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
} |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
} |
|
202
|
0
|
0
|
|
|
|
|
eval "package $package"; die $@ if $@; |
|
|
0
|
|
|
|
|
|
|
|
203
|
0
|
|
|
|
|
|
eval "sub $package" . '::new { |
|
204
|
|
|
|
|
|
|
my $class = shift; |
|
205
|
|
|
|
|
|
|
my $base = shift; |
|
206
|
|
|
|
|
|
|
my $self = {}; |
|
207
|
|
|
|
|
|
|
$self->{base} = $base; |
|
208
|
|
|
|
|
|
|
bless $self, $class; |
|
209
|
|
|
|
|
|
|
return $self; |
|
210
|
0
|
0
|
|
|
|
|
}'; die $@ if $@; |
|
211
|
|
|
|
|
|
|
# Build file objects |
|
212
|
0
|
|
|
|
|
|
foreach my $object (@objects) { |
|
213
|
0
|
0
|
0
|
|
|
|
if (-f $object && -r $object) { |
|
214
|
0
|
|
|
|
|
|
my $base_path = $objects[0]; |
|
215
|
0
|
|
|
|
|
|
my $base_path_re = $base_path; |
|
216
|
0
|
|
|
|
|
|
$base_path_re =~ s/(\W)/\\$1/g; |
|
217
|
0
|
|
|
|
|
|
my $this_path = $object; |
|
218
|
0
|
|
|
|
|
|
my $rel_path = $this_path; |
|
219
|
0
|
|
|
|
|
|
$rel_path =~ s/^$base_path_re//; |
|
220
|
|
|
|
|
|
|
|
|
221
|
0
|
0
|
|
|
|
|
if ($rel_path) { |
|
222
|
0
|
|
|
|
|
|
my @structure = split /[\\\/]/, $rel_path; |
|
223
|
0
|
|
|
|
|
|
my $filename = $structure[$#structure]; |
|
224
|
0
|
|
|
|
|
|
my $namespace = $rel_path; |
|
225
|
0
|
|
|
|
|
|
$namespace =~ s/[\\\/]/::/g; |
|
226
|
0
|
|
|
|
|
|
my $pat = $self->{file_pattern}; |
|
227
|
0
|
0
|
|
|
|
|
if ($pat) { |
|
228
|
0
|
|
|
|
|
|
$pat =~ s/^\*\.([\*\w]+)/\.\*\.$1/; |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
else { |
|
231
|
0
|
|
|
|
|
|
$pat = '.*'; |
|
232
|
|
|
|
|
|
|
} |
|
233
|
0
|
0
|
|
|
|
|
if ($namespace =~ /$pat/) { |
|
234
|
0
|
|
|
|
|
|
$namespace =~ s/\.\w+$//g; |
|
235
|
0
|
|
|
|
|
|
$namespace =~ s/[^:a-zA-Z0-9]/\_/g; |
|
236
|
|
|
|
|
|
|
|
|
237
|
0
|
|
|
|
|
|
eval "sub $package$namespace" . ' { |
|
238
|
|
|
|
|
|
|
my $db = shift->{base}; |
|
239
|
|
|
|
|
|
|
return $db->queue(\''. $this_path .'\')->process(@_); |
|
240
|
0
|
0
|
|
|
|
|
}'; die $@ if $@; |
|
241
|
|
|
|
|
|
|
} |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
} |
|
245
|
|
|
|
|
|
|
} |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
# load directives |
|
248
|
0
|
|
|
|
|
|
$self->_load_commands; |
|
249
|
0
|
|
|
|
|
|
return $self; |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=head2 call |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
I |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
call B |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
No arguments. |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
call B |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
$db->call; |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
takes 0 arguments |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
example: |
|
267
|
|
|
|
|
|
|
$db->call->file(...); |
|
268
|
|
|
|
|
|
|
$db->call->folder->file; |
|
269
|
|
|
|
|
|
|
$db->call->folder->folder->file; |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=cut |
|
272
|
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub call { |
|
274
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
275
|
0
|
|
|
|
|
|
return ("DBIx::Simple::Batch::Map::".$self->{map_key})->new($self); |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=head2 constants |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
I
|
|
281
|
|
|
|
|
|
|
be including in the execution of all commands.> |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
constants B |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=over 3 |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=item L<$custom_params|/"\%custom_params"> |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=back |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
constants B |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
$self->constants({ param1 => 1, param2 => 2}); |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
takes 1 argument |
|
296
|
|
|
|
|
|
|
1st argument - required |
|
297
|
|
|
|
|
|
|
\%hashref - display help for a specific command |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
example: |
|
300
|
|
|
|
|
|
|
$self->constants({ id => 1 }); |
|
301
|
|
|
|
|
|
|
Now, in every command `$!id` will be replaced with `1` unless a custom |
|
302
|
|
|
|
|
|
|
param is passed to the process_queue method or call accessors. |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=cut |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
sub constants { |
|
307
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
308
|
0
|
|
|
|
|
|
$self->{constants} = shift; |
|
309
|
|
|
|
|
|
|
} |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# The _load_commands method is an internal method for building the commands |
|
312
|
|
|
|
|
|
|
# dispatch table. |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
sub _load_commands { |
|
315
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
# identify commands that can only contain select statements |
|
318
|
0
|
|
|
|
|
|
$self->{select_required} = ['capture', 'replace', 'declare']; |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
# determine how blank parameters are handled by default |
|
321
|
0
|
|
|
|
|
|
$self->{settings}->{blank} = '0'; |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
#! connect: creates or replaces the database connection |
|
324
|
|
|
|
|
|
|
$self->{commands}->{connect} = sub { |
|
325
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
326
|
0
|
|
|
|
|
|
my @connect_options = $statement =~ m/(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)/g; |
|
327
|
0
|
0
|
|
|
|
|
$connect_options[1] = '' if $connect_options[1] eq '-'; |
|
328
|
0
|
0
|
|
|
|
|
$connect_options[2] = '' if $connect_options[2] eq '-'; |
|
329
|
0
|
0
|
|
|
|
|
if ($connect_options[3]) { |
|
330
|
0
|
|
|
|
|
|
$connect_options[3] = join ",", splice @connect_options, 3; |
|
331
|
0
|
|
|
|
|
|
$connect_options[3] = eval "$connect_options[3]"; |
|
332
|
0
|
0
|
|
|
|
|
$self->{dbix} = DBIx::Simple->connect(@connect_options) |
|
333
|
|
|
|
|
|
|
or die DBIx::Simple->error; |
|
334
|
|
|
|
|
|
|
} |
|
335
|
|
|
|
|
|
|
else { |
|
336
|
0
|
|
|
|
|
|
die $self->_error('Invalid database connection.'); |
|
337
|
|
|
|
|
|
|
} |
|
338
|
0
|
|
|
|
|
|
}; |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
#! capture: stores the resultset for later usage |
|
341
|
|
|
|
|
|
|
$self->{commands}->{capture} = sub { |
|
342
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
343
|
0
|
|
|
|
|
|
$self->{processing}->{resultset} = $self->_execute_query($statement, @parameters); |
|
344
|
0
|
|
|
|
|
|
$self->{sets}->[@{$self->{sets}}] = $self->{processing}->{resultset}->hashes; |
|
|
0
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
# store resultset via name |
|
347
|
0
|
|
|
|
|
|
$self->{set_names}->{$self->{processing}->{set_name}} = |
|
348
|
0
|
0
|
|
|
|
|
$self->{sets}->[(@{$self->{sets}})-1] |
|
349
|
|
|
|
|
|
|
if $self->{processing}->{set_name}; |
|
350
|
0
|
0
|
|
|
|
|
$self->{processing}->{set_name} = '' |
|
351
|
|
|
|
|
|
|
if $self->{processing}->{set_name}; |
|
352
|
0
|
|
|
|
|
|
}; |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
#! execute: execute sql commands only, nothing else, nothing fancy |
|
355
|
|
|
|
|
|
|
$self->{commands}->{execute} = sub { |
|
356
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
357
|
0
|
|
|
|
|
|
$self->{processing}->{resultset} = $self->_execute_query($statement, @parameters); |
|
358
|
0
|
|
|
|
|
|
}; |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
#! proceed: evaluates the statement passed (perl code) for truth, if true, it continues if false it |
|
361
|
|
|
|
|
|
|
# skips to the next proceed command or until the end of the sql file. |
|
362
|
|
|
|
|
|
|
$self->{commands}->{proceed} = sub { |
|
363
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
364
|
0
|
0
|
|
|
|
|
if (@parameters) { |
|
365
|
0
|
|
|
|
|
|
foreach my $parameter (@parameters) { |
|
366
|
0
|
0
|
|
|
|
|
$parameter = $self->{settings}->{blank} unless defined $parameter; |
|
367
|
0
|
|
|
|
|
|
$statement =~ s/\?/$parameter/; |
|
368
|
|
|
|
|
|
|
} |
|
369
|
|
|
|
|
|
|
} |
|
370
|
0
|
0
|
|
|
|
|
$self->{processing}->{skip_switch} = eval $statement ? 0 : 1; |
|
371
|
0
|
|
|
|
|
|
}; |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
#! ifvalid: a synonym for proceed |
|
374
|
0
|
|
|
|
|
|
$self->{commands}->{ifvalid} = $self->{commands}->{proceed}; |
|
375
|
0
|
|
|
|
|
|
$self->{commands}->{validif} = $self->{commands}->{proceed}; |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
#! replace: replaces parameters with the data from the last row of the resultset |
|
378
|
|
|
|
|
|
|
$self->{commands}->{replace} = sub { |
|
379
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
380
|
0
|
|
|
|
|
|
$self->{processing}->{resultset} = $self->_execute_query($statement, @parameters); |
|
381
|
0
|
|
|
|
|
|
$self->{processing}->{parameters} = @{$self->{processing}->{resultset}->array}; |
|
|
0
|
|
|
|
|
|
|
|
382
|
0
|
|
|
|
|
|
}; |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
#! include: processes another (sql) text file |
|
385
|
|
|
|
|
|
|
$self->{commands}->{include} = sub { |
|
386
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
387
|
0
|
|
|
|
|
|
my ($sub_sqlfile, $placeholders) = split /\s/, $statement; |
|
388
|
0
|
0
|
|
|
|
|
@parameters = split /[\,\s]/, $placeholders if $placeholders; |
|
389
|
0
|
|
|
|
|
|
my $sub = DBIx::Simple::Batch->new($self->{path}, $self->{dbix}->{dbh}); |
|
390
|
0
|
|
|
|
|
|
$sub->queue($self->{path}.$sub_sqlfile)->process_queue(@parameters, |
|
391
|
|
|
|
|
|
|
$self->{processing}->{custom_parameters}); |
|
392
|
|
|
|
|
|
|
# copying sub resultsets |
|
393
|
0
|
0
|
|
|
|
|
if (keys %{$sub->{set_names}}) { |
|
|
0
|
|
|
|
|
|
|
|
394
|
0
|
|
|
|
|
|
map { |
|
395
|
0
|
|
|
|
|
|
$self->{set_names}->{$_} = $sub->{set_names}->{$_} |
|
396
|
0
|
|
|
|
|
|
} keys %{$sub->{set_names}}; |
|
397
|
|
|
|
|
|
|
} |
|
398
|
0
|
|
|
|
|
|
}; |
|
399
|
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
#! storage: stores sql statements for later |
|
401
|
|
|
|
|
|
|
$self->{commands}->{storage} = sub { |
|
402
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
403
|
0
|
|
|
|
|
|
}; |
|
404
|
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
#! declare: uses an sql select statement to add vairables to the scope for processing |
|
406
|
|
|
|
|
|
|
$self->{commands}->{declare} = sub { |
|
407
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
408
|
0
|
|
|
|
|
|
$self->{processing}->{resultset} = $self->_execute_query($statement, @parameters); |
|
409
|
0
|
|
|
|
|
|
my $results = $self->{processing}->{resultset}->hash; |
|
410
|
0
|
0
|
|
|
|
|
if ($results) { |
|
411
|
0
|
|
|
|
|
|
my %params = %{$results}; |
|
|
0
|
|
|
|
|
|
|
|
412
|
0
|
|
|
|
|
|
while ( my ($key, $val) = each %params ) { |
|
413
|
0
|
|
|
|
|
|
$self->{processing}->{custom_parameters}->{$key} = $val; |
|
414
|
|
|
|
|
|
|
} |
|
415
|
|
|
|
|
|
|
} |
|
416
|
0
|
|
|
|
|
|
}; |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
#! forward: changes the queue position, good for looping |
|
419
|
|
|
|
|
|
|
$self->{commands}->{forward} = sub { |
|
420
|
1
|
|
|
1
|
|
14
|
no warnings; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
2650
|
|
|
421
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
422
|
0
|
|
|
|
|
|
$self->{cursor} = $statement; |
|
423
|
0
|
|
|
|
|
|
next; # purposefully next out of the loop to avoid incrementation. warning should be turned off. |
|
424
|
0
|
|
|
|
|
|
}; |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
#! process: executes a command in the queue by index number |
|
427
|
|
|
|
|
|
|
$self->{commands}->{process} = sub { |
|
428
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
429
|
0
|
|
|
|
|
|
$self->process_command($statement, @parameters); |
|
430
|
0
|
|
|
|
|
|
}; |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
#! examine: dumps the passed sql statement to the screen (should not be left in the sql file) |
|
433
|
|
|
|
|
|
|
$self->{commands}->{examine} = sub { |
|
434
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
435
|
0
|
|
|
|
|
|
my $db = $self->{dbix}->{dbh}; |
|
436
|
0
|
|
|
|
|
|
foreach my $parameter (@parameters) { |
|
437
|
0
|
|
|
|
|
|
my $placeholder = $db->quote($parameter); |
|
438
|
0
|
|
|
|
|
|
$statement =~ s/\?/$placeholder/; |
|
439
|
|
|
|
|
|
|
} |
|
440
|
0
|
|
|
|
|
|
die $self->_error( $statement ); |
|
441
|
0
|
|
|
|
|
|
}; |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
#! setting: configures how the module handles blank parameters |
|
444
|
|
|
|
|
|
|
$self->{commands}->{setting} = sub { |
|
445
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
446
|
0
|
0
|
|
|
|
|
$self->{settings}->{blank} = '0' if (lc($statement) eq 'blank as zero'); |
|
447
|
0
|
0
|
|
|
|
|
$self->{settings}->{blank} = '' if (lc($statement) eq 'blank as blank'); |
|
448
|
0
|
0
|
|
|
|
|
$self->{settings}->{blank} = 'NULL' if (lc($statement) eq 'blank as null'); |
|
449
|
0
|
|
|
|
|
|
}; |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
#! setname: configures how the module handles blank parameters |
|
452
|
|
|
|
|
|
|
$self->{commands}->{setname} = sub { |
|
453
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
454
|
0
|
0
|
|
|
|
|
$self->{processing}->{set_name} = $statement if $statement; |
|
455
|
0
|
|
|
|
|
|
}; |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
#! perl -e: provides access to perl's eval function |
|
458
|
|
|
|
|
|
|
$self->{commands}->{perl} = sub { |
|
459
|
0
|
|
|
0
|
|
|
my ($statement, @parameters) = @_; |
|
460
|
0
|
|
|
|
|
|
$statement =~ s/^\-e//; |
|
461
|
0
|
|
|
|
|
|
eval $statement; |
|
462
|
|
|
|
|
|
|
} |
|
463
|
0
|
|
|
|
|
|
} |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
# The _execute_query method is an internal method for executing queries |
|
466
|
|
|
|
|
|
|
# against the databse in a standardized fashion. |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
sub _execute_query { |
|
469
|
0
|
|
|
0
|
|
|
my ($self, $statement, @parameters) = @_; |
|
470
|
0
|
0
|
|
|
|
|
if ($statement =~ /\$\%/) { |
|
471
|
|
|
|
|
|
|
# find and replace any standard placeholders |
|
472
|
0
|
|
|
|
|
|
my $dbh = $self->{dbix}->dbh; |
|
473
|
0
|
0
|
|
|
|
|
if (@parameters) { |
|
474
|
0
|
|
|
|
|
|
foreach my $param (@parameters) { |
|
475
|
0
|
|
|
|
|
|
my $p = $dbh->quote($param); |
|
476
|
0
|
|
|
|
|
|
$statement =~ s/\?/$p/; |
|
477
|
|
|
|
|
|
|
} |
|
478
|
|
|
|
|
|
|
} |
|
479
|
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
# process sql::interp style queries, *new*, experimental |
|
481
|
0
|
|
|
|
|
|
my @params = $statement =~ /\$\%([a-z0-9A-Z\_\-]+)/g; |
|
482
|
0
|
|
|
|
|
|
my @sql = split /\,/, $statement; |
|
483
|
0
|
|
|
|
|
|
foreach my $term (@sql) { $term =~ s/(^\s+|\s+$)//; |
|
|
0
|
|
|
|
|
|
|
|
484
|
0
|
0
|
|
|
|
|
if ($term =~ /^\$\%([a-z0-9A-Z\_\-]+)$/) { |
|
485
|
0
|
|
|
|
|
|
my $param = $self->{processing}->{custom_parameters}->{$1}; |
|
486
|
0
|
0
|
|
|
|
|
$term = ref($param) ? $param : \$param; |
|
487
|
|
|
|
|
|
|
} |
|
488
|
|
|
|
|
|
|
} |
|
489
|
0
|
|
|
|
|
|
($statement, @parameters) = sql_interp(@sql); |
|
490
|
0
|
0
|
|
|
|
|
my $resultset = $self->{dbix}->query( $statement, @parameters ) or |
|
491
|
|
|
|
|
|
|
die $self->_error(undef, @parameters); |
|
492
|
0
|
|
|
|
|
|
return $resultset; |
|
493
|
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
} |
|
495
|
|
|
|
|
|
|
else { |
|
496
|
0
|
0
|
|
|
|
|
my $resultset = $self->{dbix}->query( $statement, @parameters ) or |
|
497
|
|
|
|
|
|
|
die $self->_error(undef, @parameters); |
|
498
|
0
|
|
|
|
|
|
return $resultset; |
|
499
|
|
|
|
|
|
|
} |
|
500
|
|
|
|
|
|
|
} |
|
501
|
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
# The _error method is an internal method that dies with a standardized |
|
503
|
|
|
|
|
|
|
# error message. |
|
504
|
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
sub _error { |
|
506
|
0
|
|
|
0
|
|
|
my ( $self, $message, @parameters ) = @_; |
|
507
|
0
|
|
0
|
|
|
|
my $error_message = ref($self) |
|
508
|
|
|
|
|
|
|
. " - sql file $self->{file} processing failed or is being examined,\n" |
|
509
|
|
|
|
|
|
|
. ($message || "database error") . "."; |
|
510
|
0
|
0
|
|
|
|
|
if (ref($self->{cmds}) eq "ARRAY") { |
|
511
|
0
|
0
|
0
|
|
|
|
$error_message .= " \nPoint of failure, command number " |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
. ( $self->{cursor} || '0' ) . " [" |
|
513
|
|
|
|
|
|
|
. ( $self->{cmds} ? $self->{cmds}->[ $self->{cursor} ]->{command} : '' ) |
|
514
|
|
|
|
|
|
|
. "] " |
|
515
|
|
|
|
|
|
|
. ( |
|
516
|
|
|
|
|
|
|
$self->{cmds}->[ $self->{cursor} ]->{statement} |
|
517
|
|
|
|
|
|
|
? ( "and statement \n(" |
|
518
|
|
|
|
|
|
|
. substr( $self->{cmds}->[ $self->{cursor} ]->{statement}, 0, 20 ) |
|
519
|
|
|
|
|
|
|
. "...) " ) |
|
520
|
|
|
|
|
|
|
: " " |
|
521
|
|
|
|
|
|
|
) |
|
522
|
|
|
|
|
|
|
. ( @parameters ? ( "using " . join( ', ', @parameters ) . " " ) : "" ) |
|
523
|
|
|
|
|
|
|
. "at $properties[1]" |
|
524
|
|
|
|
|
|
|
. " on line $properties[2], " |
|
525
|
|
|
|
|
|
|
. ( $message || $self->{dbix}->error || "Check the sql file for errors" ) |
|
526
|
|
|
|
|
|
|
. "."; |
|
527
|
|
|
|
|
|
|
} |
|
528
|
0
|
|
|
|
|
|
return $error_message; |
|
529
|
|
|
|
|
|
|
} |
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
# The _processor method is an internal methoed that when passed a command |
|
532
|
|
|
|
|
|
|
# hashref, processes the command. |
|
533
|
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
sub _processor { |
|
535
|
0
|
|
|
0
|
|
|
my ($self, $cmdref) = @_; |
|
536
|
0
|
|
|
|
|
|
my $command = $cmdref->{command}; |
|
537
|
0
|
|
|
|
|
|
my $statement = $cmdref->{statement}; |
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
# replace statement placeholders with actual "?" placeholders while building the statement params list |
|
540
|
|
|
|
|
|
|
# my @statement_parameters = map { $self->{processing}->{parameters}[$_] } $statement =~ m/\$(\d+)/g; |
|
541
|
|
|
|
|
|
|
# $self->{processing}->{statement_parameters} = \@statement_parameters; |
|
542
|
|
|
|
|
|
|
# $statement =~ s/\$\d+/\?/g; |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
# reset statement parameters |
|
545
|
0
|
|
|
|
|
|
$self->{processing}->{statement_parameters} = (); |
|
546
|
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
# replace statement placeholders with actual "?" placeholders while building the statement params |
|
548
|
|
|
|
|
|
|
# list using passed or custom parameters |
|
549
|
0
|
|
|
|
|
|
while ($statement =~ m/(\$\!([a-z0-9A-Z\_\-]+))|(\$(\d+(?!\w)))/) { |
|
550
|
0
|
|
|
|
|
|
my $custom = $2; |
|
551
|
0
|
|
|
|
|
|
my $passed = $4; |
|
552
|
|
|
|
|
|
|
# if the found param is a custom param |
|
553
|
0
|
0
|
|
|
|
|
if (defined $custom) { |
|
554
|
0
|
|
|
|
|
|
push @{$self->{processing}->{statement_parameters}}, $self->{processing}->{custom_parameters}->{$custom}; |
|
|
0
|
|
|
|
|
|
|
|
555
|
0
|
|
|
|
|
|
$statement =~ s/\$\!$custom/\?/; |
|
556
|
|
|
|
|
|
|
} |
|
557
|
|
|
|
|
|
|
# if the found param is a passed-in param |
|
558
|
0
|
0
|
|
|
|
|
if (defined $passed) { |
|
559
|
0
|
|
|
|
|
|
push @{$self->{processing}->{statement_parameters}}, $self->{processing}->{parameters}[$passed]; |
|
|
0
|
|
|
|
|
|
|
|
560
|
0
|
|
|
|
|
|
$statement =~ s/\$$passed/\?/; |
|
561
|
|
|
|
|
|
|
} |
|
562
|
|
|
|
|
|
|
} |
|
563
|
|
|
|
|
|
|
|
|
564
|
0
|
0
|
0
|
|
|
|
if ($self->{processing}->{skip_switch} && ( $command ne "proceed" && $command ne "ifvalid" && $command ne "validif" ) ) |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
565
|
|
|
|
|
|
|
{ |
|
566
|
|
|
|
|
|
|
# skip command while skip_switch is turned on |
|
567
|
0
|
|
|
|
|
|
return; |
|
568
|
|
|
|
|
|
|
} |
|
569
|
|
|
|
|
|
|
else |
|
570
|
|
|
|
|
|
|
{ |
|
571
|
|
|
|
|
|
|
# execute command |
|
572
|
0
|
|
|
|
|
|
$self->{commands}->{$command}->($statement, @{$self->{processing}->{statement_parameters}}); |
|
|
0
|
|
|
|
|
|
|
|
573
|
0
|
|
|
|
|
|
return $self->{processing}->{resultset}; |
|
574
|
|
|
|
|
|
|
} |
|
575
|
|
|
|
|
|
|
} |
|
576
|
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
# The _parse_parameters method examines each initially passed in parameter |
|
578
|
|
|
|
|
|
|
# specifically looking for a hashref to add its values to the custom |
|
579
|
|
|
|
|
|
|
# parameters key. |
|
580
|
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
sub _parse_parameters { |
|
582
|
0
|
|
|
0
|
|
|
my ($self, @parameters) = @_; |
|
583
|
|
|
|
|
|
|
# process constants |
|
584
|
0
|
0
|
|
|
|
|
if ($self->{constants}) { |
|
585
|
0
|
0
|
|
|
|
|
if (ref($self->{constants}) eq "ARRAY") { |
|
586
|
0
|
|
|
|
|
|
unshift @parameters, @{$self->{constants}}; |
|
|
0
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
} |
|
588
|
0
|
0
|
|
|
|
|
if (ref($self->{constants}) eq "HASH") { |
|
589
|
0
|
|
|
|
|
|
while (my($key, $val) = each (%{$self->{constants}})) { |
|
|
0
|
|
|
|
|
|
|
|
590
|
0
|
|
|
|
|
|
$self->{processing}->{custom_parameters}->{$key} = $val; |
|
591
|
|
|
|
|
|
|
} |
|
592
|
|
|
|
|
|
|
} |
|
593
|
|
|
|
|
|
|
} |
|
594
|
|
|
|
|
|
|
# normal operation |
|
595
|
0
|
|
|
|
|
|
for (my $i=0; $i < @parameters; $i++) { |
|
596
|
0
|
|
|
|
|
|
my $param = $parameters[$i]; |
|
597
|
0
|
0
|
|
|
|
|
if (ref($param) eq "HASH") { |
|
598
|
0
|
|
|
|
|
|
while (my($key, $val) = each (%{$param})) { |
|
|
0
|
|
|
|
|
|
|
|
599
|
0
|
|
|
|
|
|
$self->{processing}->{custom_parameters}->{$key} = $val; |
|
600
|
|
|
|
|
|
|
} |
|
601
|
0
|
|
|
|
|
|
delete $parameters[$i]; |
|
602
|
|
|
|
|
|
|
} |
|
603
|
|
|
|
|
|
|
} |
|
604
|
0
|
|
|
|
|
|
$self->{processing}->{parameters} = \@parameters; |
|
605
|
0
|
|
|
|
|
|
return $self; |
|
606
|
|
|
|
|
|
|
} |
|
607
|
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
# The _parse_sqlfile method scans the passed (sql) text file and returns |
|
609
|
|
|
|
|
|
|
# a list of sql statement queue objects. |
|
610
|
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
sub _parse_sqlfile { |
|
612
|
0
|
|
|
0
|
|
|
my ($self, $sqlfile) = @_; |
|
613
|
0
|
|
|
|
|
|
my (@lines, @statements); |
|
614
|
|
|
|
|
|
|
# open file and fetch commands |
|
615
|
0
|
|
|
|
|
|
$self->{file} = $sqlfile; |
|
616
|
0
|
0
|
|
|
|
|
open (SQL, "$sqlfile") || die $self->_error( "Could'nt open $sqlfile sql file" ); |
|
617
|
0
|
|
|
|
|
|
push @lines, $_ while(); |
|
618
|
0
|
0
|
|
|
|
|
close SQL || die $self->_error( "Could'nt close $sqlfile sql file" ); |
|
619
|
|
|
|
|
|
|
# attempt to parse commands w/multi-line sql support |
|
620
|
0
|
|
|
|
|
|
my $use_mlsql = 0; |
|
621
|
0
|
|
|
|
|
|
my $mlcmd = ''; |
|
622
|
0
|
|
|
|
|
|
my $mlsql = ''; |
|
623
|
0
|
|
|
|
|
|
foreach my $command (@lines) { |
|
624
|
0
|
0
|
|
|
|
|
if ($command =~ /^\!/) { |
|
625
|
0
|
|
|
|
|
|
my @commands = $command =~ /^\!\s(\w+)\s(.*)/; |
|
626
|
0
|
0
|
|
|
|
|
if (grep ( $commands[0] eq $_, keys %{$self->{commands}})) { |
|
|
0
|
|
|
|
|
|
|
|
627
|
0
|
0
|
|
|
|
|
if ($commands[1] =~ /^\{/) { |
|
628
|
0
|
|
|
|
|
|
$use_mlsql = 1; |
|
629
|
0
|
|
|
|
|
|
$mlcmd = $commands[0]; |
|
630
|
0
|
|
|
|
|
|
next; |
|
631
|
|
|
|
|
|
|
} |
|
632
|
|
|
|
|
|
|
else { |
|
633
|
0
|
|
|
|
|
|
push @statements, { "command" => "$commands[0]", "statement" => "$commands[1]" }; |
|
634
|
|
|
|
|
|
|
} |
|
635
|
|
|
|
|
|
|
} |
|
636
|
|
|
|
|
|
|
} |
|
637
|
0
|
0
|
|
|
|
|
if ( $use_mlsql == 1 ) { |
|
638
|
0
|
0
|
|
|
|
|
if ( $command !~ /^\}$/ ) { |
|
639
|
0
|
|
|
|
|
|
$mlsql .= $command; |
|
640
|
0
|
|
|
|
|
|
next; |
|
641
|
|
|
|
|
|
|
} |
|
642
|
|
|
|
|
|
|
else { |
|
643
|
0
|
|
|
|
|
|
push @statements, { "command" => "$mlcmd", "statement" => "$mlsql" }; |
|
644
|
0
|
|
|
|
|
|
$use_mlsql = 0; |
|
645
|
0
|
|
|
|
|
|
$mlcmd = ''; |
|
646
|
0
|
|
|
|
|
|
$mlsql = ''; |
|
647
|
|
|
|
|
|
|
} |
|
648
|
|
|
|
|
|
|
} |
|
649
|
|
|
|
|
|
|
} |
|
650
|
|
|
|
|
|
|
# validate statements |
|
651
|
0
|
|
|
|
|
|
$self->_validate_sqlfile(@statements); |
|
652
|
0
|
|
|
|
|
|
return @statements; |
|
653
|
|
|
|
|
|
|
} |
|
654
|
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
# The _validate_sqlfile method make sure that the supplied (sql) text |
|
656
|
|
|
|
|
|
|
# file conforms to its command(s) rules. |
|
657
|
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
sub _validate_sqlfile { |
|
659
|
0
|
|
|
0
|
|
|
my ($self, @statements) = @_; |
|
660
|
|
|
|
|
|
|
# rule1: replace, and capture can only be used with select statements |
|
661
|
0
|
|
|
|
|
|
foreach my $statement (@statements) { |
|
662
|
0
|
0
|
|
|
|
|
if (grep ( $statement->{command} eq $_, @{$self->{select_required}})) { |
|
|
0
|
|
|
|
|
|
|
|
663
|
0
|
0
|
|
|
|
|
if (lc($statement->{statement}) !~ /^(\s+)?select/) { |
|
664
|
0
|
|
|
|
|
|
die $self->_error( "Validation of the sql file $self->{file} failed. The command ($statement->{command}) can only be used with an SQL (select) statement.", $statement->{statement}); |
|
665
|
|
|
|
|
|
|
} |
|
666
|
|
|
|
|
|
|
} |
|
667
|
|
|
|
|
|
|
} |
|
668
|
|
|
|
|
|
|
} |
|
669
|
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=head2 queue |
|
671
|
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
I
|
|
673
|
|
|
|
|
|
|
of sql statements to be executed and how.> |
|
674
|
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
queue B |
|
676
|
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
=over 3 |
|
678
|
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
=item L<$sql_file|/"$sql_file"> |
|
680
|
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
=back |
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
queue B |
|
684
|
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
$db->queue($sql_file); |
|
686
|
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
takes 1 argument |
|
688
|
|
|
|
|
|
|
1st argument - required |
|
689
|
|
|
|
|
|
|
$sql_file - path to the sql file to process |
|
690
|
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
example: |
|
692
|
|
|
|
|
|
|
$db->queue($sql_file); |
|
693
|
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
=cut |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
sub queue { |
|
697
|
0
|
|
|
0
|
1
|
|
my ($self, $sqlfile) = @_; |
|
698
|
0
|
|
|
|
|
|
my (@statements); |
|
699
|
0
|
|
|
|
|
|
$self->{cmds} = ''; |
|
700
|
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
# set caller data for error reporting |
|
702
|
0
|
|
|
|
|
|
@properties = caller(); |
|
703
|
0
|
|
|
|
|
|
@statements = $self->_parse_sqlfile($sqlfile); |
|
704
|
0
|
|
|
|
|
|
$self->{cmds} = \@statements; |
|
705
|
0
|
|
|
|
|
|
return $self; |
|
706
|
|
|
|
|
|
|
} |
|
707
|
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
=head2 process_queue |
|
709
|
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
I
|
|
711
|
|
|
|
|
|
|
found the (sql) text file.> |
|
712
|
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
process_queue B |
|
714
|
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
=over 3 |
|
716
|
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
=item L<@parameters|/"@parameters"> |
|
718
|
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
=back |
|
720
|
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
process_queue B |
|
722
|
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
$self->process_queue(@parameters); |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
takes 1 argument |
|
726
|
|
|
|
|
|
|
1st argument - required |
|
727
|
|
|
|
|
|
|
@parameters - parameters to be used in parsing the sql file |
|
728
|
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
example: |
|
730
|
|
|
|
|
|
|
$db->process_queue(@parameters); |
|
731
|
|
|
|
|
|
|
$db->process_queue($hashref, @parameters); |
|
732
|
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
process_queue B |
|
734
|
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
=over 3 |
|
736
|
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
=item * process |
|
738
|
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
=back |
|
740
|
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
=cut |
|
742
|
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
sub process_queue { |
|
744
|
0
|
|
|
0
|
1
|
|
my ($self, @parameters) = @_; |
|
745
|
|
|
|
|
|
|
# set caller data for error reporting |
|
746
|
0
|
|
|
|
|
|
@properties = caller(); |
|
747
|
0
|
0
|
|
|
|
|
$self->_parse_parameters(@parameters) if @parameters; |
|
748
|
0
|
|
|
|
|
|
$self->{processing}->{skip_switch} = 0; |
|
749
|
0
|
|
|
|
|
|
$self->{cursor} = 0; |
|
750
|
0
|
0
|
|
|
|
|
if (@{$self->{cmds}}) { |
|
|
0
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
# process sql commands |
|
752
|
0
|
|
|
|
|
|
for (my $i = 0; $self->{cursor} < @{$self->{cmds}}; $i++) { |
|
|
0
|
|
|
|
|
|
|
|
753
|
0
|
|
|
|
|
|
my $cmd = $self->{cmds}->[$self->{cursor}]; |
|
754
|
0
|
0
|
|
|
|
|
if ( grep($cmd->{command} eq $_, keys %{$self->{commands}}) ) |
|
|
0
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
{ |
|
756
|
|
|
|
|
|
|
# process command |
|
757
|
0
|
|
|
|
|
|
$self->_processor($cmd); |
|
758
|
0
|
|
|
|
|
|
$self->{cursor}++; |
|
759
|
|
|
|
|
|
|
} |
|
760
|
|
|
|
|
|
|
} |
|
761
|
0
|
|
|
|
|
|
return $self->{processing}->{resultset}; |
|
762
|
|
|
|
|
|
|
} |
|
763
|
|
|
|
|
|
|
else { |
|
764
|
0
|
|
|
|
|
|
die $self->_error( "File has no commands to process" ); |
|
765
|
|
|
|
|
|
|
} |
|
766
|
0
|
|
|
|
|
|
return $self; |
|
767
|
|
|
|
|
|
|
} |
|
768
|
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
# process_queue synonym |
|
770
|
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
sub process { |
|
772
|
0
|
|
|
0
|
1
|
|
shift->process_queue(@_); |
|
773
|
|
|
|
|
|
|
} |
|
774
|
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
# The sets method provides direct access to the resultsets array or |
|
776
|
|
|
|
|
|
|
# resultsets. |
|
777
|
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
sub sets { |
|
779
|
0
|
|
|
0
|
0
|
|
return shift->{sets}; |
|
780
|
|
|
|
|
|
|
} |
|
781
|
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
=head2 cache |
|
783
|
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
I
|
|
785
|
|
|
|
|
|
|
using the (sql file) capture command and returns the resultset of the |
|
786
|
|
|
|
|
|
|
index or name passed to it or returns 0.> |
|
787
|
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
cache B |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
=over 3 |
|
791
|
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
=item L<$index|/"$index"> |
|
793
|
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
=back |
|
795
|
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
cache B |
|
797
|
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
my $results = $db->cache($index); |
|
799
|
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
takes 1 argument |
|
801
|
|
|
|
|
|
|
1st argument - required |
|
802
|
|
|
|
|
|
|
$index - name or array index of the desired resultset |
|
803
|
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
example: |
|
805
|
|
|
|
|
|
|
my $resultset = $db->cache('new_group'); |
|
806
|
|
|
|
|
|
|
my $resultset = $db->cache(2); |
|
807
|
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
cache B |
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
=over 3 |
|
811
|
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
=item * rs |
|
813
|
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
=back |
|
815
|
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
=cut |
|
817
|
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
sub cache { |
|
819
|
0
|
|
|
0
|
1
|
|
my ($self, $index) = @_; |
|
820
|
0
|
0
|
|
|
|
|
if ($index =~ /^\d+$/) { |
|
821
|
0
|
0
|
|
|
|
|
if ($self->{sets}->[$index]) { |
|
822
|
0
|
|
|
|
|
|
return $self->{sets}->[$index]; |
|
823
|
|
|
|
|
|
|
} |
|
824
|
|
|
|
|
|
|
} |
|
825
|
|
|
|
|
|
|
else { |
|
826
|
0
|
0
|
|
|
|
|
if ($self->{set_names}->{$index}) { |
|
827
|
0
|
|
|
|
|
|
return $self->{set_names}->{$index}; |
|
828
|
|
|
|
|
|
|
} |
|
829
|
|
|
|
|
|
|
} |
|
830
|
0
|
|
|
|
|
|
return 0; |
|
831
|
|
|
|
|
|
|
} |
|
832
|
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
# The rs method is a synonym for the cache method |
|
834
|
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
sub rs { |
|
836
|
0
|
|
|
0
|
1
|
|
return shift->cache(@_); |
|
837
|
|
|
|
|
|
|
} |
|
838
|
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
# The command method is used to queue a command to be processed later by the # # # process_queue method. Takes two arguments, "command" and "sql statement", |
|
840
|
|
|
|
|
|
|
# e.g. command('execute', 'select * from foo'). |
|
841
|
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
sub command { |
|
843
|
0
|
|
|
0
|
0
|
|
my ($self, $command, $statement) = @_; |
|
844
|
0
|
|
|
|
|
|
my @statements = @{$self->{cmds}}; |
|
|
0
|
|
|
|
|
|
|
|
845
|
0
|
|
|
|
|
|
push @statements, { "command" => "$command", "statement" => "$statement" }; |
|
846
|
0
|
|
|
|
|
|
$self->{cmds} = \@statements; |
|
847
|
0
|
|
|
|
|
|
return $self; |
|
848
|
|
|
|
|
|
|
} |
|
849
|
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
# The process_command method allows you to process the indexed sql |
|
851
|
|
|
|
|
|
|
# satements from your sql file individually. It take two argument, the |
|
852
|
|
|
|
|
|
|
# index of the command as it is encountered in the sql file and tries |
|
853
|
|
|
|
|
|
|
# returns a resultset, and any parameters that need to be passed to it. |
|
854
|
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
sub process_command { |
|
856
|
0
|
|
|
0
|
0
|
|
my ($self, $index, @parameters) = @_; |
|
857
|
0
|
|
|
|
|
|
my $cmd = $self->{cmds}->[$index]; |
|
858
|
0
|
0
|
|
|
|
|
if ( grep($cmd->{command} eq $_, keys %{$self->{commands}}) ) |
|
|
0
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
{ |
|
860
|
|
|
|
|
|
|
# process command |
|
861
|
0
|
0
|
|
|
|
|
$self->_parse_parameters(@parameters) if @parameters; |
|
862
|
0
|
|
|
|
|
|
return $self->_processor($cmd); |
|
863
|
|
|
|
|
|
|
} |
|
864
|
|
|
|
|
|
|
} |
|
865
|
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
=head2 clear |
|
867
|
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
I |
|
869
|
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
clear B |
|
871
|
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
No arguments. |
|
873
|
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
clear B |
|
875
|
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
$db->clear; |
|
877
|
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
takes 0 arguments |
|
879
|
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
example: |
|
881
|
|
|
|
|
|
|
$db->clear |
|
882
|
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
=cut |
|
884
|
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
sub clear { |
|
886
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
887
|
0
|
|
|
|
|
|
$self->{cmds} = ''; |
|
888
|
0
|
|
|
|
|
|
$self->{set_names} = {}; |
|
889
|
0
|
|
|
|
|
|
$self->{sets} = []; |
|
890
|
0
|
|
|
|
|
|
$self->{processing}->{resultset} = ''; |
|
891
|
0
|
|
|
|
|
|
$self->{processing}->{skip_switch} = 0; |
|
892
|
0
|
|
|
|
|
|
$self->{processing}->{parameters} = []; |
|
893
|
0
|
|
|
|
|
|
$self->{processing}->{custom_parameters} = {}; |
|
894
|
0
|
|
|
|
|
|
$self->{cursor} = 0; |
|
895
|
|
|
|
|
|
|
|
|
896
|
0
|
|
|
|
|
|
return $self; |
|
897
|
|
|
|
|
|
|
} |
|
898
|
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
=head1 AUTHOR |
|
900
|
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
Al Newkirk, C<< >> |
|
902
|
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
=head1 BUGS |
|
904
|
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
|
906
|
|
|
|
|
|
|
the web interface at L. |
|
907
|
|
|
|
|
|
|
I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. |
|
908
|
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
=head1 SUPPORT |
|
910
|
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
|
912
|
|
|
|
|
|
|
|
|
913
|
|
|
|
|
|
|
perldoc DBIx::Simple::Batch |
|
914
|
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
You can also look for information at: |
|
916
|
|
|
|
|
|
|
|
|
917
|
|
|
|
|
|
|
=over 4 |
|
918
|
|
|
|
|
|
|
|
|
919
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker |
|
920
|
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
L |
|
922
|
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
|
924
|
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
L |
|
926
|
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
=item * CPAN Ratings |
|
928
|
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
L |
|
930
|
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
=item * Search CPAN |
|
932
|
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
L |
|
934
|
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
=back |
|
936
|
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
|
938
|
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
|
940
|
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
Copyright 2009 Al Newkirk. |
|
942
|
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
|
944
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published |
|
945
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License. |
|
946
|
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information. |
|
948
|
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
=cut |
|
950
|
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
1; # End of DBIx::Simple::Batch |