use Sub::Name 'subname';
use DBIx::Class::Carp;
-use DBIx::Class::Exception;
use namespace::clean;
__PACKAGE__->mk_group_accessors (simple => qw/quote_char name_sep limit_dialect/);
+sub _quoting_enabled {
+ ( defined $_[0]->{quote_char} and length $_[0]->{quote_char} ) ? 1 : 0
+}
+
# for when I need a normalized l/r pair
sub _quote_chars {
+
+ # in case we are called in the old !!$sm->_quote_chars fashion
+ return () if !wantarray and ( ! defined $_[0]->{quote_char} or ! length $_[0]->{quote_char} );
+
map
{ defined $_ ? $_ : '' }
( ref $_[0]->{quote_char} ? (@{$_[0]->{quote_char}}) : ( ($_[0]->{quote_char}) x 2 ) )
my($func) = (caller(1))[3];
__PACKAGE__->throw_exception("[$func] Fatal: " . join ('', @_));
};
-
- # Current SQLA pollutes its namespace - clean for the time being
- namespace::clean->clean_subroutines(qw/SQL::Abstract carp croak confess/);
}
# the "oh noes offset/top without limit" constant
# as the value to abuse with MSSQL ordered subqueries)
sub __max_int () { 0x7FFFFFFF };
+# we ne longer need to check this - DBIC has ways of dealing with it
+# specifically ::Storage::DBI::_resolve_bindattrs()
+sub _assert_bindval_matches_bindtype () { 1 };
+
# poor man's de-qualifier
sub _quote {
$_[0]->next::method( ( $_[0]{_dequalify_idents} and ! ref $_[1] )
my ($self, $table, $fields, $where, $rs_attrs, $limit, $offset) = @_;
- $fields = $self->_recurse_fields($fields);
+ ($fields, @{$self->{select_bind}}) = $self->_recurse_fields($fields);
if (defined $offset) {
$self->throw_exception('A supplied offset must be a non-negative integer')
return $$fields if $ref eq 'SCALAR';
if ($ref eq 'ARRAY') {
- return join(', ', map { $self->_recurse_fields($_) } @$fields);
+ my (@select, @bind);
+ for my $field (@$fields) {
+ my ($select, @new_bind) = $self->_recurse_fields($field);
+ push @select, $select;
+ push @bind, @new_bind;
+ }
+ return (join(', ', @select), @bind);
}
elsif ($ref eq 'HASH') {
my %hash = %$fields; # shallow copy
my $as = delete $hash{-as}; # if supplied
- my ($func, $args, @toomany) = %hash;
+ my ($func, $rhs, @toomany) = %hash;
# there should be only one pair
if (@toomany) {
$self->throw_exception( "Malformed select argument - too many keys in hash: " . join (',', keys %$fields ) );
}
- if (lc ($func) eq 'distinct' && ref $args eq 'ARRAY' && @$args > 1) {
+ if (lc ($func) eq 'distinct' && ref $rhs eq 'ARRAY' && @$rhs > 1) {
$self->throw_exception (
'The select => { distinct => ... } syntax is not supported for multiple columns.'
- .' Instead please use { group_by => [ qw/' . (join ' ', @$args) . '/ ] }'
- .' or { select => [ qw/' . (join ' ', @$args) . '/ ], distinct => 1 }'
+ .' Instead please use { group_by => [ qw/' . (join ' ', @$rhs) . '/ ] }'
+ .' or { select => [ qw/' . (join ' ', @$rhs) . '/ ], distinct => 1 }'
);
}
+ my ($rhs_sql, @rhs_bind) = $self->_recurse_fields($rhs);
my $select = sprintf ('%s( %s )%s',
$self->_sqlcase($func),
- $self->_recurse_fields($args),
+ $rhs_sql,
$as
? sprintf (' %s %s', $self->_sqlcase('as'), $self->_quote ($as) )
: ''
);
- return $select;
+ return ($select, @rhs_bind);
}
- # Is the second check absolutely necessary?
elsif ( $ref eq 'REF' and ref($$fields) eq 'ARRAY' ) {
- push @{$self->{select_bind}}, @{$$fields}[1..$#$$fields];
- return $$fields->[0];
+ return @{$$fields};
}
else {
$self->throw_exception( $ref . qq{ unexpected in _recurse_fields()} );
# What we have been doing forever is hijacking the $order arg of
# SQLA::select to pass in arbitrary pieces of data (first the group_by,
# then pretty much the entire resultset attr-hash, as more and more
-# things in the SQLA space need to have mopre info about the $rs they
+# things in the SQLA space need to have more info about the $rs they
# create SQL for. The alternative would be to keep expanding the
# signature of _select with more and more positional parameters, which
# is just gross. All hail SQLA2!
my $sql = '';
if ($arg->{group_by}) {
- # horible horrible, waiting for refactor
- local $self->{select_bind};
- if (my $g = $self->_recurse_fields($arg->{group_by}) ) {
- $sql .= $self->_sqlcase(' group by ') . $g;
- push @{$self->{group_bind} ||= []}, @{$self->{select_bind}||[]};
+ if ( my ($group_sql, @group_bind) = $self->_recurse_fields($arg->{group_by}) ) {
+ $sql .= $self->_sqlcase(' group by ') . $group_sql;
+ push @{$self->{group_bind}}, @group_bind;
}
}
}
}
+sub _split_order_chunk {
+ my ($self, $chunk) = @_;
+
+ # strip off sort modifiers, but always succeed, so $1 gets reset
+ $chunk =~ s/ (?: \s+ (ASC|DESC) )? \s* $//ix;
+
+ return (
+ $chunk,
+ ( $1 and uc($1) eq 'DESC' ) ? 1 : 0,
+ );
+}
+
sub _table {
# optimized due to hotttnesss
# my ($self, $from) = @_;
sub _recurse_from {
my $self = shift;
-
return join (' ', $self->_gen_from_blocks(@_) );
}
# Backcompat for the old days when a plain hashref
# { 't1.col1' => 't2.col2' } meant ON t1.col1 = t2.col2
- # Once things settle we should start warning here so that
- # folks unroll their hacks
if (
ref $cond eq 'HASH'
and
and
! ref ( (values %$cond)[0] )
) {
+ carp_unique(
+ "ResultSet {from} structures with conditions not conforming to the "
+ . "SQL::Abstract syntax are deprecated: you either need to stop abusing "
+ . "{from} altogether, or express the condition properly using the "
+ . "{ -ident => ... } operator"
+ );
$cond = { keys %$cond => { -ident => values %$cond } }
}
elsif ( ref $cond eq 'ARRAY' ) {
return $self->_recurse_where($cond);
}
-1;
+# This is hideously ugly, but SQLA does not understand multicol IN expressions
+# FIXME TEMPORARY - DQ should have native syntax for this
+# moved here to raise API questions
+#
+# !!! EXPERIMENTAL API !!! WILL CHANGE !!!
+sub _where_op_multicolumn_in {
+ my ($self, $lhs, $rhs) = @_;
+
+ if (! ref $lhs or ref $lhs eq 'ARRAY') {
+ my (@sql, @bind);
+ for (ref $lhs ? @$lhs : $lhs) {
+ if (! ref $_) {
+ push @sql, $self->_quote($_);
+ }
+ elsif (ref $_ eq 'SCALAR') {
+ push @sql, $$_;
+ }
+ elsif (ref $_ eq 'REF' and ref $$_ eq 'ARRAY') {
+ my ($s, @b) = @$$_;
+ push @sql, $s;
+ push @bind, @b;
+ }
+ else {
+ $self->throw_exception("ARRAY of @{[ ref $_ ]}es unsupported for multicolumn IN lhs...");
+ }
+ }
+ $lhs = \[ join(', ', @sql), @bind];
+ }
+ elsif (ref $lhs eq 'SCALAR') {
+ $lhs = \[ $$lhs ];
+ }
+ elsif (ref $lhs eq 'REF' and ref $$lhs eq 'ARRAY' ) {
+ # noop
+ }
+ else {
+ $self->throw_exception( ref($lhs) . "es unsupported for multicolumn IN lhs...");
+ }
-=head1 AUTHORS
+ # is this proper...?
+ $rhs = \[ $self->_recurse_where($rhs) ];
-See L<DBIx::Class/CONTRIBUTORS>.
+ for ($lhs, $rhs) {
+ $$_->[0] = "( $$_->[0] )"
+ unless $$_->[0] =~ /^ \s* \( .* \) \s* $/xs;
+ }
+
+ \[ join( ' IN ', shift @$$lhs, shift @$$rhs ), @$$lhs, @$$rhs ];
+}
+
+=head1 FURTHER QUESTIONS?
-=head1 LICENSE
+Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
-You may distribute this code under the same terms as Perl itself.
+=head1 COPYRIGHT AND LICENSE
+
+This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
+by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
+redistribute it and/or modify it under the same terms as the
+L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
=cut
+
+1;