error checking related to literal SQL for insert_bulk
Rafael Kitover [Sun, 18 Oct 2009 08:56:54 +0000 (08:56 +0000)]
lib/DBIx/Class/Storage/DBI.pm
t/100populate.t

index da3619c..5a6d4d7 100644 (file)
@@ -1359,6 +1359,45 @@ sub insert_bulk {
 #      } map $data->[$_][$i], (1..$#$data)) == (@$data - 1);
   }
 
+  # check for bad data
+  my $bad_slice = sub {
+    my ($msg, $slice_idx) = @_;
+    $self->throw_exception(sprintf "%s for populate slice:\n%s",
+      $msg,
+      Data::Dumper::Concise::Dumper({
+        map { $cols->[$_] => $data->[$slice_idx][$_] } (0 .. $#$cols)
+      }),
+    );
+  };
+
+  for my $datum_idx (0..$#$data) {
+    my $datum = $data->[$datum_idx];
+
+    for my $col_idx (0..$#$cols) {
+      my $val            = $datum->[$col_idx];
+      my $sqla_bind      = $colvalues{ $cols->[$col_idx] };
+      my $is_literal_sql = (ref $sqla_bind) eq 'SCALAR';
+
+      if ($is_literal_sql) {
+        if (not ref $val) {
+          $bad_slice->('bind found where literal SQL expected', $datum_idx);
+        }
+        elsif ((my $reftype = ref $val) ne 'SCALAR') {
+          $bad_slice->("$reftype reference found where literal SQL expected",
+            $datum_idx);
+        }
+        elsif ($$val ne $$sqla_bind){
+          $bad_slice->("inconsistent literal SQL value, expecting: '$$sqla_bind'",
+            $datum_idx);
+        }
+      }
+      elsif (my $reftype = ref $val) {
+        $bad_slice->("$reftype reference found where bind expected",
+          $datum_idx);
+      }
+    }
+  }
+
   my ($sql, $bind) = $self->_prep_for_execute (
     'insert', undef, $source, [\%colvalues]
   );
index aa3880e..ada70d9 100644 (file)
@@ -152,4 +152,48 @@ throws_ok {
 
 is($rs->count, 0, 'populate is atomic');
 
+# Trying to use a column marked as a bind in the first slice with literal sql in
+# a later slice should throw.
+
+throws_ok {
+  $rs->populate([
+    {
+      artistid => 1,
+      name => \"'foo'",
+    },
+    {
+      artistid => \2,
+      name => \"'foo'",
+    }
+  ]);
+} qr/bind expected/, 'literal sql where bind expected throws';
+
+# ... and vice-versa.
+
+throws_ok {
+  $rs->populate([
+    {
+      artistid => \1,
+      name => \"'foo'",
+    },
+    {
+      artistid => 2,
+      name => \"'foo'",
+    }
+  ]);
+} qr/literal SQL expected/i, 'bind where literal sql expected throws';
+
+throws_ok {
+  $rs->populate([
+    {
+      artistid => 1,
+      name => \"'foo'",
+    },
+    {
+      artistid => 2,
+      name => \"'bar'",
+    }
+  ]);
+} qr/inconsistent/, 'literal sql must be the same in all slices';
+
 done_testing;