ensembl-hive  2.7.0
BaseAdaptor.pm
Go to the documentation of this file.
1 =head1 LICENSE
2 
3 See the NOTICE file distributed with this work for additional information
4 regarding copyright ownership.
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 
22 =head1 CONTACT
23 
24  Please email comments or questions to the public Ensembl
25  developers list at <http://lists.ensembl.org/mailman/listinfo/dev>.
26 
27  Questions may also be sent to the Ensembl help desk at
28  <http://www.ensembl.org/Help/Contact>.
29 
30 =cut
31 
32 =head1 NAME
33 
34 Bio::EnsEMBL::DBSQL::BaseAdaptor - Base Adaptor for DBSQL adaptors
35 
36 =head1 SYNOPSIS
37 
38  # base adaptor provides
39 
40  # SQL prepare function
41  $adaptor->prepare("sql statement");
42 
43  # get of root DBAdaptor object
44  $adaptor->db();
45 
46  # constructor, ok for inheritence
47  $adaptor = Bio::EnsEMBL::DBSQL::SubClassOfBaseAdaptor->new($dbobj);
48 
49 =head1 DESCRIPTION
50 
51 This is a true base class for Adaptors in the Ensembl DBSQL
52 system.
53 
54 Adaptors are expected to have the following functions
55 
56  $obj = $adaptor->fetch_by_dbID($internal_id);
57 
58 which builds the object from the primary key of the object. This
59 function is crucial because it allows adaptors to collaborate relatively
60 independently of each other - in other words, we can change the schema
61 under one adaptor without too many knock on changes through the other
62 adaptors.
63 
64 Most adaptors will also have
65 
66  $dbid = $adaptor->store($obj);
67 
68 which stores the object. Currently the storing of an object also causes
69 the objects to set
70 
71  $obj->dbID();
72 
73 correctly and attach the adaptor.
74 
75 Other fetch functions go by the convention of
76 
77  @object_array = @{ $adaptor->fetch_all_by_XXXX($arguments_for_XXXX) };
78 
79 sometimes it returns an array ref denoted by the 'all' in the name of
80 the method, sometimes an individual object. For example
81 
82  $gene = $gene_adaptor->fetch_by_stable_id($stable_id);
83 
84 or
85 
86  @fp = @{ $simple_feature_adaptor->fetch_all_by_Slice($slice) };
87 
88 Occassionally adaptors need to provide access to lists of ids. In this
89 case the convention is to go list_XXXX, such as
90 
91  @gene_ids = @{ $gene_adaptor->list_geneIds() };
92 
93 (note: this method is poorly named)
94 
95 =cut
96 
98 require Exporter;
99 use vars qw(@ISA @EXPORT);
100 use strict;
101 
102 use Bio::EnsEMBL::Utils::Exception qw(throw);
103 use Bio::EnsEMBL::Utils::Scalar qw(wrap_array);
104 use DBI qw(:sql_types);
105 use Data::Dumper;
106 use Scalar::Util qw/looks_like_number/;
107 
108 @ISA = qw(Exporter);
109 @EXPORT = (@{$DBI::EXPORT_TAGS{'sql_types'}});
110 
111 =head2 new
112 
113  Arg [1] : Bio::EnsEMBL::DBSQL::DBConnection $dbobj
114  Example : $adaptor = new AdaptorInheritedFromBaseAdaptor($dbobj);
115  Description: Creates a new BaseAdaptor object. The intent is that this
116  constructor would be called by an inherited superclass either
117  automatically or through $self->SUPER::new in an overridden
118  new method.
120  Exceptions : none
122  Status : Stable
123 
124 =cut
125 
126 sub new {
127  my ( $class, $dbobj ) = @_;
128 
129  my $self = bless {}, $class;
130 
131  if ( !defined $dbobj || !ref $dbobj ) {
132  throw("Don't have a db [$dbobj] for new adaptor");
133  }
134 
135  if ( $dbobj->isa('Bio::EnsEMBL::DBSQL::DBAdaptor') ) {
136  $self->db($dbobj);
137  $self->dbc( $dbobj->dbc );
138  $self->species_id( $dbobj->species_id() );
139  $self->is_multispecies( $dbobj->is_multispecies() );
140  } elsif ( ref($dbobj) =~ /DBAdaptor$/ ) {
141  $self->db($dbobj);
142  $self->dbc( $dbobj->dbc );
143  } elsif ( ref($dbobj) =~ /DBConnection$/ ) {
144  $self->dbc($dbobj);
145  } else {
146  throw("Don't have a DBAdaptor [$dbobj] for new adaptor");
147  }
148 
149  return $self;
150 }
151 
152 
153 =head2 prepare
154 
155  Arg [1] : string $string
156  a SQL query to be prepared by this adaptors database
157  Example : $sth = $adaptor->prepare("select yadda from blabla")
158  Description: provides a DBI statement handle from the adaptor. A convenience
159  function so you dont have to write $adaptor->db->prepare all the
160  time
161  Returntype : DBI::StatementHandle
162  Exceptions : none
163  Caller : Adaptors inherited from BaseAdaptor
164  Status : Stable
165 
166 =cut
167 
168 sub prepare {
169  my ( $self, $string ) = @_;
170 
171  # Uncomment next line to cancel caching on the SQL side.
172  # Needed for timing comparisons etc.
173  #$string =~ s/SELECT/SELECT SQL_NO_CACHE/i;
174 
175  return $self->dbc->prepare($string);
176 }
177 
178 
179 =head2 db
180 
181  Arg [1] : (optional) Bio::EnsEMBL::DBSQL::DBAdaptor $obj
182  the database this adaptor is using.
183  Example : $db = $adaptor->db();
184  Description: Getter/Setter for the DatabaseConnection that this adaptor is
185  using.
186  Returntype : Bio::EnsEMBL::DBSQL::DBAdaptor
187  Exceptions : none
188  Caller : Adaptors inherited from BaseAdaptor
189  Status : Stable
190 
191 =cut
192 
193 sub db {
194  my ( $self, $value ) = @_;
195 
196  if ( defined($value) ) {
197  $self->{'db'} = $value;
198  }
199 
200  return $self->{'db'};
201 }
202 
203 =head2 dbc
204 
205  Arg [1] : (optional) Bio::EnsEMBL::DBSQL::DBConnection $obj
206  the database this adaptor is using.
207  Example : $db = $adaptor->db();
208  Description: Getter/Setter for the DatabaseConnection that this adaptor is
209  using.
211  Exceptions : none
212  Caller : Adaptors inherited from BaseAdaptor
213  Status : Stable
214 
215 =cut
216 
217 sub dbc {
218  my ( $self, $value ) = @_;
219 
220  if ( defined($value) ) {
221  $self->{'dbc'} = $value;
222  }
223 
224  return $self->{'dbc'};
225 }
226 
227 =head2 is_multispecies
228 
229  Arg [1] : (optional) boolean $arg
230  Example : if ($adaptor->is_multispecies()) { }
231  Description: Getter/Setter for the is_multispecies boolean of
232  to use for this adaptor.
233  Returntype : boolean
234  Exceptions : none
235  Caller : general
236  Status : Stable
237 
238 =cut
239 
240 sub is_multispecies {
241  my ( $self, $arg ) = @_;
242 
243  if ( defined($arg) ) {
244  $self->{_is_multispecies} = $arg;
245  }
246 
247  return $self->{_is_multispecies};
248 }
249 
250 =head2 species_id
251 
252  Arg [1] : (optional) int $species_id
253  The internal ID of the species in a multi-species database.
254  Example : $db = $adaptor->db();
255  Description: Getter/Setter for the internal ID of the species in a
256  multi-species database. The default species ID is 1.
257  Returntype : Integer
258  Exceptions : none
259  Caller : Adaptors inherited from BaseAdaptor
260  Status : Stable
261 
262 =cut
263 
264 sub species_id {
265  my ( $self, $value ) = @_;
266 
267  if ( defined($value) ) {
268  $self->{'species_id'} = $value;
269  }
270 
271  return $self->{'species_id'} || 1;
272 }
273 
274 
275 # list primary keys for a particular table
276 # args are table name and primary key field
277 # if primary key field is not supplied, tablename_id is assumed
278 # returns listref of IDs
279 sub _list_dbIDs {
280  my ( $self, $table, $pk, $ordered ) = @_;
281 
282  if ( !defined($pk) ) { $pk = $table . "_id" }
283 
284  my $sql = sprintf( "SELECT `%s` FROM `%s`", $pk, $table );
285 
286  my $join_with_cs = 0;
287  if ( $self->is_multispecies()
288  && $self->isa('Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor')
289  && !$self->isa('Bio::EnsEMBL::DBSQL::UnmappedObjectAdaptor') )
290  {
291 
292  $sql .= q(
293 JOIN seq_region USING (seq_region_id)
294 JOIN coord_system cs USING (coord_system_id)
295 WHERE cs.species_id = ?
296 );
297 
298  $join_with_cs = 1;
299  }
300 
301  if ( defined($ordered) && $ordered ) {
302  $sql .= " ORDER BY seq_region_id, seq_region_start";
303  }
304 
305  my $sth = $self->prepare($sql);
306 
307  if ($join_with_cs) {
308  $sth->bind_param( 1, $self->species_id(), SQL_INTEGER );
309  }
310 
311  eval { $sth->execute() };
312  if ($@) {
313  throw("Detected an error whilst executing SQL '${sql}': $@");
314  }
315 
316  my $id;
317  $sth->bind_col( 1, \$id );
318 
319  my @out;
320  while ( $sth->fetch() ) {
321  push( @out, $id );
322  }
323 
324  return \@out;
325 } ## end sub _list_dbIDs
326 
327 
328 # _straight_join
329 
330 # Arg [1] : (optional) boolean $new_val
331 # Example : $self->_straight_join(1);
332 # $self->generic_fetch($constraint);
333 # $self->_straight_join(0);
334 # Description: PROTECTED Getter/Setter that turns on/off the use of
335 # a straight join in queries.
336 # Returntype : boolean
337 # Exceptions : none
338 # Caller : general
339 
340 sub _straight_join {
341  my $self = shift;
342  if(@_) {
343  $self->{'_straight_join'} = shift;
344  }
345 
346  return $self->{'_straight_join'};
347 }
348 
349 sub _can_straight_join {
350  my $self = shift;
351  return $self->dbc->_driver_object->can_straight_join;
352 }
353 
354 =head2 bind_param_generic_fetch
355 
356  Arg [1] : (optional) scalar $param
357  This is the parameter to bind
358  Arg [2] : (optional) int $sql_type
359  Type of the parameter (from DBI (:sql_types))
360  Example : $adaptor->bind_param_generic_fetch($stable_id,SQL_VARCHAR);
361  $adaptor->generic_fetch();
362  Description: When using parameters for the query, will call the bind_param to avoid
363  some security issues. If there are no arguments, will return the bind_parameters
364  ReturnType : listref
365  Exceptions: if called with one argument
366 
367 =cut
368 
369 sub bind_param_generic_fetch{
370  my $self = shift;
371  my $param = shift;
372  my $sql_type = shift;
373 
374  if (defined $param && !defined $sql_type){
375  throw("Need to specify sql_type for parameter $param\n");
376  }
377  elsif (defined $param && defined $sql_type){
378  #check when there is a SQL_INTEGER type that the parameter is really a number
379  if ($sql_type eq SQL_INTEGER){
380  throw "Trying to assign a non numerical parameter to an integer value in the database" if ($param !~ /^[+-]{0,1}\d+$/);
381  }
382  #both paramters have been entered, push it to the bind_param array
383  push @{$self->{'_bind_param_generic_fetch'}},[$param,$sql_type];
384  }
385  elsif (!defined $param && !defined $sql_type){
386  #when there are no arguments, return the array
387  return $self->{'_bind_param_generic_fetch'};
388  }
389 
390 }
391 
392 # Used to reset the params without circumventing scope
393 sub _bind_param_generic_fetch {
394  my ($self, $_bind_param_generic_fetch) = @_;
395  $self->{'_bind_param_generic_fetch'} = $_bind_param_generic_fetch if $_bind_param_generic_fetch;
396  return $self->{_bind_param_generic_fetch};
397 }
398 
399 =head2 generate_in_constraint
400 
401  Arg [1] : ArrayRef or Scalar $list
402  List or a single value of items to be pushed into an IN statement
403  Arg [2] : Scalar $column
404  Column this IN statement is being applied to. Please fully resolve the
405  column.
406  Arg [3] : Scalar $param_type
407  Data type which should be used when binding. Please use DBI data type symbols
408  Arg [4] : Scalar boolean $inline_variables
409  Boolean to control if variables are inlined in the constraint. If
410  false values are bound via bind_param_generic_fetch() (the default behaviour).
411 
412  Description : Used internally to generate a SQL constraint to restrict a query by an IN statement.
413  The code generates the complete IN statement.
414  Returntype : String
415  Exceptions : If no list is supplied, the list of values is empty or no data type was given
416  Caller : general
417 
418 =cut
419 
420 sub generate_in_constraint {
421  my ($self, $list, $column, $param_type, $inline_variables) = @_;
422  throw("A list of values must be given") if ! defined $list;
423  $list = wrap_array($list); # homogenise into an array
424  throw "We should be given at least one value to insert" if scalar(@{$list}) == 0;
425  throw "Please supply the DBI param type" if ! defined $param_type;
426  #Figure out if we need to quote our values if we are asked to inline the variables
427  my $quote_values = 1;
428  if($param_type == SQL_INTEGER || $param_type == SQL_TINYINT || $param_type == SQL_DOUBLE ) {
429  $quote_values = 0;
430  }
431 
432  my $constraint = qq{${column} IN (};
433  if($inline_variables) {
434  if($quote_values) {
435  $constraint .= join(q{,}, map { qq{"${_}"} } @{$list});
436  }
437  else {
438  $constraint .= join(q{,}, @{$list});
439  }
440  }
441  else {
442  my @subs = ('?') x scalar(@{$list});
443  $constraint .= join(q{,}, @subs);
444  $self->bind_param_generic_fetch($_, $param_type) for @{$list};
445  }
446  $constraint .= q{)};
447  return $constraint;
448 }
449 
450 =head2 generic_fetch
451 
452  Arg [1] : (optional) string $constraint
453  An SQL query constraint (i.e. part of the WHERE clause)
454  Arg [2] : (optional) Bio::EnsEMBL::AssemblyMapper $mapper
455  A mapper object used to remap features
456  as they are retrieved from the database
457  Arg [3] : (optional) Bio::EnsEMBL::Slice $slice
458  A slice that features should be remapped to
459  Example : $fts = $a->generic_fetch('contig_id in (1234, 1235)');
460  Description: Performs a database fetch and returns feature objects in
461  contig coordinates.
462  Returntype : listref of Bio::EnsEMBL::SeqFeature in contig coordinates
463  Exceptions : Thrown if there is an issue with querying the data
464  Caller : BaseFeatureAdaptor, ProxyDnaAlignFeatureAdaptor::generic_fetch
465  Status : Stable
466 
467 =cut
468 
469 sub generic_fetch {
470  my ($self, $constraint, $mapper, $slice) = @_;
471  my $sql = $self->_generate_sql($constraint);
472  my $params = $self->bind_param_generic_fetch();
473  $params ||= [];
474  $self->{_bind_param_generic_fetch} = undef;
475  my $sth = $self->db()->dbc()->prepare($sql);
476  my $i = 1;
477  foreach my $param (@{$params}){
478  $sth->bind_param($i,$param->[0],$param->[1]);
479  $i++;
480  }
481  eval { $sth->execute() };
482  if ($@) {
483  throw("Detected an error whilst executing SQL '${sql}': $@");
484  }
485 
486  my $res = $self->_objs_from_sth($sth, $mapper, $slice);
487  $sth->finish();
488  return $res;
489 }
490 
491 =head2 generic_count
492 
493  Arg [1] : (optional) string $constraint
494  An SQL query constraint (i.e. part of the WHERE clause)
495  Example : $number_feats = $a->generic_count('contig_id in (1234, 1235)');
496  Description: Performs a database fetch and returns a count of those features
497  found. This is analagous to C<generic_fetch()>
498  Returntype : Integer count of the elements.
499  Exceptions : Thrown if there is an issue with querying the data
500 
501 =cut
502 
503 sub generic_count {
504  my ($self, $constraint) = @_;
505  my $sql = $self->_generate_sql($constraint, 'count(*)');
506  my $params = $self->bind_param_generic_fetch();
507  $params ||= [];
508  $self->{_bind_param_generic_fetch} = undef;
509  my $h = $self->db()->dbc()->sql_helper();
510  my $count = $h->execute_single_result(-SQL => $sql, -PARAMS => $params);
511  return $count;
512 }
513 
514 sub _generate_sql {
515  my ($self, $constraint, @input_columns) = @_;
516 
517  my @tabs = $self->_tables();
518 
519  my $extra_default_where;
520 
521  # Hack for feature types that needs to be restricted to species_id (in
522  # coord_system).
523  if ( $self->is_multispecies()
524  && $self->isa('Bio::EnsEMBL::DBSQL::BaseFeatureAdaptor')
525  && !$self->isa('Bio::EnsEMBL::DBSQL::BaseAlignFeatureAdaptor')
526  && !$self->isa('Bio::EnsEMBL::DBSQL::UnmappedObjectAdaptor') )
527  {
528  # We do a check to see if there is already seq_region
529  # and coord_system defined to ensure we get the right
530  # alias. We then do the extra query irrespectively of
531  # what has already been specified by the user.
532  my %thash = map { $_->[0] => $_->[1] } @tabs;
533 
534  my $sr_alias =
535  ( exists( $thash{seq_region} ) ? $thash{seq_region} : 'sr' );
536  my $cs_alias =
537  ( exists( $thash{coord_system} ) ? $thash{coord_system} : 'cs' );
538 
539  if ( !exists( $thash{seq_region} ) ) {
540  push( @tabs, [ 'seq_region', $sr_alias ] );
541  }
542  if ( !exists( $thash{coord_system} ) ) {
543  push( @tabs, [ 'coord_system', $cs_alias ] );
544  }
545 
546  $extra_default_where = sprintf(
547  '%s.seq_region_id = %s.seq_region_id '
548  . 'AND %s.coord_system_id = %s.coord_system_id '
549  . 'AND %s.species_id = ?',
550  $tabs[0]->[1], $sr_alias, $sr_alias,
551  $cs_alias, $cs_alias );
552 
553  $self->bind_param_generic_fetch( $self->species_id(), SQL_INTEGER );
554  } ## end if ( $self->is_multispecies...)
555 
556  @input_columns = $self->_columns() if ! @input_columns;
557  my $columns = join(', ', @input_columns);
558 
559  #
560  # Construct a left join statement if one was defined, and remove the
561  # left-joined table from the table list
562  #
563  my @left_join_list = $self->_left_join();
564  my $left_join_prefix = '';
565  my $left_join = '';
566  my @tables;
567  if(@left_join_list) {
568  my %left_join_hash = map { $_->[0] => $_->[1] } @left_join_list;
569  while(my $t = shift @tabs) {
570  my $t_alias = $t->[0] . " " . $t->[1];
571  if( exists $left_join_hash{ $t->[0] } || exists $left_join_hash{$t_alias}) {
572  my $condition = $left_join_hash{ $t->[0] };
573  $condition ||= $left_join_hash{$t_alias};
574  my $syn = $t->[1];
575  $left_join .=
576  "\n LEFT JOIN " . $t->[0] . " $syn ON $condition ) ";
577  $left_join_prefix .= '(';
578  } else {
579  push @tables, $t;
580  }
581  }
582  } else {
583  @tables = @tabs;
584  }
585 
586  my $straight_join = '';
587 
588  if($self->_straight_join() and $self->_can_straight_join) {
589  $straight_join = "STRAIGHT_JOIN";
590  }
591 
592  #construct a nice table string like 'table1 t1, table2 t2'
593  my $tablenames = join(', ', map({ join(' ', @$_) } @tables));
594 
595  my $sql =
596  "SELECT $straight_join $columns \n"
597  . "FROM $left_join_prefix ($tablenames) $left_join";
598 
599  my $default_where = $self->_default_where_clause();
600  my $final_clause = $self->_final_clause;
601 
602  if ($extra_default_where) {
603  if ($default_where) {
604  $default_where .= "\n AND $extra_default_where";
605  } else {
606  $default_where = $extra_default_where;
607  }
608  }
609 
610  #append a where clause if it was defined
611  if ($constraint) {
612  $sql .= "\n WHERE $constraint ";
613  if ($default_where) {
614  $sql .= " AND\n $default_where ";
615  }
616  } elsif ($default_where) {
617  $sql .= "\n WHERE $default_where ";
618  }
619 
620  #append additional clauses which may have been defined, don't append ORDER BY twice
621  if (index($final_clause, "ORDER") == -1 || index($sql, "ORDER") == -1) {
622  $sql .= "\n$final_clause";
623  }
624 
625  # FOR DEBUG:
626  #printf(STDERR "SQL:\n%s\n", $sql);
627 
628  return $sql;
629 }
630 
631 
632 =head2 fetch_by_dbID
633 
634  Arg [1] : int $id
635  The unique database identifier for the feature to be obtained
636  Example : $feat = $adaptor->fetch_by_dbID(1234));
637  $feat = $feat->transform('contig');
638  Description: Returns the feature created from the database defined by the
639  the id $id. The feature will be returned in its native
640  coordinate system. That is, the coordinate system in which it
641  is stored in the database. In order to convert it to a
642  particular coordinate system use the transfer() or transform()
643  method. If the feature is not found in the database then
644  undef is returned instead
645  Returntype : Bio::EnsEMBL::Feature or undef
646  Exceptions : thrown if $id arg is not provided
647  does not exist
648  Caller : general
649  Status : Stable
650 
651 =cut
652 
653 sub fetch_by_dbID {
654  my ($self, $id) = @_;
655  if ($self->_no_id_cache()) {
656  return $self->_uncached_fetch_by_dbID($id);
657  }
658  return $self->_id_cache()->get($id);
659 }
660 
661 # The actual implmenetation moved sideways to allow for uncached access
662 # otherwise we'd constantly loop
663 
664 sub _uncached_fetch_by_dbID{
665  my ($self,$id) = @_;
666 
667  throw("id argument is required") if(!defined $id);
668 
669  #construct a constraint like 't1.table1_id = 123'
670  my @tabs = $self->_tables;
671  my ($name, $syn) = @{$tabs[0]};
672  $self->bind_param_generic_fetch($id,SQL_INTEGER);
673  my $constraint = "${syn}.${name}_id = ?";
674 
675  #Should only be one
676  my ($feat) = @{$self->generic_fetch($constraint)};
677 
678  return if(!$feat);
679 
680  return $feat;
681 }
682 
683 
684 =head2 fetch_all_by_dbID_list
685 
686  Arg [1] : listref of integers $id_list
687  The unique database identifiers for the features to
688  be obtained.
689  Arg [2] : optional - Bio::EnsEMBL::Slice to map features onto.
690  Example : @feats = @{$adaptor->fetch_all_by_dbID_list([1234, 2131, 982]))};
691  Description: Returns the features created from the database
692  defined by the the IDs in contained in the provided
693  ID list $id_list. The features will be returned
694  in their native coordinate system. That is, the
695  coordinate system in which they are stored in the
696  database. In order to convert the features to a
697  particular coordinate system use the transfer() or
698  transform() method. If none of the features are
699  found in the database a reference to an empty list is
700  returned.
701  Returntype : listref of Bio::EnsEMBL::Features
702  Exceptions : thrown if $id arg is not provided
703  does not exist
704  Caller : general
705  Status : Stable
706 
707 =cut
708 
709 sub fetch_all_by_dbID_list {
710  my ($self, $id_list_ref, $slice) = @_;
711  if ($self->_no_id_cache()) {
712  return $self->_uncached_fetch_all_by_dbID_list($id_list_ref, $slice);
713  }
714  return $self->_id_cache()->get_by_list($id_list_ref, $slice);
715 }
716 
717 # The actual implmenetation moved sideways to allow for uncached access
718 # otherwise we'd constantly loop
719 sub _uncached_fetch_all_by_dbID_list {
720  my ( $self, $id_list_ref, $slice ) = @_;
721  return $self->_uncached_fetch_all_by_id_list($id_list_ref, $slice, "dbID", 1);
722 } ## end sub fetch_all_by_dbID_list
723 
724 =head2 _uncached_fetch_all_by_id_list
725 
726  Arg [1] : listref of IDs
727  Arg [2] : (optional) Bio::EnsEMBL::Slice $slice
728  A slice that features should be remapped to
729  Arg [3] : String describing the ID type.
730  Valid values include dbID and stable_id. dbID is an alias for
731  the primary key, while other names map directly to table columns
732  of the Feature this adaptor manages.
733  Arg [4] : Boolean $numeric
734  Indicates if the incoming data is to be processed as a numeric
735  or as a String. If arg [3] was set to dbID then we default this to
736  be true. If arg [3] was set to stable_id then we default this to
737  be false.
738  When not using a standard arg[3] the IDs are assumed to be Strings.
739  Arg [5] : Integer $max_size
740  Control the maximum number of IDs sent to a database in a single
741  query. Defaults to 2K for Strings and 16K for integers. Only
742  provide if you know *exactly* why you need to edit it.
743  Example : $list_of_features = $adaptor->_uncached_fetch_all_by_id_list(
744  [qw(ENSG00000101321 ENSG00000101346 ENSG00000101367)],
745  undef,
746  "stable_id", 0); #using strings
747 
748  # Numeric set to true because we are using numerics
749  $list_of_features = $adaptor->_uncached_fetch_all_by_id_list(
750  [1,2,3,4],
751  undef,
752  "dbID", 1);
753 
754  # Numeric defaults to true because we are querying using dbID
755  $list_of_features = $adaptor->_uncached_fetch_all_by_id_list(
756  [1,2,3,4],
757  undef,
758  "dbID");
759  Description: This is a generic method used to fetch lists of features by IDs.
760  It avoids caches, meaning it is best suited for block fetching.
761  See fetch_all_by_dbID_list() for more info.
762  Returntype : ArrayRef of Bio::EnsEMBL::Feature
763  Exceptions : Thrown if a list of IDs is not supplied.
764  Caller : BaseFeatureAdaptor, BaseAdaptor and derived classes.
765 
766 =cut
767 
768 sub _uncached_fetch_all_by_id_list {
769  my ( $self, $id_list_ref, $slice, $id_type, $numeric, $max_size ) = @_;
770 
771  if ( !defined($id_list_ref) || ref($id_list_ref) ne 'ARRAY' ) {
772  throw("id_list list reference argument is required");
773  }
774 
775  if ( !@{$id_list_ref} ) { return [] }
776 
777  # Construct a constraint like 't1.table1_id = 123'
778  my @tabs = $self->_tables();
779  my ( $name, $syn ) = @{ $tabs[0] };
780 
781  # prepare column name for query. If the id_type was
782  # set to dbID then we assume the column must be
783  # tablename_id e.g. gene_id. Otherwise we assume the id_type
784  # is the field/column name
785  my $field_name;
786  if($id_type eq 'dbID') {
787  $field_name = $name.'_id';
788  # If numeric was not set default it to 1 since this is an int
789  $numeric = 1 if ! defined $numeric;
790  }
791  elsif($id_type eq 'stable_id') {
792  # If numeric was not set default it to 0 since this is a string
793  $numeric = 0 if ! defined $numeric;
794  $field_name = $id_type;
795  }
796  else {
797  $field_name = $id_type;
798  }
799 
800  my $sql_data_type;
801 
802  # Ensuring we do not exceed MySQL's max_allowed_packet (defaults to 1MB)
803  # by splitting large queries into smaller queries of at most 256KB
804  # (262,144 8-bit characters)
805  # If we had a numeric then really we are talking about working with
806  # integers. Normal max ensembl id size is 12 plus 2 characters for
807  # commas in our IN statement comes to 14. Even bloating this to 16 gives
808  # a max number of 16,384 IDs (262114/16).
809  #
810  if($numeric) {
811  my $first_id = $id_list_ref->[0];
812  if(!looks_like_number($first_id)) {
813  throw "You specified that we are looking for numerics but $first_id is not a numeric";
814  }
815  $max_size = 16384 if ! defined $max_size;
816  $sql_data_type = SQL_INTEGER;
817  }
818  # However when dealing with Strings those can be very large (assuming
819  # 128 is the max length of a stable ID). 128 is 8x smaller than our
820  # previous max expected integer so we reduce the max ids by 8. This gives
821  # 2048 IDs (16384/8)
822  else {
823  $max_size = 2048 if ! defined $max_size;
824  $sql_data_type = SQL_VARCHAR;
825  }
826 
827  # build up unique id list, also validate on the way by
828  my %id_list;
829  for (@{$id_list_ref}) {
830  $id_list{$_}++;
831  }
832  my @id_list = keys %id_list;
833 
834  my @out;
835  my $inline = 1;
836  while (@id_list) {
837  my @ids;
838  my $id_str;
839 
840  if ( scalar(@id_list) > $max_size ) {
841  @ids = splice( @id_list, 0, $max_size );
842  }
843  else {
844  @ids = @id_list;
845  @id_list = ();
846  }
847  # Push off to our IN statement constructor for this work
848  my $constraint = $self->generate_in_constraint(\@ids, "${syn}.${field_name}", $sql_data_type, $inline);
849  push @out, @{ $self->generic_fetch($constraint, undef, $slice) };
850  }
851 
852  return \@out;
853 }
854 
855 # might not be a good idea, but for convenience
856 # shouldnt be called on the BIG tables though
857 
858 sub fetch_all {
859  my $self = shift;
860  return $self->generic_fetch();
861 }
862 
863 =head2 last_insert_id
864 
865  Arg [1] : (optional) $field the name of the field the inserted ID was pushed
866  into
867  Arg [2] : (optional) HashRef used to pass extra attributes through to the
868  DBD driver
869  Arg [3] : (optional) $table the name of the table to use if the adaptor
870  does not implement C<_tables()>
871  Description : Delegating method which uses DBI to extract the last inserted
872  identifier. If using MySQL we just call the DBI method
873  L<DBI::last_insert_id()> since MySQL ignores any extra
874  arguments. See L<DBI> for more information about this
875  delegated method.
876  Example : my $id = $self->last_insert_id('my_id'); my $other_id = $self->last_insert_id();
877  Returntype : Scalar or undef
878 
879 =cut
880 
881 sub last_insert_id {
882  my ($self, $field, $attributes, $table) = @_;
883  my $dbc = $self->dbc();
884  my $dbh = $dbc->db_handle();
885  my @args;
886  unless (@args = $dbc->_driver_object->last_insert_id_args($field, $table)) {
887  if(!$table) {
888  my ($table_entry) = $self->_tables(); # first table entry
889  $table = $table_entry->[0]; # table_entry is [ name, alias ]
890  }
891  @args = (undef, $dbc->dbname(), $table, $field);
892  }
893  $attributes ||= {};
894  return $dbh->last_insert_id(@args, $attributes);
895 }
896 
897 =head2 insert_ignore_clause
898 =cut
899 
900 sub insert_ignore_clause {
901  my $self = shift;
902  return $self->dbc->_driver_object->insert_ignore_clause;
903 }
904 
905 =head2 _id_cache
906 
907  Description : Used to return an instance of a support BaseCache module
908  which can be used to speed up object access. The method
909  also respects the DBAdaptor's no_cache() flag and will
910  return undef in those situations
911  Example : my $cache = $self->_id_cache();
912  Returntype : Bio::EnsEMBL::DBSQL::Support::BaseCache
913 
914 =cut
915 
916 sub _id_cache {
917  my ($self) = @_;
918  return if $self->db()->no_cache() && !$self->ignore_cache_override;
919  if(! exists $self->{_id_cache}) {
920  $self->{_id_cache} = $self->_build_id_cache();
921  }
922  return $self->{_id_cache};
923 }
924 
925 =head2 _no_id_cache
926 
927  Description : Flags if the ID based caching is active or not. This could be
928  due to the adaptor not wanting to cache or because of
929  a global no_cache() flag on the DBAdaptor instance
930  Returntype : Boolean
931 
932 =cut
933 
934 sub _no_id_cache {
935  my ($self) = @_;
936  return 1 if ! $self->_id_cache();
937  return 0;
938 }
939 
940 =head2 ignore_cache_override
941 
942  Description : Method to interfere with no_cache directive from Registry on
943  a per adaptor basis. This method should be called after new()
944  in order to trigger the _build_id_cache at first query.
945  Example : $adaptor->ignore_cache_override(1);
946  Returntype : Boolean
947 
948 =cut
949 
950 sub ignore_cache_override {
951  my $self = shift;
952  $self->{'_override'} = shift if(@_);
953  unless (defined($self->{'_override'})) {return}
954  return $self->{'_override'};
955 }
956 
957 =head2 schema_version
958 
959  Description : Returns the schema version of the currently connected
960  DBAdaptor. The subroutine also caches this value so
961  repeated calls continue to be speedy.
962  Example : $adaptor->schema_version();
963  Returntype : Integer
964 
965 =cut
966 
967 sub schema_version {
968  my ($self) = @_;
969  return $self->{_schema_version} if exists $self->{_schema_version};
970  my $mc = $self->db()->get_MetaContainer();
971  return $self->{_schema_version} = $mc->get_schema_version();
972 }
973 
974 #_tables
975 #
976 # Args : none
977 # Example : $tablename = $self->_table_name()
978 # Description: ABSTRACT PROTECTED
979 # Subclasses are responsible for implementing this
980 # method. It should list of [tablename, alias] pairs.
981 # Additionally the primary table (with the dbID,
982 # analysis_id, and score) should be the first table in
983 # the list. e.g:
984 # ( ['repeat_feature', 'rf'],
985 # ['repeat_consensus', 'rc']);
986 # used to obtain features.
987 # Returntype : list of [tablename, alias] pairs
988 # Exceptions : thrown if not implemented by subclass
989 # Caller : BaseFeatureAdaptor::generic_fetch
990 #
991 
992 sub _tables {
993  throw( "abstract method _tables not defined "
994  . "by implementing subclass of BaseAdaptor" );
995 }
996 
997 
998 #_columns
999 #
1000 # Args : none
1001 # Example : $tablename = $self->_columns()
1002 # Description: ABSTRACT PROTECTED
1003 # Subclasses are responsible for implementing this
1004 # method. It should return a list of columns to be
1005 # used for feature creation.
1006 # Returntype : list of strings
1007 # Exceptions : thrown if not implemented by subclass
1008 # Caller : BaseFeatureAdaptor::generic_fetch
1009 #
1010 
1011 sub _columns {
1012  throw( "abstract method _columns not defined "
1013  . "by implementing subclass of BaseAdaptor" );
1014 }
1015 
1016 
1017 # _default_where_clause
1018 #
1019 # Arg [1] : none
1020 # Example : none
1021 # Description: May be overridden to provide an additional where
1022 # constraint to the SQL query which is generated to
1023 # fetch feature records. This constraint is always
1024 # appended to the end of the generated where clause
1025 # Returntype : string
1026 # Exceptions : none
1027 # Caller : generic_fetch
1028 #
1029 
1030 sub _default_where_clause { return '' }
1031 
1032 
1033 # _left_join
1034 
1035 # Arg [1] : none
1036 # Example : none
1037 # Description: Can be overridden by a subclass to specify any left
1038 # joins which should occur. The table name specigfied
1039 # in the join must still be present in the return
1040 # values of.
1041 # Returntype : a {'tablename' => 'join condition'} pair
1042 # Exceptions : none
1043 # Caller : general
1044 #
1045 
1046 sub _left_join { return () }
1047 
1048 
1049 #_final_clause
1050 
1051 # Arg [1] : none
1052 # Example : none
1053 # Description: May be overriden to provide an additional clause
1054 # to the end of the SQL query used to fetch feature
1055 # records. This is useful to add a required ORDER BY
1056 # clause to the query for example.
1057 # Returntype : string
1058 # Exceptions : none
1059 # Caller : generic_fetch
1060 
1061 sub _final_clause { return '' }
1062 
1063 
1064 #_objs_from_sth
1065 
1066 # Arg [1] : DBI::row_hashref $hashref containing key-value pairs
1067 # for each of the columns specified by the _columns method
1068 # Example : my @feats = $self->_obj_from_hashref
1069 # Description: ABSTRACT PROTECTED
1070 # The subclass is responsible for implementing this
1071 # method. It should take in a DBI row hash reference
1072 # and return a list of created features in contig
1073 # coordinates.
1074 # Returntype : list of Bio::EnsEMBL::*Features in contig coordinates
1075 # Exceptions : thrown if not implemented by subclass
1076 # Caller : BaseFeatureAdaptor::generic_fetch
1077 
1078 sub _objs_from_sth {
1079  throw( "abstract method _objs_from_sth not defined "
1080  . "by implementing subclass of BaseAdaptor" );
1081 }
1082 
1083 #_build_id_cache
1084 
1085 # Example : my $id_cache = $self->_build_id_cache
1086 # Description: ABSTRACT PROTECTED
1087 # The subclass is responsible for returning an instance
1088 # of the Bio::EnsEMBL::DBSQL::Support::BaseCache
1089 # which can be used to speed up ID based fetch operations
1090 # Returntype : Instance of Bio::EnsEMBL::DBSQL::Support::BaseCache
1091 # Exceptions : Could be thrown by the implementing sub-class
1092 # Caller : BaseAdaptor::_id_cache
1093 sub _build_id_cache {
1094  return;
1095 }
1096 
1097 #
1098 # Given a logic name and an existing constraint this will
1099 # add an analysis table constraint to the feature. Note that if no
1100 # analysis_id exists in the columns of the primary table then no
1101 # constraint is added at all
1102 #
1103 sub _logic_name_to_constraint {
1104  my $self = shift;
1105  my $constraint = shift;
1106  my $logic_name = shift;
1107 
1108  return $constraint if(!$logic_name);
1109 
1110  #make sure that an analysis_id exists in the primary table
1111  my ($prim_tab) = $self->_tables();
1112  my $prim_synonym = $prim_tab->[1];
1113 
1114  my $found_analysis=0;
1115  foreach my $col ($self->_columns) {
1116  my ($syn,$col_name) = split(/\./,$col);
1117  next if($syn ne $prim_synonym);
1118  if($col_name eq 'analysis_id') {
1119  $found_analysis = 1;
1120  last;
1121  }
1122  }
1123 
1124  if(!$found_analysis) {
1125  warning("This feature is not associated with an analysis.\n" .
1126  "Ignoring logic_name argument = [$logic_name].\n");
1127  return $constraint;
1128  }
1129 
1130  my $aa = $self->db->get_AnalysisAdaptor();
1131  my $an = $aa->fetch_by_logic_name($logic_name);
1132 
1133  if ( !defined($an) ) {
1134  return;
1135  }
1136 
1137  my $an_id = $an->dbID();
1138 
1139  $constraint .= ' AND' if($constraint);
1140  $constraint .= " ${prim_synonym}.analysis_id = $an_id";
1141  return $constraint;
1142 }
1143 
1144 
1145 1;
EnsEMBL
Definition: Filter.pm:1
Bio::EnsEMBL::DBSQL::DBAdaptor
Definition: DBAdaptor.pm:40
Bio::EnsEMBL::AssemblyMapper
Definition: AssemblyMapper.pm:49
map
public map()
Bio::EnsEMBL::SeqFeature
Definition: SeqFeature.pm:30
Bio::EnsEMBL::Slice
Definition: Slice.pm:50
Bio::EnsEMBL::DBSQL::BaseAdaptor::prepare
public DBI::StatementHandle prepare()
Bio::EnsEMBL::DBSQL::DBConnection::prepare
public DBI prepare()
about
public about()
Bio::EnsEMBL::DBSQL::BaseAdaptor
Definition: BaseAdaptor.pm:71
Bio::EnsEMBL::DBSQL::DBConnection
Definition: DBConnection.pm:42
Bio::EnsEMBL::Utils::Scalar
Definition: Scalar.pm:66
info
public info()
Bio
Definition: AltAlleleGroup.pm:4
Bio::EnsEMBL::Utils::Exception
Definition: Exception.pm:68