Showing 4 changed files with 208 additions and 67 deletions
+133 -40
lib/DBI/Custom.pm
... ...
@@ -13,7 +13,6 @@ use DBI::Custom::Query;
13 13
 sub user        : ClassObjectAttr { initialize => {clone => 'scalar'} }
14 14
 sub password    : ClassObjectAttr { initialize => {clone => 'scalar'} }
15 15
 sub data_source : ClassObjectAttr { initialize => {clone => 'scalar'} }
16
-sub database    : ClassObjectAttr { initialize => {clone => 'scalar'} }
17 16
 sub dbi_options : ClassObjectAttr { initialize => {clone => 'hash', 
18 17
                                                    default => sub { {} } } }
19 18
 
... ...
@@ -67,7 +66,7 @@ sub _auto_commit {
67 66
     my $self = shift;
68 67
     
69 68
     croak("Cannot change AutoCommit becouse of not connected")
70
-        unless $self->dbh;
69
+      unless $self->dbh;
71 70
     
72 71
     if (@_) {
73 72
         $self->dbh->{AutoCommit} = $_[0];
... ...
@@ -109,7 +108,7 @@ sub DESTROY {
109 108
 # Is connected?
110 109
 sub connected {
111 110
     my $self = shift;
112
-    return exists $self->{dbh} && eval {$self->{dbh}->can('prepare')};
111
+    return ref $self->{dbh} eq 'DBI::db';
113 112
 }
114 113
 
115 114
 # Disconnect
... ...
@@ -132,41 +131,87 @@ sub reconnect {
132 131
 sub run_tranzaction {
133 132
     my ($self, $tranzaction) = @_;
134 133
     
134
+    # Auto commit off
135 135
     $self->_auto_commit(0);
136 136
     
137
-    eval {
138
-        $tranzaction->();
139
-        $self->dbh->commit;
140
-    };
137
+    # Run tranzaction
138
+    eval {$tranzaction->()};
141 139
     
142
-    if ($@) {
143
-        my $tranzaction_error = $@;
140
+    # Tranzaction error
141
+    my $tranzaction_error = $@;
142
+    
143
+    # RaiseError on
144
+    my $old_raise_error = $self->dbh->{RaiseError};
145
+    $self->dbh->{RaiseError} = 1;
146
+    
147
+    # Tranzaction is failed.
148
+    if ($tranzaction_error) {
149
+        # Rollback
150
+        eval{$self->dbh->rollback};
151
+        
152
+        # Rollback error
153
+        my $rollback_error = $@;
144 154
         
145
-        $self->dbh->rollback or croak("$@ and rollback also failed");
146
-        croak("$tranzaction_error");
155
+        # Auto commit on
156
+        $self->_auto_commit(1);
157
+        
158
+        # Restore RaiseError value
159
+        $self->dbh->{RaiseError} = $old_raise_error;
160
+        
161
+        if ($rollback_error) {
162
+            # Rollback is failed
163
+            croak("${tranzaction_error}Rollback is failed : $rollback_error");
164
+        }
165
+        else {
166
+            # Rollback is success
167
+            croak("${tranzaction_error}Rollback is success");
168
+        }
169
+    }
170
+    # Tranzaction is success
171
+    else {
172
+        # Commit
173
+        eval{$self->dbh->commit};
174
+        my $commit_error = $@;
175
+        
176
+        # Auto commit on
177
+        $self->_auto_commit(1);
178
+        
179
+        # Restore RaiseError value
180
+        $self->dbh->{RaiseError} = $old_raise_error;
181
+        
182
+        # Commit is failed
183
+        croak($commit_error) if $commit_error;
147 184
     }
148
-    $self->_auto_commit(1);
149 185
 }
150 186
 
187
+# Prepare statement handle
151 188
 sub prepare {
152 189
     my ($self, $sql) = @_;
190
+    
191
+    # Connect if not
153 192
     eval{$self->connect unless $self->connected};
154 193
     croak($@) if $@;
155 194
     
195
+    # Prepare
156 196
     my $sth = eval{$self->dbh->prepare($sql)};
157 197
     croak($@) if $@;
158 198
     return $sth;
159 199
 }
160 200
 
201
+# Execute SQL directly
161 202
 sub do{
162 203
     my ($self, $sql, @bind_values) = @_;
204
+    
205
+    # Connect if not
163 206
     eval{$self->connect unless $self->connected};
164 207
     croak($@) if $@;
165 208
     
209
+    # Do
166 210
     eval{$self->dbh->do($sql, @bind_values)};
167 211
     croak($@) if $@;
168 212
 }
169 213
 
214
+# Create query
170 215
 sub create_query {
171 216
     my ($self, $template) = @_;
172 217
     
... ...
@@ -178,8 +223,9 @@ sub create_query {
178 223
     # Create Query object;
179 224
     $query = DBI::Custom::Query->new($query);
180 225
     
181
-    # connect if not
182
-    $self->connect unless $self->connected;
226
+    # Connect if not
227
+    eval{$self->connect unless $self->connected};
228
+    croak($@) if $@;
183 229
     
184 230
     # Prepare statement handle
185 231
     my $sth = eval{$self->dbh->prepare($query->{sql})};
... ...
@@ -207,6 +253,7 @@ sub create_query {
207 253
     return $query;
208 254
 }
209 255
 
256
+# Execute query
210 257
 sub execute {
211 258
     my ($self, $query, $params)  = @_;
212 259
     $params ||= {};
... ...
@@ -225,6 +272,8 @@ sub execute {
225 272
     # Execute
226 273
     my $sth = $query->sth;
227 274
     my $ret_val = eval{$sth->execute(@$bind_values)};
275
+    
276
+    # Execute error
228 277
     if ($@) {
229 278
         require Data::Dumper;
230 279
         my $sql         = $query->{sql} || '';
... ...
@@ -236,7 +285,11 @@ sub execute {
236 285
     
237 286
     # Return resultset if select statement is executed
238 287
     if ($sth->{NUM_OF_FIELDS}) {
288
+        
289
+        # Get result class
239 290
         my $result_class = $self->result_class;
291
+        
292
+        # Create result
240 293
         my $result = $result_class->new({
241 294
             sth              => $sth,
242 295
             fetch_filter     => $query->fetch_filter,
... ...
@@ -247,9 +300,9 @@ sub execute {
247 300
     return $ret_val;
248 301
 }
249 302
 
303
+# Build binding values
250 304
 sub _build_bind_values {
251 305
     my ($self, $query, $params) = @_;
252
-    
253 306
     my $key_infos           = $query->key_infos;
254 307
     my $bind_filter         = $query->bind_filter;
255 308
     my $no_bind_filters_map = $query->_no_bind_filters_map || {};
... ...
@@ -259,58 +312,96 @@ sub _build_bind_values {
259 312
     
260 313
     # Create bind values
261 314
     foreach my $key_info (@$key_infos) {
262
-        my $filtering_key = $key_info->{key};
263
-        my $access_keys = $key_info->{access_keys};
264
-        
315
+        # Set variable
316
+        my $access_keys  = $key_info->{access_keys};
265 317
         my $original_key = $key_info->{original_key} || '';
266 318
         my $table        = $key_info->{table}        || '';
267 319
         my $column       = $key_info->{column}       || '';
268 320
         
321
+        # Key is found?
269 322
         my $found;
323
+        
324
+        # Build bind values
270 325
         ACCESS_KEYS :
271 326
         foreach my $access_key (@$access_keys) {
327
+            # Root parameter
272 328
             my $root_params = $params;
329
+            
330
+            # Search corresponding value
273 331
             for (my $i = 0; $i < @$access_key; $i++) {
274
-                my $key = $access_key->[$i];
332
+                # Current key
333
+                my $current_key = $access_key->[$i];
275 334
                 
335
+                # Each access key must be string or array reference
276 336
                 croak("'access_keys' each value must be string or array reference")
277
-                  unless (ref $key eq 'ARRAY' || ($key && !ref $key));
337
+                  unless (ref $current_key eq 'ARRAY' ||
338
+                          ($current_key && !ref $current_key));
278 339
                 
340
+                # Last key
279 341
                 if ($i == @$access_key - 1) {
280
-                    if (ref $key eq 'ARRAY') {
281
-                        if ($bind_filter && !$no_bind_filters_map->{$original_key}) {
342
+                    # Key is array reference
343
+                    if (ref $current_key eq 'ARRAY') {
344
+                        # Filtering 
345
+                        if ($bind_filter &&
346
+                            !$no_bind_filters_map->{$original_key})
347
+                        {
282 348
                             push @bind_values, 
283
-                                 $bind_filter->($original_key, $root_params->[$key->[0]],
349
+                                 $bind_filter->($original_key, 
350
+                                                $root_params->[$current_key->[0]],
284 351
                                                 $table, $column);
285 352
                         }
353
+                        # Not filtering
286 354
                         else {
287
-                            push @bind_values, scalar $root_params->[$key->[0]];
355
+                            push @bind_values,
356
+                                 scalar $root_params->[$current_key->[0]];
288 357
                         }
289 358
                     }
359
+                    # Key is string
290 360
                     else {
291
-                        next ACCESS_KEYS unless exists $root_params->{$key};
292
-                        if ($bind_filter && !$no_bind_filters_map->{$original_key}) {
361
+                        # Key is not found
362
+                        next ACCESS_KEYS
363
+                          unless exists $root_params->{$current_key};
364
+                        
365
+                        # Filtering
366
+                        if ($bind_filter &&
367
+                            !$no_bind_filters_map->{$original_key}) 
368
+                        {
293 369
                             push @bind_values,
294
-                                 $bind_filter->($original_key, $root_params->{$key}, 
370
+                                 $bind_filter->($original_key,
371
+                                                $root_params->{$current_key}, 
295 372
                                                 $table, $column);
296 373
                         }
374
+                        # Not filtering
297 375
                         else {
298
-                            push @bind_values, scalar $root_params->{$key};
376
+                            push @bind_values,
377
+                                 scalar $root_params->{$current_key};
299 378
                         }
300 379
                     }
380
+                    
381
+                    # Key is found
301 382
                     $found = 1;
302 383
                 }
303
-                
304
-                if (ref $key eq 'ARRAY') {
305
-                    $root_params = $root_params->[$key->[0]];
306
-                }
384
+                # First or middle key
307 385
                 else {
308
-                    next ACCESS_KEYS unless exists $root_params->{$key};
309
-                    $root_params = $root_params->{$key};
386
+                    # Key is array reference
387
+                    if (ref $current_key eq 'ARRAY') {
388
+                        # Go next key
389
+                        $root_params = $root_params->[$current_key->[0]];
390
+                    }
391
+                    # Key is string
392
+                    else {
393
+                        # Not found
394
+                        next ACCESS_KEYS
395
+                          unless exists $root_params->{$current_key};
396
+                        
397
+                        # Go next key
398
+                        $root_params = $root_params->{$current_key};
399
+                    }
310 400
                 }
311 401
             }
312 402
         }
313 403
         
404
+        # Key is not found
314 405
         unless ($found) {
315 406
             require Data::Dumper;
316 407
             my $key_info_dump  = Data::Dumper->Dump([$key_info], ['*key_info']);
... ...
@@ -334,7 +425,14 @@ DBI::Custom - Customizable simple DBI
334 425
 
335 426
 Version 0.0101
336 427
 
337
-=cut
428
+=head1 CAUTION
429
+
430
+This module is now experimental stage.
431
+
432
+I want you to try this module
433
+because I want this module stable, and not to damage your DB data by this module bug.
434
+
435
+Please tell me bug if you find
338 436
 
339 437
 =head1 SYNOPSIS
340 438
 
... ...
@@ -576,8 +674,6 @@ See also L<DBI::Custom::SQL::Template>
576 674
 If tranzaction is success, commit is execute. 
577 675
 If tranzation is died, rollback is execute.
578 676
 
579
-
580
-
581 677
 =head1 AUTHOR
582 678
 
583 679
 Yuki Kimoto, C<< <kimoto.yuki at gmail.com> >>
... ...
@@ -591,7 +687,4 @@ Copyright 2009 Yuki Kimoto, all rights reserved.
591 687
 This program is free software; you can redistribute it and/or modify it
592 688
 under the same terms as Perl itself.
593 689
 
594
-
595 690
 =cut
596
-
597
-1; # End of DBI::Custom
+20 -14
t/01-core.t
... ...
@@ -3,7 +3,6 @@ use strict;
3 3
 use warnings;
4 4
 
5 5
 use DBI::Custom;
6
-use Scalar::Util qw/blessed/;
7 6
 use DBI::Custom::SQL::Template;
8 7
 
9 8
 # Function for test name
... ...
@@ -12,15 +11,16 @@ sub test {
12 11
     $test = shift;
13 12
 }
14 13
 
15
-# Varialbes for test
14
+# Variables for test
15
+our $SQL_TMPL = {
16
+    0 => DBI::Custom::SQL::Template->new->tag_start(0),
17
+    1 => DBI::Custom::SQL::Template->new->tag_start(1),
18
+    2 => DBI::Custom::SQL::Template->new->tag_start(2)
19
+};
16 20
 my $dbi;
17
-my $sql_tmpl;
18 21
 
19
-my $sql_tmpl1 = DBI::Custom::SQL::Template->new->tag_start(0);
20
-my $sql_tmpl2 = DBI::Custom::SQL::Template->new->tag_start(1);
21
-my $sql_tmpl3 = DBI::Custom::SQL::Template->new->tag_start(2);
22 22
 
23
-test 'constructor';
23
+test 'Constructor';
24 24
 $dbi = DBI::Custom->new(
25 25
     user => 'a',
26 26
     password => 'b',
... ...
@@ -32,12 +32,12 @@ $dbi = DBI::Custom->new(
32 32
     bind_filter => 'f',
33 33
     fetch_filter => 'g',
34 34
     result_class => 'g',
35
-    sql_template => $sql_tmpl1,
35
+    sql_template => $SQL_TMPL->{0},
36 36
 );
37 37
 is_deeply($dbi,{user => 'a', password => 'b', data_source => 'c', 
38 38
                 dbi_options => {d => 1, e => 2}, filters => {f => 3}, bind_filter => 'f',
39 39
                 fetch_filter => 'g', result_class => 'g',
40
-                sql_template => $sql_tmpl1}, $test);
40
+                sql_template => $SQL_TMPL->{0}}, $test);
41 41
 isa_ok($dbi, 'DBI::Custom');
42 42
 
43 43
 
... ...
@@ -57,7 +57,7 @@ test 'Sub class constructor';
57 57
       ->bind_filter('f')
58 58
       ->fetch_filter('g')
59 59
       ->result_class('DBI::Custom::Result')
60
-      ->sql_template($sql_tmpl1)
60
+      ->sql_template($SQL_TMPL->{0})
61 61
     ;
62 62
 }
63 63
 $dbi = DBI::Custom::T1->new(
... ...
@@ -71,7 +71,7 @@ $dbi = DBI::Custom::T1->new(
71 71
     bind_filter => 'fo',
72 72
     fetch_filter => 'go',
73 73
     result_class => 'ho',
74
-    sql_template => $sql_tmpl1,
74
+    sql_template => $SQL_TMPL->{0},
75 75
 );
76 76
 is($dbi->user, 'ao', "$test : user");
77 77
 is($dbi->password, 'bo', "$test : passowr");
... ...
@@ -97,12 +97,12 @@ is($dbi->result_class, 'DBI::Custom::Result', "$test : result_class");
97 97
 is($dbi->sql_template->tag_start, 0, "$test : sql_template");
98 98
 isa_ok($dbi, 'DBI::Custom::T1');
99 99
 
100
+
100 101
 test 'Sub sub class constructor default';
101 102
 {
102 103
     package DBI::Custom::T1_2;
103 104
     use base 'DBI::Custom::T1';
104 105
 }
105
-
106 106
 $dbi = DBI::Custom::T1_2->new;
107 107
 is($dbi->user, 'a', "$test : user");
108 108
 is($dbi->password, 'b', "$test : passowrd");
... ...
@@ -132,7 +132,7 @@ test 'Customized sub class constructor default';
132 132
       ->bind_filter('fo')
133 133
       ->fetch_filter('go')
134 134
       ->result_class('ho')
135
-      ->sql_template($sql_tmpl2)
135
+      ->sql_template($SQL_TMPL->{1})
136 136
     ;
137 137
 }
138 138
 $dbi = DBI::Custom::T1_3->new;
... ...
@@ -160,7 +160,7 @@ $dbi = DBI::Custom::T1_3->new(
160 160
     bind_filter => 'f',
161 161
     fetch_filter => 'g',
162 162
     result_class => 'h',
163
-    sql_template => $sql_tmpl3,
163
+    sql_template => $SQL_TMPL->{2},
164 164
 );
165 165
 is($dbi->user, 'a', "$test : user");
166 166
 is($dbi->password, 'b', "$test : password");
... ...
@@ -173,3 +173,9 @@ is($dbi->result_class, 'h', "$test : result_class");
173 173
 is($dbi->sql_template->tag_start, 2, "$test : sql_template");
174 174
 isa_ok($dbi, 'DBI::Custom');
175 175
 
176
+
177
+test 'add_filters';
178
+$dbi = DBI::Custom->new;
179
+$dbi->add_filter(a => sub {1});
180
+is($dbi->filters->{a}->(), 1, $test);
181
+
+50 -8
t/02-sqlite.t
... ...
@@ -18,6 +18,8 @@ sub test {
18 18
     $test = shift;
19 19
 }
20 20
 
21
+
22
+
21 23
 # Varialbes for test
22 24
 our $CREATE_TABLE = {
23 25
     0 => 'create table table1 (key1 char(255), key2 char(255));',
... ...
@@ -28,6 +30,10 @@ our $SELECT_TMPL = {
28 30
     0 => 'select * from table1;'
29 31
 };
30 32
 
33
+our $DROP_TABLE = {
34
+    0 => 'drop table table1'
35
+};
36
+
31 37
 my $dbi;
32 38
 my $sth;
33 39
 my $tmpl;
... ...
@@ -46,13 +52,18 @@ my $update_query;
46 52
 my $ret_val;
47 53
 
48 54
 
49
-
50
-test 'Disconnect';
55
+test 'disconnect';
51 56
 $dbi = DBI::Custom->new(data_source => 'dbi:SQLite:dbname=:memory:');
52 57
 $dbi->connect;
53 58
 $dbi->disconnect;
54 59
 ok(!$dbi->dbh, $test);
55 60
 
61
+test 'connected';
62
+$dbi = DBI::Custom->new(data_source => 'dbi:SQLite:dbname=:memory:');
63
+ok(!$dbi->connected, "$test : not connected");
64
+$dbi->connect;
65
+ok($dbi->connected, "$test : connected");
66
+
56 67
 # Prepare table
57 68
 $dbi = DBI::Custom->new(data_source => 'dbi:SQLite:dbname=:memory:');
58 69
 $dbi->connect;
... ...
@@ -112,7 +123,7 @@ is_deeply(\@rows, [[1, 2], [3, 4]], "$test : fetch_all_hash list context");
112 123
 
113 124
 
114 125
 test 'Insert query return value';
115
-$dbi->reconnect;
126
+$dbi->do($DROP_TABLE->{0});
116 127
 $dbi->do($CREATE_TABLE->{0});
117 128
 $tmpl = "insert into table1 {insert key1 key2}";
118 129
 $query = $dbi->create_query($tmpl);
... ...
@@ -121,7 +132,7 @@ ok($ret_val, $test);
121 132
 
122 133
 
123 134
 test 'Direct execute';
124
-$dbi->reconnect;
135
+$dbi->do($DROP_TABLE->{0});
125 136
 $dbi->do($CREATE_TABLE->{0});
126 137
 $insert_tmpl = "insert into table1 {insert key1 key2}";
127 138
 $dbi->execute($insert_tmpl, {key1 => 1, key2 => 2}, sub {
... ...
@@ -140,7 +151,7 @@ is_deeply($rows, [{key1 => 1, key2 => 3}], $test);
140 151
 
141 152
 
142 153
 test 'Filter basic';
143
-$dbi->reconnect;
154
+$dbi->do($DROP_TABLE->{0});
144 155
 $dbi->do($CREATE_TABLE->{0});
145 156
 
146 157
 $insert_tmpl  = "insert into table1 {insert key1 key2};";
... ...
@@ -173,7 +184,7 @@ $result = $dbi->execute($select_query);
173 184
 $rows = $result->fetch_all_hash;
174 185
 is_deeply($rows, [{key1 => 1, key2 => 2}], "$test : no_fetch_filters no_bind_filters");
175 186
 
176
-$dbi->reconnect;
187
+$dbi->do($DROP_TABLE->{0});
177 188
 $dbi->do($CREATE_TABLE->{0});
178 189
 $insert_tmpl  = "insert into table1 {insert table1.key1 table1.key2}";
179 190
 $insert_query = $dbi->create_query($insert_tmpl);
... ...
@@ -209,7 +220,7 @@ is_deeply($rows, [{key1 => 2, key2 => 4}], "$test : bind_filter");
209 220
 
210 221
 
211 222
 test 'DBI::Custom::SQL::Template basic tag';
212
-$dbi->reconnect;
223
+$dbi->do($DROP_TABLE->{0});
213 224
 $dbi->do($CREATE_TABLE->{1});
214 225
 $sth = $dbi->prepare("insert into table1 (key1, key2, key3, key4, key5) values (?, ?, ?, ?, ?);");
215 226
 $sth->execute(1, 2, 3, 4, 5);
... ...
@@ -253,7 +264,7 @@ is_deeply($rows, [{key1 => 1, key2 => 2, key3 => 3, key4 => 4, key5 => 5}], "$te
253 264
 
254 265
 
255 266
 test 'DIB::Custom::SQL::Template in tag';
256
-$dbi->reconnect;
267
+$dbi->do($DROP_TABLE->{0});
257 268
 $dbi->do($CREATE_TABLE->{1});
258 269
 $sth = $dbi->prepare("insert into table1 (key1, key2, key3, key4, key5) values (?, ?, ?, ?, ?);");
259 270
 $sth->execute(1, 2, 3, 4, 5);
... ...
@@ -366,3 +377,34 @@ $rows = $result->fetch_all_hash;
366 377
 is_deeply($rows, [{key1 => 6, key2 => 6, key3 => 6, key4 => 6, key5 => 5},
367 378
                   {key1 => 6, key2 => 7, key3 => 8, key4 => 9, key5 => 10}], "$test : update tag #update with table name dot");
368 379
 
380
+
381
+test 'run_tansaction';
382
+$dbi->do($DROP_TABLE->{0});
383
+$dbi->do($CREATE_TABLE->{0});
384
+$dbi->run_tranzaction(sub {
385
+    $insert_tmpl = 'insert into table1 {insert key1 key2}';
386
+    $dbi->execute($insert_tmpl, {key1 => 1, key2 => 2});
387
+    $dbi->execute($insert_tmpl, {key1 => 3, key2 => 4});
388
+});
389
+$result = $dbi->execute($SELECT_TMPL->{0});
390
+$rows   = $result->fetch_all_hash;
391
+is_deeply($rows, [{key1 => 1, key2 => 2}, {key1 => 3, key2 => 4}], "$test : commit");
392
+
393
+$dbi->do($DROP_TABLE->{0});
394
+$dbi->do($CREATE_TABLE->{0});
395
+$dbi->dbh->{RaiseError} = 0;
396
+eval{
397
+    $dbi->run_tranzaction(sub {
398
+        $insert_tmpl = 'insert into table1 {insert key1 key2}';
399
+        $dbi->execute($insert_tmpl, {key1 => 1, key2 => 2});
400
+        die "Fatal Error";
401
+        $dbi->execute($insert_tmpl, {key1 => 3, key2 => 4});
402
+    })
403
+};
404
+like($@, qr/Fatal Error.*Rollback is success/ms, "$test : Rollback success message");
405
+ok(!$dbi->dbh->{RaiseError}, "$test : restore RaiseError value");
406
+$result = $dbi->execute($SELECT_TMPL->{0});
407
+$rows   = $result->fetch_all_hash;
408
+is_deeply($rows, [], "$test : rollback");
409
+
410
+
+5 -5
t/101-mysql_private.t
... ...
@@ -3,9 +3,9 @@ use strict;
3 3
 use warnings;
4 4
 
5 5
 # user password database
6
-our ($U, $P, $D) = connect_info();
6
+our ($USER, $PASSWORD, $DATABASE) = connect_info();
7 7
 
8
-plan skip_all => 'private MySQL test' unless $U;
8
+plan skip_all => 'private MySQL test' unless $USER;
9 9
 
10 10
 plan 'no_plan';
11 11
 
... ...
@@ -13,9 +13,9 @@ use DBI::Custom;
13 13
 use Scalar::Util 'blessed';
14 14
 {
15 15
     my $dbi = DBI::Custom->new(
16
-        user => $U,
17
-        password => $P,
18
-        data_source => "dbi:mysql:dbname=$D"
16
+        user => $USER,
17
+        password => $PASSWORD,
18
+        data_source => "dbi:mysql:dbname=$DATABASE"
19 19
     );
20 20
     $dbi->connect;
21 21