ensembl-hive  2.5
DBAdaptor.pm
Go to the documentation of this file.
1 =pod
2 
3 =head1 NAME
4 
6 
7 =head1 SYNOPSIS
8 
9  my $db = Bio::EnsEMBL::Hive::DBSQL::DBAdaptor->new( -url => 'mysql://my_username:my_password@my_hostname:3306/my_hive_database' );
10 
11 =head1 DESCRIPTION
12 
13  This object represents the handle for a Hive system enabled database
14 
15 =head1 LICENSE
16 
17  Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
18  Copyright [2016-2022] EMBL-European Bioinformatics Institute
19 
20  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
21  You may obtain a copy of the License at
22 
23  http://www.apache.org/licenses/LICENSE-2.0
24 
25  Unless required by applicable law or agreed to in writing, software distributed under the License
26  is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27  See the License for the specific language governing permissions and limitations under the License.
28 
29 =head1 CONTACT
30 
31  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
32 
33 =cut
34 
35 
36 package Bio::EnsEMBL::Hive::DBSQL::DBAdaptor;
37 
38 use strict;
39 use warnings;
40 
41 use Scalar::Util qw(weaken);
42 
47 use Bio::EnsEMBL::Hive::Utils ('throw');
48 
58 
59 
60 sub new {
61  my $class = shift @_;
62  my %flags = @_;
63 
64  my ($dbc, $url, $reg_conf, $reg_type, $reg_alias, $species, $no_sql_schema_version_check)
65  = delete @flags{qw(-dbconn -url -reg_conf -reg_type -reg_alias -species -no_sql_schema_version_check)};
66 
67  if ($url && $no_sql_schema_version_check) {
68  #check to see if the url has been quoted. If so, move the quote
69  #after the no_sql_schema_version_check
70  $url =~ s/([\'\"]?)$/;no_sql_schema_version_check=1$1/;
71  }
72 
73  if($reg_conf or $reg_alias) { # need to initialize Registry even if $reg_conf is not really given
74  require Bio::EnsEMBL::Registry;
75  Bio::EnsEMBL::Registry->load_all($reg_conf); # if undefined, default reg_conf will be used
76  }
77 
78  my $self;
79 
80  if($url) {
81  $dbc = Bio::EnsEMBL::Hive::DBSQL::DBConnection->new(-url => $url, %flags)
82  or die "Unable to create a DBC using url='$url'";
83 
84  } elsif($reg_alias) {
85 
86  if($reg_alias=~/^(\w+):(\w+)$/) {
87  ($reg_type, $reg_alias) = ($1, $2);
88  }
89 
90  unless($reg_type) { # if no $reg_type explicitly given, try to guess:
91  my $dbas = Bio::EnsEMBL::Registry->get_all_DBAdaptors(-species => $reg_alias);
92 
93  if( scalar(@$dbas) == 1 ) {
94  $self = $dbas->[0];
95  } elsif( @$dbas ) {
96  warn "The registry contains multiple entries for '$reg_alias', please prepend the reg_alias with the desired type\n";
97  }
98  }
99 
100  unless($self) { # otherwise (or if not found) try a specific $reg_type
101  $reg_type ||= 'hive';
102  $self = Bio::EnsEMBL::Registry->get_DBAdaptor($reg_alias, $reg_type)
103  or die "Unable to connect to DBA using reg_conf='$reg_conf', reg_type='$reg_type', reg_alias='$reg_alias'\n";
104  }
105 
106  if( $self and !$self->isa($class) ) { # if we found a non-Hive Registry entry, detach the $dbc and build a Hive dba around it:
107  $dbc = $self->dbc;
108  $self = undef;
109  }
110  }
111 
112  if($dbc && !$self) {
113  $self = bless {}, $class;
114  $self->dbc( $dbc );
115  }
116 
117  unless($no_sql_schema_version_check) {
118 
119  my $dbc = $self->dbc();
120 
121  # Make a safe URL without affecting EHIVE_PASS, which could have been set by the user
122  my $safe_url = $dbc->url('EHIVE_TMP_PASSWORD');
123  $safe_url =~ s/EHIVE_TMP_PASSWORD/EHIVE_PASS/;
124 
125  my $code_sql_schema_version = Bio::EnsEMBL::Hive::DBSQL::SqlSchemaAdaptor->get_code_sql_schema_version()
126  || die "DB($safe_url) Could not establish code_sql_schema_version, please check that 'EHIVE_ROOT_DIR' environment variable is set correctly";
127 
128  my $db_sql_schema_version = eval { $self->get_MetaAdaptor->fetch_by_meta_key( 'hive_sql_schema_version' )->{'meta_value'}; };
129 
130  if($@) {
131  if($@ =~ /hive_meta.*doesn't exist/) {
132 
133  die "\nDB($safe_url) The 'hive_meta' table does not seem to exist in the database yet.\nPlease patch the database up to sql_schema_version '$code_sql_schema_version' and try again.\n";
134 
135  } else {
136 
137  die "DB($safe_url) $@";
138  }
139 
140  } elsif(!$db_sql_schema_version) {
141 
142  die "\nDB($safe_url) The 'hive_meta' table does not contain 'hive_sql_schema_version' entry.\nPlease investigate.\n";
143 
144  } elsif($db_sql_schema_version < $code_sql_schema_version) {
145 
146  my $new_patches = Bio::EnsEMBL::Hive::DBSQL::SqlSchemaAdaptor->get_sql_schema_patches( $db_sql_schema_version, $dbc->driver )
147  || die "DB($safe_url) sql_schema_version mismatch: the database's version is '$db_sql_schema_version' but the code is already '$code_sql_schema_version'.\n"
148  ."Unfortunately we cannot patch the database; you may have to create a new database or agree to run older code\n";
149 
150  my $sql_patcher_command = "$ENV{'EHIVE_ROOT_DIR'}/scripts/db_cmd.pl -url $safe_url";
151 
152  die "DB($safe_url) sql_schema_version mismatch: the database's version is '$db_sql_schema_version' but the code is already '$code_sql_schema_version'.\n"
153  ."Please upgrade the database by applying the following patches:\n\n"
154  .join("\n", map { ($_=~/\.\w*sql\w*$/) ? "\t$sql_patcher_command < $_" : "$_ -url $safe_url" } @$new_patches)
155  ."\n\nand try again.\n";
156 
157  } elsif($code_sql_schema_version < $db_sql_schema_version) {
158 
159  die "DB($safe_url) sql_schema_version mismatch: the database's version is '$db_sql_schema_version', but your code is still '$code_sql_schema_version'.\n"
160  ."Please update the code and try again.\n";
161  }
162  }
163 
164  if($species) { # [compatibility with core code] store the DBAdaptor in Registry:
165  require Bio::EnsEMBL::Registry;
166  Bio::EnsEMBL::Registry->add_DBAdaptor( $species, 'hive', $self );
167  }
168 
169  return $self;
170 }
171 
172 
173 sub species { # a stub to please Registry code
174  return @_;
175 }
176 
177 sub group { # a stub to please Registry code
178  return 'hive';
179 }
180 
181 
182 sub dbc {
183  my $self = shift;
184 
185  $self->{'_dbc'} = bless shift, 'Bio::EnsEMBL::Hive::DBSQL::DBConnection' if(@_);
186 
187  return $self->{'_dbc'};
188 }
189 
190 
191 sub hive_pipeline {
192  my $self = shift @_;
193  if (@_) {
194  $self->{'_hive_pipeline'} = shift @_;
195  }
196  unless ($self->{'_hive_pipeline'}) {
197  $self->{'_hive_pipeline'} = Bio::EnsEMBL::Hive::HivePipeline->new( -dba => $self ); # ToDo: this lazy-loaded object is not registered in TheApiary (yet)
198  }
199  return $self->{'_hive_pipeline'};
200 }
201 
202 
203 our %adaptor_type_2_package_name = (
204  'Accumulator' => 'Bio::EnsEMBL::Hive::DBSQL::AccumulatorAdaptor',
205  'Analysis' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisAdaptor',
206  'AnalysisCtrlRule' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisCtrlRuleAdaptor',
207  'AnalysisData' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisDataAdaptor',
208  'AnalysisJob' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisJobAdaptor',
209  'AnalysisStats' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisStatsAdaptor',
210  'Beekeeper' => 'Bio::EnsEMBL::Hive::DBSQL::BeekeeperAdaptor',
211  'DataflowRule' => 'Bio::EnsEMBL::Hive::DBSQL::DataflowRuleAdaptor',
212  'DataflowTarget' => 'Bio::EnsEMBL::Hive::DBSQL::DataflowTargetAdaptor',
213  'LogMessage' => 'Bio::EnsEMBL::Hive::DBSQL::LogMessageAdaptor',
214  'Meta' => 'Bio::EnsEMBL::Hive::DBSQL::MetaAdaptor',
215  'PipelineWideParameters'=> 'Bio::EnsEMBL::Hive::DBSQL::PipelineWideParametersAdaptor',
216  'NakedTable' => 'Bio::EnsEMBL::Hive::DBSQL::NakedTableAdaptor',
217  'ResourceClass' => 'Bio::EnsEMBL::Hive::DBSQL::ResourceClassAdaptor',
218  'ResourceDescription' => 'Bio::EnsEMBL::Hive::DBSQL::ResourceDescriptionAdaptor',
219  'Role' => 'Bio::EnsEMBL::Hive::DBSQL::RoleAdaptor',
220  'Semaphore' => 'Bio::EnsEMBL::Hive::DBSQL::SemaphoreAdaptor',
221  'Queen' => 'Bio::EnsEMBL::Hive::Queen',
222 
223  # aliases:
224  'Job' => 'Bio::EnsEMBL::Hive::DBSQL::AnalysisJobAdaptor',
225  'Worker' => 'Bio::EnsEMBL::Hive::Queen',
226  'MetaParameters' => 'Bio::EnsEMBL::Hive::DBSQL::MetaAdaptor',
227 );
228 
229 
230 sub get_available_adaptors {
231 
232  return \%adaptor_type_2_package_name;
233 }
234 
235 
236 sub parse_underscored_id_name {
237  my ($self, $underscored_id_name) = @_;
238 
239  my ($is_an_id, $foo_id_method_name, $foo_obj_method_name);
240 
241  my @syll = split(/_/, $underscored_id_name);
242  if($syll[scalar(@syll)-1] eq 'id') {
243  pop @syll;
244  ($is_an_id, $foo_id_method_name, $foo_obj_method_name) = ( 1, $underscored_id_name, join('_', @syll) );
245  } else {
246  ($is_an_id, $foo_id_method_name, $foo_obj_method_name) = ( 0, $underscored_id_name .'_id' , $underscored_id_name );
247  }
248 
249  my $AdaptorType = ''; # will be growing from right to left
250  while(@syll) {
251  $AdaptorType = ucfirst(pop @syll) . $AdaptorType;
252  if(exists( $self->get_available_adaptors->{ $AdaptorType })) {
253  return ($AdaptorType, $is_an_id, $foo_id_method_name, $foo_obj_method_name);
254  }
255  }
256  return; # could not parse
257 }
258 
259 
260 sub get_adaptor {
261  my $self = shift;
262  my $AdaptorType = shift;
263 
264  my $adaptor_package_name = $self->get_available_adaptors()->{$AdaptorType}
265  or throw("Could not find a module corresponding to '$AdaptorType'");
266 
267  my $signature = join(':', $adaptor_package_name, @_);
268 
269  unless( $self->{'_cached_adaptor'}{$signature} ) {
270 
271  eval "require $adaptor_package_name"
272  or throw("Could not load or compile module '$adaptor_package_name' because $@");
273 
274  $self->{'_cached_adaptor'}{$signature} = $adaptor_package_name->new( $self, @_ );
275  }
276 
277  return $self->{'_cached_adaptor'}{$signature};
278 }
279 
280 
281 sub DESTROY { } # to simplify AUTOLOAD
282 
283 sub AUTOLOAD {
284  our $AUTOLOAD;
285 
286  my $type;
287  if ( $AUTOLOAD =~ /^.*::get_(\w+)Adaptor$/ ) {
288  $type = $1;
289  } elsif ( $AUTOLOAD =~ /^.*::get_(\w+)$/ ) {
290  $type = $1;
291  } else {
292  throw( "DBAdaptor::AUTOLOAD: Could not interpret the method: $AUTOLOAD" );
293  }
294 
295  my $self = shift;
296 
297  return $self->get_adaptor($type, @_);
298 }
299 
300 
301 1;