[Mono-bugs] [Bug 69887][Wis] New - DbDataAdapter.Update needs to check for multiple results

bugzilla-daemon@bugzilla.ximian.com bugzilla-daemon@bugzilla.ximian.com
Wed, 24 Nov 2004 15:06:57 -0500 (EST)


Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.

Changed by rscaletta@augustmack.com.

http://bugzilla.ximian.com/show_bug.cgi?id=69887

--- shadow/69887	2004-11-24 15:06:57.000000000 -0500
+++ shadow/69887.tmp.2520	2004-11-24 15:06:57.000000000 -0500
@@ -0,0 +1,102 @@
+Bug#: 69887
+Product: Mono: Class Libraries
+Version: 1.0
+OS: All
+OS Details: 
+Status: NEW   
+Resolution: 
+Severity: 
+Priority: Wishlist
+Component: Sys.Data
+AssignedTo: mono-bugs@ximian.com                            
+ReportedBy: rscaletta@augustmack.com               
+QAContact: mono-bugs@ximian.com
+TargetMilestone: ---
+URL: 
+Cc: 
+Summary: DbDataAdapter.Update needs to check for multiple results
+
+Please fill in this template when reporting a bug, unless you know what you
+are doing.
+Description of Problem:
+
+Some database commands will return multiple result sets.  This are most
+often used to retrieve automatic values generated by the database server. 
+DbDataAdapter.Update() should get multiple results and store any values
+back into the row being updated.
+
+Microsoft's implementation appears to be hard-coded to only check for 2
+results, so that will be sufficient.
+
+
+Steps to reproduce the problem:
+// Create a database with schema "CREATE TABLE t (id INTEGER PRIMARY KEY, 
+//   a TEXT, b TEXT)";
+// When used with SQLite, this means id will be autoincremented by the 
+// database.
+
+SQLiteCommand cmd = new SQLiteCommand("INSERT INTO t (a, b) VALUES (@a,
+@b); SELECT id, a, b FROM t WHERE (id=last_insert_rowid())");
+DataSet ds;
+// set the schema on ds
+...
+// Insert a new row
+DataRow r = ds.Tables[0].NewRow();
+r["a"] = "val";
+r["b"] = "val2";
+ds.Tables[0].Rows.Add(r);
+
+SQLiteDataAdapter adapter = new SQLiteDataAdapter("SELECT id, a, b FROM t",
+_connection);
+adapter.InsertCommand = cmd;
+adapter.Update(ds);
+
+// OK, here's the test... it should have pulled in the id and it should be
+// and integer
+Debug.Assert(r["id"] != DbNull.Value && 
+  Int32.Parse(r["id"].ToString()) > 0);
+
+
+Actual Results:
+r["id"] is DbNull.Value
+
+Expected Results:
+r["id"] should be the autogenerated integer.
+
+How often does this happen? 
+All the time.
+
+Additional Information:
+Here's a proposed solution:
+Don't know how to get a proper patch, so I'll show you:
+in System.Data.Common/DbDataAdapter.cs :
+protected virtual int Update(DataRow[] dataRows, DataTableMapping tableMapping)
+{
+    // Skip ahead a bit, nothing has changed
+    ...
+    try
+    {
+	// use ExecuteReader because we want to use the commandbehavior parameter.
+	// so the connection will be closed if needed.
+	reader = command.ExecuteReader (commandBehavior);
+	int tmp = reader.RecordsAffected;
+        // CHANGE: Pull in next command if it's a batch command
+        if (reader.NextResult() {
+             // Does it return values? If so, store them back
+             if (reader.FieldCount > 0) {
+                 object[] values = new object[reader.FieldCount];
+                 // Assume it will only return one row, call Read only once
+                 Read();
+                 reader.GetValues(values);
+                 row.ItemArray = values;
+             }
+        }
+        // DONE CHANGING
+	// if the execute does not effect any rows we throw an exception.
+	if (tmp == 0)
+	throw new DBConcurrencyException("Concurrency violation: the " +
+commandName +"Command affected 0 records.");
+	updateCount += tmp;
+
+        // The rest is good.
+        ...