Set name_sep by default (even if unused). Simplify raw-sql scanner code
Peter Rabbitson [Thu, 14 Oct 2010 05:06:28 +0000 (07:06 +0200)]
lib/DBIx/Class/Manual/Cookbook.pod
lib/DBIx/Class/SQLMaker.pm
lib/DBIx/Class/SQLMaker/LimitDialects.pm
lib/DBIx/Class/Storage/DBI.pm
lib/DBIx/Class/Storage/DBIHacks.pm
t/71mysql.t

index 87ffd96..4f599b7 100644 (file)
@@ -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>:
index ea2b23e..f43aa0b 100644 (file)
@@ -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
index 723001d..846cab7 100644 (file)
@@ -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 )
     ]
   );
@@ -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);
@@ -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;
@@ -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;
 }
 
index d54e0b2..6a85b2c 100644 (file)
@@ -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
@@ -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
 
@@ -525,7 +519,7 @@ L<DBIx::Class::Schema/connect>
       'postgres',
       'my_pg_password',
       { AutoCommit => 1 },
-      { quote_char => q{"}, name_sep => q{.} },
+      { quote_char => q{"} },
     ]
   );
 
@@ -999,6 +993,7 @@ sub sql_maker {
       bindtype=>'columns',
       array_datatypes => 1,
       limit_dialect => $dialect,
+      name_sep => '.',
       %opts,
     ));
   }
index ed5de4d..23b528b 100644 (file)
@@ -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),
@@ -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);
@@ -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}}) {
@@ -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
@@ -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;
     }
   }
 
@@ -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)
index 01c32d8..66ebfd2 100644 (file)
@@ -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');