First cut. Need to add control of how many rows are sent at once.
Rob Kinyon [Mon, 14 Mar 2011 03:20:24 +0000 (23:20 -0400)]
Changes
lib/DBIx/Class/SQLMaker/MySQL.pm
lib/DBIx/Class/Storage/DBI.pm
lib/DBIx/Class/Storage/DBI/mysql.pm
t/71mysql.t

diff --git a/Changes b/Changes
index 1306d67..f44d793 100644 (file)
--- a/Changes
+++ b/Changes
@@ -7,6 +7,9 @@ Revision history for DBIx::Class
         - Both the ::ODBC and ::ADO dispatchers now warn if a rdbms-specific
           driver is not found for this connection before falling back to
           plain ::Storage::DBI
+        - populate() in void context now uses the multi-row INSERT
+          statement in MySQL. It will send 500 rows at one time. You can
+          change this behavior by setting ????
 
     * Fixes
         - Fix exiting via next warnings from ResultSource
index ccb1195..7d86993 100644 (file)
@@ -21,6 +21,30 @@ sub insert {
   return $self->SUPER::insert (@_);
 }
 
+sub insert_bulk {
+  my ($self, $table, $data, $cols) = @_;
+
+  my $sql = sprintf(
+    'INSERT INTO %s ( ', $self->_quote($table),
+  );
+  $sql .= join( ', ', map { $self->_quote($_) } @$cols );
+  $sql .= ' ) VALUES ';
+
+  my @bind;
+  my @sql;
+  foreach my $datum ( @$data ) {
+    push @sql, '('
+      . join( ', ', ('?') x @$datum )
+      . ')';
+    push @bind, map { [ dummy => $_ ] } @$datum;
+  }
+
+  return (
+    $sql . join(',', @sql),
+    @bind
+  );
+}
+
 # Allow STRAIGHT_JOIN's
 sub _generate_join_clause {
     my ($self, $join_type) = @_;
index 2dc005c..b3cead4 100644 (file)
@@ -1830,8 +1830,17 @@ sub insert_bulk {
     }
   }
 
+  return $self->_insert_bulk(
+    $source, $cols, \%colvalues, $data,
+  );
+}
+
+# Broken out so that it can be overridden in Storage/DBI/mysql.pm
+sub _insert_bulk {
+  my ($self, $source, $cols, $colvalues, $data) = @_;
+
   my ($sql, $bind) = $self->_prep_for_execute (
-    'insert', undef, $source, [\%colvalues]
+    'insert', undef, $source, [$colvalues]
   );
 
   if (! @$bind) {
@@ -1841,7 +1850,7 @@ sub insert_bulk {
     # directly into the SQL. This obviosly can't be good for multi-inserts
 
     $self->throw_exception('Cannot insert_bulk without support for placeholders')
-      if first { ref $_ ne 'SCALAR' } values %colvalues;
+      if first { ref $_ ne 'SCALAR' } values %$colvalues;
   }
 
   # neither _execute_array, nor _execute_inserts_with_no_binds are
index fcf9fbf..0f4d210 100644 (file)
@@ -121,6 +121,16 @@ sub _subq_update_delete {
   return shift->_per_row_update_delete (@_);
 }
 
+sub _insert_bulk {
+  my ($self, $source, $cols, $colvalues, $data) = @_;
+
+  my $bind_attrs = $self->source_bind_attributes($source);
+
+  return $self->_execute(
+    'insert_bulk' => [], $source, $bind_attrs, $data, $cols,
+  );
+}
+
 1;
 
 =head1 NAME
index 84bebc7..1f45311 100644 (file)
@@ -411,4 +411,32 @@ ZEROINSEARCH: {
   ok ($rs->find({ name => "Hardcore Forker $pid" }), 'Expected row created');
 }
 
+# Verify that populate in void context uses INSERT INTO foo VALUES (), (), ()
+# instead of 3 distinct SQL statements as other databases may require.
+{
+  my $rsrc = $schema->resultset('Artist')->result_source;
+  my ($rv, $sth, @bind) = $schema->storage->insert_bulk(
+    $rsrc,
+    [qw/ artistid name rank charfield /],
+    [
+      [ 100, 'John', 200, 'Smith' ],
+      [ 101, 'Joan', 201, 'Snith' ],
+    ],
+  );
+
+  is_same_sql_bind(
+    $sth->{Statement},
+    \@bind,
+    q{INSERT INTO artist ( artistid, name, rank, charfield ) VALUES ( ?, ?, ?, ? ), ( ?, ?, ?, ? )},
+    [
+      map { [ dummy => $_ ] } (
+        100, 'John', 200, 'Smith',
+        101, 'Joan', 201, 'Snith',
+      ),
+    ],
+  );
+
+  is( $schema->resultset('Artist')->find( 100 )->name, 'John' );
+}
+
 done_testing;