ensembl-hive  2.6
DBConnection.pm
Go to the documentation of this file.
1 =head1 LICENSE
2 
3 Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
4 Copyright [2016-2024] EMBL-European Bioinformatics Institute
5 
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9 
10  http://www.apache.org/licenses/LICENSE-2.0
11 
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 
18 =cut
19 
20 
21 =head1 CONTACT
22 
23  Please email comments or questions to the public Ensembl
24  developers list at <http://lists.ensembl.org/mailman/listinfo/dev>.
25 
26  Questions may also be sent to the Ensembl help desk at
27  <http://www.ensembl.org/Help/Contact>.
28 
29 =cut
30 
31 =head1 NAME
32 
34 
35 =head1 SYNOPSIS
36 
38  -user => 'anonymous',
39  -dbname => 'homo_sapiens_core_20_34c',
40  -host => 'ensembldb.ensembl.org',
41  -driver => 'mysql',
42  );
43 
44  # SQL statements should be created/executed through this modules
45  # prepare() and do() methods.
46 
47  $sth = $dbc->prepare("SELECT something FROM yourtable");
48 
49  $sth->execute();
50 
51  # do something with rows returned ...
52 
53  $sth->finish();
54 
55 =head1 DESCRIPTION
56 
57 This class is a wrapper around DBIs datbase handle. It provides some
58 additional functionality such as the ability to automatically disconnect
59 when inactive and reconnect when needed.
60 
61 Generally this class will be used through one of the object adaptors or
62 the Bio::EnsEMBL::Registry and will not be instantiated directly.
63 
64 =head1 METHODS
65 
66 =cut
67 
68 
70 
71 use vars qw(@ISA);
72 use strict;
73 
74 use DBI;
75 
77 
78 use Bio::EnsEMBL::Utils::Exception qw/deprecate throw warning/;
79 use Bio::EnsEMBL::Utils::Argument qw/rearrange/;
80 use Bio::EnsEMBL::Utils::Scalar qw/assert_ref wrap_array/;
82 
83 =head2 new
84 
85  Arg [DBNAME] : (optional) string
86  The name of the database to connect to.
87  Arg [HOST] : (optional) string
88  The domain name of the database host to connect to.
89  'localhost' by default.
90  Arg [USER] : string
91  The name of the database user to connect with
92  Arg [PASS] : (optional) string
93  The password to be used to connect to the database
94  Arg [PORT] : (optional) int
95  The port to use when connecting to the database
96  3306 by default if the driver is mysql.
97  Arg [DRIVER] : (optional) string
98  The type of database driver to use to connect to the DB
99  mysql by default.
100  Arg [DBCONN] : (optional)
101  Open another handle to the same database as another connection
102  If this argument is specified, no other arguments should be
103  specified.
104  Arg [DISCONNECT_WHEN_INACTIVE]: (optional) boolean
105  If set to true, the database connection will be disconnected
106  everytime there are no active statement handles. This is
107  useful when running a lot of jobs on a compute farm
108  which would otherwise keep open a lot of connections to the
109  database. Database connections are automatically reopened
110  when required.Do not use this option together with RECONNECT_WHEN_CONNECTION_LOST.
111  Arg [WAIT_TIMEOUT]: (optional) integer
112  Time in seconds for the wait timeout to happen. Time after which
113  the connection is deleted if not used. By default this is 28800 (8 hours)
114  on most systems.
115  So set this to greater than this if your connection are getting deleted.
116  Only set this if you are having problems and know what you are doing.
117  Arg [RECONNECT_WHEN_CONNECTION_LOST]: (optional) boolean
118  In case you're reusing the same database connection, i.e. DISCONNECT_WHEN_INACTIVE is
119  set to false and running a job which takes a long time to process (over 8hrs),
120  which means that the db connection may be lost, set this option to true.
121  On each prepare or do statement the db handle will be pinged and the database
122  connection will be reconnected if it's lost.
123 
124  Example : $dbc = Bio::EnsEMBL::DBSQL::DBConnection->new
125  (-user => 'anonymous',
126  -dbname => 'homo_sapiens_core_20_34c',
127  -host => 'ensembldb.ensembl.org',
128  -driver => 'mysql');
129 
130  Description: Constructor for a Database Connection. Any adaptors that require
131  database connectivity should inherit from this class.
133  Exceptions : thrown if USER or DBNAME are not specified, or if the database
134  cannot be connected to.
135  Caller : Bio::EnsEMBL::Utils::ConfigRegistry ( for newer code using the registry)
136  Bio::EnsEMBL::DBSQL::DBAdaptor ( for old style code)
137  Status : Stable
138 
139 =cut
140 
141 sub new {
142  my $class = shift;
143 
144  my (
145  $db, $host, $driver_arg,
146  $user, $password, $port,
147  $inactive_disconnect, $dbconn, $wait_timeout, $reconnect
148  )
149  = rearrange( [
150  'DBNAME', 'HOST', 'DRIVER', 'USER', 'PASS', 'PORT',
151  'DISCONNECT_WHEN_INACTIVE', 'DBCONN', 'WAIT_TIMEOUT', 'RECONNECT_WHEN_CONNECTION_LOST'
152  ],
153  @_
154  );
155 
156  my $self = {};
157  bless $self, $class;
158 
159  my $driver = $dbconn ? $dbconn->driver() : $driver_arg;
160  $driver ||= 'mysql';
161  if ($driver eq 'pgsql') {
162  deprecate("Using 'pgsql' as an alias for the 'Pg' driver is deprecated.");
163  $driver = 'Pg';
164  }
165  $self->driver($driver);
166 
167  my $driver_class = 'Bio::EnsEMBL::DBSQL::Driver::' . $driver;
168  eval "require $driver_class"; ## no critic
169  throw("Cannot load '$driver_class': $@") if $@;
170  my $driver_object = $driver_class->new($self);
171  $self->_driver_object($driver_object);
172 
173  if($dbconn) {
174  if($db || $host || $driver_arg || $password || $port || $inactive_disconnect || $reconnect) {
175  throw("Cannot specify other arguments when -DBCONN argument used.");
176  }
177 
178  $self->host($dbconn->host());
179  $self->port($dbconn->port());
180  $self->username($dbconn->username());
181  $self->password($dbconn->password());
182  $self->dbname($dbconn->dbname());
183 
184  if($dbconn->disconnect_when_inactive()) {
185  $self->disconnect_when_inactive(1);
186  }
187  } else {
188 
189  if($driver eq 'mysql') {
190  $user || throw("-USER argument is required.");
191  $host ||= 'mysql';
192  if(!defined($port)){
193  $port = 3306;
194  if($host eq "ensembldb.ensembl.org"){
195  if( $db =~ /\w+_\w+_\w+_(\d+)/){
196  if($1 >= 48){
197  $port = 5306;
198  }
199  }
200  }
201  }
202  } elsif($driver eq 'pgsql') {
203  if(!defined($port)){
204  $port = 5432;
205  }
206  }
207 
208  $wait_timeout ||= 0;
209 
210  $self->host( $host );
211  $self->port($port);
212  $self->username( $user );
213  $self->password( $password );
214  $self->dbname( $db );
215  $self->timeout($wait_timeout);
216 
217  if($inactive_disconnect) {
218  $self->disconnect_when_inactive($inactive_disconnect);
219  }
220  if($reconnect) {
221  $self->reconnect_when_lost($reconnect);
222  }
223  }
224 
225 # if(defined $dnadb) {
226 # $self->dnadb($dnadb);
227 # }
228  return $self;
229 }
230 
231 
232 =head2 connect
233 
234  Example : $dbcon->connect()
235  Description: Connects to the database using the connection attribute
236  information.
237  Returntype : none
238  Exceptions : none
239  Caller : new, db_handle
240  Status : Stable
241 
242 =cut
243 
244 sub connect {
245  my ($self) = @_;
246 
247  if ( $self->connected() ) { return }
248 
249  $self->connected(1);
250 
251  if ( defined( $self->db_handle() ) and $self->db_handle()->ping() ) {
252  warning( "unconnected db_handle is still pingable, "
253  . "reseting connected boolean\n" );
254  }
255 
256  my $dbh;
257 
258  my $params = $self->_driver_object->connect_params($self);
259  eval {
260  $dbh = DBI->connect( @{$params}{qw(dsn username password attributes)} );
261  };
262  my $error = $@;
263 
264  if ( !$dbh || $error || !$dbh->ping() ) {
265 
266  my $dsn = $params->{dsn};
267  warn( "Could not connect to database "
268  . $self->dbname()
269  . " as user "
270  . $self->username()
271  . " using [$dsn] as a locator:\n"
272  . $error );
273 
274  $self->connected(0);
275 
276  throw( "Could not connect to database "
277  . $self->dbname()
278  . " as user "
279  . $self->username()
280  . " using [$dsn] as a locator:\n"
281  . $error );
282  }
283 
284  $self->db_handle($dbh);
285 
286  if ( $self->timeout() ) {
287  $self->_driver_object->set_wait_timeout( $dbh, $self->timeout() );
288  }
289 
290  #print("CONNECT\n");
291 } ## end sub connect
292 
293 
294 =head2 connected
295 
296  Example : $dbcon->connected()
297  Description: Boolean which tells if DBConnection is connected or not.
298  State is set internally, and external processes should not alter state.
299  Returntype : undef or 1
300  Exceptions : none
301  Caller : db_handle, connect, disconnect_if_idle, user processes
302  Status : Stable
303 
304 =cut
305 
306 sub connected {
307  my $self = shift;
308 
309  # Use the process id ($$) as part of the key for the connected flag.
310  # This forces the opening of another connection in a forked subprocess.
311  $self->{'connected'.$$} = shift if(@_);
312  return $self->{'connected'.$$};
313 }
314 
315 sub disconnect_count {
316  my $self = shift;
317  return $self->{'disconnect_count'} = shift if(@_);
318  $self->{'disconnect_count'}=0 unless(defined($self->{'disconnect_count'}));
319  return $self->{'disconnect_count'};
320 }
321 
322 sub timeout{
323  my($self, $arg ) = @_;
324 
325  (defined $arg) &&
326  ($self->{_timeout} = $arg );
327 
328  return $self->{_timeout};
329 
330 }
331 
332 sub query_count {
333  my $self = shift;
334  return $self->{'_query_count'} = shift if(@_);
335  $self->{'_query_count'}=0 unless(defined($self->{'_query_count'}));
336  return $self->{'_query_count'};
337 }
338 
339 =head2 equals
340 
341  Example : warn 'Same!' if($dbc->equals($other_dbc));
342  Description: Equality checker for DBConnection objects
343  Returntype : boolean
344  Exceptions : none
345  Caller : new
346  Status : Stable
347 
348 =cut
349 
350 
351 sub equals {
352  my ( $self, $dbc ) = @_;
353  return 0 if ! defined $dbc;
354  my $return = 0;
355  my $undef_str = q{!-undef-!};
356  my $undef_num = -1;
357 
358  $return = 1 if (
359  (($self->host() || $undef_str) eq ($dbc->host() || $undef_str)) &&
360  (($self->dbname() || $undef_str) eq ($dbc->dbname() || $undef_str)) &&
361  (($self->port() || $undef_num) == ($dbc->port() || $undef_num)) &&
362  (($self->username() || $undef_str) eq ($dbc->username() || $undef_str)) &&
363  ($self->driver() eq $dbc->driver())
364  );
365 
366  return $return;
367 }
368 
369 =head2 driver
370 
371  Arg [1] : (optional) string $arg
372  the name of the driver to use to connect to the database
373  Example : $driver = $db_connection->driver()
374  Description: Getter / Setter for the driver this connection uses.
375  Right now there is no point to setting this value after a
376  connection has already been established in the constructor.
377  Returntype : string
378  Exceptions : none
379  Caller : new
380  Status : Stable
381 
382 =cut
383 
384 sub driver {
385  my($self, $arg ) = @_;
386 
387  (defined $arg) &&
388  ($self->{_driver} = $arg );
389  return $self->{_driver};
390 }
391 
392 
393 =head2 port
394 
395  Arg [1] : (optional) int $arg
396  the TCP or UDP port to use to connect to the database
397  Example : $port = $db_connection->port();
398  Description: Getter / Setter for the port this connection uses to communicate
399  to the database daemon. There currently is no point in
400  setting this value after the connection has already been
401  established by the constructor.
402  Returntype : string
403  Exceptions : none
404  Caller : new
405  Status : Stable
406 
407 =cut
408 
409 sub port {
410  my ( $self, @args ) = @_;
411 
412  if ( @args ) {
413  $self->{'_port'} = $args[0];
414  }
415 
416  return $self->{'_port'};
417 }
418 
419 
420 =head2 dbname
421 
422  Arg [1] : (optional) string $arg
423  The new value of the database name used by this connection.
424  Example : $dbname = $db_connection->dbname()
425  Description: Getter/Setter for the name of the database used by this
426  connection. There is currently no point in setting this value
427  after the connection has already been established by the
428  constructor.
429  Returntype : string
430  Exceptions : none
431  Caller : new
432  Status : Stable
433 
434 =cut
435 
436 sub dbname {
437  my ($self, @args ) = @_;
438  ( @args ) &&
439  ( $self->{_dbname} = $args[0] );
440  $self->{_dbname};
441 }
442 
443 
444 =head2 username
445 
446  Arg [1] : (optional) string $arg
447  The new value of the username used by this connection.
448  Example : $username = $db_connection->username()
449  Description: Getter/Setter for the username used by this
450  connection. There is currently no point in setting this value
451  after the connection has already been established by the
452  constructor.
453  Returntype : string
454  Exceptions : none
455  Caller : new
456  Status : Stable
457 
458 =cut
459 
460 sub username {
461  my ($self, @args ) = @_;
462  ( @args ) &&
463  ( $self->{_username} = $args[0] );
464  $self->{_username};
465 }
466 
467 =head2 user
468 
469  Arg [1] : (optional) string $arg
470  The new value of the username used by this connection.
471  Example : $user = $db_connection->user()
472  Description: Convenience alias for the username method
473  Returntype : String
474 
475 =cut
476 
477 sub user {
478  my ($self, @args) = @_;
479  return $self->username(@args);
480 }
481 
482 
483 =head2 host
484 
485  Arg [1] : (optional) string $arg
486  The new value of the host used by this connection.
487  Example : $host = $db_connection->host()
488  Description: Getter/Setter for the domain name of the database host use by
489  this connection. There is currently no point in setting
490  this value after the connection has already been established
491  by the constructor.
492  Returntype : string
493  Exceptions : none
494  Caller : new
495  Status : Stable
496 
497 =cut
498 
499 sub host {
500  my ($self, @args ) = @_;
501  ( @args ) &&
502  ( $self->{_host} = $args[0] );
503  $self->{_host};
504 }
505 
506 =head2 hostname
507 
508  Arg [1] : (optional) string $arg
509  The new value of the host used by this connection.
510  Example : $hostname = $db_connection->hostname()
511  Description: Convenience alias for the host method
512  Returntype : String
513 
514 =cut
515 
516 sub hostname {
517  my ($self, @args) = @_;
518  return $self->host(@args);
519 }
520 
521 
522 =head2 password
523 
524  Arg [1] : (optional) string $arg
525  The new value of the password used by this connection.
526  Example : $host = $db_connection->password()
527  Description: Getter/Setter for the password of to use for this
528  connection. There is currently no point in setting
529  this value after the connection has already been
530  established by the constructor.
531  Returntype : string
532  Exceptions : none
533  Caller : new
534  Status : Stable
535 
536 =cut
537 
538 sub password {
539  my ( $self, @args ) = @_;
540 
541  if ( @args ) {
542  # Use an anonymous subroutine that will return the password when
543  # invoked. This will prevent the password from being accidentally
544  # displayed when using e.g. Data::Dumper on a structure containing
545  # one of these objects.
546 
547  $self->{_password} = sub { $args[0] };
548  }
549 
550  return ( ref( $self->{_password} ) && &{ $self->{_password} } ) || '';
551 }
552 
553 =head2 pass
554 
555  Arg [1] : (optional) string $arg
556  The new value of the password used by this connection.
557  Example : $pass = $db_connection->pass()
558  Description: Convenience alias for the password method
559  Returntype : String
560 
561 =cut
562 
563 sub pass {
564  my ($self, @args) = @_;
565  return $self->password(@args);
566 }
567 
568 =head2 disconnect_when_inactive
569 
570  Arg [1] : (optional) boolean $newval
571  Example : $db->disconnect_when_inactive(1);
572  Description: Getter/Setter for the disconnect_when_inactive flag. If set
573  to true this DBConnection will continually disconnect itself
574  when there are no active statement handles and reconnect as
575  necessary. Useful for farm environments when there can be
576  many (often inactive) open connections to a database at once.
577  Returntype : boolean
578  Exceptions : none
579  Caller : Pipeline
580  Status : Stable
581 
582 =cut
583 
584 sub disconnect_when_inactive {
585  my ( $self, $value ) = @_;
586 
587  if ( defined($value) ) {
588  $self->{'disconnect_when_inactive'} = $value;
589  if ($value) {
590  $self->disconnect_if_idle();
591  }
592  }
593 
594  return $self->{'disconnect_when_inactive'};
595 }
596 
597 
598 =head2 reconnect_when_lost
599 
600  Arg [1] : (optional) boolean $newval
601  Example : $db->reconnect_when_lost(1);
602  Description: Getter/Setter for the reconnect_when_lost flag. If set
603  to true the db handle will be pinged on each prepare or do statement
604  and the connection will be reestablished in case it's lost.
605  Useful for long running jobs (over 8hrs), which means that the db
606  connection may be lost.
607  Returntype : boolean
608  Exceptions : none
609  Caller : Pipeline
610  Status : Stable
611 
612 =cut
613 
614 sub reconnect_when_lost {
615  my ( $self, $value ) = @_;
616 
617  if ( defined($value) ) {
618  $self->{'reconnect_when_lost'} = $value;
619  }
620 
621  return $self->{'reconnect_when_lost'};
622 }
623 
624 
625 
626 =head2 locator
627 
628  Arg [1] : none
629  Example : $locator = $dbc->locator;
630  Description: Constructs a locator string for this database connection
631  that can, for example, be used by the DBLoader module
632  Returntype : string
633  Exceptions : none
634  Caller : general
635  Status : Stable
636 
637 =cut
638 
639 
640 sub locator {
641  my ($self) = @_;
642 
643  return sprintf(
644  "%s/host=%s;port=%s;dbname=%s;user=%s;pass=%s",
645  ref($self), $self->host(), $self->port(),
646  $self->dbname(), $self->username(), $self->password() );
647 }
648 
649 
650 =head2 db_handle
651 
652  Arg [1] : DBI Database Handle $value
653  Example : $dbh = $db_connection->db_handle()
654  Description: Getter / Setter for the Database handle used by this
655  database connection.
656  Returntype : DBI Database Handle
657  Exceptions : none
658  Caller : new, DESTROY
659  Status : Stable
660 
661 =cut
662 
663 sub db_handle {
664  my $self = shift;
665 
666  # Use the process id ($$) as part of the key for the database handle
667  # this makes this object fork safe. fork() does not makes copies
668  # of the open socket which creates problems when one of the forked
669  # processes disconnects,
670  return $self->{'db_handle'.$$} = shift if(@_);
671  return $self->{'db_handle'.$$} if($self->connected);
672 
673  $self->connect();
674  return $self->{'db_handle'.$$};
675 }
676 
677 
678 =head2 prepare
679 
680  Arg [1] : string $string
681  the SQL statement to prepare
682  Example : $sth = $db_connection->prepare("SELECT column FROM table");
683  Description: Prepares a SQL statement using the internal DBI database handle
684  and returns the DBI statement handle.
685  Returntype : DBI statement handle
686  Exceptions : thrown if the SQL statement is empty, or if the internal
687  database handle is not present
688  Caller : Adaptor modules
689  Status : Stable
690 
691 =cut
692 
693 sub prepare {
694  my ($self,@args) = @_;
695 
696  if( ! $args[0] ) {
697  throw("Attempting to prepare an empty SQL query.");
698  }
699 
700  #warn "SQL(".$self->dbname."):" . join(' ', @args) . "\n";
701  if ( ($self->reconnect_when_lost()) and (!$self->db_handle()->ping()) ) {
702  $self->reconnect();
703  }
704  my $sth = $self->db_handle->prepare(@args);
705 
706  # return an overridden statement handle that provides us with
707  # the means to disconnect inactive statement handles automatically
708  bless $sth, "Bio::EnsEMBL::DBSQL::StatementHandle";
709  $sth->dbc($self);
710  $sth->sql($args[0]);
711 
712  $self->query_count($self->query_count()+1);
713  return $sth;
714 }
715 
716 
717 =head2 prepare_cached
718 
719  Arg [1] : string $string
720  the SQL statement to prepare
721  Example : $sth = $db_connection->prepare_cached("SELECT column FROM table");
722  Description: Prepares a SQL statement using the internal DBI database handle
723  and returns the DBI statement handle. The prepared statement is
724  cached so that it does not have to be prepared again.
725 
726  If only a subset of rows are required, finish() should be called
727  on the object to free up the statement handle.
728 
729  For further information please consult https://metacpan.org/pod/DBI#prepare_cached
730  Returntype : DBI statement handle
731  Exceptions : thrown if the SQL statement is empty, or if the internal
732  database handle is not present
733  Caller : Adaptor modules
734  Status : Experimental
735 
736 =cut
737 
738 sub prepare_cached {
739  my ($self, @args) = @_;
740 
741  if( ! $args[0] ) {
742  throw("Attempting to prepare_cached an empty SQL query.");
743  }
744 
745  if ( ( $self->reconnect_when_lost() ) and ( !$self->db_handle()->{Active} ) ) {
746  $self->reconnect();
747  }
748  my $sth = $self->db_handle->prepare_cached( @args );
749 
750  # return an overridden statement handle that provides us with
751  # the means to disconnect inactive statement handles automatically
752  bless $sth, "Bio::EnsEMBL::DBSQL::StatementHandle";
753  $sth->dbc( $self );
754  $sth->sql( $args[0] );
755 
756  $self->query_count( $self->query_count() + 1 );
757  return $sth;
758 }
759 
760 
761 =head2 reconnect
762 
763  Example : $dbcon->reconnect()
764  Description: Reconnects to the database using the connection attribute
765  information if db_handle no longer pingable.
766  Returntype : none
767  Exceptions : none
768  Caller : new, db_handle
769  Status : Stable
770 
771 =cut
772 
773 sub reconnect {
774  my ($self) = @_;
775  $self->connected(undef);
776  $self->db_handle(undef);
777  $self->connect();
778  return;
779 }
780 
781 
782 =head2 do
783 
784  Arg [1] : string $string
785  the SQL statement to prepare
786  Example : $sth = $db_connection->do("SELECT column FROM table");
787  Description: Executes a SQL statement using the internal DBI database handle.
788  Returntype : Result of DBI dbh do() method
789  Exceptions : thrown if the SQL statement is empty, or if the internal
790  database handle is not present.
791  Caller : Adaptor modules
792  Status : Stable
793 
794 =cut
795 
796 sub do {
797  my ($self,$string, $attr, @bind_values) = @_;
798 
799  if( ! $string ) {
800  throw("Attempting to do an empty SQL query.");
801  }
802 
803  # warn "SQL(".$self->dbname."): $string";
804  my $error;
805 
806  my $do_result = $self->work_with_db_handle(sub {
807  my ($dbh) = @_;
808  my $result = eval { $dbh->do($string, $attr, @bind_values) };
809  $error = $@ if $@;
810  return $result;
811  });
812 
813  throw "Detected an error whilst executing statement '$string': $error" if $error;
814 
815  return $do_result;
816 }
817 
818 =head2 work_with_db_handle
819 
820  Arg [1] : CodeRef $callback
821  Example : my $q_t = $dbc->work_with_db_handle(sub { my ($dbh) = @_; return $dbh->quote_identifier('table'); });
822  Description: Gives access to the DBI handle to execute methods not normally
823  provided by the DBConnection interface
824  Returntype : Any from callback
825  Exceptions : If the callback paramater is not a CodeRef; all other
826  errors are re-thrown after cleanup.
827  Caller : Adaptor modules
828  Status : Stable
829 
830 =cut
831 
832 sub work_with_db_handle {
833  my ($self, $callback) = @_;
834  my $wantarray = wantarray;
835  assert_ref($callback, 'CODE', 'callback');
836  if( $self->reconnect_when_lost() && !$self->db_handle()->ping()) {
837  $self->reconnect();
838  }
839  my @results;
840  eval {
841  if($wantarray) {
842  @results = $callback->($self->db_handle())
843  }
844  elsif(defined $wantarray) {
845  $results[0] = $callback->($self->db_handle());
846  }
847  else {
848  $callback->($self->db_handle());
849  }
850  };
851  my $original_error = $@;
852 
853  $self->query_count($self->query_count()+1);
854  eval {
855  if($self->disconnect_when_inactive()) {
856  $self->disconnect_if_idle();
857  }
858  };
859  if($@) {
860  warning "Detected an error whilst attempting to disconnect the DBI handle: $@";
861  }
862  if($original_error) {
863  throw "Detected an error when running DBI wrapper callback:\n$original_error";
864  }
865 
866  if(defined $wantarray) {
867  return ($wantarray) ? @results : $results[0];
868  }
869  return;
870 }
871 
872 =head2 prevent_disconnect
873 
874  Arg[1] : CodeRef $callback
875  Example : $dbc->prevent_disconnect(sub { $dbc->do('do something'); $dbc->do('something else')});
876  Description : A wrapper method which prevents database disconnection for the
877  duration of the callback. This is very useful if you need
878  to make multiple database calls avoiding excessive database
879  connection creation/destruction but still want the API
880  to disconnect after the body of work.
881 
882  The value of C<disconnect_when_inactive()> is set to 0 no
883  matter what the original value was & after $callback has
884  been executed. If C<disconnect_when_inactive()> was
885  already set to 0 then this method will be an effective no-op.
886  Returntype : None
887  Exceptions : Raised if there are issues with reverting the connection to its
888  default state.
889  Caller : DBConnection methods
890  Status : Beta
891 
892 =cut
893 
894 sub prevent_disconnect {
895  my ($self, $callback) = @_;
896  assert_ref($callback, 'CODE', 'callback');
897  my $original_dwi = $self->disconnect_when_inactive();
898  $self->disconnect_when_inactive(0);
899  eval { $callback->(); };
900  my $original_error = $@;
901  eval {
902  $self->disconnect_when_inactive($original_dwi);
903  };
904  if($@) {
905  warning "Detected an error whilst attempting to reset disconnect_when_idle: $@";
906  }
907  if($original_error) {
908  throw "Detected an error when running DBI wrapper callback:\n$original_error";
909  }
910  return;
911 }
912 
913 =head2 quote_identifier
914 
915  Arg [n] : scalar/ArrayRef
916  Example : $q = $dbc->quote_identifier('table', 'other');
917  $q = $dbc->quote_identifier([undef, 'my_db', 'table'], [undef, 'my_db', 'other']);
918  Description: Executes the DBI C<quote_identifier> method which will quote
919  any given string using the database driver's quote character.
920  Returntype : ArrayRef
921  Exceptions : None
922  Caller : General
923  Status : Stable
924 
925 =cut
926 
927 sub quote_identifier {
928  my ($self, @identifiers) = @_;
929  return $self->work_with_db_handle(sub {
930  my ($dbh) = @_;
931  my @output;
932  foreach my $identifier_array (@identifiers) {
933  $identifier_array = wrap_array($identifier_array);
934  push(@output, $dbh->quote_identifier(@{$identifier_array}));
935  }
936  return \@output;
937  });
938 }
939 
940 =head2 disconnect_if_idle
941 
942  Arg [1] : none
943  Example : $dbc->disconnect_if_idle();
944  Description: Disconnects from the database if there are no currently active
945  statement handles.
946  It is called automatically by the DESTROY method of the
947  Bio::EnsEMBL::DBSQL::SQL::StatementHandle if the
948  disconect_when_inactive flag is set.
949  Users may call it whenever they want to disconnect. Connection will
950  reestablish on next access to db_handle()
951  Returntype : 1 or 0
952  1=problem trying to disconnect while a statement handle was still active
953  Exceptions : none
954  Caller : Bio::EnsEMBL::DBSQL::SQL::StatementHandle::DESTROY
955  Bio::EnsEMBL::DBSQL::DBConnection::do
956  Status : Stable
957 
958 =cut
959 
960 sub disconnect_if_idle {
961  my $self = shift;
962 
963  return 0 if(!$self->connected());
964  my $db_handle = $self->db_handle();
965  return 0 unless(defined($db_handle));
966 
967  #printf("disconnect_if_idle : kids=%d activekids=%d\n",
968  # $db_handle->{Kids}, $db_handle->{ActiveKids});
969 
970  #If InactiveDestroy is set, don't disconnect.
971  #To comply with DBI specification
972  return 0 if($db_handle->{InactiveDestroy});
973 
974  #If any statement handles are still active, don't allow disconnection
975  #In this case it is being called before a query has been fully processed
976  #either by not reading all rows of data returned, or not calling ->finish
977  #on the statement handle. Don't disconnect, send warning
978  if($db_handle->{ActiveKids} != 0) {
979  warn("Problem disconnect : kids=",$db_handle->{Kids},
980  " activekids=",$db_handle->{ActiveKids},"\n");
981  return 1;
982  }
983 
984  $db_handle->disconnect();
985  $self->connected(undef);
986  $self->disconnect_count($self->disconnect_count()+1);
987  #print("DISCONNECT\n");
988  $self->db_handle(undef);
989  return 0;
990 }
991 
992 
993 =head2 add_limit_clause
994 
995  Arg [1] : string $sql
996  Arg [2] : int $max_number
997  Example : my $new_sql = $dbc->add_limit_clause($sql,$max_number);
998  Description: Giving an SQL statement, it adds a limit clause, dependent on the database
999  (in MySQL, should add a LIMIT at the end, MSSQL uses a TOP clause)
1000  Returntype : String containing the new valid SQL statement
1001  Exceptions : none
1002  Caller : general
1003  Status : at risk
1004 
1005 =cut
1006 
1007 
1008 sub add_limit_clause{
1009  my $self = shift;
1010  my $sql = shift;
1011  my $max_number = shift;
1012 
1013  my $new_sql = '';
1014  if ($self->driver eq 'mysql'){
1015  $new_sql = $sql . ' LIMIT ' . $max_number;
1016  }
1017  elsif ($self->driver eq 'odbc'){
1018  #need to get anything after the SELECT statement
1019  $sql =~ /select(.*)/i;
1020  $new_sql = 'SELECT TOP ' . $max_number . $1;
1021  }
1022  else{
1023  warning("Not possible to convert $sql to an unknow database driver: ", $self->driver, " no limit applied");
1024  $new_sql = $sql;
1025  }
1026  return $new_sql;
1027 }
1028 
1029 
1030 =head2 from_date_to_seconds
1031 
1032  Arg [1] : date $date
1033  Example : my $string = $dbc->from_date_to_seconds($date);
1034  Description: Giving a string representing a column of type date
1035  applies the database function to convert to the number of seconds from 01-01-1970
1036  Returntype : string
1037  Exceptions : none
1038  Caller : general
1039  Status : at risk
1040 
1041 =cut
1042 
1043 sub from_date_to_seconds{
1044  my ($self, @args) = @_;
1045  return $self->_driver_object->from_date_to_seconds(@args);
1046 }
1047 
1048 =head2 from_seconds_to_date
1049 
1050  Arg [1] : int $seconds
1051  Example : my $string = $dbc->from_seconds_to_date($seconds);
1052  Description: Giving an int representing number of seconds
1053  applies the database function to convert to a date
1054  Returntype : string
1055  Exceptions : none
1056  Caller : general
1057  Status : at risk
1058 
1059 =cut
1060 
1061 sub from_seconds_to_date {
1062  my $self = shift;
1063  my $seconds = shift;
1064 
1065  if ($seconds) {
1066  return $self->_driver_object->from_seconds_to_date($seconds);
1067  }
1068  return;
1069 }
1070 
1071 =head2 sql_helper
1072 
1073  Example : my $h = $dbc->sql_helper();
1074  Description: Lazy generated instance of L<Bio::EnsEMBL::Utils::SqlHelper>
1075  which provides useful wrapper methods for interacting with a
1076  DBConnection instance.
1077  Returntype : Bio::EnsEMBL::Utils::SqlHelper
1078  Exceptions : none
1079  Caller : general
1080  Status : Stable
1081 
1082 =cut
1083 
1084 sub sql_helper {
1085  my ($self) = @_;
1086  if(! exists $self->{_sql_helper}) {
1087  my $helper = Bio::EnsEMBL::Utils::SqlHelper->new(-DB_CONNECTION => $self);
1088  $self->{_sql_helper} = $helper;
1089  }
1090  return $self->{_sql_helper};
1091 }
1092 
1093 =head2 to_hash
1094 
1095  Example : my $hash = $dbc->to_hash();
1096  my $new_dbc = $dbc->new(%{$hash});
1097  Description: Provides a hash which is compatible with the
1098  parameters for DBConnection's new() method. This can be
1099  useful during serialisation
1100  Returntype : Hash
1101  Exceptions : none
1102  Caller : general
1103  Status : New
1104 
1105 =cut
1106 
1107 sub to_hash {
1108  my ($self) = @_;
1109  my $hash = {
1110  -HOST => $self->host(),
1111  -PORT => $self->port(),
1112  -USER => $self->username(),
1113  -DRIVER => $self->driver(),
1114  };
1115  $hash->{'-DBNAME'} = $self->dbname() if defined $self->dbname();
1116  $hash->{'-PASS'} = $self->password() if defined $self->password();
1117  return $hash;
1118 }
1119 
1120 =head2 _driver_object
1121 =cut
1122 
1123 sub _driver_object {
1124  my ($self, @args) = @_;
1125  ($self->{_driver_object}) = @args if @args;
1126  return $self->{_driver_object};
1127 }
1128 
1129 1;
EnsEMBL
Definition: Filter.pm:1
Bio::EnsEMBL::DBSQL::DBAdaptor
Definition: DBAdaptor.pm:40
Bio::EnsEMBL::Utils::ConfigRegistry
Definition: ConfigRegistry.pm:23
Bio::EnsEMBL::Registry
Definition: Registry.pm:113
Bio::EnsEMBL::DBSQL::DBConnection::prepare
public DBI prepare()
Bio::EnsEMBL::Utils::SqlHelper::new
public Instance new()
Bio::EnsEMBL::DBSQL::StatementHandle
Definition: StatementHandle.pm:21
Bio::EnsEMBL::DBSQL::DBConnection
Definition: DBConnection.pm:42
Bio::EnsEMBL::Utils::Scalar
Definition: Scalar.pm:66
Bio::EnsEMBL::Utils::Exception::deprecate
public void deprecate()
Bio::EnsEMBL::DBSQL::DBConnection::new
public Bio::EnsEMBL::DBSQL::DBConnection new()
Bio::EnsEMBL::Utils::SqlHelper
Definition: SqlHelper.pm:55
Bio
Definition: AltAlleleGroup.pm:4
Bio::EnsEMBL::Utils::Argument
Definition: Argument.pm:34
Bio::EnsEMBL::Utils::Exception
Definition: Exception.pm:68