File Coverage

blib/lib/DBR/Query/Select.pm
Criterion Covered Total %
statement 66 68 97.0
branch 16 28 57.1
condition 7 16 43.7
subroutine 16 17 94.1
pod 0 8 0.0
total 105 137 76.6


line stmt bran cond sub pod time code
1             # The contents of this file are Copyright (c) 2010 Daniel Norman
2             # This program is free software; you can redistribute it and/or
3             # modify it under the terms of the GNU General Public License as
4             # published by the Free Software Foundation.
5              
6             ###########################################
7             package DBR::Query::Select;
8              
9 18     18   123 use strict;
  18         34  
  18         689  
10 18     18   123 use base 'DBR::Query';
  18         37  
  18         1764  
11 18     18   103 use Carp;
  18         34  
  18         1212  
12 18     18   10299 use DBR::Record::Maker;
  18         64  
  18         27300  
13              
14 590     590   4053 sub _params { qw (fields tables where builder limit lock quiet_error) }
15 574     574   2498 sub _reqparams { qw (fields tables) }
16 574     574   2217 sub _validate_self{ 1 } # If I exist, I'm valid
17              
18             sub fields{
19 603     603 0 1126 my $self = shift;
20 603 50 50     2096 exists( $_[0] ) or return wantarray?( @{$self->{fields}||[]} ) : $self->{fields} || undef;
  27 100       232  
    100          
21              
22 574         3055 my @fields = $self->_arrayify(@_);
23 574 50       2662 scalar(@fields) || croak('must provide at least one field');
24              
25 574         1259 my $lastidx = -1;
26 574         1546 for (@fields){
27 2455 50       14136 ref($_) =~ /^DBR::Config::Field/ || croak('must specify field as a DBR::Config::Field object'); # Could also be ::Anon
28 2455         10009 $_->index( ++$lastidx );
29             }
30 574         2604 $self->{last_idx} = $lastidx;
31 574         1361 $self->{fields} = \@fields;
32              
33 574         2111 return 1;
34             }
35              
36              
37             sub sql{
38 564     564 0 2144 my $self = shift;
39 564 50       2511 my $conn = $self->instance->connect('conn') or return $self->_error('failed to connect');
40 564         1087 my $sql;
41              
42 564         1929 my $tables = join(',', map { $_->sql( $conn ) } @{$self->{tables}} );
  566         2668  
  564         3633  
43 564         2518 my $fields = join(',', map { $_->sql( $conn ) } @{$self->{fields}} );
  2445         10630  
  564         1538  
44              
45 564         2744 $sql = "SELECT $fields FROM $tables";
46 564 100       4707 $sql .= ' WHERE ' . $self->{where}->sql($conn) if $self->{where};
47 564 50       3474 $sql .= ' FOR UPDATE' if $self->{lock};
48 564 50       2099 $sql .= ' LIMIT ' . $self->{limit} if $self->{limit};
49              
50 564         2429 $self->_logDebug2( $sql );
51 564         4222 return $sql;
52             }
53              
54 27     27 0 333 sub lastidx { $_[0]{last_idx} }
55 1 50   1 0 4 sub can_be_subquery { scalar( @{ $_[0]->fields || [] } ) == 1 }; # Must have exactly one field
  1         6  
56              
57             sub run {
58 567     567 0 1117 my $self = shift;
59 567   33     4624 return $self->{sth} ||= $self->instance->getconn->prepare( $self->sql ) || confess "Failed to prepare"; # only run once
      66        
60             }
61             sub reset {
62 0     0 0 0 my $self = shift;
63 0   0     0 return $self->{sth} && $self->{sth}->finish;
64             }
65              
66             # HERE - it's a little funky that we are handling split queries here,
67             # but non-split queries in ResultSet. Not horrible... just funky.
68             sub fetch_segment{
69 10     10 0 16 my $self = shift;
70 10         24 my $value = shift;
71              
72 10   50     82 return ( $self->{spvals} ||= $self->_do_split )->{ $value } || [];
73             }
74              
75             sub _do_split{
76 4     4   9 my $self = shift;
77              
78             # Should have a splitfield if we're getting here. Don't check for it. speeed.
79 4 50       23 defined( my $idx = $self->{splitfield}->index ) or croak 'field object must provide an index';
80              
81 4         17 my $sth = $self->run;
82              
83 4 50       571 defined( $sth->execute ) or croak 'failed to execute statement (' . $sth->errstr. ')';
84              
85 4         11 my $row;
86 4         22 my $code = 'while($row = $sth->fetch){ push @{$groupby{ $row->[' . $idx . '] }}, [@$row] }';
87 4         39 $self->_logDebug3($code);
88              
89 4         8 my %groupby;
90 4         1647 eval $code;
91 4 50       25 $@ && confess $@;
92              
93 4         20 $sth->finish;
94 4         281 return \%groupby;
95             }
96              
97              
98             sub get_record_obj{
99 39     39 0 92 my $self = shift;
100              
101             # Only make the record-maker object once per query. Even split queries should be able to share the same one.
102 39 0 66     757 return $self->{recordobj} ||= DBR::Record::Maker->new(
103             session => $self->{session},
104             query => $self, # This value is not preserved by the record maker, thus no memory leak
105             ) or confess ('failed to create record class');
106             }
107              
108             sub DESTROY{
109 580     580   69523 my $self = shift;
110              
111             # Can't finish the sth when going out of scope, it might live longer than this object.
112              
113 580         30714 return 1;
114             }
115             1;