DBIx-Custom / lib / DBIx / Custom.pm /
Newer Older
934 lines | 22.975kb
cleanup
yuki-kimoto authored on 2009-12-22
1
package DBIx::Custom;
2

            
3
use strict;
4
use warnings;
5

            
remove run_transaction().
yuki-kimoto authored on 2010-01-30
6
use base 'Object::Simple';
many change
yuki-kimoto authored on 2010-02-11
7

            
packaging one directory
yuki-kimoto authored on 2009-11-16
8
use Carp 'croak';
9
use DBI;
10
use DBIx::Custom::Result;
many many changes
yuki-kimoto authored on 2010-04-30
11
use DBIx::Custom::SQLTemplate;
cleanup
yuki-kimoto authored on 2010-02-11
12
use DBIx::Custom::Query;
update document
yuki-kimoto authored on 2010-05-27
13
use Encode qw/encode_utf8 decode_utf8/;
packaging one directory
yuki-kimoto authored on 2009-11-16
14

            
catch up with Object::Simple...
yuki-kimoto authored on 2010-01-18
15
__PACKAGE__->attr('dbh');
cleanup
yuki-kimoto authored on 2010-04-28
16
__PACKAGE__->attr([qw/user password data_source/]);
update document
yuki-kimoto authored on 2010-05-27
17
__PACKAGE__->attr([qw/default_query_filter default_fetch_filter/]);
packaging one directory
yuki-kimoto authored on 2009-11-16
18

            
removed register_format()
yuki-kimoto authored on 2010-05-26
19
__PACKAGE__->dual_attr('filters', default => sub { {} },
20
                                  inherit => 'hash_copy');
21
__PACKAGE__->register_filter(
update document
yuki-kimoto authored on 2010-05-27
22
    encode_utf8 => sub { encode_utf8($_[0]) },
23
    decode_utf8 => sub { decode_utf8($_[0]) }
removed register_format()
yuki-kimoto authored on 2010-05-26
24
);
packaging one directory
yuki-kimoto authored on 2009-11-16
25

            
cleanup
yuki-kimoto authored on 2010-04-28
26
__PACKAGE__->attr(result_class => 'DBIx::Custom::Result');
removed register_format()
yuki-kimoto authored on 2010-05-26
27
__PACKAGE__->attr(sql_template => sub { DBIx::Custom::SQLTemplate->new });
add cache attribute
yuki-kimoto authored on 2010-06-14
28
__PACKAGE__->attr(cache => 1);
removed register_format()
yuki-kimoto authored on 2010-05-26
29

            
packaging one directory
yuki-kimoto authored on 2009-11-16
30
sub connect {
removed register_format()
yuki-kimoto authored on 2010-05-26
31
    my $proto = shift;
32
    
33
    # Create
34
    my $self = ref $proto ? $proto : $proto->new(@_);
update document
yuki-kimoto authored on 2010-01-30
35
    
36
    # Information
packaging one directory
yuki-kimoto authored on 2009-11-16
37
    my $data_source = $self->data_source;
38
    my $user        = $self->user;
39
    my $password    = $self->password;
40
    
update document
yuki-kimoto authored on 2010-01-30
41
    # Connect
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
42
    my $dbh = eval {DBI->connect(
packaging one directory
yuki-kimoto authored on 2009-11-16
43
        $data_source,
44
        $user,
45
        $password,
46
        {
47
            RaiseError => 1,
48
            PrintError => 0,
49
            AutoCommit => 1,
50
        }
51
    )};
52
    
update document
yuki-kimoto authored on 2010-01-30
53
    # Connect error
packaging one directory
yuki-kimoto authored on 2009-11-16
54
    croak $@ if $@;
55
    
update document
yuki-kimoto authored on 2010-01-30
56
    # Database handle
packaging one directory
yuki-kimoto authored on 2009-11-16
57
    $self->dbh($dbh);
update document
yuki-kimoto authored on 2010-01-30
58
    
packaging one directory
yuki-kimoto authored on 2009-11-16
59
    return $self;
60
}
61

            
62
sub disconnect {
63
    my $self = shift;
update document
yuki-kimoto authored on 2010-01-30
64
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
65
    # Disconnect
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
66
    my $ret = eval { $self->dbh->disconnect };
67
    croak $@ if $@;
removed reconnect method
yuki-kimoto authored on 2010-05-28
68
    $self->dbh(undef);
update document
yuki-kimoto authored on 2010-01-30
69
    
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
70
    return $ret;
packaging one directory
yuki-kimoto authored on 2009-11-16
71
}
72

            
removed register_format()
yuki-kimoto authored on 2010-05-26
73
our %VALID_INSERT_ARGS = map { $_ => 1 } qw/table param append filter/;
cleanup insert
yuki-kimoto authored on 2010-04-28
74

            
packaging one directory
yuki-kimoto authored on 2009-11-16
75
sub insert {
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
76
    my ($self, %args) = @_;
removed register_format()
yuki-kimoto authored on 2010-05-26
77

            
cleanup insert
yuki-kimoto authored on 2010-04-28
78
    # Check arguments
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
79
    foreach my $name (keys %args) {
cleanup insert
yuki-kimoto authored on 2010-04-28
80
        croak "\"$name\" is invalid name"
81
          unless $VALID_INSERT_ARGS{$name};
82
    }
83
    
removed register_format()
yuki-kimoto authored on 2010-05-26
84
    # Arguments
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
85
    my $table  = $args{table} || '';
86
    my $param  = $args{param} || {};
87
    my $append = $args{append} || '';
88
    my $filter = $args{filter};
packaging one directory
yuki-kimoto authored on 2009-11-16
89
    
90
    # Insert keys
removed register_format()
yuki-kimoto authored on 2010-05-26
91
    my @insert_keys = keys %$param;
packaging one directory
yuki-kimoto authored on 2009-11-16
92
    
93
    # Not exists insert keys
94
    croak("Key-value pairs for insert must be specified to 'insert' second argument")
95
      unless @insert_keys;
96
    
97
    # Templte for insert
98
    my $template = "insert into $table {insert " . join(' ', @insert_keys) . '}';
removed register_format()
yuki-kimoto authored on 2010-05-26
99
    $template .= " $append" if $append;
packaging one directory
yuki-kimoto authored on 2009-11-16
100
    
101
    # Execute query
removed register_format()
yuki-kimoto authored on 2010-05-26
102
    my $ret_val = $self->execute($template, param  => $param, 
103
                                            filter => $filter);
packaging one directory
yuki-kimoto authored on 2009-11-16
104
    
105
    return $ret_val;
106
}
107

            
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
108
our %VALID_UPDATE_ARGS
removed register_format()
yuki-kimoto authored on 2010-05-26
109
  = map { $_ => 1 } qw/table param where append filter allow_update_all/;
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
110

            
packaging one directory
yuki-kimoto authored on 2009-11-16
111
sub update {
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
112
    my ($self, %args) = @_;
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
113
    
114
    # Check arguments
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
115
    foreach my $name (keys %args) {
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
116
        croak "\"$name\" is invalid name"
117
          unless $VALID_UPDATE_ARGS{$name};
118
    }
119
    
120
    # Arguments
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
121
    my $table            = $args{table} || '';
122
    my $param            = $args{param} || {};
123
    my $where            = $args{where} || {};
124
    my $append_statement = $args{append} || '';
125
    my $filter           = $args{filter};
126
    my $allow_update_all = $args{allow_update_all};
packaging one directory
yuki-kimoto authored on 2009-11-16
127
    
128
    # Update keys
removed register_format()
yuki-kimoto authored on 2010-05-26
129
    my @update_keys = keys %$param;
packaging one directory
yuki-kimoto authored on 2009-11-16
130
    
131
    # Not exists update kyes
132
    croak("Key-value pairs for update must be specified to 'update' second argument")
133
      unless @update_keys;
134
    
135
    # Where keys
removed register_format()
yuki-kimoto authored on 2010-05-26
136
    my @where_keys = keys %$where;
packaging one directory
yuki-kimoto authored on 2009-11-16
137
    
138
    # Not exists where keys
139
    croak("Key-value pairs for where clause must be specified to 'update' third argument")
cleanup update and update_al...
yuki-kimoto authored on 2010-04-28
140
      if !@where_keys && !$allow_update_all;
packaging one directory
yuki-kimoto authored on 2009-11-16
141
    
142
    # Update clause
143
    my $update_clause = '{update ' . join(' ', @update_keys) . '}';
144
    
145
    # Where clause
146
    my $where_clause = '';
simplify filtering system
yuki-kimoto authored on 2010-05-01
147
    my $new_where = {};
many change
yuki-kimoto authored on 2010-04-30
148
    
packaging one directory
yuki-kimoto authored on 2009-11-16
149
    if (@where_keys) {
150
        $where_clause = 'where ';
151
        foreach my $where_key (@where_keys) {
simplify filtering system
yuki-kimoto authored on 2010-05-01
152
            
153
            $where_clause .= "{= $where_key} and ";
packaging one directory
yuki-kimoto authored on 2009-11-16
154
        }
155
        $where_clause =~ s/ and $//;
156
    }
157
    
158
    # Template for update
159
    my $template = "update $table $update_clause $where_clause";
insert, update, delete appnd...
yuki-kimoto authored on 2009-11-16
160
    $template .= " $append_statement" if $append_statement;
packaging one directory
yuki-kimoto authored on 2009-11-16
161
    
162
    # Rearrange parammeters
removed register_format()
yuki-kimoto authored on 2010-05-26
163
    foreach my $wkey (@where_keys) {
simplify filtering system
yuki-kimoto authored on 2010-05-01
164
        
removed register_format()
yuki-kimoto authored on 2010-05-26
165
        if (exists $param->{$wkey}) {
166
            $param->{$wkey} = [$param->{$wkey}]
167
              unless ref $param->{$wkey} eq 'ARRAY';
simplify filtering system
yuki-kimoto authored on 2010-05-01
168
            
removed register_format()
yuki-kimoto authored on 2010-05-26
169
            push @{$param->{$wkey}}, $where->{$wkey};
simplify filtering system
yuki-kimoto authored on 2010-05-01
170
        }
add tests
yuki-kimoto authored on 2010-05-01
171
        else {
removed register_format()
yuki-kimoto authored on 2010-05-26
172
            $param->{$wkey} = $where->{$wkey};
add tests
yuki-kimoto authored on 2010-05-01
173
        }
simplify filtering system
yuki-kimoto authored on 2010-05-01
174
    }
packaging one directory
yuki-kimoto authored on 2009-11-16
175
    
176
    # Execute query
removed register_format()
yuki-kimoto authored on 2010-05-26
177
    my $ret_val = $self->execute($template, param  => $param, 
178
                                            filter => $filter);
packaging one directory
yuki-kimoto authored on 2009-11-16
179
    
180
    return $ret_val;
181
}
182

            
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
183
sub update_all { shift->update(allow_update_all => 1, @_) };
packaging one directory
yuki-kimoto authored on 2009-11-16
184

            
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
185
our %VALID_DELETE_ARGS
removed register_format()
yuki-kimoto authored on 2010-05-26
186
  = map { $_ => 1 } qw/table where append filter allow_delete_all/;
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
187

            
packaging one directory
yuki-kimoto authored on 2009-11-16
188
sub delete {
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
189
    my ($self, %args) = @_;
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
190
    
191
    # Check arguments
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
192
    foreach my $name (keys %args) {
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
193
        croak "\"$name\" is invalid name"
194
          unless $VALID_DELETE_ARGS{$name};
195
    }
196
    
197
    # Arguments
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
198
    my $table            = $args{table} || '';
199
    my $where            = $args{where} || {};
200
    my $append_statement = $args{append};
201
    my $filter           = $args{filter};
202
    my $allow_delete_all = $args{allow_delete_all};
packaging one directory
yuki-kimoto authored on 2009-11-16
203
    
204
    # Where keys
removed register_format()
yuki-kimoto authored on 2010-05-26
205
    my @where_keys = keys %$where;
packaging one directory
yuki-kimoto authored on 2009-11-16
206
    
207
    # Not exists where keys
208
    croak("Key-value pairs for where clause must be specified to 'delete' second argument")
refactoring delete and delet...
yuki-kimoto authored on 2010-04-28
209
      if !@where_keys && !$allow_delete_all;
packaging one directory
yuki-kimoto authored on 2009-11-16
210
    
211
    # Where clause
212
    my $where_clause = '';
213
    if (@where_keys) {
214
        $where_clause = 'where ';
removed register_format()
yuki-kimoto authored on 2010-05-26
215
        foreach my $wkey (@where_keys) {
216
            $where_clause .= "{= $wkey} and ";
packaging one directory
yuki-kimoto authored on 2009-11-16
217
        }
218
        $where_clause =~ s/ and $//;
219
    }
220
    
221
    # Template for delete
222
    my $template = "delete from $table $where_clause";
insert, update, delete appnd...
yuki-kimoto authored on 2009-11-16
223
    $template .= " $append_statement" if $append_statement;
packaging one directory
yuki-kimoto authored on 2009-11-16
224
    
225
    # Execute query
removed register_format()
yuki-kimoto authored on 2010-05-26
226
    my $ret_val = $self->execute($template, param  => $where, 
227
                                            filter => $filter);
packaging one directory
yuki-kimoto authored on 2009-11-16
228
    
229
    return $ret_val;
230
}
231

            
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
232
sub delete_all { shift->delete(allow_delete_all => 1, @_) }
packaging one directory
yuki-kimoto authored on 2009-11-16
233

            
refactoring select
yuki-kimoto authored on 2010-04-28
234
our %VALID_SELECT_ARGS
added commit method
yuki-kimoto authored on 2010-05-27
235
  = map { $_ => 1 } qw/table column where append relation filter param/;
refactoring select
yuki-kimoto authored on 2010-04-28
236

            
packaging one directory
yuki-kimoto authored on 2009-11-16
237
sub select {
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
238
    my ($self, %args) = @_;
packaging one directory
yuki-kimoto authored on 2009-11-16
239
    
refactoring select
yuki-kimoto authored on 2010-04-28
240
    # Check arguments
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
241
    foreach my $name (keys %args) {
refactoring select
yuki-kimoto authored on 2010-04-28
242
        croak "\"$name\" is invalid name"
243
          unless $VALID_SELECT_ARGS{$name};
244
    }
packaging one directory
yuki-kimoto authored on 2009-11-16
245
    
refactoring select
yuki-kimoto authored on 2010-04-28
246
    # Arguments
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
247
    my $tables = $args{table} || [];
removed register_format()
yuki-kimoto authored on 2010-05-26
248
    $tables = [$tables] unless ref $tables eq 'ARRAY';
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
249
    my $columns  = $args{column} || [];
250
    my $where    = $args{where} || {};
251
    my $relation = $args{relation};
252
    my $append   = $args{append};
253
    my $filter   = $args{filter};
254
    my $param    = $args{param} || {};
packaging one directory
yuki-kimoto authored on 2009-11-16
255
    
256
    # SQL template for select statement
257
    my $template = 'select ';
258
    
added commit method
yuki-kimoto authored on 2010-05-27
259
    # Column clause
packaging one directory
yuki-kimoto authored on 2009-11-16
260
    if (@$columns) {
261
        foreach my $column (@$columns) {
262
            $template .= "$column, ";
263
        }
264
        $template =~ s/, $/ /;
265
    }
266
    else {
267
        $template .= '* ';
268
    }
269
    
added commit method
yuki-kimoto authored on 2010-05-27
270
    # Table
packaging one directory
yuki-kimoto authored on 2009-11-16
271
    $template .= 'from ';
272
    foreach my $table (@$tables) {
273
        $template .= "$table, ";
274
    }
275
    $template =~ s/, $/ /;
276
    
added commit method
yuki-kimoto authored on 2010-05-27
277
    # Where clause
278
    my @where_keys = keys %$where;
packaging one directory
yuki-kimoto authored on 2009-11-16
279
    if (@where_keys) {
280
        $template .= 'where ';
281
        foreach my $where_key (@where_keys) {
compile success
yuki-kimoto authored on 2010-05-01
282
            $template .= "{= $where_key} and ";
packaging one directory
yuki-kimoto authored on 2009-11-16
283
        }
284
    }
285
    $template =~ s/ and $//;
286
    
added commit method
yuki-kimoto authored on 2010-05-27
287
    # Relation
288
    if ($relation) {
289
        $template .= @where_keys ? "and " : "where ";
290
        foreach my $rkey (keys %$relation) {
291
            $template .= "$rkey = " . $relation->{$rkey} . " and ";
packaging one directory
yuki-kimoto authored on 2009-11-16
292
        }
293
    }
added commit method
yuki-kimoto authored on 2010-05-27
294
    $template =~ s/ and $//;
295
    
296
    # Append some statement
297
    $template .= " $append" if $append;
packaging one directory
yuki-kimoto authored on 2009-11-16
298
    
299
    # Execute query
added commit method
yuki-kimoto authored on 2010-05-27
300
    my $result = $self->execute($template, param  => $where, 
removed register_format()
yuki-kimoto authored on 2010-05-26
301
                                           filter => $filter);
packaging one directory
yuki-kimoto authored on 2009-11-16
302
    
303
    return $result;
304
}
305

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
306
sub create_query {
307
    my ($self, $template) = @_;
version 0.0901
yuki-kimoto authored on 2009-12-17
308
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
309
    # Create query from SQL template
310
    my $sql_template = $self->sql_template;
removed register_format()
yuki-kimoto authored on 2010-05-26
311
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
312
    # Get cached query
add cache attribute
yuki-kimoto authored on 2010-06-14
313
    my $cached = $self->{_cached}->{$template};
version 0.0901
yuki-kimoto authored on 2009-12-17
314
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
315
    # Create query
316
    my $query;
add cache attribute
yuki-kimoto authored on 2010-06-14
317
    if ($cached) {
318
        $query = DBIx::Custom::Query->new($cached);
removed reconnect method
yuki-kimoto authored on 2010-05-28
319
    }
320
    else {
321
        $query = eval{$sql_template->create_query($template)};
322
        croak($@) if $@;
323
        
add cache attribute
yuki-kimoto authored on 2010-06-14
324
        $self->{_cached}->{$template} = {sql => $query->sql, columns => $query->columns}
325
          if $self->cache && ! $self->{_cached}->{$template};
removed reconnect method
yuki-kimoto authored on 2010-05-28
326
    }
version 0.0901
yuki-kimoto authored on 2009-12-17
327
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
328
    # Prepare statement handle
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
329
    my $sth = eval {$self->dbh->prepare($query->{sql})};
330
    croak $@ if $@;
renamed fetch_rows to fetch_...
yuki-kimoto authored on 2010-05-01
331
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
332
    # Set statement handle
333
    $query->sth($sth);
334
    
335
    return $query;
336
}
337

            
338
our %VALID_EXECUTE_ARGS = map { $_ => 1 } qw/param filter/;
339

            
340
sub execute{
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
341
    my ($self, $query, %args)  = @_;
removed reconnect method
yuki-kimoto authored on 2010-05-28
342
    
343
    # Check arguments
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
344
    foreach my $name (keys %args) {
removed reconnect method
yuki-kimoto authored on 2010-05-28
345
        croak "\"$name\" is invalid name"
346
          unless $VALID_EXECUTE_ARGS{$name};
347
    }
348
    
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
349
    my $params = $args{param} || {};
removed reconnect method
yuki-kimoto authored on 2010-05-28
350
    
351
    # First argument is SQL template
352
    unless (ref $query eq 'DBIx::Custom::Query') {
353
        my $template;
354
        
355
        if (ref $query eq 'ARRAY') {
356
            $template = $query->[0];
357
        }
358
        else { $template = $query }
359
        
360
        $query = $self->create_query($template);
361
    }
362
    
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
363
    my $filter = $args{filter} || $query->filter || {};
removed reconnect method
yuki-kimoto authored on 2010-05-28
364
    
365
    # Create bind value
366
    my $bind_values = $self->_build_bind_values($query, $params, $filter);
367
    
368
    # Execute
369
    my $sth      = $query->sth;
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
370
    my $affected = eval {$sth->execute(@$bind_values)};
371
    croak $@ if $@;
removed reconnect method
yuki-kimoto authored on 2010-05-28
372
    
373
    # Return resultset if select statement is executed
374
    if ($sth->{NUM_OF_FIELDS}) {
375
        
376
        # Get result class
377
        my $result_class = $self->result_class;
378
        
379
        # Create result
380
        my $result = $result_class->new({
381
            sth             => $sth,
382
            default_filter  => $self->default_fetch_filter,
383
            filters         => $self->filters
384
        });
385
        return $result;
386
    }
387
    return $affected;
388
}
389

            
390
sub _build_bind_values {
391
    my ($self, $query, $params, $filter) = @_;
392
    
393
    # binding values
394
    my @bind_values;
395
    
396
    # Build bind values
397
    my $count = {};
398
    foreach my $column (@{$query->columns}) {
399
        
400
        croak "\"$column\" is not exists in params"
401
          unless exists $params->{$column};
402
        
403
        # Value
404
        my $value = ref $params->{$column} eq 'ARRAY'
405
                  ? $params->{$column}->[$count->{$column} || 0]
406
                  : $params->{$column};
407
        
408
        # Filter
409
        $filter ||= {};
410
        
411
        # Filter name
412
        my $fname = $filter->{$column} || $self->default_query_filter || '';
413
        
414
        my $filter_func;
415
        if ($fname) {
416
            
417
            if (ref $fname eq 'CODE') {
418
                $filter_func = $fname;
419
            }
420
            else {
421
                my $filters = $self->filters;
422
                croak "Not exists filter \"$fname\"" unless exists $filters->{$fname};
423
                $filter_func = $filters->{$fname};
424
            }            
425
        }
426
        
427
        push @bind_values, $filter_func
428
                         ? $filter_func->($value)
429
                         : $value;
430
        
431
        # Count up 
432
        $count->{$column}++;
433
    }
434
    
435
    return \@bind_values;
436
}
437

            
438
sub register_filter {
439
    my $invocant = shift;
440
    
441
    # Add filter
442
    my $filters = ref $_[0] eq 'HASH' ? $_[0] : {@_};
443
    $invocant->filters({%{$invocant->filters}, %$filters});
444
    
445
    return $invocant;
446
}
447

            
448
sub auto_commit {
449
    my $self = shift;
450
    
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
451
    # Not connected
452
    croak "Not connected" unless $self->dbh;
453
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
454
    if (@_) {
455
        
456
        # Set AutoCommit
457
        $self->dbh->{AutoCommit} = $_[0];
458
        
459
        return $self;
460
    }
461
    return $self->dbh->{AutoCommit};
462
}
463

            
select, insert, update, upda...
yuki-kimoto authored on 2010-06-14
464
sub commit   { 
465
    my $ret = eval { shift->dbh->commit };
466
    croak $@ if $@;
467
    return $ret;
468
}
469
sub rollback {
470
    my $ret = eval { shift->dbh->rollback };
471
    croak $@ if $@;
472
    return $ret;
473
}
removed reconnect method
yuki-kimoto authored on 2010-05-28
474

            
475
sub DESTROY {
476
    my $self = shift;
477
    
478
    # Disconnect
479
    $self->disconnect if $self->dbh;
480
}
481

            
482
=head1 NAME
483

            
484
DBIx::Custom - DBI with hash parameter binding and filtering system
485

            
486
=head1 VERSION
487

            
488
Version 0.1503
489

            
490
=cut
491

            
492
our $VERSION = '0.1503';
493
$VERSION = eval $VERSION;
494

            
495
=head1 STABILITY
496

            
497
This module is not stable. Method name and functionality will be change.
498

            
499
=head1 SYNOPSYS
500
    
501
    # Connect
502
    my $dbi = DBIx::Custom->connect(data_source => "dbi:mysql:database=books",
503
                                    user => 'ken', password => '!LFKD%$&');
504
    
505
    # Disconnect
506
    $dbi->disconnect
507

            
508
    # Insert 
509
    $dbi->insert(table  => 'books',
510
                 param  => {title => 'perl', author => 'Ken'},
511
                 filter => {title => 'encode_utf8'});
512
    
513
    # Update 
514
    $dbi->update(table  => 'books', 
515
                 param  => {title => 'aaa', author => 'Ken'}, 
516
                 where  => {id => 5},
517
                 filter => {title => 'encode_utf8'});
518
    
519
    # Update all
520
    $dbi->update_all(table  => 'books',
521
                     param  => {title => 'aaa'},
522
                     filter => {title => 'encode_utf8'});
523
    
524
    # Delete
525
    $dbi->delete(table  => 'books',
526
                 where  => {author => 'Ken'},
527
                 filter => {title => 'encode_utf8'});
528
    
529
    # Delete all
530
    $dbi->delete_all(table => 'books');
531
    
532
    # Select
533
    my $result = $dbi->select(table => 'books');
renamed fetch_rows to fetch_...
yuki-kimoto authored on 2010-05-01
534
    
removed register_format()
yuki-kimoto authored on 2010-05-26
535
    # Select(more complex)
renamed fetch_rows to fetch_...
yuki-kimoto authored on 2010-05-01
536
    my $result = $dbi->select(
update document
yuki-kimoto authored on 2010-05-27
537
        table  => 'books',
538
        column => [qw/author title/],
539
        where  => {author => 'Ken'},
540
        append => 'order by id limit 1',
541
        filter => {tilte => 'encode_utf8'}
renamed fetch_rows to fetch_...
yuki-kimoto authored on 2010-05-01
542
    );
added commit method
yuki-kimoto authored on 2010-05-27
543
    
544
    # Select(Join table)
545
    my $result = $dbi->select(
546
        table => ['books', 'rental'],
547
        column => ['books.name as book_name']
548
        relation => {'books.id' => 'rental.book_id'}
549
    );
removed reconnect method
yuki-kimoto authored on 2010-05-28
550
    
removed register_format()
yuki-kimoto authored on 2010-05-26
551
    # Execute SQL
552
    $dbi->execute("select title from books");
553
    
554
    # Execute SQL with parameters and filter
555
    $dbi->execute("select id from books where {= author} && {like title}",
556
                  param  => {author => 'ken', title => '%Perl%'},
557
                  filter => {tilte => 'encode_utf8'});
removed reconnect method
yuki-kimoto authored on 2010-05-28
558

            
559
    # Create query and execute it
560
    my $query = $dbi->create_query(
561
        "select id from books where {= author} && {like title}"
562
    );
563
    $dbi->execute($query, param => {author => 'ken', title => '%Perl%'})
removed register_format()
yuki-kimoto authored on 2010-05-26
564
    
565
    # Default filter
566
    $dbi->default_query_filter('encode_utf8');
567
    $dbi->default_fetch_filter('decode_utf8');
568
    
569
    # Fetch
570
    while (my $row = $result->fetch) {
571
        # ...
572
    }
573
    
574
    # Fetch hash
575
    while (my $row = $result->fetch_hash) {
576
        
577
    }
578
    
update document
yuki-kimoto authored on 2010-05-27
579
    # DBI instance
580
    my $dbh = $dbi->dbh;
removed reconnect method
yuki-kimoto authored on 2010-05-28
581

            
582
=head1 DESCRIPTION
583

            
584
L<DBIx::Custom> is useful L<DBI> extention.
585
This module have hash parameter binding and filtering system.
586

            
587
Normally, binding parameter is array.
588
L<DBIx::Custom> enable you to pass binding parameter as hash.
589

            
590
This module also provide filtering system.
591
You can filter the binding parameter
592
or the value of fetching row.
593

            
594
And have useful method such as insert(), update(), delete(), and select().
595

            
596
=head2 Features
597

            
598
=over 4
599

            
600
=item 1. Hash parameter binding.
601

            
602
=item 2. Value filtering.
603

            
604
=item 3. Useful methos such as insert(), update(), delete(), and select().
605

            
606
=back
607

            
update document
yuki-kimoto authored on 2010-01-30
608
=head1 ATTRIBUTES
packaging one directory
yuki-kimoto authored on 2009-11-16
609

            
610
=head2 user
611

            
update document
yuki-kimoto authored on 2010-05-27
612
Database user name.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
613
    
version 0.0901
yuki-kimoto authored on 2009-12-17
614
    $dbi  = $dbi->user('Ken');
615
    $user = $dbi->user;
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
616
    
packaging one directory
yuki-kimoto authored on 2009-11-16
617
=head2 password
618

            
update document
yuki-kimoto authored on 2010-05-27
619
Database password.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
620
    
version 0.0901
yuki-kimoto authored on 2009-12-17
621
    $dbi      = $dbi->password('lkj&le`@s');
622
    $password = $dbi->password;
packaging one directory
yuki-kimoto authored on 2009-11-16
623

            
624
=head2 data_source
625

            
update document
yuki-kimoto authored on 2010-05-27
626
Database data source.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
627
    
version 0.0901
yuki-kimoto authored on 2009-12-17
628
    $dbi         = $dbi->data_source("dbi:mysql:dbname=$database");
629
    $data_source = $dbi->data_source;
packaging one directory
yuki-kimoto authored on 2009-11-16
630
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
631
=head2 dbh
packaging one directory
yuki-kimoto authored on 2009-11-16
632

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
633
Database handle. This is the innstance of L<DBI>
634
    
635
    $dbi = $dbi->dbh($dbh);
636
    $dbh = $dbi->dbh;
packaging one directory
yuki-kimoto authored on 2009-11-16
637

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
638
You can use all methods of L<DBI>
packaging one directory
yuki-kimoto authored on 2009-11-16
639

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
640
    my $sth    = $dbi->dbh->prepare("...");
641
    my $errstr = $dbi->dbh->errstr;
642
    
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
643
=head2 filters
packaging one directory
yuki-kimoto authored on 2009-11-16
644

            
update document
yuki-kimoto authored on 2010-01-30
645
Filters
packaging one directory
yuki-kimoto authored on 2009-11-16
646

            
update document
yuki-kimoto authored on 2010-05-27
647
    $dbi     = $dbi->filters({%filters});
version 0.0901
yuki-kimoto authored on 2009-12-17
648
    $filters = $dbi->filters;
649

            
update document
yuki-kimoto authored on 2010-05-27
650
encode_utf8 and decode_utf8 is set to this attribute by default.
version 0.0901
yuki-kimoto authored on 2009-12-17
651

            
update document
yuki-kimoto authored on 2010-05-27
652
    $encode_utf8 = $dbi->filters->{encode_utf8};
653
    $decode_utf8 = $dbi->filters->{decode_utf8};
packaging one directory
yuki-kimoto authored on 2009-11-16
654

            
rename bind_filter to query_...
yuki-kimoto authored on 2010-04-28
655
=head2 default_query_filter
packaging one directory
yuki-kimoto authored on 2009-11-16
656

            
update document
yuki-kimoto authored on 2010-05-27
657
Default query filter.
packaging one directory
yuki-kimoto authored on 2009-11-16
658

            
update document
yuki-kimoto authored on 2010-05-27
659
    $dbi                  = $dbi->default_query_filter('encode_utf8');
rename bind_filter to query_...
yuki-kimoto authored on 2010-04-28
660
    $default_query_filter = $dbi->default_query_filter
packaging one directory
yuki-kimoto authored on 2009-11-16
661

            
cleanup
yuki-kimoto authored on 2010-04-28
662
=head2 default_fetch_filter
packaging one directory
yuki-kimoto authored on 2009-11-16
663

            
update document
yuki-kimoto authored on 2010-05-27
664
Fetching filter.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
665

            
update document
yuki-kimoto authored on 2010-05-27
666
    $dbi                  = $dbi->default_fetch_filter('decode_utf8');
cleanup
yuki-kimoto authored on 2010-04-28
667
    $default_fetch_filter = $dbi->default_fetch_filter;
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
668

            
packaging one directory
yuki-kimoto authored on 2009-11-16
669
=head2 result_class
670

            
update document
yuki-kimoto authored on 2010-05-27
671
Result class.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
672

            
version 0.0901
yuki-kimoto authored on 2009-12-17
673
    $dbi          = $dbi->result_class('DBIx::Custom::Result');
packaging one directory
yuki-kimoto authored on 2009-11-16
674
    $result_class = $dbi->result_class;
675

            
update document
yuki-kimoto authored on 2010-05-27
676
L<DBIx::Custom::Result> is set to this attribute by default.
update document
yuki-kimoto authored on 2010-01-30
677

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
678
=head2 sql_template
added commit method
yuki-kimoto authored on 2010-05-27
679

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
680
SQLTemplate instance. sql_template attribute must be 
681
the instance of L<DBIx::Cutom::SQLTemplate> subclass.
added commit method
yuki-kimoto authored on 2010-05-27
682

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
683
    $dbi          = $dbi->sql_template(DBIx::Cutom::SQLTemplate->new);
684
    $sql_template = $dbi->sql_template;
added commit method
yuki-kimoto authored on 2010-05-27
685

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
686
the instance of DBIx::Cutom::SQLTemplate is set to 
687
this attribute by default.
added commit method
yuki-kimoto authored on 2010-05-27
688

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
689
=head1 METHODS
added commit method
yuki-kimoto authored on 2010-05-27
690

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
691
This class is L<Object::Simple> subclass.
692
You can use all methods of L<Object::Simple>
added commit method
yuki-kimoto authored on 2010-05-27
693

            
packaging one directory
yuki-kimoto authored on 2009-11-16
694
=head2 connect
695

            
update document
yuki-kimoto authored on 2010-05-27
696
Connect to database.
697
    
698
    my $dbi = DBIx::Custom->connect(data_source => "dbi:mysql:database=books",
699
                                    user => 'ken', password => '!LFKD%$&');
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
700

            
update document
yuki-kimoto authored on 2010-05-27
701
"AutoCommit" and "RaiseError" option is true, 
702
and "PrintError" option is false by dfault.
packaging one directory
yuki-kimoto authored on 2009-11-16
703

            
704
=head2 disconnect
705

            
update document
yuki-kimoto authored on 2010-05-27
706
Disconnect database.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
707

            
packaging one directory
yuki-kimoto authored on 2009-11-16
708
    $dbi->disconnect;
709

            
version 0.0901
yuki-kimoto authored on 2009-12-17
710
If database is already disconnected, this method do nothing.
packaging one directory
yuki-kimoto authored on 2009-11-16
711

            
712
=head2 insert
713

            
added commit method
yuki-kimoto authored on 2010-05-27
714
Insert row.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
715

            
removed register_format()
yuki-kimoto authored on 2010-05-26
716
    $affected = $dbi->insert(table  => $table, 
717
                             param  => {%param},
718
                             append => $append,
719
                             filter => {%filter});
update document
yuki-kimoto authored on 2009-11-19
720

            
added commit method
yuki-kimoto authored on 2010-05-27
721
Retruned value is affected rows count.
packaging one directory
yuki-kimoto authored on 2009-11-16
722
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
723
Example:
version 0.0901
yuki-kimoto authored on 2009-12-17
724

            
removed register_format()
yuki-kimoto authored on 2010-05-26
725
    # insert
726
    $dbi->insert(table  => 'books', 
727
                 param  => {title => 'Perl', author => 'Taro'},
728
                 append => "some statement",
729
                 filter => {title => 'encode_utf8'})
version 0.0901
yuki-kimoto authored on 2009-12-17
730

            
packaging one directory
yuki-kimoto authored on 2009-11-16
731
=head2 update
732

            
added commit method
yuki-kimoto authored on 2010-05-27
733
Update rows.
update document
yuki-kimoto authored on 2009-11-19
734

            
removed register_format()
yuki-kimoto authored on 2010-05-26
735
    $affected = $dbi->update(table  => $table, 
736
                             param  => {%params},
737
                             where  => {%where},
738
                             append => $append,
739
                             filter => {%filter})
version 0.0901
yuki-kimoto authored on 2009-12-17
740

            
added commit method
yuki-kimoto authored on 2010-05-27
741
Retruned value is affected rows count
update document
yuki-kimoto authored on 2009-11-19
742

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
743
Example:
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
744

            
removed register_format()
yuki-kimoto authored on 2010-05-26
745
    #update
746
    $dbi->update(table  => 'books',
747
                 param  => {title => 'Perl', author => 'Taro'},
748
                 where  => {id => 5},
749
                 append => "some statement",
added commit method
yuki-kimoto authored on 2010-05-27
750
                 filter => {title => 'encode_utf8'});
version 0.0901
yuki-kimoto authored on 2009-12-17
751

            
packaging one directory
yuki-kimoto authored on 2009-11-16
752
=head2 update_all
753

            
added commit method
yuki-kimoto authored on 2010-05-27
754
Update all rows.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
755

            
removed register_format()
yuki-kimoto authored on 2010-05-26
756
    $affected = $dbi->update_all(table  => $table, 
757
                                 param  => {%params},
758
                                 filter => {%filter},
759
                                 append => $append);
update document
yuki-kimoto authored on 2009-11-19
760

            
added commit method
yuki-kimoto authored on 2010-05-27
761
Retruned value is affected rows count.
version 0.0901
yuki-kimoto authored on 2009-12-17
762

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
763
Example:
update document
yuki-kimoto authored on 2009-11-19
764

            
removed register_format()
yuki-kimoto authored on 2010-05-26
765
    # update_all
766
    $dbi->update_all(table  => 'books', 
767
                     param  => {author => 'taro'},
768
                     filter => {author => 'encode_utf8'});
packaging one directory
yuki-kimoto authored on 2009-11-16
769

            
770
=head2 delete
771

            
added commit method
yuki-kimoto authored on 2010-05-27
772
Delete rows.
update document
yuki-kimoto authored on 2009-11-19
773

            
removed register_format()
yuki-kimoto authored on 2010-05-26
774
    $affected = $dbi->delete(table  => $table,
775
                             where  => {%where},
added commit method
yuki-kimoto authored on 2010-05-27
776
                             append => $append,
removed register_format()
yuki-kimoto authored on 2010-05-26
777
                             filter => {%filter});
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
778

            
version 0.0901
yuki-kimoto authored on 2009-12-17
779
Retrun value is affected rows count
packaging one directory
yuki-kimoto authored on 2009-11-16
780
    
removed reconnect method
yuki-kimoto authored on 2010-05-28
781
Example:
packaging one directory
yuki-kimoto authored on 2009-11-16
782

            
removed register_format()
yuki-kimoto authored on 2010-05-26
783
    # delete
784
    $dbi->delete(table  => 'books',
785
                 where  => {id => 5},
786
                 append => 'some statement',
removed reconnect method
yuki-kimoto authored on 2010-05-28
787
                 filter => {id => 'encode_utf8'});
version 0.0901
yuki-kimoto authored on 2009-12-17
788

            
packaging one directory
yuki-kimoto authored on 2009-11-16
789
=head2 delete_all
790

            
added commit method
yuki-kimoto authored on 2010-05-27
791
Delete all rows.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
792

            
removed register_format()
yuki-kimoto authored on 2010-05-26
793
    $affected = $dbi->delete_all(table => $table);
packaging one directory
yuki-kimoto authored on 2009-11-16
794

            
added commit method
yuki-kimoto authored on 2010-05-27
795
Retruned value is affected rows count.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
796

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
797
Example:
removed register_format()
yuki-kimoto authored on 2010-05-26
798
    
799
    # delete_all
removed reconnect method
yuki-kimoto authored on 2010-05-28
800
    $dbi->delete_all(table => 'books');
packaging one directory
yuki-kimoto authored on 2009-11-16
801

            
802
=head2 select
803
    
added commit method
yuki-kimoto authored on 2010-05-27
804
Select rows.
bind_filter argument is chan...
yuki-kimoto authored on 2009-11-19
805

            
added commit method
yuki-kimoto authored on 2010-05-27
806
    $result = $dbi->select(table    => $table,
807
                           column   => [@column],
808
                           where    => {%where},
809
                           append   => $append,
removed reconnect method
yuki-kimoto authored on 2010-05-28
810
                           relation => {%relation},
added commit method
yuki-kimoto authored on 2010-05-27
811
                           filter   => {%filter});
update document
yuki-kimoto authored on 2009-11-19
812

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
813
Return value is the instance of L<DBIx::Custom::Result>.
update document
yuki-kimoto authored on 2009-11-19
814

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
815
Example:
update document
yuki-kimoto authored on 2009-11-19
816

            
added commit method
yuki-kimoto authored on 2010-05-27
817
    # select * from books;
removed reconnect method
yuki-kimoto authored on 2010-05-28
818
    $result = $dbi->select(table => 'books');
packaging one directory
yuki-kimoto authored on 2009-11-16
819
    
update document
yuki-kimoto authored on 2009-11-19
820
    # select * from books where title = 'Perl';
removed reconnect method
yuki-kimoto authored on 2010-05-28
821
    $result = $dbi->select(table => 'books', where => {title => 1});
update document
yuki-kimoto authored on 2009-11-19
822
    
823
    # select title, author from books where id = 1 for update;
824
    $result = $dbi->select(
removed register_format()
yuki-kimoto authored on 2010-05-26
825
        table  => 'books',
removed reconnect method
yuki-kimoto authored on 2010-05-28
826
        column => ['title', 'author'],
removed register_format()
yuki-kimoto authored on 2010-05-26
827
        where  => {id => 1},
828
        appned => 'for update'
update document
yuki-kimoto authored on 2009-11-19
829
    );
830
    
added commit method
yuki-kimoto authored on 2010-05-27
831
    # select books.name as book_name from books, rental 
832
    # where books.id = rental.book_id;
833
    my $result = $dbi->select(
removed reconnect method
yuki-kimoto authored on 2010-05-28
834
        table    => ['books', 'rental'],
835
        column   => ['books.name as book_name']
added commit method
yuki-kimoto authored on 2010-05-27
836
        relation => {'books.id' => 'rental.book_id'}
update document
yuki-kimoto authored on 2009-11-19
837
    );
838

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
839
=head2 create_query
840
    
841
Create the instance of L<DBIx::Custom::Query>. 
842
This receive the string written by SQL template.
packaging one directory
yuki-kimoto authored on 2009-11-16
843

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
844
    my $query = $dbi->create_query("select * from authors where {= name} and {= age}");
845

            
846
=head2 execute
847

            
848
Execute the instace of L<DBIx::Custom::Query> or
849
the string written by SQL template.
850
Return value is the instance of L<DBIx::Custom::Result>.
851

            
852
    $result = $dbi->execute($query,    param => $params, filter => {%filter});
853
    $result = $dbi->execute($template, param => $params, filter => {%filter});
854

            
855
Example:
856

            
857
    $result = $dbi->execute("select * from authors where {= name} and {= age}", 
858
                            param => {name => 'taro', age => 19});
859
    
860
    while (my $row = $result->fetch) {
861
        # do something
862
    }
863

            
864
See also L<DBIx::Custom::SQLTemplate> to know how to write SQL template.
865

            
866
=head2 register_filter
867

            
868
Resister filter.
869
    
870
    $dbi->register_filter(%filters);
871
    
872
Example:
packaging one directory
yuki-kimoto authored on 2009-11-16
873

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
874
    $dbi->register_filter(
875
        encode_utf8 => sub {
876
            my $value = shift;
877
            
878
            require Encode;
879
            
880
            return Encode::encode('UTF-8', $value);
881
        },
882
        decode_utf8 => sub {
883
            my $value = shift;
884
            
885
            require Encode;
886
            
887
            return Encode::decode('UTF-8', $value)
888
        }
889
    );
890

            
891
=head2 auto_commit
892

            
893
Auto commit.
packaging one directory
yuki-kimoto authored on 2009-11-16
894

            
removed reconnect method
yuki-kimoto authored on 2010-05-28
895
    $self        = $dbi->auto_commit(1);
896
    $auto_commit = $dbi->auto_commit;
897

            
898
This is equal to
899

            
900
    $dbi->dbh->{AutoCommit} = 1;
901
    $auto_commit = $dbi->dbh->{AutoCommit};
902

            
903
=head2 commit
904

            
905
Commit.
906

            
907
    $dbi->commit;
908

            
909
This is equal to
910

            
911
    $dbi->dbh->commit;
912

            
913
=head2 rollback
914

            
915
Rollback.
916

            
917
    $dbi->rollback
918

            
919
This is equal to
920

            
921
    $dbi->dbh->rollback;
922

            
923
=head1 AUTHOR
924

            
925
Yuki Kimoto, C<< <kimoto.yuki at gmail.com> >>
version 0.0901
yuki-kimoto authored on 2009-12-17
926

            
packaging one directory
yuki-kimoto authored on 2009-11-16
927
=head1 COPYRIGHT & LICENSE
928

            
929
Copyright 2009 Yuki Kimoto, all rights reserved.
930

            
931
This program is free software; you can redistribute it and/or modify it
932
under the same terms as Perl itself.
933

            
934
=cut