File Coverage

lib/DB/Object.pm
Criterion Covered Total %
statement 261 1220 21.3
branch 24 542 4.4
condition 11 394 2.7
subroutine 72 225 32.0
pod 84 85 98.8
total 452 2466 18.3


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