use List::Util 'first';
use Scalar::Util 'blessed';
-use Sub::Name 'subname';
-use DBIx::Class::_Util qw(is_plain_value is_literal_value UNRESOLVABLE_CONDITION);
+use DBIx::Class::_Util 'UNRESOLVABLE_CONDITION';
+use SQL::Abstract qw(is_plain_value is_literal_value);
use namespace::clean;
#
my $outer_attrs = { %$attrs };
delete @{$outer_attrs}{qw(from bind rows offset group_by _grouped_by_distinct having)};
- my $inner_attrs = { %$attrs };
- delete @{$inner_attrs}{qw(for collapse select as _related_results_construction)};
+ my $inner_attrs = { %$attrs, _simple_passthrough_construction => 1 };
+ delete @{$inner_attrs}{qw(for collapse select as)};
# there is no point of ordering the insides if there is no limit
delete $inner_attrs->{order_by} if (
# name_sep, otherwise sorry nasty legacy syntax like
# { 'count(foo.id)' => { '>' => 3 } } will stop working >:(
local $sql_maker->{quote_char} = $sql_maker->{quote_char};
+ local $sql_maker->{escape_char} = $sql_maker->{escape_char};
local $sql_maker->{name_sep} = $sql_maker->{name_sep};
unless (defined $sql_maker->{quote_char} and length $sql_maker->{quote_char}) {
$sql_maker->{quote_char} = ["\x00", "\xFF"];
+ $sql_maker->{escape_char} = "\xFF";
# if we don't unset it we screw up retarded but unfortunately working
# 'MAX(foo.bar)' => { '>', 3 }
$sql_maker->{name_sep} = '';
# now loop through all fully qualified columns and get the corresponding
# alias (should work even if they are in scalarrefs)
+ my $ident_re = $sql_maker->_quoted_ident_re;
for my $alias (keys %$alias_list) {
my $al_re = qr/
- $lquote $alias $rquote $sep (?: $lquote ([^$rquote]+) $rquote )?
+ $lquote \Q$alias\E $rquote $sep ($ident_re)?
|
- \b $alias \. ([^\s\)\($rquote]+)?
+ \b \Q$alias\E \. ([^\s\)\($rquote]+)?
/x;
for my $type (keys %$to_scan) {
for my $piece (@{$to_scan->{$type}}) {
- if (my @matches = $piece =~ /$al_re/g) {
+ if (my @matches = map { $sql_maker->_unquote($_) } $piece =~ /$al_re/g) {
$aliases_by_type->{$type}{$alias} ||= { -parents => $alias_list->{$alias}{-join_path}||[] };
$aliases_by_type->{$type}{$alias}{-seen_columns}{"$alias.$_"} = "$alias.$_"
for grep { defined $_ } @matches;
for my $col (keys %$colinfo) {
next if $col =~ / \. /x; # if column is qualified it was caught by the above
- my $col_re = qr/ $lquote ($col) $rquote /x;
+ my $col_re = qr/ $lquote (\Q$col\E) $rquote /x;
for my $type (keys %$to_scan) {
for my $piece (@{$to_scan->{$type}}) {
return scalar $sql_maker->_order_by_chunks ($order_by)
unless wantarray;
- my ($lq, $rq, $sep) = map { quotemeta($_) } (
- ($orig_quote_chars ? @$orig_quote_chars : $sql_maker->_quote_chars),
- $sql_maker->name_sep
- );
+ my $sep = quotemeta($sql_maker->name_sep);
+
+ my @quotes = map { quotemeta($_) }
+ $orig_quote_chars
+ ? @$orig_quote_chars
+ : ($sql_maker->_quote_chars, $sql_maker->_escape_char);
+
+ my $quoted_ident_re = $sql_maker->_quoted_ident_re(@quotes);
my @chunks;
for ($sql_maker->_order_by_chunks ($order_by) ) {
# order criteria may have come back pre-quoted (literals and whatnot)
# this is fragile, but the best we can currently do
- $chunk->[0] =~ s/^ $lq (.+?) $rq $sep $lq (.+?) $rq $/"$1.$2"/xe
- or $chunk->[0] =~ s/^ $lq (.+) $rq $/$1/x;
+ if (my @quoted = $chunk->[0] =~ /\A ($quoted_ident_re) (?: $sep ($quoted_ident_re) )? \z/x) {
+ $chunk->[0] = join('.', map { $sql_maker->_unquote($_, @quotes) } grep { defined } @quoted);
+ }
push @chunks, $chunk;
}
# pass these in to deal with literals coming from
# the user or the deep guts of prefetch
- my $orig_quote_chars = [$sql_maker->_quote_chars];
+ my $orig_quote_chars = [$sql_maker->_quote_chars, $sql_maker->_escape_char];
local $sql_maker->{quote_char};
return $parser->($sql_maker, $order_by, $orig_quote_chars);