|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package DBR::Interface::Where;  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
3
 | 
18
 | 
 
 | 
 
 | 
  
18
  
 | 
 
 | 
107
 | 
 use strict;  | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
    | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
688
 | 
    | 
| 
4
 | 
18
 | 
 
 | 
 
 | 
  
18
  
 | 
 
 | 
100
 | 
 use Carp;  | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
    | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1287
 | 
    | 
| 
5
 | 
18
 | 
 
 | 
 
 | 
  
18
  
 | 
 
 | 
108
 | 
 use DBR::Query::Part;  | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
44
 | 
    | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
464
 | 
    | 
| 
6
 | 
18
 | 
 
 | 
 
 | 
  
18
  
 | 
 
 | 
16680
 | 
 use Clone;  | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
108107
 | 
    | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1269
 | 
    | 
| 
7
 | 
18
 | 
 
 | 
 
 | 
  
18
  
 | 
 
 | 
189
 | 
 use Digest::MD5 qw(md5_base64);  | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
41
 | 
    | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1010
 | 
    | 
| 
8
 | 
18
 | 
 
 | 
 
 | 
  
18
  
 | 
 
 | 
10553
 | 
 use DBR::Misc::General;  | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
52
 | 
    | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
52032
 | 
    | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub new {  | 
| 
11
 | 
31
 | 
 
 | 
 
 | 
  
31
  
 | 
  
0
  
 | 
210
 | 
       my( $package ) = shift;  | 
| 
12
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
188
 | 
       my %params = @_;  | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
14
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
75
 | 
       my $self = {};  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
16
 | 
31
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
178
 | 
       $self->{session}  = $params{session}       or croak "session is required";  | 
| 
17
 | 
31
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
228
 | 
       $self->{instance} = $params{instance}      or croak "instance is required";  | 
| 
18
 | 
31
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
456
 | 
       $self->{table}    = $params{primary_table} or croak "primary_table is required";  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
20
 | 
31
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
140
 | 
       croak('primary_table object must be specified') unless ref($self->{table}) eq 'DBR::Config::Table';  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
22
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
125
 | 
       bless( $self, $package );  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
24
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
250
 | 
       $self->{tables} = [$self->{table}];  | 
| 
25
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
87
 | 
       $self->{aliascount} = 0;  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
27
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
244
 | 
       return( $self );  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
30
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
  
0
  
 | 
89
 | 
 sub tables { shift->{tables} }  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _andify{   | 
| 
33
 | 
64
 | 
 
 | 
 
 | 
  
64
  
 | 
 
 | 
101
 | 
       my $self = shift;  | 
| 
34
 | 
64
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
319
 | 
       return $_[0] if (@_ == 1);  | 
| 
35
 | 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
209
 | 
       return DBR::Query::Part::And->new( @_ );  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # fast way to discern the difference between one where clause  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # and another without actually doing the work of assembling everything  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub digest{  | 
| 
41
 | 
150010
 | 
 
 | 
 
 | 
  
150010
  
 | 
  
0
  
 | 
878718
 | 
       my $self = shift;  | 
| 
42
 | 
150010
 | 
 
 | 
 
 | 
 
 | 
 
 | 
201859
 | 
       md5_base64( join ( "\0|", map {_expandstr($_)} @{ shift() } ) );  | 
| 
 
 | 
600020
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1514568
 | 
    | 
| 
 
 | 
150010
 | 
 
 | 
 
 | 
 
 | 
 
 | 
278759
 | 
    | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub digest_clear{  | 
| 
45
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
       my $self = shift;  | 
| 
46
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       join ( "\0|", map {_expandstr($_)} @{ shift() } );  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub build{  | 
| 
49
 | 
47
 | 
 
 | 
 
 | 
  
47
  
 | 
  
0
  
 | 
265
 | 
       my $self = shift;  | 
| 
50
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
77
 | 
       my @input = @{shift()}; # Make a shallow copy  | 
| 
 
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
186
 | 
    | 
| 
51
 | 
47
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
276
 | 
       scalar (@input) || croak "input is required";  | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
53
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
177
 | 
       my $pendgroup = { table => $self->{table} }; # prime the pump.  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
55
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
92
 | 
       my @andparts = (); # Storage for finished query part objects  | 
| 
56
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
72
 | 
       my $pendct;  | 
| 
57
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
142
 | 
       while (@input){ # Iterate over key/value pairs  | 
| 
58
 | 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
170
 | 
 	    my $next    = shift @input;  | 
| 
59
 | 
88
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
288
 | 
 	    if(ref($next) eq 'DBR::_LOP'){ # Logical OPerator  | 
| 
60
 | 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
99
 | 
 		  my $op = $next->operator;  | 
| 
61
 | 
22
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
114
 | 
 		  scalar(@andparts) || $pendct || croak('Cannot use an operator without a preceeding comparison');  | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
63
 | 
22
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
152
 | 
 		  if ($op eq 'And'){  | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
64
 | 
11
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
43
 | 
 			if( $next->only_contains_and ){  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			      # This is an optomisation to prevent unnecessary recusion,  | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			      # and to avoid duplication of subqueries when possible.  | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			      # Because: A and ( B and C ) is equivelant to A and B and C...  | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			      # We are able to collapse the contents of the AND into the current context,  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			      # provided the sequence is maintained. Thus unshift, not push  | 
| 
70
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
 			      unshift @input, @{$next->value};  | 
| 
 
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
    | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}else{  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			      # We have to recurse to handle this situation properly  | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			      # A AND (B OR C) is not equivelant to A AND B OR C  | 
| 
74
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
 			      push @andparts,  $self->build( $next->value );  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  } elsif ( $op eq 'Or' ){  | 
| 
77
 | 
11
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
40
 | 
 			if($pendct){  | 
| 
78
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
 			      push @andparts, $self->_reljoin( $pendgroup ); # Everything before me (pending)...  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
80
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
 			my $A = $self->_andify( @andparts );  | 
| 
81
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
 			my $B = $self->build( $next->value );         # Compared to everything inside  | 
| 
82
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
83
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
 			@andparts = ( DBR::Query::Part::Or->new( $A, $B ) ); # Russian dolls... Get in mahh belly  | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
85
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
43
 | 
 			$pendgroup = { table => $self->{table} };      # Reset  | 
| 
86
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
40
 | 
 			$pendct = 0;                                   # Reset  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  }else{  | 
| 
88
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			confess "Sanity error. Invalid operator."  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  }  | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
91
 | 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
71
 | 
 		  next;  | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    }  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
94
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
105
 | 
 	    my $rawval = shift @input;  | 
| 
95
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
107
 | 
 	    $pendct++;  | 
| 
96
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
230
 | 
  	    $self->_process_comparison($next, $rawval, $pendgroup); # add it to the hopper  | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
100
 | 
47
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
140
 | 
       scalar(@input) and croak('Odd number of arguments in where parameters'); # I hate leftovers  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
102
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
180
 | 
       push @andparts, $self->_reljoin( $pendgroup );  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
104
 | 
47
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
208
 | 
       return wantarray?(@andparts):$self->_andify(@andparts); # don't wrap it in an and if we want an array  | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Process ONE comparison.  | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Walk the relation.relation.relation.field chain and set up the heirarchical hash structure for reljoin.  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _process_comparison{  | 
| 
111
 | 
66
 | 
 
 | 
 
 | 
  
66
  
 | 
 
 | 
96
 | 
       my $self = shift;  | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
113
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
129
 | 
       my $key = shift;  | 
| 
114
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
87
 | 
       my $rawval = shift;  | 
| 
115
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
90
 | 
       my $ref = shift;  | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
117
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
351
 | 
       $key =~ /^\s+|\s+$/g; # trim junk  | 
| 
118
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
334
 | 
       my @parts = split(/\s*\.\s*/,$key); # Break down each key into parts  | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
120
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
121
 | 
       my $tablect;  | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
122
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
207
 | 
       my $cur_table = $self->{table}; # Start  | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
124
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
231
 | 
       while ( my $part = shift @parts ){  | 
| 
125
 | 
78
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
209
 | 
 	    my $last = (scalar(@parts) == 0)?1:0;  | 
| 
126
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
127
 | 
78
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
181
 | 
 		  if($last){ # The last part should always be a field  | 
| 
128
 | 
66
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
247
 | 
 			croak ('Duplicate field ' .$part ) if $ref->{fields}->{$part};  | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
130
 | 
66
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
363
 | 
 			my $field = $cur_table->get_field( $part ) or croak("invalid field $part");  | 
| 
131
 | 
66
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
345
 | 
 			my $value = $field->makevalue( $rawval )   or croak("failed to build value object for $part");  | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
133
 | 
66
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
406
 | 
 			my $out = DBR::Query::Part::Compare->new( field => $field, value => $value ) or confess('failed to create compare object');  | 
| 
134
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
297
 | 
 			my $conn = $self->{instance}->connect;  | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
136
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
399
 | 
 			$ref->{fields}->{$part} = $out;  | 
| 
137
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  }else{  | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			#test for relation?  | 
| 
140
 | 
12
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
91
 | 
 			$ref = $ref->{kids}->{$part} ||= {}; # step deeper into the tree  | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
142
 | 
12
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
41
 | 
 			if( $ref->{been_here} ){ # Dejavu - merge any common paths together  | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
144
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
 			      $cur_table = $ref->{table};  # next!  | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}else{  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
148
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
54
 | 
 			      my $relation = $cur_table->get_relation($part) or croak("invalid relationship $part");  | 
| 
149
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
37
 | 
 			      my $maptable = $relation->maptable             or confess("failed to get maptable");  | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
151
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			      # Any to_one relationship results in a join. we'll need some table aliases for later.  | 
| 
152
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			      # Do them now so everything is in sync. I originally assigned the alias in _reljoin,  | 
| 
153
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			      # but it didn't always alias the fields that needed to be aliased due to the order of execution.  | 
| 
154
 | 
9
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
39
 | 
 			      if( $relation->is_same_schema && $relation->is_to_one ){  | 
| 
155
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
43
 | 
 				    croak ('No more than 25 tables allowed in a join') if $self->{aliascount} > 24;  | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
157
 | 
9
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
54
 | 
 				    $cur_table ->alias() || $cur_table ->alias( chr(97 + $self->{aliascount}++)  ); # might be doing this one again  | 
| 
158
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
44
 | 
 				    $maptable  ->alias( chr(97 + $self->{aliascount}++)  );  | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			      }  | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
161
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
 			      $ref->{relation}  = $relation;  | 
| 
162
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
 			      $ref->{prevtable} = $cur_table;  | 
| 
163
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
 			      $ref->{table}     = $maptable;  | 
| 
164
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
 			      $ref->{been_here} = 1;  | 
| 
165
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
166
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
61
 | 
 			      $cur_table = $maptable; # next!  | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  }  | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    };  | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _reljoin{  | 
| 
173
 | 
65
 | 
 
 | 
 
 | 
  
65
  
 | 
 
 | 
105
 | 
       my $self = shift;  | 
| 
174
 | 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
169
 | 
       my $ref  = shift;  | 
| 
175
 | 
65
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
527
 | 
       my $tables = shift || $self->{tables}; # Allow override of table list for subqueries  | 
| 
176
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
177
 | 
65
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
290
 | 
       confess ('ref must be hash') unless ref($ref) eq 'HASH';  | 
| 
178
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
179
 | 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
86
 | 
       my @and;  | 
| 
180
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
181
 | 
65
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
270
 | 
       if($ref->{kids}){  | 
| 
182
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
 	    foreach my $key (sort keys %{$ref->{kids}}){ # sort for consistent sql ordering  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
50
 | 
    | 
| 
183
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
75
 | 
 		  my $kid = $ref->{kids}->{ $key };  | 
| 
184
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
 		  my $relation = $kid->{relation};  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
186
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  # it's important we use the same table objects to preserve aliases  | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
188
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
32
 | 
 		  my $table     = $kid->{table}      or confess("failed to get table");  | 
| 
189
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
39
 | 
 		  my $prevtable = $kid->{prevtable}  or confess("failed to get prev_table");  | 
| 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
191
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
47
 | 
 		  my $field     = $relation->mapfield or confess('Failed to fetch field');  | 
| 
192
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
46
 | 
 		  my $prevfield = $relation->field    or confess('Failed to fetch prevfield');  | 
| 
193
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
194
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
 		  my $prevalias = $prevtable ->alias();  | 
| 
195
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
 		  my $alias     = $table     ->alias();  | 
| 
196
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
197
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
70
 | 
 		  $prevfield ->table_alias( $prevalias ) if $prevalias;  | 
| 
198
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
41
 | 
 		  $field     ->table_alias( $alias     ) if $alias;  | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
200
 | 
9
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
29
 | 
 		  if ($relation->is_same_schema && $relation->is_to_one) { # Do a join  | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
202
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
25
 | 
 			$prevalias or die('Sanity error: prevtable alias is required');  | 
| 
203
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
23
 | 
 			$alias     or die('Sanity error: table alias is required');  | 
| 
204
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
205
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
 			push @$tables, $table;  | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
207
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
72
 | 
 			my $where = $self->_reljoin( $kid, $tables ) or confess('_reljoin failed');  | 
| 
208
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
 			push @and, $where;  | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
210
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
56
 | 
 			my $join = DBR::Query::Part::Join->new($field,$prevfield) or confess('failed to create join object');  | 
| 
211
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
37
 | 
 			push @and, $join;  | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
213
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  }else{ # if it's a to_many relationship ( or cross schema ), then subqery  | 
| 
214
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			my @tables = $table;  | 
| 
215
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			my $where = $self->_reljoin( $kid, \@tables ) or confess('_reljoin failed');  | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
217
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			my $instance = $self->{instance};  | 
| 
218
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			unless ( $relation->is_same_schema ){  | 
| 
219
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			      $instance = $table->schema->get_instance( $instance->class ) or return $self->_error('Failed to retrieve db instance for subquery table');  | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
222
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
  			my $query = DBR::Query::Select->new(  | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 							    instance => $instance,  | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 							    session  => $self->{session},  | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 							    fields => [$field],  | 
| 
226
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 							    tables   => \@tables,  | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 							    where    => $where,  | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 							   ) or confess('failed to create query object');  | 
| 
229
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
230
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			my $runflag = ! $relation->is_same_schema;  | 
| 
231
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
  			my $subquery = DBR::Query::Part::Subquery->new($prevfield, $query, $runflag) or confess ('failed to create subquery object');  | 
| 
232
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			push @and, $subquery;  | 
| 
233
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  }  | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    }  | 
| 
236
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
237
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
238
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # It's important that fields are evaluated after all relationships are processed for this node  | 
| 
239
 | 
65
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
197
 | 
       if($ref->{fields}){  | 
| 
240
 | 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
301
 | 
 	    my $alias = $ref->{table}->alias;  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
242
 | 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
101
 | 
 	    foreach my $key (sort keys %{$ref->{fields}}){  | 
| 
 
 | 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
571
 | 
    | 
| 
243
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
138
 | 
 		  my $compare = $ref->{fields}->{ $key };  | 
| 
244
 | 
66
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
189
 | 
 		  $compare->field->table_alias( $alias ) if $alias;  | 
| 
245
 | 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
212
 | 
 		  push @and, $compare;  | 
| 
246
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    }  | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
249
 | 
65
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
301
 | 
       return wantarray?(@and):$self->_andify(@and); # don't wrap it in an and if we want an array  | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  |