Merge 'trunk' into 'sybase_support'
Rafael Kitover [Mon, 28 Sep 2009 08:49:27 +0000 (08:49 +0000)]
r20734@hlagh (orig r7709):  ribasushi | 2009-09-20 20:49:11 -0400
Oops
r20735@hlagh (orig r7710):  ribasushi | 2009-09-21 05:02:14 -0400
Changes
r20736@hlagh (orig r7711):  ribasushi | 2009-09-21 06:49:30 -0400
Undocument the from attribute (the description was mostly outdated anyway)
r20737@hlagh (orig r7712):  ribasushi | 2009-09-21 06:58:58 -0400
Release 0.08112
r20740@hlagh (orig r7715):  ribasushi | 2009-09-21 10:26:07 -0400
A test for an obscure join syntax - make sure we don't break it
r20746@hlagh (orig r7721):  ribasushi | 2009-09-22 06:58:09 -0400
this would break in the future - sanitize sql fed to the tester
r20749@hlagh (orig r7724):  ribasushi | 2009-09-22 07:07:31 -0400
The hack is no longer necessary with a recent sqla
r20754@hlagh (orig r7729):  caelum | 2009-09-24 17:44:01 -0400
add test for multiple active statements in mssql over dbd::sybase
r20755@hlagh (orig r7730):  caelum | 2009-09-25 02:46:22 -0400
test on_connect_do with a coderef connect_info too
r20785@hlagh (orig r7731):  caelum | 2009-09-25 17:26:52 -0400
failing test for simple transaction with mssql via dbd::sybase

Changes
Makefile.PL
lib/DBIx/Class.pm
lib/DBIx/Class/ResultSet.pm
lib/DBIx/Class/SQLAHacks.pm
t/74mssql.t
t/relationship/core.t
t/relationship/update_or_create_multi.t
t/storage/on_connect_do.t

diff --git a/Changes b/Changes
index 53e4cf3..8060991 100644 (file)
--- a/Changes
+++ b/Changes
@@ -3,20 +3,22 @@ Revision history for DBIx::Class
         - Complete Sybase RDBMS support including:
           - Support for TEXT/IMAGE columns
           - Support for the 'money' datatype
-          - Transaction savepoints support
-          - DateTime inflation support
-          - Support for bind variables when connecting to a newer Sybase with
-            OpenClient libraries
-          - Support for connections via FreeTDS with CASTs for bind variables
-            when needed
-          - Support for interpolated variables with proper quoting when
-            connecting to an older Sybase and/or via FreeTDS
+        - Transaction savepoints support
+        - DateTime inflation support
+        - Support for bind variables when connecting to a newer Sybase with
+           OpenClient libraries
+        - Support for connections via FreeTDS with CASTs for bind variables
+           when needed
+        - Support for interpolated variables with proper quoting when
+           connecting to an older Sybase and/or via FreeTDS
+
+0.08112 2009-09-21 10:57:00 (UTC)
         - Remove the recommends from Makefile.PL, DBIx::Class is not
           supposed to have optional dependencies. ever.
         - Mangle the DBIx/Class.pm POD to be more clear about
           copyright and license
         - Put back PG's multiple autoinc per table support, accidentally
-          dropped during the serial-autodetection rwrite
+          dropped during the serial-autodetection rewrite
         - Make sure ResultSetColumn does not depend on the (undefined)
           return value of ->cursor->reset()
         - Add single() to ResultSetColumn (same semantics as ResultSet)
@@ -29,6 +31,8 @@ Revision history for DBIx::Class
         - Warn about using distinct with an existing group_by
         - Warn about attempting to $rs->get_column a non-unique column
           when has_many joins are added to resultset
+        - Refactor of the exception handling system (now everything is a
+          DBIx::Class::Exception object)
 
 0.08111 2009-09-06 21:58:00 (UTC)
         - The hashref to connection_info now accepts a 'dbh_maker'
index 8c1e88b..b76b7c9 100644 (file)
@@ -42,7 +42,7 @@ requires 'MRO::Compat'              => '0.09';
 requires 'Module::Find'             => '0.06';
 requires 'Path::Class'              => '0.16';
 requires 'Scope::Guard'             => '0.03';
-requires 'SQL::Abstract'            => '1.58';
+requires 'SQL::Abstract'            => '1.60';
 requires 'SQL::Abstract::Limit'     => '0.13';
 requires 'Sub::Name'                => '0.04';
 
@@ -122,7 +122,7 @@ my %force_requires_if_author = (
   ,
 );
 #************************************************************************#
-# Make *ABSOLUTELY SURE* that nothing on the list aboveis a real require,#
+# Make ABSOLUTELY SURE that nothing on the list above is a real require, #
 # since every module listed in %force_requires_if_author is deleted      #
 # from the final META.yml (thus will never make it as a CPAN dependency) #
 #************************************************************************#
index ff6a4c6..530bac2 100644 (file)
@@ -24,7 +24,7 @@ sub component_base_class { 'DBIx::Class' }
 # Always remember to do all digits for the version even if they're 0
 # i.e. first release of 0.XX *must* be 0.XX000. This avoids fBSD ports
 # brain damage and presumably various other packaging systems too
-$VERSION = '0.08111';
+$VERSION = '0.08112';
 
 $VERSION = eval $VERSION; # numify for warning-free dev releases
 
index 6b85685..60da1ca 100644 (file)
@@ -3578,177 +3578,6 @@ By default, searches are not cached.
 For more examples of using these attributes, see
 L<DBIx::Class::Manual::Cookbook>.
 
-=head2 from
-
-=over 4
-
-=item Value: \@from_clause
-
-=back
-
-The C<from> attribute gives you manual control over the C<FROM> clause of SQL
-statements generated by L<DBIx::Class>, allowing you to express custom C<JOIN>
-clauses.
-
-NOTE: Use this on your own risk.  This allows you to shoot off your foot!
-
-C<join> will usually do what you need and it is strongly recommended that you
-avoid using C<from> unless you cannot achieve the desired result using C<join>.
-And we really do mean "cannot", not just tried and failed. Attempting to use
-this because you're having problems with C<join> is like trying to use x86
-ASM because you've got a syntax error in your C. Trust us on this.
-
-Now, if you're still really, really sure you need to use this (and if you're
-not 100% sure, ask the mailing list first), here's an explanation of how this
-works.
-
-The syntax is as follows -
-
-  [
-    { <alias1> => <table1> },
-    [
-      { <alias2> => <table2>, -join_type => 'inner|left|right' },
-      [], # nested JOIN (optional)
-      { <table1.column1> => <table2.column2>, ... (more conditions) },
-    ],
-    # More of the above [ ] may follow for additional joins
-  ]
-
-  <table1> <alias1>
-  JOIN
-    <table2> <alias2>
-    [JOIN ...]
-  ON <table1.column1> = <table2.column2>
-  <more joins may follow>
-
-An easy way to follow the examples below is to remember the following:
-
-    Anything inside "[]" is a JOIN
-    Anything inside "{}" is a condition for the enclosing JOIN
-
-The following examples utilize a "person" table in a family tree application.
-In order to express parent->child relationships, this table is self-joined:
-
-    # Person->belongs_to('father' => 'Person');
-    # Person->belongs_to('mother' => 'Person');
-
-C<from> can be used to nest joins. Here we return all children with a father,
-then search against all mothers of those children:
-
-  $rs = $schema->resultset('Person')->search(
-      undef,
-      {
-          alias => 'mother', # alias columns in accordance with "from"
-          from => [
-              { mother => 'person' },
-              [
-                  [
-                      { child => 'person' },
-                      [
-                          { father => 'person' },
-                          { 'father.person_id' => 'child.father_id' }
-                      ]
-                  ],
-                  { 'mother.person_id' => 'child.mother_id' }
-              ],
-          ]
-      },
-  );
-
-  # Equivalent SQL:
-  # SELECT mother.* FROM person mother
-  # JOIN (
-  #   person child
-  #   JOIN person father
-  #   ON ( father.person_id = child.father_id )
-  # )
-  # ON ( mother.person_id = child.mother_id )
-
-The type of any join can be controlled manually. To search against only people
-with a father in the person table, we could explicitly use C<INNER JOIN>:
-
-    $rs = $schema->resultset('Person')->search(
-        undef,
-        {
-            alias => 'child', # alias columns in accordance with "from"
-            from => [
-                { child => 'person' },
-                [
-                    { father => 'person', -join_type => 'inner' },
-                    { 'father.id' => 'child.father_id' }
-                ],
-            ]
-        },
-    );
-
-    # Equivalent SQL:
-    # SELECT child.* FROM person child
-    # INNER JOIN person father ON child.father_id = father.id
-
-You can select from a subquery by passing a resultset to from as follows.
-
-    $schema->resultset('Artist')->search( 
-        undef, 
-        {   alias => 'artist2',
-            from  => [ { artist2 => $artist_rs->as_query } ],
-        } );
-
-    # and you'll get sql like this..
-    # SELECT artist2.artistid, artist2.name, artist2.rank, artist2.charfield FROM 
-    #   ( SELECT me.artistid, me.name, me.rank, me.charfield FROM artists me ) artist2
-
-If you need to express really complex joins, you
-can supply literal SQL to C<from> via a scalar reference. In this case
-the contents of the scalar will replace the table name associated with the
-resultsource.
-
-WARNING: This technique might very well not work as expected on chained
-searches - you have been warned.
-
-    # Assuming the Event resultsource is defined as:
-
-        MySchema::Event->add_columns (
-            sequence => {
-                data_type => 'INT',
-                is_auto_increment => 1,
-            },
-            location => {
-                data_type => 'INT',
-            },
-            type => {
-                data_type => 'INT',
-            },
-        );
-        MySchema::Event->set_primary_key ('sequence');
-
-    # This will get back the latest event for every location. The column
-    # selector is still provided by DBIC, all we do is add a JOIN/WHERE
-    # combo to limit the resultset
-
-    $rs = $schema->resultset('Event');
-    $table = $rs->result_source->name;
-    $latest = $rs->search (
-        undef,
-        { from => \ "
-            (SELECT e1.* FROM $table e1
-                JOIN $table e2
-                    ON e1.location = e2.location
-                    AND e1.sequence < e2.sequence
-                WHERE e2.sequence is NULL
-            ) me",
-        },
-    );
-
-    # Equivalent SQL (with the DBIC chunks added):
-
-    SELECT me.sequence, me.location, me.type FROM
-       (SELECT e1.* FROM events e1
-           JOIN events e2
-               ON e1.location = e2.location
-               AND e1.sequence < e2.sequence
-           WHERE e2.sequence is NULL
-       ) me;
-
 =head2 for
 
 =over 4
index 93c1009..429be4f 100644 (file)
@@ -47,52 +47,6 @@ sub new {
   $self;
 }
 
-# Some databases (sqlite) do not handle multiple parenthesis
-# around in/between arguments. A tentative x IN ( (1, 2 ,3) )
-# is interpreted as x IN 1 or something similar.
-#
-# Since we currently do not have access to the SQLA AST, resort
-# to barbaric mutilation of any SQL supplied in literal form
-sub _strip_outer_paren {
-  my ($self, $arg) = @_;
-
-  return $self->_SWITCH_refkind ($arg, {
-    ARRAYREFREF => sub {
-      $$arg->[0] = __strip_outer_paren ($$arg->[0]);
-      return $arg;
-    },
-    SCALARREF => sub {
-      return \__strip_outer_paren( $$arg );
-    },
-    FALLBACK => sub {
-      return $arg
-    },
-  });
-}
-
-sub __strip_outer_paren {
-  my $sql = shift;
-
-  if ($sql and not ref $sql) {
-    while ($sql =~ /^ \s* \( (.*) \) \s* $/x ) {
-      $sql = $1;
-    }
-  }
-
-  return $sql;
-}
-
-sub _where_field_IN {
-  my ($self, $lhs, $op, $rhs) = @_;
-  $rhs = $self->_strip_outer_paren ($rhs);
-  return $self->SUPER::_where_field_IN ($lhs, $op, $rhs);
-}
-
-sub _where_field_BETWEEN {
-  my ($self, $lhs, $op, $rhs) = @_;
-  $rhs = $self->_strip_outer_paren ($rhs);
-  return $self->SUPER::_where_field_BETWEEN ($lhs, $op, $rhs);
-}
 
 # Slow but ANSI standard Limit/Offset support. DB2 uses this
 sub _RowNumberOver {
index c93aee0..172c78d 100644 (file)
@@ -18,7 +18,7 @@ my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSSQL_${_}" } qw/DSN USER PASS/};
 plan skip_all => 'Set $ENV{DBICTEST_MSSQL_DSN}, _USER and _PASS to run this test'
   unless ($dsn);
 
-my $TESTS = 13;
+my $TESTS = 15;
 
 plan tests => $TESTS * 2;
 
@@ -133,6 +133,27 @@ SQL
 
   is $rs->find($row->id)->amount,
     undef, 'updated money value to NULL round-trip';
+
+  $rs->create({ amount => 300 }) for (1..3);
+
+  # test multiple active statements
+  lives_ok {
+    my $artist_rs = $schema->resultset('Artist');
+    while (my $row = $rs->next) {
+      my $artist = $artist_rs->next;
+    }
+    $rs->reset;
+  } 'multiple active statements';
+
+  # test multiple active statements in a transaction
+  TODO: {
+    local $TODO = 'needs similar FreeTDS fixes to the ones in Sybase.pm';
+    lives_ok {
+      $schema->txn_do(sub {
+        $rs->create({ amount => 400 });
+      });
+    } 'simple transaction';
+  }
 }
 
 # clean up our mess
index 566e5f3..6a09c57 100644 (file)
@@ -5,12 +5,11 @@ use Test::More;
 use Test::Exception;
 use lib qw(t/lib);
 use DBICTest;
+use DBIC::SqlMakerTest;
 
 my $schema = DBICTest->init_schema();
 my $sdebug = $schema->storage->debug;
 
-plan tests => 79;
-
 # has_a test
 my $cd = $schema->resultset("CD")->find(4);
 my ($artist) = ($INC{'DBICTest/HelperRels'}
@@ -260,8 +259,22 @@ is($def_artist_cd->has_column_loaded('artist'), 1, 'FK loaded');
 is($def_artist_cd->search_related('artist')->count, 0, 'closed search on null FK');
 
 # test undirected many-to-many relationship (e.g. "related artists")
-my $undir_maps = $schema->resultset("Artist")->find(1)->artist_undirected_maps;
+my $undir_maps = $schema->resultset("Artist")
+                          ->search ({artistid => 1})
+                            ->search_related ('artist_undirected_maps');
 is($undir_maps->count, 1, 'found 1 undirected map for artist 1');
+is_same_sql_bind (
+  $undir_maps->as_query,
+  '(
+    SELECT artist_undirected_maps.id1, artist_undirected_maps.id2
+      FROM artist me
+      LEFT JOIN artist_undirected_map artist_undirected_maps
+        ON artist_undirected_maps.id1 = me.artistid OR artist_undirected_maps.id2 = me.artistid
+    WHERE ( artistid = ? )
+  )',
+  [[artistid => 1]],
+  'expected join sql produced',
+);
 
 $undir_maps = $schema->resultset("Artist")->find(2)->artist_undirected_maps;
 is($undir_maps->count, 1, 'found 1 undirected map for artist 2');
@@ -310,3 +323,5 @@ is($cds->count, 1, "subjoins under left joins force_left (arrayref)");
 
 $cds = $schema->resultset("CD")->search({ 'me.cdid' => 5 }, { join => { single_track => { cd => {} } } });
 is($cds->count, 1, "subjoins under left joins force_left (hashref)");
+
+done_testing;
index 885b15c..56936f8 100644 (file)
@@ -76,8 +76,9 @@ $genre->update_or_create_related ('cds', {
 $schema->storage->debugcb(undef);
 $schema->storage->debug ($sdebug);
 
+my ($search_sql) = $sql[0] =~ /^(SELECT .+?)\:/;
 is_same_sql (
-  $sql[0],
+  $search_sql,
   'SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
     FROM cd me 
     WHERE ( me.artist = ? AND me.title = ? AND me.genreid = ? )
index d132e35..ca13d6c 100644 (file)
@@ -5,6 +5,7 @@ use Test::More tests => 12;
 
 use lib qw(t/lib);
 use base 'DBICTest';
+require DBI;
 
 
 my $schema = DBICTest->init_schema(
@@ -28,7 +29,7 @@ is_deeply (
 $schema->storage->disconnect;
 
 ok $schema->connection(
-    DBICTest->_database,
+    sub { DBI->connect(DBICTest->_database) },
     {
         on_connect_do       => [
             'CREATE TABLE TEST_empty (id INTEGER)',