Handle NULLS clauses when mangling ordering
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / SQLMaker.pm
1 package DBIx::Class::SQLMaker;
2
3 use strict;
4 use warnings;
5
6 =head1 NAME
7
8 DBIx::Class::SQLMaker - An SQL::Abstract-based SQL maker class
9
10 =head1 DESCRIPTION
11
12 This module is currently a subclass of L<SQL::Abstract> and includes a number of
13 DBIC-specific extensions/workarounds, not suitable for inclusion into the
14 L<SQL::Abstract> core. It also provides all (and more than) the functionality
15 of L<SQL::Abstract::Limit>, see L<DBIx::Class::SQLMaker::LimitDialects> for
16 more info.
17
18 Currently the enhancements over L<SQL::Abstract> are:
19
20 =over
21
22 =item * Support for C<JOIN> statements (via extended C<table/from> support)
23
24 =item * Support of functions in C<SELECT> lists
25
26 =item * C<GROUP BY>/C<HAVING> support (via extensions to the order_by parameter)
27
28 =item * A rudimentary multicolumn IN operator
29
30 =item * Support of C<...FOR UPDATE> type of select statement modifiers
31
32 =back
33
34 =head1 ROADMAP
35
36 Some maintainer musings on the current state of SQL generation within DBIC as
37 of Oct 2015
38
39 =head2 Folding of most (or all) of L<SQL::Abstract (SQLA)|SQL::Abstract> into DBIC
40
41 The rise of complex prefetch use, and the general streamlining of result
42 parsing within DBIC ended up pushing the actual SQL generation to the forefront
43 of many casual performance profiles. While the idea behind SQLA's API is sound,
44 the actual implementation is terribly inefficient (once again bumping into the
45 ridiculously high overhead of perl function calls).
46
47 Given that SQLA has a B<very> distinct life on its own, and is used within an
48 order of magnitude more projects compared to DBIC, it is prudent to B<not>
49 disturb the current call chains within SQLA itself. Instead in the near future
50 an effort will be undertaken to seek a more thorough decoupling of DBIC SQL
51 generation from reliance on SQLA, possibly to a point where B<DBIC will no
52 longer depend on SQLA> at all.
53
54 B<The L<SQL::Abstract> library itself will continue being maintained> although
55 it is not likely to gain many extra features, notably dialect support, at least
56 not within the base C<SQL::Abstract> namespace.
57
58 This work (if undertaken) will take into consideration the following
59 constraints:
60
61 =over
62
63 =item Main API compatibility
64
65 The object returned by C<< $schema->storage->sqlmaker >> needs to be able to
66 satisfy most of the basic tests found in the current-at-the-time SQLA dist.
67 While things like L<case|SQL::Abstract/case> or L<logic|SQL::Abstract/logic>
68 or even worse L<convert|SQL::Abstract/convert> will definitely remain
69 unsupported, the rest of the tests should pass (within reason).
70
71 =item Ability to plug back an SQL::Abstract (or derivative)
72
73 During the initial work on L<Data::Query> the test suite of DBIC turned out to
74 be an invaluable asset to iron out hard-to-reason-about corner cases. In
75 addition the test suite is much more vast and intricate than the tests of SQLA
76 itself. This state of affairs is way too valuable to sacrifice in order to gain
77 faster SQL generation. Thus a compile-time-ENV-check will be introduced along
78 with an extra CI configuration to ensure that DBIC is used with an off-the-CPAN
79 SQLA and that it continues to flawlessly run its entire test suite. While this
80 will undoubtedly complicate the implementation of the better performing SQL
81 generator, it will preserve both the usability of the test suite for external
82 projects and will keep L<SQL::Abstract> from regressions in the future.
83
84 =back
85
86 Aside from these constraints it is becoming more and more practical to simply
87 stop using SQLA in day-to-day production deployments of DBIC. The flexibility
88 of the internals is simply not worth the performance cost.
89
90 =head2 Relationship to L<Data::Query (DQ)|Data::Query>
91
92 When initial work on DQ was taking place, the tools in L<::Storage::DBIHacks
93 |http://github.com/dbsrgits/dbix-class/blob/master/lib/DBIx/Class/Storage/DBIHacks.pm>
94 were only beginning to take shape, and it wasn't clear how important they will
95 become further down the road. In fact the I<regexing all over the place> was
96 considered an ugly stop-gap, and even a couple of highly entertaining talks
97 were given to that effect. As the use-cases of DBIC were progressing, and
98 evidence for the importance of supporting arbitrary SQL was mounting, it became
99 clearer that DBIC itself would not really benefit in any way from an
100 integration with DQ, but on the contrary is likely to lose functionality while
101 the corners of the brand new DQ codebase are sanded off.
102
103 The current status of DBIC/DQ integration is that the only benefit is for DQ by
104 having access to the very extensive "early adopter" test suite, in the same
105 manner as early DBIC benefitted tremendously from usurping the Class::DBI test
106 suite. As far as the DBIC user-base - there are no immediate practical upsides
107 to DQ integration, neither in terms of API nor in performance.
108
109 So (as described higher up) the DBIC development effort will in the foreseable
110 future ignore the existence of DQ, and will continue optimizing the preexisting
111 SQLA-based solution, potentially "organically growing" its own compatible
112 implementation. Also (again, as described higher up) the ability to plug a
113 separate SQLA-compatible class providing the necessary surface API will remain
114 possible, and will be protected at all costs in order to continue providing DQ
115 access to the test cases of DBIC.
116
117 In the short term, after one more pass over the ResultSet internals is
118 undertaken I<real soon now (tm)>, and before the SQLA/SQLMaker integration
119 takes place, the preexisting DQ-based branches will be pulled/modified/rebased
120 to get up-to-date with the current state of the codebase, which changed very
121 substantially since the last migration effort, especially in the SQL
122 classification meta-parsing codepath.
123
124 =cut
125
126 use base qw/
127   DBIx::Class::SQLMaker::LimitDialects
128   SQL::Abstract
129   DBIx::Class
130 /;
131 use mro 'c3';
132
133 use DBIx::Class::Carp;
134 use DBIx::Class::_Util 'set_subname';
135 use namespace::clean;
136
137 __PACKAGE__->mk_group_accessors (simple => qw/quote_char name_sep limit_dialect/);
138
139 sub _quoting_enabled {
140   ( defined $_[0]->{quote_char} and length $_[0]->{quote_char} ) ? 1 : 0
141 }
142
143 # for when I need a normalized l/r pair
144 sub _quote_chars {
145
146   # in case we are called in the old !!$sm->_quote_chars fashion
147   return () if !wantarray and ( ! defined $_[0]->{quote_char} or ! length $_[0]->{quote_char} );
148
149   map
150     { defined $_ ? $_ : '' }
151     ( ref $_[0]->{quote_char} ? (@{$_[0]->{quote_char}}) : ( ($_[0]->{quote_char}) x 2 ) )
152   ;
153 }
154
155 # FIXME when we bring in the storage weaklink, check its schema
156 # weaklink and channel through $schema->throw_exception
157 sub throw_exception { DBIx::Class::Exception->throw($_[1]) }
158
159 BEGIN {
160   # reinstall the belch()/puke() functions of SQL::Abstract with custom versions
161   # that use DBIx::Class::Carp/DBIx::Class::Exception instead of plain Carp
162   no warnings qw/redefine/;
163
164   *SQL::Abstract::belch = set_subname 'SQL::Abstract::belch' => sub (@) {
165     my($func) = (caller(1))[3];
166     carp "[$func] Warning: ", @_;
167   };
168
169   *SQL::Abstract::puke = set_subname 'SQL::Abstract::puke' => sub (@) {
170     my($func) = (caller(1))[3];
171     __PACKAGE__->throw_exception("[$func] Fatal: " . join ('',  @_));
172   };
173 }
174
175 # the "oh noes offset/top without limit" constant
176 # limited to 31 bits for sanity (and consistency,
177 # since it may be handed to the like of sprintf %u)
178 #
179 # Also *some* builds of SQLite fail the test
180 #   some_column BETWEEN ? AND ?: 1, 4294967295
181 # with the proper integer bind attrs
182 #
183 # Implemented as a method, since ::Storage::DBI also
184 # refers to it (i.e. for the case of software_limit or
185 # as the value to abuse with MSSQL ordered subqueries)
186 sub __max_int () { 0x7FFFFFFF };
187
188 # we ne longer need to check this - DBIC has ways of dealing with it
189 # specifically ::Storage::DBI::_resolve_bindattrs()
190 sub _assert_bindval_matches_bindtype () { 1 };
191
192 # poor man's de-qualifier
193 sub _quote {
194   $_[0]->next::method( ( $_[0]{_dequalify_idents} and ! ref $_[1] )
195     ? $_[1] =~ / ([^\.]+) $ /x
196     : $_[1]
197   );
198 }
199
200 sub _where_op_NEST {
201   carp_unique ("-nest in search conditions is deprecated, you most probably wanted:\n"
202       .q|{..., -and => [ \%cond0, \@cond1, \'cond2', \[ 'cond3', [ col => bind ] ], etc. ], ... }|
203   );
204
205   shift->next::method(@_);
206 }
207
208 # Handle limit-dialect selection
209 sub select {
210   my ($self, $table, $fields, $where, $rs_attrs, $limit, $offset) = @_;
211
212
213   ($fields, @{$self->{select_bind}}) = $self->_recurse_fields($fields);
214
215   if (defined $offset) {
216     $self->throw_exception('A supplied offset must be a non-negative integer')
217       if ( $offset =~ /[^0-9]/ or $offset < 0 );
218   }
219   $offset ||= 0;
220
221   if (defined $limit) {
222     $self->throw_exception('A supplied limit must be a positive integer')
223       if ( $limit =~ /[^0-9]/ or $limit <= 0 );
224   }
225   elsif ($offset) {
226     $limit = $self->__max_int;
227   }
228
229
230   my ($sql, @bind);
231   if ($limit) {
232     # this is legacy code-flow from SQLA::Limit, it is not set in stone
233
234     ($sql, @bind) = $self->next::method ($table, $fields, $where);
235
236     my $limiter;
237
238     if( $limiter = $self->can ('emulate_limit') ) {
239       carp_unique(
240         'Support for the legacy emulate_limit() mechanism inherited from '
241       . 'SQL::Abstract::Limit has been deprecated, and will be removed at '
242       . 'some future point, as it gets in the way of architectural and/or '
243       . 'performance advances within DBIC. If your code uses this type of '
244       . 'limit specification please file an RT and provide the source of '
245       . 'your emulate_limit() implementation, so an acceptable upgrade-path '
246       . 'can be devised'
247       );
248     }
249     else {
250       my $dialect = $self->limit_dialect
251         or $self->throw_exception( "Unable to generate SQL-limit - no limit dialect specified on $self" );
252
253       $limiter = $self->can ("_$dialect")
254         or $self->throw_exception(__PACKAGE__ . " does not implement the requested dialect '$dialect'");
255     }
256
257     $sql = $self->$limiter (
258       $sql,
259       { %{$rs_attrs||{}}, _selector_sql => $fields },
260       $limit,
261       $offset
262     );
263   }
264   else {
265     ($sql, @bind) = $self->next::method ($table, $fields, $where, $rs_attrs);
266   }
267
268   push @{$self->{where_bind}}, @bind;
269
270 # this *must* be called, otherwise extra binds will remain in the sql-maker
271   my @all_bind = $self->_assemble_binds;
272
273   $sql .= $self->_lock_select ($rs_attrs->{for})
274     if $rs_attrs->{for};
275
276   return wantarray ? ($sql, @all_bind) : $sql;
277 }
278
279 sub _assemble_binds {
280   my $self = shift;
281   return map { @{ (delete $self->{"${_}_bind"}) || [] } } (qw/pre_select select from where group having order limit/);
282 }
283
284 my $for_syntax = {
285   update => 'FOR UPDATE',
286   shared => 'FOR SHARE',
287 };
288 sub _lock_select {
289   my ($self, $type) = @_;
290
291   my $sql;
292   if (ref($type) eq 'SCALAR') {
293     $sql = "FOR $$type";
294   }
295   else {
296     $sql = $for_syntax->{$type} || $self->throw_exception( "Unknown SELECT .. FOR type '$type' requested" );
297   }
298
299   return " $sql";
300 }
301
302 # Handle default inserts
303 sub insert {
304 # optimized due to hotttnesss
305 #  my ($self, $table, $data, $options) = @_;
306
307   # FIXME SQLA will emit INSERT INTO $table ( ) VALUES ( )
308   # which is sadly understood only by MySQL. Change default behavior here,
309   # until we fold the extra pieces into SQLMaker properly
310   if (! $_[2] or (ref $_[2] eq 'HASH' and !keys %{$_[2]} ) ) {
311     my @bind;
312     my $sql = sprintf(
313       'INSERT INTO %s DEFAULT VALUES', $_[0]->_quote($_[1])
314     );
315
316     if ( ($_[3]||{})->{returning} ) {
317       my $s;
318       ($s, @bind) = $_[0]->_insert_returning ($_[3]);
319       $sql .= $s;
320     }
321
322     return ($sql, @bind);
323   }
324
325   next::method(@_);
326 }
327
328 sub _recurse_fields {
329   my ($self, $fields) = @_;
330   my $ref = ref $fields;
331   return $self->_quote($fields) unless $ref;
332   return $$fields if $ref eq 'SCALAR';
333
334   if ($ref eq 'ARRAY') {
335     my (@select, @bind);
336     for my $field (@$fields) {
337       my ($select, @new_bind) = $self->_recurse_fields($field);
338       push @select, $select;
339       push @bind, @new_bind;
340     }
341     return (join(', ', @select), @bind);
342   }
343   elsif ($ref eq 'HASH') {
344     my %hash = %$fields;  # shallow copy
345
346     my $as = delete $hash{-as};   # if supplied
347
348     my ($func, $rhs, @toomany) = %hash;
349
350     # there should be only one pair
351     if (@toomany) {
352       $self->throw_exception( "Malformed select argument - too many keys in hash: " . join (',', keys %$fields ) );
353     }
354
355     if (lc ($func) eq 'distinct' && ref $rhs eq 'ARRAY' && @$rhs > 1) {
356       $self->throw_exception (
357         'The select => { distinct => ... } syntax is not supported for multiple columns.'
358        .' Instead please use { group_by => [ qw/' . (join ' ', @$rhs) . '/ ] }'
359        .' or { select => [ qw/' . (join ' ', @$rhs) . '/ ], distinct => 1 }'
360       );
361     }
362
363     my ($rhs_sql, @rhs_bind) = $self->_recurse_fields($rhs);
364     my $select = sprintf ('%s( %s )%s',
365       $self->_sqlcase($func),
366       $rhs_sql,
367       $as
368         ? sprintf (' %s %s', $self->_sqlcase('as'), $self->_quote ($as) )
369         : ''
370     );
371
372     return ($select, @rhs_bind);
373   }
374   elsif ( $ref eq 'REF' and ref($$fields) eq 'ARRAY' ) {
375     return @{$$fields};
376   }
377   else {
378     $self->throw_exception( $ref . qq{ unexpected in _recurse_fields()} );
379   }
380 }
381
382
383 # this used to be a part of _order_by but is broken out for clarity.
384 # What we have been doing forever is hijacking the $order arg of
385 # SQLA::select to pass in arbitrary pieces of data (first the group_by,
386 # then pretty much the entire resultset attr-hash, as more and more
387 # things in the SQLA space need to have more info about the $rs they
388 # create SQL for. The alternative would be to keep expanding the
389 # signature of _select with more and more positional parameters, which
390 # is just gross.
391 #
392 # FIXME - this will have to transition out to a subclass when the effort
393 # of folding the SQLA machinery into SQLMaker takes place
394 sub _parse_rs_attrs {
395   my ($self, $arg) = @_;
396
397   my $sql = '';
398   my @sqlbind;
399
400   if (
401     $arg->{group_by}
402       and
403     @sqlbind = $self->_recurse_fields($arg->{group_by})
404   ) {
405     $sql .= $self->_sqlcase(' group by ') . shift @sqlbind;
406     push @{$self->{group_bind}}, @sqlbind;
407   }
408
409   if (
410     $arg->{having}
411       and
412     @sqlbind = $self->_recurse_where($arg->{having})
413   ) {
414     $sql .= $self->_sqlcase(' having ') . shift @sqlbind;
415     push(@{$self->{having_bind}}, @sqlbind);
416   }
417
418   if ($arg->{order_by}) {
419     # unlike the 2 above, _order_by injects into @{...bind...} for us
420     $sql .= $self->_order_by ($arg->{order_by});
421   }
422
423   return $sql;
424 }
425
426 sub _order_by {
427   my ($self, $arg) = @_;
428
429   # check that we are not called in legacy mode (order_by as 4th argument)
430   (
431     ref $arg eq 'HASH'
432       and
433     not grep { $_ =~ /^-(?:desc|asc)/i } keys %$arg
434   )
435     ? $self->_parse_rs_attrs ($arg)
436     : do {
437       my ($sql, @bind) = $self->next::method($arg);
438       push @{$self->{order_bind}}, @bind;
439       $sql; # RV
440     }
441   ;
442 }
443
444 sub _split_order_chunk {
445   my ($self, $chunk) = @_;
446
447   # strip off sort modifiers, but always succeed, so $1 gets reset
448   $chunk =~ s/ (?: \s+ (ASC|DESC) )? (?: \s+ NULLS \s+ (FIRST|LAST) )? \s* $//ix;
449
450   return (
451     $chunk,
452     ( $1 and uc($1) eq 'DESC' ) ? 1 : 0,
453     $2 ? uc($2) : undef
454   );
455 }
456
457 sub _table {
458 # optimized due to hotttnesss
459 #  my ($self, $from) = @_;
460   if (my $ref = ref $_[1] ) {
461     if ($ref eq 'ARRAY') {
462       return $_[0]->_recurse_from(@{$_[1]});
463     }
464     elsif ($ref eq 'HASH') {
465       return $_[0]->_recurse_from($_[1]);
466     }
467     elsif ($ref eq 'REF' && ref ${$_[1]} eq 'ARRAY') {
468       my ($sql, @bind) = @{ ${$_[1]} };
469       push @{$_[0]->{from_bind}}, @bind;
470       return $sql
471     }
472   }
473   return $_[0]->next::method ($_[1]);
474 }
475
476 sub _generate_join_clause {
477     my ($self, $join_type) = @_;
478
479     $join_type = $self->{_default_jointype}
480       if ! defined $join_type;
481
482     return sprintf ('%s JOIN ',
483       $join_type ?  $self->_sqlcase($join_type) : ''
484     );
485 }
486
487 sub _recurse_from {
488   my $self = shift;
489   return join (' ', $self->_gen_from_blocks(@_) );
490 }
491
492 sub _gen_from_blocks {
493   my ($self, $from, @joins) = @_;
494
495   my @fchunks = $self->_from_chunk_to_sql($from);
496
497   for (@joins) {
498     my ($to, $on) = @$_;
499
500     # check whether a join type exists
501     my $to_jt = ref($to) eq 'ARRAY' ? $to->[0] : $to;
502     my $join_type;
503     if (ref($to_jt) eq 'HASH' and defined($to_jt->{-join_type})) {
504       $join_type = $to_jt->{-join_type};
505       $join_type =~ s/^\s+ | \s+$//xg;
506     }
507
508     my @j = $self->_generate_join_clause( $join_type );
509
510     if (ref $to eq 'ARRAY') {
511       push(@j, '(', $self->_recurse_from(@$to), ')');
512     }
513     else {
514       push(@j, $self->_from_chunk_to_sql($to));
515     }
516
517     my ($sql, @bind) = $self->_join_condition($on);
518     push(@j, ' ON ', $sql);
519     push @{$self->{from_bind}}, @bind;
520
521     push @fchunks, join '', @j;
522   }
523
524   return @fchunks;
525 }
526
527 sub _from_chunk_to_sql {
528   my ($self, $fromspec) = @_;
529
530   return join (' ', do {
531     if (! ref $fromspec) {
532       $self->_quote($fromspec);
533     }
534     elsif (ref $fromspec eq 'SCALAR') {
535       $$fromspec;
536     }
537     elsif (ref $fromspec eq 'REF' and ref $$fromspec eq 'ARRAY') {
538       push @{$self->{from_bind}}, @{$$fromspec}[1..$#$$fromspec];
539       $$fromspec->[0];
540     }
541     elsif (ref $fromspec eq 'HASH') {
542       my ($as, $table, $toomuch) = ( map
543         { $_ => $fromspec->{$_} }
544         ( grep { $_ !~ /^\-/ } keys %$fromspec )
545       );
546
547       $self->throw_exception( "Only one table/as pair expected in from-spec but an exra '$toomuch' key present" )
548         if defined $toomuch;
549
550       ($self->_from_chunk_to_sql($table), $self->_quote($as) );
551     }
552     else {
553       $self->throw_exception('Unsupported from refkind: ' . ref $fromspec );
554     }
555   });
556 }
557
558 sub _join_condition {
559   my ($self, $cond) = @_;
560
561   # Backcompat for the old days when a plain hashref
562   # { 't1.col1' => 't2.col2' } meant ON t1.col1 = t2.col2
563   if (
564     ref $cond eq 'HASH'
565       and
566     keys %$cond == 1
567       and
568     (keys %$cond)[0] =~ /\./
569       and
570     ! ref ( (values %$cond)[0] )
571   ) {
572     carp_unique(
573       "ResultSet {from} structures with conditions not conforming to the "
574     . "SQL::Abstract syntax are deprecated: you either need to stop abusing "
575     . "{from} altogether, or express the condition properly using the "
576     . "{ -ident => ... } operator"
577     );
578     $cond = { keys %$cond => { -ident => values %$cond } }
579   }
580   elsif ( ref $cond eq 'ARRAY' ) {
581     # do our own ORing so that the hashref-shim above is invoked
582     my @parts;
583     my @binds;
584     foreach my $c (@$cond) {
585       my ($sql, @bind) = $self->_join_condition($c);
586       push @binds, @bind;
587       push @parts, $sql;
588     }
589     return join(' OR ', @parts), @binds;
590   }
591
592   return $self->_recurse_where($cond);
593 }
594
595 # !!! EXPERIMENTAL API !!! WILL CHANGE !!!
596 #
597 # This is rather odd, but vanilla SQLA does not have support for multicolumn IN
598 # expressions
599 # Currently has only one callsite in ResultSet, body moved into this subclass
600 # of SQLA to raise API questions like:
601 # - how do we convey a list of idents...?
602 # - can binds reside on lhs?
603 #
604 # !!! EXPERIMENTAL API !!! WILL CHANGE !!!
605 sub _where_op_multicolumn_in {
606   my ($self, $lhs, $rhs) = @_;
607
608   if (! ref $lhs or ref $lhs eq 'ARRAY') {
609     my (@sql, @bind);
610     for (ref $lhs ? @$lhs : $lhs) {
611       if (! ref $_) {
612         push @sql, $self->_quote($_);
613       }
614       elsif (ref $_ eq 'SCALAR') {
615         push @sql, $$_;
616       }
617       elsif (ref $_ eq 'REF' and ref $$_ eq 'ARRAY') {
618         my ($s, @b) = @$$_;
619         push @sql, $s;
620         push @bind, @b;
621       }
622       else {
623         $self->throw_exception("ARRAY of @{[ ref $_ ]}es unsupported for multicolumn IN lhs...");
624       }
625     }
626     $lhs = \[ join(', ', @sql), @bind];
627   }
628   elsif (ref $lhs eq 'SCALAR') {
629     $lhs = \[ $$lhs ];
630   }
631   elsif (ref $lhs eq 'REF' and ref $$lhs eq 'ARRAY' ) {
632     # noop
633   }
634   else {
635     $self->throw_exception( ref($lhs) . "es unsupported for multicolumn IN lhs...");
636   }
637
638   # is this proper...?
639   $rhs = \[ $self->_recurse_where($rhs) ];
640
641   for ($lhs, $rhs) {
642     $$_->[0] = "( $$_->[0] )"
643       unless $$_->[0] =~ /^ \s* \( .* \) \s* $/xs;
644   }
645
646   \[ join( ' IN ', shift @$$lhs, shift @$$rhs ), @$$lhs, @$$rhs ];
647 }
648
649 =head1 FURTHER QUESTIONS?
650
651 Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
652
653 =head1 COPYRIGHT AND LICENSE
654
655 This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
656 by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
657 redistribute it and/or modify it under the same terms as the
658 L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
659
660 =cut
661
662 1;