line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# -*- perl -*- |
2
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
3
|
|
|
|
|
|
|
## Database Object Interface - ~/lib/DB/Object.pm |
4
|
|
|
|
|
|
|
## Version v0.11.6 |
5
|
|
|
|
|
|
|
## Copyright(c) 2023 DEGUEST Pte. Ltd. |
6
|
|
|
|
|
|
|
## Author: Jacques Deguest <jack@deguest.jp> |
7
|
|
|
|
|
|
|
## Created 2017/07/19 |
8
|
|
|
|
|
|
|
## Modified 2023/06/21 |
9
|
|
|
|
|
|
|
## All rights reserved |
10
|
|
|
|
|
|
|
## |
11
|
|
|
|
|
|
|
## This program is free software; you can redistribute it and/or modify it |
12
|
|
|
|
|
|
|
## under the same terms as Perl itself. |
13
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
14
|
|
|
|
|
|
|
## This is the subclassable module for driver specific ones. |
15
|
|
|
|
|
|
|
package DB::Object; |
16
|
|
|
|
|
|
|
BEGIN |
17
|
0
|
|
|
|
|
0
|
{ |
18
|
3
|
|
|
3
|
|
216
|
require 5.16.0; |
19
|
3
|
|
|
3
|
|
210964
|
use strict; |
|
3
|
|
|
|
|
17
|
|
|
3
|
|
|
|
|
97
|
|
20
|
3
|
|
|
3
|
|
15
|
use warnings; |
|
3
|
|
|
|
|
16
|
|
|
3
|
|
|
|
|
90
|
|
21
|
3
|
|
|
3
|
|
1013
|
use parent qw( Module::Generic DBI ); |
|
3
|
|
|
|
|
694
|
|
|
3
|
|
|
|
|
16
|
|
22
|
3
|
|
|
|
|
374
|
use vars qw( |
23
|
|
|
|
|
|
|
$VERSION $AUTOLOAD @AVAILABLE_DATABASES $CACHE_DIR $CACHE_QUERIES $CACHE_SIZE |
24
|
|
|
|
|
|
|
$CACHE_TABLE $CONNECT_VIA $CONSTANT_QUERIES_CACHE $DB_ERRSTR @DBH $DRIVER2PACK |
25
|
|
|
|
|
|
|
$ERROR $DEBUG $MOD_PERL $QUERIES_CACHE $USE_BIND $USE_CACHE |
26
|
3
|
|
|
3
|
|
23716115
|
); |
|
3
|
|
|
|
|
6
|
|
27
|
3
|
|
|
3
|
|
1640
|
use Regexp::Common; |
|
3
|
|
|
|
|
7212
|
|
|
3
|
|
|
|
|
11
|
|
28
|
3
|
|
|
3
|
|
455583
|
use Scalar::Util qw( blessed ); |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
215
|
|
29
|
3
|
|
|
3
|
|
1468
|
use DB::Object::Cache::Tables; |
|
3
|
|
|
|
|
11
|
|
|
3
|
|
|
|
|
40
|
|
30
|
3
|
|
|
3
|
|
935
|
use DBI; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
129
|
|
31
|
3
|
|
|
3
|
|
19
|
use JSON; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
26
|
|
32
|
3
|
|
|
3
|
|
399
|
use Module::Generic::File qw( sys_tmpdir ); |
|
3
|
|
|
|
|
17
|
|
|
3
|
|
|
|
|
18
|
|
33
|
3
|
|
|
3
|
|
728
|
use POSIX (); |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
52
|
|
34
|
3
|
|
|
3
|
|
20
|
use Want; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
211
|
|
35
|
3
|
|
|
|
|
58
|
$VERSION = 'v0.11.6'; |
36
|
3
|
|
|
3
|
|
19
|
use Devel::Confess; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
32
|
|
37
|
|
|
|
|
|
|
}; |
38
|
|
|
|
|
|
|
|
39
|
3
|
|
|
3
|
|
12
|
use strict; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
56
|
|
40
|
3
|
|
|
3
|
|
14
|
use warnings; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
16273
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
$DB_ERRSTR = ''; |
43
|
|
|
|
|
|
|
$DEBUG = 0; |
44
|
|
|
|
|
|
|
# This is our system cache queries |
45
|
|
|
|
|
|
|
$CACHE_QUERIES = []; |
46
|
|
|
|
|
|
|
$CACHE_SIZE = 10; |
47
|
|
|
|
|
|
|
$CACHE_TABLE = {}; |
48
|
|
|
|
|
|
|
$USE_BIND = 0; |
49
|
|
|
|
|
|
|
$USE_CACHE = 0; |
50
|
|
|
|
|
|
|
$MOD_PERL = 0; |
51
|
|
|
|
|
|
|
@DBH = (); |
52
|
|
|
|
|
|
|
$CACHE_DIR = ''; |
53
|
|
|
|
|
|
|
$CONSTANT_QUERIES_CACHE = {}; |
54
|
|
|
|
|
|
|
# This is for the user convenience |
55
|
|
|
|
|
|
|
$QUERIES_CACHE = {}; |
56
|
|
|
|
|
|
|
if( $INC{ 'Apache/DBI.pm' } && |
57
|
|
|
|
|
|
|
substr( $ENV{GATEWAY_INTERFACE}|| '', 0, 8 ) eq 'CGI-Perl' ) |
58
|
|
|
|
|
|
|
{ |
59
|
|
|
|
|
|
|
$CONNECT_VIA = "Apache::DBI::connect"; |
60
|
|
|
|
|
|
|
$MOD_PERL++; |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
our $DRIVER2PACK = |
63
|
|
|
|
|
|
|
{ |
64
|
|
|
|
|
|
|
mysql => 'DB::Object::Mysql', |
65
|
|
|
|
|
|
|
Pg => 'DB::Object::Postgres', |
66
|
|
|
|
|
|
|
SQLite => 'DB::Object::SQLite', |
67
|
|
|
|
|
|
|
}; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub new |
70
|
|
|
|
|
|
|
{ |
71
|
3
|
|
|
3
|
1
|
231
|
my $that = shift( @_ ); |
72
|
3
|
|
33
|
|
|
31
|
my $class = ref( $that ) || $that; |
73
|
3
|
|
|
|
|
9
|
my $self = {}; |
74
|
3
|
|
|
|
|
8
|
bless( $self, $class ); |
75
|
3
|
|
|
|
|
21
|
return( $self->init( @_ ) ); |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub init |
79
|
|
|
|
|
|
|
{ |
80
|
3
|
|
|
3
|
1
|
11
|
my $self = shift( @_ ); |
81
|
3
|
|
|
|
|
196
|
$self->{cache_connections} = 1; |
82
|
3
|
|
|
|
|
17
|
$self->{cache_dir} = sys_tmpdir(); |
83
|
3
|
|
|
|
|
6615332
|
$self->{driver} = ''; |
84
|
|
|
|
|
|
|
# Auto-decode json data into perl hash |
85
|
3
|
|
|
|
|
34
|
$self->{auto_decode_json} = 1; |
86
|
3
|
|
|
|
|
31
|
$self->{auto_convert_datetime_to_object} = 0; |
87
|
3
|
|
|
|
|
41
|
$self->{allow_bulk_delete} = 0; |
88
|
3
|
|
|
|
|
17
|
$self->{allow_bulk_update} = 0; |
89
|
3
|
|
|
|
|
25
|
$self->{unknown_field} = 'ignore'; |
90
|
3
|
|
|
|
|
11
|
$self->{_init_strict_use_sub} = 1; |
91
|
3
|
|
|
|
|
37
|
$self->Module::Generic::init( @_ ); |
92
|
|
|
|
|
|
|
# $self->{constant_queries_cache} = $DB::Object::CONSTANT_QUERIES_CACHE; |
93
|
3
|
|
|
|
|
475
|
return( $self ); |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
0
|
|
|
0
|
1
|
0
|
sub allow_bulk_delete { return( shift->_set_get_scalar( 'allow_bulk_delete', @_ ) ); } |
97
|
|
|
|
|
|
|
|
98
|
0
|
|
|
0
|
1
|
0
|
sub allow_bulk_update { return( shift->_set_get_scalar( 'allow_bulk_update', @_ ) ); } |
99
|
|
|
|
|
|
|
|
100
|
0
|
|
|
0
|
1
|
0
|
sub ALL { return( DB::Object::ALL->new( splice( @_, 1 ) ) ); } |
101
|
|
|
|
|
|
|
|
102
|
0
|
|
|
0
|
1
|
0
|
sub AND { shift( @_ ); return( DB::Object::AND->new( @_ ) ); } |
|
0
|
|
|
|
|
0
|
|
103
|
|
|
|
|
|
|
|
104
|
0
|
|
|
0
|
1
|
0
|
sub ANY { return( DB::Object::ANY->new( splice( @_, 1 ) ) ); } |
105
|
|
|
|
|
|
|
|
106
|
0
|
|
|
0
|
1
|
0
|
sub auto_convert_datetime_to_object { return( shift->_set_get_scalar( 'auto_convert_datetime_to_object', @_ ) ); } |
107
|
|
|
|
|
|
|
|
108
|
0
|
|
|
0
|
1
|
0
|
sub auto_decode_json { return( shift->_set_get_scalar( 'auto_decode_json', @_ ) ); } |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub attribute($;$@) |
111
|
|
|
|
|
|
|
{ |
112
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
113
|
|
|
|
|
|
|
# $h->{AttributeName} = ...; # set/write |
114
|
|
|
|
|
|
|
# ... = $h->{AttributeName}; # get/read |
115
|
|
|
|
|
|
|
# 1 means that the attribute may be modified |
116
|
|
|
|
|
|
|
# 0 mneas that the attribute may only be read |
117
|
0
|
0
|
|
|
|
0
|
my $name = shift( @_ ) if( @_ == 1 ); |
118
|
0
|
|
|
|
|
0
|
my %arg = ( @_ ); |
119
|
0
|
|
|
|
|
0
|
my %attr = |
120
|
|
|
|
|
|
|
( |
121
|
|
|
|
|
|
|
Active => 0, |
122
|
|
|
|
|
|
|
ActiveKids => 0, |
123
|
|
|
|
|
|
|
AutoCommit => 1, |
124
|
|
|
|
|
|
|
AutoInactiveDestroy => 1, |
125
|
|
|
|
|
|
|
CachedKids => 0, |
126
|
|
|
|
|
|
|
Callbacks => 1, |
127
|
|
|
|
|
|
|
ChildHandles => 0, |
128
|
|
|
|
|
|
|
ChopBlanks => 1, |
129
|
|
|
|
|
|
|
CompatMode => 1, |
130
|
|
|
|
|
|
|
CursorName => 0, |
131
|
|
|
|
|
|
|
ErrCount => 0, |
132
|
|
|
|
|
|
|
Executed => 0, |
133
|
|
|
|
|
|
|
FetchHashKeyName => 0, |
134
|
|
|
|
|
|
|
HandleError => 1, |
135
|
|
|
|
|
|
|
HandleSetErr => 1, |
136
|
|
|
|
|
|
|
InactiveDestroy => 1, |
137
|
|
|
|
|
|
|
Kids => 0, |
138
|
|
|
|
|
|
|
LongReadLen => 1, |
139
|
|
|
|
|
|
|
LongTruncOk => 1, |
140
|
|
|
|
|
|
|
NAME => 0, |
141
|
|
|
|
|
|
|
NULLABLE => 0, |
142
|
|
|
|
|
|
|
NUM_OF_FIELDS => 0, |
143
|
|
|
|
|
|
|
NUM_OF_PARAMS => 0, |
144
|
|
|
|
|
|
|
Name => 0, |
145
|
|
|
|
|
|
|
PRECISION => 0, |
146
|
|
|
|
|
|
|
PrintError => 1, |
147
|
|
|
|
|
|
|
PrintWarn => 1, |
148
|
|
|
|
|
|
|
Profile => 0, |
149
|
|
|
|
|
|
|
RaiseError => 1, |
150
|
|
|
|
|
|
|
ReadOnly => 1, |
151
|
|
|
|
|
|
|
RowCacheSize => 0, |
152
|
|
|
|
|
|
|
RowsInCache => 0, |
153
|
|
|
|
|
|
|
SCALE => 0, |
154
|
|
|
|
|
|
|
ShowErrorStatement => 1, |
155
|
|
|
|
|
|
|
Statement => 0, |
156
|
|
|
|
|
|
|
TYPE => 0, |
157
|
|
|
|
|
|
|
Taint => 1, |
158
|
|
|
|
|
|
|
TaintIn => 1, |
159
|
|
|
|
|
|
|
TaintOut => 1, |
160
|
|
|
|
|
|
|
TraceLevel => 1, |
161
|
|
|
|
|
|
|
Type => 0, |
162
|
|
|
|
|
|
|
Warn => 1, |
163
|
|
|
|
|
|
|
); |
164
|
|
|
|
|
|
|
# Only those attribute exist |
165
|
|
|
|
|
|
|
# Using an a non existing attribute produce an exception, so we better avoid |
166
|
0
|
0
|
|
|
|
0
|
if( $name ) |
167
|
|
|
|
|
|
|
{ |
168
|
0
|
0
|
|
|
|
0
|
return( $self->{dbh}->{ $name } ) if( exists( $attr{ $name } ) ); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
else |
171
|
|
|
|
|
|
|
{ |
172
|
0
|
|
|
|
|
0
|
my $value; |
173
|
0
|
|
|
|
|
0
|
while( ( $name, $value ) = each( %arg ) ) |
174
|
|
|
|
|
|
|
{ |
175
|
|
|
|
|
|
|
# We intend to modifiy the value of an attribute |
176
|
|
|
|
|
|
|
# we are allowed to modify this value if it is true |
177
|
0
|
0
|
0
|
|
|
0
|
if( exists( $attr{ $name } ) && |
|
|
|
0
|
|
|
|
|
178
|
|
|
|
|
|
|
defined( $value ) && |
179
|
|
|
|
|
|
|
$attr{ $name } ) |
180
|
|
|
|
|
|
|
{ |
181
|
0
|
|
|
|
|
0
|
$self->{dbh}->{ $name } = $value; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub available_drivers(@) |
188
|
|
|
|
|
|
|
{ |
189
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
190
|
0
|
|
0
|
|
|
0
|
my $class = ref( $self ) || $self; |
191
|
|
|
|
|
|
|
# @ary = DBI->available_drivers( $quiet ); |
192
|
0
|
|
|
|
|
0
|
return( $class->SUPER::available_drivers( 1 ) ); |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub base_class |
196
|
|
|
|
|
|
|
{ |
197
|
1
|
|
|
1
|
1
|
5
|
my $self = shift( @_ ); |
198
|
1
|
|
|
|
|
11
|
my @supported_classes = $self->supported_class; |
199
|
1
|
|
|
|
|
3
|
push( @supported_classes, 'DB::Object' ); |
200
|
1
|
|
|
|
|
5
|
my $ok_classes = join( '|', @supported_classes ); |
201
|
1
|
50
|
|
|
|
9
|
my $class = ref( $self ) ? ref( $self ) : $self; |
202
|
1
|
|
|
|
|
59
|
my $base_class = ( $class =~ /^($ok_classes)/ )[0]; |
203
|
1
|
|
|
|
|
8
|
return( $base_class ); |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
# This method is common to DB::Object and DB::Object::Statement |
207
|
|
|
|
|
|
|
sub bind |
208
|
|
|
|
|
|
|
{ |
209
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
210
|
|
|
|
|
|
|
# Usage: |
211
|
|
|
|
|
|
|
# This activate the binding stuff |
212
|
|
|
|
|
|
|
# $dbh->bind() or $dbh->bind->where( "something" ) or $dbh->bind->select->fetchrow_hashref(); |
213
|
|
|
|
|
|
|
# Later, $dbh->bind( 'thingy' )->select->fetchrow_hashref() |
214
|
|
|
|
|
|
|
# When used like $table->bind; this means the user is setting the use bind option as a setting for all transactions, but |
215
|
|
|
|
|
|
|
# when used like $table->bind->select then the use bind option is only used for this transaction only and is reset after |
216
|
|
|
|
|
|
|
$self->{bind} = Want::want('VOID') |
217
|
|
|
|
|
|
|
? 2 |
218
|
|
|
|
|
|
|
# Otherwise is it already set maybe? |
219
|
|
|
|
|
|
|
: $self->{bind} |
220
|
|
|
|
|
|
|
# Then use it |
221
|
|
|
|
|
|
|
? $self->{bind} |
222
|
0
|
0
|
|
|
|
0
|
: 1; |
|
|
0
|
|
|
|
|
|
223
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
224
|
|
|
|
|
|
|
{ |
225
|
|
|
|
|
|
|
# If we are using the cache system, we search the object of this query |
226
|
0
|
|
|
|
|
0
|
my $obj = ''; |
227
|
|
|
|
|
|
|
# Ensure that we have something to look for at the least |
228
|
|
|
|
|
|
|
# my $queries = $self->{queries}; |
229
|
0
|
|
|
|
|
0
|
my $queries = $self->_cache_queries; |
230
|
0
|
|
|
|
|
0
|
my $base_class = $self->base_class; |
231
|
0
|
0
|
0
|
|
|
0
|
if( $self->isa( "${base_class}::Statement" ) ) |
|
|
0
|
|
|
|
|
|
232
|
|
|
|
|
|
|
{ |
233
|
0
|
|
|
|
|
0
|
$obj = $self; |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
elsif( $self->{cache} && @$queries ) |
236
|
|
|
|
|
|
|
{ |
237
|
0
|
|
|
|
|
0
|
$obj = $queries->[0]; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
# Otherwise, our object is the statement object to use |
240
|
|
|
|
|
|
|
else |
241
|
|
|
|
|
|
|
{ |
242
|
0
|
|
|
|
|
0
|
$obj = $self; |
243
|
|
|
|
|
|
|
} |
244
|
0
|
|
|
|
|
0
|
$obj->{binded} = [ @_ ]; |
245
|
|
|
|
|
|
|
# Since new binded parameters have been passed, since mean a new request to the |
246
|
|
|
|
|
|
|
# same statement is pending, so we need to re-execute the statement |
247
|
|
|
|
|
|
|
# and since most of the fetch method rely on AUTOLOAD that call |
248
|
|
|
|
|
|
|
# execute() automatically *IF* the statement was not already executed.... |
249
|
|
|
|
|
|
|
# we need to delete 'executed' value or set it to false, so the statement gets re-executed |
250
|
0
|
|
|
|
|
0
|
$obj->{executed} = 0; |
251
|
0
|
|
|
|
|
0
|
return( $obj ); |
252
|
|
|
|
|
|
|
} |
253
|
0
|
|
|
|
|
0
|
return( $self ); |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub cache |
257
|
|
|
|
|
|
|
{ |
258
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
259
|
|
|
|
|
|
|
# activate cache |
260
|
|
|
|
|
|
|
# So we may be called as: $tbl->cache->select->fetchrow_hashref(); |
261
|
0
|
|
|
|
|
0
|
$self->{cache}++; |
262
|
0
|
|
|
|
|
0
|
return( $self ); |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
0
|
|
|
0
|
1
|
0
|
sub cache_connections { return( shift->_set_get_boolean( 'cache_connections', @_ ) ); } |
266
|
|
|
|
|
|
|
# { |
267
|
|
|
|
|
|
|
# my $self = shift( @_ ); |
268
|
|
|
|
|
|
|
# $self->{_cache_connections} = shift( @_ ) if( @_ ); |
269
|
|
|
|
|
|
|
# return( $self->{_cache_connections} ); |
270
|
|
|
|
|
|
|
# } |
271
|
|
|
|
|
|
|
|
272
|
0
|
|
|
0
|
1
|
0
|
sub cache_dir { return( shift->_set_get_scalar( 'cache_dir', @_ ) ); } |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
sub cache_query_get |
275
|
|
|
|
|
|
|
{ |
276
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
277
|
0
|
|
0
|
|
|
0
|
my $name = shift( @_ ) || return( $self->error( "No name for this query cache was provided." ) ); |
278
|
0
|
|
|
|
|
0
|
return( $QUERIES_CACHE->{ $name } ); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub cache_query_set |
282
|
|
|
|
|
|
|
{ |
283
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
284
|
0
|
|
0
|
|
|
0
|
my $name = shift( @_ ) || return( $self->error( "No name for this query cache was provided." ) ); |
285
|
0
|
|
0
|
|
|
0
|
my $sth = shift( @_ ) || return( $self->error( "No statement handler was provided." ) ); |
286
|
0
|
|
|
|
|
0
|
return( $QUERIES_CACHE->{ $name } = $sth ); |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
0
|
|
|
0
|
1
|
0
|
sub cache_tables { return( shift->_set_get_object( 'cache_tables', 'DB::Object::Cache::Tables', @_ ) ); } |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
sub check_driver() |
292
|
|
|
|
|
|
|
{ |
293
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
294
|
0
|
|
0
|
|
|
0
|
my $driver = shift( @_ ) || return( $self->error( "No SQL driver provided to check" ) ); |
295
|
0
|
|
|
|
|
0
|
my $ok = undef(); |
296
|
0
|
|
|
|
|
0
|
local $_; |
297
|
0
|
|
|
|
|
0
|
my @drivers = $self->available_drivers(); |
298
|
0
|
|
|
|
|
0
|
foreach( @drivers ) |
299
|
|
|
|
|
|
|
{ |
300
|
0
|
0
|
|
|
|
0
|
if( m/$driver/s ) |
301
|
|
|
|
|
|
|
{ |
302
|
0
|
|
|
|
|
0
|
$ok++; |
303
|
0
|
|
|
|
|
0
|
last; |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
} |
306
|
0
|
|
|
|
|
0
|
return( $ok ); |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
sub connect |
310
|
|
|
|
|
|
|
{ |
311
|
0
|
|
|
0
|
1
|
0
|
my $this = shift( @_ ); |
312
|
0
|
|
0
|
|
|
0
|
my $class = ref( $this ) || $this; |
313
|
0
|
|
|
|
|
0
|
my $opts = $this->_get_args_as_hash( @_ ); |
314
|
|
|
|
|
|
|
# We pass the arguments so that debug and other init parameters can be set early |
315
|
0
|
0
|
|
|
|
0
|
my $that = ref( $this ) ? $this : $this->Module::Generic::new( debug => $opts->{debug} ); |
316
|
|
|
|
|
|
|
# my $this = { @_ }; |
317
|
|
|
|
|
|
|
# print( STDERR "${class}::connect() DEBUG is $DEBUG\n" ); |
318
|
0
|
|
0
|
|
|
0
|
my $param = $that->_connection_params2hash( @_ ) || return( $this->error( "No valid connection parameters found" ) ); |
319
|
|
|
|
|
|
|
# print( STDERR $class, "::connect(): \$param is: ", $that->dumper( $param ), "\n" ); |
320
|
0
|
|
|
|
|
0
|
my $driver2pack = |
321
|
|
|
|
|
|
|
{ |
322
|
|
|
|
|
|
|
mysql => 'DB::Object::Mysql', |
323
|
|
|
|
|
|
|
Pg => 'DB::Object::Postgres', |
324
|
|
|
|
|
|
|
SQLite => 'DB::Object::SQLite', |
325
|
|
|
|
|
|
|
}; |
326
|
0
|
0
|
|
|
|
0
|
return( $that->error( "No driver was provided." ) ) if( !exists( $param->{driver} ) ); |
327
|
0
|
0
|
|
|
|
0
|
if( !exists( $driver2pack->{ $param->{driver} } ) ) |
328
|
|
|
|
|
|
|
{ |
329
|
0
|
|
|
|
|
0
|
return( $that->error( "Driver $param->{driver} is not supported." ) ); |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
# For example, will make this object a DB::ObjectD::Postgres object |
332
|
0
|
|
|
|
|
0
|
my $driver_class = $driver2pack->{ $param->{driver} }; |
333
|
0
|
|
|
|
|
0
|
my $driver_module = $driver_class; |
334
|
0
|
|
|
|
|
0
|
$driver_module =~ s|::|/|g; |
335
|
0
|
|
|
|
|
0
|
$driver_module .= '.pm'; |
336
|
|
|
|
|
|
|
# print( STDERR "${class}::connect() Requiring class '$driver_class' ($driver_module)\n" ); |
337
|
|
|
|
|
|
|
eval |
338
|
0
|
|
|
|
|
0
|
{ |
339
|
|
|
|
|
|
|
# local $SIG{ '__DIE__' } = sub{ }; |
340
|
|
|
|
|
|
|
# local $SIG{ '__WARN__' } = sub{ }; |
341
|
0
|
|
|
|
|
0
|
local $DEBUG; |
342
|
0
|
|
|
|
|
0
|
require $driver_module; |
343
|
|
|
|
|
|
|
}; |
344
|
|
|
|
|
|
|
# print( STDERR "${class}::connect() eval error? '$@'\n" ) if( $self->{debug} ); |
345
|
0
|
0
|
|
|
|
0
|
return( $that->error( "Unable to load module $driver_class ($driver_module): $@" ) ) if( $@ ); |
346
|
0
|
|
0
|
|
|
0
|
my $self = $driver_class->new || die( "Cannot get object from package $driver_class\n" ); |
347
|
|
|
|
|
|
|
# $self->debug( 3 ); |
348
|
0
|
0
|
|
|
|
0
|
$self->{debug} = CORE::exists( $param->{debug} ) ? CORE::delete( $param->{debug} ) : CORE::exists( $param->{Debug} ) ? CORE::delete( $param->{Debug} ) : $DEBUG; |
|
|
0
|
|
|
|
|
|
349
|
0
|
0
|
|
|
|
0
|
$self->{cache_dir} = CORE::exists( $param->{cache_dir} ) ? CORE::delete( $param->{cache_dir} ) : CORE::exists( $that->{cache_dir} ) ? $that->{cache_dir} : $CACHE_DIR; |
|
|
0
|
|
|
|
|
|
350
|
0
|
0
|
|
|
|
0
|
$self->{unknown_field} = CORE::delete( $param->{unknown_field} ) if( CORE::exists( $param->{unknown_field} ) ); |
351
|
|
|
|
|
|
|
|
352
|
0
|
|
0
|
|
|
0
|
$param = $self->_check_connect_param( $param ) || return( $self->pass_error ); |
353
|
0
|
|
|
|
|
0
|
my $opt = {}; |
354
|
0
|
0
|
|
|
|
0
|
if( exists( $param->{opt} ) ) |
355
|
|
|
|
|
|
|
{ |
356
|
0
|
|
|
|
|
0
|
$opt = CORE::delete( $param->{opt} ); |
357
|
0
|
|
|
|
|
0
|
$opt = $self->_check_default_option( $opt ); |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
# print( STDERR ref( $self ), "::connect(): \$param is: ", $self->dumper( $param ), "\n" ); |
360
|
0
|
0
|
|
|
|
0
|
$self->{database} = CORE::exists( $param->{database} ) ? CORE::delete( $param->{database} ) : CORE::exists( $param->{db} ) ? CORE::delete( $param->{db} ) : undef(); |
|
|
0
|
|
|
|
|
|
361
|
0
|
0
|
|
|
|
0
|
$self->{host} = CORE::exists( $param->{host} ) ? CORE::delete( $param->{host} ) : CORE::exists( $param->{server} ) ? CORE::delete( $param->{server} ) : undef(); |
|
|
0
|
|
|
|
|
|
362
|
0
|
|
|
|
|
0
|
$self->{port} = CORE::delete( $param->{port} ); |
363
|
|
|
|
|
|
|
# $self->{database} = CORE::delete( $param->{ 'db' } ); |
364
|
0
|
|
|
|
|
0
|
$self->{login} = CORE::delete( $param->{login} ); |
365
|
0
|
|
|
|
|
0
|
$self->{passwd} = CORE::delete( $param->{passwd} ); |
366
|
0
|
|
|
|
|
0
|
$self->{driver} = CORE::delete( $param->{driver} ); |
367
|
0
|
0
|
|
|
|
0
|
$self->{cache} = CORE::exists( $param->{use_cache} ) ? CORE::delete( $param->{use_cache} ) : $USE_CACHE; |
368
|
0
|
0
|
|
|
|
0
|
$self->{bind} = CORE::exists( $param->{use_bind} ) ? CORE::delete( $param->{use_bind} ) : $USE_BIND; |
369
|
|
|
|
|
|
|
# Needed to be specified if the user does not want to cache connections |
370
|
|
|
|
|
|
|
# Will be used in _dbi_connect() |
371
|
0
|
0
|
|
|
|
0
|
$self->{cache_connections} = CORE::delete( $param->{cache_connections} ) if( CORE::exists( $param->{cache_connections} ) ); |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
# If parameters starting with an upper case are provided, they are DBI database parameters |
374
|
|
|
|
|
|
|
#my @dbi_opts = grep( /^[A-Z][a-zA-Z]+/, keys( %$param ) ); |
375
|
|
|
|
|
|
|
#@$opt{ @dbi_opts } = @$param{ @dbi_opts }; |
376
|
|
|
|
|
|
|
|
377
|
0
|
0
|
|
|
|
0
|
$self->{drh} = $that->SUPER::install_driver( $self->{driver} ) if( $self->{driver} ); |
378
|
0
|
0
|
|
|
|
0
|
$opt->{RaiseError} = 0 if( !CORE::exists( $opt->{RaiseError} ) ); |
379
|
0
|
0
|
|
|
|
0
|
$opt->{AutoCommit} = 1 if( !CORE::exists( $opt->{AutoCommit} ) ); |
380
|
0
|
0
|
|
|
|
0
|
$opt->{PrintError} = 0 if( !CORE::exists( $opt->{PrintError} ) ); |
381
|
0
|
|
|
|
|
0
|
$self->{opt} = $opt; |
382
|
|
|
|
|
|
|
# Debug( $DB, $LOGIN, $PASSWD, $SERVER, $DRIVER ); |
383
|
|
|
|
|
|
|
# return( DBI->connect( "$DRIVER:$DB:$SERVER", $LOGIN, $PASSWD, \%OPT ) ); |
384
|
|
|
|
|
|
|
# open( DEB, '>>/tmp/manager_db_debug.txt' ); |
385
|
|
|
|
|
|
|
# print( DEB "DB::Object::connect( '$driver:$db:$server', '$login', '$passwd', '$opt', 'undef()', '$CONNECT_VIA'\n" ); |
386
|
|
|
|
|
|
|
# close( DEB ); |
387
|
0
|
|
0
|
|
|
0
|
my $dbh = $self->_dbi_connect || return( $self->pass_error ); |
388
|
0
|
|
|
|
|
0
|
$self->{dbh} = $dbh; |
389
|
|
|
|
|
|
|
# If we are not running under mod_perl, cleanup the database object handle in case it was not shutdown |
390
|
|
|
|
|
|
|
# using the DESTROY, but also the END block |
391
|
0
|
0
|
|
|
|
0
|
push( @DBH, $dbh ) if( !$MOD_PERL ); |
392
|
|
|
|
|
|
|
#$self->param( |
393
|
|
|
|
|
|
|
# ## Do not allow SELECT that will take too long or too much resource, i.e. over 2Gb of data |
394
|
|
|
|
|
|
|
# ## This is idiot proof mode |
395
|
|
|
|
|
|
|
# 'SQL_BIG_SELECTS' => 0, |
396
|
|
|
|
|
|
|
# ## SQL will abort if a DELETE or UPDATE is being executed w/o LIMIT nor WHERE clause |
397
|
|
|
|
|
|
|
# 'SQL_SAFE_MODE' => 1, |
398
|
|
|
|
|
|
|
#); |
399
|
0
|
|
|
|
|
0
|
local $/ = "\n"; |
400
|
0
|
|
|
|
|
0
|
my $tables = []; |
401
|
|
|
|
|
|
|
# 1 day |
402
|
|
|
|
|
|
|
# my $tbl_cache_timeout = 86400; |
403
|
0
|
|
0
|
|
|
0
|
my $host = $self->{host} || 'localhost'; |
404
|
0
|
|
0
|
|
|
0
|
my $port = $self->{port} || 0; |
405
|
0
|
|
|
|
|
0
|
my $driver = $self->{driver}; |
406
|
0
|
|
|
|
|
0
|
my $database = $self->database; |
407
|
0
|
|
|
|
|
0
|
my $cache_params = {}; |
408
|
0
|
0
|
|
|
|
0
|
$cache_params->{cache_dir} = $self->{cache_dir} if( $self->{cache_dir} ); |
409
|
0
|
0
|
|
|
|
0
|
$cache_params->{debug} = $self->{debug} if( $self->{debug} ); |
410
|
0
|
|
|
|
|
0
|
my $cache_tables = DB::Object::Cache::Tables->new( $cache_params ); |
411
|
0
|
|
|
|
|
0
|
$self->cache_tables( $cache_tables ); |
412
|
0
|
|
|
|
|
0
|
$tables = $self->tables_info; |
413
|
0
|
|
|
|
|
0
|
my $cache = |
414
|
|
|
|
|
|
|
{ |
415
|
|
|
|
|
|
|
host => $host, |
416
|
|
|
|
|
|
|
driver => $driver, |
417
|
|
|
|
|
|
|
port => $port, |
418
|
|
|
|
|
|
|
database => $database, |
419
|
|
|
|
|
|
|
tables => $tables, |
420
|
|
|
|
|
|
|
}; |
421
|
0
|
0
|
|
|
|
0
|
if( !defined( $cache_tables->set( $cache ) ) ) |
422
|
|
|
|
|
|
|
{ |
423
|
0
|
|
|
|
|
0
|
warn( "Unable to write to tables cache: ", $cache_tables->error, "\n" ); |
424
|
|
|
|
|
|
|
} |
425
|
0
|
|
|
|
|
0
|
return( $self ); |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
# sub constant_queries_cache { return( shift->_set_get_hash( 'constant_queries_cache', @_ ) ); } |
429
|
0
|
|
|
0
|
1
|
0
|
sub constant_queries_cache { return( $CONSTANT_QUERIES_CACHE ); } |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
sub constant_queries_cache_get |
432
|
|
|
|
|
|
|
{ |
433
|
0
|
|
|
0
|
1
|
0
|
my( $self, $def ) = @_; |
434
|
0
|
|
|
|
|
0
|
my $hash = $self->constant_queries_cache; |
435
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Parameter provided must be a hash, but I got '$def'." ) ) if( ref( $def ) ne 'HASH' ); |
436
|
0
|
|
|
|
|
0
|
foreach my $k ( qw( pack file line ) ) |
437
|
|
|
|
|
|
|
{ |
438
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Parameter \"$k\" is missing from the hash." ) ) if( !CORE::length( $def->{ $k } ) ); |
439
|
|
|
|
|
|
|
} |
440
|
0
|
|
|
|
|
0
|
my $key = CORE::join( '|', @$def{qw( pack file line )} ); |
441
|
0
|
|
|
|
|
0
|
my $ref = $hash->{ $key }; |
442
|
|
|
|
|
|
|
# $ts is thee timestamp of the file recorded at the time |
443
|
0
|
|
|
|
|
0
|
my $ts = $ref->{ts}; |
444
|
|
|
|
|
|
|
# A DB::Object::Statement object |
445
|
0
|
|
|
|
|
0
|
my $qo = $ref->query_object; |
446
|
0
|
0
|
|
|
|
0
|
return if( !CORE::length( $def->{file} ) ); |
447
|
0
|
0
|
|
|
|
0
|
return if( !-e( $def->{file} ) ); |
448
|
0
|
0
|
|
|
|
0
|
return if( ( CORE::stat( $def->{file} ) )[9] != $ts ); |
449
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Query object retrieved from constant query cache is void!" ) ) if( !$qo ); |
450
|
0
|
0
|
0
|
|
|
0
|
return( $self->error( "Query object retrieved from constant query cache is not a DB::Object::Query object or one of its sub classes." ) ) if( !$self->_is_object( $qo ) || !$qo->isa( 'DB::Object::Query' ) ); |
451
|
0
|
0
|
|
|
|
0
|
return if( $self->database ne $qo->database_object->database ); |
452
|
0
|
|
|
|
|
0
|
return( $self->_cache_this( $qo ) ); |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
sub constant_queries_cache_set |
456
|
|
|
|
|
|
|
{ |
457
|
0
|
|
|
0
|
1
|
0
|
my( $self, $def ) = @_; |
458
|
0
|
|
|
|
|
0
|
my $hash = $self->constant_queries_cache; |
459
|
0
|
|
|
|
|
0
|
foreach my $k ( qw( pack file line query_object ) ) |
460
|
|
|
|
|
|
|
{ |
461
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Parameter \"$k\" is missing from the hash." ) ) if( !CORE::length( $def->{ $k } ) ); |
462
|
|
|
|
|
|
|
} |
463
|
0
|
0
|
0
|
|
|
0
|
return( $self->error( "Provided query object is not a DB::Object::Query." ) ) if( !$self->_is_object( $def->{query_object} ) || !$def->{query_object}->isa( 'DB::Object::Query' ) ); |
464
|
0
|
|
|
|
|
0
|
$def->{ts} = ( CORE::stat( $def->{file} ) )[9]; |
465
|
0
|
|
|
|
|
0
|
my $key = CORE::join( '|', @$def{qw( pack file line )} ); |
466
|
0
|
|
|
|
|
0
|
$hash->{ $key } = $def; |
467
|
0
|
|
|
|
|
0
|
return( $def ); |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
sub copy |
471
|
|
|
|
|
|
|
{ |
472
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
473
|
0
|
|
|
|
|
0
|
my $opts = $self->_get_args_as_hash( @_ ); |
474
|
0
|
|
|
|
|
0
|
my $ref = $self->select->fetchrow_hashref(); |
475
|
0
|
|
|
|
|
0
|
my $keys = keys( %$opts ); |
476
|
0
|
|
|
|
|
0
|
@$ref{ @$keys } = @$opts{ @$keys }; |
477
|
0
|
0
|
|
|
|
0
|
return(0) if( !scalar( keys( %$ref ) ) ); |
478
|
0
|
|
|
|
|
0
|
$self->insert( $ref ); |
479
|
0
|
|
|
|
|
0
|
return(1); |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
|
482
|
0
|
|
|
0
|
1
|
0
|
sub create_db { return( shift->error( "THe driver has not implemented the create database method create_db." ) ); } |
483
|
|
|
|
|
|
|
|
484
|
0
|
|
|
0
|
1
|
0
|
sub create_table { return( shift->error( "THe driver has not implemented the create table method create_table." ) ); } |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
sub data_sources($;\%) |
487
|
|
|
|
|
|
|
{ |
488
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
489
|
0
|
|
0
|
|
|
0
|
my $class = ref( $self ) || $self; |
490
|
0
|
|
|
|
|
0
|
my $opt; |
491
|
0
|
0
|
|
|
|
0
|
$opt = shift( @_ ) if( @_ ); |
492
|
0
|
|
0
|
|
|
0
|
my $driver = $self->{driver} || return( $self->error( "No driver to to use to check for data sources." ) ); |
493
|
0
|
|
|
|
|
0
|
return( $class->SUPER::data_sources( $driver, $opt ) ); |
494
|
|
|
|
|
|
|
} |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
sub data_type |
497
|
|
|
|
|
|
|
{ |
498
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
499
|
0
|
0
|
|
|
|
0
|
my $type = @_ == 1 ? shift( @_ ) : [ @_ ] if( @_ ); |
|
|
0
|
|
|
|
|
|
500
|
|
|
|
|
|
|
my $ref = eval |
501
|
0
|
|
|
|
|
0
|
{ |
502
|
0
|
|
|
0
|
|
0
|
local $SIG{__DIE__} = sub{ }; |
503
|
0
|
|
|
0
|
|
0
|
local $SIG{__WARN__} = sub{ }; |
504
|
0
|
|
|
|
|
0
|
$self->{dbh}->type_info_all(); |
505
|
|
|
|
|
|
|
}; |
506
|
0
|
0
|
|
|
|
0
|
return( $self->error( "type_info_all() is unsupported by vendor '$self->{ 'driver' }'." ) ) if( $@ ); |
507
|
|
|
|
|
|
|
# First item is a reference to hash containing the order of the header |
508
|
0
|
|
|
|
|
0
|
my $header = shift( @$ref ); |
509
|
0
|
|
|
|
|
0
|
my $hash = {}; |
510
|
0
|
|
|
|
|
0
|
my $name_idx = $header->{TYPE_NAME}; |
511
|
0
|
|
|
|
|
0
|
my @found = (); |
512
|
0
|
0
|
|
|
|
0
|
if( $type ) |
513
|
|
|
|
|
|
|
{ |
514
|
0
|
0
|
|
|
|
0
|
my @types = ref( $type ) ? @$type : ( $type ); |
515
|
0
|
|
|
|
|
0
|
foreach my $requested ( @types ) |
516
|
|
|
|
|
|
|
{ |
517
|
0
|
|
|
|
|
0
|
push( @found, grep{ uc( $requested ) eq $_->[ $name_idx ] } @$ref ); |
|
0
|
|
|
|
|
0
|
|
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
else |
521
|
|
|
|
|
|
|
{ |
522
|
0
|
|
|
|
|
0
|
@found = @$ref; |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
# Stop. No need to go further |
525
|
0
|
0
|
|
|
|
0
|
return( wantarray() ? () : undef() ) if( !@found ); |
|
|
0
|
|
|
|
|
|
526
|
0
|
|
|
|
|
0
|
my @names = map{ lc( $_ ) } keys( %$header ); |
|
0
|
|
|
|
|
0
|
|
527
|
0
|
|
|
|
|
0
|
my $len = scalar( keys( %$header ) ); |
528
|
0
|
|
|
|
|
0
|
my @order = values( %$header ); |
529
|
|
|
|
|
|
|
map |
530
|
|
|
|
|
|
|
{ |
531
|
0
|
0
|
|
|
|
0
|
next if( @$_ != $len ); |
|
0
|
|
|
|
|
0
|
|
532
|
0
|
|
|
|
|
0
|
my %data; |
533
|
0
|
|
|
|
|
0
|
@data{ @names } = @{ $_ }[ @order ]; |
|
0
|
|
|
|
|
0
|
|
534
|
0
|
|
|
|
|
0
|
$hash->{ lc( $_->[ $name_idx ] ) } = \%data; |
535
|
|
|
|
|
|
|
} @found; |
536
|
0
|
0
|
|
|
|
0
|
return( wantarray() ? () : undef() ) if( !%$hash ); |
|
|
0
|
|
|
|
|
|
537
|
0
|
0
|
|
|
|
0
|
return( wantarray() ? %$hash : $hash ); |
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
sub database |
541
|
|
|
|
|
|
|
{ |
542
|
|
|
|
|
|
|
# Read only |
543
|
0
|
|
|
0
|
1
|
0
|
return( shift->{database} ); |
544
|
|
|
|
|
|
|
} |
545
|
|
|
|
|
|
|
|
546
|
0
|
|
|
0
|
1
|
0
|
sub databases { return( shift->error( "Method databases() is not implemented by driver." ) ); } |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
sub disconnect($) |
549
|
|
|
|
|
|
|
{ |
550
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
551
|
|
|
|
|
|
|
# my( $pack, $file, $line ) = caller(); |
552
|
|
|
|
|
|
|
# print( STDERR "disconnect() called from package '$pack' in file '$file' at line '$line'.\n" ); |
553
|
0
|
|
|
|
|
0
|
my $rc = $self->{dbh}->disconnect( @_ ); |
554
|
0
|
|
|
|
|
0
|
return( $rc ); |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
sub do($;$@) |
558
|
|
|
|
|
|
|
{ |
559
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
560
|
|
|
|
|
|
|
# $rc = $dbh->do( $statement ) || die( $dbh->errstr ); |
561
|
|
|
|
|
|
|
# $rc = $dbh->do( $statement, \%attr ) || die( $dbh->errstr ); |
562
|
|
|
|
|
|
|
# $rv = $dbh->do( $statement, \%attr, @bind_values ) || ... |
563
|
|
|
|
|
|
|
# my( $rows_deleted ) = $dbh->do( |
564
|
|
|
|
|
|
|
# q{ |
565
|
|
|
|
|
|
|
# DELETE FROM table WHERE status = ? |
566
|
|
|
|
|
|
|
# }, undef(), 'DONE' ) || die( $dbh->errstr ); |
567
|
0
|
|
|
|
|
0
|
my $query = shift( @_ ); |
568
|
0
|
|
0
|
|
|
0
|
my $opt_ref = shift( @_ ) || undef(); |
569
|
0
|
|
0
|
|
|
0
|
my $param_ref = shift( @_ ) || []; |
570
|
0
|
|
0
|
|
|
0
|
my $dbh = $self->{dbh} || return( $self->error( "Could not find database handler." ) ); |
571
|
0
|
|
0
|
|
|
0
|
my $sth = $dbh->prepare( $query, $opt_ref ) || |
572
|
|
|
|
|
|
|
return( $self->error( "Error while preparing do query:\n$query", $dbh->errstr() ) ); |
573
|
0
|
0
|
|
|
|
0
|
$sth->execute( @$param_ref ) || |
574
|
|
|
|
|
|
|
return( $self->error( "Error while executing do query:\n$query", $sth->errstr() ) ); |
575
|
|
|
|
|
|
|
# my $rows = $sth->rows(); |
576
|
|
|
|
|
|
|
# return( ( $rows == 0 ) ? "0E0" : $rows ); |
577
|
0
|
|
|
|
|
0
|
return( $sth ); |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
|
580
|
0
|
|
|
0
|
1
|
0
|
sub driver { return( shift->_set_get( 'driver' ) ); } |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
sub enhance |
583
|
|
|
|
|
|
|
{ |
584
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
585
|
0
|
|
|
|
|
0
|
my $prev = $self->{enhance}; |
586
|
0
|
0
|
|
|
|
0
|
$self->{enhance} = shift( @_ ) if( @_ ); |
587
|
0
|
|
|
|
|
0
|
return( $prev ); |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
sub err(@) |
591
|
|
|
|
|
|
|
{ |
592
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
593
|
|
|
|
|
|
|
# $rv = $h->err; |
594
|
0
|
0
|
|
|
|
0
|
if( defined( $self->{sth} ) ) |
|
|
0
|
|
|
|
|
|
595
|
|
|
|
|
|
|
{ |
596
|
0
|
|
|
|
|
0
|
return( $self->{sth}->err() ); |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
elsif( $self->{dbh} ) |
599
|
|
|
|
|
|
|
{ |
600
|
0
|
|
|
|
|
0
|
return( $self->{dbh}->err() ); |
601
|
|
|
|
|
|
|
} |
602
|
|
|
|
|
|
|
#else |
603
|
|
|
|
|
|
|
#{ |
604
|
|
|
|
|
|
|
# return( $self->{ 'drh' }->err() ); |
605
|
|
|
|
|
|
|
# return( DBI::err(); |
606
|
|
|
|
|
|
|
#} |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
sub errno |
610
|
|
|
|
|
|
|
{ |
611
|
0
|
|
|
0
|
1
|
0
|
goto( &err ); |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
sub errmesg |
615
|
|
|
|
|
|
|
{ |
616
|
0
|
|
|
0
|
1
|
0
|
goto( &errstr ); |
617
|
|
|
|
|
|
|
} |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
sub errstr(@) |
620
|
|
|
|
|
|
|
{ |
621
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
622
|
0
|
0
|
0
|
|
|
0
|
if( !ref( $self ) ) |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
623
|
|
|
|
|
|
|
{ |
624
|
0
|
|
0
|
|
|
0
|
return( $DBI::errstr || $DB_ERRSTR ); |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
elsif( defined( $self->{sth} ) && $self->{sth}->errstr() ) |
627
|
|
|
|
|
|
|
{ |
628
|
0
|
|
|
|
|
0
|
return( $self->{sth}->errstr() ); |
629
|
|
|
|
|
|
|
} |
630
|
|
|
|
|
|
|
elsif( defined( $self->{dbh} ) && $self->{dbh}->errstr() ) |
631
|
|
|
|
|
|
|
{ |
632
|
0
|
|
|
|
|
0
|
return( $self->{dbh}->errstr() ); |
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
else |
635
|
|
|
|
|
|
|
{ |
636
|
0
|
|
|
|
|
0
|
return( $self->{errstr} ); |
637
|
|
|
|
|
|
|
} |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
|
640
|
0
|
|
|
0
|
1
|
0
|
sub FALSE { return( 'FALSE' ); } |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
sub fatal |
643
|
|
|
|
|
|
|
{ |
644
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
645
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
646
|
|
|
|
|
|
|
{ |
647
|
0
|
|
|
|
|
0
|
$self->{fatal} = int( shift( @_ ) ); |
648
|
|
|
|
|
|
|
} |
649
|
0
|
|
|
|
|
0
|
return( $self->{fatal} ); |
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
|
652
|
0
|
|
|
0
|
1
|
0
|
sub get_sql_type { return( shift->error( "The driver has not provided support for this method get_sql_type()" ) ); } |
653
|
|
|
|
|
|
|
|
654
|
0
|
|
|
0
|
1
|
0
|
sub host { return( shift->_set_get_scalar( 'host', @_ ) ); } |
655
|
|
|
|
|
|
|
|
656
|
0
|
|
|
0
|
1
|
0
|
sub IN { return( DB::Object::IN->new( splice( @_, 1 ) ) ); } |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
# $rv = $dbh->last_insert_id($catalog, $schema, $table, $field, \%attr); |
659
|
|
|
|
|
|
|
sub last_insert_id |
660
|
|
|
|
|
|
|
{ |
661
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
662
|
0
|
|
|
|
|
0
|
return( $self->error( "Method \"last_insert_id\" has not been implemented by driver $self->{driver} (object = $self)." ) ); |
663
|
|
|
|
|
|
|
} |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
sub lock |
666
|
|
|
|
|
|
|
{ |
667
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
668
|
0
|
|
|
|
|
0
|
return( $self->error( "Method \"lock\" has not been implemented by driver $self->{driver} (object = $self)." ) ); |
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
|
671
|
0
|
|
|
0
|
1
|
0
|
sub login { return( shift->_set_get_scalar( 'login', @_ ) ); } |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
sub no_bind |
674
|
|
|
|
|
|
|
{ |
675
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
676
|
|
|
|
|
|
|
# Done, already |
677
|
0
|
0
|
|
|
|
0
|
return( $self ) if( !$self->{bind} ); |
678
|
0
|
|
|
|
|
0
|
$self->{bind} = 0; |
679
|
0
|
|
|
|
|
0
|
my $q = $self->_reset_query; |
680
|
0
|
|
|
|
|
0
|
my $where = $q->where(); |
681
|
0
|
|
|
|
|
0
|
my $group = $q->group(); |
682
|
0
|
|
|
|
|
0
|
my $order = $q->order(); |
683
|
0
|
|
|
|
|
0
|
my $limit = $q->limit(); |
684
|
0
|
|
|
|
|
0
|
my $binded_where = $q->binded_where; |
685
|
0
|
|
|
|
|
0
|
my $binded_group = $q->binded_group; |
686
|
0
|
|
|
|
|
0
|
my $binded_order = $q->binded_order; |
687
|
0
|
|
|
|
|
0
|
my $binded_limit = $q->binded_limit; |
688
|
|
|
|
|
|
|
# Replace the place holders by their corresponding value |
689
|
|
|
|
|
|
|
# and have them re-processed by their corresponding method |
690
|
0
|
0
|
0
|
|
|
0
|
if( $where && @$binded_where ) |
691
|
|
|
|
|
|
|
{ |
692
|
0
|
|
|
|
|
0
|
$where =~ s/(=\s*\?)/"='" . quotemeta( $binded_where->[ $#+ ] ) . "'"/ge; |
|
0
|
|
|
|
|
0
|
|
693
|
0
|
|
|
|
|
0
|
$self->where( $where ); |
694
|
|
|
|
|
|
|
} |
695
|
0
|
0
|
0
|
|
|
0
|
if( $group && @$binded_group ) |
696
|
|
|
|
|
|
|
{ |
697
|
0
|
|
|
|
|
0
|
$group =~ s/(=\s*\?)/"='" . quotemeta( $binded_group->[ $#+ ] ) . "'"/ge; |
|
0
|
|
|
|
|
0
|
|
698
|
0
|
|
|
|
|
0
|
$self->group( $group ); |
699
|
|
|
|
|
|
|
} |
700
|
0
|
0
|
0
|
|
|
0
|
if( $order && @$binded_order ) |
701
|
|
|
|
|
|
|
{ |
702
|
0
|
|
|
|
|
0
|
$order =~ s/(=\s*\?)/"='" . quotemeta( $binded_order->[ $#+ ] ) . "'"/ge; |
|
0
|
|
|
|
|
0
|
|
703
|
0
|
|
|
|
|
0
|
$self->order( $order ); |
704
|
|
|
|
|
|
|
} |
705
|
0
|
0
|
0
|
|
|
0
|
if( $limit && @$binded_limit ) |
706
|
|
|
|
|
|
|
{ |
707
|
|
|
|
|
|
|
# $limit =~ s/(=\s*\?)/"='" . quotemeta( $binded_limit[ $#+ ] ) . "'"/ge; |
708
|
0
|
|
|
|
|
0
|
$self->limit( @$binded_limit ); |
709
|
|
|
|
|
|
|
} |
710
|
0
|
|
|
|
|
0
|
$q->reset_bind; |
711
|
0
|
|
|
|
|
0
|
return( $self ); |
712
|
|
|
|
|
|
|
} |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
sub no_cache |
715
|
|
|
|
|
|
|
{ |
716
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
717
|
0
|
|
|
|
|
0
|
$self->{cache} = 0; |
718
|
0
|
|
|
|
|
0
|
return( $self ); |
719
|
|
|
|
|
|
|
} |
720
|
|
|
|
|
|
|
|
721
|
0
|
|
|
0
|
1
|
0
|
sub NOT { shift( @_ ); return( DB::Object::NOT->new( @_ ) ); } |
|
0
|
|
|
|
|
0
|
|
722
|
|
|
|
|
|
|
|
723
|
0
|
|
|
0
|
1
|
0
|
sub NULL { return( 'NULL' ); } |
724
|
|
|
|
|
|
|
|
725
|
0
|
|
|
0
|
1
|
0
|
sub OR { shift( @_ ); return( DB::Object::OR->new( @_ ) ); } |
|
0
|
|
|
|
|
0
|
|
726
|
|
|
|
|
|
|
|
727
|
1
|
|
|
1
|
1
|
1444
|
sub P { shift( @_ ); return( DB::Object::Placeholder->new( @_ ) ); } |
|
1
|
|
|
|
|
17
|
|
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
sub param |
730
|
|
|
|
|
|
|
{ |
731
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
732
|
0
|
0
|
|
|
|
0
|
return if( !@_ ); |
733
|
0
|
|
|
|
|
0
|
my @supported = |
734
|
|
|
|
|
|
|
qw( |
735
|
|
|
|
|
|
|
SQL_AUTO_IS_NULL AUTOCOMMIT SQL_BIG_TABLES SQL_BIG_SELECTS |
736
|
|
|
|
|
|
|
SQL_BUFFER_RESULT SQL_LOW_PRIORITY_UPDATES SQL_MAX_JOIN_SIZE |
737
|
|
|
|
|
|
|
SQL_SAFE_MODE SQL_SELECT_LIMIT SQL_LOG_OFF SQL_LOG_UPDATE |
738
|
|
|
|
|
|
|
TIMESTAMP INSERT_ID LAST_INSERT_ID |
739
|
|
|
|
|
|
|
); |
740
|
0
|
|
0
|
|
|
0
|
my $params = $self->{params} ||= {}; |
741
|
0
|
0
|
|
|
|
0
|
if( @_ == 1 ) |
742
|
|
|
|
|
|
|
{ |
743
|
0
|
|
|
|
|
0
|
my $type = shift( @_ ); |
744
|
0
|
0
|
|
|
|
0
|
$type = uc( $type ) if( scalar( grep{ /^$_[ 0 ]$/i } @supported ) ); |
|
0
|
|
|
|
|
0
|
|
745
|
0
|
|
|
|
|
0
|
return( $params->{ $type } ); |
746
|
|
|
|
|
|
|
} |
747
|
|
|
|
|
|
|
else |
748
|
|
|
|
|
|
|
{ |
749
|
0
|
|
|
|
|
0
|
my %arg = ( @_ ); |
750
|
0
|
|
|
|
|
0
|
my( $type, $value ); |
751
|
0
|
|
|
|
|
0
|
my @query = (); |
752
|
0
|
|
|
|
|
0
|
while( ( $type, $value ) = each( %arg ) ) |
753
|
|
|
|
|
|
|
{ |
754
|
0
|
|
|
|
|
0
|
my @found = grep{ /^(SQL_)?$type$/i } @supported; |
|
0
|
|
|
|
|
0
|
|
755
|
|
|
|
|
|
|
# SQL parameter |
756
|
0
|
0
|
|
|
|
0
|
if( scalar( @found ) ) |
757
|
|
|
|
|
|
|
{ |
758
|
0
|
|
|
|
|
0
|
$type = uc( $type ); |
759
|
0
|
0
|
0
|
|
|
0
|
$value = 0 if( !defined( $value ) || $value eq '' ); |
760
|
0
|
|
|
|
|
0
|
$params->{ $type } = $value; |
761
|
0
|
0
|
0
|
|
|
0
|
if( $type eq 'AUTOCOMMIT' && $self->{dbh} && $value =~ /^(?:1|0)$/ ) |
|
|
|
0
|
|
|
|
|
762
|
|
|
|
|
|
|
{ |
763
|
0
|
|
|
|
|
0
|
$self->{dbh}->{AutoCommit} = $value; |
764
|
|
|
|
|
|
|
} |
765
|
0
|
|
|
|
|
0
|
push( @query, "$type = $value" ); |
766
|
|
|
|
|
|
|
} |
767
|
|
|
|
|
|
|
# Private parameter - May be anything |
768
|
|
|
|
|
|
|
else |
769
|
|
|
|
|
|
|
{ |
770
|
0
|
|
|
|
|
0
|
$params->{ $type } = $value; |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
} |
773
|
0
|
0
|
|
|
|
0
|
return( $self ) if( !scalar( @query ) ); |
774
|
0
|
|
0
|
|
|
0
|
my $dbh = $self->{dbh} || return( $self->error( "Could not find database handler." ) ); |
775
|
0
|
|
|
|
|
0
|
my $query = 'SET ' . CORE::join( ', ', @query ); |
776
|
0
|
|
0
|
|
|
0
|
my $sth = $dbh->prepare( $query ) || |
777
|
|
|
|
|
|
|
return( $self->error( "Unable to set options '", CORE::join( ', ', @query ), "'" ) ); |
778
|
0
|
|
|
|
|
0
|
$sth->execute(); |
779
|
0
|
|
|
|
|
0
|
$sth->finish(); |
780
|
0
|
|
|
|
|
0
|
return( $self ); |
781
|
|
|
|
|
|
|
} |
782
|
|
|
|
|
|
|
} |
783
|
|
|
|
|
|
|
|
784
|
0
|
|
|
0
|
1
|
0
|
sub passwd { return( shift->_set_get_scalar( 'passwd', @_ ) ); } |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
sub ping(@) |
787
|
|
|
|
|
|
|
{ |
788
|
|
|
|
|
|
|
#return( shift->{ 'dbh' }->ping ); |
789
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
790
|
0
|
|
|
|
|
0
|
return( $self->{dbh}->ping ); |
791
|
|
|
|
|
|
|
} |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
sub ping_select(@) |
794
|
|
|
|
|
|
|
{ |
795
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
796
|
|
|
|
|
|
|
# $rc = $dbh->ping; |
797
|
|
|
|
|
|
|
# Some new ping method replacement.... See Apache::DBI |
798
|
|
|
|
|
|
|
# my( $dbh ) = @_; |
799
|
0
|
|
|
|
|
0
|
my $ret = 0; |
800
|
|
|
|
|
|
|
eval |
801
|
0
|
|
|
|
|
0
|
{ |
802
|
0
|
|
|
0
|
|
0
|
local( $SIG{__DIE__} ) = sub{ return( 0 ); }; |
|
0
|
|
|
|
|
0
|
|
803
|
0
|
|
|
0
|
|
0
|
local( $SIG{__WARN__} ) = sub{ return( 0 ); }; |
|
0
|
|
|
|
|
0
|
|
804
|
|
|
|
|
|
|
# adapt the select statement to your database: |
805
|
0
|
|
|
|
|
0
|
my $sth = $self->prepare( "SELECT 1" ); |
806
|
0
|
|
0
|
|
|
0
|
$ret = $sth && ( $sth->execute() ); |
807
|
0
|
|
|
|
|
0
|
$sth->finish(); |
808
|
|
|
|
|
|
|
}; |
809
|
0
|
0
|
|
|
|
0
|
return( ($@) ? 0 : $ret ); |
810
|
|
|
|
|
|
|
} |
811
|
|
|
|
|
|
|
|
812
|
42
|
|
|
42
|
1
|
61
|
sub placeholder { shift( @_ ); return( DB::Object::Placeholder->new( @_ ) ); } |
|
42
|
|
|
|
|
150
|
|
813
|
|
|
|
|
|
|
|
814
|
0
|
|
|
0
|
1
|
0
|
sub port { return( shift->_set_get_number( 'port', @_ ) ); } |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
# Gateway to DB::Object::Statement |
817
|
|
|
|
|
|
|
sub prepare($;$) |
818
|
|
|
|
|
|
|
{ |
819
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
820
|
0
|
|
0
|
|
|
0
|
my $class = ref( $self ) || $self; |
821
|
0
|
|
|
|
|
0
|
my $query = shift( @_ ); |
822
|
0
|
|
0
|
|
|
0
|
my $opt_ref = shift( @_ ) || undef(); |
823
|
0
|
|
|
|
|
0
|
my $base_class = $self->base_class; |
824
|
0
|
|
|
|
|
0
|
my $q; |
825
|
0
|
0
|
0
|
|
|
0
|
if( ref( $q ) && $q->isa( 'DB::Object::Query' ) ) |
826
|
|
|
|
|
|
|
{ |
827
|
0
|
|
|
|
|
0
|
$q = $query; |
828
|
0
|
|
|
|
|
0
|
$query = $q->as_string; |
829
|
|
|
|
|
|
|
} |
830
|
0
|
|
|
|
|
0
|
$self->_clean_statement( \$query ); |
831
|
|
|
|
|
|
|
# Wether we are called from DB::Object or DB::Object::Tables object |
832
|
0
|
|
0
|
|
|
0
|
my $dbo = $self->{dbo} || $self; |
833
|
0
|
0
|
|
|
|
0
|
if( !$dbo->ping ) |
834
|
|
|
|
|
|
|
{ |
835
|
0
|
|
0
|
|
|
0
|
my $dbh = $dbo->_dbi_connect || return; |
836
|
0
|
|
|
|
|
0
|
$self->{dbh} = $dbo->{dbh} = $dbh; |
837
|
|
|
|
|
|
|
} |
838
|
|
|
|
|
|
|
my $sth = eval |
839
|
0
|
|
|
|
|
0
|
{ |
840
|
0
|
|
|
0
|
|
0
|
local( $SIG{__DIE__} ) = sub{ }; |
841
|
0
|
|
|
0
|
|
0
|
local( $SIG{__WARN__} ) = sub{ }; |
842
|
0
|
|
|
|
|
0
|
$dbo->{dbh}->prepare( $query, $opt_ref ); |
843
|
|
|
|
|
|
|
}; |
844
|
0
|
0
|
|
|
|
0
|
if( $sth ) |
845
|
|
|
|
|
|
|
{ |
846
|
|
|
|
|
|
|
# my $data = { 'sth' => $sth, 'query' => $query }; |
847
|
|
|
|
|
|
|
my $data = |
848
|
|
|
|
|
|
|
{ |
849
|
|
|
|
|
|
|
sth => $sth, |
850
|
|
|
|
|
|
|
query => $query, |
851
|
|
|
|
|
|
|
query_values => $self->{query_values}, |
852
|
|
|
|
|
|
|
selected_fields => $self->{selected_fields}, |
853
|
0
|
|
|
|
|
0
|
query_object => $q |
854
|
|
|
|
|
|
|
}; |
855
|
0
|
|
|
|
|
0
|
return( $self->_make_sth( "${base_class}::Statement", $data ) ); |
856
|
|
|
|
|
|
|
} |
857
|
|
|
|
|
|
|
else |
858
|
|
|
|
|
|
|
{ |
859
|
0
|
|
0
|
|
|
0
|
my $err = $@ || $self->{dbh}->errstr() || 'Unknown error while cache preparing query.'; |
860
|
0
|
|
|
|
|
0
|
$self->{query} = $query; |
861
|
0
|
|
|
|
|
0
|
return( $self->error( $err ) ); |
862
|
|
|
|
|
|
|
} |
863
|
|
|
|
|
|
|
} |
864
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
sub prepare_cached |
866
|
|
|
|
|
|
|
{ |
867
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
868
|
0
|
|
0
|
|
|
0
|
my $class = ref( $self ) || $self; |
869
|
0
|
|
|
|
|
0
|
my $query = shift( @_ ); |
870
|
0
|
|
0
|
|
|
0
|
my $opt_ref = shift( @_ ) || undef(); |
871
|
0
|
|
|
|
|
0
|
my $base_class = $self->base_class; |
872
|
0
|
|
|
|
|
0
|
my $q; |
873
|
0
|
0
|
0
|
|
|
0
|
if( ref( $q ) && $q->isa( 'DB::Object::Query' ) ) |
874
|
|
|
|
|
|
|
{ |
875
|
0
|
|
|
|
|
0
|
$q = $query; |
876
|
0
|
|
|
|
|
0
|
$query = $q->as_string; |
877
|
|
|
|
|
|
|
} |
878
|
0
|
|
|
|
|
0
|
$self->_clean_statement( \$query ); |
879
|
|
|
|
|
|
|
# Wether we are called from DB::Object or DB::Object::Tables object |
880
|
0
|
|
0
|
|
|
0
|
my $dbo = $self->{dbo} || $self; |
881
|
0
|
0
|
|
|
|
0
|
if( !$dbo->ping ) |
882
|
|
|
|
|
|
|
{ |
883
|
0
|
|
0
|
|
|
0
|
my $dbh = $dbo->_dbi_connect || return; |
884
|
0
|
|
|
|
|
0
|
$self->{dbh} = $dbo->{dbh} = $dbh; |
885
|
|
|
|
|
|
|
} |
886
|
|
|
|
|
|
|
my $sth = eval |
887
|
0
|
|
|
|
|
0
|
{ |
888
|
0
|
|
|
0
|
|
0
|
local( $SIG{__DIE__} ) = sub{ }; |
889
|
0
|
|
|
0
|
|
0
|
local( $SIG{__WARN__} ) = sub{ }; |
890
|
0
|
|
|
|
|
0
|
$dbo->{dbh}->prepare_cached( $query, $opt_ref ); |
891
|
|
|
|
|
|
|
}; |
892
|
0
|
0
|
|
|
|
0
|
if( $sth ) |
893
|
|
|
|
|
|
|
{ |
894
|
|
|
|
|
|
|
# my $data = { %$self, 'sth' => $sth, 'query' => $query }; |
895
|
|
|
|
|
|
|
# my $data = { 'sth' => $sth, 'query' => $query }; |
896
|
|
|
|
|
|
|
my $data = |
897
|
|
|
|
|
|
|
{ |
898
|
|
|
|
|
|
|
sth => $sth, |
899
|
|
|
|
|
|
|
query => $query, |
900
|
|
|
|
|
|
|
query_values => $self->{query_values}, |
901
|
|
|
|
|
|
|
selected_fields => $self->{selected_fields}, |
902
|
0
|
|
|
|
|
0
|
query_object => $q, |
903
|
|
|
|
|
|
|
}; |
904
|
|
|
|
|
|
|
# CORE::delete( $data->{ 'executed' } ); |
905
|
|
|
|
|
|
|
# This is an inner package |
906
|
|
|
|
|
|
|
# bless( $data, "DB::Object::Statement" ); |
907
|
|
|
|
|
|
|
# return( $data ); |
908
|
0
|
|
|
|
|
0
|
return( $self->_make_sth( "${base_class}::Statement", $data ) ); |
909
|
|
|
|
|
|
|
} |
910
|
|
|
|
|
|
|
else |
911
|
|
|
|
|
|
|
{ |
912
|
0
|
|
0
|
|
|
0
|
my $err = $@ || $self->{dbh}->errstr() || 'Unknown error while cache preparing query.'; |
913
|
0
|
|
|
|
|
0
|
$self->{query} = $query; |
914
|
0
|
|
|
|
|
0
|
return( $self->error( $err ) ); |
915
|
|
|
|
|
|
|
} |
916
|
|
|
|
|
|
|
} |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
sub query($$) |
919
|
|
|
|
|
|
|
{ |
920
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
921
|
0
|
|
|
|
|
0
|
my $sth = $self->prepare( @_ ); |
922
|
0
|
|
|
|
|
0
|
my $result; |
923
|
0
|
0
|
0
|
|
|
0
|
if( $sth && !( $result = $sth->execute() ) ) |
924
|
|
|
|
|
|
|
{ |
925
|
0
|
|
|
|
|
0
|
return; |
926
|
|
|
|
|
|
|
} |
927
|
|
|
|
|
|
|
else |
928
|
|
|
|
|
|
|
{ |
929
|
|
|
|
|
|
|
# bless( $sth, ref( $self ) ); |
930
|
0
|
|
|
|
|
0
|
return( $sth ); |
931
|
|
|
|
|
|
|
} |
932
|
|
|
|
|
|
|
} |
933
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
sub quote |
935
|
|
|
|
|
|
|
{ |
936
|
16
|
|
|
16
|
1
|
19863
|
my $self = shift( @_ ); |
937
|
|
|
|
|
|
|
# my $dbh = $self->{dbh} || return( $self->error( "No database handler was set." ) ); |
938
|
16
|
|
|
|
|
37
|
my $dbh; |
939
|
16
|
50
|
|
|
|
54
|
unless( $dbh = $self->{dbh} ) |
940
|
|
|
|
|
|
|
{ |
941
|
|
|
|
|
|
|
# This is a fallback in case we need to use quote, but do not have a database connection yet. |
942
|
16
|
|
|
|
|
33
|
my $str = shift( @_ ); |
943
|
|
|
|
|
|
|
# print( STDERR ref( $self ), "::quote -> \$str is '$str' (without surrounding quote\n" ); |
944
|
16
|
50
|
33
|
|
|
92
|
return( $self->NULL ) if( !defined( $str ) || uc( $str ) eq 'NULL' ); |
945
|
16
|
50
|
|
|
|
108
|
if( $str =~ /^$RE{num}{real}$/ ) |
946
|
|
|
|
|
|
|
{ |
947
|
16
|
|
|
|
|
2548
|
return( $str ); |
948
|
|
|
|
|
|
|
} |
949
|
|
|
|
|
|
|
else |
950
|
|
|
|
|
|
|
{ |
951
|
0
|
|
|
|
|
0
|
$str =~ s/'/''/g; # iso SQL 2 |
952
|
0
|
|
|
|
|
0
|
return( "'$str'" ); |
953
|
|
|
|
|
|
|
} |
954
|
|
|
|
|
|
|
} |
955
|
0
|
|
|
|
|
0
|
return( $dbh->quote( @_ ) ); |
956
|
|
|
|
|
|
|
} |
957
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
sub set |
959
|
|
|
|
|
|
|
{ |
960
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
961
|
0
|
|
|
|
|
0
|
my $vars = ''; |
962
|
0
|
|
|
|
|
0
|
$vars = shift( @_ ); |
963
|
0
|
|
0
|
|
|
0
|
$vars ||= $self->local(); |
964
|
|
|
|
|
|
|
# Are there any variable declaration? |
965
|
0
|
0
|
|
|
|
0
|
if( $vars ) |
966
|
|
|
|
|
|
|
{ |
967
|
0
|
|
|
|
|
0
|
my $query = "SET $vars"; |
968
|
|
|
|
|
|
|
eval |
969
|
0
|
|
|
|
|
0
|
{ |
970
|
0
|
|
|
0
|
|
0
|
local( $SIG{__DIE__} ) = sub{ }; |
971
|
0
|
|
|
0
|
|
0
|
local( $SIG{__WARN__} ) = sub{ }; |
972
|
0
|
|
|
0
|
|
0
|
local( $SIG{ALRM} ) = sub{ die( "Timeout while processing query to set variables:\n$query\n" ) }; |
|
0
|
|
|
|
|
0
|
|
973
|
0
|
|
|
|
|
0
|
$self->do( $query ); |
974
|
|
|
|
|
|
|
}; |
975
|
0
|
0
|
|
|
|
0
|
if( $@ ) |
976
|
|
|
|
|
|
|
{ |
977
|
0
|
|
|
|
|
0
|
my $err = '*** ' . join( "\n*** ", split( /\n/, $@ ) ); |
978
|
0
|
0
|
|
|
|
0
|
if( $self->fatal() ) |
979
|
|
|
|
|
|
|
{ |
980
|
0
|
|
|
|
|
0
|
die( "Error occured while setting SQL variables before executing query:\n$self->{sth}->{Statement}\n$err\n" ); |
981
|
|
|
|
|
|
|
} |
982
|
|
|
|
|
|
|
else |
983
|
|
|
|
|
|
|
{ |
984
|
0
|
|
|
|
|
0
|
return( $self->error( $@ ) ); |
985
|
|
|
|
|
|
|
} |
986
|
|
|
|
|
|
|
} |
987
|
|
|
|
|
|
|
} |
988
|
0
|
|
|
|
|
0
|
return(1); |
989
|
|
|
|
|
|
|
} |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
# To also consider: |
992
|
|
|
|
|
|
|
# $sth = $dbh->statistics_info( undef, $schema, $table, $unique_only, $quick ); |
993
|
|
|
|
|
|
|
sub stat |
994
|
|
|
|
|
|
|
{ |
995
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
996
|
0
|
|
|
|
|
0
|
my $type = lc( shift( @_ ) ); |
997
|
0
|
|
|
|
|
0
|
my $sth = $self->prepare( "SHOW STATUS" ); |
998
|
0
|
|
|
|
|
0
|
$sth->execute(); |
999
|
0
|
|
|
|
|
0
|
my @data = (); |
1000
|
0
|
|
|
|
|
0
|
my $ref = {}; |
1001
|
0
|
|
|
|
|
0
|
while( @data = $sth->fetchrow() ) |
1002
|
|
|
|
|
|
|
{ |
1003
|
0
|
|
|
|
|
0
|
$ref->{ lc( $data[ 0 ] ) } = $data[ 1 ]; |
1004
|
|
|
|
|
|
|
} |
1005
|
0
|
|
|
|
|
0
|
$sth->finish(); |
1006
|
0
|
0
|
|
|
|
0
|
if( $type ) |
1007
|
|
|
|
|
|
|
{ |
1008
|
0
|
0
|
|
|
|
0
|
return( exists( $ref->{ $type } ) ? $ref->{ $type } : undef() ); |
1009
|
|
|
|
|
|
|
} |
1010
|
|
|
|
|
|
|
else |
1011
|
|
|
|
|
|
|
{ |
1012
|
0
|
0
|
|
|
|
0
|
return( wantarray() ? () : undef() ) if( !%$ref ); |
|
|
0
|
|
|
|
|
|
1013
|
0
|
0
|
|
|
|
0
|
return( wantarray() ? %$ref : $ref ); |
1014
|
|
|
|
|
|
|
} |
1015
|
|
|
|
|
|
|
} |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
sub state(@) |
1018
|
|
|
|
|
|
|
{ |
1019
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1020
|
|
|
|
|
|
|
# $str = $h->state; |
1021
|
0
|
0
|
|
|
|
0
|
if( !ref( $self ) ) |
1022
|
|
|
|
|
|
|
{ |
1023
|
0
|
|
|
|
|
0
|
return( $DBI::state ); |
1024
|
|
|
|
|
|
|
} |
1025
|
|
|
|
|
|
|
else |
1026
|
|
|
|
|
|
|
{ |
1027
|
0
|
|
|
|
|
0
|
return( $self->SUPER::state() ); |
1028
|
|
|
|
|
|
|
} |
1029
|
|
|
|
|
|
|
} |
1030
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
sub supported_class |
1032
|
|
|
|
|
|
|
{ |
1033
|
1
|
|
|
1
|
1
|
4
|
my $self = shift( @_ ); |
1034
|
1
|
|
|
|
|
16
|
my @classes = values( %$DRIVER2PACK ); |
1035
|
1
|
|
|
|
|
6
|
return( @classes ); |
1036
|
|
|
|
|
|
|
} |
1037
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
sub supported_drivers |
1039
|
|
|
|
|
|
|
{ |
1040
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1041
|
0
|
|
|
|
|
0
|
my @drivers = keys( %$DRIVER2PACK ); |
1042
|
0
|
|
|
|
|
0
|
return( @drivers ); |
1043
|
|
|
|
|
|
|
} |
1044
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
sub table |
1046
|
|
|
|
|
|
|
{ |
1047
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1048
|
0
|
|
|
|
|
0
|
my $base_class = $self->base_class; |
1049
|
0
|
0
|
|
|
|
0
|
return( $self->error( "You must use the database object to access this method." ) ) if( ref( $self ) ne $base_class ); |
1050
|
0
|
|
0
|
|
|
0
|
my $table = shift( @_ ) || |
1051
|
|
|
|
|
|
|
return( $self->error( "You must provide a table name to access the table methods." ) ); |
1052
|
0
|
|
|
|
|
0
|
my $table_class = "${base_class}::Tables"; |
1053
|
0
|
0
|
|
|
|
0
|
$self->_load_class( $table_class ) || return( $self->pass_error ); |
1054
|
0
|
|
0
|
|
|
0
|
my $host = $self->{server} // ''; |
1055
|
0
|
|
0
|
|
|
0
|
my $db = $self->{database} // ''; |
1056
|
3
|
|
|
3
|
|
25
|
no strict 'refs'; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
3972
|
|
1057
|
0
|
|
|
|
|
0
|
my $cache_table = ${ $base_class . '::CACHE_TABLE' }; |
|
0
|
|
|
|
|
0
|
|
1058
|
0
|
0
|
|
|
|
0
|
return( $self->error( "CACHE_TABLE is not set in base class $base_class" ) ) if( !$self->_is_hash( $cache_table ) ); |
1059
|
0
|
0
|
|
|
|
0
|
$cache_table->{ "${host}:${db}" } = {} if( !CORE::exists( $cache_table->{ "${host}:${db}" } ) ); |
1060
|
0
|
|
|
|
|
0
|
my $tables = $cache_table->{ "${host}:${db}" }; |
1061
|
|
|
|
|
|
|
# my $tables = {}; |
1062
|
0
|
|
|
|
|
0
|
my $tbl = $tables->{ $table }; |
1063
|
0
|
0
|
|
|
|
0
|
if( !$tbl ) |
1064
|
|
|
|
|
|
|
{ |
1065
|
|
|
|
|
|
|
# Prepare what we want to share with DB::Object::Tables *before* creating the object |
1066
|
|
|
|
|
|
|
# Because, during DB::Object::Tables object initialization, 'dbh' is required |
1067
|
0
|
|
|
|
|
0
|
my $hash = {}; |
1068
|
|
|
|
|
|
|
# map{ $hash->{ $_ } = $self->{ $_ } } qw( dbh drh server login passwd database driver tables verbose debug bind cache params ); |
1069
|
|
|
|
|
|
|
# The database handler must be shared here because during the initiation process |
1070
|
0
|
|
|
|
|
0
|
my @new_keys = qw( dbh tables verbose debug bind cache params ); |
1071
|
0
|
|
|
|
|
0
|
@$hash{ @new_keys } = @$self{ @new_keys }; |
1072
|
0
|
|
|
|
|
0
|
$hash->{dbo} = $self; |
1073
|
0
|
|
0
|
|
|
0
|
$tbl = $table_class->new( $table, %$hash ) || return( $self->pass_error( $table_class->error ) ); |
1074
|
0
|
|
|
|
|
0
|
$tbl->reset; |
1075
|
|
|
|
|
|
|
# $tbl->_query_object_get_or_create; |
1076
|
|
|
|
|
|
|
# $tbl->_reset_query; |
1077
|
|
|
|
|
|
|
# TODO: Suspend caching. It creates segfault and I do not have time right now to deal with it. Putting it in the TODO |
1078
|
|
|
|
|
|
|
# $tables->{ $table } = $tbl; |
1079
|
|
|
|
|
|
|
} |
1080
|
|
|
|
|
|
|
else |
1081
|
|
|
|
|
|
|
{ |
1082
|
0
|
|
|
|
|
0
|
$tbl = $tbl->clone; |
1083
|
0
|
|
|
|
|
0
|
$tbl->debug( $self->debug ); |
1084
|
|
|
|
|
|
|
# INFO: Need to set the current dbo because in threaded environment, DBI will raise an error if we share dbh across threads |
1085
|
0
|
|
|
|
|
0
|
$tbl->database_object( $self ); |
1086
|
0
|
|
|
|
|
0
|
$tbl->reset; |
1087
|
|
|
|
|
|
|
} |
1088
|
0
|
|
|
|
|
0
|
$tbl->{dbo} = $self; |
1089
|
|
|
|
|
|
|
# $tbl->{drh} = $self->{drh}; |
1090
|
|
|
|
|
|
|
# We set debug and verbose again here in case it changed since the table object was instantiated |
1091
|
0
|
|
|
|
|
0
|
$tbl->{debug} = $self->{debug}; |
1092
|
0
|
|
|
|
|
0
|
$tbl->{verbose} = $self->{verbose}; |
1093
|
|
|
|
|
|
|
# $tbl->{bind} = $self->use_bind(); |
1094
|
|
|
|
|
|
|
# $tbl->{cache} = $self->use_cache(); |
1095
|
|
|
|
|
|
|
# $tbl->{enhance} = 1; |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
# $tbl->reset; |
1098
|
|
|
|
|
|
|
# $tbl->query_object->reset; |
1099
|
|
|
|
|
|
|
# $tbl->query_object->enhance(1); |
1100
|
0
|
|
|
|
|
0
|
return( $tbl ); |
1101
|
|
|
|
|
|
|
} |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
sub table_exists |
1104
|
|
|
|
|
|
|
{ |
1105
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1106
|
0
|
|
0
|
|
|
0
|
my $table = shift( @_ ) || |
1107
|
|
|
|
|
|
|
return( $self->error( "You must provide a table name to access the table methods." ) ); |
1108
|
0
|
|
|
|
|
0
|
my $cache_tables = $self->cache_tables; |
1109
|
0
|
|
|
|
|
0
|
my $tables_in_cache = $cache_tables->get({ |
1110
|
|
|
|
|
|
|
host => $self->host, |
1111
|
|
|
|
|
|
|
driver => $self->driver, |
1112
|
|
|
|
|
|
|
port => $self->port, |
1113
|
|
|
|
|
|
|
database => $self->database, |
1114
|
|
|
|
|
|
|
}); |
1115
|
0
|
|
|
|
|
0
|
foreach my $ref ( @$tables_in_cache ) |
1116
|
|
|
|
|
|
|
{ |
1117
|
0
|
0
|
|
|
|
0
|
return( 1 ) if( $ref->{name} eq $table ); |
1118
|
|
|
|
|
|
|
} |
1119
|
|
|
|
|
|
|
# We did not find it, so let's try by checking directly the database |
1120
|
0
|
|
0
|
|
|
0
|
my $def = $self->table_info( $table ) || return; |
1121
|
0
|
0
|
|
|
|
0
|
return( 0 ) if( !scalar( @$def ) ); |
1122
|
0
|
|
|
|
|
0
|
return( 1 ); |
1123
|
|
|
|
|
|
|
} |
1124
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
sub table_info |
1126
|
|
|
|
|
|
|
{ |
1127
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1128
|
0
|
|
|
|
|
0
|
return( $self->error( "table_info() has not been implemented by driver \"$self->{driver}\" (object = $self)." ) ); |
1129
|
|
|
|
|
|
|
} |
1130
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
sub table_push |
1132
|
|
|
|
|
|
|
{ |
1133
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1134
|
0
|
|
0
|
|
|
0
|
my $table = shift( @_ ) || return( $self->error( "No table provided to add to our cache." ) ); |
1135
|
0
|
|
0
|
|
|
0
|
my $def = $self->tables_info || return; |
1136
|
0
|
|
|
|
|
0
|
my $hash = |
1137
|
|
|
|
|
|
|
{ |
1138
|
|
|
|
|
|
|
host => $self->host, |
1139
|
|
|
|
|
|
|
driver => $self->driver, |
1140
|
|
|
|
|
|
|
port => $self->port, |
1141
|
|
|
|
|
|
|
database => $self->database, |
1142
|
|
|
|
|
|
|
tables => $def, |
1143
|
|
|
|
|
|
|
}; |
1144
|
0
|
|
|
|
|
0
|
my $cache_tables = $self->cache_tables; |
1145
|
0
|
0
|
|
|
|
0
|
if( !defined( $cache_tables->set( $hash ) ) ) |
1146
|
|
|
|
|
|
|
{ |
1147
|
0
|
|
|
|
|
0
|
return( $self->pass_error( $cache_tables->error ) ); |
1148
|
|
|
|
|
|
|
} |
1149
|
0
|
|
|
|
|
0
|
return( $table ); |
1150
|
|
|
|
|
|
|
} |
1151
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
sub tables |
1153
|
|
|
|
|
|
|
{ |
1154
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1155
|
0
|
|
0
|
|
|
0
|
my $db = shift( @_ ) || $self->database; |
1156
|
0
|
|
|
|
|
0
|
my $opts = {}; |
1157
|
0
|
0
|
0
|
|
|
0
|
$opts = pop( @_ ) if( @_ && $self->_is_hash( $_[-1] ) ); |
1158
|
0
|
0
|
|
|
|
0
|
$db = $opts->{database} if( $opts->{database} ); |
1159
|
0
|
|
|
|
|
0
|
my $all = []; |
1160
|
0
|
0
|
0
|
|
|
0
|
if( !$opts->{no_cache} && !$opts->{live} ) |
1161
|
|
|
|
|
|
|
{ |
1162
|
0
|
0
|
|
|
|
0
|
if( my $cache_tables = $self->cache_tables ) |
1163
|
|
|
|
|
|
|
{ |
1164
|
|
|
|
|
|
|
$all = $cache_tables->get({ |
1165
|
|
|
|
|
|
|
host => $self->host, |
1166
|
|
|
|
|
|
|
driver => $self->driver, |
1167
|
|
|
|
|
|
|
port => $self->port, |
1168
|
|
|
|
|
|
|
database => $db, |
1169
|
|
|
|
|
|
|
}) || do |
1170
|
0
|
|
0
|
|
|
0
|
{ |
1171
|
|
|
|
|
|
|
$self->error( "Warning only: an error occured while trying to fetch the tables cache for host '", $self->host, "', driver '", $self->driver, "', port '", $self->port, "' and database '", $self->database, "': ", $cache_tables->error, "\n" ); |
1172
|
|
|
|
|
|
|
}; |
1173
|
|
|
|
|
|
|
} |
1174
|
|
|
|
|
|
|
else |
1175
|
|
|
|
|
|
|
{ |
1176
|
0
|
|
|
|
|
0
|
$self->error( "Warning only: no cache tables object found in our self ($self)! Current keys are: '", join( "', '", sort( keys( %$self ) ) ), "'." ); |
1177
|
|
|
|
|
|
|
} |
1178
|
|
|
|
|
|
|
} |
1179
|
0
|
0
|
0
|
|
|
0
|
if( $opts->{no_cache} || $opts->{live} || !scalar( @$all ) ) |
|
|
|
0
|
|
|
|
|
1180
|
|
|
|
|
|
|
{ |
1181
|
0
|
|
0
|
|
|
0
|
$all = $self->tables_info || return; |
1182
|
|
|
|
|
|
|
} |
1183
|
0
|
|
|
|
|
0
|
my @tables = (); |
1184
|
0
|
0
|
|
|
|
0
|
@tables = map( $_->{name}, @$all ) if( scalar( @$all ) ); |
1185
|
|
|
|
|
|
|
# return( wantarray() ? () : [] ) if( !@tables ); |
1186
|
|
|
|
|
|
|
# return( wantarray() ? @tables : \@tables ); |
1187
|
0
|
|
|
|
|
0
|
return( \@tables ); |
1188
|
|
|
|
|
|
|
} |
1189
|
|
|
|
|
|
|
|
1190
|
|
|
|
|
|
|
sub tables_cache |
1191
|
|
|
|
|
|
|
{ |
1192
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1193
|
0
|
|
|
|
|
0
|
my $opts = {}; |
1194
|
0
|
0
|
0
|
|
|
0
|
$opts = shift( @_ ) if( @_ && $self->_is_hash( $_[0] ) ); |
1195
|
0
|
|
|
|
|
0
|
my $cache_tables = $self->cache_tables; |
1196
|
0
|
|
|
|
|
0
|
my $cache = $cache_tables->get({ |
1197
|
|
|
|
|
|
|
host => $self->host, |
1198
|
|
|
|
|
|
|
driver => $self->driver, |
1199
|
|
|
|
|
|
|
port => $self->port, |
1200
|
|
|
|
|
|
|
database => $self->database, |
1201
|
|
|
|
|
|
|
}); |
1202
|
0
|
|
|
|
|
0
|
return( $cache ); |
1203
|
|
|
|
|
|
|
} |
1204
|
|
|
|
|
|
|
|
1205
|
0
|
|
|
0
|
1
|
0
|
sub tables_info { return( shift->error( "tables_info() has not been implemented by driver." ) ); } |
1206
|
|
|
|
|
|
|
|
1207
|
|
|
|
|
|
|
sub tables_refresh |
1208
|
|
|
|
|
|
|
{ |
1209
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1210
|
0
|
|
0
|
|
|
0
|
my $db = shift( @_ ) || $self->database; |
1211
|
0
|
|
0
|
|
|
0
|
my $tables = $self->tables_info || return; |
1212
|
0
|
|
|
|
|
0
|
my $hash = |
1213
|
|
|
|
|
|
|
{ |
1214
|
|
|
|
|
|
|
host => $self->host, |
1215
|
|
|
|
|
|
|
driver => $self->driver, |
1216
|
|
|
|
|
|
|
port => $self->port, |
1217
|
|
|
|
|
|
|
database => $self->database, |
1218
|
|
|
|
|
|
|
tables => $tables, |
1219
|
|
|
|
|
|
|
}; |
1220
|
0
|
|
|
|
|
0
|
my $cache_tables = $self->cache_tables; |
1221
|
0
|
0
|
|
|
|
0
|
if( !defined( $cache_tables->set( $hash ) ) ) |
1222
|
|
|
|
|
|
|
{ |
1223
|
0
|
|
|
|
|
0
|
return( $self->pass_error( $cache_tables->error ) ); |
1224
|
|
|
|
|
|
|
} |
1225
|
0
|
0
|
|
|
|
0
|
return( wantarray() ? @$tables : $tables ); |
1226
|
|
|
|
|
|
|
} |
1227
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
# Used to flag this as a transaction when begin_work is triggered |
1229
|
0
|
|
|
0
|
1
|
0
|
sub transaction { return( shift->_set_get_boolean( 'transaction', @_ ) ); } |
1230
|
|
|
|
|
|
|
|
1231
|
0
|
|
|
0
|
1
|
0
|
sub TRUE { return( 'TRUE' ); } |
1232
|
|
|
|
|
|
|
|
1233
|
0
|
|
|
0
|
0
|
0
|
sub unknown_field { return( shift->_set_get_scalar( 'unknown_field', @_ ) ); } |
1234
|
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
sub unlock |
1236
|
|
|
|
|
|
|
{ |
1237
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1238
|
0
|
|
|
|
|
0
|
return( $self->error( "Method \"unlock\" has not been implemented by driver $self->{driver} (object $self)." ) ); |
1239
|
|
|
|
|
|
|
} |
1240
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
sub use |
1242
|
|
|
|
|
|
|
{ |
1243
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1244
|
0
|
|
|
|
|
0
|
my $base_class = $self->base_class; |
1245
|
0
|
0
|
|
|
|
0
|
return( $self->error( "You must use the the database object to switch database." ) ) if( ref( $self ) ne $base_class ); |
1246
|
0
|
|
|
|
|
0
|
my $db = shift( @_ ); |
1247
|
|
|
|
|
|
|
# No need to go further |
1248
|
0
|
0
|
|
|
|
0
|
return( $self ) if( $db eq $self->{database} ); |
1249
|
0
|
0
|
|
|
|
0
|
if( !@AVAILABLE_DATABASES ) |
1250
|
|
|
|
|
|
|
{ |
1251
|
0
|
|
|
|
|
0
|
@AVAILABLE_DATABASES = $self->databases(); |
1252
|
|
|
|
|
|
|
} |
1253
|
0
|
0
|
|
|
|
0
|
if( !scalar( grep{ /^$db$/ } @AVAILABLE_DATABASES ) ) |
|
0
|
|
|
|
|
0
|
|
1254
|
|
|
|
|
|
|
{ |
1255
|
0
|
|
|
|
|
0
|
return( $self->error( "The database '$db' does not exist." ) ); |
1256
|
|
|
|
|
|
|
} |
1257
|
0
|
|
0
|
|
|
0
|
my $dbh = $base_class->connect( $db ) || |
1258
|
|
|
|
|
|
|
return( $self->error( "Unable to connect to database '$db'." ) ); |
1259
|
0
|
|
|
|
|
0
|
$self->param( 'multi_db' => 1 ); |
1260
|
0
|
|
|
|
|
0
|
$dbh->param( 'multi_db' => 1 ); |
1261
|
0
|
|
|
|
|
0
|
return( $dbh ); |
1262
|
|
|
|
|
|
|
} |
1263
|
|
|
|
|
|
|
|
1264
|
0
|
|
|
0
|
1
|
0
|
sub use_cache { return( shift->_set_get_boolean( 'cache', @_ ) ) } |
1265
|
|
|
|
|
|
|
|
1266
|
0
|
|
|
0
|
1
|
0
|
sub use_bind { return( shift->_set_get_boolean( 'bind', @_ ) ) } |
1267
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
sub variables |
1269
|
|
|
|
|
|
|
{ |
1270
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1271
|
0
|
|
|
|
|
0
|
my $type = shift( @_ ); |
1272
|
0
|
0
|
|
|
|
0
|
$self->error( "Variable '$type' is a read-only value." ) if( @_ ); |
1273
|
0
|
|
0
|
|
|
0
|
my $vars = $self->{variables} ||= {}; |
1274
|
0
|
0
|
|
|
|
0
|
if( !%$vars ) |
1275
|
|
|
|
|
|
|
{ |
1276
|
0
|
|
0
|
|
|
0
|
my $sth = $self->prepare( "SHOW VARIABLES" ) || |
1277
|
|
|
|
|
|
|
return( $self->error( "SHOW VARIABLES is not supported." ) ); |
1278
|
0
|
|
|
|
|
0
|
$sth->execute(); |
1279
|
0
|
|
|
|
|
0
|
my $ref = $self->fetchall_arrayref(); |
1280
|
0
|
|
|
|
|
0
|
my %vars = map{ lc( $_->[ 0 ] ) => $_->[ 1 ] } @$ref; |
|
0
|
|
|
|
|
0
|
|
1281
|
0
|
0
|
|
|
|
0
|
$vars = \%vars if( %vars ); |
1282
|
0
|
|
|
|
|
0
|
$sth->finish(); |
1283
|
|
|
|
|
|
|
} |
1284
|
0
|
|
|
|
|
0
|
my @found = grep{ /$type/i } keys( %$vars ); |
|
0
|
|
|
|
|
0
|
|
1285
|
0
|
0
|
|
|
|
0
|
return( '' ) if( !scalar( @found ) ); |
1286
|
0
|
|
|
|
|
0
|
return( $vars->{ $found[ 0 ] } ); |
1287
|
|
|
|
|
|
|
} |
1288
|
|
|
|
|
|
|
|
1289
|
|
|
|
|
|
|
sub version |
1290
|
|
|
|
|
|
|
{ |
1291
|
0
|
|
|
0
|
1
|
0
|
return( shift->error( "This driver has not set the version() method." ) ); |
1292
|
|
|
|
|
|
|
} |
1293
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
sub _cache_queries |
1295
|
|
|
|
|
|
|
{ |
1296
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1297
|
0
|
|
|
|
|
0
|
my $base_class = $self->base_class; |
1298
|
|
|
|
|
|
|
# DB::Object::CACHE_QUERIES, DB::Object::Postgres::CACHE_QUERIES, etc |
1299
|
3
|
|
|
3
|
|
23
|
no strict 'refs'; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
9233
|
|
1300
|
0
|
|
|
|
|
0
|
my $cachedb = ${"${base_class}\::CACHE_QUERIES"}; |
|
0
|
|
|
|
|
0
|
|
1301
|
0
|
|
|
|
|
0
|
return( $cachedb ); |
1302
|
|
|
|
|
|
|
} |
1303
|
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
sub _cache_this |
1305
|
|
|
|
|
|
|
{ |
1306
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1307
|
|
|
|
|
|
|
# When this method is accessed by method from package DB::Object::Statement, they CAN NOT |
1308
|
|
|
|
|
|
|
# implicitly passed the statement string or they would risk to modify the previous stored |
1309
|
|
|
|
|
|
|
# query object they represent. |
1310
|
|
|
|
|
|
|
# For instance: |
1311
|
|
|
|
|
|
|
# $obj->select->join( 'some_table', { 'parameter', 'list' } )->fetchrow_hashref() |
1312
|
|
|
|
|
|
|
# here the first query is prepared and cached and its resulting object is passed on to join |
1313
|
|
|
|
|
|
|
# here join will rebuild the query, but will search first if there was one already cached |
1314
|
|
|
|
|
|
|
# if join passes implictly the statement string, this means it will modify the cached query select() |
1315
|
|
|
|
|
|
|
# has just previously stored... This is why method such as join must pass explicitly the query string |
1316
|
0
|
|
|
|
|
0
|
my $q = shift( @_ ); |
1317
|
0
|
0
|
0
|
|
|
0
|
my $query = ( ref( $q ) && $q->isa( 'DB::Object::Query' ) ) ? $q->as_string : $q; |
1318
|
0
|
|
|
|
|
0
|
my $base_class = $self->base_class; |
1319
|
0
|
|
|
|
|
0
|
my $cache = $self->{cache}; |
1320
|
0
|
|
|
|
|
0
|
my $bind = $self->{bind}; |
1321
|
0
|
|
|
|
|
0
|
my $queries = ''; |
1322
|
0
|
|
|
|
|
0
|
my @saved = (); |
1323
|
|
|
|
|
|
|
# my $cachedb = ${"${base_class}\::CACHE_QUERIES"}; |
1324
|
0
|
|
|
|
|
0
|
my $cachedb = $self->_cache_queries; |
1325
|
0
|
0
|
|
|
|
0
|
return( $self->error( "CACHE_QUERIES is not set in class $base_class" ) ) if( !$self->_is_array( $cachedb ) ); |
1326
|
0
|
|
|
|
|
0
|
my $cache_size = scalar( @$cachedb ); |
1327
|
0
|
|
|
|
|
0
|
my $cached_sth = ''; |
1328
|
|
|
|
|
|
|
# If database object exists, this means this is a DB::Object::Tables object, otherwise a DB::Object object |
1329
|
|
|
|
|
|
|
# my $dbo = $self->{ 'dbo' } || $self; |
1330
|
0
|
0
|
|
|
|
0
|
if( $cache ) |
1331
|
|
|
|
|
|
|
{ |
1332
|
0
|
0
|
0
|
|
|
0
|
if( $CACHE_SIZE > 0 && $cache_size > $CACHE_SIZE ) |
1333
|
|
|
|
|
|
|
{ |
1334
|
|
|
|
|
|
|
# Take 20% off of the cache |
1335
|
0
|
|
|
|
|
0
|
my $truncate_limit = int( ( $cache_size * 20 ) / 100 ); |
1336
|
0
|
|
|
|
|
0
|
splice( @$cachedb, ( $cache_size - $truncate_limit ) ); |
1337
|
|
|
|
|
|
|
} |
1338
|
0
|
|
|
|
|
0
|
foreach my $obj ( @$cachedb ) |
1339
|
|
|
|
|
|
|
{ |
1340
|
|
|
|
|
|
|
# print( STDERR ref( $self ) . "::_cache_this(): Is query:\n\t'$query'\nthe same than:\n\t'$obj->{ 'query' }'\n" ); |
1341
|
0
|
0
|
0
|
|
|
0
|
if( $query && $obj->{query} && $obj->{query} eq $query ) |
|
|
|
0
|
|
|
|
|
1342
|
|
|
|
|
|
|
{ |
1343
|
0
|
|
|
|
|
0
|
$cached_sth = $obj; |
1344
|
0
|
|
|
|
|
0
|
last; |
1345
|
|
|
|
|
|
|
} |
1346
|
|
|
|
|
|
|
} |
1347
|
|
|
|
|
|
|
} |
1348
|
0
|
|
|
|
|
0
|
my $sth = ''; |
1349
|
|
|
|
|
|
|
# We found a previous query exactly the same |
1350
|
0
|
0
|
|
|
|
0
|
if( $cached_sth ) |
1351
|
|
|
|
|
|
|
{ |
1352
|
0
|
|
|
|
|
0
|
my $data = { sth => $cached_sth->{sth}, query => $cached_sth->{query} }; |
1353
|
|
|
|
|
|
|
# This is an inner package |
1354
|
0
|
|
|
|
|
0
|
$sth = $self->_make_sth( "${base_class}::Statement", $data ); |
1355
|
|
|
|
|
|
|
} |
1356
|
|
|
|
|
|
|
else |
1357
|
|
|
|
|
|
|
{ |
1358
|
|
|
|
|
|
|
# Maybe we ought to write: |
1359
|
|
|
|
|
|
|
# $prepare = $cache ? \&prepare_cached : \prepare; |
1360
|
|
|
|
|
|
|
# $sth = $prepare->( $self, $self->{ 'query' } ) || |
1361
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
# $sth = $self->prepare_cached( $query ) || |
1363
|
0
|
|
|
|
|
0
|
my $prepare_options = {}; |
1364
|
0
|
0
|
0
|
|
|
0
|
if( $q && $self->_is_a( $q, 'DB::Object::Query' ) ) |
1365
|
|
|
|
|
|
|
{ |
1366
|
0
|
|
|
|
|
0
|
$prepare_options = $q->prepare_options->as_hash; |
1367
|
|
|
|
|
|
|
} |
1368
|
0
|
0
|
|
|
|
0
|
if( scalar( keys( %$prepare_options ) ) ) |
1369
|
|
|
|
|
|
|
{ |
1370
|
|
|
|
|
|
|
$sth = $self->prepare( $query, $prepare_options ) || do |
1371
|
0
|
|
0
|
|
|
0
|
{ |
1372
|
|
|
|
|
|
|
return; |
1373
|
|
|
|
|
|
|
}; |
1374
|
|
|
|
|
|
|
} |
1375
|
|
|
|
|
|
|
else |
1376
|
|
|
|
|
|
|
{ |
1377
|
|
|
|
|
|
|
$sth = $self->prepare( $query ) || do |
1378
|
0
|
|
0
|
|
|
0
|
{ |
1379
|
|
|
|
|
|
|
return; |
1380
|
|
|
|
|
|
|
}; |
1381
|
|
|
|
|
|
|
} |
1382
|
|
|
|
|
|
|
# $sth = $self->prepare( $self->{ 'query' } ) || |
1383
|
|
|
|
|
|
|
# return( $self->error( "Error while preparing the query on table '$self->{ 'table' }':\n$self->{ 'query' }\n", $self->errstr() ) ); |
1384
|
|
|
|
|
|
|
# Let the proper method set its error text |
1385
|
|
|
|
|
|
|
# If caching of queries is turned on, cache the request |
1386
|
0
|
0
|
|
|
|
0
|
if( $cache ) |
|
|
0
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
{ |
1388
|
0
|
|
|
|
|
0
|
unshift( @$cachedb, $sth ); |
1389
|
|
|
|
|
|
|
} |
1390
|
|
|
|
|
|
|
# If caching is off, but the query is a binded parameters' one, |
1391
|
|
|
|
|
|
|
# make the current object hold the statement object |
1392
|
|
|
|
|
|
|
elsif( $bind ) |
1393
|
|
|
|
|
|
|
{ |
1394
|
0
|
|
|
|
|
0
|
$self->{sth} = $sth; |
1395
|
|
|
|
|
|
|
} |
1396
|
|
|
|
|
|
|
} |
1397
|
|
|
|
|
|
|
#$sth->{query_object} = ( ref( $q ) && $q->isa( 'DB::Object::Query' ) ) ? $q : ''; |
1398
|
0
|
0
|
|
|
|
0
|
$sth->query_object( $q ) if( $self->_is_a( $q, 'DB::Object::Query' ) ); |
1399
|
|
|
|
|
|
|
# print( STDERR ref( $self ) . "::_cache_this(): prepared statement was ", $cached_sth ? 'cached' : 'not cached.', "\n" ); |
1400
|
|
|
|
|
|
|
# Caching the query as a constant |
1401
|
0
|
0
|
0
|
|
|
0
|
if( $q && $self->_is_object( $q ) && $q->isa( 'DB::Object::Query' ) ) |
|
|
|
0
|
|
|
|
|
1402
|
|
|
|
|
|
|
{ |
1403
|
0
|
|
|
|
|
0
|
my $constant = $q->constant; |
1404
|
0
|
0
|
|
|
|
0
|
if( scalar( keys( %$constant ) ) ) |
1405
|
|
|
|
|
|
|
{ |
1406
|
0
|
|
|
|
|
0
|
foreach my $k (qw( pack file line )) |
1407
|
|
|
|
|
|
|
{ |
1408
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Could not find the parameter \"$k\" in the constant query hash reference." ) ) if( !$constant->{ $k } ); |
1409
|
|
|
|
|
|
|
} |
1410
|
0
|
|
|
|
|
0
|
$constant->{query_object} = $q; |
1411
|
0
|
|
|
|
|
0
|
$self->constant_queries_cache_set( $constant ); |
1412
|
|
|
|
|
|
|
} |
1413
|
|
|
|
|
|
|
} |
1414
|
0
|
|
|
|
|
0
|
return( $sth ); |
1415
|
|
|
|
|
|
|
} |
1416
|
|
|
|
|
|
|
|
1417
|
|
|
|
|
|
|
sub _check_connect_param |
1418
|
|
|
|
|
|
|
{ |
1419
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1420
|
0
|
|
|
|
|
0
|
my $param = shift( @_ ); |
1421
|
|
|
|
|
|
|
# my @valid = qw( db login passwd host driver database server debug ); |
1422
|
0
|
|
|
|
|
0
|
my $valid = $self->_connection_parameters( $param ); |
1423
|
0
|
|
|
|
|
0
|
my $opts = $self->_connection_options( $param ); |
1424
|
0
|
|
|
|
|
0
|
foreach my $k ( keys( %$param ) ) |
1425
|
|
|
|
|
|
|
{ |
1426
|
|
|
|
|
|
|
# If it is not in the list and it does not start with an upper case; those are like RaiseError, AutoCommit, etc |
1427
|
0
|
0
|
0
|
|
|
0
|
if( CORE::length( $param->{ $k } ) && !grep( /^$k$/, @$valid ) && !CORE::exists( $opts->{ $k } ) ) |
|
|
|
0
|
|
|
|
|
1428
|
|
|
|
|
|
|
{ |
1429
|
0
|
|
|
|
|
0
|
return( $self->error( "Invalid parameter '$k'." ) ); |
1430
|
|
|
|
|
|
|
} |
1431
|
|
|
|
|
|
|
} |
1432
|
0
|
|
|
|
|
0
|
my @opts_to_remove = keys( %$opts ); |
1433
|
0
|
0
|
|
|
|
0
|
CORE::delete( @$param{ @opts_to_remove } ) if( scalar( @opts_to_remove ) ); |
1434
|
0
|
|
|
|
|
0
|
$param->{opt} = $opts; |
1435
|
0
|
0
|
0
|
|
|
0
|
$param->{database} = CORE::delete( $param->{db} ) if( !length( $param->{database} ) && $param->{db} ); |
1436
|
0
|
|
|
|
|
0
|
return( $param ); |
1437
|
|
|
|
|
|
|
} |
1438
|
|
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
sub _check_default_option |
1440
|
|
|
|
|
|
|
{ |
1441
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1442
|
0
|
|
|
|
|
0
|
my $opts = $self->_get_args_as_hash( @_ ); |
1443
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Provided option is not a hash reference." ) ) if( !$self->_is_hash( $opts ) ); |
1444
|
|
|
|
|
|
|
# This method should be superseded by an inherited class |
1445
|
0
|
|
|
|
|
0
|
return( $opts ); |
1446
|
|
|
|
|
|
|
} |
1447
|
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
sub _connection_options |
1449
|
|
|
|
|
|
|
{ |
1450
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1451
|
0
|
|
|
|
|
0
|
my $param = shift( @_ ); |
1452
|
0
|
|
|
|
|
0
|
my @dbi_opts = grep( /^[A-Z][a-zA-Z]+/, keys( %$param ) ); |
1453
|
0
|
|
|
|
|
0
|
my $opt = {}; |
1454
|
0
|
0
|
0
|
|
|
0
|
$opt = CORE::delete( $param->{opt} ) if( $param->{opt} && $self->_is_hash( $param->{opt} ) ); |
1455
|
0
|
|
|
|
|
0
|
@$opt{ @dbi_opts } = @$param{ @dbi_opts }; |
1456
|
0
|
|
|
|
|
0
|
return( $opt ); |
1457
|
|
|
|
|
|
|
} |
1458
|
|
|
|
|
|
|
|
1459
|
|
|
|
|
|
|
sub _connection_parameters |
1460
|
|
|
|
|
|
|
{ |
1461
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1462
|
0
|
|
|
|
|
0
|
my $param = shift( @_ ); |
1463
|
0
|
|
|
|
|
0
|
return( [qw( db login passwd host port driver database server opt uri debug cache_connections unknown_field )] ); |
1464
|
|
|
|
|
|
|
} |
1465
|
|
|
|
|
|
|
|
1466
|
|
|
|
|
|
|
sub _connection_params2hash |
1467
|
|
|
|
|
|
|
{ |
1468
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1469
|
0
|
|
|
|
|
0
|
my $param = {}; |
1470
|
0
|
0
|
|
|
|
0
|
if( !( @_ % 2 ) ) |
|
|
0
|
|
|
|
|
|
1471
|
|
|
|
|
|
|
{ |
1472
|
0
|
|
|
|
|
0
|
$param = { @_ }; |
1473
|
|
|
|
|
|
|
} |
1474
|
|
|
|
|
|
|
elsif( ref( $_[ 0 ] ) eq 'HASH' ) |
1475
|
|
|
|
|
|
|
{ |
1476
|
0
|
|
|
|
|
0
|
$param = shift( @_ ); |
1477
|
|
|
|
|
|
|
} |
1478
|
|
|
|
|
|
|
else |
1479
|
|
|
|
|
|
|
{ |
1480
|
0
|
|
|
|
|
0
|
my @keys = qw( database login passwd host driver schema ); |
1481
|
|
|
|
|
|
|
# Only add in the $param hash the keys value we were given, so we don't create keys entry when not needed |
1482
|
0
|
|
|
|
|
0
|
for( my $i = 0; $i < scalar( @_ ); $i++ ) |
1483
|
|
|
|
|
|
|
{ |
1484
|
0
|
|
|
|
|
0
|
$param->{ $keys[ $i ] } = $_[ $i ]; |
1485
|
|
|
|
|
|
|
} |
1486
|
|
|
|
|
|
|
} |
1487
|
|
|
|
|
|
|
|
1488
|
0
|
|
|
|
|
0
|
my $equi = |
1489
|
|
|
|
|
|
|
{ |
1490
|
|
|
|
|
|
|
database => 'DB_NAME', |
1491
|
|
|
|
|
|
|
login => 'DB_LOGIN', |
1492
|
|
|
|
|
|
|
passwd => 'DB_PASSWD', |
1493
|
|
|
|
|
|
|
host => 'DB_HOST', |
1494
|
|
|
|
|
|
|
port => 'DB_PORT', |
1495
|
|
|
|
|
|
|
driver => 'DB_DRIVER', |
1496
|
|
|
|
|
|
|
schema => 'DB_SCHEMA', |
1497
|
|
|
|
|
|
|
}; |
1498
|
0
|
|
|
|
|
0
|
foreach my $prop ( keys( %$equi ) ) |
1499
|
|
|
|
|
|
|
{ |
1500
|
0
|
0
|
0
|
|
|
0
|
$param->{ $prop } = $ENV{ $equi->{ $prop } } if( $ENV{ $equi->{ $prop } } && !length( $param->{ $prop } ) ); |
1501
|
|
|
|
|
|
|
} |
1502
|
|
|
|
|
|
|
|
1503
|
|
|
|
|
|
|
# A simple json file |
1504
|
|
|
|
|
|
|
# An URI coul be http://localhost:5432?database=somedb etc... |
1505
|
|
|
|
|
|
|
# or it could also be file:/foo/bar?opt={"RaiseError":true} |
1506
|
0
|
0
|
0
|
|
|
0
|
if( $param->{uri} || $ENV{DB_CON_URI} ) |
1507
|
|
|
|
|
|
|
{ |
1508
|
0
|
|
|
|
|
0
|
my $uri; |
1509
|
|
|
|
|
|
|
eval |
1510
|
0
|
|
|
|
|
0
|
{ |
1511
|
0
|
|
|
|
|
0
|
require URI; |
1512
|
0
|
|
0
|
|
|
0
|
$uri = URI->new( $param->{uri} || $ENV{DB_CON_URI} ); |
1513
|
|
|
|
|
|
|
}; |
1514
|
0
|
0
|
0
|
|
|
0
|
if( !$@ && $uri ) |
1515
|
|
|
|
|
|
|
{ |
1516
|
|
|
|
|
|
|
# Make sure our parameter is a valid URI object |
1517
|
0
|
|
|
|
|
0
|
$param->{uri} = $uri; |
1518
|
0
|
0
|
|
|
|
0
|
if( $uri->can( 'port' ) ) |
|
|
0
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
{ |
1520
|
0
|
|
|
|
|
0
|
$param->{host} = $uri->host; |
1521
|
0
|
0
|
|
|
|
0
|
$param->{port} = $uri->port if( $uri->port ); |
1522
|
|
|
|
|
|
|
} |
1523
|
|
|
|
|
|
|
# file:/ |
1524
|
|
|
|
|
|
|
elsif( length( $uri->path ) ) |
1525
|
|
|
|
|
|
|
{ |
1526
|
0
|
|
|
|
|
0
|
$param->{database} = ( $uri->path_segments )[-1]; |
1527
|
|
|
|
|
|
|
} |
1528
|
0
|
|
|
|
|
0
|
my( %q ) = $uri->query_form; |
1529
|
0
|
0
|
|
|
|
0
|
$param->{host} = $q{host} if( $q{host} ); |
1530
|
0
|
0
|
|
|
|
0
|
$param->{port} = $q{port} if( $q{port} ); |
1531
|
0
|
0
|
|
|
|
0
|
$param->{database} = $q{database} if( $q{database} ); |
1532
|
0
|
0
|
|
|
|
0
|
$param->{schema} = $q{schema} if( $q{schema} ); |
1533
|
0
|
0
|
|
|
|
0
|
$param->{user} = $q{user} if( $q{user} ); |
1534
|
0
|
0
|
|
|
|
0
|
$param->{login} = $q{login} if( $q{login} ); |
1535
|
0
|
0
|
|
|
|
0
|
$param->{password} = $q{password} if( $q{password} ); |
1536
|
0
|
0
|
|
|
|
0
|
$param->{opt} = $q{opt} if( $q{opt} ); |
1537
|
0
|
0
|
0
|
|
|
0
|
$param->{login} = CORE::delete( $param->{user} ) if( !$param->{login} && $param->{user} ); |
1538
|
0
|
0
|
|
|
|
0
|
if( $q{opt} ) |
1539
|
|
|
|
|
|
|
{ |
1540
|
0
|
|
|
|
|
0
|
my $jdata = {}; |
1541
|
|
|
|
|
|
|
eval |
1542
|
0
|
|
|
|
|
0
|
{ |
1543
|
0
|
|
|
|
|
0
|
require JSON; |
1544
|
0
|
0
|
|
|
|
0
|
if( defined( *{ "JSON::" } ) ) |
|
0
|
|
|
|
|
0
|
|
1545
|
|
|
|
|
|
|
{ |
1546
|
0
|
|
|
|
|
0
|
my $j = JSON->new->allow_nonref; |
1547
|
0
|
|
|
|
|
0
|
$jdata = $j->decode( $q{opt} ); |
1548
|
|
|
|
|
|
|
} |
1549
|
|
|
|
|
|
|
}; |
1550
|
0
|
0
|
|
|
|
0
|
if( $@ ) |
1551
|
|
|
|
|
|
|
{ |
1552
|
0
|
|
|
|
|
0
|
warn( "Found the database connection opt parameter provided in the connection uri \"$uri\", but could not decode its json value: $@\n" ); |
1553
|
|
|
|
|
|
|
} |
1554
|
0
|
0
|
|
|
|
0
|
$param->{opt} = $jdata if( scalar( keys( %$jdata ) ) ); |
1555
|
|
|
|
|
|
|
} |
1556
|
|
|
|
|
|
|
} |
1557
|
|
|
|
|
|
|
} |
1558
|
|
|
|
|
|
|
|
1559
|
0
|
0
|
0
|
|
|
0
|
if( $param->{conf_file} || $param->{config_file} || $ENV{DB_CON_FILE} ) |
|
|
|
0
|
|
|
|
|
1560
|
|
|
|
|
|
|
{ |
1561
|
0
|
|
0
|
|
|
0
|
my $db_con_file = $self->new_file( CORE::delete( $param->{conf_file} ) || CORE::delete( $param->{config_file} ) || $ENV{DB_CON_FILE} ); |
1562
|
0
|
|
|
|
|
0
|
my $db_con_file_ok = 0; |
1563
|
0
|
0
|
|
|
|
0
|
if( !$db_con_file->exists ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1564
|
|
|
|
|
|
|
{ |
1565
|
0
|
|
|
|
|
0
|
warn( "Database connection parameter file \"$db_con_file\" was provided but does not exist.\n" ); |
1566
|
|
|
|
|
|
|
} |
1567
|
|
|
|
|
|
|
elsif( $db_con_file->is_empty ) |
1568
|
|
|
|
|
|
|
{ |
1569
|
0
|
|
|
|
|
0
|
warn( "Database connection parameter file \"$db_con_file\" was provided but the file is empty.\n" ); |
1570
|
|
|
|
|
|
|
} |
1571
|
|
|
|
|
|
|
elsif( !$db_con_file->can_read ) |
1572
|
|
|
|
|
|
|
{ |
1573
|
0
|
|
|
|
|
0
|
warn( "Database connection parameter file \"$db_con_file\" was provided but the file lacks privileges to be read.\n" ); |
1574
|
|
|
|
|
|
|
} |
1575
|
|
|
|
|
|
|
else |
1576
|
|
|
|
|
|
|
{ |
1577
|
0
|
|
|
|
|
0
|
$db_con_file_ok++; |
1578
|
|
|
|
|
|
|
} |
1579
|
|
|
|
|
|
|
|
1580
|
0
|
|
|
|
|
0
|
my $json = {}; |
1581
|
|
|
|
|
|
|
eval |
1582
|
0
|
|
|
|
|
0
|
{ |
1583
|
0
|
|
|
|
|
0
|
require JSON; |
1584
|
0
|
0
|
|
|
|
0
|
if( defined( *{ "JSON::" } ) ) |
|
0
|
|
|
|
|
0
|
|
1585
|
|
|
|
|
|
|
{ |
1586
|
0
|
|
|
|
|
0
|
my $j = JSON->new->allow_nonref; |
1587
|
0
|
0
|
|
|
|
0
|
if( my $io = $db_con_file->open_utf8( '<' ) ) |
1588
|
|
|
|
|
|
|
{ |
1589
|
0
|
|
|
|
|
0
|
my $data = $db_con_file->load; |
1590
|
0
|
|
|
|
|
0
|
$json = $j->decode( $data ); |
1591
|
|
|
|
|
|
|
} |
1592
|
|
|
|
|
|
|
else |
1593
|
|
|
|
|
|
|
{ |
1594
|
0
|
|
|
|
|
0
|
warn( "Unable to open database connection parameter file \"$db_con_file\": $!\n" ); |
1595
|
|
|
|
|
|
|
} |
1596
|
|
|
|
|
|
|
} |
1597
|
|
|
|
|
|
|
}; |
1598
|
0
|
0
|
|
|
|
0
|
if( $@ ) |
1599
|
|
|
|
|
|
|
{ |
1600
|
0
|
|
|
|
|
0
|
warn( "Database connection parameter file \"$db_con_file\" was provided, but I encountered the following error while trying to read its json data: $@\n" ); |
1601
|
|
|
|
|
|
|
} |
1602
|
0
|
0
|
|
|
|
0
|
$json = {} if( !$self->_is_hash( $json ) ); |
1603
|
0
|
|
|
|
|
0
|
my $ref = {}; |
1604
|
0
|
0
|
|
|
|
0
|
if( exists( $json->{databases} ) ) |
1605
|
|
|
|
|
|
|
{ |
1606
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Found a property 'databases' in the connections configuration file \"$db_con_file\". I was expecting this property to be an array reference and instead I found this: '$json->{databases}'" ) ) if( !$self->_is_array( $json->{databases} ) ); |
1607
|
|
|
|
|
|
|
# When called from sub classes, this is set |
1608
|
0
|
|
|
|
|
0
|
my $driver = $self->driver; |
1609
|
|
|
|
|
|
|
# We take the first one matching our driver if any, or else we just take the first one |
1610
|
0
|
|
|
|
|
0
|
foreach my $this ( @{$json->{databases}} ) |
|
0
|
|
|
|
|
0
|
|
1611
|
|
|
|
|
|
|
{ |
1612
|
0
|
0
|
0
|
|
|
0
|
if( !$param->{database} && ( !$driver || $this->{driver} eq $driver ) ) |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1613
|
|
|
|
|
|
|
{ |
1614
|
0
|
|
|
|
|
0
|
$ref = $this; |
1615
|
0
|
|
|
|
|
0
|
last; |
1616
|
|
|
|
|
|
|
} |
1617
|
|
|
|
|
|
|
elsif( $param->{database} && $this->{database} eq $param->{database} && |
1618
|
|
|
|
|
|
|
( !$param->{host} || $param->{host} eq $this->{host} ) && |
1619
|
|
|
|
|
|
|
( !$param->{port} || $param->{port} eq $this->{port} ) ) |
1620
|
|
|
|
|
|
|
{ |
1621
|
0
|
|
|
|
|
0
|
$ref = $this; |
1622
|
0
|
|
|
|
|
0
|
last; |
1623
|
|
|
|
|
|
|
} |
1624
|
|
|
|
|
|
|
} |
1625
|
|
|
|
|
|
|
} |
1626
|
|
|
|
|
|
|
else |
1627
|
|
|
|
|
|
|
{ |
1628
|
0
|
|
|
|
|
0
|
$ref = $json; |
1629
|
|
|
|
|
|
|
} |
1630
|
0
|
0
|
|
|
|
0
|
if( scalar( keys( %$ref ) ) ) |
1631
|
|
|
|
|
|
|
{ |
1632
|
0
|
|
|
|
|
0
|
foreach my $k ( qw( database login passwd host port driver schema opt ) ) |
1633
|
|
|
|
|
|
|
{ |
1634
|
0
|
0
|
0
|
|
|
0
|
$param->{ $k } = $ref->{ $k } if( !length( $param->{ $k } ) && length( $ref->{ $k } ) ); |
1635
|
|
|
|
|
|
|
} |
1636
|
|
|
|
|
|
|
} |
1637
|
|
|
|
|
|
|
} |
1638
|
0
|
0
|
0
|
|
|
0
|
if( CORE::exists( $param->{host} ) && index( $param->{host}, ':' ) != -1 ) |
1639
|
|
|
|
|
|
|
{ |
1640
|
0
|
|
|
|
|
0
|
@$param{ qw( host port ) } = split( /:/, $param->{host}, 2 ); |
1641
|
|
|
|
|
|
|
} |
1642
|
|
|
|
|
|
|
|
1643
|
0
|
0
|
0
|
|
|
0
|
if( !$param->{opt} && $ENV{DB_OPT} ) |
1644
|
|
|
|
|
|
|
{ |
1645
|
0
|
|
|
|
|
0
|
my $jdata = {}; |
1646
|
|
|
|
|
|
|
eval |
1647
|
0
|
|
|
|
|
0
|
{ |
1648
|
0
|
|
|
|
|
0
|
require JSON; |
1649
|
0
|
0
|
|
|
|
0
|
if( defined( *{ "JSON::" } ) ) |
|
0
|
|
|
|
|
0
|
|
1650
|
|
|
|
|
|
|
{ |
1651
|
0
|
|
|
|
|
0
|
my $j = JSON->new->allow_nonref; |
1652
|
0
|
|
|
|
|
0
|
$jdata = $j->decode( $ENV{DB_OPT} ); |
1653
|
|
|
|
|
|
|
} |
1654
|
|
|
|
|
|
|
}; |
1655
|
0
|
0
|
|
|
|
0
|
if( $@ ) |
1656
|
|
|
|
|
|
|
{ |
1657
|
0
|
|
|
|
|
0
|
warn( "Found the database connection opt parameter provided in the envionment variable DB_OPT, but could not decode its json value: $@\n" ); |
1658
|
|
|
|
|
|
|
} |
1659
|
0
|
0
|
|
|
|
0
|
$param->{opt} = $jdata if( scalar( keys( %$jdata ) ) ); |
1660
|
|
|
|
|
|
|
} |
1661
|
0
|
|
|
|
|
0
|
return( $param ); |
1662
|
|
|
|
|
|
|
} |
1663
|
|
|
|
|
|
|
|
1664
|
|
|
|
|
|
|
sub _clean_statement |
1665
|
|
|
|
|
|
|
{ |
1666
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1667
|
0
|
|
|
|
|
0
|
my $data = shift( @_ ); |
1668
|
0
|
0
|
|
|
|
0
|
my $query = ref( $data ) ? $data : \$data; |
1669
|
0
|
|
|
|
|
0
|
$$query = CORE::join( "\n", map{ s/^\s+|\s+$//gs; $_ } split( /\n/, $$query ) ); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1670
|
0
|
0
|
|
|
|
0
|
return( $$query ) if( !ref( $data ) ); |
1671
|
|
|
|
|
|
|
} |
1672
|
|
|
|
|
|
|
|
1673
|
|
|
|
|
|
|
sub _convert_datetime2object |
1674
|
|
|
|
|
|
|
{ |
1675
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1676
|
0
|
|
|
|
|
0
|
my $opts = $self->_get_args_as_hash( @_ ); |
1677
|
0
|
|
|
|
|
0
|
return( $opts->{data} ); |
1678
|
|
|
|
|
|
|
} |
1679
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
# Does nothing by default |
1681
|
|
|
|
|
|
|
# Must be superseded by the subclasses because we use the data types like PG_JSON, PG_JSONB |
1682
|
|
|
|
|
|
|
# and we don't have them at this top level |
1683
|
|
|
|
|
|
|
sub _convert_json2hash |
1684
|
|
|
|
|
|
|
{ |
1685
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1686
|
0
|
|
|
|
|
0
|
my $opts = $self->_get_args_as_hash( @_ ); |
1687
|
0
|
|
|
|
|
0
|
return( $opts->{data} ); |
1688
|
|
|
|
|
|
|
} |
1689
|
|
|
|
|
|
|
|
1690
|
|
|
|
|
|
|
sub _dbi_connect |
1691
|
|
|
|
|
|
|
{ |
1692
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1693
|
0
|
|
|
|
|
0
|
my $dbh; |
1694
|
0
|
|
|
|
|
0
|
my $dsn = $self->_dsn; |
1695
|
|
|
|
|
|
|
# print( STDERR ref( $self ) . "::_dbi_connect() Options are: ", $self->dumper( $self->{opt} ), "\n" ); |
1696
|
0
|
0
|
|
|
|
0
|
if( $self->{cache_connections} ) |
1697
|
|
|
|
|
|
|
{ |
1698
|
|
|
|
|
|
|
$dbh = DBI->connect_cached( |
1699
|
|
|
|
|
|
|
$dsn, |
1700
|
|
|
|
|
|
|
$self->{login}, |
1701
|
|
|
|
|
|
|
$self->{passwd}, |
1702
|
|
|
|
|
|
|
$self->{opt}, |
1703
|
0
|
|
|
|
|
0
|
undef(), |
1704
|
|
|
|
|
|
|
$CONNECT_VIA, |
1705
|
|
|
|
|
|
|
); |
1706
|
|
|
|
|
|
|
} |
1707
|
|
|
|
|
|
|
else |
1708
|
|
|
|
|
|
|
{ |
1709
|
|
|
|
|
|
|
$dbh = DBI->connect( |
1710
|
|
|
|
|
|
|
$dsn, |
1711
|
|
|
|
|
|
|
$self->{login}, |
1712
|
|
|
|
|
|
|
$self->{passwd}, |
1713
|
|
|
|
|
|
|
$self->{opt}, |
1714
|
0
|
|
|
|
|
0
|
undef(), |
1715
|
|
|
|
|
|
|
$CONNECT_VIA, |
1716
|
|
|
|
|
|
|
); |
1717
|
|
|
|
|
|
|
} |
1718
|
0
|
0
|
|
|
|
0
|
return( $self->error( $DBI::errstr ) ) if( !$dbh ); |
1719
|
0
|
|
|
|
|
0
|
return( $dbh ); |
1720
|
|
|
|
|
|
|
} |
1721
|
|
|
|
|
|
|
|
1722
|
|
|
|
|
|
|
sub _decode_json |
1723
|
|
|
|
|
|
|
{ |
1724
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1725
|
0
|
|
|
|
|
0
|
my $json = shift( @_ ); |
1726
|
0
|
0
|
|
|
|
0
|
return if( !CORE::length( $json ) ); |
1727
|
0
|
|
|
|
|
0
|
my $j = JSON->new->allow_nonref; |
1728
|
|
|
|
|
|
|
my $hash = eval |
1729
|
0
|
|
|
|
|
0
|
{ |
1730
|
0
|
|
|
|
|
0
|
$j->decode( $json ); |
1731
|
|
|
|
|
|
|
}; |
1732
|
0
|
0
|
|
|
|
0
|
return if( $@ ); |
1733
|
0
|
|
|
|
|
0
|
return( $hash ); |
1734
|
|
|
|
|
|
|
} |
1735
|
|
|
|
|
|
|
|
1736
|
|
|
|
|
|
|
sub _dsn |
1737
|
|
|
|
|
|
|
{ |
1738
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1739
|
0
|
|
0
|
|
|
0
|
my $class = ref( $self ) || $self; |
1740
|
0
|
|
|
|
|
0
|
die( "Method _dsn is not implemented in class $class\n" ); |
1741
|
|
|
|
|
|
|
} |
1742
|
|
|
|
|
|
|
|
1743
|
|
|
|
|
|
|
sub _encode_json |
1744
|
|
|
|
|
|
|
{ |
1745
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1746
|
0
|
0
|
0
|
|
|
0
|
return if( !scalar( @_ ) || ( scalar( @_ ) == 1 && !defined( $_[0] ) ) ); |
|
|
|
0
|
|
|
|
|
1747
|
0
|
|
|
|
|
0
|
my $this = shift( @_ ); |
1748
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Value provided is not a hash reference. I was expecting a hash reference to encode data into json." ) ) if( !$self->_is_hash( $this ) ); |
1749
|
0
|
|
|
|
|
0
|
my $j = JSON->new; |
1750
|
|
|
|
|
|
|
my $json = eval |
1751
|
0
|
|
|
|
|
0
|
{ |
1752
|
0
|
|
|
|
|
0
|
$j->encode( $this ); |
1753
|
|
|
|
|
|
|
}; |
1754
|
0
|
0
|
|
|
|
0
|
return( $self->error( "An error occurred while trying to encode hash reference provided: $@" ) ) if( $@ ); |
1755
|
0
|
|
|
|
|
0
|
return( $json ); |
1756
|
|
|
|
|
|
|
} |
1757
|
|
|
|
|
|
|
|
1758
|
|
|
|
|
|
|
sub _make_sth |
1759
|
|
|
|
|
|
|
{ |
1760
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1761
|
0
|
|
|
|
|
0
|
my $pkg = shift( @_ ); |
1762
|
0
|
|
0
|
|
|
0
|
my $data = shift( @_ ) || {}; |
1763
|
0
|
|
|
|
|
0
|
my $base_class = $self->base_class; |
1764
|
0
|
0
|
|
|
|
0
|
$self->_load_class( $pkg ) || return( $self->pass_error ); |
1765
|
|
|
|
|
|
|
# map{ $data->{ $_ } = $self->{ $_ } } |
1766
|
|
|
|
|
|
|
# qw( |
1767
|
|
|
|
|
|
|
# dbh drh server login passwd database driver |
1768
|
|
|
|
|
|
|
# table verbose debug bind cache params selected_fields |
1769
|
|
|
|
|
|
|
# local where limit group_by order_by reverse from_table left_join |
1770
|
|
|
|
|
|
|
# tie tie_order |
1771
|
|
|
|
|
|
|
# ); |
1772
|
0
|
|
|
|
|
0
|
map{ $data->{ $_ } = $self->{ $_ } } |
|
0
|
|
|
|
|
0
|
|
1773
|
|
|
|
|
|
|
qw( |
1774
|
|
|
|
|
|
|
table verbose debug bind cache params from_table left_join |
1775
|
|
|
|
|
|
|
); |
1776
|
0
|
|
|
|
|
0
|
$data->{dbh} = $self->{dbh}; |
1777
|
0
|
0
|
|
|
|
0
|
$data->{dbo} = $self->{dbo} ? $self->{dbo} : ref( $self ) eq $self->base_class ? $self : ''; |
|
|
0
|
|
|
|
|
|
1778
|
|
|
|
|
|
|
# $data->{ 'binded' } = $self->{ 'binded' } if( $self->{ 'binded' } && ref( $self ) ne $base_class ); |
1779
|
|
|
|
|
|
|
# In any case suppress the binded parameter from our parent object to avoid polluting the next queries |
1780
|
|
|
|
|
|
|
# If needed, the binded parameter will be rebuilt using the data stored in 'where', 'group', 'order' and 'limit' |
1781
|
|
|
|
|
|
|
# CORE::delete( $self->{ 'binded' } ); |
1782
|
|
|
|
|
|
|
# Binded parameters are now either in the DB::Object::Query package or one of its descendant OR passed as arguments to execute |
1783
|
0
|
|
|
|
|
0
|
$data->{errstr} = ''; |
1784
|
0
|
|
|
|
|
0
|
CORE::delete( $data->{executed} ); |
1785
|
0
|
|
|
|
|
0
|
$data->{query_time} = time(); |
1786
|
0
|
0
|
|
|
|
0
|
$data->{selected_fields} = '' if( !exists( $data->{selected_fields} ) ); |
1787
|
0
|
|
|
|
|
0
|
$data->{table_object} = $self; |
1788
|
0
|
|
|
|
|
0
|
my $this = bless( $data, $pkg ); |
1789
|
0
|
|
|
|
|
0
|
$this->debug( $self->debug ); |
1790
|
0
|
|
|
|
|
0
|
return( $this ); |
1791
|
|
|
|
|
|
|
} |
1792
|
|
|
|
|
|
|
|
1793
|
|
|
|
|
|
|
sub _param2hash |
1794
|
|
|
|
|
|
|
{ |
1795
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1796
|
0
|
|
|
|
|
0
|
my $opts = {}; |
1797
|
0
|
0
|
|
|
|
0
|
if( scalar( @_ ) ) |
1798
|
|
|
|
|
|
|
{ |
1799
|
0
|
0
|
|
|
|
0
|
if( $self->_is_hash( $_[0] ) ) |
|
|
0
|
|
|
|
|
|
1800
|
|
|
|
|
|
|
{ |
1801
|
0
|
|
|
|
|
0
|
$opts = shift( @_ ); |
1802
|
|
|
|
|
|
|
} |
1803
|
|
|
|
|
|
|
elsif( !( scalar( @_ ) % 2 ) ) |
1804
|
|
|
|
|
|
|
{ |
1805
|
0
|
|
|
|
|
0
|
$opts = { @_ }; |
1806
|
|
|
|
|
|
|
} |
1807
|
|
|
|
|
|
|
else |
1808
|
|
|
|
|
|
|
{ |
1809
|
0
|
|
|
|
|
0
|
return( $self->error( "Uneven number of parameters. I was expecting a hash or a hash reference." ) ); |
1810
|
|
|
|
|
|
|
} |
1811
|
|
|
|
|
|
|
} |
1812
|
0
|
|
|
|
|
0
|
return( $opts ); |
1813
|
|
|
|
|
|
|
} |
1814
|
|
|
|
|
|
|
|
1815
|
|
|
|
|
|
|
# INFO: _query_object_add needs to reside in DB::Object (called indirectly by no_bind) |
1816
|
|
|
|
|
|
|
sub _query_object_add |
1817
|
|
|
|
|
|
|
{ |
1818
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1819
|
0
|
|
0
|
|
|
0
|
my $obj = shift( @_ ) || return( $self->error( "No query object was provided" ) ); |
1820
|
0
|
|
|
|
|
0
|
my $base = $self->base_class; |
1821
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Object provided is not a query object class" ) ) if( ref( $obj ) !~ /^${base}\::Query$/ ); |
1822
|
0
|
|
|
|
|
0
|
$self->query_object( $obj ); |
1823
|
0
|
|
|
|
|
0
|
return( $obj ); |
1824
|
|
|
|
|
|
|
} |
1825
|
|
|
|
|
|
|
|
1826
|
|
|
|
|
|
|
# INFO: _query_object_create needs to reside in DB::Object (called indirectly by no_bind) |
1827
|
|
|
|
|
|
|
sub _query_object_create |
1828
|
|
|
|
|
|
|
{ |
1829
|
1
|
|
|
1
|
|
2
|
my $self = shift( @_ ); |
1830
|
1
|
|
|
|
|
14
|
my $base = $self->base_class; |
1831
|
1
|
|
|
|
|
3
|
my $query_class = "${base}::Query"; |
1832
|
|
|
|
|
|
|
eval |
1833
|
1
|
|
|
|
|
3
|
{ |
1834
|
1
|
|
|
|
|
45
|
$self->_load_class( $query_class ); |
1835
|
|
|
|
|
|
|
}; |
1836
|
1
|
50
|
|
|
|
529
|
return( $self->error( "Unable to load Query builder module $query_class: $@" ) ) if( $@ ); |
1837
|
|
|
|
|
|
|
# my $o = $query_class->new( debug => $self->debug, table_object => $self ) || return( $self->pass_error( $query_class->error ) ); |
1838
|
1
|
|
|
|
|
9
|
my $o = $query_class->new; |
1839
|
1
|
|
|
|
|
41
|
$o->debug( $self->debug ); |
1840
|
1
|
50
|
|
|
|
121
|
$o->enhance( $self->{enhance} ) if( CORE::length( $self->{enhance} ) ); |
1841
|
|
|
|
|
|
|
# $o->verbose( $self->verbose ); |
1842
|
1
|
50
|
|
|
|
992
|
$o->table_object( $self ) || return( $self->pass_error( $o->error ) ); |
1843
|
1
|
|
|
|
|
97
|
return( $o ); |
1844
|
|
|
|
|
|
|
} |
1845
|
|
|
|
|
|
|
|
1846
|
|
|
|
|
|
|
# INFO: _query_object_current needs to reside in DB::Object (called indirectly by no_bind) |
1847
|
0
|
|
|
0
|
|
0
|
sub _query_object_current { return( shift->{query_object} ); } |
1848
|
|
|
|
|
|
|
|
1849
|
|
|
|
|
|
|
# INFO: _query_object_get_or_create needs to reside in DB::Object (called indirectly by no_bind) |
1850
|
|
|
|
|
|
|
# If the stack is empty, we create an object, add it and resend it |
1851
|
|
|
|
|
|
|
sub _query_object_get_or_create |
1852
|
|
|
|
|
|
|
{ |
1853
|
1
|
|
|
1
|
|
4
|
my $self = shift( @_ ); |
1854
|
1
|
|
|
|
|
4
|
my $obj = $self->query_object; |
1855
|
1
|
50
|
|
|
|
31
|
if( !$obj ) |
1856
|
|
|
|
|
|
|
{ |
1857
|
1
|
|
50
|
|
|
9
|
$obj = $self->_query_object_create || return( $self->pass_error ); |
1858
|
|
|
|
|
|
|
#require Devel::StackTrace; |
1859
|
|
|
|
|
|
|
# my $trace = Devel::StackTrace->new; |
1860
|
1
|
|
|
|
|
36
|
$self->query_object( $obj ); |
1861
|
|
|
|
|
|
|
#my $s = Devel::StackTrace->new; |
1862
|
|
|
|
|
|
|
} |
1863
|
1
|
|
|
|
|
89
|
return( $obj ); |
1864
|
|
|
|
|
|
|
} |
1865
|
|
|
|
|
|
|
|
1866
|
|
|
|
|
|
|
# INFO: _query_object_remove needs to reside in DB::Object (called indirectly by no_bind) |
1867
|
|
|
|
|
|
|
sub _query_object_remove |
1868
|
|
|
|
|
|
|
{ |
1869
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1870
|
0
|
|
0
|
|
|
0
|
my $obj = shift( @_ ) || return( $self->error( "No query object was provided" ) ); |
1871
|
0
|
|
|
|
|
0
|
my $base = $self->base_class; |
1872
|
|
|
|
|
|
|
# return( $self->error( "Object provided is not a query object class" ) ) if( ref( $obj ) !~ /^${base}\::Query$/ ); |
1873
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Object provided is not a query object class" ) ) if( !$obj->isa( "DB::Object::Query" ) ); |
1874
|
0
|
|
|
|
|
0
|
$self->query_object( undef ); |
1875
|
0
|
|
|
|
|
0
|
return( $obj ); |
1876
|
|
|
|
|
|
|
} |
1877
|
|
|
|
|
|
|
|
1878
|
|
|
|
|
|
|
sub _query_type_old |
1879
|
|
|
|
|
|
|
{ |
1880
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1881
|
0
|
0
|
0
|
|
|
0
|
if( $self->{query} && length( $self->{query} ) ) |
1882
|
|
|
|
|
|
|
{ |
1883
|
0
|
|
|
|
|
0
|
return( lc( ( $self->{query} =~ /^[[:blank:]]*(ALTER|CREATE|DROP|GRANT|LISTEN|NOTIFY|INSERT|UPDATE|DELETE|SELECT|TRUNCATE)\b/i )[0] ) ) |
1884
|
|
|
|
|
|
|
} |
1885
|
0
|
|
|
|
|
0
|
return; |
1886
|
|
|
|
|
|
|
} |
1887
|
|
|
|
|
|
|
|
1888
|
|
|
|
|
|
|
# INFO: _reset_query needs to reside in DB::Object (called directly by no_bind) |
1889
|
|
|
|
|
|
|
sub _reset_query |
1890
|
|
|
|
|
|
|
{ |
1891
|
1
|
|
|
1
|
|
10
|
my $self = shift( @_ ); |
1892
|
1
|
50
|
|
|
|
8
|
if( !$self->{query_reset} ) |
1893
|
|
|
|
|
|
|
{ |
1894
|
1
|
|
|
|
|
36
|
$self->{query_reset}++; |
1895
|
1
|
|
|
|
|
17
|
$self->{enhance} = 1; |
1896
|
1
|
|
|
|
|
7
|
my $obj = $self->query_object; |
1897
|
1
|
50
|
|
|
|
52
|
$self->_query_object_remove( $obj ) if( $obj ); |
1898
|
1
|
50
|
33
|
|
|
24
|
if( $obj && $obj->join_tables->length > 0 ) |
1899
|
|
|
|
|
|
|
{ |
1900
|
|
|
|
|
|
|
$obj->join_tables->foreach(sub{ |
1901
|
0
|
|
|
0
|
|
0
|
my $tbl = shift( @_ ); |
1902
|
0
|
0
|
|
|
|
0
|
return if( $tbl->name eq $self->name ); |
1903
|
0
|
|
|
|
|
0
|
my $this_query_object = $tbl->query_object; |
1904
|
0
|
0
|
|
|
|
0
|
$tbl->_query_object_remove( $this_query_object ) if( $this_query_object ); |
1905
|
0
|
0
|
|
|
|
0
|
$tbl->use_bind(0) unless( $tbl->use_bind > 1 ); |
1906
|
0
|
0
|
|
|
|
0
|
$tbl->use_cache(0) unless( $tbl->use_cache > 1 ); |
1907
|
0
|
|
|
|
|
0
|
$tbl->query_reset(1); |
1908
|
0
|
|
|
|
|
0
|
return( $tbl->_query_object_get_or_create ); |
1909
|
0
|
|
|
|
|
0
|
}); |
1910
|
|
|
|
|
|
|
} |
1911
|
1
|
50
|
33
|
|
|
13
|
$self->{bind} = 0 unless( defined( $self->{bind} ) && $self->{bind} > 1 ); |
1912
|
1
|
50
|
33
|
|
|
11
|
$self->{cache} = 0 unless( defined( $self->{cache} ) && $self->{cache} > 1 ); |
1913
|
1
|
|
|
|
|
17
|
return( $self->_query_object_get_or_create ); |
1914
|
|
|
|
|
|
|
} |
1915
|
|
|
|
|
|
|
else |
1916
|
|
|
|
|
|
|
{ |
1917
|
|
|
|
|
|
|
} |
1918
|
0
|
|
|
|
|
0
|
return( $self->_query_object_current ); |
1919
|
|
|
|
|
|
|
} |
1920
|
|
|
|
|
|
|
|
1921
|
|
|
|
|
|
|
# NOTE: AUtOLOAD |
1922
|
|
|
|
|
|
|
AUTOLOAD |
1923
|
|
|
|
|
|
|
{ |
1924
|
0
|
|
|
0
|
|
0
|
my $self; |
1925
|
0
|
0
|
0
|
|
|
0
|
$self = shift( @_ ) if( blessed( $_[ 0 ] ) || index( $_[0], '::' ) != -1 ); |
1926
|
0
|
|
|
|
|
0
|
my( $class, $meth ); |
1927
|
0
|
0
|
|
|
|
0
|
if( $self ) |
1928
|
|
|
|
|
|
|
{ |
1929
|
0
|
|
0
|
|
|
0
|
$class = ref( $self ) || $self; |
1930
|
|
|
|
|
|
|
} |
1931
|
0
|
|
|
|
|
0
|
$meth = $AUTOLOAD; |
1932
|
0
|
0
|
|
|
|
0
|
if( CORE::index( $meth, '::' ) != -1 ) |
1933
|
|
|
|
|
|
|
{ |
1934
|
0
|
|
|
|
|
0
|
my $idx = rindex( $meth, '::' ); |
1935
|
0
|
|
|
|
|
0
|
$class = substr( $meth, 0, $idx ); |
1936
|
0
|
|
|
|
|
0
|
$meth = substr( $meth, $idx + 2 ); |
1937
|
|
|
|
|
|
|
} |
1938
|
0
|
|
|
|
|
0
|
my @supported_class = DB::Object->supported_class; |
1939
|
0
|
|
|
|
|
0
|
push( @supported_class, 'DB::Object' ); |
1940
|
0
|
|
|
|
|
0
|
my $ok_classes = join( '|', @supported_class ); |
1941
|
0
|
|
|
|
|
0
|
my $base_class = ( $class =~ /^($ok_classes)/ )[0]; |
1942
|
0
|
|
|
|
|
0
|
my( $call_pack, $call_file, $call_line, @other ) = caller; |
1943
|
0
|
|
|
|
|
0
|
my $call_sub = ( caller( 1 ) )[3]; |
1944
|
|
|
|
|
|
|
# print( STDERR "${class}::AUTOLOAD() [$AUTOLOAD]: Searching for routine '$meth' from package '$class' with \$self being '$self'.\n" ) if( $DEBUG ); |
1945
|
|
|
|
|
|
|
# my( $pkg, $file, $line, $sub ) = caller( 1 ); |
1946
|
|
|
|
|
|
|
# print( STDERR ref( $self ), ": method $meth() called with parameters: '", join( ', ', @_ ), "' within sub '$sub' at line '$line' in file '$file'.\n" ); |
1947
|
|
|
|
|
|
|
|
1948
|
|
|
|
|
|
|
# Is it a table object that is being requested? |
1949
|
|
|
|
|
|
|
# if( $self && scalar( grep{ /^$meth$/ } @$tables ) ) |
1950
|
|
|
|
|
|
|
# Getting table object take NO argument. |
1951
|
|
|
|
|
|
|
# If the user wants to access a method, and somehow the table name is identical to one of our methods, |
1952
|
|
|
|
|
|
|
# it is likely it will take an argument |
1953
|
0
|
0
|
0
|
|
|
0
|
if( $class eq $base_class && !scalar( @_ ) && $self->table_exists( $meth ) ) |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
1954
|
|
|
|
|
|
|
{ |
1955
|
0
|
|
|
|
|
0
|
return( $self->table( $meth ) ); |
1956
|
|
|
|
|
|
|
} |
1957
|
0
|
|
|
|
|
0
|
elsif( $self && $self->can( $meth ) && defined( &{ "$class\::$meth" } ) ) |
1958
|
|
|
|
|
|
|
{ |
1959
|
0
|
|
|
|
|
0
|
return( $self->$meth( @_ ) ); |
1960
|
|
|
|
|
|
|
} |
1961
|
|
|
|
|
|
|
# For imported subs |
1962
|
|
|
|
|
|
|
elsif( defined( &$meth ) ) |
1963
|
|
|
|
|
|
|
{ |
1964
|
3
|
|
|
3
|
|
25
|
no strict 'refs'; |
|
3
|
|
|
|
|
19
|
|
|
3
|
|
|
|
|
844
|
|
1965
|
0
|
|
|
|
|
0
|
*{"${class}\::${meth}"} = \&$meth; |
|
0
|
|
|
|
|
0
|
|
1966
|
|
|
|
|
|
|
# if( $self ) |
1967
|
|
|
|
|
|
|
# { |
1968
|
|
|
|
|
|
|
# print( STDERR "'can' I execute the method $meth in my own class $class now ? ", ( $self->can( $meth ) ? 'Yes' : 'No' ), "\n" ) if( $DEBUG ); |
1969
|
|
|
|
|
|
|
# } |
1970
|
0
|
0
|
|
|
|
0
|
unshift( @_, $self ) if( $self ); |
1971
|
|
|
|
|
|
|
# print( STDERR "Calling method $meth with arguments: '", join( "', '", @_ ), "'\n" ) if( $DEBUG ); |
1972
|
0
|
|
|
|
|
0
|
return( &$meth( @_ ) ); |
1973
|
|
|
|
|
|
|
} |
1974
|
|
|
|
|
|
|
# Taken from AutoLoader.pm |
1975
|
|
|
|
|
|
|
elsif( $class =~ /^(?:$ok_classes)$/ ) |
1976
|
|
|
|
|
|
|
{ |
1977
|
0
|
|
|
|
|
0
|
my $filename; |
1978
|
0
|
|
|
|
|
0
|
my $pkg = $class; |
1979
|
0
|
|
|
|
|
0
|
$pkg =~ s/::/\//g; |
1980
|
0
|
0
|
|
|
|
0
|
if( defined( $filename = $INC{ "$pkg.pm" } ) ) |
1981
|
|
|
|
|
|
|
{ |
1982
|
0
|
|
|
|
|
0
|
$filename =~ s%^(.*)$pkg\.pm\z%$1auto/${pkg}/${meth}.al%s; |
1983
|
0
|
0
|
|
|
|
0
|
if( -r( $filename ) ) |
1984
|
|
|
|
|
|
|
{ |
1985
|
0
|
0
|
|
|
|
0
|
unless( $filename =~ m|^/|s ) |
1986
|
|
|
|
|
|
|
{ |
1987
|
0
|
|
|
|
|
0
|
$filename = "./$filename"; |
1988
|
|
|
|
|
|
|
} |
1989
|
|
|
|
|
|
|
} |
1990
|
|
|
|
|
|
|
else |
1991
|
|
|
|
|
|
|
{ |
1992
|
0
|
|
|
|
|
0
|
$filename = undef(); |
1993
|
|
|
|
|
|
|
} |
1994
|
|
|
|
|
|
|
} |
1995
|
0
|
0
|
|
|
|
0
|
if( !defined( $filename ) ) |
1996
|
|
|
|
|
|
|
{ |
1997
|
0
|
|
|
|
|
0
|
$filename = "auto/${meth}.al"; |
1998
|
0
|
|
|
|
|
0
|
$filename =~ s/::/\//g; |
1999
|
|
|
|
|
|
|
} |
2000
|
0
|
|
|
|
|
0
|
my $save = $@; |
2001
|
|
|
|
|
|
|
eval |
2002
|
0
|
|
|
|
|
0
|
{ |
2003
|
0
|
|
|
0
|
|
0
|
local $SIG{__DIE__} = sub{ }; |
2004
|
0
|
|
|
0
|
|
0
|
local $SIG{__WARN__} = sub{ }; |
2005
|
0
|
|
|
|
|
0
|
require $filename; |
2006
|
|
|
|
|
|
|
}; |
2007
|
0
|
0
|
|
|
|
0
|
if( $@ ) |
2008
|
|
|
|
|
|
|
{ |
2009
|
0
|
0
|
|
|
|
0
|
if( substr( $AUTOLOAD, -9 ) eq '::DESTROY' ) |
2010
|
|
|
|
|
|
|
{ |
2011
|
3
|
|
|
3
|
|
22
|
no strict 'refs'; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
2045
|
|
2012
|
0
|
|
|
0
|
|
0
|
*$meth = sub {}; |
2013
|
|
|
|
|
|
|
} |
2014
|
|
|
|
|
|
|
else |
2015
|
|
|
|
|
|
|
{ |
2016
|
|
|
|
|
|
|
# The load might just have failed because the filename was too |
2017
|
|
|
|
|
|
|
# long for some old SVR3 systems which treat long names as errors. |
2018
|
|
|
|
|
|
|
# If we can succesfully truncate a long name then it's worth a go. |
2019
|
|
|
|
|
|
|
# There is a slight risk that we could pick up the wrong file here |
2020
|
|
|
|
|
|
|
# but autosplit should have warned about that when splitting. |
2021
|
0
|
0
|
|
|
|
0
|
if( $filename =~ s/(\w{12,})\.al$/substr( $1, 0, 11 ) . ".al"/e ) |
|
0
|
|
|
|
|
0
|
|
2022
|
|
|
|
|
|
|
{ |
2023
|
|
|
|
|
|
|
eval |
2024
|
0
|
|
|
|
|
0
|
{ |
2025
|
0
|
|
|
0
|
|
0
|
local $SIG{__DIE__} = sub{ }; |
2026
|
0
|
|
|
0
|
|
0
|
local $SIG{__WARN__} = sub{ }; |
2027
|
0
|
|
|
|
|
0
|
require $filename |
2028
|
|
|
|
|
|
|
}; |
2029
|
|
|
|
|
|
|
} |
2030
|
|
|
|
|
|
|
} |
2031
|
|
|
|
|
|
|
} |
2032
|
0
|
0
|
|
|
|
0
|
unless( $@ ) |
2033
|
|
|
|
|
|
|
{ |
2034
|
0
|
|
|
|
|
0
|
$@ = $save; |
2035
|
0
|
0
|
|
|
|
0
|
unshift( @_, $self ) if( $self ); |
2036
|
0
|
|
|
|
|
0
|
goto &$meth; |
2037
|
|
|
|
|
|
|
} |
2038
|
0
|
|
|
|
|
0
|
$@ = $save; |
2039
|
|
|
|
|
|
|
} |
2040
|
|
|
|
|
|
|
|
2041
|
0
|
0
|
0
|
|
|
0
|
if( $self && exists( $self->{sth} ) ) |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
2042
|
|
|
|
|
|
|
{ |
2043
|
|
|
|
|
|
|
# e.g. $sth->pg_server_prepare => $self->{sth}->{pg_server_prepare} |
2044
|
0
|
0
|
|
|
|
0
|
if( CORE::exists( $self->{sth}->{ $meth } ) ) |
2045
|
|
|
|
|
|
|
{ |
2046
|
0
|
0
|
|
|
|
0
|
$self->{sth}->{ $meth } = shift( @_ ) if( scalar( @_ ) ); |
2047
|
0
|
|
|
|
|
0
|
return( $self->{sth}->{ $meth } ); |
2048
|
|
|
|
|
|
|
} |
2049
|
0
|
0
|
|
|
|
0
|
if( !$self->executed() ) |
2050
|
|
|
|
|
|
|
{ |
2051
|
0
|
0
|
|
|
|
0
|
$self->execute() || return( $self->error( $self->{sth}->errstr() ) ); |
2052
|
|
|
|
|
|
|
} |
2053
|
|
|
|
|
|
|
# $self->_cleanup(); |
2054
|
|
|
|
|
|
|
# print( STDERR "Calling DBI method $meth with sth '$self->{sth}' arguments: '", join( "', '", @_ ), "'\n" ) if( $DEBUG ); |
2055
|
|
|
|
|
|
|
# *{ "${class}\::$meth" } = sub{ return( shift->{ 'sth' }->$meth( @_ ) ); }; |
2056
|
0
|
|
|
|
|
0
|
return( $self->{sth}->$meth( @_ ) ); |
2057
|
|
|
|
|
|
|
} |
2058
|
|
|
|
|
|
|
# e.g. $dbh->pg_notifies |
2059
|
|
|
|
|
|
|
elsif( $self && ( ( $self->{dbh} && $self->{dbh}->can( $meth ) ) || defined( &{ "DBI::db::" . $meth } ) ) ) |
2060
|
|
|
|
|
|
|
{ |
2061
|
0
|
|
|
|
|
0
|
return( $self->{dbh}->$meth( @_ ) ); |
2062
|
|
|
|
|
|
|
} |
2063
|
|
|
|
|
|
|
# e.g. $dbh->pg_enable_utf8 becomes $self->{dbh}->{pg_enable_utf8] |
2064
|
|
|
|
|
|
|
elsif( $self && $self->{dbh} && CORE::exists( $self->{dbh}->{ $meth } ) ) |
2065
|
|
|
|
|
|
|
{ |
2066
|
0
|
0
|
|
|
|
0
|
$self->{dbh}->{ $meth } = shift( @_ ) if( scalar( @_ ) ); |
2067
|
0
|
|
|
|
|
0
|
return( $self->{dbh}->{ $meth } ); |
2068
|
|
|
|
|
|
|
} |
2069
|
0
|
|
|
|
|
0
|
elsif( defined( &{ "DBI::" . $meth } ) ) |
2070
|
|
|
|
|
|
|
{ |
2071
|
0
|
|
|
|
|
0
|
my $h = &{ "DBI::" . $meth }( @_ ); |
|
0
|
|
|
|
|
0
|
|
2072
|
0
|
0
|
|
|
|
0
|
if( defined( $h ) ) |
2073
|
|
|
|
|
|
|
{ |
2074
|
0
|
|
|
|
|
0
|
bless( $h, $class ); |
2075
|
0
|
|
|
|
|
0
|
return( $h ); |
2076
|
|
|
|
|
|
|
} |
2077
|
|
|
|
|
|
|
else |
2078
|
|
|
|
|
|
|
{ |
2079
|
0
|
|
|
|
|
0
|
return; |
2080
|
|
|
|
|
|
|
} |
2081
|
|
|
|
|
|
|
} |
2082
|
|
|
|
|
|
|
# if( defined( &$meth ) ) |
2083
|
|
|
|
|
|
|
# { |
2084
|
|
|
|
|
|
|
# no strict 'refs'; |
2085
|
|
|
|
|
|
|
# *$meth = \&{ $meth }; |
2086
|
|
|
|
|
|
|
# return( &{ $meth }( @_ ) ); |
2087
|
|
|
|
|
|
|
# } |
2088
|
0
|
0
|
|
|
|
0
|
my $what = $self ? $self : $class; |
2089
|
0
|
|
|
|
|
0
|
return( $what->error( "${class}::AUTOLOAD: Not defined in $class and not autoloadable (last try $meth)" ) ); |
2090
|
|
|
|
|
|
|
} |
2091
|
|
|
|
|
|
|
|
2092
|
|
|
|
|
|
|
DESTROY |
2093
|
|
|
|
|
|
|
{ |
2094
|
1
|
|
|
1
|
|
35792
|
my $self = shift( @_ ); |
2095
|
1
|
|
33
|
|
|
5
|
my $class = ref( $self ) || $self; |
2096
|
1
|
50
|
33
|
|
|
9
|
if( $self->{sth} ) |
|
|
50
|
|
|
|
|
|
2097
|
|
|
|
|
|
|
{ |
2098
|
0
|
0
|
|
|
|
0
|
print( STDERR "DESTROY(): Terminating sth '$self' for query:\n$self->{query}\n" ) if( $DEBUG ); |
2099
|
0
|
|
|
|
|
0
|
$self->{sth}->finish(); |
2100
|
|
|
|
|
|
|
} |
2101
|
|
|
|
|
|
|
elsif( $self->{dbh} && $class =~ /^AI\:\:DB(?:\:\:(?:Postgres|Mysql|SQLite))?$/ ) |
2102
|
|
|
|
|
|
|
{ |
2103
|
0
|
|
|
0
|
|
0
|
local( $SIG{__WARN__} ) = sub { }; |
2104
|
|
|
|
|
|
|
# $self->{ 'dbh' }->disconnect(); |
2105
|
0
|
0
|
|
|
|
0
|
if( $DEBUG ) |
2106
|
|
|
|
|
|
|
{ |
2107
|
0
|
|
|
|
|
0
|
my( $pack, $file, $line, $sub ) = ( caller( 0 ) )[ 0, 1, 2, 3 ]; |
2108
|
0
|
|
|
|
|
0
|
my( $pack2, $file2, $line2, $sub2 ) = ( caller( 1 ) ) [ 0, 1, 2, 3 ]; |
2109
|
0
|
|
|
|
|
0
|
print( STDERR "DESTROY database handle ($self) [$self->{ 'query' }]\ncalled within sub '$sub' ($sub2) from package '$pack' ($pack2) in file '$file' ($file2) at line '$line' ($line2).\n" ); |
2110
|
|
|
|
|
|
|
} |
2111
|
0
|
|
|
|
|
0
|
$self->disconnect(); |
2112
|
|
|
|
|
|
|
} |
2113
|
1
|
|
|
|
|
3
|
my $locks = $self->{_locks}; |
2114
|
1
|
50
|
33
|
|
|
16
|
if( $locks && $self->_is_array( $locks ) ) |
2115
|
|
|
|
|
|
|
{ |
2116
|
0
|
|
|
|
|
0
|
foreach my $name ( @$locks ) |
2117
|
|
|
|
|
|
|
{ |
2118
|
0
|
|
|
|
|
0
|
$self->unlock( $name ); |
2119
|
|
|
|
|
|
|
} |
2120
|
|
|
|
|
|
|
} |
2121
|
|
|
|
|
|
|
} |
2122
|
|
|
|
|
|
|
|
2123
|
|
|
|
|
|
|
END |
2124
|
|
|
|
3
|
|
|
{ |
2125
|
|
|
|
|
|
|
# foreach my $dbh ( @DBH ) |
2126
|
|
|
|
|
|
|
# { |
2127
|
|
|
|
|
|
|
# $dbh->disconnect(); |
2128
|
|
|
|
|
|
|
# } |
2129
|
|
|
|
|
|
|
}; |
2130
|
|
|
|
|
|
|
|
2131
|
|
|
|
|
|
|
# NOTE: package DB::Object::Operator |
2132
|
|
|
|
|
|
|
package DB::Object::Operator; |
2133
|
|
|
|
|
|
|
BEGIN |
2134
|
0
|
|
|
|
|
0
|
{ |
2135
|
3
|
|
|
3
|
|
31
|
use strict; |
|
3
|
|
|
0
|
|
6
|
|
|
3
|
|
|
|
|
434
|
|
2136
|
|
|
|
|
|
|
}; |
2137
|
|
|
|
|
|
|
|
2138
|
|
|
|
|
|
|
sub new |
2139
|
|
|
|
|
|
|
{ |
2140
|
0
|
|
|
0
|
|
0
|
my $that = shift( @_ ); |
2141
|
0
|
0
|
0
|
|
|
0
|
my $val = ( scalar( @_ ) == 1 && ref( $_[0] ) eq 'ARRAY' ) ? [ @{$_[0]} ] : [ @_ ]; |
|
0
|
|
|
|
|
0
|
|
2142
|
0
|
|
0
|
|
|
0
|
return( bless( { value => $val } => ( ref( $that ) || $that ) ) ); |
2143
|
|
|
|
|
|
|
} |
2144
|
|
|
|
|
|
|
|
2145
|
0
|
|
|
0
|
|
0
|
sub operator { return( '' ); } |
2146
|
|
|
|
|
|
|
|
2147
|
0
|
0
|
|
0
|
|
0
|
sub value { return( wantarray() ? @{$_[0]->{value}} : $_[0]->{value} ); } |
|
0
|
|
|
|
|
0
|
|
2148
|
|
|
|
|
|
|
|
2149
|
|
|
|
|
|
|
# Ref: |
2150
|
|
|
|
|
|
|
# <https://www.postgresql.org/docs/12/arrays.html#ARRAYS-SEARCHING> |
2151
|
|
|
|
|
|
|
# NOTE: package DB::Object::ALL |
2152
|
|
|
|
|
|
|
package DB::Object::ALL; |
2153
|
|
|
|
|
|
|
BEGIN |
2154
|
0
|
|
|
|
|
0
|
{ |
2155
|
3
|
|
|
3
|
|
19
|
use strict; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
59
|
|
2156
|
3
|
|
|
3
|
|
13
|
use warnings; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
106
|
|
2157
|
3
|
|
|
3
|
|
13
|
use parent -norequire, qw( DB::Object::Operator ); |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
17
|
|
2158
|
3
|
|
|
3
|
|
128
|
use Scalar::Util (); |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
245
|
|
2159
|
|
|
|
|
|
|
use overload ( |
2160
|
|
|
|
|
|
|
'""' => 'as_string', |
2161
|
0
|
|
|
0
|
|
0
|
'bool' => sub{1}, |
2162
|
0
|
|
|
0
|
|
0
|
'==' => sub{ &_opt_overload( @_, '==' ) }, |
2163
|
0
|
|
|
0
|
|
0
|
'!=' => sub{ &_opt_overload( @_, '!=' ) }, |
2164
|
3
|
|
|
|
|
39
|
fallback => 1, |
2165
|
3
|
|
|
3
|
|
17
|
); |
|
3
|
|
|
0
|
|
5
|
|
2166
|
|
|
|
|
|
|
}; |
2167
|
|
|
|
|
|
|
|
2168
|
|
|
|
|
|
|
sub as_string |
2169
|
|
|
|
|
|
|
{ |
2170
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2171
|
0
|
|
|
|
|
0
|
my $vals = $self->value; |
2172
|
0
|
|
|
|
|
0
|
my @list = (); |
2173
|
0
|
|
|
|
|
0
|
foreach my $elem ( @$vals ) |
2174
|
|
|
|
|
|
|
{ |
2175
|
0
|
0
|
|
|
|
0
|
next unless( defined( $elem ) ); |
2176
|
0
|
0
|
0
|
|
|
0
|
if( Scalar::Util::blessed( $elem ) && |
2177
|
|
|
|
|
|
|
$elem->isa( 'DB::Object::Statement' ) ) |
2178
|
|
|
|
|
|
|
{ |
2179
|
0
|
|
|
|
|
0
|
push( @list, $elem->as_string ); |
2180
|
|
|
|
|
|
|
} |
2181
|
|
|
|
|
|
|
else |
2182
|
|
|
|
|
|
|
{ |
2183
|
0
|
|
|
|
|
0
|
push( @list, $elem ); |
2184
|
|
|
|
|
|
|
} |
2185
|
|
|
|
|
|
|
} |
2186
|
0
|
|
|
|
|
0
|
local $" = ','; |
2187
|
0
|
|
|
|
|
0
|
my $sql = "ALL (@list)"; |
2188
|
0
|
|
|
|
|
0
|
return( $sql ); |
2189
|
|
|
|
|
|
|
} |
2190
|
|
|
|
|
|
|
|
2191
|
0
|
|
|
0
|
|
0
|
sub operator { return( 'ALL' ); } |
2192
|
|
|
|
|
|
|
|
2193
|
|
|
|
|
|
|
sub _opt_overload |
2194
|
|
|
|
|
|
|
{ |
2195
|
0
|
|
|
0
|
|
0
|
my( $self, $val, $swap, $op ) = @_; |
2196
|
0
|
|
|
|
|
0
|
my $map = |
2197
|
|
|
|
|
|
|
{ |
2198
|
|
|
|
|
|
|
'!=' => '!= ', |
2199
|
|
|
|
|
|
|
'==' => '= ', |
2200
|
|
|
|
|
|
|
}; |
2201
|
0
|
|
|
|
|
0
|
my $not = $map->{ $op }; |
2202
|
0
|
|
|
|
|
0
|
my $in = $self->as_string; |
2203
|
0
|
0
|
0
|
|
|
0
|
my $lval = ( Scalar::Util::blessed( $val ) && $val->isa( 'DB::Object::Fields::Field' ) ) |
|
|
0
|
0
|
|
|
|
|
2204
|
|
|
|
|
|
|
? $val->name |
2205
|
|
|
|
|
|
|
: ( $val eq '?' || $self->_is_number( $val ) ) |
2206
|
|
|
|
|
|
|
? $val |
2207
|
|
|
|
|
|
|
: qq{'${val}'}; |
2208
|
0
|
|
|
|
|
0
|
return( DB::Object::Expression->new( "${lval} ${not}${in}" ) ); |
2209
|
|
|
|
|
|
|
} |
2210
|
|
|
|
|
|
|
|
2211
|
|
|
|
|
|
|
# NOTE: package DB::Object::AND |
2212
|
|
|
|
|
|
|
package DB::Object::AND; |
2213
|
|
|
|
|
|
|
BEGIN |
2214
|
0
|
|
|
|
|
0
|
{ |
2215
|
3
|
|
|
3
|
|
1133
|
use strict; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
93
|
|
2216
|
3
|
|
|
3
|
|
13
|
use parent -norequire, qw( DB::Object::Operator ); |
|
3
|
|
|
0
|
|
6
|
|
|
3
|
|
|
|
|
11
|
|
2217
|
|
|
|
|
|
|
}; |
2218
|
|
|
|
|
|
|
|
2219
|
0
|
|
|
0
|
|
0
|
sub operator { return( 'AND' ); } |
2220
|
|
|
|
|
|
|
|
2221
|
|
|
|
|
|
|
# Ref: |
2222
|
|
|
|
|
|
|
# <https://www.postgresql.org/docs/12/arrays.html#ARRAYS-SEARCHING> |
2223
|
|
|
|
|
|
|
# NOTE: package DB::Object::ANY |
2224
|
|
|
|
|
|
|
package DB::Object::ANY; |
2225
|
|
|
|
|
|
|
BEGIN |
2226
|
0
|
|
|
|
|
0
|
{ |
2227
|
3
|
|
|
3
|
|
248
|
use strict; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
61
|
|
2228
|
3
|
|
|
3
|
|
14
|
use warnings; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
103
|
|
2229
|
3
|
|
|
3
|
|
14
|
use parent -norequire, qw( DB::Object::Operator ); |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
13
|
|
2230
|
3
|
|
|
3
|
|
107
|
use Scalar::Util (); |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
238
|
|
2231
|
|
|
|
|
|
|
use overload ( |
2232
|
|
|
|
|
|
|
'""' => 'as_string', |
2233
|
0
|
|
|
0
|
|
0
|
'bool' => sub{1}, |
2234
|
0
|
|
|
0
|
|
0
|
'==' => sub{ &_opt_overload( @_, '==' ) }, |
2235
|
0
|
|
|
0
|
|
0
|
'!=' => sub{ &_opt_overload( @_, '!=' ) }, |
2236
|
3
|
|
|
|
|
26
|
fallback => 1, |
2237
|
3
|
|
|
3
|
|
14
|
); |
|
3
|
|
|
0
|
|
7
|
|
2238
|
|
|
|
|
|
|
}; |
2239
|
|
|
|
|
|
|
|
2240
|
|
|
|
|
|
|
sub as_string |
2241
|
|
|
|
|
|
|
{ |
2242
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2243
|
0
|
|
|
|
|
0
|
my $vals = $self->value; |
2244
|
0
|
|
|
|
|
0
|
my @list = (); |
2245
|
0
|
|
|
|
|
0
|
foreach my $elem ( @$vals ) |
2246
|
|
|
|
|
|
|
{ |
2247
|
0
|
0
|
|
|
|
0
|
next unless( defined( $elem ) ); |
2248
|
0
|
0
|
0
|
|
|
0
|
if( Scalar::Util::blessed( $elem ) && |
2249
|
|
|
|
|
|
|
$elem->isa( 'DB::Object::Statement' ) ) |
2250
|
|
|
|
|
|
|
{ |
2251
|
0
|
|
|
|
|
0
|
push( @list, $elem->as_string ); |
2252
|
|
|
|
|
|
|
} |
2253
|
|
|
|
|
|
|
else |
2254
|
|
|
|
|
|
|
{ |
2255
|
0
|
|
|
|
|
0
|
push( @list, $elem ); |
2256
|
|
|
|
|
|
|
} |
2257
|
|
|
|
|
|
|
} |
2258
|
0
|
|
|
|
|
0
|
local $" = ','; |
2259
|
0
|
|
|
|
|
0
|
my $sql = "ANY (@list)"; |
2260
|
0
|
|
|
|
|
0
|
return( $sql ); |
2261
|
|
|
|
|
|
|
} |
2262
|
|
|
|
|
|
|
|
2263
|
0
|
|
|
0
|
|
0
|
sub operator { return( 'ANY' ); } |
2264
|
|
|
|
|
|
|
|
2265
|
|
|
|
|
|
|
sub _opt_overload |
2266
|
|
|
|
|
|
|
{ |
2267
|
0
|
|
|
0
|
|
0
|
my( $self, $val, $swap, $op ) = @_; |
2268
|
0
|
|
|
|
|
0
|
my $map = |
2269
|
|
|
|
|
|
|
{ |
2270
|
|
|
|
|
|
|
'!=' => '!= ', |
2271
|
|
|
|
|
|
|
'==' => '= ', |
2272
|
|
|
|
|
|
|
}; |
2273
|
0
|
|
|
|
|
0
|
my $not = $map->{ $op }; |
2274
|
0
|
|
|
|
|
0
|
my $in = $self->as_string; |
2275
|
0
|
0
|
0
|
|
|
0
|
my $lval = ( Scalar::Util::blessed( $val ) && $val->isa( 'DB::Object::Fields::Field' ) ) |
|
|
0
|
0
|
|
|
|
|
2276
|
|
|
|
|
|
|
? $val->name |
2277
|
|
|
|
|
|
|
: ( $val eq '?' || $self->_is_number( $val ) ) |
2278
|
|
|
|
|
|
|
? $val |
2279
|
|
|
|
|
|
|
: qq{'${val}'}; |
2280
|
0
|
|
|
|
|
0
|
return( DB::Object::Expression->new( "${lval} ${not}${in}" ) ); |
2281
|
|
|
|
|
|
|
} |
2282
|
|
|
|
|
|
|
|
2283
|
|
|
|
|
|
|
# NOTE: package DB::Object::Expression |
2284
|
|
|
|
|
|
|
package DB::Object::Expression; |
2285
|
|
|
|
|
|
|
BEGIN |
2286
|
0
|
|
|
|
|
0
|
{ |
2287
|
3
|
|
|
3
|
|
1105
|
use strict; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
59
|
|
2288
|
3
|
|
|
3
|
|
17
|
use warnings; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
171
|
|
2289
|
|
|
|
|
|
|
use overload ( |
2290
|
|
|
|
|
|
|
'""' => 'as_string', |
2291
|
0
|
|
|
0
|
|
0
|
'bool' => sub{1}, |
2292
|
3
|
|
|
|
|
22
|
fallback => 1, |
2293
|
3
|
|
|
3
|
|
15
|
); |
|
3
|
|
|
0
|
|
8
|
|
2294
|
|
|
|
|
|
|
}; |
2295
|
|
|
|
|
|
|
|
2296
|
|
|
|
|
|
|
sub new |
2297
|
|
|
|
|
|
|
{ |
2298
|
0
|
|
|
0
|
|
0
|
my $that = shift( @_ ); |
2299
|
0
|
0
|
0
|
|
|
0
|
my $val = ( scalar( @_ ) == 1 && ref( $_[0] ) eq 'ARRAY' ) ? [ @{$_[0]} ] : [ @_ ]; |
|
0
|
|
|
|
|
0
|
|
2300
|
0
|
|
0
|
|
|
0
|
return( bless( { value => $val } => ( ref( $that ) || $that ) ) ); |
2301
|
|
|
|
|
|
|
} |
2302
|
|
|
|
|
|
|
|
2303
|
|
|
|
|
|
|
sub as_string |
2304
|
|
|
|
|
|
|
{ |
2305
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2306
|
0
|
|
|
|
|
0
|
my $vals = $self->components; |
2307
|
0
|
|
|
|
|
0
|
return( join( ' ', @$vals ) ); |
2308
|
|
|
|
|
|
|
} |
2309
|
|
|
|
|
|
|
|
2310
|
0
|
0
|
|
0
|
|
0
|
sub components { return( wantarray() ? @{$_[0]->{value}} : $_[0]->{value} ); } |
|
0
|
|
|
|
|
0
|
|
2311
|
|
|
|
|
|
|
|
2312
|
|
|
|
|
|
|
|
2313
|
|
|
|
|
|
|
# Ref: |
2314
|
|
|
|
|
|
|
# <https://www.postgresql.org/docs/12/functions-subquery.html#FUNCTIONS-SUBQUERY-IN> |
2315
|
|
|
|
|
|
|
# <https://www.postgresql.org/docs/12/functions-comparisons.html#FUNCTIONS-COMPARISONS-IN-SCALAR> |
2316
|
|
|
|
|
|
|
# <https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#operator_in> |
2317
|
|
|
|
|
|
|
# <https://www.sqlite.org/lang_expr.html#the_in_and_not_in_operators> |
2318
|
|
|
|
|
|
|
# NOTE: package DB::Object::IN |
2319
|
|
|
|
|
|
|
package DB::Object::IN; |
2320
|
|
|
|
|
|
|
BEGIN |
2321
|
0
|
|
|
|
|
0
|
{ |
2322
|
3
|
|
|
3
|
|
736
|
use strict; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
61
|
|
2323
|
3
|
|
|
3
|
|
14
|
use warnings; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
114
|
|
2324
|
3
|
|
|
3
|
|
15
|
use parent -norequire, qw( DB::Object::Operator ); |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
17
|
|
2325
|
3
|
|
|
3
|
|
116
|
use Scalar::Util (); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
261
|
|
2326
|
|
|
|
|
|
|
use overload ( |
2327
|
|
|
|
|
|
|
'""' => 'as_string', |
2328
|
0
|
|
|
0
|
|
0
|
'bool' => sub{1}, |
2329
|
0
|
|
|
0
|
|
0
|
'==' => sub{ &_opt_overload( @_, '==' ) }, |
2330
|
0
|
|
|
0
|
|
0
|
'!=' => sub{ &_opt_overload( @_, '!=' ) }, |
2331
|
3
|
|
|
|
|
27
|
fallback => 1, |
2332
|
3
|
|
|
3
|
|
14
|
); |
|
3
|
|
|
0
|
|
10
|
|
2333
|
|
|
|
|
|
|
}; |
2334
|
|
|
|
|
|
|
|
2335
|
|
|
|
|
|
|
sub as_string |
2336
|
|
|
|
|
|
|
{ |
2337
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2338
|
0
|
|
|
|
|
0
|
my $vals = $self->value; |
2339
|
0
|
|
|
|
|
0
|
my @list = (); |
2340
|
0
|
|
|
|
|
0
|
foreach my $elem ( @$vals ) |
2341
|
|
|
|
|
|
|
{ |
2342
|
0
|
0
|
|
|
|
0
|
next unless( defined( $elem ) ); |
2343
|
0
|
0
|
0
|
|
|
0
|
if( Scalar::Util::blessed( $elem ) && |
2344
|
|
|
|
|
|
|
$elem->isa( 'DB::Object::Statement' ) ) |
2345
|
|
|
|
|
|
|
{ |
2346
|
0
|
|
|
|
|
0
|
push( @list, $elem->as_string ); |
2347
|
|
|
|
|
|
|
} |
2348
|
|
|
|
|
|
|
else |
2349
|
|
|
|
|
|
|
{ |
2350
|
0
|
|
|
|
|
0
|
push( @list, $elem ); |
2351
|
|
|
|
|
|
|
} |
2352
|
|
|
|
|
|
|
} |
2353
|
0
|
|
|
|
|
0
|
local $" = ','; |
2354
|
0
|
|
|
|
|
0
|
my $sql = "IN (@list)"; |
2355
|
0
|
|
|
|
|
0
|
return( $sql ); |
2356
|
|
|
|
|
|
|
} |
2357
|
|
|
|
|
|
|
|
2358
|
0
|
|
|
0
|
|
0
|
sub operator { return( 'IN' ); } |
2359
|
|
|
|
|
|
|
|
2360
|
|
|
|
|
|
|
sub _opt_overload |
2361
|
|
|
|
|
|
|
{ |
2362
|
0
|
|
|
0
|
|
0
|
my( $self, $val, $swap, $op ) = @_; |
2363
|
0
|
|
|
|
|
0
|
my $map = |
2364
|
|
|
|
|
|
|
{ |
2365
|
|
|
|
|
|
|
'!=' => 'NOT ', |
2366
|
|
|
|
|
|
|
'==' => '', |
2367
|
|
|
|
|
|
|
}; |
2368
|
0
|
|
|
|
|
0
|
my $not = $map->{ $op }; |
2369
|
0
|
|
|
|
|
0
|
my $in = $self->as_string; |
2370
|
0
|
0
|
0
|
|
|
0
|
my $lval = ( Scalar::Util::blessed( $val ) && $val->isa( 'DB::Object::Fields::Field' ) ) |
|
|
0
|
0
|
|
|
|
|
2371
|
|
|
|
|
|
|
? $val->name |
2372
|
|
|
|
|
|
|
: ( $val eq '?' || $self->_is_number( $val ) ) |
2373
|
|
|
|
|
|
|
? $val |
2374
|
|
|
|
|
|
|
: qq{'${val}'}; |
2375
|
0
|
|
|
|
|
0
|
return( DB::Object::Expression->new( "${lval} ${not}${in}" ) ); |
2376
|
|
|
|
|
|
|
} |
2377
|
|
|
|
|
|
|
|
2378
|
|
|
|
|
|
|
# NOTE: package DB::Object::NOT |
2379
|
|
|
|
|
|
|
package DB::Object::NOT; |
2380
|
|
|
|
|
|
|
BEGIN |
2381
|
0
|
|
|
|
|
0
|
{ |
2382
|
3
|
|
|
3
|
|
1054
|
use strict; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
103
|
|
2383
|
3
|
|
|
3
|
|
14
|
use parent -norequire, qw( DB::Object::Operator ); |
|
3
|
|
|
0
|
|
7
|
|
|
3
|
|
|
|
|
14
|
|
2384
|
|
|
|
|
|
|
}; |
2385
|
|
|
|
|
|
|
|
2386
|
0
|
|
|
0
|
|
0
|
sub operator { return( 'NOT' ); } |
2387
|
|
|
|
|
|
|
|
2388
|
|
|
|
|
|
|
# NOTE: package DB::Object::OR |
2389
|
|
|
|
|
|
|
package DB::Object::OR; |
2390
|
|
|
|
|
|
|
BEGIN |
2391
|
0
|
|
|
|
|
0
|
{ |
2392
|
3
|
|
|
3
|
|
211
|
use strict; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
76
|
|
2393
|
3
|
|
|
3
|
|
12
|
use parent -norequire, qw( DB::Object::Operator ); |
|
3
|
|
|
0
|
|
5
|
|
|
3
|
|
|
|
|
11
|
|
2394
|
|
|
|
|
|
|
}; |
2395
|
|
|
|
|
|
|
|
2396
|
0
|
|
|
0
|
|
0
|
sub operator { return( 'OR' ); } |
2397
|
|
|
|
|
|
|
|
2398
|
|
|
|
|
|
|
# NOTE: package DB::Object::Placeholder |
2399
|
|
|
|
|
|
|
package DB::Object::Placeholder; |
2400
|
|
|
|
|
|
|
BEGIN |
2401
|
|
|
|
|
|
|
{ |
2402
|
3
|
|
|
3
|
|
194
|
use strict; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
133
|
|
2403
|
3
|
|
|
3
|
|
14
|
use warnings; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
84
|
|
2404
|
3
|
|
|
3
|
|
16
|
use vars qw( $REGISTRY ); |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
150
|
|
2405
|
3
|
|
|
3
|
|
1220
|
use Module::Generic::Array; |
|
3
|
|
|
|
|
16442
|
|
|
3
|
|
|
|
|
85
|
|
2406
|
3
|
|
|
3
|
|
17
|
use Scalar::Util (); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
61
|
|
2407
|
|
|
|
|
|
|
use overload ( |
2408
|
3
|
|
|
|
|
12
|
'""' => 'as_string', |
2409
|
3
|
|
|
3
|
|
13
|
); |
|
3
|
|
|
|
|
4
|
|
2410
|
3
|
|
|
3
|
|
236
|
our $REGISTRY = {}; |
2411
|
|
|
|
|
|
|
}; |
2412
|
|
|
|
|
|
|
|
2413
|
3
|
|
|
3
|
|
14
|
use strict; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
56
|
|
2414
|
3
|
|
|
3
|
|
30
|
use warnings; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
1318
|
|
2415
|
|
|
|
|
|
|
|
2416
|
|
|
|
|
|
|
sub new |
2417
|
|
|
|
|
|
|
{ |
2418
|
43
|
|
|
43
|
|
134
|
my $that = shift( @_ ); |
2419
|
43
|
|
|
|
|
82
|
my $args = { @_ }; |
2420
|
43
|
|
33
|
|
|
181
|
my $self = bless( $args => ( ref( $that ) || $that ) ); |
2421
|
43
|
|
|
|
|
96
|
my $addr = Scalar::Util::refaddr( $self ); |
2422
|
43
|
|
|
|
|
293
|
$REGISTRY->{ $addr } = $self; |
2423
|
43
|
|
|
|
|
224
|
return( $self ); |
2424
|
|
|
|
|
|
|
} |
2425
|
|
|
|
|
|
|
|
2426
|
|
|
|
|
|
|
sub as_string |
2427
|
|
|
|
|
|
|
{ |
2428
|
3
|
|
|
3
|
|
1761
|
my $self = shift( @_ ); |
2429
|
3
|
|
|
|
|
17
|
my $addr = Scalar::Util::refaddr( $self ); |
2430
|
3
|
|
|
|
|
19
|
return( "__PLACEHOLDER__${addr}__" ); |
2431
|
|
|
|
|
|
|
} |
2432
|
|
|
|
|
|
|
|
2433
|
|
|
|
|
|
|
sub has |
2434
|
|
|
|
|
|
|
{ |
2435
|
40
|
|
|
40
|
|
244
|
my $self = shift( @_ ); |
2436
|
40
|
|
|
|
|
62
|
my $str = shift( @_ ); |
2437
|
40
|
100
|
|
|
|
109
|
$str = Scalar::Util::reftype( $str ) eq 'SCALAR' ? $str : \$str; |
2438
|
40
|
|
|
|
|
273
|
return( CORE::index( $$str, '__PLACEHOLDER__' ) != -1 ); |
2439
|
|
|
|
|
|
|
} |
2440
|
|
|
|
|
|
|
|
2441
|
|
|
|
|
|
|
sub replace |
2442
|
|
|
|
|
|
|
{ |
2443
|
2
|
|
|
2
|
|
798
|
my $self = shift( @_ ); |
2444
|
2
|
|
|
|
|
8
|
my $str = shift( @_ ); |
2445
|
2
|
50
|
|
|
|
21
|
$str = Scalar::Util::reftype( $str ) eq 'SCALAR' ? $str : \$str; |
2446
|
2
|
50
|
33
|
|
|
37
|
return if( !defined( $$str ) || !length( $$str ) ); |
2447
|
2
|
|
|
|
|
17
|
my $types = Module::Generic::Array->new( [] ); |
2448
|
2
|
|
|
|
|
50
|
my $values = Module::Generic::Array->new( [] ); |
2449
|
2
|
|
|
|
|
66
|
$$str =~ s |
2450
|
|
|
|
|
|
|
{ |
2451
|
|
|
|
|
|
|
__PLACEHOLDER__(\d+)__ |
2452
|
|
|
|
|
|
|
} |
2453
|
3
|
50
|
|
|
|
23
|
{ |
2454
|
|
|
|
|
|
|
if( exists( $REGISTRY->{ $1 } ) ) |
2455
|
3
|
|
|
|
|
12
|
{ |
2456
|
3
|
|
|
|
|
22
|
my $p = $REGISTRY->{ $1 }; |
2457
|
3
|
|
|
|
|
17
|
push( @$types, $p->type ); |
2458
|
|
|
|
|
|
|
push( @$values, $p->value ); |
2459
|
3
|
|
|
|
|
40
|
} |
2460
|
|
|
|
|
|
|
"?"; |
2461
|
2
|
50
|
|
|
|
26
|
}gexm; |
2462
|
|
|
|
|
|
|
return( wantarray() ? ( $types, $$str ) : $types ); |
2463
|
|
|
|
|
|
|
} |
2464
|
|
|
|
|
|
|
|
2465
|
|
|
|
|
|
|
sub type |
2466
|
3
|
|
|
3
|
|
9
|
{ |
2467
|
3
|
50
|
|
|
|
10
|
my $self = shift( @_ ); |
2468
|
3
|
|
|
|
|
9
|
$self->{type} = shift( @_ ) if( @_ ); |
2469
|
|
|
|
|
|
|
return( $self->{type} ); |
2470
|
|
|
|
|
|
|
} |
2471
|
|
|
|
|
|
|
|
2472
|
|
|
|
|
|
|
sub value |
2473
|
3
|
|
|
3
|
|
11
|
{ |
2474
|
3
|
50
|
|
|
|
12
|
my $self = shift( @_ ); |
2475
|
3
|
|
|
|
|
14
|
$self->{value} = shift( @_ ) if( @_ ); |
2476
|
|
|
|
|
|
|
return( $self->{value} ); |
2477
|
|
|
|
|
|
|
} |
2478
|
|
|
|
|
|
|
|
2479
|
|
|
|
|
|
|
1; |
2480
|
|
|
|
|
|
|
# NOTE: POD |
2481
|
|
|
|
|
|
|
__END__ |
2482
|
|
|
|
|
|
|
|
2483
|
|
|
|
|
|
|
=encoding utf8 |
2484
|
|
|
|
|
|
|
|
2485
|
|
|
|
|
|
|
=head1 NAME |
2486
|
|
|
|
|
|
|
|
2487
|
|
|
|
|
|
|
DB::Object - SQL API |
2488
|
|
|
|
|
|
|
|
2489
|
|
|
|
|
|
|
=head1 SYNOPSIS |
2490
|
|
|
|
|
|
|
|
2491
|
|
|
|
|
|
|
use DB::Object; |
2492
|
|
|
|
|
|
|
|
2493
|
|
|
|
|
|
|
my $dbh = DB::Object->connect({ |
2494
|
|
|
|
|
|
|
driver => 'Pg', |
2495
|
|
|
|
|
|
|
conf_file => 'db-settings.json', |
2496
|
|
|
|
|
|
|
database => 'webstore', |
2497
|
|
|
|
|
|
|
host => 'localhost', |
2498
|
|
|
|
|
|
|
login => 'store-admin', |
2499
|
|
|
|
|
|
|
schema => 'auth', |
2500
|
|
|
|
|
|
|
debug => 3, |
2501
|
|
|
|
|
|
|
}) || bailout( "Unable to connect to sql server on host localhost: ", DB::Object->error ); |
2502
|
|
|
|
|
|
|
|
2503
|
|
|
|
|
|
|
# Legacy regular query |
2504
|
|
|
|
|
|
|
my $sth = $dbh->prepare( "SELECT login,name FROM login WHERE login='jack'" ) || |
2505
|
|
|
|
|
|
|
die( $dbh->errstr() ); |
2506
|
|
|
|
|
|
|
$sth->execute() || die( $sth->errstr() ); |
2507
|
|
|
|
|
|
|
my $ref = $sth->fetchrow_hashref(); |
2508
|
|
|
|
|
|
|
$sth->finish(); |
2509
|
|
|
|
|
|
|
|
2510
|
|
|
|
|
|
|
# Get a list of databases; |
2511
|
|
|
|
|
|
|
my @databases = $dbh->databases; |
2512
|
|
|
|
|
|
|
# Doesn't exist? Create it: |
2513
|
|
|
|
|
|
|
my $dbh2 = $dbh->create_db( 'webstore' ); |
2514
|
|
|
|
|
|
|
# Load some sql into it |
2515
|
|
|
|
|
|
|
my $rv = $dbh2->do( $sql ) || die( $dbh->error ); |
2516
|
|
|
|
|
|
|
|
2517
|
|
|
|
|
|
|
# Check a table exists |
2518
|
|
|
|
|
|
|
$dbh->table_exists( 'customers' ) || die( "Cannot find the customers table!\n" ); |
2519
|
|
|
|
|
|
|
|
2520
|
|
|
|
|
|
|
# Get list of tables, as array reference: |
2521
|
|
|
|
|
|
|
my $tables = $dbh->tables; |
2522
|
|
|
|
|
|
|
|
2523
|
|
|
|
|
|
|
my $cust = $dbh->customers || die( "Cannot get customers object." ); |
2524
|
|
|
|
|
|
|
$cust->where( email => 'john@example.org' ); |
2525
|
|
|
|
|
|
|
my $str = $cust->delete->as_string; |
2526
|
|
|
|
|
|
|
# Becomes: DELETE FROM customers WHERE email='john\@example.org' |
2527
|
|
|
|
|
|
|
|
2528
|
|
|
|
|
|
|
# Do some insert with transaction |
2529
|
|
|
|
|
|
|
$dbh->begin_work; |
2530
|
|
|
|
|
|
|
# Making some other inserts and updates here... |
2531
|
|
|
|
|
|
|
my $cust_sth_ins = $cust->insert( |
2532
|
|
|
|
|
|
|
first_name => 'Paul', |
2533
|
|
|
|
|
|
|
last_name => 'Goldman', |
2534
|
|
|
|
|
|
|
email => 'paul@example.org', |
2535
|
|
|
|
|
|
|
active => 0, |
2536
|
|
|
|
|
|
|
) || do |
2537
|
|
|
|
|
|
|
{ |
2538
|
|
|
|
|
|
|
# Rollback everything since the begin_work |
2539
|
|
|
|
|
|
|
$dbh->rollback; |
2540
|
|
|
|
|
|
|
die( "Error while create query to add data to table customers: " . $cust->error ); |
2541
|
|
|
|
|
|
|
}; |
2542
|
|
|
|
|
|
|
$result = $cust_sth_ins->as_string; |
2543
|
|
|
|
|
|
|
# INSERT INTO customers (first_name, last_name, email, active) VALUES('Paul', 'Goldman', 'paul\@example.org', '0') |
2544
|
|
|
|
|
|
|
$dbh->commit; |
2545
|
|
|
|
|
|
|
# Get the last used insert id |
2546
|
|
|
|
|
|
|
my $id = $dbh->last_insert_id(); |
2547
|
|
|
|
|
|
|
|
2548
|
|
|
|
|
|
|
$cust->where( email => 'john@example.org' ); |
2549
|
|
|
|
|
|
|
$cust->order( 'last_name' ); |
2550
|
|
|
|
|
|
|
$cust->having( email => qr/\@example/ ); |
2551
|
|
|
|
|
|
|
$cust->limit( 10 ); |
2552
|
|
|
|
|
|
|
my $cust_sth_sel = $cust->select || die( "An error occurred while creating a query to select data frm table customers: " . $cust->error ); |
2553
|
|
|
|
|
|
|
# Becomes: |
2554
|
|
|
|
|
|
|
# SELECT id, first_name, last_name, email, created, modified, active, created::ABSTIME::INTEGER AS created_unixtime, modified::ABSTIME::INTEGER AS modified_unixtime, CONCAT(first_name, ' ', last_name) AS name FROM customers WHERE email='john\@example.org' HAVING email ~ '\@example' ORDER BY last_name LIMIT 10 |
2555
|
|
|
|
|
|
|
|
2556
|
|
|
|
|
|
|
$cust->reset; |
2557
|
|
|
|
|
|
|
$cust->where( email => 'john@example.org' ); |
2558
|
|
|
|
|
|
|
my $cust_sth_upd = $cust->update( active => 0 ) |
2559
|
|
|
|
|
|
|
# Would become: |
2560
|
|
|
|
|
|
|
# UPDATE ONLY customers SET active='0' WHERE email='john\@example.org' |
2561
|
|
|
|
|
|
|
|
2562
|
|
|
|
|
|
|
# Lets' dump the result of our query |
2563
|
|
|
|
|
|
|
# First to STDERR |
2564
|
|
|
|
|
|
|
$login->where( "login='jack'" ); |
2565
|
|
|
|
|
|
|
$login->select->dump(); |
2566
|
|
|
|
|
|
|
# Now dump the result to a file |
2567
|
|
|
|
|
|
|
$login->select->dump( "my_file.txt" ); |
2568
|
|
|
|
|
|
|
|
2569
|
|
|
|
|
|
|
Using fields objects |
2570
|
|
|
|
|
|
|
|
2571
|
|
|
|
|
|
|
$cust->where( $dbh->OR( $cust->fo->email == 'john@example.org', $cust->fo->id == 2 ) ); |
2572
|
|
|
|
|
|
|
my $ref = $cust->select->fetchrow_hashref; |
2573
|
|
|
|
|
|
|
|
2574
|
|
|
|
|
|
|
Doing some left join |
2575
|
|
|
|
|
|
|
|
2576
|
|
|
|
|
|
|
my $geo_tbl = $dbh->geoip || return( $self->error( "Unable to get the database object \"geoip\"." ) ); |
2577
|
|
|
|
|
|
|
my $name_tbl = $dbh->geoname || return( $self->error( "Unable to get the database object \"geoname\"." ) ); |
2578
|
|
|
|
|
|
|
$geo_tbl->as( 'i' ); |
2579
|
|
|
|
|
|
|
$name_tbl->as( 'l' ); |
2580
|
|
|
|
|
|
|
$geo_tbl->where( "INET '?'" << $geo_tbl->fo->network ); |
2581
|
|
|
|
|
|
|
$geo_tbl->alias( id => 'ip_id' ); |
2582
|
|
|
|
|
|
|
$name_tbl->alias( country_iso_code => 'code' ); |
2583
|
|
|
|
|
|
|
my $sth = $geo_tbl->select->join( $name_tbl, $geo_tbl->fo->geoname_id == $name_tbl->fo->geoname_id ); |
2584
|
|
|
|
|
|
|
# SELECT |
2585
|
|
|
|
|
|
|
# -- tables fields |
2586
|
|
|
|
|
|
|
# FROM |
2587
|
|
|
|
|
|
|
# geoip AS i |
2588
|
|
|
|
|
|
|
# LEFT JOIN geoname AS l ON i.geoname_id = l.geoname_id |
2589
|
|
|
|
|
|
|
# WHERE |
2590
|
|
|
|
|
|
|
# INET '?' << i.network |
2591
|
|
|
|
|
|
|
|
2592
|
|
|
|
|
|
|
Using a promise (L<Promise::Me>) to execute an asynchronous query: |
2593
|
|
|
|
|
|
|
|
2594
|
|
|
|
|
|
|
my $sth = $dbh->prepare( "SELECT some_slow_function(?)" ) || die( $dbh->error ); |
2595
|
|
|
|
|
|
|
my $p = $sth->promise(10)->then(sub |
2596
|
|
|
|
|
|
|
{ |
2597
|
|
|
|
|
|
|
my $st = shift( @_ ); |
2598
|
|
|
|
|
|
|
my $ref = $st->fetchrow_hashref; |
2599
|
|
|
|
|
|
|
my $obj = My::Module->new( %$ref ); |
2600
|
|
|
|
|
|
|
})->catch(sub |
2601
|
|
|
|
|
|
|
{ |
2602
|
|
|
|
|
|
|
$log->warn( "Failed to execute query: ", @_ ); |
2603
|
|
|
|
|
|
|
}); |
2604
|
|
|
|
|
|
|
# Do other regular processing here |
2605
|
|
|
|
|
|
|
# Get the My::Module object |
2606
|
|
|
|
|
|
|
my( $obj ) = await( $p ); |
2607
|
|
|
|
|
|
|
|
2608
|
|
|
|
|
|
|
Sometimes, having placeholders in expression makes it difficult to work, so you can use placeholder objects to make it work: |
2609
|
|
|
|
|
|
|
|
2610
|
|
|
|
|
|
|
my $P = $dbh->placeholder( type => 'inet' ); |
2611
|
|
|
|
|
|
|
$orders_tbl->where( $dbh->OR( $orders_tbl->fo->ip_addr == "inet $P", "inet $P" << $orders_tbl->fo->ip_addr ) ); |
2612
|
|
|
|
|
|
|
my $order_ip_sth = $orders_tbl->select( 'id' ) || fail( "An error has occurred while trying to create a select by ip query for table orders: " . $orders_tbl->error ); |
2613
|
|
|
|
|
|
|
# SELECT id FROM orders WHERE ip_addr = inet ? OR inet ? << ip_addr |
2614
|
|
|
|
|
|
|
|
2615
|
|
|
|
|
|
|
=head1 VERSION |
2616
|
|
|
|
|
|
|
|
2617
|
|
|
|
|
|
|
v0.11.6 |
2618
|
|
|
|
|
|
|
|
2619
|
|
|
|
|
|
|
=head1 DESCRIPTION |
2620
|
|
|
|
|
|
|
|
2621
|
|
|
|
|
|
|
L<DB::Object> is a SQL API much alike C<DBI>, but with the added benefits that it formats queries in a simple object oriented, chaining way. |
2622
|
|
|
|
|
|
|
|
2623
|
|
|
|
|
|
|
So why use a private module instead of using that great C<DBI> package? |
2624
|
|
|
|
|
|
|
|
2625
|
|
|
|
|
|
|
At first, I started to inherit from C<DBI> to conform to C<perlmod> perl manual page and to general perl coding guidlines. It became very quickly a real hassle. Barely impossible to inherit, difficulty to handle error, too much dependent from an API that changes its behaviour with new versions. |
2626
|
|
|
|
|
|
|
In short, I wanted a better, more accurate control over the SQL connection and an easy way to format sql statement using an object oriented approach. |
2627
|
|
|
|
|
|
|
|
2628
|
|
|
|
|
|
|
So, L<DB::Object> acts as a convenient, modifiable wrapper that provides the programmer with an intuitive, user-friendly, object oriented and hassle free interface. |
2629
|
|
|
|
|
|
|
|
2630
|
|
|
|
|
|
|
However, if you use the power of this interface to prepare queries conveniently, you should cache the resulting statement handler object, because there is an obvious real cost penalty in preparing queries and they absolutely do not need to be prepared each time. So you can do something like: |
2631
|
|
|
|
|
|
|
|
2632
|
|
|
|
|
|
|
my $sth; |
2633
|
|
|
|
|
|
|
unless( $sth = $dbh->cache_query_get( 'some_arbitrary_identifier' ) ) |
2634
|
|
|
|
|
|
|
{ |
2635
|
|
|
|
|
|
|
# prepare the query |
2636
|
|
|
|
|
|
|
my $tbl = $dbh->some_table || die( $dbh->error ); |
2637
|
|
|
|
|
|
|
$tbl->where( id => '?' ); |
2638
|
|
|
|
|
|
|
$sth = $tbl->select || die( $tbl->error ); |
2639
|
|
|
|
|
|
|
$dbh->cache_query_set( some_arbitrary_identifier => $sth ); |
2640
|
|
|
|
|
|
|
} |
2641
|
|
|
|
|
|
|
$sth->exec(12) || die( $sth->error ); |
2642
|
|
|
|
|
|
|
my $ref = $sth->fetchrow_hashref; |
2643
|
|
|
|
|
|
|
|
2644
|
|
|
|
|
|
|
This will provide you with the convenience and power of L<DB::Object> while keeping execution fast. |
2645
|
|
|
|
|
|
|
|
2646
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
2647
|
|
|
|
|
|
|
|
2648
|
|
|
|
|
|
|
=head2 new |
2649
|
|
|
|
|
|
|
|
2650
|
|
|
|
|
|
|
Create a new instance of L<DB::Object>. Nothing much to say. |
2651
|
|
|
|
|
|
|
|
2652
|
|
|
|
|
|
|
=head2 connect |
2653
|
|
|
|
|
|
|
|
2654
|
|
|
|
|
|
|
Provided with a C<database>, C<login>, C<password>, C<server>:[C<port>], C<driver>, C<schema>, and optional hash or hash reference of parameters and this will issue a, possibly cached, database connection and return the resulting database handler. |
2655
|
|
|
|
|
|
|
|
2656
|
|
|
|
|
|
|
Create a new instance of L<DB::Object>, but also attempts a connection to SQL server. |
2657
|
|
|
|
|
|
|
|
2658
|
|
|
|
|
|
|
It can take either an array of value in the order database name, login, password, host, driver and optionally schema, or it can take a has or hash reference. The hash or hash reference attributes are as follow. |
2659
|
|
|
|
|
|
|
|
2660
|
|
|
|
|
|
|
Note that if you provide connection options that are not among the followings, this will return an error. |
2661
|
|
|
|
|
|
|
|
2662
|
|
|
|
|
|
|
=over 4 |
2663
|
|
|
|
|
|
|
|
2664
|
|
|
|
|
|
|
=item I<cache_connections> |
2665
|
|
|
|
|
|
|
|
2666
|
|
|
|
|
|
|
Defaults to true. |
2667
|
|
|
|
|
|
|
|
2668
|
|
|
|
|
|
|
If true, this will instruct L<DBI> to use L<DBI/connect_cached> instead of just L<DBI/connect> |
2669
|
|
|
|
|
|
|
|
2670
|
|
|
|
|
|
|
Beware that using cached connections can have some drawbacks, such as if you open a cached connection, enters into a transaction using L<DB::Object/begin_work>, then somewhere else in your code a call to a cached connection using the same parameters, which L<DBI> will provide, but will reset the database handler parameters, including the C<AutoCommit> that will have been temporarily set to false when you called L</begin_work>, and then you close your transaction by calling L</rollback> or L</commit>, but it will trigger an error, because C<AutoCommit> will have been reset on this cached connection to a true value. L</rollback> and L</commit> require that C<AutoCommit> be disabled, which L</begin_work> normally do. |
2671
|
|
|
|
|
|
|
|
2672
|
|
|
|
|
|
|
Thus, if you want to avoid using a cached connection, set this to false. |
2673
|
|
|
|
|
|
|
|
2674
|
|
|
|
|
|
|
More on this issue at L<DBI documentation|https://metacpan.org/pod/DBI#connect_cached> |
2675
|
|
|
|
|
|
|
|
2676
|
|
|
|
|
|
|
=item I<database> or I<DB_NAME> |
2677
|
|
|
|
|
|
|
|
2678
|
|
|
|
|
|
|
The database name you wish to connect to |
2679
|
|
|
|
|
|
|
|
2680
|
|
|
|
|
|
|
=item I<login> or I<DB_LOGIN> |
2681
|
|
|
|
|
|
|
|
2682
|
|
|
|
|
|
|
The login used to access that database |
2683
|
|
|
|
|
|
|
|
2684
|
|
|
|
|
|
|
=item I<passwd> or I<DB_PASSWD> |
2685
|
|
|
|
|
|
|
|
2686
|
|
|
|
|
|
|
The password that goes along |
2687
|
|
|
|
|
|
|
|
2688
|
|
|
|
|
|
|
=item I<host> or I<DB_HOST> |
2689
|
|
|
|
|
|
|
|
2690
|
|
|
|
|
|
|
The server, that is hostname of the machine serving a SQL server. |
2691
|
|
|
|
|
|
|
|
2692
|
|
|
|
|
|
|
=item I<port> or I<DB_PORT> |
2693
|
|
|
|
|
|
|
|
2694
|
|
|
|
|
|
|
The port to connect to |
2695
|
|
|
|
|
|
|
|
2696
|
|
|
|
|
|
|
=item I<driver> or I<DB_DRIVER> |
2697
|
|
|
|
|
|
|
|
2698
|
|
|
|
|
|
|
The driver you want to use. It needs to be of the same type than the server you want to connect to. If you are connecting to a MySQL server, you would use C<mysql>, if you would connecto to an Oracle server, you would use C<oracle>. |
2699
|
|
|
|
|
|
|
|
2700
|
|
|
|
|
|
|
You need to make sure that those driver are properly installed in the system before attempting to connect. |
2701
|
|
|
|
|
|
|
|
2702
|
|
|
|
|
|
|
To install the required driver, you could start with the command line: |
2703
|
|
|
|
|
|
|
|
2704
|
|
|
|
|
|
|
perl -MCPAN -e shell |
2705
|
|
|
|
|
|
|
|
2706
|
|
|
|
|
|
|
which will provide you a special shell to install modules in a convenient way. |
2707
|
|
|
|
|
|
|
|
2708
|
|
|
|
|
|
|
=item I<schema> or I<DB_SCHEMA> |
2709
|
|
|
|
|
|
|
|
2710
|
|
|
|
|
|
|
The schema to use to access the tables. Currently only used by PostgreSQL |
2711
|
|
|
|
|
|
|
|
2712
|
|
|
|
|
|
|
=item I<opt> |
2713
|
|
|
|
|
|
|
|
2714
|
|
|
|
|
|
|
This takes a hash reference and contains the standard C<DBI> options such as I<PrintError>, I<RaiseError>, I<AutoCommit>, etc |
2715
|
|
|
|
|
|
|
|
2716
|
|
|
|
|
|
|
=item I<conf_file> or I<DB_CON_FILE> |
2717
|
|
|
|
|
|
|
|
2718
|
|
|
|
|
|
|
This is used to specify a json connection configuration file. It can also provided via the environment variable I<DB_CON_FILE>. It has the following structure: |
2719
|
|
|
|
|
|
|
|
2720
|
|
|
|
|
|
|
{ |
2721
|
|
|
|
|
|
|
"database": "some_database", |
2722
|
|
|
|
|
|
|
"host": "db.example.com", |
2723
|
|
|
|
|
|
|
"login": "sql_joe", |
2724
|
|
|
|
|
|
|
"passwd": "some password", |
2725
|
|
|
|
|
|
|
"driver": "Pg", |
2726
|
|
|
|
|
|
|
"schema": "warehouse", |
2727
|
|
|
|
|
|
|
"opt": |
2728
|
|
|
|
|
|
|
{ |
2729
|
|
|
|
|
|
|
"RaiseError": false, |
2730
|
|
|
|
|
|
|
"PrintError": true, |
2731
|
|
|
|
|
|
|
"AutoCommit": true |
2732
|
|
|
|
|
|
|
} |
2733
|
|
|
|
|
|
|
} |
2734
|
|
|
|
|
|
|
|
2735
|
|
|
|
|
|
|
Alternatively, it can contain connections parameters for multiple databases and drivers, such as: |
2736
|
|
|
|
|
|
|
|
2737
|
|
|
|
|
|
|
{ |
2738
|
|
|
|
|
|
|
"databases": [ |
2739
|
|
|
|
|
|
|
{ |
2740
|
|
|
|
|
|
|
"database": "some_database", |
2741
|
|
|
|
|
|
|
"host": "db.example.com", |
2742
|
|
|
|
|
|
|
"port": 5432, |
2743
|
|
|
|
|
|
|
"login": "sql_joe", |
2744
|
|
|
|
|
|
|
"passwd": "some password", |
2745
|
|
|
|
|
|
|
"driver": "Pg", |
2746
|
|
|
|
|
|
|
"schema": "warehouse", |
2747
|
|
|
|
|
|
|
"opt": |
2748
|
|
|
|
|
|
|
{ |
2749
|
|
|
|
|
|
|
"RaiseError": false, |
2750
|
|
|
|
|
|
|
"PrintError": true, |
2751
|
|
|
|
|
|
|
"AutoCommit": true |
2752
|
|
|
|
|
|
|
} |
2753
|
|
|
|
|
|
|
}, |
2754
|
|
|
|
|
|
|
{ |
2755
|
|
|
|
|
|
|
"database": "other_database", |
2756
|
|
|
|
|
|
|
"host": "db.example2.com", |
2757
|
|
|
|
|
|
|
"login": "sql_bob", |
2758
|
|
|
|
|
|
|
"passwd": "other password", |
2759
|
|
|
|
|
|
|
"driver": "mysql", |
2760
|
|
|
|
|
|
|
}, |
2761
|
|
|
|
|
|
|
{ |
2762
|
|
|
|
|
|
|
"database": "/path/to/my/database.sqlite", |
2763
|
|
|
|
|
|
|
"driver": "SQLite", |
2764
|
|
|
|
|
|
|
} |
2765
|
|
|
|
|
|
|
] |
2766
|
|
|
|
|
|
|
} |
2767
|
|
|
|
|
|
|
|
2768
|
|
|
|
|
|
|
=item I<uri> or I<DB_CON_URI> |
2769
|
|
|
|
|
|
|
|
2770
|
|
|
|
|
|
|
This is used to specify an uri to contain all the connection parameters for one database connection. It can also provided via the environment variable I<DB_CON_URI>. For example: |
2771
|
|
|
|
|
|
|
|
2772
|
|
|
|
|
|
|
http://db.example.com:5432?database=some_database&login=sql_joe&passwd=some%020password&driver=Pg&schema=warehouse&&opt=%7B%22RaiseError%22%3A+false%2C+%22PrintError%22%3Atrue%2C+%22AutoCommit%22%3Atrue%7D |
2773
|
|
|
|
|
|
|
|
2774
|
|
|
|
|
|
|
Here the I<opt> parameter is passed as a json string, for example: |
2775
|
|
|
|
|
|
|
|
2776
|
|
|
|
|
|
|
{"RaiseError": false, "PrintError":true, "AutoCommit":true} |
2777
|
|
|
|
|
|
|
|
2778
|
|
|
|
|
|
|
=back |
2779
|
|
|
|
|
|
|
|
2780
|
|
|
|
|
|
|
=head1 METHODS |
2781
|
|
|
|
|
|
|
|
2782
|
|
|
|
|
|
|
=head2 alias |
2783
|
|
|
|
|
|
|
|
2784
|
|
|
|
|
|
|
See L<DB::Object::Tables/alias> |
2785
|
|
|
|
|
|
|
|
2786
|
|
|
|
|
|
|
=head2 allow_bulk_delete |
2787
|
|
|
|
|
|
|
|
2788
|
|
|
|
|
|
|
Sets/gets the boolean value for whether to allow unsafe bulk delete. This means query without any C<where> clause. |
2789
|
|
|
|
|
|
|
|
2790
|
|
|
|
|
|
|
=head2 allow_bulk_update |
2791
|
|
|
|
|
|
|
|
2792
|
|
|
|
|
|
|
Sets/gets the boolean value for whether to allow unsafe bulk update. This means query without any C<where> clause. |
2793
|
|
|
|
|
|
|
|
2794
|
|
|
|
|
|
|
=head2 AND |
2795
|
|
|
|
|
|
|
|
2796
|
|
|
|
|
|
|
Takes any arguments and wrap them into a C<AND> clause. |
2797
|
|
|
|
|
|
|
|
2798
|
|
|
|
|
|
|
$tbl->where( $dbh->AND( $tbl->fo->id == ?, $tbl->fo->frequency >= .30 ) ); |
2799
|
|
|
|
|
|
|
|
2800
|
|
|
|
|
|
|
=head2 as_string |
2801
|
|
|
|
|
|
|
|
2802
|
|
|
|
|
|
|
See L<DB::Object::Statement/as_string> |
2803
|
|
|
|
|
|
|
|
2804
|
|
|
|
|
|
|
=head2 auto_convert_datetime_to_object |
2805
|
|
|
|
|
|
|
|
2806
|
|
|
|
|
|
|
Sets or gets the boolean value. If true, then this api will automatically transcode datetime value into their equivalent L<DateTime> object. |
2807
|
|
|
|
|
|
|
|
2808
|
|
|
|
|
|
|
=head2 auto_decode_json |
2809
|
|
|
|
|
|
|
|
2810
|
|
|
|
|
|
|
Sets or gets the boolean value. If true, then this api will automatically transcode json data into perl hash reference. |
2811
|
|
|
|
|
|
|
|
2812
|
|
|
|
|
|
|
=head2 avoid |
2813
|
|
|
|
|
|
|
|
2814
|
|
|
|
|
|
|
See L<DB::Object::Tables/avoid> |
2815
|
|
|
|
|
|
|
|
2816
|
|
|
|
|
|
|
=head2 attribute |
2817
|
|
|
|
|
|
|
|
2818
|
|
|
|
|
|
|
Sets or get the value of database connection parameters. |
2819
|
|
|
|
|
|
|
|
2820
|
|
|
|
|
|
|
If only one argument is provided, returns its value. |
2821
|
|
|
|
|
|
|
If multiple arguments in a form of pair => value are provided, it sets the corresponding database parameters. |
2822
|
|
|
|
|
|
|
|
2823
|
|
|
|
|
|
|
The authorised parameters are: |
2824
|
|
|
|
|
|
|
|
2825
|
|
|
|
|
|
|
=over 4 |
2826
|
|
|
|
|
|
|
|
2827
|
|
|
|
|
|
|
=item I<Active> |
2828
|
|
|
|
|
|
|
|
2829
|
|
|
|
|
|
|
Is read-only. |
2830
|
|
|
|
|
|
|
|
2831
|
|
|
|
|
|
|
=item I<ActiveKids> |
2832
|
|
|
|
|
|
|
|
2833
|
|
|
|
|
|
|
Is read-only. |
2834
|
|
|
|
|
|
|
|
2835
|
|
|
|
|
|
|
=item I<AutoCommit> |
2836
|
|
|
|
|
|
|
|
2837
|
|
|
|
|
|
|
Can be changed. |
2838
|
|
|
|
|
|
|
|
2839
|
|
|
|
|
|
|
=item I<AutoInactiveDestroy> |
2840
|
|
|
|
|
|
|
|
2841
|
|
|
|
|
|
|
Can be changed. |
2842
|
|
|
|
|
|
|
|
2843
|
|
|
|
|
|
|
=item I<CachedKids> |
2844
|
|
|
|
|
|
|
|
2845
|
|
|
|
|
|
|
Is read-only. |
2846
|
|
|
|
|
|
|
|
2847
|
|
|
|
|
|
|
=item I<Callbacks> |
2848
|
|
|
|
|
|
|
|
2849
|
|
|
|
|
|
|
Can be changed. |
2850
|
|
|
|
|
|
|
|
2851
|
|
|
|
|
|
|
=item I<ChildHandles> |
2852
|
|
|
|
|
|
|
|
2853
|
|
|
|
|
|
|
Is read-only. |
2854
|
|
|
|
|
|
|
|
2855
|
|
|
|
|
|
|
=item I<ChopBlanks> |
2856
|
|
|
|
|
|
|
|
2857
|
|
|
|
|
|
|
Can be changed. |
2858
|
|
|
|
|
|
|
|
2859
|
|
|
|
|
|
|
=item I<CompatMode> |
2860
|
|
|
|
|
|
|
|
2861
|
|
|
|
|
|
|
Can be changed. |
2862
|
|
|
|
|
|
|
|
2863
|
|
|
|
|
|
|
=item I<CursorName> |
2864
|
|
|
|
|
|
|
|
2865
|
|
|
|
|
|
|
Is read-only. |
2866
|
|
|
|
|
|
|
|
2867
|
|
|
|
|
|
|
=item I<ErrCount> |
2868
|
|
|
|
|
|
|
|
2869
|
|
|
|
|
|
|
Is read-only. |
2870
|
|
|
|
|
|
|
|
2871
|
|
|
|
|
|
|
=item I<Executed> |
2872
|
|
|
|
|
|
|
|
2873
|
|
|
|
|
|
|
Is read-only. |
2874
|
|
|
|
|
|
|
|
2875
|
|
|
|
|
|
|
=item I<FetchHashKeyName> |
2876
|
|
|
|
|
|
|
|
2877
|
|
|
|
|
|
|
Is read-only. |
2878
|
|
|
|
|
|
|
|
2879
|
|
|
|
|
|
|
=item I<HandleError> |
2880
|
|
|
|
|
|
|
|
2881
|
|
|
|
|
|
|
Can be changed. |
2882
|
|
|
|
|
|
|
|
2883
|
|
|
|
|
|
|
=item I<HandleSetErr> |
2884
|
|
|
|
|
|
|
|
2885
|
|
|
|
|
|
|
Can be changed. |
2886
|
|
|
|
|
|
|
|
2887
|
|
|
|
|
|
|
=item I<InactiveDestroy> |
2888
|
|
|
|
|
|
|
|
2889
|
|
|
|
|
|
|
Can be changed. |
2890
|
|
|
|
|
|
|
|
2891
|
|
|
|
|
|
|
=item I<Kids> |
2892
|
|
|
|
|
|
|
|
2893
|
|
|
|
|
|
|
Is read-only. |
2894
|
|
|
|
|
|
|
|
2895
|
|
|
|
|
|
|
=item I<LongReadLen> |
2896
|
|
|
|
|
|
|
|
2897
|
|
|
|
|
|
|
Can be changed. |
2898
|
|
|
|
|
|
|
|
2899
|
|
|
|
|
|
|
=item I<LongTruncOk> |
2900
|
|
|
|
|
|
|
|
2901
|
|
|
|
|
|
|
Can be changed. |
2902
|
|
|
|
|
|
|
|
2903
|
|
|
|
|
|
|
=item I<NAME> |
2904
|
|
|
|
|
|
|
|
2905
|
|
|
|
|
|
|
Is read-only. |
2906
|
|
|
|
|
|
|
|
2907
|
|
|
|
|
|
|
=item I<NULLABLE> |
2908
|
|
|
|
|
|
|
|
2909
|
|
|
|
|
|
|
Is read-only. |
2910
|
|
|
|
|
|
|
|
2911
|
|
|
|
|
|
|
=item I<NUM_OF_FIELDS> |
2912
|
|
|
|
|
|
|
|
2913
|
|
|
|
|
|
|
Is read-only. |
2914
|
|
|
|
|
|
|
|
2915
|
|
|
|
|
|
|
=item I<NUM_OF_PARAMS> |
2916
|
|
|
|
|
|
|
|
2917
|
|
|
|
|
|
|
Is read-only. |
2918
|
|
|
|
|
|
|
|
2919
|
|
|
|
|
|
|
=item I<Name> |
2920
|
|
|
|
|
|
|
|
2921
|
|
|
|
|
|
|
Is read-only. |
2922
|
|
|
|
|
|
|
|
2923
|
|
|
|
|
|
|
=item I<PRECISION> |
2924
|
|
|
|
|
|
|
|
2925
|
|
|
|
|
|
|
Is read-only. |
2926
|
|
|
|
|
|
|
|
2927
|
|
|
|
|
|
|
=item I<PrintError> |
2928
|
|
|
|
|
|
|
|
2929
|
|
|
|
|
|
|
Can be changed. |
2930
|
|
|
|
|
|
|
|
2931
|
|
|
|
|
|
|
=item I<PrintWarn> |
2932
|
|
|
|
|
|
|
|
2933
|
|
|
|
|
|
|
Can be changed. |
2934
|
|
|
|
|
|
|
|
2935
|
|
|
|
|
|
|
=item I<Profile> |
2936
|
|
|
|
|
|
|
|
2937
|
|
|
|
|
|
|
Is read-only. |
2938
|
|
|
|
|
|
|
|
2939
|
|
|
|
|
|
|
=item I<RaiseError> |
2940
|
|
|
|
|
|
|
|
2941
|
|
|
|
|
|
|
Can be changed. |
2942
|
|
|
|
|
|
|
|
2943
|
|
|
|
|
|
|
=item I<ReadOnly> |
2944
|
|
|
|
|
|
|
|
2945
|
|
|
|
|
|
|
Can be changed. |
2946
|
|
|
|
|
|
|
|
2947
|
|
|
|
|
|
|
=item I<RowCacheSize> |
2948
|
|
|
|
|
|
|
|
2949
|
|
|
|
|
|
|
Is read-only. |
2950
|
|
|
|
|
|
|
|
2951
|
|
|
|
|
|
|
=item I<RowsInCache> |
2952
|
|
|
|
|
|
|
|
2953
|
|
|
|
|
|
|
Is read-only. |
2954
|
|
|
|
|
|
|
|
2955
|
|
|
|
|
|
|
=item I<SCALE> |
2956
|
|
|
|
|
|
|
|
2957
|
|
|
|
|
|
|
Is read-only. |
2958
|
|
|
|
|
|
|
|
2959
|
|
|
|
|
|
|
=item I<ShowErrorStatement> |
2960
|
|
|
|
|
|
|
|
2961
|
|
|
|
|
|
|
Can be changed. |
2962
|
|
|
|
|
|
|
|
2963
|
|
|
|
|
|
|
=item I<Statement> |
2964
|
|
|
|
|
|
|
|
2965
|
|
|
|
|
|
|
Is read-only. |
2966
|
|
|
|
|
|
|
|
2967
|
|
|
|
|
|
|
=item I<TYPE> |
2968
|
|
|
|
|
|
|
|
2969
|
|
|
|
|
|
|
Is read-only. |
2970
|
|
|
|
|
|
|
|
2971
|
|
|
|
|
|
|
=item I<Taint> |
2972
|
|
|
|
|
|
|
|
2973
|
|
|
|
|
|
|
Can be changed. |
2974
|
|
|
|
|
|
|
|
2975
|
|
|
|
|
|
|
=item I<TaintIn> |
2976
|
|
|
|
|
|
|
|
2977
|
|
|
|
|
|
|
Can be changed. |
2978
|
|
|
|
|
|
|
|
2979
|
|
|
|
|
|
|
=item I<TaintOut> |
2980
|
|
|
|
|
|
|
|
2981
|
|
|
|
|
|
|
Can be changed. |
2982
|
|
|
|
|
|
|
|
2983
|
|
|
|
|
|
|
=item I<TraceLevel> |
2984
|
|
|
|
|
|
|
|
2985
|
|
|
|
|
|
|
Can be changed. |
2986
|
|
|
|
|
|
|
|
2987
|
|
|
|
|
|
|
=item I<Type> |
2988
|
|
|
|
|
|
|
|
2989
|
|
|
|
|
|
|
Is read-only. |
2990
|
|
|
|
|
|
|
|
2991
|
|
|
|
|
|
|
=item I<Warn> |
2992
|
|
|
|
|
|
|
|
2993
|
|
|
|
|
|
|
Can be changed. |
2994
|
|
|
|
|
|
|
|
2995
|
|
|
|
|
|
|
=back |
2996
|
|
|
|
|
|
|
|
2997
|
|
|
|
|
|
|
=head2 available_drivers |
2998
|
|
|
|
|
|
|
|
2999
|
|
|
|
|
|
|
Return the list of available drivers. |
3000
|
|
|
|
|
|
|
|
3001
|
|
|
|
|
|
|
=head2 base_class |
3002
|
|
|
|
|
|
|
|
3003
|
|
|
|
|
|
|
Returns the base class. |
3004
|
|
|
|
|
|
|
|
3005
|
|
|
|
|
|
|
=head2 bind |
3006
|
|
|
|
|
|
|
|
3007
|
|
|
|
|
|
|
If no values to bind to the underlying query is provided, L</bind> simply activate the bind value feature. |
3008
|
|
|
|
|
|
|
|
3009
|
|
|
|
|
|
|
If values are provided, they are allocated to the statement object and will be applied when the query will be executed. |
3010
|
|
|
|
|
|
|
|
3011
|
|
|
|
|
|
|
Example: |
3012
|
|
|
|
|
|
|
|
3013
|
|
|
|
|
|
|
$dbh->bind() |
3014
|
|
|
|
|
|
|
# or |
3015
|
|
|
|
|
|
|
$dbh->bind->where( "something" ) |
3016
|
|
|
|
|
|
|
# or |
3017
|
|
|
|
|
|
|
$dbh->bind->select->fetchrow_hashref() |
3018
|
|
|
|
|
|
|
# and then later |
3019
|
|
|
|
|
|
|
$dbh->bind( 'thingy' )->select->fetchrow_hashref() |
3020
|
|
|
|
|
|
|
|
3021
|
|
|
|
|
|
|
=head2 cache |
3022
|
|
|
|
|
|
|
|
3023
|
|
|
|
|
|
|
Activate caching. |
3024
|
|
|
|
|
|
|
|
3025
|
|
|
|
|
|
|
$tbl->cache->select->fetchrow_hashref(); |
3026
|
|
|
|
|
|
|
|
3027
|
|
|
|
|
|
|
=head2 cache_connections |
3028
|
|
|
|
|
|
|
|
3029
|
|
|
|
|
|
|
Sets/get the cached database connection. |
3030
|
|
|
|
|
|
|
|
3031
|
|
|
|
|
|
|
=head2 cache_dir |
3032
|
|
|
|
|
|
|
|
3033
|
|
|
|
|
|
|
Sets or gets the directory on the file system used for caching data. |
3034
|
|
|
|
|
|
|
|
3035
|
|
|
|
|
|
|
=head2 cache_query_get |
3036
|
|
|
|
|
|
|
|
3037
|
|
|
|
|
|
|
my $sth; |
3038
|
|
|
|
|
|
|
unless( $sth = $dbh->cache_query_get( 'some_arbitrary_identifier' ) ) |
3039
|
|
|
|
|
|
|
{ |
3040
|
|
|
|
|
|
|
# prepare the query |
3041
|
|
|
|
|
|
|
my $tbl = $dbh->some_table || die( $dbh->error ); |
3042
|
|
|
|
|
|
|
$tbl->where( id => '?' ); |
3043
|
|
|
|
|
|
|
$sth = $tbl->select || die( $tbl->error ); |
3044
|
|
|
|
|
|
|
$dbh->cache_query_set( some_arbitrary_identifier => $sth ); |
3045
|
|
|
|
|
|
|
} |
3046
|
|
|
|
|
|
|
$sth->exec(12) || die( $sth->error ); |
3047
|
|
|
|
|
|
|
my $ref = $sth->fetchrow_hashref; |
3048
|
|
|
|
|
|
|
|
3049
|
|
|
|
|
|
|
Provided with a unique name, and this will return a cached statement object if it exists already, otherwise it will return undef |
3050
|
|
|
|
|
|
|
|
3051
|
|
|
|
|
|
|
=head2 cache_query_set |
3052
|
|
|
|
|
|
|
|
3053
|
|
|
|
|
|
|
my $sth; |
3054
|
|
|
|
|
|
|
unless( $sth = $dbh->cache_query_get( 'some_arbitrary_identifier' ) ) |
3055
|
|
|
|
|
|
|
{ |
3056
|
|
|
|
|
|
|
# prepare the query |
3057
|
|
|
|
|
|
|
my $tbl = $dbh->some_table || die( $dbh->error ); |
3058
|
|
|
|
|
|
|
$tbl->where( id => '?' ); |
3059
|
|
|
|
|
|
|
$sth = $tbl->select || die( $tbl->error ); |
3060
|
|
|
|
|
|
|
$dbh->cache_query_set( some_arbitrary_identifier => $sth ); |
3061
|
|
|
|
|
|
|
} |
3062
|
|
|
|
|
|
|
$sth->exec(12) || die( $sth->error ); |
3063
|
|
|
|
|
|
|
my $ref = $sth->fetchrow_hashref; |
3064
|
|
|
|
|
|
|
|
3065
|
|
|
|
|
|
|
Provided with a unique name and a statement object (L<DB::Object::Statement>), and this will cache it. |
3066
|
|
|
|
|
|
|
|
3067
|
|
|
|
|
|
|
What this does simply is store the statement object in a global C<$QUERIES_CACHE> hash reference of identifier-statement object pairs. |
3068
|
|
|
|
|
|
|
|
3069
|
|
|
|
|
|
|
It returns the statement object cached. |
3070
|
|
|
|
|
|
|
|
3071
|
|
|
|
|
|
|
=head2 cache_tables |
3072
|
|
|
|
|
|
|
|
3073
|
|
|
|
|
|
|
Sets or gets the L<DB::Object::Cache::Tables> object. |
3074
|
|
|
|
|
|
|
|
3075
|
|
|
|
|
|
|
=head2 check_driver |
3076
|
|
|
|
|
|
|
|
3077
|
|
|
|
|
|
|
Check that the driver set in I<$SQL_DRIVER> in ~/etc/common.cfg is indeed available. |
3078
|
|
|
|
|
|
|
|
3079
|
|
|
|
|
|
|
It does this by calling L</available_drivers>. |
3080
|
|
|
|
|
|
|
|
3081
|
|
|
|
|
|
|
=head2 connect |
3082
|
|
|
|
|
|
|
|
3083
|
|
|
|
|
|
|
This will attempt a database server connection. |
3084
|
|
|
|
|
|
|
|
3085
|
|
|
|
|
|
|
It called L</_connection_params2hash> to get the necessary connection parameters, which is superseded in each driver package. |
3086
|
|
|
|
|
|
|
|
3087
|
|
|
|
|
|
|
Then, it will call L</_check_connect_param> to get the right parameters for connection. |
3088
|
|
|
|
|
|
|
|
3089
|
|
|
|
|
|
|
It will also call L</_check_default_option> to get some driver specific default options unless the previous call to _check_connect_param returned an has with a property I<opt>. |
3090
|
|
|
|
|
|
|
|
3091
|
|
|
|
|
|
|
It will then set the following current object properties: L</database>, L</host>, L</port>, L</login>, L</passwd>, L</driver>, L</cache>, L</bind>, L</opt> |
3092
|
|
|
|
|
|
|
|
3093
|
|
|
|
|
|
|
Unless specified in the connection options retrieved with L</_check_default_option>, it sets some basic default value: |
3094
|
|
|
|
|
|
|
|
3095
|
|
|
|
|
|
|
=over 4 |
3096
|
|
|
|
|
|
|
|
3097
|
|
|
|
|
|
|
=item I<AutoCommit> 1 |
3098
|
|
|
|
|
|
|
|
3099
|
|
|
|
|
|
|
=item I<PrintError> 0 |
3100
|
|
|
|
|
|
|
|
3101
|
|
|
|
|
|
|
=item I<RaiseError> 0 |
3102
|
|
|
|
|
|
|
|
3103
|
|
|
|
|
|
|
=back |
3104
|
|
|
|
|
|
|
|
3105
|
|
|
|
|
|
|
Finally it tries to connect by calling the, possibly superseded, method L</_dbi_connect> |
3106
|
|
|
|
|
|
|
|
3107
|
|
|
|
|
|
|
It instantiate a L<DB::Object::Cache::Tables> object to cache database tables and return the current object. |
3108
|
|
|
|
|
|
|
|
3109
|
|
|
|
|
|
|
=head2 constant_queries_cache |
3110
|
|
|
|
|
|
|
|
3111
|
|
|
|
|
|
|
Returns the global value for C<$CONSTANT_QUERIES_CACHE> |
3112
|
|
|
|
|
|
|
|
3113
|
|
|
|
|
|
|
=head2 constant_queries_cache_get |
3114
|
|
|
|
|
|
|
|
3115
|
|
|
|
|
|
|
Provided with some hash reference with properties C<pack>, C<file> and C<line> that are together used as a key in the cache and this will use an existing entry in the cache if available. |
3116
|
|
|
|
|
|
|
|
3117
|
|
|
|
|
|
|
=head2 constant_queries_cache_set |
3118
|
|
|
|
|
|
|
|
3119
|
|
|
|
|
|
|
Provided with some hash reference with properties C<pack>, C<file> and C<line> that are together used as a key in the cache and C<query_object> and this will set an entry in the cache. it returns the hash reference initially provided. |
3120
|
|
|
|
|
|
|
|
3121
|
|
|
|
|
|
|
=head2 copy |
3122
|
|
|
|
|
|
|
|
3123
|
|
|
|
|
|
|
Provided with either a reference to an hash or an hash of key => value pairs, L</copy> will first execute a select statement on the table object, then fetch the row of data, then replace the key-value pair in the result by the ones provided, and finally will perform an insert. |
3124
|
|
|
|
|
|
|
|
3125
|
|
|
|
|
|
|
Return false if no data to copy were provided, otherwise it always returns true. |
3126
|
|
|
|
|
|
|
|
3127
|
|
|
|
|
|
|
=head2 create_db |
3128
|
|
|
|
|
|
|
|
3129
|
|
|
|
|
|
|
This is a method that must be implemented by the driver package. |
3130
|
|
|
|
|
|
|
|
3131
|
|
|
|
|
|
|
=head2 create_table |
3132
|
|
|
|
|
|
|
|
3133
|
|
|
|
|
|
|
This is a method that must be implemented by the driver package. |
3134
|
|
|
|
|
|
|
|
3135
|
|
|
|
|
|
|
=head2 data_sources |
3136
|
|
|
|
|
|
|
|
3137
|
|
|
|
|
|
|
Given an optional list of options as hash, this return the data source of the database handler. |
3138
|
|
|
|
|
|
|
|
3139
|
|
|
|
|
|
|
=head2 data_type |
3140
|
|
|
|
|
|
|
|
3141
|
|
|
|
|
|
|
Given a reference to an array or an array of data type, L</data_type> will check their availability in the database driver. |
3142
|
|
|
|
|
|
|
|
3143
|
|
|
|
|
|
|
If nothing found, it return an empty list in list context, or undef in scalar context. |
3144
|
|
|
|
|
|
|
|
3145
|
|
|
|
|
|
|
If something was found, it returns a hash in list context or a reference to a hash in list context. |
3146
|
|
|
|
|
|
|
|
3147
|
|
|
|
|
|
|
=head2 database |
3148
|
|
|
|
|
|
|
|
3149
|
|
|
|
|
|
|
Return the name of the current database. |
3150
|
|
|
|
|
|
|
|
3151
|
|
|
|
|
|
|
=head2 databases |
3152
|
|
|
|
|
|
|
|
3153
|
|
|
|
|
|
|
This returns the list of available databases. |
3154
|
|
|
|
|
|
|
|
3155
|
|
|
|
|
|
|
This is a method that must be implemented by the driver package. |
3156
|
|
|
|
|
|
|
|
3157
|
|
|
|
|
|
|
=head2 delete |
3158
|
|
|
|
|
|
|
|
3159
|
|
|
|
|
|
|
See L<DB::Object::Tables/delete> |
3160
|
|
|
|
|
|
|
|
3161
|
|
|
|
|
|
|
=head2 disconnect |
3162
|
|
|
|
|
|
|
|
3163
|
|
|
|
|
|
|
Disconnect from database. Returns the return code. |
3164
|
|
|
|
|
|
|
|
3165
|
|
|
|
|
|
|
my $rc = $dbh->disconnect; |
3166
|
|
|
|
|
|
|
|
3167
|
|
|
|
|
|
|
=head2 do |
3168
|
|
|
|
|
|
|
|
3169
|
|
|
|
|
|
|
Provided with a string representing a sql query, some hash reference of attributes and some optional values to bind and this will execute the query and return the statement handler. |
3170
|
|
|
|
|
|
|
|
3171
|
|
|
|
|
|
|
The attributes list will be used to B<prepare> the query and the bind values will be used when executing the query. |
3172
|
|
|
|
|
|
|
|
3173
|
|
|
|
|
|
|
Example: |
3174
|
|
|
|
|
|
|
|
3175
|
|
|
|
|
|
|
$rc = $dbh->do( $statement ) || die( $dbh->errstr ); |
3176
|
|
|
|
|
|
|
$rc = $dbh->do( $statement, \%attr ) || die( $dbh->errstr ); |
3177
|
|
|
|
|
|
|
$rv = $dbh->do( $statement, \%attr, @bind_values ) || die( $dbh->errstr ); |
3178
|
|
|
|
|
|
|
my $rows_deleted = $dbh->do( |
3179
|
|
|
|
|
|
|
q{ |
3180
|
|
|
|
|
|
|
DELETE FROM table WHERE status = ? |
3181
|
|
|
|
|
|
|
}, undef(), 'DONE' ) || die( $dbh->errstr ); |
3182
|
|
|
|
|
|
|
|
3183
|
|
|
|
|
|
|
=head2 driver |
3184
|
|
|
|
|
|
|
|
3185
|
|
|
|
|
|
|
Return the name of the driver for the current object. |
3186
|
|
|
|
|
|
|
|
3187
|
|
|
|
|
|
|
=head2 enhance |
3188
|
|
|
|
|
|
|
|
3189
|
|
|
|
|
|
|
Toggle the enhance mode on/off. |
3190
|
|
|
|
|
|
|
|
3191
|
|
|
|
|
|
|
When on, the functions L</from_unixtime> and L</unix_timestamp> will be used on date/time field to translate from and to unix time seamlessly. |
3192
|
|
|
|
|
|
|
|
3193
|
|
|
|
|
|
|
=head2 err |
3194
|
|
|
|
|
|
|
|
3195
|
|
|
|
|
|
|
Get the currently set error. |
3196
|
|
|
|
|
|
|
|
3197
|
|
|
|
|
|
|
=head2 errno |
3198
|
|
|
|
|
|
|
|
3199
|
|
|
|
|
|
|
Is just an alias for L</err>. |
3200
|
|
|
|
|
|
|
|
3201
|
|
|
|
|
|
|
=head2 errmesg |
3202
|
|
|
|
|
|
|
|
3203
|
|
|
|
|
|
|
Is just an alias for L</errstr>. |
3204
|
|
|
|
|
|
|
|
3205
|
|
|
|
|
|
|
=head2 errstr |
3206
|
|
|
|
|
|
|
|
3207
|
|
|
|
|
|
|
Get the currently set error string. |
3208
|
|
|
|
|
|
|
|
3209
|
|
|
|
|
|
|
=head2 FALSE |
3210
|
|
|
|
|
|
|
|
3211
|
|
|
|
|
|
|
This return the keyword C<FALSE> to be used in queries. |
3212
|
|
|
|
|
|
|
|
3213
|
|
|
|
|
|
|
=head2 fatal |
3214
|
|
|
|
|
|
|
|
3215
|
|
|
|
|
|
|
Provided a boolean value and this toggles fatal mode on/off. |
3216
|
|
|
|
|
|
|
|
3217
|
|
|
|
|
|
|
=head2 format_statement |
3218
|
|
|
|
|
|
|
|
3219
|
|
|
|
|
|
|
See L<DB::Object::Tables/format_statement> |
3220
|
|
|
|
|
|
|
|
3221
|
|
|
|
|
|
|
=head2 format_update |
3222
|
|
|
|
|
|
|
|
3223
|
|
|
|
|
|
|
See L<DB::Object::Tables/format_update> |
3224
|
|
|
|
|
|
|
|
3225
|
|
|
|
|
|
|
=head2 from_unixtime |
3226
|
|
|
|
|
|
|
|
3227
|
|
|
|
|
|
|
See L<DB::Object::Tables/from_unixtime> |
3228
|
|
|
|
|
|
|
|
3229
|
|
|
|
|
|
|
=head2 get_sql_type |
3230
|
|
|
|
|
|
|
|
3231
|
|
|
|
|
|
|
Provided with a sql type, irrespective of the character case, and this will return the driver equivalent constant value. |
3232
|
|
|
|
|
|
|
|
3233
|
|
|
|
|
|
|
=head2 group |
3234
|
|
|
|
|
|
|
|
3235
|
|
|
|
|
|
|
See L<DB::Object::Tables/group> |
3236
|
|
|
|
|
|
|
|
3237
|
|
|
|
|
|
|
=head2 host |
3238
|
|
|
|
|
|
|
|
3239
|
|
|
|
|
|
|
Sets or gets the C<host> property for this database object. |
3240
|
|
|
|
|
|
|
|
3241
|
|
|
|
|
|
|
=head2 insert |
3242
|
|
|
|
|
|
|
|
3243
|
|
|
|
|
|
|
See L<DB::Object::Tables/insert> |
3244
|
|
|
|
|
|
|
|
3245
|
|
|
|
|
|
|
=head2 last_insert_id |
3246
|
|
|
|
|
|
|
|
3247
|
|
|
|
|
|
|
Get the id of the primary key from the last insert. |
3248
|
|
|
|
|
|
|
|
3249
|
|
|
|
|
|
|
=head2 limit |
3250
|
|
|
|
|
|
|
|
3251
|
|
|
|
|
|
|
See L<DB::Object::Tables/limit> |
3252
|
|
|
|
|
|
|
|
3253
|
|
|
|
|
|
|
=head2 local |
3254
|
|
|
|
|
|
|
|
3255
|
|
|
|
|
|
|
See L<DB::Object::Tables/local> |
3256
|
|
|
|
|
|
|
|
3257
|
|
|
|
|
|
|
=head2 lock |
3258
|
|
|
|
|
|
|
|
3259
|
|
|
|
|
|
|
This method must be implemented by the driver package. |
3260
|
|
|
|
|
|
|
|
3261
|
|
|
|
|
|
|
=head2 login |
3262
|
|
|
|
|
|
|
|
3263
|
|
|
|
|
|
|
Sets or gets the C<login> property for this database object. |
3264
|
|
|
|
|
|
|
|
3265
|
|
|
|
|
|
|
=head2 no_bind |
3266
|
|
|
|
|
|
|
|
3267
|
|
|
|
|
|
|
When invoked, L</no_bind> will change any preparation made so far for caching the query with bind parameters, and instead substitute the value in lieu of the question mark placeholder. |
3268
|
|
|
|
|
|
|
|
3269
|
|
|
|
|
|
|
=head2 no_cache |
3270
|
|
|
|
|
|
|
|
3271
|
|
|
|
|
|
|
Disable caching of queries. |
3272
|
|
|
|
|
|
|
|
3273
|
|
|
|
|
|
|
=head2 NOT |
3274
|
|
|
|
|
|
|
|
3275
|
|
|
|
|
|
|
Returns a new L<DB::Object::NOT> object, passing it whatever arguments were provided. |
3276
|
|
|
|
|
|
|
|
3277
|
|
|
|
|
|
|
=head2 NULL |
3278
|
|
|
|
|
|
|
|
3279
|
|
|
|
|
|
|
Returns a C<NULL> string to be used in queries. |
3280
|
|
|
|
|
|
|
|
3281
|
|
|
|
|
|
|
=head2 on_conflict |
3282
|
|
|
|
|
|
|
|
3283
|
|
|
|
|
|
|
See L<DB::Object::Tables/on_conflict> |
3284
|
|
|
|
|
|
|
|
3285
|
|
|
|
|
|
|
=head2 OR |
3286
|
|
|
|
|
|
|
|
3287
|
|
|
|
|
|
|
Returns a new L<DB::Object::OR> object, passing it whatever arguments were provided. |
3288
|
|
|
|
|
|
|
|
3289
|
|
|
|
|
|
|
=head2 order |
3290
|
|
|
|
|
|
|
|
3291
|
|
|
|
|
|
|
See L<DB::Object::Tables/order> |
3292
|
|
|
|
|
|
|
|
3293
|
|
|
|
|
|
|
=head2 P |
3294
|
|
|
|
|
|
|
|
3295
|
|
|
|
|
|
|
Returns a L<DB::Object::Placeholder> object, passing it whatever arguments was provided. |
3296
|
|
|
|
|
|
|
|
3297
|
|
|
|
|
|
|
=head2 param |
3298
|
|
|
|
|
|
|
|
3299
|
|
|
|
|
|
|
If only a single parameter is provided, its value is return. If a list of parameters is provided they are set accordingly using the C<SET> sql command. |
3300
|
|
|
|
|
|
|
|
3301
|
|
|
|
|
|
|
Supported parameters are: |
3302
|
|
|
|
|
|
|
|
3303
|
|
|
|
|
|
|
=over 4 |
3304
|
|
|
|
|
|
|
|
3305
|
|
|
|
|
|
|
=item AUTOCOMMIT |
3306
|
|
|
|
|
|
|
|
3307
|
|
|
|
|
|
|
=item INSERT_ID |
3308
|
|
|
|
|
|
|
|
3309
|
|
|
|
|
|
|
=item LAST_INSERT_ID |
3310
|
|
|
|
|
|
|
|
3311
|
|
|
|
|
|
|
=item SQL_AUTO_IS_NULL |
3312
|
|
|
|
|
|
|
|
3313
|
|
|
|
|
|
|
=item SQL_BIG_SELECTS |
3314
|
|
|
|
|
|
|
|
3315
|
|
|
|
|
|
|
=item SQL_BIG_TABLES |
3316
|
|
|
|
|
|
|
|
3317
|
|
|
|
|
|
|
=item SQL_BUFFER_RESULT |
3318
|
|
|
|
|
|
|
|
3319
|
|
|
|
|
|
|
=item SQL_LOG_OFF |
3320
|
|
|
|
|
|
|
|
3321
|
|
|
|
|
|
|
=item SQL_LOW_PRIORITY_UPDATES |
3322
|
|
|
|
|
|
|
|
3323
|
|
|
|
|
|
|
=item SQL_MAX_JOIN_SIZE |
3324
|
|
|
|
|
|
|
|
3325
|
|
|
|
|
|
|
=item SQL_SAFE_MODE |
3326
|
|
|
|
|
|
|
|
3327
|
|
|
|
|
|
|
=item SQL_SELECT_LIMIT |
3328
|
|
|
|
|
|
|
|
3329
|
|
|
|
|
|
|
=item SQL_LOG_UPDATE |
3330
|
|
|
|
|
|
|
|
3331
|
|
|
|
|
|
|
=item TIMESTAMP |
3332
|
|
|
|
|
|
|
|
3333
|
|
|
|
|
|
|
=back |
3334
|
|
|
|
|
|
|
|
3335
|
|
|
|
|
|
|
If unsupported parameters are provided, they are considered to be private and not passed to the database handler. |
3336
|
|
|
|
|
|
|
|
3337
|
|
|
|
|
|
|
It then execute the query and return L<perlfunc/undef> in case of error. |
3338
|
|
|
|
|
|
|
|
3339
|
|
|
|
|
|
|
Otherwise, it returns the current object used to call the method. |
3340
|
|
|
|
|
|
|
|
3341
|
|
|
|
|
|
|
=head2 passwd |
3342
|
|
|
|
|
|
|
|
3343
|
|
|
|
|
|
|
Sets or gets the C<passwd> property for this database object. |
3344
|
|
|
|
|
|
|
|
3345
|
|
|
|
|
|
|
=head2 ping |
3346
|
|
|
|
|
|
|
|
3347
|
|
|
|
|
|
|
Evals a SELECT 1 statement and returns 0 if errors occurred or the return value. |
3348
|
|
|
|
|
|
|
|
3349
|
|
|
|
|
|
|
=head2 ping_select |
3350
|
|
|
|
|
|
|
|
3351
|
|
|
|
|
|
|
Will prepare and execute a simple C<SELECT 1> and return 0 upon failure or return the value returned from calling L<DBI/execute>. |
3352
|
|
|
|
|
|
|
|
3353
|
|
|
|
|
|
|
=head2 placeholder |
3354
|
|
|
|
|
|
|
|
3355
|
|
|
|
|
|
|
Same as L</P>. Returns a L<DB::Object::Placeholder> object, passing it whatever arguments was provided. |
3356
|
|
|
|
|
|
|
|
3357
|
|
|
|
|
|
|
=head2 port |
3358
|
|
|
|
|
|
|
|
3359
|
|
|
|
|
|
|
Sets or gets the C<port> property for this database object. |
3360
|
|
|
|
|
|
|
|
3361
|
|
|
|
|
|
|
=head2 prepare |
3362
|
|
|
|
|
|
|
|
3363
|
|
|
|
|
|
|
Provided with a sql query and some hash reference of options and this will prepare the query using the options provided. The options are the same as the one in L<DBI/prepare> method. |
3364
|
|
|
|
|
|
|
|
3365
|
|
|
|
|
|
|
It returns a L<DB::Object::Statement> object upon success or undef if an error occurred. The error can then be retrieved using L</errstr> or L</error>. |
3366
|
|
|
|
|
|
|
|
3367
|
|
|
|
|
|
|
=head2 prepare_cached |
3368
|
|
|
|
|
|
|
|
3369
|
|
|
|
|
|
|
Same as L</prepare> except the query is cached. |
3370
|
|
|
|
|
|
|
|
3371
|
|
|
|
|
|
|
=head2 query |
3372
|
|
|
|
|
|
|
|
3373
|
|
|
|
|
|
|
It prepares and executes the given SQL query with the options provided and return L<perlfunc/undef> upon error or the statement handler upon success. |
3374
|
|
|
|
|
|
|
|
3375
|
|
|
|
|
|
|
=head2 quote |
3376
|
|
|
|
|
|
|
|
3377
|
|
|
|
|
|
|
This is used to properly format data by surrounding them with quotes or not. |
3378
|
|
|
|
|
|
|
|
3379
|
|
|
|
|
|
|
Calls L<DBI/quote> and pass it whatever argument was provided. |
3380
|
|
|
|
|
|
|
|
3381
|
|
|
|
|
|
|
=head2 replace |
3382
|
|
|
|
|
|
|
|
3383
|
|
|
|
|
|
|
See L<DB::Object::Tables/replace> |
3384
|
|
|
|
|
|
|
|
3385
|
|
|
|
|
|
|
=head2 reset |
3386
|
|
|
|
|
|
|
|
3387
|
|
|
|
|
|
|
See L<DB::Object::Tables/reset> |
3388
|
|
|
|
|
|
|
|
3389
|
|
|
|
|
|
|
=head2 returning |
3390
|
|
|
|
|
|
|
|
3391
|
|
|
|
|
|
|
See L<DB::Object::Tables/returning> |
3392
|
|
|
|
|
|
|
|
3393
|
|
|
|
|
|
|
=head2 reverse |
3394
|
|
|
|
|
|
|
|
3395
|
|
|
|
|
|
|
See L<DB::Object::Tables/reverse> |
3396
|
|
|
|
|
|
|
|
3397
|
|
|
|
|
|
|
=head2 select |
3398
|
|
|
|
|
|
|
|
3399
|
|
|
|
|
|
|
See L<DB::Object::Tables/select> |
3400
|
|
|
|
|
|
|
|
3401
|
|
|
|
|
|
|
=head2 set |
3402
|
|
|
|
|
|
|
|
3403
|
|
|
|
|
|
|
Provided with variable and this will issue a query to C<SET> the given SQL variable. |
3404
|
|
|
|
|
|
|
|
3405
|
|
|
|
|
|
|
If any error occurred, undef will be returned and an error set, otherwise it returns true. |
3406
|
|
|
|
|
|
|
|
3407
|
|
|
|
|
|
|
=head2 sort |
3408
|
|
|
|
|
|
|
|
3409
|
|
|
|
|
|
|
See L<DB::Object::Tables/sort> |
3410
|
|
|
|
|
|
|
|
3411
|
|
|
|
|
|
|
=head2 stat |
3412
|
|
|
|
|
|
|
|
3413
|
|
|
|
|
|
|
Issue a C<SHOW STATUS> query and if a particular C<$type> is provided, it will return its value if it exists, otherwise it will return L<perlfunc/undef>. |
3414
|
|
|
|
|
|
|
|
3415
|
|
|
|
|
|
|
In absence of particular $type provided, it returns the hash list of values returns or a reference to the hash list in scalar context. |
3416
|
|
|
|
|
|
|
|
3417
|
|
|
|
|
|
|
=head2 state |
3418
|
|
|
|
|
|
|
|
3419
|
|
|
|
|
|
|
Queries the DBI state and return its value. |
3420
|
|
|
|
|
|
|
|
3421
|
|
|
|
|
|
|
=head2 supported_class |
3422
|
|
|
|
|
|
|
|
3423
|
|
|
|
|
|
|
Returns the list of driver packages such as L<DB::Object::Postgres> |
3424
|
|
|
|
|
|
|
|
3425
|
|
|
|
|
|
|
=head2 supported_drivers |
3426
|
|
|
|
|
|
|
|
3427
|
|
|
|
|
|
|
Returns the list of driver name such as L<Pg> |
3428
|
|
|
|
|
|
|
|
3429
|
|
|
|
|
|
|
=head2 table |
3430
|
|
|
|
|
|
|
|
3431
|
|
|
|
|
|
|
Given a table name, L</table> will return a L<DB::Object::Tables> object. The object is cached for re-use. |
3432
|
|
|
|
|
|
|
|
3433
|
|
|
|
|
|
|
When a cached table object is found, it is cloned and reset (using L</reset>), before it is returned to avoid undesirable effets in following query that would have some table properties set such as table alias. |
3434
|
|
|
|
|
|
|
|
3435
|
|
|
|
|
|
|
=head2 table_exists |
3436
|
|
|
|
|
|
|
|
3437
|
|
|
|
|
|
|
Provided with a table name and this returns true if the table exist or false otherwise. |
3438
|
|
|
|
|
|
|
|
3439
|
|
|
|
|
|
|
=head2 table_info |
3440
|
|
|
|
|
|
|
|
3441
|
|
|
|
|
|
|
This is a method that must be implemented by the driver package. |
3442
|
|
|
|
|
|
|
|
3443
|
|
|
|
|
|
|
=head2 table_push |
3444
|
|
|
|
|
|
|
|
3445
|
|
|
|
|
|
|
Add the given table name to the stack of cached table names. |
3446
|
|
|
|
|
|
|
|
3447
|
|
|
|
|
|
|
=head2 tables |
3448
|
|
|
|
|
|
|
|
3449
|
|
|
|
|
|
|
Connects to the database and finds out the list of all available tables. If cache is available, it will use it instead of querying the database server. |
3450
|
|
|
|
|
|
|
|
3451
|
|
|
|
|
|
|
Returns undef or empty list in scalar or list context respectively if no table found. |
3452
|
|
|
|
|
|
|
|
3453
|
|
|
|
|
|
|
Otherwise, it returns the list of table in list context or a reference of it in scalar context. |
3454
|
|
|
|
|
|
|
|
3455
|
|
|
|
|
|
|
=head2 tables_cache |
3456
|
|
|
|
|
|
|
|
3457
|
|
|
|
|
|
|
Returns the table cache object |
3458
|
|
|
|
|
|
|
|
3459
|
|
|
|
|
|
|
=head2 tables_info |
3460
|
|
|
|
|
|
|
|
3461
|
|
|
|
|
|
|
This is a method that must be implemented by the driver package. |
3462
|
|
|
|
|
|
|
|
3463
|
|
|
|
|
|
|
=head2 tables_refresh |
3464
|
|
|
|
|
|
|
|
3465
|
|
|
|
|
|
|
Rebuild the list of available database table. |
3466
|
|
|
|
|
|
|
|
3467
|
|
|
|
|
|
|
Returns the list of table in list context or a reference of it in scalar context. |
3468
|
|
|
|
|
|
|
|
3469
|
|
|
|
|
|
|
=head2 tie |
3470
|
|
|
|
|
|
|
|
3471
|
|
|
|
|
|
|
See L<DB::Object::Tables/tie> |
3472
|
|
|
|
|
|
|
|
3473
|
|
|
|
|
|
|
=head2 transaction |
3474
|
|
|
|
|
|
|
|
3475
|
|
|
|
|
|
|
True when a transaction has been started with L</begin_work>, false otherwise. |
3476
|
|
|
|
|
|
|
|
3477
|
|
|
|
|
|
|
=head2 TRUE |
3478
|
|
|
|
|
|
|
|
3479
|
|
|
|
|
|
|
Returns C<TRUE> to be used in queries. |
3480
|
|
|
|
|
|
|
|
3481
|
|
|
|
|
|
|
=head2 unix_timestamp |
3482
|
|
|
|
|
|
|
|
3483
|
|
|
|
|
|
|
See L<DB::Object::Tables/unix_timestamp> |
3484
|
|
|
|
|
|
|
|
3485
|
|
|
|
|
|
|
=head2 unlock |
3486
|
|
|
|
|
|
|
|
3487
|
|
|
|
|
|
|
This is a convenient wrapper around L<DB::Object::Query/unlock> |
3488
|
|
|
|
|
|
|
|
3489
|
|
|
|
|
|
|
=head2 update |
3490
|
|
|
|
|
|
|
|
3491
|
|
|
|
|
|
|
See L<DB::Object::Tables/update> |
3492
|
|
|
|
|
|
|
|
3493
|
|
|
|
|
|
|
=head2 use |
3494
|
|
|
|
|
|
|
|
3495
|
|
|
|
|
|
|
Given a database, it switch to it, but before it checks that the database exists. |
3496
|
|
|
|
|
|
|
If the database is different than the current one, it sets the I<multi_db> parameter, which will have the fields in the queries be prefixed by their respective database name. |
3497
|
|
|
|
|
|
|
|
3498
|
|
|
|
|
|
|
It returns the database handler. |
3499
|
|
|
|
|
|
|
|
3500
|
|
|
|
|
|
|
=head2 use_cache |
3501
|
|
|
|
|
|
|
|
3502
|
|
|
|
|
|
|
Provided with a boolean value and this sets or get the I<use_cache> parameter. |
3503
|
|
|
|
|
|
|
|
3504
|
|
|
|
|
|
|
=head2 use_bind |
3505
|
|
|
|
|
|
|
|
3506
|
|
|
|
|
|
|
Provided with a boolean value and this sets or get the I<use_cache> parameter. |
3507
|
|
|
|
|
|
|
|
3508
|
|
|
|
|
|
|
=head2 variables |
3509
|
|
|
|
|
|
|
|
3510
|
|
|
|
|
|
|
Query the SQL variable $type |
3511
|
|
|
|
|
|
|
|
3512
|
|
|
|
|
|
|
It returns a blank string if nothing was found, or the value found. |
3513
|
|
|
|
|
|
|
|
3514
|
|
|
|
|
|
|
=head2 version |
3515
|
|
|
|
|
|
|
|
3516
|
|
|
|
|
|
|
This is a method that must be implemented by the driver package. |
3517
|
|
|
|
|
|
|
|
3518
|
|
|
|
|
|
|
=head2 where |
3519
|
|
|
|
|
|
|
|
3520
|
|
|
|
|
|
|
See L<DB::Object::Tables/where> |
3521
|
|
|
|
|
|
|
|
3522
|
|
|
|
|
|
|
=head2 _cache_this |
3523
|
|
|
|
|
|
|
|
3524
|
|
|
|
|
|
|
Provided with a query, this will cache it for future re-use. |
3525
|
|
|
|
|
|
|
|
3526
|
|
|
|
|
|
|
It does some check and maintenance job to ensure the cache does not get too big whenever it exceed the value of $CACHE_SIZE set in the main config file. |
3527
|
|
|
|
|
|
|
|
3528
|
|
|
|
|
|
|
It returns the cached statement as an L<DB::Object::Statement> object. |
3529
|
|
|
|
|
|
|
|
3530
|
|
|
|
|
|
|
=head2 _check_connect_param |
3531
|
|
|
|
|
|
|
|
3532
|
|
|
|
|
|
|
Provided with an hash reference of connection parameters, this will get the valid parameters by calling L</_connection_parameters> and the connection default options by calling L</_connection_options> |
3533
|
|
|
|
|
|
|
|
3534
|
|
|
|
|
|
|
It returns the connection parameters hash reference. |
3535
|
|
|
|
|
|
|
|
3536
|
|
|
|
|
|
|
=head2 _check_default_option |
3537
|
|
|
|
|
|
|
|
3538
|
|
|
|
|
|
|
Provided with an hash reference of options, and it actually returns it, so this does not do much, because this method is supposed to be supereded by the driver package. |
3539
|
|
|
|
|
|
|
|
3540
|
|
|
|
|
|
|
=head2 _connection_options |
3541
|
|
|
|
|
|
|
|
3542
|
|
|
|
|
|
|
Provided with an hash reference of connection parameters and this will returns an hash reference of options whose keys match the regular expression C</^[A-Z][a-zA-Z]+/> |
3543
|
|
|
|
|
|
|
|
3544
|
|
|
|
|
|
|
So this does not do much, because this method is supposed to be superseded by the driver package. |
3545
|
|
|
|
|
|
|
|
3546
|
|
|
|
|
|
|
=head2 _connection_parameters |
3547
|
|
|
|
|
|
|
|
3548
|
|
|
|
|
|
|
Returns an array reference containing the following keys: db login passwd host port driver database server opt uri debug |
3549
|
|
|
|
|
|
|
|
3550
|
|
|
|
|
|
|
=head2 _connection_params2hash |
3551
|
|
|
|
|
|
|
|
3552
|
|
|
|
|
|
|
Provided with an hash reference of connection parameters and this will check if the following environment variables exists and if so use them: C<DB_NAME>, C<DB_LOGIN>, C<DB_PASSWD>, C<DB_HOST>, C<DB_PORT>, C<DB_DRIVER>, C<DB_SCHEMA> |
3553
|
|
|
|
|
|
|
|
3554
|
|
|
|
|
|
|
If the parameter property I<uri> was provided of if the environment variable C<DB_CON_URI> is set, it will use this connection uri to get the necessary connection parameters values. |
3555
|
|
|
|
|
|
|
|
3556
|
|
|
|
|
|
|
An L<URI> could be C<http://localhost:5432?database=somedb> or C<file:/foo/bar?opt={"RaiseError":true}> |
3557
|
|
|
|
|
|
|
|
3558
|
|
|
|
|
|
|
Alternatively, if the connection parameter I<conf_file> is provided then its json content will be read and decoded into an hash reference. |
3559
|
|
|
|
|
|
|
|
3560
|
|
|
|
|
|
|
The following keys can be used in the json data in the I<conf_file>: C<database>, C<login>, C<passwd>, C<host>, C<port>, C<driver>, C<schema>, C<opt> |
3561
|
|
|
|
|
|
|
|
3562
|
|
|
|
|
|
|
The port can be specified in the I<host> parameter by separating it with a semicolon such as C<localhost:5432> |
3563
|
|
|
|
|
|
|
|
3564
|
|
|
|
|
|
|
The I<opt> parameter can Alternatively be provided through the environment variable C<DB_OPT> |
3565
|
|
|
|
|
|
|
|
3566
|
|
|
|
|
|
|
It returns the hash reference of connection parameters. |
3567
|
|
|
|
|
|
|
|
3568
|
|
|
|
|
|
|
=head2 _clean_statement |
3569
|
|
|
|
|
|
|
|
3570
|
|
|
|
|
|
|
Given a query string or a reference to it, it cleans the statement by removing leading and trailing space before and after line breaks. |
3571
|
|
|
|
|
|
|
|
3572
|
|
|
|
|
|
|
It returns the cleaned up query as a string if the original query was provided as a scalar reference. |
3573
|
|
|
|
|
|
|
|
3574
|
|
|
|
|
|
|
=head2 _convert_datetime2object |
3575
|
|
|
|
|
|
|
|
3576
|
|
|
|
|
|
|
Provided with an hash or hash reference of options and this will simply return the I<data> property. |
3577
|
|
|
|
|
|
|
|
3578
|
|
|
|
|
|
|
This does not do anything meaningful, because it is supposed to be superseded by the diver package. |
3579
|
|
|
|
|
|
|
|
3580
|
|
|
|
|
|
|
=head2 _convert_json2hash |
3581
|
|
|
|
|
|
|
|
3582
|
|
|
|
|
|
|
Provided with an hash or hash reference of options and this will simply return the I<data> property. |
3583
|
|
|
|
|
|
|
|
3584
|
|
|
|
|
|
|
This does not do anything meaningful, because it is supposed to be superseded by the diver package. |
3585
|
|
|
|
|
|
|
|
3586
|
|
|
|
|
|
|
=head2 _dbi_connect |
3587
|
|
|
|
|
|
|
|
3588
|
|
|
|
|
|
|
This will call L</_dsn> which must exist in the driver package, and based on the C<dsn> received, this will initiate a L<DBI/connect_cache> if the object property L</cache_connections> has a true value, or simply a L<DBI/connect> otherwise. |
3589
|
|
|
|
|
|
|
|
3590
|
|
|
|
|
|
|
It returns the database handler. |
3591
|
|
|
|
|
|
|
|
3592
|
|
|
|
|
|
|
=head2 _decode_json |
3593
|
|
|
|
|
|
|
|
3594
|
|
|
|
|
|
|
Provided with some json data and this will decode it using L<JSON> and return the associated hash reference or L<perlfunc/undef> if an error occurred. |
3595
|
|
|
|
|
|
|
|
3596
|
|
|
|
|
|
|
=head2 _dsn |
3597
|
|
|
|
|
|
|
|
3598
|
|
|
|
|
|
|
This will die complaining the driver has not implemented this method, unless the driver did implement it. |
3599
|
|
|
|
|
|
|
|
3600
|
|
|
|
|
|
|
=head2 _encode_json |
3601
|
|
|
|
|
|
|
|
3602
|
|
|
|
|
|
|
Provided with an hash reference and this will encode it into a json string and return it. |
3603
|
|
|
|
|
|
|
|
3604
|
|
|
|
|
|
|
=head2 _make_sth |
3605
|
|
|
|
|
|
|
|
3606
|
|
|
|
|
|
|
Given a package name and a hash reference, this builds a statement object with all the necessary parameters. |
3607
|
|
|
|
|
|
|
|
3608
|
|
|
|
|
|
|
It also sets the query time to the current time with the parameter I<query_time> |
3609
|
|
|
|
|
|
|
|
3610
|
|
|
|
|
|
|
It returns an object of the given $package. |
3611
|
|
|
|
|
|
|
|
3612
|
|
|
|
|
|
|
=head2 _param2hash |
3613
|
|
|
|
|
|
|
|
3614
|
|
|
|
|
|
|
Provided with some hash reference parameters and this will simply return it, so it does not do anything meaningful. |
3615
|
|
|
|
|
|
|
|
3616
|
|
|
|
|
|
|
This is supposed to be superseded by the driver package. |
3617
|
|
|
|
|
|
|
|
3618
|
|
|
|
|
|
|
=head2 _process_limit |
3619
|
|
|
|
|
|
|
|
3620
|
|
|
|
|
|
|
A convenient wrapper around the L<DB::Object::Query/_process_limit> |
3621
|
|
|
|
|
|
|
|
3622
|
|
|
|
|
|
|
=head2 _query_object_add |
3623
|
|
|
|
|
|
|
|
3624
|
|
|
|
|
|
|
Provided with a L<DB::Object::Query> and this will add it to the current object property I<query_object> and return it. |
3625
|
|
|
|
|
|
|
|
3626
|
|
|
|
|
|
|
=head2 _query_object_create |
3627
|
|
|
|
|
|
|
|
3628
|
|
|
|
|
|
|
This is supposed to be called from a L<DB::Object::Tables> |
3629
|
|
|
|
|
|
|
|
3630
|
|
|
|
|
|
|
Create a new L<DB::Object::Query> object, sets the I<debug> and I<verbose> values and sets its property L<DB::Object::Query/table_object> to the value of the current object. |
3631
|
|
|
|
|
|
|
|
3632
|
|
|
|
|
|
|
=head2 _query_object_current |
3633
|
|
|
|
|
|
|
|
3634
|
|
|
|
|
|
|
Returns the current I<query_object> |
3635
|
|
|
|
|
|
|
|
3636
|
|
|
|
|
|
|
=head2 _query_object_get_or_create |
3637
|
|
|
|
|
|
|
|
3638
|
|
|
|
|
|
|
Check to see if the L</query_object> is already set and then return its value, otherwise create a new object by calling L</_query_object_create> and return it. |
3639
|
|
|
|
|
|
|
|
3640
|
|
|
|
|
|
|
=head2 _query_object_remove |
3641
|
|
|
|
|
|
|
|
3642
|
|
|
|
|
|
|
Provided with a L<DB::Object::Query> and this will remove it from the current object property I<query_object>. |
3643
|
|
|
|
|
|
|
|
3644
|
|
|
|
|
|
|
It returns the object removed. |
3645
|
|
|
|
|
|
|
|
3646
|
|
|
|
|
|
|
=head2 _reset_query |
3647
|
|
|
|
|
|
|
|
3648
|
|
|
|
|
|
|
If this has not already been reset, this will mark the current query object as reset and calls L</_query_object_remove> and return the value for L</_query_object_get_or_create> |
3649
|
|
|
|
|
|
|
|
3650
|
|
|
|
|
|
|
If it has been already reset, this will return the value for L</_query_object_current> |
3651
|
|
|
|
|
|
|
|
3652
|
|
|
|
|
|
|
=head1 OPERATORS |
3653
|
|
|
|
|
|
|
|
3654
|
|
|
|
|
|
|
=head2 ALL( VALUES ) |
3655
|
|
|
|
|
|
|
|
3656
|
|
|
|
|
|
|
This operator is used to query an array where all elements must match. |
3657
|
|
|
|
|
|
|
|
3658
|
|
|
|
|
|
|
my $tbl = $dbh->hosts || die( "Uable to get table object 'hosts'." ); |
3659
|
|
|
|
|
|
|
$tbl->where( $dbh->OR( |
3660
|
|
|
|
|
|
|
$tbl->fo->name == 'example.com', |
3661
|
|
|
|
|
|
|
'example.com' == $dbh->ALL( $tbl->fo->alias ) |
3662
|
|
|
|
|
|
|
)); |
3663
|
|
|
|
|
|
|
my $sth = $tbl->select || die( "Failed to prepare query to get host information: ", $tbl->error ); |
3664
|
|
|
|
|
|
|
my $ref = $sth->fetchrow_hashref; |
3665
|
|
|
|
|
|
|
|
3666
|
|
|
|
|
|
|
See L<PostgreSQL documentation|https://www.postgresql.org/docs/current/arrays.html> |
3667
|
|
|
|
|
|
|
|
3668
|
|
|
|
|
|
|
=head2 AND( VALUES ) |
3669
|
|
|
|
|
|
|
|
3670
|
|
|
|
|
|
|
Given a value, this returns a L<DB::Object::AND> object. You can retrieve the value with L<DB::Object::AND/value> |
3671
|
|
|
|
|
|
|
|
3672
|
|
|
|
|
|
|
This is used by L</where> |
3673
|
|
|
|
|
|
|
|
3674
|
|
|
|
|
|
|
my $op = $dbh->AND( login => 'joe', status => 'active' ); |
3675
|
|
|
|
|
|
|
# will produce: |
3676
|
|
|
|
|
|
|
WHERE login = 'joe' AND status = 'active' |
3677
|
|
|
|
|
|
|
|
3678
|
|
|
|
|
|
|
=head2 ANY( VALUES ) |
3679
|
|
|
|
|
|
|
|
3680
|
|
|
|
|
|
|
This operator is used to query an array where all elements must match. |
3681
|
|
|
|
|
|
|
|
3682
|
|
|
|
|
|
|
my $tbl = $dbh->hosts || die( "Uable to get table object 'hosts'." ); |
3683
|
|
|
|
|
|
|
$tbl->where( $dbh->OR( |
3684
|
|
|
|
|
|
|
$tbl->fo->name == 'example.com', |
3685
|
|
|
|
|
|
|
'example.com' == $dbh->ANY( $tbl->fo->alias ) |
3686
|
|
|
|
|
|
|
)); |
3687
|
|
|
|
|
|
|
my $sth = $tbl->select || die( "Failed to prepare query to get host information: ", $tbl->error ); |
3688
|
|
|
|
|
|
|
my $ref = $sth->fetchrow_hashref; |
3689
|
|
|
|
|
|
|
|
3690
|
|
|
|
|
|
|
See L<PostgreSQL documentation|https://www.postgresql.org/docs/current/arrays.html> |
3691
|
|
|
|
|
|
|
|
3692
|
|
|
|
|
|
|
=head2 IN |
3693
|
|
|
|
|
|
|
|
3694
|
|
|
|
|
|
|
For example: |
3695
|
|
|
|
|
|
|
|
3696
|
|
|
|
|
|
|
SELECT |
3697
|
|
|
|
|
|
|
c.code, c.name, c.name_l10n, c.locale |
3698
|
|
|
|
|
|
|
FROM country_locale AS c |
3699
|
|
|
|
|
|
|
WHERE |
3700
|
|
|
|
|
|
|
c.locale = 'fr_FR' OR |
3701
|
|
|
|
|
|
|
('fr_FR' NOT IN (SELECT DISTINCT l.locale FROM country_locale AS l ORDER BY l.locale) AND |
3702
|
|
|
|
|
|
|
c.locale = 'en_GB') |
3703
|
|
|
|
|
|
|
ORDER BY c.code |
3704
|
|
|
|
|
|
|
|
3705
|
|
|
|
|
|
|
my $tbl = $dbh->country_locale || die( $dbh->error ); |
3706
|
|
|
|
|
|
|
my $tbl2 = $dbh->country_locale || die( $dbh->error ); |
3707
|
|
|
|
|
|
|
$tbl2->as( 'l' ); |
3708
|
|
|
|
|
|
|
$tbl2->order( 'locale' ); |
3709
|
|
|
|
|
|
|
my $sth2 = $tbl2->select( 'DISTINCT locale' ) || die( $tbl2->error ); |
3710
|
|
|
|
|
|
|
|
3711
|
|
|
|
|
|
|
$tbl->as( 'c' ); |
3712
|
|
|
|
|
|
|
$tbl->where( $dbh->OR( |
3713
|
|
|
|
|
|
|
$tbl->fo->locale == 'fr_FR', |
3714
|
|
|
|
|
|
|
$dbh->AND( |
3715
|
|
|
|
|
|
|
'fr_FR' != $dbh->IN( $sth2 ), |
3716
|
|
|
|
|
|
|
$tbl->fo->locale == 'en_GB' |
3717
|
|
|
|
|
|
|
) |
3718
|
|
|
|
|
|
|
) ); |
3719
|
|
|
|
|
|
|
|
3720
|
|
|
|
|
|
|
$tbl->order( $tbl->fo->code ); |
3721
|
|
|
|
|
|
|
my $sth = $tbl->select( qw( code name name_l10n locale ) ) || die( $tbl->error ); |
3722
|
|
|
|
|
|
|
say $sth->as_string; |
3723
|
|
|
|
|
|
|
|
3724
|
|
|
|
|
|
|
=head2 NOT( VALUES ) |
3725
|
|
|
|
|
|
|
|
3726
|
|
|
|
|
|
|
Given a value, this returns a L<DB::Object::NOT> object. You can retrieve the value with L<DB::Object::NOT/value> |
3727
|
|
|
|
|
|
|
|
3728
|
|
|
|
|
|
|
This is used by L</where> |
3729
|
|
|
|
|
|
|
|
3730
|
|
|
|
|
|
|
my $op = $dbh->AND( login => 'joe', status => $dbh->NOT( 'active' ) ); |
3731
|
|
|
|
|
|
|
# will produce: |
3732
|
|
|
|
|
|
|
WHERE login = 'joe' AND status != 'active' |
3733
|
|
|
|
|
|
|
|
3734
|
|
|
|
|
|
|
=head2 OR( VALUES ) |
3735
|
|
|
|
|
|
|
|
3736
|
|
|
|
|
|
|
Given a value, this returns a L<DB::Object::OR> object. You can retrieve the value with L<DB::Object::OR/value> |
3737
|
|
|
|
|
|
|
|
3738
|
|
|
|
|
|
|
This is used by L</where> |
3739
|
|
|
|
|
|
|
|
3740
|
|
|
|
|
|
|
my $op = $dbh->OR( login => 'joe', login => 'john' ); |
3741
|
|
|
|
|
|
|
# will produce: |
3742
|
|
|
|
|
|
|
WHERE login = 'joe' OR login = 'john' |
3743
|
|
|
|
|
|
|
|
3744
|
|
|
|
|
|
|
=head1 SEE ALSO |
3745
|
|
|
|
|
|
|
|
3746
|
|
|
|
|
|
|
L<DBI>, L<Apache::DBI> |
3747
|
|
|
|
|
|
|
|
3748
|
|
|
|
|
|
|
=head1 AUTHOR |
3749
|
|
|
|
|
|
|
|
3750
|
|
|
|
|
|
|
Jacques Deguest E<lt>F<jack@deguest.jp>E<gt> |
3751
|
|
|
|
|
|
|
|
3752
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
3753
|
|
|
|
|
|
|
|
3754
|
|
|
|
|
|
|
Copyright (c) 2019-2021 DEGUEST Pte. Ltd. |
3755
|
|
|
|
|
|
|
|
3756
|
|
|
|
|
|
|
You can use, copy, modify and redistribute this package and associated |
3757
|
|
|
|
|
|
|
files under the same terms as Perl itself. |
3758
|
|
|
|
|
|
|
|
3759
|
|
|
|
|
|
|
=cut |