line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Data::Model::Driver::DBI; |
2
|
94
|
|
|
94
|
|
38190173
|
use strict; |
|
94
|
|
|
|
|
249
|
|
|
94
|
|
|
|
|
4071
|
|
3
|
94
|
|
|
94
|
|
800
|
use warnings; |
|
94
|
|
|
|
|
200
|
|
|
94
|
|
|
|
|
3720
|
|
4
|
94
|
|
|
94
|
|
549
|
use base 'Data::Model::Driver'; |
|
94
|
|
|
|
|
263
|
|
|
94
|
|
|
|
|
53479
|
|
5
|
|
|
|
|
|
|
|
6
|
94
|
|
|
94
|
|
595
|
use Carp (); |
|
94
|
|
|
|
|
179
|
|
|
94
|
|
|
|
|
2430
|
|
7
|
|
|
|
|
|
|
$Carp::Internal{(__PACKAGE__)}++; |
8
|
94
|
|
|
94
|
|
8196
|
use DBI; |
|
94
|
|
|
|
|
64728
|
|
|
94
|
|
|
|
|
4821
|
|
9
|
|
|
|
|
|
|
|
10
|
94
|
|
|
94
|
|
66952
|
use Data::Model::SQL; |
|
94
|
|
|
|
|
332
|
|
|
94
|
|
|
|
|
3990
|
|
11
|
94
|
|
|
94
|
|
65947
|
use Data::Model::Driver::DBI::DBD; |
|
94
|
|
|
|
|
243
|
|
|
94
|
|
|
|
|
335243
|
|
12
|
|
|
|
|
|
|
|
13
|
2768
|
|
|
2768
|
0
|
15856
|
sub dbd { $_[0]->{dbd} } |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub dbi_config { |
16
|
962
|
|
|
962
|
0
|
2084
|
my($self, $name) = @_; |
17
|
962
|
50
|
|
|
|
5867
|
$self->{dbi_config}->{$name} |
18
|
|
|
|
|
|
|
or Carp::croak "has not dbi_config name '$name'"; |
19
|
|
|
|
|
|
|
} |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub init { |
22
|
49
|
|
|
49
|
0
|
372
|
my $self = shift; |
23
|
49
|
50
|
|
|
|
894
|
if (my($type) = $self->{dsn} =~ /^dbi:(\w*)/i) { |
24
|
49
|
|
|
|
|
812
|
$self->{dbd} = Data::Model::Driver::DBI::DBD->new($type); |
25
|
|
|
|
|
|
|
} |
26
|
49
|
|
|
|
|
569
|
$self->{dbi_config} = +{ |
27
|
|
|
|
|
|
|
rw => +{ |
28
|
|
|
|
|
|
|
dsn => delete $self->{dsn}, |
29
|
|
|
|
|
|
|
username => delete $self->{username}, |
30
|
|
|
|
|
|
|
password => delete $self->{password}, |
31
|
|
|
|
|
|
|
connect_options => delete $self->{connect_options}, |
32
|
|
|
|
|
|
|
dbh => undef, |
33
|
|
|
|
|
|
|
}, |
34
|
|
|
|
|
|
|
}; |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
my %reuse_handles; |
38
|
|
|
|
|
|
|
sub init_db { |
39
|
36
|
|
|
36
|
0
|
105
|
my($self, $name, %args) = @_; |
40
|
36
|
|
|
|
|
124
|
my $dbi_config = $self->dbi_config($name); |
41
|
36
|
|
|
|
|
121
|
my $dsn = $dbi_config->{dsn}; |
42
|
36
|
|
|
|
|
77
|
my $dbh; |
43
|
36
|
100
|
|
|
|
168
|
if ($self->{reuse_dbh}) { |
44
|
2
|
|
|
|
|
5
|
$dbh = $reuse_handles{$dsn}; |
45
|
|
|
|
|
|
|
} |
46
|
36
|
100
|
33
|
|
|
209
|
unless ($dbh && ($args{no_ping} || $dbh->ping)) { |
|
|
|
66
|
|
|
|
|
47
|
35
|
50
|
|
|
|
673
|
$dbh = DBI->connect( |
48
|
|
|
|
|
|
|
$dsn, $dbi_config->{username}, $dbi_config->{password}, |
49
|
35
|
50
|
|
|
|
138
|
{ RaiseError => 1, PrintError => 0, AutoCommit => 1, %{ $dbi_config->{connect_options} || {} } }, |
50
|
|
|
|
|
|
|
) or Carp::croak("Connection error: " . $DBI::errstr); |
51
|
35
|
100
|
|
|
|
49723
|
if ($self->{reuse_dbh}) { |
52
|
1
|
|
|
|
|
5
|
$reuse_handles{$dsn} = $dbh; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
} |
55
|
36
|
|
|
|
|
142
|
$self->{__dbh_init_by_driver} = 1; |
56
|
36
|
|
|
|
|
348
|
$dbh; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub _get_dbh { |
60
|
926
|
|
|
926
|
|
1767
|
my $self = shift; |
61
|
926
|
|
50
|
|
|
3239
|
my $name = shift || 'rw'; |
62
|
926
|
|
|
|
|
2848
|
my %args = @_; # this option is experimental |
63
|
926
|
|
|
|
|
3827
|
my $dbi_config = $self->dbi_config($name); |
64
|
926
|
50
|
|
|
|
4996
|
unless ($args{no_ping}) { |
65
|
926
|
50
|
66
|
|
|
22179
|
$dbi_config->{dbh} = undef if $dbi_config->{dbh} and !$dbi_config->{dbh}->ping; |
66
|
|
|
|
|
|
|
} |
67
|
926
|
100
|
66
|
|
|
66934
|
unless ($dbi_config->{dbh} || $args{cannot_reconnect}) { |
68
|
36
|
50
|
|
|
|
174
|
if (my $getter = $self->{get_dbh}) { |
69
|
0
|
|
|
|
|
0
|
$dbi_config->{dbh} = $getter->(); |
70
|
|
|
|
|
|
|
} else { |
71
|
36
|
50
|
|
|
|
202
|
$dbi_config->{dbh} = $self->init_db($name, %args) or Carp::croak $self->last_error; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
} |
74
|
926
|
|
|
|
|
4218
|
$dbi_config->{dbh}; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
890
|
|
|
890
|
0
|
4331
|
sub rw_handle { shift->_get_dbh('rw', @_) }; |
78
|
448
|
|
|
448
|
0
|
1990
|
sub r_handle { shift->rw_handle(@_) } |
79
|
|
|
|
|
|
|
|
80
|
0
|
|
|
0
|
0
|
0
|
sub last_error {} |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub add_key_to_where { |
83
|
441
|
|
|
441
|
0
|
1309
|
my($self, $stmt, $columns, $key) = @_; |
84
|
441
|
50
|
|
|
|
1656
|
if ($key) { |
85
|
|
|
|
|
|
|
# add where |
86
|
441
|
|
|
|
|
721
|
my $i = 0; |
87
|
441
|
|
|
|
|
816
|
for my $i (0..( scalar(@{ $key }) - 1 )) { |
|
441
|
|
|
|
|
1906
|
|
88
|
489
|
|
|
|
|
2659
|
$stmt->add_where( $columns->[$i] => $key->[$i] ); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub add_index_to_where { |
94
|
61
|
|
|
61
|
0
|
154
|
my($self, $schema, $stmt, $index_obj) = @_; |
95
|
61
|
50
|
|
|
|
131
|
return unless my($index, $index_key) = (%{ $index_obj }); |
|
61
|
|
|
|
|
468
|
|
96
|
61
|
100
|
|
|
|
596
|
$index_key = [ $index_key ] unless ref($index_key) eq 'ARRAY'; |
97
|
61
|
|
|
|
|
163
|
for my $index_type (qw/ unique index /) { |
98
|
98
|
100
|
|
|
|
480
|
if (exists $schema->$index_type->{$index}) { |
99
|
61
|
|
|
|
|
222
|
$self->add_key_to_where($stmt, $schema->$index_type->{$index}, $index_key); |
100
|
61
|
|
|
|
|
209
|
last; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub bind_params { |
106
|
837
|
|
|
837
|
0
|
3474
|
my($self, $schema, $columns, $sth) = @_; |
107
|
837
|
|
|
|
|
3923
|
my $i = 1; |
108
|
837
|
|
|
|
|
1485
|
for my $column (@{ $columns }) { |
|
837
|
|
|
|
|
2818
|
|
109
|
1302
|
|
|
|
|
1961
|
my($col, $val) = @{ $column }; |
|
1302
|
|
|
|
|
8078
|
|
110
|
1302
|
|
|
|
|
6922
|
my $type = $schema->column_type($col); |
111
|
1302
|
|
|
|
|
4925
|
my $attr = $self->dbd->bind_param_attributes($type, $columns, $col); |
112
|
1302
|
|
100
|
|
|
20362
|
$sth->bind_param($i++, $val, $attr || undef); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub fetch { |
117
|
456
|
|
|
456
|
0
|
1214
|
my($self, $rec, $schema, $key, $columns, %args) = @_; |
118
|
|
|
|
|
|
|
|
119
|
456
|
100
|
|
|
|
1457
|
$columns = +{} unless $columns; |
120
|
|
|
|
|
|
|
|
121
|
456
|
|
50
|
|
|
4494
|
$columns->{select} ||= [ $schema->column_names ]; |
122
|
456
|
|
50
|
|
|
3715
|
$columns->{from} ||= []; |
123
|
456
|
|
|
|
|
833
|
unshift @{ $columns->{from} }, $schema->model; |
|
456
|
|
|
|
|
2738
|
|
124
|
|
|
|
|
|
|
|
125
|
456
|
|
|
|
|
1514
|
my $index_query = delete $columns->{index}; |
126
|
456
|
|
|
|
|
1035
|
my $stmt = Data::Model::SQL->new(%{ $columns }); |
|
456
|
|
|
|
|
4378
|
|
127
|
456
|
100
|
|
|
|
3765
|
$self->add_key_to_where($stmt, $schema->key, $key) if $key; |
128
|
456
|
100
|
|
|
|
1692
|
$self->add_index_to_where($schema, $stmt, $index_query) if $index_query; |
129
|
456
|
|
|
|
|
8838
|
my $sql = $stmt->as_sql; |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# bind_params |
132
|
456
|
|
|
|
|
948
|
my @params; |
133
|
456
|
|
|
|
|
933
|
for my $i (1..scalar(@{ $stmt->bind })) { |
|
456
|
|
|
|
|
2437
|
|
134
|
530
|
|
|
|
|
1806
|
push @params, [ $stmt->bind_column->[$i - 1], $stmt->bind->[$i - 1] ]; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
456
|
|
|
|
|
961
|
my @bind; |
138
|
456
|
|
|
|
|
4163
|
my $map = $stmt->select_map; |
139
|
456
|
|
|
|
|
1011
|
for my $col (@{ $stmt->select }) { |
|
456
|
|
|
|
|
2095
|
|
140
|
1056
|
50
|
|
|
|
5094
|
push @bind, \$rec->{ exists $map->{$col} ? $map->{$col} : $col }; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
456
|
|
|
|
|
1547
|
my $sth; |
144
|
456
|
|
|
|
|
952
|
eval { |
145
|
456
|
|
|
|
|
3146
|
my $dbh = $self->r_handle; |
146
|
456
|
|
|
|
|
3895
|
$self->start_query($sql, $stmt->bind); |
147
|
456
|
100
|
|
|
|
7081
|
$sth = $args{no_cached_prepare} ? $dbh->prepare($sql) : $dbh->prepare_cached($sql); |
148
|
456
|
|
|
|
|
63865
|
$self->bind_params($schema, \@params, $sth); |
149
|
456
|
|
|
|
|
75725
|
$sth->execute; |
150
|
456
|
|
|
|
|
5246
|
$sth->bind_columns(undef, @bind); |
151
|
|
|
|
|
|
|
}; |
152
|
456
|
50
|
|
|
|
22575
|
if ($@) { |
153
|
0
|
|
|
|
|
0
|
$self->_stack_trace($sth, $sql, $stmt->bind, $@); |
154
|
|
|
|
|
|
|
} |
155
|
456
|
|
|
|
|
8728
|
$sth; |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
sub lookup { |
159
|
106
|
|
|
106
|
0
|
6572
|
my($self, $schema, $id, %args) = @_; |
160
|
|
|
|
|
|
|
|
161
|
106
|
|
|
|
|
275
|
my $rec = +{}; |
162
|
106
|
|
|
|
|
620
|
my $sth = $self->fetch($rec, $schema, $id, {}, %args); |
163
|
|
|
|
|
|
|
|
164
|
106
|
|
|
|
|
2623
|
my $rv = $sth->fetch; |
165
|
106
|
|
|
|
|
663
|
$sth->finish; |
166
|
106
|
|
|
|
|
427
|
$self->end_query($sth); |
167
|
106
|
|
|
|
|
228
|
undef $sth; |
168
|
106
|
100
|
|
|
|
392
|
return unless $rv; |
169
|
92
|
|
|
|
|
535
|
return $rec; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub lookup_multi { |
173
|
23
|
|
|
23
|
0
|
71
|
my($self, $schema, $ids, %args) = @_; |
174
|
|
|
|
|
|
|
|
175
|
23
|
|
|
|
|
60
|
my @keys = @{ $schema->key }; |
|
23
|
|
|
|
|
85
|
|
176
|
23
|
|
|
|
|
60
|
my $query = {}; |
177
|
23
|
100
|
|
|
|
84
|
if (@keys == 1) { |
178
|
19
|
|
|
|
|
32
|
my @id_list = map { $_->[0] } @{ $ids }; |
|
49
|
|
|
|
|
336
|
|
|
19
|
|
|
|
|
49
|
|
179
|
19
|
|
|
|
|
103
|
$query = { where => [ $keys[0] => \@id_list ] }; |
180
|
|
|
|
|
|
|
} else { |
181
|
4
|
|
|
|
|
10
|
my @queries; |
182
|
4
|
|
|
|
|
9
|
for my $id (@{ $ids }) { |
|
4
|
|
|
|
|
12
|
|
183
|
7
|
|
|
|
|
12
|
my %query; |
184
|
7
|
|
|
|
|
10
|
@query{@keys} = @{ $id }; |
|
7
|
|
|
|
|
25
|
|
185
|
7
|
|
|
|
|
43
|
push @queries, '-and' => [ %query ]; |
186
|
|
|
|
|
|
|
} |
187
|
4
|
|
|
|
|
27
|
$query = { where => [ -or => \@queries ] }; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
23
|
|
|
|
|
61
|
my $rec = +{}; |
191
|
23
|
|
|
|
|
90
|
local $args{no_cached_prepare} = 1; |
192
|
23
|
|
|
|
|
149
|
my $sth = $self->fetch($rec, $schema, undef, $query, %args); |
193
|
|
|
|
|
|
|
|
194
|
23
|
|
|
|
|
58
|
my %resultlist; |
195
|
23
|
|
|
|
|
424
|
while ($sth->fetch) { |
196
|
42
|
|
|
|
|
325
|
my $key = $schema->get_key_array_by_hash($rec); |
197
|
42
|
|
|
|
|
63
|
$resultlist{join "\0", @{ $key }} = +{ %{ $rec } }; |
|
42
|
|
|
|
|
783
|
|
|
42
|
|
|
|
|
231
|
|
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
23
|
|
|
|
|
112
|
$sth->finish; |
201
|
23
|
|
|
|
|
86
|
$self->end_query($sth); |
202
|
23
|
|
|
|
|
46
|
undef $sth; |
203
|
|
|
|
|
|
|
|
204
|
23
|
|
|
|
|
658
|
\%resultlist; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
sub get { |
208
|
327
|
|
|
327
|
0
|
1091
|
my($self, $schema, $key, $columns, %args) = @_; |
209
|
|
|
|
|
|
|
|
210
|
327
|
|
|
|
|
1146
|
my $rec = +{}; |
211
|
327
|
|
|
|
|
1920
|
my $sth = $self->fetch($rec, $schema, $key, $columns, %args); |
212
|
|
|
|
|
|
|
|
213
|
327
|
|
|
|
|
688
|
my $i = 0; |
214
|
|
|
|
|
|
|
my $iterator = sub { |
215
|
1033
|
100
|
|
1033
|
|
4779
|
return unless $sth; |
216
|
1029
|
100
|
|
|
|
4872
|
return $rec if $i++ eq 1; |
217
|
759
|
100
|
|
|
|
13588
|
unless ($sth->fetch) { |
218
|
323
|
|
|
|
|
1589
|
$sth->finish; |
219
|
323
|
|
|
|
|
1151
|
$self->end_query($sth); |
220
|
323
|
|
|
|
|
563
|
undef $sth; |
221
|
323
|
|
|
|
|
1699
|
return; |
222
|
|
|
|
|
|
|
} |
223
|
436
|
|
|
|
|
1342
|
$rec; |
224
|
327
|
|
|
|
|
2260
|
}; |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# pre load |
227
|
327
|
100
|
|
|
|
1003
|
return unless $iterator->(); |
228
|
|
|
|
|
|
|
return $iterator, +{ |
229
|
274
|
100
|
|
274
|
|
4261
|
end => sub { if ($sth) { $sth->finish; $self->end_query($sth); undef $sth; } }, |
|
4
|
|
|
|
|
133
|
|
|
4
|
|
|
|
|
21
|
|
|
4
|
|
|
|
|
86
|
|
230
|
274
|
|
|
|
|
3137
|
}; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# insert or replace |
234
|
|
|
|
|
|
|
sub set { |
235
|
277
|
|
|
277
|
0
|
674
|
my $self = shift; |
236
|
277
|
|
|
|
|
1271
|
$self->_insert_or_replace(0, @_); |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub replace { |
240
|
4
|
|
|
4
|
0
|
14
|
my($self, $schema, $key, $columns, %args) = @_; |
241
|
4
|
50
|
|
|
|
21
|
if ($self->dbd->can_replace) { |
242
|
4
|
|
|
|
|
33
|
return $self->_insert_or_replace(1, $schema, $key, $columns, %args); |
243
|
|
|
|
|
|
|
} else { |
244
|
|
|
|
|
|
|
# $self->thx(sub { |
245
|
0
|
|
|
|
|
0
|
$self->delete($schema, $key, +{}, %args); |
246
|
0
|
|
|
|
|
0
|
return $self->set($schema, $key, $columns, %args); |
247
|
|
|
|
|
|
|
# }); |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub _on_duplicate_key_update { |
252
|
0
|
|
|
0
|
|
0
|
my($self, $schema, $columns, $args, $sql, $column_list) = @_; |
253
|
0
|
|
|
|
|
0
|
my $table = $schema->model; |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
# check unique keys |
256
|
0
|
|
|
|
|
0
|
my $keys = $schema->key; |
257
|
0
|
|
|
|
|
0
|
my $unique = $schema->unique; |
258
|
0
|
|
|
|
|
0
|
my $key_columns = []; |
259
|
0
|
0
|
|
|
|
0
|
if (scalar(@{ $keys }) >= 1) { |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
260
|
0
|
0
|
|
|
|
0
|
if (scalar(keys %{ $unique }) >= 1) { |
|
0
|
|
|
|
|
0
|
|
261
|
0
|
|
|
|
|
0
|
Carp::croak "on_duplicate_key_update support: $table has multi unique key"; |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
# OK |
264
|
0
|
|
|
|
|
0
|
$key_columns = $keys; |
265
|
0
|
|
|
|
|
0
|
} elsif (scalar(keys %{ $unique }) > 1) { |
266
|
0
|
|
|
|
|
0
|
Carp::croak "on_duplicate_key_update support: $table has multi unique key"; |
267
|
|
|
|
|
|
|
} elsif (scalar(keys %{ $unique }) == 1) { |
268
|
|
|
|
|
|
|
# OK |
269
|
0
|
|
|
|
|
0
|
while (my($k, $v) = each %{ $unique }) { |
|
0
|
|
|
|
|
0
|
|
270
|
0
|
|
|
|
|
0
|
$key_columns = $v; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
} else { |
273
|
0
|
|
|
|
|
0
|
Carp::croak "on_duplicate_key_update support: $table not has key or unique index"; |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
# check key num |
277
|
0
|
|
|
|
|
0
|
my $has_keys = 1; |
278
|
0
|
|
|
|
|
0
|
for my $k (@{ $key_columns }) { |
|
0
|
|
|
|
|
0
|
|
279
|
0
|
0
|
|
|
|
0
|
$has_keys = 0 unless defined $columns->{$k}; |
280
|
|
|
|
|
|
|
} |
281
|
0
|
0
|
|
|
|
0
|
Carp::croak "on_duplicate_key_update support: $table is insufficient keys" unless $has_keys; |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
# append sql |
284
|
0
|
|
|
|
|
0
|
my @set; |
285
|
0
|
|
|
|
|
0
|
for my $column (keys %{ $args }) { |
|
0
|
|
|
|
|
0
|
|
286
|
0
|
|
|
|
|
0
|
my $val = $args->{$column}; |
287
|
0
|
0
|
|
|
|
0
|
if (ref($val) eq 'SCALAR') { |
|
|
0
|
|
|
|
|
|
288
|
0
|
|
|
|
|
0
|
push @set, "$column = " . ${ $val }; |
|
0
|
|
|
|
|
0
|
|
289
|
|
|
|
|
|
|
} elsif (!ref($val)) { |
290
|
0
|
|
|
|
|
0
|
push @set, "$column = ?"; |
291
|
0
|
|
|
|
|
0
|
push @{ $column_list }, [ $column => $val ]; |
|
0
|
|
|
|
|
0
|
|
292
|
|
|
|
|
|
|
} else { |
293
|
0
|
|
|
|
|
0
|
Carp::confess 'No references other than a SCALAR reference can use a update column'; |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
} |
296
|
0
|
|
|
|
|
0
|
${ $sql } .= ' ON DUPLICATE KEY UPDATE ' . join(', ', @set) . "\n"; |
|
0
|
|
|
|
|
0
|
|
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
sub _insert_or_replace { |
300
|
281
|
|
|
281
|
|
1096
|
my($self, $is_replace, $schema, $key, $columns, %args) = @_; |
301
|
281
|
100
|
|
|
|
998
|
my $select_or_replace = $is_replace ? 'REPLACE' : 'INSERT'; |
302
|
|
|
|
|
|
|
|
303
|
281
|
|
|
|
|
1658
|
my $table = $schema->model; |
304
|
281
|
|
|
|
|
622
|
my $cols = [ keys %{ $columns } ]; |
|
281
|
|
|
|
|
1369
|
|
305
|
606
|
|
|
|
|
2858
|
my @column_list = map { |
306
|
281
|
|
|
|
|
718
|
[ $_ => $columns->{$_} ] |
307
|
281
|
|
|
|
|
771
|
} @{ $cols }; |
308
|
281
|
|
|
|
|
1377
|
my $sql = "$select_or_replace INTO $table\n"; |
309
|
281
|
|
|
|
|
1434
|
$sql .= '(' . join(', ', @{ $cols }) . ')' . "\n" . |
|
281
|
|
|
|
|
1578
|
|
310
|
281
|
|
|
|
|
744
|
'VALUES (' . join(', ', ('?') x @{ $cols }) . ')' . "\n"; |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# ON DUPLICATE KEY UPDATE support for MySQL |
313
|
281
|
50
|
33
|
|
|
1520
|
if ($args{on_duplicate_key_update} && $self->dbd->has_support('on_duplicate_key_update')) { |
314
|
0
|
|
|
|
|
0
|
$self->_on_duplicate_key_update($schema, $columns, $args{on_duplicate_key_update}, \$sql, \@column_list); |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
281
|
|
|
|
|
1049
|
my $sth; |
318
|
281
|
|
|
|
|
554
|
eval { |
319
|
281
|
|
|
|
|
1400
|
my $dbh = $self->rw_handle; |
320
|
281
|
|
|
|
|
1971
|
$self->start_query($sql, $columns); |
321
|
281
|
|
|
|
|
3242
|
$sth = $dbh->prepare_cached($sql); |
322
|
281
|
|
|
|
|
40500
|
$self->bind_params($schema, \@column_list, $sth); |
323
|
281
|
|
|
|
|
17631803
|
$sth->execute; |
324
|
277
|
|
|
|
|
7803
|
$sth->finish; |
325
|
277
|
|
|
|
|
3358
|
$self->end_query($sth); |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# set autoincrement key |
328
|
277
|
|
|
92
|
|
10124
|
$self->_set_auto_increment($schema, $columns, sub { $self->dbd->fetch_last_id( $schema, $columns, $dbh, $sth ) }); |
|
92
|
|
|
|
|
741
|
|
329
|
|
|
|
|
|
|
}; |
330
|
281
|
100
|
|
|
|
2883
|
if ($@) { |
331
|
4
|
|
|
|
|
23
|
$self->_stack_trace($sth, $sql, \@column_list, $@); |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
277
|
|
|
|
|
1323
|
undef $sth; |
335
|
277
|
|
|
|
|
9229
|
$columns; |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
# update |
339
|
|
|
|
|
|
|
sub _update { |
340
|
47
|
|
|
47
|
|
143
|
my($self, $schema, $changed_columns, $columns, $where_sql, $pre_bind, $pre_bind_column) = @_; |
341
|
|
|
|
|
|
|
|
342
|
47
|
|
|
|
|
99
|
my @bind; |
343
|
|
|
|
|
|
|
my @bind_column; |
344
|
0
|
|
|
|
|
0
|
my @set; |
345
|
47
|
|
|
|
|
186
|
for my $column (keys %{ $changed_columns }) { |
|
47
|
|
|
|
|
318
|
|
346
|
57
|
|
|
|
|
131
|
my $val = $columns->{$column}; |
347
|
57
|
100
|
|
|
|
282
|
if (ref($val) eq 'SCALAR') { |
|
|
50
|
|
|
|
|
|
348
|
1
|
|
|
|
|
2
|
push @set, "$column = " . ${ $val }; |
|
1
|
|
|
|
|
5
|
|
349
|
|
|
|
|
|
|
} elsif (!ref($val)) { |
350
|
56
|
|
|
|
|
160
|
push @set, "$column = ?"; |
351
|
56
|
|
|
|
|
108
|
push @bind, $val; |
352
|
56
|
|
|
|
|
265
|
push @bind_column, $column; |
353
|
|
|
|
|
|
|
} else { |
354
|
0
|
|
|
|
|
0
|
Carp::confess 'No references other than a SCALAR reference can use a update column'; |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
} |
357
|
47
|
|
|
|
|
108
|
push @bind, @{ $pre_bind }; |
|
47
|
|
|
|
|
106
|
|
358
|
47
|
|
|
|
|
78
|
push @bind_column, @{ $pre_bind_column }; |
|
47
|
|
|
|
|
106
|
|
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
# bind_params |
361
|
47
|
|
|
|
|
95
|
my @params; |
362
|
47
|
|
|
|
|
159
|
for my $i (1..scalar(@bind)) { |
363
|
107
|
|
|
|
|
477
|
push @params, [ $bind_column[$i - 1], $bind[$i - 1] ]; |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
47
|
|
|
|
|
243
|
my $sql = 'UPDATE ' . $schema->model . ' SET ' . join(', ', @set) . ' ' . $where_sql; |
367
|
47
|
|
|
|
|
103
|
my $sth; |
368
|
47
|
|
|
|
|
101
|
eval { |
369
|
47
|
|
|
|
|
173
|
my $dbh = $self->rw_handle; |
370
|
47
|
|
|
|
|
309
|
$self->start_query($sql, \@bind); |
371
|
47
|
|
|
|
|
1857
|
$sth = $dbh->prepare_cached($sql); |
372
|
47
|
|
|
|
|
11038
|
$self->bind_params($schema, \@params, $sth); |
373
|
47
|
|
|
|
|
2169035
|
$sth->execute; |
374
|
47
|
|
|
|
|
2680
|
$sth->finish; |
375
|
47
|
|
|
|
|
748
|
$self->end_query($sth); |
376
|
|
|
|
|
|
|
}; |
377
|
47
|
50
|
|
|
|
351
|
if ($@) { |
378
|
0
|
|
|
|
|
0
|
$self->_stack_trace($sth, $sql, \@params, $@); |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
47
|
50
|
|
|
|
294
|
if (wantarray) { |
382
|
0
|
|
|
|
|
0
|
my @ret = $sth->rows; |
383
|
0
|
|
|
|
|
0
|
undef $sth; |
384
|
0
|
|
|
|
|
0
|
return @ret; |
385
|
|
|
|
|
|
|
} else { |
386
|
47
|
|
|
|
|
420
|
my $ret = $sth->rows; |
387
|
47
|
|
|
|
|
161
|
undef $sth; |
388
|
47
|
|
|
|
|
2534
|
return $ret; |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
sub update { |
393
|
23
|
|
|
23
|
0
|
83
|
my($self, $schema, $old_key, $key, $old_columns, $columns, $changed_columns, %args) = @_; |
394
|
|
|
|
|
|
|
|
395
|
23
|
|
|
|
|
149
|
my $stmt = Data::Model::SQL->new; |
396
|
23
|
|
|
|
|
115
|
$self->add_key_to_where($stmt, $schema->key, $old_key); |
397
|
|
|
|
|
|
|
|
398
|
23
|
|
|
|
|
124
|
my $where_sql = $stmt->as_sql_where; |
399
|
23
|
50
|
|
|
|
102
|
return unless $where_sql; |
400
|
|
|
|
|
|
|
|
401
|
23
|
|
|
|
|
105
|
return $self->_update($schema, $changed_columns, $columns, $where_sql, $stmt->bind, $stmt->bind_column); |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
sub update_direct { |
405
|
24
|
|
|
24
|
0
|
300
|
my($self, $schema, $key, $query, $columns, %args) = @_; |
406
|
|
|
|
|
|
|
|
407
|
24
|
|
|
|
|
70
|
my $index_query = delete $query->{index}; |
408
|
24
|
|
|
|
|
49
|
my $stmt = Data::Model::SQL->new(%{ $query }); |
|
24
|
|
|
|
|
167
|
|
409
|
24
|
100
|
|
|
|
1338
|
$self->add_key_to_where($stmt, $schema->key, $key) if $key; |
410
|
24
|
100
|
|
|
|
100
|
$self->add_index_to_where($schema, $stmt, $index_query) if $index_query; |
411
|
|
|
|
|
|
|
|
412
|
24
|
|
|
|
|
116
|
my $where_sql = $stmt->as_sql_where; |
413
|
24
|
50
|
|
|
|
3761
|
return unless $where_sql; |
414
|
|
|
|
|
|
|
|
415
|
24
|
|
|
|
|
111
|
return $self->_update($schema, $columns, $columns, $where_sql, $stmt->bind, $stmt->bind_column); |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
# delete |
419
|
|
|
|
|
|
|
sub delete { |
420
|
53
|
|
|
53
|
0
|
304
|
my($self, $schema, $key, $columns, %args) = @_; |
421
|
|
|
|
|
|
|
|
422
|
53
|
|
|
|
|
228
|
$columns->{from} = [ $schema->model ]; |
423
|
53
|
|
|
|
|
191
|
my $index_query = delete $columns->{index}; |
424
|
53
|
|
|
|
|
115
|
my $stmt = Data::Model::SQL->new(%{ $columns }); |
|
53
|
|
|
|
|
402
|
|
425
|
53
|
100
|
|
|
|
392
|
$self->add_key_to_where($stmt, $schema->key, $key) if $key; |
426
|
53
|
50
|
|
|
|
203
|
$self->add_index_to_where($schema, $stmt, $index_query) if $index_query; |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
# bind_params |
429
|
53
|
|
|
|
|
98
|
my @params; |
430
|
53
|
|
|
|
|
99
|
for my $i (1..scalar(@{ $stmt->bind })) { |
|
53
|
|
|
|
|
469
|
|
431
|
59
|
|
|
|
|
232
|
push @params, [ $stmt->bind_column->[$i - 1], $stmt->bind->[$i - 1] ]; |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
|
434
|
53
|
|
|
|
|
238
|
my $sql = "DELETE " . $stmt->as_sql; |
435
|
53
|
|
|
|
|
112
|
my $sth; |
436
|
53
|
|
|
|
|
106
|
eval { |
437
|
53
|
|
|
|
|
183
|
my $dbh = $self->rw_handle; |
438
|
53
|
|
|
|
|
234
|
$self->start_query($sql, $stmt->bind); |
439
|
53
|
|
|
|
|
582
|
$sth = $dbh->prepare_cached($sql); |
440
|
53
|
|
|
|
|
8666
|
$self->bind_params($schema, \@params, $sth); |
441
|
53
|
|
|
|
|
1878751
|
$sth->execute; |
442
|
53
|
|
|
|
|
1046
|
$sth->finish; |
443
|
53
|
|
|
|
|
417
|
$self->end_query($sth); |
444
|
|
|
|
|
|
|
}; |
445
|
53
|
50
|
|
|
|
485
|
if ($@) { |
446
|
0
|
|
|
|
|
0
|
$self->_stack_trace($sth, $sql, $stmt->bind, $@); |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
|
449
|
53
|
50
|
|
|
|
441
|
if (wantarray) { |
450
|
0
|
|
|
|
|
0
|
my @ret = $sth->rows; |
451
|
0
|
|
|
|
|
0
|
undef $sth; |
452
|
0
|
|
|
|
|
0
|
return @ret; |
453
|
|
|
|
|
|
|
} else { |
454
|
53
|
|
|
|
|
1466
|
my $ret = $sth->rows; |
455
|
53
|
|
|
|
|
151
|
undef $sth; |
456
|
53
|
|
|
|
|
2868
|
return $ret; |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
# for schema |
461
|
|
|
|
|
|
|
sub _as_sql_hook { |
462
|
1370
|
|
|
1370
|
|
1704
|
my $self = shift; |
463
|
1370
|
|
|
|
|
2647
|
$self->dbd->_as_sql_hook(@_); |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
# stack trace |
467
|
|
|
|
|
|
|
sub _stack_trace { |
468
|
4
|
|
|
4
|
|
12
|
my($self, $sth, $sql, $binds, $reason) = @_; |
469
|
4
|
|
|
|
|
4374
|
require Data::Dumper; |
470
|
|
|
|
|
|
|
|
471
|
4
|
50
|
|
|
|
14128
|
if ($sth) { |
472
|
|
|
|
|
|
|
# finalize sth handle |
473
|
4
|
|
|
|
|
43
|
$sth->finish; |
474
|
4
|
|
|
|
|
18
|
$self->end_query($sth); |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
|
477
|
4
|
|
|
|
|
27
|
$sql =~ s/\n/\n /gm; |
478
|
4
|
|
|
|
|
19
|
Carp::croak sprintf <<"TRACE", $reason, $sql, Data::Dumper::Dumper($binds); |
479
|
|
|
|
|
|
|
**** { Data::Model::Driver::DBI 's Exception **** |
480
|
|
|
|
|
|
|
Reason : %s |
481
|
|
|
|
|
|
|
SQL : %s |
482
|
|
|
|
|
|
|
**** BINDS DUMP **** |
483
|
|
|
|
|
|
|
%s |
484
|
|
|
|
|
|
|
**** Data::Model::Driver::DBI 's Exception } **** |
485
|
|
|
|
|
|
|
TRACE |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
# profile |
489
|
837
|
|
|
837
|
0
|
1495
|
sub start_query {} |
490
|
837
|
|
|
837
|
0
|
2975
|
sub end_query {} |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
sub DESTROY { |
493
|
17
|
|
|
17
|
|
16960
|
my $self = shift; |
494
|
17
|
100
|
|
|
|
1207
|
return unless $self->{__dbh_init_by_driver}; |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
# if (my $dbh = $self->dbh) { |
497
|
|
|
|
|
|
|
# $dbh->disconnect if $dbh; |
498
|
|
|
|
|
|
|
# } |
499
|
|
|
|
|
|
|
} |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
# for transactions |
502
|
|
|
|
|
|
|
sub txn_begin { |
503
|
33
|
|
|
33
|
0
|
72
|
my $self = shift; |
504
|
33
|
|
|
|
|
87
|
$self->{active_transaction} = 1; |
505
|
33
|
|
|
|
|
132
|
my $dbh = $self->rw_handle; |
506
|
33
|
50
|
|
|
|
228
|
eval { $dbh->begin_work } or Carp::croak $@; |
|
33
|
|
|
|
|
920
|
|
507
|
|
|
|
|
|
|
} |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
sub txn_rollback { |
510
|
22
|
|
|
22
|
0
|
40
|
my $self = shift; |
511
|
22
|
50
|
|
|
|
75
|
return unless $self->{active_transaction}; |
512
|
22
|
|
|
|
|
73
|
my $dbh = $self->rw_handle; |
513
|
22
|
50
|
|
|
|
48
|
eval { $dbh->rollback } or Carp::croak $@; |
|
22
|
|
|
|
|
8198
|
|
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
sub txn_commit { |
517
|
11
|
|
|
11
|
0
|
23
|
my $self = shift; |
518
|
11
|
50
|
|
|
|
42
|
return unless $self->{active_transaction}; |
519
|
11
|
|
|
|
|
39
|
my $dbh = $self->rw_handle; |
520
|
11
|
50
|
|
|
|
26
|
eval { $dbh->commit } or Carp::croak $@; |
|
11
|
|
|
|
|
1241159
|
|
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
sub txn_end { |
524
|
33
|
|
|
33
|
0
|
122
|
$_[0]->{active_transaction} = 0; |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
1; |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=head1 NAME |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
Data::Model::Driver::DBI - storage driver for DBI |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=head1 SYNOPSIS |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
package MyDB; |
536
|
|
|
|
|
|
|
use base 'Data::Model'; |
537
|
|
|
|
|
|
|
use Data::Model::Schema; |
538
|
|
|
|
|
|
|
use Data::Model::Driver::DBI; |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
my $dbi_connect_options = {}; |
541
|
|
|
|
|
|
|
my $driver = Data::Model::Driver::DBI->new( |
542
|
|
|
|
|
|
|
dsn => 'dbi:mysql:host=localhost:database=test', |
543
|
|
|
|
|
|
|
username => 'user', |
544
|
|
|
|
|
|
|
password => 'password', |
545
|
|
|
|
|
|
|
connect_options => $dbi_connect_options, |
546
|
|
|
|
|
|
|
reuse_dbh => 1, # sharing dbh (experimental option) |
547
|
|
|
|
|
|
|
# When you use by MySQL, please set up |
548
|
|
|
|
|
|
|
# connect_options => { mysql_auto_reconnect => 1 }, |
549
|
|
|
|
|
|
|
# simultaneously. but mysql_auto_reconnect is very unsettled. |
550
|
|
|
|
|
|
|
); |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
base_driver $driver; |
553
|
|
|
|
|
|
|
install_model model_name => schema { |
554
|
|
|
|
|
|
|
.... |
555
|
|
|
|
|
|
|
}; |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
=head1 DESCRIPTION |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
DBD that is working now is only mysql and SQLite. |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
=head1 SEE ALSO |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
L, |
564
|
|
|
|
|
|
|
L |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
=head1 AUTHOR |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
Kazuhiro Osawa Eyappo shibuya plE |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
=head1 LICENSE |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
573
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
=cut |