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 |