Merge 'trunk' into 'mssql_top_fixes'
Peter Rabbitson [Thu, 11 Jun 2009 16:26:40 +0000 (16:26 +0000)]
r6557@Thesaurus (orig r6556):  ash | 2009-06-09 12:20:34 +0200
Addjust bug to show problem with rows => 1 + child rel

r6558@Thesaurus (orig r6557):  ribasushi | 2009-06-09 13:12:46 +0200
Require a recent bugfixed Devel::Cycle
r6560@Thesaurus (orig r6559):  ash | 2009-06-09 15:07:30 +0200
Make IC::DT extra warning state the column name too

r6575@Thesaurus (orig r6574):  ribasushi | 2009-06-10 00:19:48 +0200
AuthorCheck fixes
r6579@Thesaurus (orig r6578):  ribasushi | 2009-06-10 00:52:17 +0200
 r6522@Thesaurus (orig r6521):  ribasushi | 2009-06-05 19:27:55 +0200
 New branch to try resultsource related stuff
 r6545@Thesaurus (orig r6544):  ribasushi | 2009-06-08 13:00:54 +0200
 First stab at adding resultsources to each join in select - works won-der-ful-ly
 r6546@Thesaurus (orig r6545):  ribasushi | 2009-06-08 13:14:08 +0200
 Commit failing test and thoughts on search arg deflation
 r6576@Thesaurus (orig r6575):  ribasushi | 2009-06-10 00:31:55 +0200
 Todoify DT in search deflation test until after 0.09
 r6577@Thesaurus (orig r6576):  ribasushi | 2009-06-10 00:48:07 +0200
 Factor out the $ident resolver

r6581@Thesaurus (orig r6580):  ribasushi | 2009-06-10 01:21:50 +0200
Move as_query out of the cursor
r6582@Thesaurus (orig r6581):  ribasushi | 2009-06-10 01:27:19 +0200
Think before commit
r6583@Thesaurus (orig r6582):  ribasushi | 2009-06-10 09:37:19 +0200
Clarify and disable rows/prefetch test - fix is easy, but architecturally unsound - need more time
r6591@Thesaurus (orig r6590):  ribasushi | 2009-06-10 13:33:37 +0200
 r6544@Thesaurus (orig r6543):  ribasushi | 2009-06-08 11:44:59 +0200
 Attempt to figure out why do we repeat joins on complex search_related
 r6586@Thesaurus (orig r6585):  ribasushi | 2009-06-10 11:22:05 +0200
 Move the rs preservation test to a more suitable place
 r6589@Thesaurus (orig r6588):  ribasushi | 2009-06-10 13:15:48 +0200
 Finally commit trully failing test
 r6590@Thesaurus (orig r6589):  ribasushi | 2009-06-10 13:33:14 +0200
 Duh, this was a pretty simple bug

r6593@Thesaurus (orig r6592):  ribasushi | 2009-06-10 13:43:31 +0200
What was I thinking - resultsource does not have an ->alias
r6598@Thesaurus (orig r6597):  ribasushi | 2009-06-10 14:48:39 +0200
Adjust changelog
r6601@Thesaurus (orig r6600):  ribasushi | 2009-06-10 15:50:43 +0200
Release 0.08104
r6615@Thesaurus (orig r6614):  ribasushi | 2009-06-11 14:29:48 +0200
Move around inflation tests
r6616@Thesaurus (orig r6615):  ribasushi | 2009-06-11 14:32:07 +0200
explicitly remove manifest on author mode make
r6617@Thesaurus (orig r6616):  ribasushi | 2009-06-11 15:02:41 +0200
IC::DT changes:
Switch SQLite storage to DT::F::SQLite
Fix exception when undef_if_invalid and timezone are both set on a column
Split t/89inflate_datetime into separate tests
Adjust makefile author dependencies
r6618@Thesaurus (orig r6617):  ribasushi | 2009-06-11 15:07:41 +0200
Move file_column test to inflate/ too
r6621@Thesaurus (orig r6620):  ribasushi | 2009-06-11 16:16:20 +0200
 r5713@Thesaurus (orig r5712):  ribasushi | 2009-03-08 23:53:28 +0100
 Branch for datatype-aware updates
 r6604@Thesaurus (orig r6603):  ribasushi | 2009-06-10 18:08:25 +0200
 Test for type-aware update
 r6607@Thesaurus (orig r6606):  ribasushi | 2009-06-10 19:57:04 +0200
 Datatype aware update works
 r6609@Thesaurus (orig r6608):  ribasushi | 2009-06-10 20:06:40 +0200
 Whoops
 r6614@Thesaurus (orig r6613):  ribasushi | 2009-06-11 09:23:54 +0200
 Add attribute doc
 r6620@Thesaurus (orig r6619):  ribasushi | 2009-06-11 16:15:53 +0200
 Use equality, not comparison

r6623@Thesaurus (orig r6622):  ribasushi | 2009-06-11 16:21:53 +0200
Changes

lib/DBIx/Class/Storage/DBI.pm
lib/DBIx/Class/Storage/DBI/AmbiguousGlob.pm [new file with mode: 0644]
lib/DBIx/Class/Storage/DBI/MSSQL.pm
lib/DBIx/Class/Storage/DBI/ODBC.pm
lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm
lib/DBIx/Class/Storage/DBI/mysql.pm
t/746mssql.t

index c6f13f5..bff3800 100644 (file)
@@ -3,7 +3,7 @@ package DBIx::Class::Storage::DBI;
 
 use base 'DBIx::Class::Storage';
 
-use strict;    
+use strict;
 use warnings;
 use Carp::Clan qw/^DBIx::Class/;
 use DBI;
@@ -89,8 +89,8 @@ recognized by DBIx::Class:
 
 =item *
 
-A single code reference which returns a connected 
-L<DBI database handle|DBI/connect> optionally followed by 
+A single code reference which returns a connected
+L<DBI database handle|DBI/connect> optionally followed by
 L<extra attributes|/DBIx::Class specific connection attributes> recognized
 by DBIx::Class:
 
@@ -109,7 +109,7 @@ mixed together:
     %extra_attributes,
   }];
 
-This is particularly useful for L<Catalyst> based applications, allowing the 
+This is particularly useful for L<Catalyst> based applications, allowing the
 following config (L<Config::General> style):
 
   <Model::DB>
@@ -128,7 +128,7 @@ Please note that the L<DBI> docs recommend that you always explicitly
 set C<AutoCommit> to either I<0> or I<1>.  L<DBIx::Class> further
 recommends that it be set to I<1>, and that you perform transactions
 via our L<DBIx::Class::Schema/txn_do> method.  L<DBIx::Class> will set it
-to I<1> if you do not do explicitly set it to zero.  This is the default 
+to I<1> if you do not do explicitly set it to zero.  This is the default
 for most DBDs. See L</DBIx::Class and AutoCommit> for details.
 
 =head3 DBIx::Class specific connection attributes
@@ -182,7 +182,7 @@ storage object.
 If set to a true value, this option will disable the caching of
 statement handles via L<DBI/prepare_cached>.
 
-=item limit_dialect 
+=item limit_dialect
 
 Sets the limit dialect. This is useful for JDBC-bridge among others
 where the remote SQL-dialect cannot be determined by the name of the
@@ -190,7 +190,7 @@ driver alone. See also L<SQL::Abstract::Limit>.
 
 =item quote_char
 
-Specifies what characters to use to quote table and column names. If 
+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.
 
 C<quote_char> expects either a single character, in which case is it
@@ -202,8 +202,8 @@ 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 
-specify the charecter that seperates elements (schemas, tables, columns) from 
+This only needs to be used in conjunction with C<quote_char>, and is used to
+specify the charecter that seperates 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>
@@ -594,7 +594,7 @@ sub dbh {
 
 sub _sql_maker_args {
     my ($self) = @_;
-    
+
     return ( bindtype=>'columns', array_datatypes => 1, limit_dialect => $self->dbh, %{$self->_sql_maker_opts} );
 }
 
@@ -753,11 +753,11 @@ sub svp_begin {
 
   $self->throw_exception ("Your Storage implementation doesn't support savepoints")
     unless $self->can('_svp_begin');
-  
+
   push @{ $self->{savepoints} }, $name;
 
   $self->debugobj->svp_begin($name) if $self->debug;
-  
+
   return $self->_svp_begin($name);
 }
 
@@ -817,7 +817,7 @@ sub svp_rollback {
   }
 
   $self->debugobj->svp_rollback($name) if $self->debug;
-  
+
   return $self->_svp_rollback($name);
 }
 
@@ -986,7 +986,7 @@ sub _dbh_execute {
 
   my $sth = $self->sth($sql,$op);
 
-  my $placeholder_index = 1; 
+  my $placeholder_index = 1;
 
   foreach my $bound (@$bind) {
     my $attributes = {};
@@ -1045,7 +1045,7 @@ sub insert {
 }
 
 ## Still not quite perfect, and EXPERIMENTAL
-## Currently it is assumed that all values passed will be "normal", i.e. not 
+## Currently it is assumed that all values passed will be "normal", i.e. not
 ## scalar refs, or at least, all the same type as the first set, the statement is
 ## only prepped once.
 sub insert_bulk {
@@ -1054,7 +1054,7 @@ sub insert_bulk {
   my $table = $source->from;
   @colvalues{@$cols} = (0..$#$cols);
   my ($sql, @bind) = $self->sql_maker->insert($table, \%colvalues);
-  
+
   $self->_query_start( $sql, @bind );
   my $sth = $self->sth($sql);
 
@@ -1067,7 +1067,7 @@ sub insert_bulk {
   my $bind_attributes = $self->source_bind_attributes($source);
 
   ## Bind the values and execute
-  my $placeholder_index = 1; 
+  my $placeholder_index = 1;
 
   foreach my $bound (@bind) {
 
@@ -1115,7 +1115,7 @@ sub update {
   my $self = shift @_;
   my $source = shift @_;
   my $bind_attributes = $self->source_bind_attributes($source);
-  
+
   return $self->_execute('update' => [], $source, $bind_attributes, @_);
 }
 
@@ -1123,9 +1123,9 @@ sub update {
 sub delete {
   my $self = shift @_;
   my $source = shift @_;
-  
+
   my $bind_attrs = $self->source_bind_attributes($source);
-  
+
   return $self->_execute('delete' => [], $source, $bind_attrs, @_);
 }
 
@@ -1374,10 +1374,10 @@ sub _grouped_count_select {
 
 sub source_bind_attributes {
   my ($self, $source) = @_;
-  
+
   my $bind_attributes;
   foreach my $column ($source->columns) {
-  
+
     my $data_type = $source->column_info($column)->{data_type} || '';
     $bind_attributes->{$column} = $self->bind_attribute_by_data_type($data_type)
      if $data_type;
@@ -1626,13 +1626,13 @@ By default, C<\%sqlt_args> will have
 
  { add_drop_table => 1, ignore_constraint_names => 1, ignore_index_names => 1 }
 
-merged with the hash passed in. To disable any of those features, pass in a 
+merged with the hash passed in. To disable any of those features, pass in a
 hashref like the following
 
  { ignore_constraint_names => 0, # ... other options }
 
 
-Note that this feature is currently EXPERIMENTAL and may not work correctly 
+Note that this feature is currently EXPERIMENTAL and may not work correctly
 across all databases, or fully handle complex relationships.
 
 WARNING: Please check all SQL files created, before applying them.
@@ -1653,7 +1653,7 @@ sub create_ddl_dir {
   $version ||= $schema_version;
 
   $sqltargs = {
-    add_drop_table => 1, 
+    add_drop_table => 1,
     ignore_constraint_names => 1,
     ignore_index_names => 1,
     %{$sqltargs || {}}
@@ -1693,7 +1693,7 @@ sub create_ddl_dir {
     }
     print $file $output;
     close($file);
-  
+
     next unless ($preversion);
 
     require SQL::Translator::Diff;
@@ -1709,7 +1709,7 @@ sub create_ddl_dir {
       carp("Overwriting existing diff file - $difffile");
       unlink($difffile);
     }
-    
+
     my $source_schema;
     {
       my $t = SQL::Translator->new($sqltargs);
@@ -1728,7 +1728,7 @@ sub create_ddl_dir {
         unless ( $source_schema->name );
     }
 
-    # The "new" style of producers have sane normalization and can support 
+    # The "new" style of producers have sane normalization and can support
     # diffing a SQL file against a DBIC->SQLT schema. Old style ones don't
     # And we have to diff parsed SQL against parsed SQL.
     my $dest_schema = $sqlt_schema;
@@ -1749,12 +1749,12 @@ sub create_ddl_dir {
       $dest_schema->name( $filename )
         unless $dest_schema->name;
     }
-    
+
     my $diff = SQL::Translator::Diff::schema_diff($source_schema, $db,
                                                   $dest_schema,   $db,
                                                   $sqltargs
                                                  );
-    if(!open $file, ">$difffile") { 
+    if(!open $file, ">$difffile") {
       $self->throw_exception("Can't write to $difffile ($!)");
       next;
     }
@@ -1798,7 +1798,7 @@ sub deployment_statements {
   if(-f $filename)
   {
       my $file;
-      open($file, "<$filename") 
+      open($file, "<$filename")
         or $self->throw_exception("Can't open $filename ($!)");
       my @rows = <$file>;
       close($file);
@@ -1813,7 +1813,7 @@ sub deployment_statements {
   eval qq{use SQL::Translator::Producer::${type}};
   $self->throw_exception($@) if $@;
 
-  # sources needs to be a parser arg, but for simplicty allow at top level 
+  # sources needs to be a parser arg, but for simplicty allow at top level
   # coming in
   $sqltargs->{parser_args}{sources} = delete $sqltargs->{sources}
       if exists $sqltargs->{sources};
@@ -1918,7 +1918,7 @@ returned by databases that don't support replication.
 
 sub is_replicating {
     return;
-    
+
 }
 
 =head2 lag_behind_master
diff --git a/lib/DBIx/Class/Storage/DBI/AmbiguousGlob.pm b/lib/DBIx/Class/Storage/DBI/AmbiguousGlob.pm
new file mode 100644 (file)
index 0000000..c848fc1
--- /dev/null
@@ -0,0 +1,43 @@
+package DBIx::Class::Storage::DBI::AmbiguousGlob;\r
+\r
+use strict;\r
+use warnings;\r
+\r
+use base 'DBIx::Class::Storage::DBI';\r
+\r
+=head1 NAME\r
+\r
+DBIx::Class::Storage::DBI::AmbiguousGlob - Storage component for RDBMS supporting multicolumn in clauses\r
+\r
+=head1 DESCRIPTION\r
+\r
+Some servers choke on things like:\r
+\r
+  COUNT(*) FROM (SELECT tab1.col, tab2.col FROM tab1 JOIN tab2 ... )\r
+\r
+claiming that col is a duplicate column (it loses the table specifiers by\r
+the time it gets to the *). Thus for any subquery count we select only the\r
+primary keys of the main table in the inner query. This hopefully still\r
+hits the indexes and keeps the server happy.\r
+\r
+At this point the only overriden method is C<_grouped_count_select()>\r
+\r
+=cut\r
+\r
+sub _grouped_count_select {\r
+  my ($self, $source, $rs_args) = @_;\r
+  my @pcols = map { join '.', $rs_args->{alias}, $_ } ($source->primary_columns);\r
+  return @pcols ? \@pcols : $rs_args->{group_by};\r
+}\r
+\r
+=head1 AUTHORS\r
+\r
+See L<DBIx::Class/CONTRIBUTORS>\r
+\r
+=head1 LICENSE\r
+\r
+You may distribute this code under the same terms as Perl itself.\r
+\r
+=cut\r
+\r
+1;\r
index 40afe76..c6b9360 100644 (file)
@@ -3,7 +3,7 @@ package DBIx::Class::Storage::DBI::MSSQL;
 use strict;
 use warnings;
 
-use base qw/DBIx::Class::Storage::DBI/;
+use base qw/DBIx::Class::Storage::DBI::AmbiguousGlob DBIx::Class::Storage::DBI/;
 
 sub _dbh_last_insert_id {
   my ($self, $dbh, $source, $col) = @_;
index 09a7c6b..40d12aa 100644 (file)
@@ -11,9 +11,11 @@ sub _rebless {
     unless ( $@ ) {
         # Translate the backend name into a perl identifier
         $dbtype =~ s/\W/_/gi;
-        my $class = "DBIx::Class::Storage::DBI::ODBC::${dbtype}";
-        eval "require $class";
-        bless $self, $class unless $@;
+        my $subclass = "DBIx::Class::Storage::DBI::ODBC::${dbtype}";
+        if ($self->load_optional_class($subclass) && !$self->isa($subclass)) {
+            bless $self, $subclass;
+            $self->_rebless;
+        }
     }
 }
 
index 3a464fd..75e9497 100644 (file)
@@ -5,13 +5,34 @@ use warnings;
 use base qw/DBIx::Class::Storage::DBI::MSSQL/;
 
 sub _prep_for_execute {
-    my $self = shift;
-    my ($op, $extra_bind, $ident, $args) = @_;
+  my $self = shift;
+  my ($op, $extra_bind, $ident, $args) = @_;
+
+  my ($sql, $bind) = $self->next::method (@_);
+  $sql .= ';SELECT SCOPE_IDENTITY()' if $op eq 'insert';
+
+  my $alias2src = $self->_resolve_ident_sources($ident);
+  my %identity_insert_tables;
+  foreach my $bound (@{$bind}) {
+    my $col =  $bound->[0];
+    my $name_sep = $self->_sql_maker_opts->{name_sep} || '.';
+
+    $col =~ s/^([^\Q${name_sep}\E]*)\Q${name_sep}\E//;
+    my $alias = $1 || 'me';
+    my $rsrc = $alias2src->{$alias};
+
+    my $is_auto_increment = $rsrc && $rsrc->column_info($col)->{is_auto_increment};
+    my $table;
+    if ($is_auto_increment) {
+      $identity_insert_tables{$rsrc->from} = 1;
+    }
+  }
 
-    my ($sql, $bind) = $self->next::method (@_);
-    $sql .= ';SELECT SCOPE_IDENTITY()' if $op eq 'insert';
+  my $identity_insert_on = join '', map { "SET IDENTITY_INSERT $_ ON; " } keys %identity_insert_tables;
+  my $identity_insert_off = join '', map { "SET IDENTITY_INSERT $_ OFF; " } keys %identity_insert_tables;
+  $sql = "$identity_insert_on $sql $identity_insert_off";
 
-    return ($sql, $bind);
+  return ($sql, $bind);
 }
 
 sub _execute {
@@ -64,3 +85,4 @@ Marc Mims C<< <marc@questright.com> >>
 You may distribute this code under the same terms as Perl itself.
 
 =cut
+# vim: sw=2 sts=2
index 221548a..e36b6d7 100644 (file)
@@ -3,7 +3,7 @@ package DBIx::Class::Storage::DBI::mysql;
 use strict;
 use warnings;
 
-use base qw/DBIx::Class::Storage::DBI::MultiColumnIn/;
+use base qw/DBIx::Class::Storage::DBI::MultiColumnIn DBIx::Class::Storage::DBI::AmbiguousGlob/;
 
 __PACKAGE__->sql_maker_class('DBIx::Class::SQLAHacks::MySQL');
 
@@ -41,7 +41,7 @@ sub _svp_rollback {
 
     $self->dbh->do("ROLLBACK TO SAVEPOINT $name")
 }
+
 sub is_replicating {
     my $status = shift->dbh->selectrow_hashref('show slave status');
     return ($status->{Slave_IO_Running} eq 'Yes') && ($status->{Slave_SQL_Running} eq 'Yes');
@@ -57,19 +57,6 @@ sub _subq_update_delete {
   return shift->_per_row_update_delete (@_);
 }
 
-# MySql chokes on things like:
-# COUNT(*) FROM (SELECT tab1.col, tab2.col FROM tab1 JOIN tab2 ... )
-# claiming that col is a duplicate column (it loses the table specifiers by
-# the time it gets to the *). Thus for any subquery count we select only the
-# primary keys of the main table in the inner query. This hopefully still
-# hits the indexes and keeps mysql happy.
-# (mysql does not care if the SELECT and the GROUP BY match)
-sub _grouped_count_select {
-  my ($self, $source, $rs_args) = @_;
-  my @pcols = map { join '.', $rs_args->{alias}, $_ } ($source->primary_columns);
-  return @pcols ? \@pcols : $rs_args->{group_by};
-}
-
 1;
 
 =head1 NAME
index f53d49f..b1871f1 100644 (file)
@@ -1,5 +1,5 @@
 use strict;
-use warnings;  
+use warnings;
 
 use Test::More;
 use lib qw(t/lib);
@@ -10,7 +10,7 @@ my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSSQL_ODBC_${_}" } qw/DSN USER PA
 plan skip_all => 'Set $ENV{DBICTEST_MSSQL_ODBC_DSN}, _USER and _PASS to run this test'
   unless ($dsn && $user);
 
-plan tests => 13;
+plan tests => 21;
 
 my $schema = DBICTest::Schema->connect($dsn, $user, $pass, {AutoCommit => 1});
 
@@ -73,10 +73,117 @@ $it->next;
 is( $it->next->name, "Artist 2", "iterator->next ok" );
 is( $it->next, undef, "next past end of resultset ok" );
 
+$schema->storage->dbh_do (sub {
+    my ($storage, $dbh) = @_;
+    eval { $dbh->do("DROP TABLE Owners") };
+    eval { $dbh->do("DROP TABLE Books") };
+    $dbh->do(<<'SQL');
+
+
+CREATE TABLE Books (
+   id INT IDENTITY (1, 1) NOT NULL,
+   source VARCHAR(100),
+   owner INT,
+   title VARCHAR(10),
+   price INT NULL
+)
+
+CREATE TABLE Owners (
+   id INT IDENTITY (1, 1) NOT NULL,
+   [name] VARCHAR(100),
+)
+
+SET IDENTITY_INSERT Owners ON
+
+SQL
+
+});
+$schema->populate ('Owners', [
+  [qw/id  [name]  /],
+  [qw/1   wiggle/],
+  [qw/2   woggle/],
+  [qw/3   boggle/],
+  [qw/4   fREW/],
+  [qw/5   fRIOUX/],
+  [qw/6   fROOH/],
+  [qw/7   fRUE/],
+  [qw/8   fISMBoC/],
+  [qw/9   station/],
+  [qw/10   mirror/],
+  [qw/11   dimly/],
+  [qw/12   face_to_face/],
+  [qw/13   icarus/],
+  [qw/14   dream/],
+  [qw/15   dyrstyggyr/],
+]);
+
+$schema->populate ('BooksInLibrary', [
+  [qw/source  owner title   /],
+  [qw/Library 1     secrets1/],
+  [qw/Eatery  1     secrets2/],
+  [qw/Library 2     secrets3/],
+  [qw/Library 3     secrets4/],
+  [qw/Eatery  3     secrets5/],
+  [qw/Library 4     secrets6/],
+  [qw/Library 5     secrets7/],
+  [qw/Eatery  5     secrets8/],
+  [qw/Library 6     secrets9/],
+  [qw/Library 7     secrets10/],
+  [qw/Eatery  7     secrets11/],
+  [qw/Library 8     secrets12/],
+]);
+
+#
+# try a distinct + prefetch on tables with identically named columns
+#
+
+{
+  # try a ->has_many direction (due to a 'multi' accessor the select/group_by group is collapsed)
+  my $owners = $schema->resultset ('Owners')->search ({
+      'books.id' => { '!=', undef }
+    }, {
+      prefetch => 'books',
+      distinct => 1,
+      order_by => 'name',
+      page     => 2,
+      rows     => 5,
+    });
+
+  my $owners2 = $schema->resultset ('Owners')->search ({ id => { -in => $owners->get_column ('me.id')->as_query }});
+  for ($owners, $owners2) {
+    is ($_->all, 2, 'Prefetched grouped search returns correct number of rows');
+    is ($_->count, 2, 'Prefetched grouped search returns correct count');
+  }
+
+  # try a ->belongs_to direction (no select collapse)
+  my $books = $schema->resultset ('BooksInLibrary')->search ({
+      'owner.name' => 'wiggle'
+    }, {
+      prefetch => 'owner',
+      distinct => 1,
+      order_by => 'name',
+      page     => 2,
+      rows     => 5,
+    });
+
+  my $books2 = $schema->resultset ('BooksInLibrary')->search ({ id => { -in => $books->get_column ('me.id')->as_query }});
+  for ($books, $books2) {
+    is ($_->all, 1, 'Prefetched grouped search returns correct number of rows');
+    is ($_->count, 1, 'Prefetched grouped search returns correct count');
+  }
+
+  #my $result = $schema->resultset('BooksInLibrary')->search(undef, {
+        #page     => 1,
+        #rows     => 25,
+        #order_by => ['name', 'title'],
+        #prefetch => 'owner'
+     #})->first;
+
+}
 
 # clean up our mess
 END {
     my $dbh = eval { $schema->storage->_dbh };
     $dbh->do('DROP TABLE artist') if $dbh;
 }
-
+# vim:sw=2 sts=2