fixed WhereJoins to handle conditions edge cases
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Oracle / WhereJoins.pm
CommitLineData
9382ad07 1package DBIx::Class::Storage::DBI::Oracle::WhereJoins;
2
3use base qw( DBIx::Class::Storage::DBI::Oracle::Generic );
4
5use strict;
6use warnings;
7
8BEGIN {
9 package DBIC::SQL::Abstract::Oracle;
10
11 use base qw( DBIC::SQL::Abstract );
12
13 sub select {
14 my ($self, $table, $fields, $where, $order, @rest) = @_;
15
67bdc1ef 16 if (ref($table) eq 'ARRAY') {
17 $where = $self->_oracle_joins($where, @{ $table });
18 }
9382ad07 19
20 return $self->SUPER::select($table, $fields, $where, $order, @rest);
21 }
22
23 sub _recurse_from {
24 my ($self, $from, @join) = @_;
25
26 my @sqlf = $self->_make_as($from);
27
28 foreach my $j (@join) {
29 my ($to, $on) = @{ $j };
30
31 if (ref $to eq 'ARRAY') {
32 push (@sqlf, $self->_recurse_from(@{ $to }));
33 }
34 else {
35 push (@sqlf, $self->_make_as($to));
36 }
37 }
38
39 return join q{, }, @sqlf;
40 }
41
42 sub _oracle_joins {
43 my ($self, $where, $from, @join) = @_;
67bdc1ef 44 my $join_where = {};
45 $self->_recurse_oracle_joins($join_where, $from, @join);
46 if (keys %$join_where) {
47 if (!defined($where)) {
48 $where = $join_where;
49 } else {
50 if (ref($where) eq 'ARRAY') {
51 $where = { -or => $where };
52 }
53 $where = { -and => [ $join_where, $where ] };
54 }
55 }
56 return $where;
57 }
58
59 sub _recurse_oracle_joins {
60 my ($self, $where, $from, @join) = @_;
9382ad07 61
62 foreach my $j (@join) {
63 my ($to, $on) = @{ $j };
64
65 if (ref $to eq 'ARRAY') {
67bdc1ef 66 $self->_recurse_oracle_joins($where, @{ $to });
9382ad07 67 }
68
69 my $to_jt = ref $to eq 'ARRAY' ? $to->[0] : $to;
70 my $left_join = q{};
71 my $right_join = q{};
72
73 if (ref $to_jt eq 'HASH' and exists $to_jt->{-join_type}) {
74 #TODO: Support full outer joins -- this would happen much earlier in
75 #the sequence since oracle 8's full outer join syntax is best
76 #described as INSANE.
77 die "Can't handle full outer joins in Oracle 8 yet!\n"
78 if $to_jt->{-join_type} =~ /full/i;
79
4a90cd56 80 $left_join = q{(+)} if $to_jt->{-join_type} =~ /left/i
9382ad07 81 && $to_jt->{-join_type} !~ /inner/i;
82
4a90cd56 83 $right_join = q{(+)} if $to_jt->{-join_type} =~ /right/i
9382ad07 84 && $to_jt->{-join_type} !~ /inner/i;
85 }
86
87 foreach my $lhs (keys %{ $on }) {
67bdc1ef 88 $where->{$lhs . $left_join} = \"= $on->{ $lhs }$right_join";
9382ad07 89 }
90 }
91 }
92}
93
94sub sql_maker {
95 my ($self) = @_;
96
97 unless ($self->_sql_maker) {
98 $self->_sql_maker(
99 new DBIC::SQL::Abstract::Oracle( $self->_sql_maker_args )
100 );
101 }
102
103 return $self->_sql_maker;
104}
105
1061;
107
108__END__
109
110=pod
111
112=head1 NAME
113
114DBIx::Class::Storage::DBI::Oracle::WhereJoins - Oracle joins in WHERE syntax
115support (instead of ANSI).
116
117=head1 PURPOSE
118
119This module was originally written to support Oracle < 9i where ANSI joins
120weren't supported at all, but became the module for Oracle >= 8 because
121Oracle's optimising of ANSI joins is horrible. (See:
122http://scsys.co.uk:8001/7495)
123
124=head1 SYNOPSIS
125
126DBIx::Class should automagically detect Oracle and use this module with no
127work from you.
128
129=head1 DESCRIPTION
130
131This class implements Oracle's WhereJoin support. Instead of:
132
133 SELECT x FROM y JOIN z ON y.id = z.id
134
135It will write:
136
137 SELECT x FROM y, z WHERE y.id = z.id
138
139It should properly support left joins, and right joins. Full outer joins are
140not possible due to the fact that Oracle requires the entire query be written
141to union the results of a left and right join, and by the time this module is
142called to create the where query and table definition part of the sql query,
143it's already too late.
144
145=head1 METHODS
146
147This module replaces a subroutine contained in DBIC::SQL::Abstract:
148
149=over
150
151=item sql_maker
152
153=back
154
155It also creates a new module in its BEGIN { } block called
156DBIC::SQL::Abstract::Oracle which has the following methods:
157
158=over
159
160=item select ($\@$;$$@)
161
162Replaces DBIC::SQL::Abstract's select() method, which calls _oracle_joins()
163to modify the column and table list before calling SUPER::select().
164
165=item _recurse_from ($$\@)
166
167Recursive subroutine that builds the table list.
168
169=item _oracle_joins ($$$@)
170
171Creates the left/right relationship in the where query.
172
173=back
174
175=head1 BUGS
176
177Does not support full outer joins.
178Probably lots more.
179
180=head1 SEE ALSO
181
182=over
183
184=item L<DBIC::SQL::Abstract>
185
186=item L<DBIx::Class::Storage::DBI::Oracle::Generic>
187
188=item L<DBIx::Class>
189
190=back
191
192=head1 AUTHOR
193
194Justin Wheeler C<< <jwheeler@datademons.com> >>
195
196=head1 CONTRIBUTORS
197
198David Jack Olrik C<< <djo@cpan.org> >>
199
200=head1 LICENSE
201
202This module is licensed under the same terms as Perl itself.
203
204=cut