| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package DBI::Easy; |
|
2
|
|
|
|
|
|
|
|
|
3
|
6
|
|
|
6
|
|
848346
|
use Class::Easy::Base; |
|
|
6
|
|
|
|
|
28128
|
|
|
|
6
|
|
|
|
|
42
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
6
|
|
|
6
|
|
16623
|
use DBI 1.611; |
|
|
6
|
|
|
|
|
64147
|
|
|
|
6
|
|
|
|
|
401
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#use Hash::Util; |
|
8
|
|
|
|
|
|
|
|
|
9
|
6
|
|
|
6
|
|
52
|
use vars qw($VERSION); |
|
|
6
|
|
|
|
|
17
|
|
|
|
6
|
|
|
|
|
490
|
|
|
10
|
|
|
|
|
|
|
$VERSION = '0.24'; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
|
13
|
|
|
|
|
|
|
# interface splitted to various sections: |
|
14
|
|
|
|
|
|
|
# sql generation stuff prefixed with sql and located |
|
15
|
|
|
|
|
|
|
# at DBI::Class::SQL |
|
16
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
|
17
|
|
|
|
|
|
|
|
|
18
|
6
|
|
|
6
|
|
5734
|
use DBI::Easy::SQL; |
|
|
6
|
|
|
|
|
17
|
|
|
|
6
|
|
|
|
|
216
|
|
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
|
21
|
|
|
|
|
|
|
# real dbh operations contains methods fetch_* and no_fetch |
|
22
|
|
|
|
|
|
|
# and placed in DBI::Class::DBH |
|
23
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
|
24
|
|
|
|
|
|
|
|
|
25
|
6
|
|
|
6
|
|
4425
|
use DBI::Easy::DBH; |
|
|
6
|
|
|
|
|
20
|
|
|
|
6
|
|
|
|
|
187
|
|
|
26
|
|
|
|
|
|
|
|
|
27
|
6
|
|
|
6
|
|
3632
|
use DBI::Easy::DriverPatcher; |
|
|
6
|
|
|
|
|
16
|
|
|
|
6
|
|
|
|
|
150
|
|
|
28
|
|
|
|
|
|
|
|
|
29
|
6
|
|
|
6
|
|
3276
|
use DBI::Easy::Helper; |
|
|
6
|
|
|
|
|
22
|
|
|
|
6
|
|
|
|
|
7961
|
|
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# bwahahahaha |
|
32
|
|
|
|
|
|
|
our %GREP_COLUMN_INFO = qw(TYPE_NAME 1 mysql_values 1); |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
our $wrapper = 1; |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
our $H = 'DBI::Easy::Helper'; |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub new { |
|
39
|
77
|
|
|
77
|
1
|
7143
|
my $class = shift; |
|
40
|
|
|
|
|
|
|
|
|
41
|
77
|
|
|
|
|
125
|
my $params; |
|
42
|
|
|
|
|
|
|
my $init_params; |
|
43
|
|
|
|
|
|
|
|
|
44
|
77
|
100
|
|
|
|
1238
|
$init_params = $class->_init (@_) |
|
45
|
|
|
|
|
|
|
if $class->can ('_init'); |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
$params = $init_params || {(@_ == 1 && ref $_[0] && ref $_[0] eq 'HASH') |
|
48
|
77
|
|
100
|
|
|
576
|
? %{$_[0]} |
|
49
|
|
|
|
|
|
|
: @_ |
|
50
|
|
|
|
|
|
|
}; |
|
51
|
|
|
|
|
|
|
|
|
52
|
77
|
|
|
|
|
783
|
bless $params, $class; |
|
53
|
|
|
|
|
|
|
} |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub import { |
|
56
|
33
|
|
|
33
|
|
161
|
my $class = shift; |
|
57
|
|
|
|
|
|
|
|
|
58
|
33
|
100
|
|
|
|
61
|
unless (${"${class}::imported"}) { |
|
|
33
|
|
|
|
|
414
|
|
|
59
|
23
|
|
|
|
|
261
|
make_accessor ($class, 'dbh', is => 'rw', global => 1); |
|
60
|
|
|
|
|
|
|
make_accessor ($class, 'dbh_modify', is => 'rw', global => 1, default => sub { |
|
61
|
42
|
|
|
42
|
|
137
|
return shift->dbh; |
|
62
|
23
|
|
|
|
|
1212
|
}); |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
|
|
65
|
33
|
100
|
66
|
|
|
998
|
if (! ${"${class}::wrapper"} and $class ne __PACKAGE__ and ! ${"${class}::imported"} ) { |
|
|
33
|
|
100
|
|
|
688
|
|
|
|
21
|
|
|
|
|
147
|
|
|
66
|
|
|
|
|
|
|
|
|
67
|
17
|
|
|
|
|
104
|
debug "importing $class"; |
|
68
|
|
|
|
|
|
|
|
|
69
|
17
|
|
|
|
|
1375
|
my $t = timer ('init_class'); |
|
70
|
17
|
|
|
|
|
1040
|
$class->_init_class; |
|
71
|
|
|
|
|
|
|
|
|
72
|
17
|
|
|
|
|
824
|
$t->lap ('init_db'); |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# we call _init_db from package before real db |
|
75
|
17
|
|
|
|
|
289
|
$class->_init_db; |
|
76
|
|
|
|
|
|
|
|
|
77
|
17
|
|
|
|
|
1075
|
$t->lap ("init_collection $class"); |
|
78
|
|
|
|
|
|
|
|
|
79
|
17
|
100
|
|
|
|
246
|
$class->_init_collection |
|
80
|
|
|
|
|
|
|
if $class->is_collection; |
|
81
|
|
|
|
|
|
|
|
|
82
|
17
|
|
|
|
|
421
|
$t->lap ("dbh check and accessors $class"); |
|
83
|
|
|
|
|
|
|
|
|
84
|
17
|
50
|
33
|
|
|
145
|
die "can't use database class '$class' without db connection: $DBI::errstr" |
|
85
|
|
|
|
|
|
|
if ! $class->dbh or $class->dbh eq '0E0'; |
|
86
|
|
|
|
|
|
|
|
|
87
|
17
|
50
|
|
|
|
722
|
die "can't retrieve table '".$class->table_name."' columns for '$class'" |
|
88
|
|
|
|
|
|
|
unless $class->_init_make_accessors; |
|
89
|
|
|
|
|
|
|
|
|
90
|
17
|
|
|
|
|
118
|
$t->lap ("init_last $class"); |
|
91
|
|
|
|
|
|
|
|
|
92
|
17
|
|
|
|
|
299
|
$class->_init_last; |
|
93
|
|
|
|
|
|
|
|
|
94
|
17
|
|
|
|
|
69
|
$t->end; |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# my $driver = $class->dbh->get_info (17); |
|
97
|
|
|
|
|
|
|
# warn "driver name from |
|
98
|
|
|
|
|
|
|
# get_info ($DBI::Const::GetInfoType{SQL_DBMS_NAME}): $driver"; |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
|
|
101
|
33
|
|
|
|
|
133
|
${"${class}::imported"} = 1; |
|
|
33
|
|
|
|
|
138
|
|
|
102
|
|
|
|
|
|
|
|
|
103
|
33
|
50
|
|
|
|
506
|
$class::SUPER->import (@_) |
|
104
|
|
|
|
|
|
|
if (defined $class::SUPER); |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub _init_db { |
|
109
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
110
|
0
|
|
|
|
|
0
|
$self->dbh (DBI->connect); |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub _init_class { |
|
114
|
17
|
|
|
17
|
|
44
|
my $self = shift; |
|
115
|
|
|
|
|
|
|
|
|
116
|
17
|
|
33
|
|
|
667
|
my $ref = ref $self || $self; |
|
117
|
|
|
|
|
|
|
|
|
118
|
17
|
|
|
|
|
111
|
my @pack_chunks = split /\:\:/, $ref; |
|
119
|
|
|
|
|
|
|
|
|
120
|
17
|
|
|
|
|
40
|
my $is_collection = 0; |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# fix for collections |
|
123
|
17
|
100
|
|
|
|
82
|
if ($pack_chunks[-1] eq 'Collection') { |
|
|
|
50
|
|
|
|
|
|
|
124
|
6
|
|
|
|
|
12
|
pop @pack_chunks; |
|
125
|
|
|
|
|
|
|
|
|
126
|
6
|
|
|
|
|
30
|
make_accessor ($ref, 'record_package', is => 'rw', global => 1); |
|
127
|
|
|
|
|
|
|
|
|
128
|
6
|
|
|
|
|
215
|
$is_collection = 1; |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
} elsif ($pack_chunks[-1] eq 'Record') { |
|
131
|
0
|
|
|
|
|
0
|
pop @pack_chunks; |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
17
|
|
|
|
|
71
|
make_accessor ($ref, 'is_collection', default => $is_collection); |
|
135
|
|
|
|
|
|
|
|
|
136
|
17
|
|
|
|
|
992
|
my $table_name = DBI::Easy::Helper::table_from_package ($pack_chunks[-1]); |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# dies when this method called without object reference; |
|
139
|
|
|
|
|
|
|
# expected behaviour |
|
140
|
|
|
|
|
|
|
|
|
141
|
17
|
|
|
|
|
43
|
my $common_table_prefix = ''; |
|
142
|
|
|
|
|
|
|
|
|
143
|
17
|
100
|
|
|
|
570
|
$common_table_prefix = $ref->common_table_prefix |
|
144
|
|
|
|
|
|
|
if $ref->can ('common_table_prefix'); |
|
145
|
|
|
|
|
|
|
|
|
146
|
17
|
50
|
|
|
|
647
|
make_accessor ( |
|
147
|
|
|
|
|
|
|
$ref, 'table_name', is => 'rw', global => 1, |
|
148
|
|
|
|
|
|
|
default => $common_table_prefix . $table_name |
|
149
|
|
|
|
|
|
|
) unless $ref->can ('table_name'); |
|
150
|
|
|
|
|
|
|
|
|
151
|
17
|
|
|
|
|
723
|
make_accessor ($ref, '_date_format', is => 'rw', global => 1); |
|
152
|
|
|
|
|
|
|
|
|
153
|
17
|
50
|
|
|
|
786
|
make_accessor ( |
|
154
|
|
|
|
|
|
|
$ref, 'column_prefix', is => 'rw', global => 1, |
|
155
|
|
|
|
|
|
|
default => $ref->table_name . "_" |
|
156
|
|
|
|
|
|
|
) unless $ref->can ('column_prefix'); |
|
157
|
|
|
|
|
|
|
|
|
158
|
17
|
|
|
|
|
773
|
make_accessor ($ref, 'fieldset', is => 'rw', default => '*'); |
|
159
|
|
|
|
|
|
|
|
|
160
|
17
|
|
|
|
|
749
|
make_accessor ($ref, 'prepare_method', is => 'rw', global => 1, |
|
161
|
|
|
|
|
|
|
default => 'prepare_cached'); |
|
162
|
17
|
|
|
|
|
598
|
make_accessor ($ref, 'prepare_param', is => 'rw', global => 1, |
|
163
|
|
|
|
|
|
|
default => 3); |
|
164
|
17
|
|
|
|
|
613
|
make_accessor ($ref, 'undef_as_null', is => 'rw', global => 1, |
|
165
|
|
|
|
|
|
|
default => 0); |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
sub _init_collection { |
|
170
|
6
|
|
|
6
|
|
132
|
my $self = shift; |
|
171
|
|
|
|
|
|
|
|
|
172
|
6
|
|
|
|
|
27
|
my $rec_pkg = $self->record_package; |
|
173
|
|
|
|
|
|
|
|
|
174
|
6
|
50
|
|
|
|
135
|
unless ($rec_pkg) { |
|
175
|
6
|
|
33
|
|
|
39
|
my $ref = ref $self || $self; |
|
176
|
|
|
|
|
|
|
|
|
177
|
6
|
|
|
|
|
35
|
my @pack_chunks = split /\:\:/, $ref; |
|
178
|
|
|
|
|
|
|
|
|
179
|
6
|
|
|
|
|
13
|
pop @pack_chunks; |
|
180
|
|
|
|
|
|
|
|
|
181
|
6
|
|
|
|
|
22
|
$rec_pkg = join '::', @pack_chunks; |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# TODO: move to Class::Easy |
|
184
|
6
|
50
|
|
|
|
26
|
unless (try_to_use ($rec_pkg)) { |
|
185
|
0
|
0
|
|
|
|
0
|
die unless try_to_use ($rec_pkg . '::Record'); |
|
186
|
|
|
|
|
|
|
} |
|
187
|
|
|
|
|
|
|
|
|
188
|
6
|
|
|
|
|
5727
|
$self->record_package ($rec_pkg); |
|
189
|
|
|
|
|
|
|
} |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub _detect_vendor { |
|
194
|
17
|
|
|
17
|
|
35
|
my $class = shift; |
|
195
|
|
|
|
|
|
|
|
|
196
|
17
|
|
|
|
|
60
|
my $dbh = $class->dbh; |
|
197
|
|
|
|
|
|
|
|
|
198
|
17
|
|
|
|
|
390
|
my $vendor = lc ($dbh->get_info(17)); |
|
199
|
|
|
|
|
|
|
|
|
200
|
17
|
|
|
|
|
243
|
make_accessor ($class, 'dbh_vendor', default => $vendor); |
|
201
|
|
|
|
|
|
|
|
|
202
|
17
|
|
|
|
|
869
|
my $vendor_pack = "DBI::Easy::Vendor::$vendor"; |
|
203
|
17
|
|
|
|
|
76
|
my $have_vendor_pack = try_to_use_quiet ($vendor_pack); |
|
204
|
|
|
|
|
|
|
|
|
205
|
17
|
50
|
|
|
|
15926
|
unless ($have_vendor_pack) { |
|
206
|
17
|
|
|
|
|
41
|
$vendor_pack = "DBI::Easy::Vendor::Base"; |
|
207
|
17
|
50
|
|
|
|
60
|
die unless try_to_use_quiet ($vendor_pack); |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
|
|
210
|
6
|
|
|
6
|
|
65
|
no strict 'refs'; |
|
|
6
|
|
|
|
|
12
|
|
|
|
6
|
|
|
|
|
390
|
|
|
211
|
|
|
|
|
|
|
|
|
212
|
17
|
|
|
|
|
2348
|
push @{"$class\::ISA"}, $vendor_pack; |
|
|
17
|
|
|
|
|
754
|
|
|
213
|
|
|
|
|
|
|
|
|
214
|
6
|
|
|
6
|
|
36
|
use strict 'refs'; |
|
|
6
|
|
|
|
|
13
|
|
|
|
6
|
|
|
|
|
16417
|
|
|
215
|
|
|
|
|
|
|
|
|
216
|
17
|
|
|
|
|
256
|
$class->_init_vendor; |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
} |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# here we retrieve fields and create make_accessors |
|
221
|
|
|
|
|
|
|
sub _init_make_accessors { |
|
222
|
17
|
|
|
17
|
|
38
|
my $class = shift; |
|
223
|
|
|
|
|
|
|
|
|
224
|
17
|
|
|
|
|
86
|
my $table_name = $class->table_name; |
|
225
|
17
|
|
|
|
|
125
|
my $column_prefix = $class->column_prefix; |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# detecting vendor |
|
228
|
17
|
|
|
|
|
220
|
$class->_detect_vendor; |
|
229
|
|
|
|
|
|
|
|
|
230
|
17
|
|
|
|
|
150
|
my $t = timer ('columns info wrapper'); |
|
231
|
|
|
|
|
|
|
|
|
232
|
17
|
|
|
|
|
1106
|
my $columns = $class->_dbh_columns_info; |
|
233
|
|
|
|
|
|
|
|
|
234
|
17
|
|
|
|
|
65
|
$t->end; |
|
235
|
|
|
|
|
|
|
|
|
236
|
17
|
|
|
|
|
153
|
make_accessor ($class, 'columns', default => $columns); |
|
237
|
17
|
|
|
|
|
962
|
make_accessor ($class, 'column_values', is => 'rw'); |
|
238
|
|
|
|
|
|
|
|
|
239
|
17
|
|
|
|
|
584
|
my $fields = {}; |
|
240
|
|
|
|
|
|
|
|
|
241
|
17
|
|
|
|
|
65
|
make_accessor ($class, 'fields', default => $fields); |
|
242
|
17
|
|
|
|
|
633
|
make_accessor ($class, 'field_values', is => 'rw'); |
|
243
|
|
|
|
|
|
|
|
|
244
|
17
|
|
|
|
|
786
|
my $pri_key; |
|
245
|
|
|
|
|
|
|
my $pri_key_column; |
|
246
|
|
|
|
|
|
|
|
|
247
|
17
|
|
|
|
|
76
|
foreach my $col_name (keys %$columns) { |
|
248
|
81
|
|
|
|
|
1892
|
my $col_meta = $columns->{$col_name}; |
|
249
|
|
|
|
|
|
|
# here we translate rows |
|
250
|
81
|
|
|
|
|
315
|
my $field_name = lc ($col_name); # oracle fix |
|
251
|
|
|
|
|
|
|
|
|
252
|
81
|
100
|
33
|
|
|
1304
|
if ( |
|
|
|
|
66
|
|
|
|
|
|
253
|
|
|
|
|
|
|
defined $column_prefix |
|
254
|
|
|
|
|
|
|
and $column_prefix ne '' |
|
255
|
|
|
|
|
|
|
and $col_name =~ /^$column_prefix(.*)/i |
|
256
|
|
|
|
|
|
|
) { |
|
257
|
32
|
|
|
|
|
166
|
$field_name = lc($1); |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# field meta referenced to column meta |
|
261
|
|
|
|
|
|
|
# no we can use $field_meta->{col_name} and $col_meta->{field_name} |
|
262
|
81
|
|
|
|
|
182
|
$fields->{$field_name} = $col_meta; |
|
263
|
|
|
|
|
|
|
|
|
264
|
81
|
|
|
|
|
175
|
$col_meta->{field_name} = $field_name; |
|
265
|
|
|
|
|
|
|
|
|
266
|
81
|
50
|
33
|
|
|
251
|
if ($col_meta->{type_name} eq 'ENUM' and $#{$col_meta->{mysql_values}} >= 0) { |
|
|
0
|
|
|
|
|
0
|
|
|
267
|
0
|
|
|
|
|
0
|
make_accessor ($class, "${field_name}_variants", |
|
268
|
|
|
|
|
|
|
default => $col_meta->{mysql_values}); |
|
269
|
|
|
|
|
|
|
} |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# attach decoder for complex datatypes, as example date, datetime, timestamp |
|
272
|
81
|
|
|
|
|
387
|
$class->attach_decoder ($col_meta); |
|
273
|
|
|
|
|
|
|
|
|
274
|
81
|
100
|
66
|
|
|
383
|
if (exists $col_meta->{X_IS_PK} and $col_meta->{X_IS_PK} == 1) { |
|
275
|
|
|
|
|
|
|
|
|
276
|
17
|
50
|
|
|
|
64
|
if ($pri_key) { |
|
277
|
0
|
|
|
|
|
0
|
warn "multiple pri keys: $fields->{$pri_key}->{column_name} and $field_name"; |
|
278
|
|
|
|
|
|
|
} else { |
|
279
|
17
|
|
|
|
|
35
|
$pri_key = $field_name; |
|
280
|
17
|
|
|
|
|
48
|
$pri_key_column = $col_name; |
|
281
|
|
|
|
|
|
|
} |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
my $fetch_by_pk_sub = sub { |
|
284
|
5
|
|
|
5
|
|
97
|
my $package = shift; |
|
285
|
5
|
|
|
|
|
9
|
my $value = shift; |
|
286
|
|
|
|
|
|
|
|
|
287
|
5
|
|
|
|
|
74
|
return $package->fetch ({$field_name => $value}, @_); |
|
288
|
17
|
|
|
|
|
99
|
}; |
|
289
|
|
|
|
|
|
|
|
|
290
|
17
|
|
|
|
|
83
|
make_accessor ($class, "fetch_by_$field_name", default => $fetch_by_pk_sub); |
|
291
|
17
|
|
|
|
|
608
|
make_accessor ($class, "fetch_by_pk", default => $fetch_by_pk_sub); |
|
292
|
|
|
|
|
|
|
} |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
# access to the precise field value or column value without cool accessors |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
make_accessor ($class, $field_name, default => sub { |
|
297
|
47
|
|
|
47
|
|
6823
|
my $self = shift; |
|
298
|
|
|
|
|
|
|
|
|
299
|
47
|
100
|
|
|
|
163
|
unless (@_) { |
|
300
|
|
|
|
|
|
|
# bad style? |
|
301
|
|
|
|
|
|
|
return |
|
302
|
44
|
|
66
|
|
|
436
|
$self->{field_values}->{$field_name} || ( |
|
303
|
|
|
|
|
|
|
exists $self->columns->{$col_name}->{decoder} |
|
304
|
|
|
|
|
|
|
? $self->columns->{$col_name}->{decoder}->($self) # ($self->{column_values}->{$col_name}); |
|
305
|
|
|
|
|
|
|
: $self->{column_values}->{$col_name}); |
|
306
|
|
|
|
|
|
|
} |
|
307
|
|
|
|
|
|
|
|
|
308
|
3
|
50
|
|
|
|
18
|
die "too many parameters" if @_ > 1; |
|
309
|
|
|
|
|
|
|
|
|
310
|
3
|
|
|
|
|
49
|
$self->assign_values ($field_name => $_[0]); |
|
311
|
|
|
|
|
|
|
|
|
312
|
81
|
|
|
|
|
920
|
}); |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
make_accessor ($class, "_fetched_${field_name}", default => sub { |
|
315
|
1
|
|
|
1
|
|
564
|
my $self = shift; |
|
316
|
|
|
|
|
|
|
|
|
317
|
1
|
50
|
|
|
|
5
|
unless (@_) { |
|
318
|
1
|
|
|
|
|
7
|
return $self->{column_values}->{$col_name}; |
|
319
|
|
|
|
|
|
|
} |
|
320
|
|
|
|
|
|
|
|
|
321
|
0
|
|
|
|
|
0
|
die "too many parameters"; |
|
322
|
81
|
|
|
|
|
3123
|
}); |
|
323
|
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
make_accessor ($class, "_raw_${field_name}", default => sub { |
|
325
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
|
326
|
|
|
|
|
|
|
|
|
327
|
1
|
50
|
|
|
|
6
|
die "you must supply one parameter" unless @_ == 1; |
|
328
|
|
|
|
|
|
|
|
|
329
|
1
|
|
|
|
|
5
|
$self->{field_values}->{$field_name} = $_[0]; |
|
330
|
81
|
|
|
|
|
3476
|
}); |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
} |
|
333
|
|
|
|
|
|
|
|
|
334
|
17
|
|
|
|
|
1238
|
make_accessor ($class, '_pk_', default => $pri_key); |
|
335
|
17
|
|
|
|
|
559
|
make_accessor ($class, '_pk_column_', default => $pri_key_column); |
|
336
|
|
|
|
|
|
|
|
|
337
|
17
|
|
|
|
|
950
|
return $class; |
|
338
|
|
|
|
|
|
|
} |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub assign_values { |
|
341
|
3
|
|
|
3
|
0
|
6
|
my $self = shift; |
|
342
|
3
|
|
|
|
|
12
|
my $to_assign = {@_}; |
|
343
|
|
|
|
|
|
|
|
|
344
|
3
|
|
|
|
|
15
|
foreach my $k (keys %$to_assign) { |
|
345
|
3
|
|
|
|
|
26
|
$self->{field_values}->{$k} = $to_assign->{$k}; |
|
346
|
|
|
|
|
|
|
} |
|
347
|
|
|
|
|
|
|
} |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
sub attach_decoder { |
|
350
|
81
|
|
|
81
|
0
|
113
|
my $class = shift; |
|
351
|
81
|
|
|
|
|
98
|
my $col_meta = shift; |
|
352
|
|
|
|
|
|
|
|
|
353
|
81
|
|
|
|
|
132
|
my $type = $col_meta->{type_name}; |
|
354
|
|
|
|
|
|
|
|
|
355
|
81
|
50
|
33
|
|
|
452
|
if (defined $type and $H->is_rich_type ($type)) { |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
$col_meta->{decoder} = sub { |
|
358
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
359
|
0
|
|
|
|
|
0
|
my $value = $self->column_values->{$col_meta->{column_name}}; |
|
360
|
0
|
|
|
|
|
0
|
return $H->value_from_type ($type, $value, $self); |
|
361
|
|
|
|
|
|
|
} |
|
362
|
0
|
|
|
|
|
0
|
} |
|
363
|
|
|
|
|
|
|
} |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
|
|
366
|
17
|
|
|
17
|
|
29
|
sub _init_last { |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
} |
|
369
|
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
sub _dbh_columns_info { |
|
371
|
17
|
|
|
17
|
|
41
|
my $class = shift; |
|
372
|
|
|
|
|
|
|
|
|
373
|
17
|
|
|
|
|
58
|
my $ts = timer ('inside columns info'); |
|
374
|
|
|
|
|
|
|
|
|
375
|
17
|
|
|
|
|
853
|
my $dbh = $class->dbh; |
|
376
|
|
|
|
|
|
|
|
|
377
|
17
|
|
|
|
|
128
|
my $table_name = $class->table_name; |
|
378
|
|
|
|
|
|
|
|
|
379
|
17
|
|
|
|
|
115
|
$ts->lap ('make accessor'); |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
# preparations |
|
382
|
17
|
|
|
|
|
300
|
make_accessor ( |
|
383
|
|
|
|
|
|
|
$class, 'table_quoted', |
|
384
|
|
|
|
|
|
|
default => $class->quote_identifier ($table_name) |
|
385
|
|
|
|
|
|
|
); |
|
386
|
|
|
|
|
|
|
|
|
387
|
17
|
|
|
|
|
1536
|
my $real_row_count = 0; |
|
388
|
|
|
|
|
|
|
|
|
389
|
17
|
|
|
|
|
39
|
my $column_info = {}; |
|
390
|
|
|
|
|
|
|
|
|
391
|
17
|
|
|
|
|
68
|
$ts->lap ('eval column info'); |
|
392
|
|
|
|
|
|
|
|
|
393
|
17
|
|
|
|
|
106
|
eval { |
|
394
|
|
|
|
|
|
|
|
|
395
|
17
|
|
|
|
|
56
|
my $t = timer ('column info call'); |
|
396
|
|
|
|
|
|
|
|
|
397
|
17
|
|
|
|
|
795
|
my $sth = $dbh->column_info( |
|
398
|
|
|
|
|
|
|
undef, undef, $table_name, '%' |
|
399
|
|
|
|
|
|
|
); |
|
400
|
|
|
|
|
|
|
|
|
401
|
17
|
|
|
|
|
53856
|
$t->lap ('execute'); |
|
402
|
|
|
|
|
|
|
|
|
403
|
17
|
50
|
|
|
|
243
|
$sth->execute |
|
404
|
|
|
|
|
|
|
unless $sth->{Executed}; |
|
405
|
|
|
|
|
|
|
|
|
406
|
17
|
|
|
|
|
1347
|
$t->lap ('fetchrow hashref'); |
|
407
|
|
|
|
|
|
|
|
|
408
|
17
|
|
|
|
|
275
|
while (my $row = $sth->fetchrow_hashref) { |
|
409
|
81
|
|
|
|
|
2361
|
$real_row_count ++; |
|
410
|
|
|
|
|
|
|
|
|
411
|
81
|
|
|
|
|
150
|
my $column_name = $row->{COLUMN_NAME}; |
|
412
|
|
|
|
|
|
|
|
|
413
|
81
|
|
|
|
|
907
|
$column_info->{$column_name} = { |
|
414
|
|
|
|
|
|
|
(map { |
|
415
|
1458
|
|
|
|
|
2710
|
lc($_) => $row->{$_} |
|
416
|
|
|
|
|
|
|
} grep { |
|
417
|
81
|
|
|
|
|
354
|
exists $GREP_COLUMN_INFO{$_} |
|
418
|
|
|
|
|
|
|
} keys %$row), |
|
419
|
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
column_name => $column_name, |
|
421
|
|
|
|
|
|
|
quoted_column_name => $dbh->quote_identifier ($column_name), |
|
422
|
|
|
|
|
|
|
nullable => $row->{NULLABLE}, |
|
423
|
|
|
|
|
|
|
}; |
|
424
|
|
|
|
|
|
|
|
|
425
|
81
|
|
|
|
|
2414
|
my $default_val = $row->{COLUMN_DEF}; |
|
426
|
81
|
100
|
|
|
|
1084
|
if (defined $default_val) { |
|
427
|
5
|
|
|
|
|
89
|
$default_val =~ s/^"(.*)"$/$1/; |
|
428
|
5
|
|
|
|
|
84
|
$column_info->{$column_name}->{default} = $default_val; |
|
429
|
|
|
|
|
|
|
} |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
} |
|
432
|
|
|
|
|
|
|
|
|
433
|
17
|
|
|
|
|
630
|
$t->end; |
|
434
|
|
|
|
|
|
|
|
|
435
|
17
|
|
|
|
|
674
|
$t->total; |
|
436
|
|
|
|
|
|
|
|
|
437
|
17
|
50
|
|
|
|
967
|
if ($real_row_count == 0) { |
|
438
|
0
|
|
|
|
|
0
|
die "no rows for table '$table_name' fetched"; |
|
439
|
|
|
|
|
|
|
} |
|
440
|
|
|
|
|
|
|
}; |
|
441
|
|
|
|
|
|
|
|
|
442
|
17
|
|
|
|
|
79
|
$ts->lap ('_dbh_error'); |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
return |
|
445
|
17
|
50
|
|
|
|
753
|
if $class->_dbh_error ($@); |
|
446
|
|
|
|
|
|
|
|
|
447
|
17
|
|
|
|
|
31
|
$real_row_count = 0; |
|
448
|
|
|
|
|
|
|
|
|
449
|
17
|
|
|
|
|
66
|
$ts->lap ('primary_key_info'); |
|
450
|
|
|
|
|
|
|
|
|
451
|
17
|
|
|
|
|
109
|
eval { |
|
452
|
|
|
|
|
|
|
|
|
453
|
17
|
|
|
|
|
76
|
my $t = timer ('primary key'); |
|
454
|
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
# fuckin oracle |
|
456
|
17
|
|
|
|
|
1105
|
my $schema = $class->vendor_schema; |
|
457
|
|
|
|
|
|
|
|
|
458
|
17
|
|
|
|
|
152
|
my $sth = $dbh->primary_key_info( |
|
459
|
|
|
|
|
|
|
undef, $schema, $table_name |
|
460
|
|
|
|
|
|
|
); |
|
461
|
|
|
|
|
|
|
|
|
462
|
17
|
|
|
|
|
25351
|
$t->lap ('execute'); |
|
463
|
|
|
|
|
|
|
|
|
464
|
17
|
50
|
|
|
|
168
|
if ($sth) { |
|
465
|
17
|
50
|
|
|
|
116
|
$sth->execute |
|
466
|
|
|
|
|
|
|
unless $sth->{Executed}; |
|
467
|
|
|
|
|
|
|
|
|
468
|
17
|
|
|
|
|
512
|
$t->lap ('fetchrow'); |
|
469
|
|
|
|
|
|
|
|
|
470
|
17
|
|
|
|
|
466
|
while (my $row = $sth->fetchrow_hashref) { |
|
471
|
17
|
|
|
|
|
330
|
$real_row_count ++; |
|
472
|
|
|
|
|
|
|
# here we translate rows |
|
473
|
17
|
|
|
|
|
45
|
my $pri_key_name = $row->{COLUMN_NAME}; |
|
474
|
|
|
|
|
|
|
|
|
475
|
17
|
|
|
|
|
64
|
$column_info->{$row->{COLUMN_NAME}}->{X_IS_PK} = 1; |
|
476
|
17
|
|
|
|
|
212
|
$column_info->{$row->{COLUMN_NAME}}->{nullable} = 0; |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
} |
|
479
|
|
|
|
|
|
|
} |
|
480
|
|
|
|
|
|
|
|
|
481
|
17
|
|
|
|
|
303
|
$t->end; |
|
482
|
|
|
|
|
|
|
|
|
483
|
17
|
|
|
|
|
109
|
$t->total; |
|
484
|
|
|
|
|
|
|
|
|
485
|
17
|
50
|
|
|
|
796
|
if ($real_row_count == 0) { |
|
486
|
0
|
|
|
|
|
0
|
warn "no primary keys for table '$table_name'"; |
|
487
|
|
|
|
|
|
|
} |
|
488
|
|
|
|
|
|
|
}; |
|
489
|
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
return |
|
491
|
17
|
50
|
|
|
|
75
|
if $class->_dbh_error ($@); |
|
492
|
|
|
|
|
|
|
|
|
493
|
17
|
|
|
|
|
62
|
$ts->end; |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
#Hash::Util::lock_hash_recurse (%$column_info); |
|
496
|
|
|
|
|
|
|
|
|
497
|
17
|
|
|
|
|
127
|
return $column_info; |
|
498
|
|
|
|
|
|
|
} |
|
499
|
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
sub _dbh_error { |
|
501
|
102
|
|
|
102
|
|
251
|
my $self = shift; |
|
502
|
102
|
|
|
|
|
219
|
my $error = shift; |
|
503
|
102
|
|
|
|
|
193
|
my $statement = shift; |
|
504
|
|
|
|
|
|
|
|
|
505
|
102
|
50
|
|
|
|
584
|
return unless $error; |
|
506
|
|
|
|
|
|
|
|
|
507
|
0
|
|
|
|
|
0
|
my @caller = caller (1); |
|
508
|
0
|
|
|
|
|
0
|
my @caller2 = caller (2); |
|
509
|
|
|
|
|
|
|
|
|
510
|
0
|
0
|
0
|
|
|
0
|
if ($DBI::Easy::ERRHANDLER and ref $DBI::Easy::ERRHANDLER eq 'CODE') { |
|
511
|
0
|
|
|
|
|
0
|
&$DBI::Easy::ERRHANDLER ($self, $error, $statement); |
|
512
|
|
|
|
|
|
|
} else { |
|
513
|
0
|
|
|
|
|
0
|
warn ("[db error at $caller[3] ($caller[2]) called at $caller2[3] ($caller2[2])] ", |
|
514
|
|
|
|
|
|
|
$error |
|
515
|
|
|
|
|
|
|
); |
|
516
|
|
|
|
|
|
|
} |
|
517
|
|
|
|
|
|
|
|
|
518
|
0
|
0
|
|
|
|
0
|
if ($self->{in_transaction}) { |
|
519
|
0
|
|
|
|
|
0
|
eval {$self->rollback}; |
|
|
0
|
|
|
|
|
0
|
|
|
520
|
0
|
|
|
|
|
0
|
die $error; |
|
521
|
|
|
|
|
|
|
} |
|
522
|
|
|
|
|
|
|
|
|
523
|
0
|
|
|
|
|
0
|
return 1; |
|
524
|
|
|
|
|
|
|
} |
|
525
|
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
|
528
|
|
|
|
|
|
|
# we always work with one table or view. |
|
529
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
sub _prefix_manipulations { |
|
532
|
107
|
|
|
107
|
|
160
|
my $self = shift; |
|
533
|
107
|
|
|
|
|
149
|
my $dir = shift; |
|
534
|
107
|
|
|
|
|
246
|
my $values = shift; |
|
535
|
107
|
|
50
|
|
|
474
|
my $in_place = shift || 0; |
|
536
|
|
|
|
|
|
|
|
|
537
|
107
|
|
|
|
|
445
|
my $entities; |
|
538
|
|
|
|
|
|
|
my $ent_key; |
|
539
|
0
|
|
|
|
|
0
|
my $convert; |
|
540
|
107
|
50
|
|
|
|
309
|
if ($dir eq 'fields2cols') { |
|
|
|
0
|
|
|
|
|
|
|
541
|
107
|
|
|
|
|
633
|
$entities = $self->fields; |
|
542
|
107
|
|
|
|
|
554
|
$ent_key = 'column_name'; |
|
543
|
107
|
|
|
|
|
291
|
$convert = 'value_to_type'; |
|
544
|
107
|
100
|
|
|
|
508
|
$values = $self->field_values |
|
545
|
|
|
|
|
|
|
unless $values; |
|
546
|
|
|
|
|
|
|
} elsif ($dir eq 'cols2fields') { |
|
547
|
0
|
|
|
|
|
0
|
$entities = $self->cols; |
|
548
|
0
|
|
|
|
|
0
|
$ent_key = 'field_name'; |
|
549
|
0
|
|
|
|
|
0
|
$convert = 'value_from_type'; |
|
550
|
0
|
0
|
|
|
|
0
|
$values = $self->column_values |
|
551
|
|
|
|
|
|
|
unless $values; |
|
552
|
|
|
|
|
|
|
} else { |
|
553
|
0
|
|
|
|
|
0
|
die "you can't call _prefix_manipulations without direction"; |
|
554
|
|
|
|
|
|
|
} |
|
555
|
|
|
|
|
|
|
|
|
556
|
107
|
100
|
|
|
|
575
|
return $values if ! ref $values; |
|
557
|
|
|
|
|
|
|
|
|
558
|
79
|
|
|
|
|
110
|
my $place = $values; |
|
559
|
79
|
50
|
|
|
|
362
|
unless ($in_place) { |
|
560
|
79
|
|
|
|
|
257
|
$place = {}; |
|
561
|
|
|
|
|
|
|
} |
|
562
|
|
|
|
|
|
|
|
|
563
|
79
|
|
|
|
|
289
|
foreach (keys %$values) { |
|
564
|
|
|
|
|
|
|
|
|
565
|
84
|
50
|
66
|
|
|
467
|
next unless exists $entities->{$_} or /^[_:-]\w+$/; |
|
566
|
|
|
|
|
|
|
#&& ($self->undef_as_null || defined $entities->{$_}) |
|
567
|
|
|
|
|
|
|
|
|
568
|
84
|
100
|
|
|
|
302
|
if (/^:\w+$/) { # copy placeholders |
|
569
|
1
|
50
|
|
|
|
4
|
unless ($in_place) { |
|
570
|
1
|
|
|
|
|
3
|
$place->{$_} = $values->{$_}; |
|
571
|
|
|
|
|
|
|
} |
|
572
|
1
|
|
|
|
|
4
|
next; |
|
573
|
|
|
|
|
|
|
} |
|
574
|
|
|
|
|
|
|
# next if $ent->{$ent_key} eq $_ and $in_place; # |
|
575
|
83
|
|
|
|
|
498
|
my ($column_prefix, $k) = (/^(_?)(\w+)$/); |
|
576
|
83
|
50
|
|
|
|
228
|
$column_prefix = '' |
|
577
|
|
|
|
|
|
|
unless defined $column_prefix; |
|
578
|
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
# debug $k, $_; |
|
580
|
|
|
|
|
|
|
|
|
581
|
83
|
|
|
|
|
171
|
my $ent = $entities->{$k}; |
|
582
|
83
|
|
|
|
|
174
|
my $value = $values->{$_}; |
|
583
|
|
|
|
|
|
|
|
|
584
|
83
|
50
|
|
|
|
193
|
if ($in_place) { |
|
585
|
0
|
|
|
|
|
0
|
delete $values->{$_}; |
|
586
|
|
|
|
|
|
|
} |
|
587
|
|
|
|
|
|
|
|
|
588
|
83
|
|
|
|
|
351
|
my $v = $value; |
|
589
|
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
# we must convert only convertible values |
|
591
|
|
|
|
|
|
|
# field => 'value' |
|
592
|
|
|
|
|
|
|
# _field => {'>', 'value'} |
|
593
|
83
|
100
|
66
|
|
|
364
|
if ($column_prefix eq '') { |
|
|
|
100
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
594
|
73
|
|
|
|
|
1151
|
$v = $H->$convert ( |
|
595
|
|
|
|
|
|
|
$ent->{type_name}, $value, $self |
|
596
|
|
|
|
|
|
|
); |
|
597
|
|
|
|
|
|
|
} elsif ( |
|
598
|
|
|
|
|
|
|
$column_prefix eq '_' and ref $value and ref $value eq 'HASH' |
|
599
|
|
|
|
|
|
|
and keys %$value == 1 |
|
600
|
|
|
|
|
|
|
) { |
|
601
|
3
|
|
|
|
|
8
|
my $condition = (keys %$value)[0]; |
|
602
|
3
|
|
|
|
|
23
|
$v = $condition . $self->quote ($H->$convert ( |
|
603
|
|
|
|
|
|
|
$ent->{type_name}, $value->{$condition}, $self |
|
604
|
|
|
|
|
|
|
)); |
|
605
|
|
|
|
|
|
|
} |
|
606
|
|
|
|
|
|
|
|
|
607
|
83
|
50
|
|
|
|
317
|
next unless exists $ent->{$ent_key}; |
|
608
|
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
# warn "$prefix/$ent_key => $ent->{$ent_key}"; |
|
610
|
83
|
|
|
|
|
382
|
$place->{$column_prefix . $ent->{$ent_key}} = $v; |
|
611
|
|
|
|
|
|
|
} |
|
612
|
|
|
|
|
|
|
|
|
613
|
79
|
50
|
|
|
|
662
|
return $place |
|
614
|
|
|
|
|
|
|
unless $in_place; |
|
615
|
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
} |
|
617
|
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
sub fields_to_columns { |
|
619
|
107
|
|
|
107
|
0
|
191
|
my $self = shift; |
|
620
|
|
|
|
|
|
|
|
|
621
|
107
|
|
|
|
|
541
|
$self->_prefix_manipulations ('fields2cols', shift, 0); |
|
622
|
|
|
|
|
|
|
} |
|
623
|
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
sub columns_to_fields { |
|
625
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
626
|
|
|
|
|
|
|
|
|
627
|
0
|
|
|
|
|
|
$self->_prefix_manipulations ('cols2fields', shift, 0); |
|
628
|
|
|
|
|
|
|
} |
|
629
|
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
|
631
|
|
|
|
|
|
|
# we always work with one table or view. |
|
632
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
|
633
|
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
|
636
|
|
|
|
|
|
|
# simplified sql execute |
|
637
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
|
638
|
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
1; |
|
642
|
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
=head1 NAME |
|
644
|
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
DBI::Easy - yet another perl ORM for SQL databases |
|
646
|
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
648
|
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
DBI::Easy is another ORM, aimed at making the life of the developer |
|
650
|
|
|
|
|
|
|
using it a lot easier. |
|
651
|
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
=head1 INTRODUCTION |
|
653
|
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
The key notions of DBI::Easy are data records, collection of data records |
|
655
|
|
|
|
|
|
|
and relations between them. A data record is a presentation of SQL result: |
|
656
|
|
|
|
|
|
|
row or blessed hash, depending on how you look at it. Data records collection |
|
657
|
|
|
|
|
|
|
is a set of records limited by certain criteria or without any limitations. |
|
658
|
|
|
|
|
|
|
the differentiation between collections and records has to do with |
|
659
|
|
|
|
|
|
|
different relations between them: one-to-one, one-to-many, many-to-many. |
|
660
|
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
For Example: Within a domain auction based on DBI::Easy, every user may |
|
662
|
|
|
|
|
|
|
have a few bids, but each bid belongs to just one concrete user. |
|
663
|
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
It's also worth mentioning the relations between DBI::Easy and SQL. DBI::Easy |
|
665
|
|
|
|
|
|
|
is currently using a small set of sql, limited to tables and views, |
|
666
|
|
|
|
|
|
|
including four operations to work with data: insert, update, select, delete. |
|
667
|
|
|
|
|
|
|
The relations between SQL objects are not formed automatically with the help |
|
668
|
|
|
|
|
|
|
of constraints. |
|
669
|
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
Also it's important that DBI::Easy is not trying to hide SQL from you. |
|
671
|
|
|
|
|
|
|
If you need it you can use it fully. However, it allows carrying out the vast |
|
672
|
|
|
|
|
|
|
majority of simple operations with data without the participation of SQL. |
|
673
|
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
675
|
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
Let's start from the most simple things. To start the work you will need two |
|
677
|
|
|
|
|
|
|
modules that will return database handler ($dbh) upon request. |
|
678
|
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
To avoid unpleasant consequences it's recommended to cache the returned |
|
680
|
|
|
|
|
|
|
connection only after the fork, if there is a fork in your code. |
|
681
|
|
|
|
|
|
|
for the case when CL environment variables for DBI_DSN and DBI_* are defined, |
|
682
|
|
|
|
|
|
|
and they can be used to establish a connection that doesn't need to be cached, |
|
683
|
|
|
|
|
|
|
you can do without these modules at all. The main task for 'Entity' is to |
|
684
|
|
|
|
|
|
|
acquire DBI::Easy::Record[::Collection] or one of the child classes. |
|
685
|
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
package DBEntity; |
|
687
|
|
|
|
|
|
|
use strict; |
|
688
|
|
|
|
|
|
|
use DBI; |
|
689
|
|
|
|
|
|
|
use DBI::Easy::Record; |
|
690
|
|
|
|
|
|
|
use base qw(DBI::Easy::Record); |
|
691
|
|
|
|
|
|
|
sub dbh { # optional. You don't have to write a procedure similar |
|
692
|
|
|
|
|
|
|
# to this one since DBI->connect is requested |
|
693
|
|
|
|
|
|
|
# when a ready $dbh hasn't been provided |
|
694
|
|
|
|
|
|
|
return DBI->connect; |
|
695
|
|
|
|
|
|
|
}; |
|
696
|
|
|
|
|
|
|
1; |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
#----------------------------------------- |
|
699
|
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
package DBEntity::Collection; |
|
701
|
|
|
|
|
|
|
use strict; |
|
702
|
|
|
|
|
|
|
use DBI::Easy::Record::Collection; |
|
703
|
|
|
|
|
|
|
use base qw(DBI::Easy::Record::Collection); |
|
704
|
|
|
|
|
|
|
1; |
|
705
|
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
Now let's get down to something concrete. Let's assume we have a user and his |
|
707
|
|
|
|
|
|
|
passport data (one-to-one relation) and some contact data (one-to-many) |
|
708
|
|
|
|
|
|
|
NOTE: the many-to-many relations hasn't been realized yet. |
|
709
|
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
package Entity::Passport; |
|
712
|
|
|
|
|
|
|
use strict; |
|
713
|
|
|
|
|
|
|
use DBEntity; |
|
714
|
|
|
|
|
|
|
use base qw(DBEntity); |
|
715
|
|
|
|
|
|
|
1; |
|
716
|
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
#----------------------------------------- |
|
718
|
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
package Entity::Contact; |
|
720
|
|
|
|
|
|
|
use strict; |
|
721
|
|
|
|
|
|
|
use DBEntity; |
|
722
|
|
|
|
|
|
|
use base qw(DBEntity); |
|
723
|
|
|
|
|
|
|
1; |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
#----------------------------------------- |
|
726
|
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
package Entity::Contact::Collection; |
|
728
|
|
|
|
|
|
|
use strict; |
|
729
|
|
|
|
|
|
|
use DBEntity::Collection; |
|
730
|
|
|
|
|
|
|
use base qw(DBEntity::Collection); |
|
731
|
|
|
|
|
|
|
1; |
|
732
|
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
#----------------------------------------- |
|
734
|
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
package Entity::Account; |
|
736
|
|
|
|
|
|
|
use strict; |
|
737
|
|
|
|
|
|
|
use DBEntity; |
|
738
|
|
|
|
|
|
|
use base qw(DBEntity); |
|
739
|
|
|
|
|
|
|
use Entity::Passport; |
|
740
|
|
|
|
|
|
|
use Entity::Contact::Collection; |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
sub _init_last { |
|
743
|
|
|
|
|
|
|
my $self = shift; |
|
744
|
|
|
|
|
|
|
$self->is_related_to ( |
|
745
|
|
|
|
|
|
|
passport => 'Entity::Passport' |
|
746
|
|
|
|
|
|
|
); |
|
747
|
|
|
|
|
|
|
$self->is_related_to ( |
|
748
|
|
|
|
|
|
|
contacts => 'Entity::Contact::Collection' |
|
749
|
|
|
|
|
|
|
); |
|
750
|
|
|
|
|
|
|
} |
|
751
|
|
|
|
|
|
|
1; |
|
752
|
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
#----------------------------------------- |
|
754
|
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
package Entity::Account::Collection; |
|
756
|
|
|
|
|
|
|
use strict; |
|
757
|
|
|
|
|
|
|
use DBEntity::Collection; |
|
758
|
|
|
|
|
|
|
use base qw(DBEntity::Collection); |
|
759
|
|
|
|
|
|
|
1; |
|
760
|
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
#----------------------------------------- |
|
762
|
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
Now let's create some SQL tables for our test application (using SQLite): |
|
764
|
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
create table account ( |
|
766
|
|
|
|
|
|
|
account_id serial not null primary key, |
|
767
|
|
|
|
|
|
|
account_login varchar (50) not null |
|
768
|
|
|
|
|
|
|
); |
|
769
|
|
|
|
|
|
|
create table pasport ( |
|
770
|
|
|
|
|
|
|
passport_id serial not null primary key, |
|
771
|
|
|
|
|
|
|
passport_serial varchar (50) not null, |
|
772
|
|
|
|
|
|
|
account_id integer |
|
773
|
|
|
|
|
|
|
); |
|
774
|
|
|
|
|
|
|
create table contact ( |
|
775
|
|
|
|
|
|
|
contact_id serial not null primary key, |
|
776
|
|
|
|
|
|
|
contact_proto varchar (10) not null, |
|
777
|
|
|
|
|
|
|
contact_address varchar (200) not null, |
|
778
|
|
|
|
|
|
|
account_id integer |
|
779
|
|
|
|
|
|
|
); |
|
780
|
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
And now the funniest part: the script itself: |
|
782
|
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
#----------------------------------------- |
|
784
|
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
#!/usr/bin/perl |
|
786
|
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
use strict; |
|
788
|
|
|
|
|
|
|
use Entity::Account; |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
# here it doesn`t matter whether there is a user with such a login in |
|
791
|
|
|
|
|
|
|
# the database, if needed we can create it. |
|
792
|
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
my $account = Entity::Account->fetch_or_create ({login => 'apla'}); |
|
794
|
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
# here fetch_or_create is implicitly activated with the parameters |
|
796
|
|
|
|
|
|
|
# {id => $account->id, serial => 'aabbcc'} |
|
797
|
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
$account->passport ({serial => 'aabbcc'}); |
|
799
|
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
my $acc_contacts = $account->contacts; |
|
801
|
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
my $contact = $acc_contacts->new_record ({ |
|
803
|
|
|
|
|
|
|
proto => 'email', address => 'apla@localhost' |
|
804
|
|
|
|
|
|
|
}); |
|
805
|
|
|
|
|
|
|
$contact->save; |
|
806
|
|
|
|
|
|
|
$acc_contacts->count; |
|
807
|
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
1; |
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
=head1 AUTHOR |
|
813
|
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
Ivan Baktsheev, C<< >> |
|
815
|
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
=head1 BUGS |
|
817
|
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
Please report any bugs or feature requests to my email address, |
|
819
|
|
|
|
|
|
|
or through the web interface at L. |
|
820
|
|
|
|
|
|
|
I will be notified, and then you'll automatically be notified |
|
821
|
|
|
|
|
|
|
of progress on your bug as I make changes. |
|
822
|
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
=head1 SUPPORT |
|
824
|
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
|
828
|
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
|
832
|
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
Copyright 2008-2009 Ivan Baktsheev |
|
834
|
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
|
836
|
|
|
|
|
|
|
under the same terms as Perl itself. |
|
837
|
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
=cut |
|
839
|
|
|
|
|
|
|
|