X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FSQLAHacks.pm;h=3cf750c151dae47b5a27cfb26a1005286950d1cb;hb=f8583f8f51fd7ac8eeb348ad390219152a8a3bf8;hp=faa3a48dc153f86ae8dc56efa42c5e03e251654f;hpb=25abda27234677d2fc89230c0e11bb2fe56b6b20;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/SQLAHacks.pm b/lib/DBIx/Class/SQLAHacks.pm index faa3a48..3cf750c 100644 --- a/lib/DBIx/Class/SQLAHacks.pm +++ b/lib/DBIx/Class/SQLAHacks.pm @@ -8,8 +8,10 @@ package # Hide from PAUSE use base qw/SQL::Abstract::Limit/; use strict; use warnings; -use Carp::Clan qw/^DBIx::Class|^SQL::Abstract/; -use Sub::Name(); +use List::Util 'first'; +use Sub::Name 'subname'; +use namespace::clean; +use Carp::Clan qw/^DBIx::Class|^SQL::Abstract|^Try::Tiny/; BEGIN { # reinstall the carp()/croak() functions imported into SQL::Abstract @@ -19,7 +21,7 @@ BEGIN { for my $f (qw/carp croak/) { my $orig = \&{"SQL::Abstract::$f"}; - *{"SQL::Abstract::$f"} = Sub::Name::subname "SQL::Abstract::$f" => + *{"SQL::Abstract::$f"} = subname "SQL::Abstract::$f" => sub { if (Carp::longmess() =~ /DBIx::Class::SQLAHacks::[\w]+ .+? called \s at/x) { __PACKAGE__->can($f)->(@_); @@ -31,6 +33,11 @@ BEGIN { } } +# the "oh noes offset/top without limit" constant +# limited to 32 bits for sanity (and since it is fed +# to sprintf %u) +sub __max_int { 0xFFFFFFFF }; + # Tries to determine limit dialect. # @@ -115,8 +122,8 @@ sub _subqueried_limit_attrs { # for possible further chaining) my (@in_sel, @out_sel, %renamed); for my $node (@sel) { - if (List::Util::first { $_ =~ / (?{as}, $node->{unquoted_sql}) ) { - $node->{as} =~ s/ $re_sep /__/xg; + if (first { $_ =~ / (?{as}, $node->{unquoted_sql}) ) { + $node->{as} = $self->_unqualify_colname($node->{as}); my $quoted_as = $self->_quote($node->{as}); push @in_sel, sprintf '%s AS %s', $node->{sql}, $quoted_as; push @out_sel, $quoted_as; @@ -152,6 +159,13 @@ sub _subqueried_limit_attrs { ); } +sub _unqualify_colname { + my ($self, $fqcn) = @_; + my $re_sep = quotemeta($self->name_sep || '.'); + $fqcn =~ s/ $re_sep /__/xg; + return $fqcn; +} + # ANSI standard Limit/Offset implementation. DB2 and MSSQL >= 2005 use this sub _RowNumberOver { my ($self, $sql, $rs_attrs, $rows, $offset ) = @_; @@ -390,6 +404,21 @@ sub _Top { return $sql; } +# This for Sybase ASE, to use SET ROWCOUNT when there is no offset, and +# GenericSubQ otherwise. +sub _RowCountOrGenericSubQ { + my $self = shift; + my ($sql, $rs_attrs, $rows, $offset) = @_; + + return $self->_GenericSubQ(@_) if $offset; + + return sprintf <<"EOF", $rows, $sql; +SET ROWCOUNT %d +%s +SET ROWCOUNT 0 +EOF +} + # This is the most evil limit "dialect" (more of a hack) for *really* # stupid databases. It works by ordering the set by some unique column, # and calculating amount of rows that have a less-er value (thus @@ -466,7 +495,8 @@ sub _GenericSubQ { my $cmp_op = $direction eq 'desc' ? '>' : '<'; my $count_tbl_alias = 'rownum__emulation'; - my $order_group_having = $self->_parse_rs_attrs($rs_attrs); + my $order_sql = $self->_order_by (delete $rs_attrs->{order_by}); + my $group_having_sql = $self->_parse_rs_attrs($rs_attrs); # add the order supplement (if any) as this is what will be used for the outer WHERE $in_sel .= ", $_" for keys %{$extra_order_sel||{}}; @@ -474,9 +504,10 @@ sub _GenericSubQ { $sql = sprintf (<_quote ($_) } ( $rs_attrs->{alias}, @@ -508,8 +539,6 @@ sub _find_syntax { sub select { my ($self, $table, $fields, $where, $rs_attrs, @rest) = @_; - $self->{"${_}_bind"} = [] for (qw/having from order/); - if (not ref($table) or ref($table) eq 'SCALAR') { $table = $self->_quote($table); } @@ -518,10 +547,20 @@ sub select { croak "LIMIT 0 Does Not Compute" if $rest[0] == 0; # and anyway, SQL::Abstract::Limit will cause a barf if we don't first - my ($sql, @where_bind) = $self->SUPER::select( + my ($sql, @bind) = $self->SUPER::select( $table, $self->_recurse_fields($fields), $where, $rs_attrs, @rest ); - return wantarray ? ($sql, @{$self->{from_bind}}, @where_bind, @{$self->{having_bind}}, @{$self->{order_bind}} ) : $sql; + push @{$self->{where_bind}}, @bind; + +# this *must* be called, otherwise extra binds will remain in the sql-maker + my @all_bind = $self->_assemble_binds; + + return wantarray ? ($sql, @all_bind) : $sql; +} + +sub _assemble_binds { + my $self = shift; + return map { @{ (delete $self->{"${_}_bind"}) || [] } } (qw/from where having order/); } # Quotes table names, and handles default inserts @@ -783,7 +822,7 @@ sub _join_condition { } elsif (ref $cond eq 'ARRAY') { return join(' OR ', map { $self->_join_condition($_) } @$cond); } else { - die "Can't handle this yet!"; + croak "Can't handle this yet!"; } }