ensembl-hive  2.6
StatementHandle.pm
Go to the documentation of this file.
1 =pod
2 
3 =head1 NAME
4 
6 
7 =head1 SYNOPSIS
8 
9  Do not use this class directly.
10  It will automatically be used by the Bio::EnsEMBL::Hive::DBSQL::DBConnection class.
11 
12 =head1 DESCRIPTION
13 
14  This class extends DBI::st via containment, intercepts possible "gone away" errors,
15  automatically reconnects and re-prepares the statement. It should take much less resources
16  than pinging or worrying about disconnecting before and reconnecting after external processes
17  whose duration we do not control.
18 
19 =head1 LICENSE
20 
21  Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
22  Copyright [2016-2024] EMBL-European Bioinformatics Institute
23 
24  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
25  You may obtain a copy of the License at
26 
27  http://www.apache.org/licenses/LICENSE-2.0
28 
29  Unless required by applicable law or agreed to in writing, software distributed under the License
30  is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31  See the License for the specific language governing permissions and limitations under the License.
32 
33 =head1 CONTACT
34 
35  Please subscribe to the Hive mailing list: http://listserver.ebi.ac.uk/mailman/listinfo/ehive-users to discuss Hive-related questions or to be notified of our updates
36 
37 =cut
38 
39 
41 
42 use strict;
43 no strict 'refs';
44 use warnings;
45 use Bio::EnsEMBL::Hive::Utils ('throw', 'stringify');
47 
48 
49 sub new {
50  my ($class, $dbc, $sql, $attr) = @_;
51 
52  my $dbi_sth;
53  eval {
54  $dbi_sth = $dbc->protected_prepare( $sql, $attr );
55  1;
56  } or do {
57  throw( "FAILED_SQL(".$dbc->dbname."): " . join(' ', $sql, stringify($attr)) . "\nGot: ".$@."\n" );
58  };
59 
60  my $self = bless {}, $class;
61 
62  my $real_self = {};
63  # $self will remain empty whereas $real_self will actually have all the data
64  # Its only purpose is to offer a hash-reference on which perl allows
65  # calling hash accessors, e.g. $sth->{Active}
66  tie %$self, 'DBIstHashProxy', $dbi_sth, $real_self;
67 
68  $self->dbc( $dbc );
69  $self->sql( $sql );
70  $self->attr( $attr );
71 
72  $self->dbi_sth( $dbi_sth );
73 
74  return $self;
75 }
76 
77 ## Since $self is a tied hash and doesn't have any data,
78 ## real_self returns the real underlying hash and is used
79 ## in most of the function calls below
80 
81 sub real_self {
82  my $self = shift;
83  return (tied %$self)->[1];
84 }
85 
86 
87 sub dbc {
88  my $self = shift;
89  $self = $self->real_self;
90  $self->{'_dbc'} = shift if(@_);
91  return $self->{'_dbc'};
92 }
93 
94 
95 sub sql {
96  my $self = shift;
97  $self = $self->real_self;
98  $self->{'_sql'} = shift if(@_);
99  return $self->{'_sql'};
100 }
101 
102 
103 sub attr {
104  my $self = shift;
105  $self = $self->real_self;
106  $self->{'_attr'} = shift if(@_);
107  return $self->{'_attr'};
108 }
109 
110 
111 ## dbi_sth is the exception since it has to be in the first position
112 ## of the tied structure for Tie::ExtraHash to work.
113 sub dbi_sth {
114  my $self = shift;
115  my $self_array = tied %$self;
116  $self_array->[0] = shift if(@_);
117  return $self_array->[0];
118 }
119 
120 
121 sub AUTOLOAD {
122  our $AUTOLOAD;
123 
124  $AUTOLOAD=~/^.+::(\w+)$/;
125  my $method_name = $1;
126 
127 # warn "[AUTOLOAD instantiating '$method_name'] ($AUTOLOAD)\n";
128 
129  *$AUTOLOAD = sub {
130 # warn "[AUTOLOADed method '$method_name' running] ($AUTOLOAD)\n";
131 
132  my $self = shift @_;
133  my $dbi_sth = $self->dbi_sth() or throw( "dbi_sth returns false" );
134  my $wantarray = wantarray;
135 
136  my @retval;
137  eval {
138  if( $wantarray ) {
139  @retval = $dbi_sth->$method_name( @_ );
140  } else {
141  $retval[0] = $dbi_sth->$method_name( @_ );
142  }
143  1;
144  } or do {
145  my $error = $@;
146  my $dbc = $self->dbc();
148 
149  my $sql = $self->sql();
150  my $attr = $self->attr();
151 
152  warn "trying to reconnect...";
153  $dbc->reconnect();
154 
155  warn "trying to re-prepare [$sql". ($attr ? (', '.stringify($attr)) : '') ."]...";
156  # NOTE: parameters set via the hash interface of $sth will be lost
157  $dbi_sth = $dbc->db_handle->prepare( $sql, $attr );
158  $self->dbi_sth( $dbi_sth );
159 
160  warn "trying to re-$method_name...";
161  if( $wantarray ) {
162  @retval = $dbi_sth->$method_name( @_ );
163  } else {
164  $retval[0] = $dbi_sth->$method_name( @_ );
165  }
166  } else {
167  throw( $error );
168  }
169  };
170 
171  return $wantarray ? @retval : $retval[0];
172  };
173  goto &$AUTOLOAD;
174 }
175 
176 
177 sub DESTROY { # note AUTOLOAD/DESTROY interdependence!
178  my ($self) = @_;
179 
180  my $dbc = $self->dbc;
181  $self->dbc(undef);
182 
183  my $sql = $self->sql;
184  $self->sql(undef);
185 
186  $self->dbi_sth( undef ); # make sure it goes through its own DESTROY *now*
187 
188  #
189  # Forgetting $dbi_sth gets it out of scope, which decrements $db_handle->{Kids} .
190  # If as the result the $db_handle has no more Kids, we can safely trigger the disconnect if it was requested.
191  #
192 
193  if ( $dbc
194  && $dbc->disconnect_when_inactive()
195  && $dbc->connected
196  && ( $dbc->db_handle->{Kids} == 0 ) ) {
197 
198  if ( $dbc->disconnect_if_idle() ) {
199  warn("Problem disconnect $self around sql = $sql\n");
200  }
201  }
202 }
203 
204 
205 ## Just like AUTOLOAD for function calls, we need to redirect
206 ## the HASH methods to the DBI::st instance
207 ## We can conveniently use Tie::ExtraHash, which maps the methods
208 ## to the first element of the array, allowing us to store
209 ## other things in the other elements.
210 
211 package DBIstHashProxy;
212 
213 use Tie::Hash;
214 use base ('Tie::ExtraHash');
215 
216 # Pass the target hash as the first argument
217 sub TIEHASH {
218  my $class = shift;
219  my $self = [@_];
220  bless $self, $class;
221  return $self;
222 }
223 
224 
225 1;
Bio::EnsEMBL::Hive::Utils
Definition: Collection.pm:4
Bio::EnsEMBL::Hive::Utils::SQLErrorParser
Definition: SQLErrorParser.pm:12
Bio::EnsEMBL::Hive::Version
Definition: Version.pm:19
Bio::EnsEMBL::Hive::DBSQL::StatementHandle
Definition: StatementHandle.pm:22
Bio::EnsEMBL::Hive::Utils::stringify
public stringify()
about
public about()
Bio::EnsEMBL::Hive
Definition: Hive.pm:38
Bio
Definition: AltAlleleGroup.pm:4
Bio::EnsEMBL::Hive::Utils::SQLErrorParser::is_connection_lost
public is_connection_lost()