Skip to content

Commit

Permalink
Set name_sep by default (even if unused). Simplify raw-sql scanner code
Browse files Browse the repository at this point in the history
  • Loading branch information
ribasushi committed Oct 14, 2010
1 parent f3e9f01 commit 3f5b99f
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 48 deletions.
3 changes: 2 additions & 1 deletion lib/DBIx/Class/Manual/Cookbook.pod
Expand Up @@ -1669,7 +1669,8 @@ brackets, or a C<"> or C<'>:

Check the documentation of your database for the correct quote
characters to use. C<name_sep> needs to be set to allow the SQL
generator to put the quotes the correct place.
generator to put the quotes the correct place, and defaults to
C<.> if not supplied.

In most cases you should set these as part of the arguments passed to
L<DBIx::Class::Schema/connect>:
Expand Down
8 changes: 8 additions & 0 deletions lib/DBIx/Class/SQLMaker.pm
Expand Up @@ -42,6 +42,14 @@ use namespace::clean;

__PACKAGE__->mk_group_accessors (simple => qw/quote_char name_sep limit_dialect/);

# for when I need a normalized l/r pair
sub _quote_chars {
map
{ defined $_ ? $_ : '' }
( ref $_[0]->{quote_char} ? (@{$_[0]->{quote_char}}) : ( ($_[0]->{quote_char}) x 2 ) )
;
}

BEGIN {
# reinstall the carp()/croak() functions imported into SQL::Abstract
# as Carp and Carp::Clan do not like each other much
Expand Down
16 changes: 8 additions & 8 deletions lib/DBIx/Class/SQLMaker/LimitDialects.pm
Expand Up @@ -348,7 +348,7 @@ sub _Top {
my $inner_order = ($order_by_requested
? $requested_order
: [ map
{ join ('', $rs_attrs->{alias}, $self->{name_sep}||'.', $_ ) }
{ "$rs_attrs->{alias}.$_" }
( $rs_attrs->{_rsroot_source_handle}->resolve->_pri_cols )
]
);
Expand Down Expand Up @@ -608,10 +608,7 @@ sub _subqueried_limit_attrs {
croak 'Limit dialect implementation usable only in the context of DBIC (missing $rs_attrs)'
unless ref ($rs_attrs) eq 'HASH';

my ($re_sep, $re_alias) = map { quotemeta $_ } (
$self->name_sep || '.',
$rs_attrs->{alias},
);
my ($re_sep, $re_alias) = map { quotemeta $_ } ( $self->{name_sep}, $rs_attrs->{alias} );

# correlate select and as, build selection index
my (@sel, $in_sel_index);
Expand Down Expand Up @@ -651,7 +648,11 @@ sub _subqueried_limit_attrs {
# for possible further chaining)
my (@in_sel, @out_sel, %renamed);
for my $node (@sel) {
if (first { $_ =~ / (?<! ^ $re_alias ) $re_sep /x } ($node->{as}, $node->{unquoted_sql}) ) {
if (
$node->{as} =~ / (?<! ^ $re_alias ) \. /x
or
$node->{unquoted_sql} =~ / (?<! ^ $re_alias ) $re_sep /x
) {
$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;
Expand Down Expand Up @@ -690,8 +691,7 @@ sub _subqueried_limit_attrs {

sub _unqualify_colname {
my ($self, $fqcn) = @_;
my $re_sep = quotemeta($self->name_sep || '.');
$fqcn =~ s/ $re_sep /__/xg;
$fqcn =~ s/ \. /__/xg;
return $fqcn;
}

Expand Down
15 changes: 5 additions & 10 deletions lib/DBIx/Class/Storage/DBI.pm
Expand Up @@ -453,8 +453,7 @@ of available limit dialects see L<DBIx::Class::SQLMaker::LimitDialects>.
=item quote_char
Specifies what characters to use to quote table and column names. If
you use this you will want to specify L</name_sep> as well.
Specifies what characters to use to quote table and column names.
C<quote_char> expects either a single character, in which case is it
is placed on either side of the table/column name, or an arrayref of length
Expand All @@ -465,14 +464,9 @@ SQL Server you should use C<< quote_char => [qw/[ ]/] >>.
=item name_sep
This only needs to be used in conjunction with C<quote_char>, and is used to
This parameter is only useful in conjunction with C<quote_char>, and is used to
specify the character that separates elements (schemas, tables, columns) from
each other. In most cases this is simply a C<.>.
The consequences of not supplying this value is that L<SQL::Abstract>
will assume DBIx::Class' uses of aliases to be complete column
names. The output will look like I<"me.name"> when it should actually
be I<"me"."name">.
each other. If unspecified it defaults to the most commonly used C<.>.
=item unsafe
Expand Down Expand Up @@ -525,7 +519,7 @@ L<DBIx::Class::Schema/connect>
'postgres',
'my_pg_password',
{ AutoCommit => 1 },
{ quote_char => q{"}, name_sep => q{.} },
{ quote_char => q{"} },
]
);
Expand Down Expand Up @@ -999,6 +993,7 @@ sub sql_maker {
bindtype=>'columns',
array_datatypes => 1,
limit_dialect => $dialect,
name_sep => '.',
%opts,
));
}
Expand Down
51 changes: 23 additions & 28 deletions lib/DBIx/Class/Storage/DBIHacks.pm
Expand Up @@ -226,21 +226,27 @@ sub _resolve_aliastypes_from_select_args {

# set up a botched SQLA
my $sql_maker = $self->sql_maker;
my $sep = quotemeta ($self->_sql_maker_opts->{name_sep} || '.');

my ($orig_lquote, $orig_rquote) = map { quotemeta $_ } (do {
if (ref $sql_maker->{quote_char} eq 'ARRAY') {
@{$sql_maker->{quote_char}}
}
else {
($sql_maker->{quote_char} || '') x 2;
}
});
local $sql_maker->{having_bind}; # these are throw away results

# we can't scan properly without any quoting (\b doesn't cut it
# everywhere), so unless there is proper quoting set - use our
# own weird impossible character.
# Also in the case of no quoting, we need to explicitly disable
# 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->{name_sep} = $sql_maker->{name_sep};

unless (defined $sql_maker->{quote_char} and length $sql_maker->{quote_char}) {
$sql_maker->{quote_char} = "\x00";
$sql_maker->{name_sep} = '';
}

my ($lquote, $rquote, $sep) = map { quotemeta $_ } ($sql_maker->_quote_chars, $sql_maker->name_sep);

local $sql_maker->{quote_char} = "\x00"; # so that we can regex away

# generate sql chunks
local $sql_maker->{having_bind}; # these are throw away results
my $to_scan = {
restricting => [
$sql_maker->_recurse_where ($where),
Expand All @@ -261,16 +267,11 @@ sub _resolve_aliastypes_from_select_args {
# alias (should work even if they are in scalarrefs)
for my $alias (keys %$alias_list) {
my $al_re = qr/
\x00 $alias \x00 $sep
$lquote $alias $rquote $sep
|
\b $alias $sep
\b $alias \.
/x;

# add matching for possible quoted literal sql
$al_re = qr/ $al_re | $orig_lquote $alias $orig_rquote /x
if ($orig_lquote && $orig_rquote);


for my $type (keys %$to_scan) {
for my $piece (@{$to_scan->{$type}}) {
$aliases_by_type->{$type}{$alias} = 1 if ($piece =~ $al_re);
Expand All @@ -281,12 +282,9 @@ sub _resolve_aliastypes_from_select_args {
# now loop through unqualified column names, and try to locate them within
# the chunks
for my $col (keys %$colinfo) {
next if $col =~ $sep; # if column is qualified it was caught by the above

my $col_re = qr/ \x00 $col \x00 /x;
next if $col =~ / \. /x; # if column is qualified it was caught by the above

$col_re = qr/ $col_re | $orig_lquote $col $orig_rquote /x
if ($orig_lquote && $orig_rquote);
my $col_re = qr/ $lquote $col $rquote /x;

for my $type (keys %$to_scan) {
for my $piece (@{$to_scan->{$type}}) {
Expand Down Expand Up @@ -361,9 +359,6 @@ sub _resolve_column_info {
my ($self, $ident, $colnames) = @_;
my ($alias2src, $root_alias) = $self->_resolve_ident_sources($ident);

my $sep = $self->_sql_maker_opts->{name_sep} || '.';
my $qsep = quotemeta $sep;

my (%return, %seen_cols, @auto_colnames);

# compile a global list of column names, to be able to properly
Expand All @@ -372,7 +367,7 @@ sub _resolve_column_info {
my $rsrc = $alias2src->{$alias};
for my $colname ($rsrc->columns) {
push @{$seen_cols{$colname}}, $alias;
push @auto_colnames, "$alias$sep$colname" unless $colnames;
push @auto_colnames, "$alias.$colname" unless $colnames;
}
}

Expand All @@ -383,7 +378,7 @@ sub _resolve_column_info {

COLUMN:
foreach my $col (@$colnames) {
my ($alias, $colname) = $col =~ m/^ (?: ([^$qsep]+) $qsep)? (.+) $/x;
my ($alias, $colname) = $col =~ m/^ (?: ([^\.]+) \. )? (.+) $/x;

unless ($alias) {
# see if the column was seen exactly once (so we know which rsrc it came from)
Expand Down
1 change: 0 additions & 1 deletion t/71mysql.t
Expand Up @@ -263,7 +263,6 @@ NULLINSEARCH: {
my $ansi_schema = DBICTest::Schema->connect ($dsn, $user, $pass, {
on_connect_call => 'set_strict_mode',
quote_char => '`',
name_sep => '.'
});
my $rs = $ansi_schema->resultset('CD');

Expand Down

0 comments on commit 3f5b99f

Please sign in to comment.