List:Commits« Previous MessageNext Message »
From:Reggie Burnett Date:July 19 2010 6:29pm
Subject:bzr commit into connector-net-6.1 branch (reggie.burnett:827)
View as plain text  
#At file:///C:/work/bzr-connector-net/6.1/ based on revid:reggie.burnett@stripped

  827 Reggie Burnett	2010-07-19 [merge]
      merged

    modified:
      CHANGES
      MySql.Data/Provider/Source/dataadapter.cs
      MySql.Data/Tests/Source/DataAdapterTests.cs
=== modified file 'CHANGES'
=== modified file 'CHANGES'
--- a/CHANGES	2010-07-19 18:25:42 +0000
+++ b/CHANGES	2010-07-19 18:29:11 +0000
@@ -1,3 +1,5 @@
+- Fix "Connection must be valid and open" exception When UpdateBatchSize > 1 
+  and MySqlDataAdapter is not using an open connection (Bug #38411)
 - Make sure MySqlDataAdapter.Update() works for custom stored procedure driven update commands 
   that make use of UpdateRowSource.FirstReturnedRecord (Bug#54895)
 - Ensure exceptions are not silently eaten inside MySqlDataReader.Read()  (Bug#53439)

=== modified file 'MySql.Data/Provider/Source/dataadapter.cs'
--- a/MySql.Data/Provider/Source/dataadapter.cs	2010-07-01 22:48:45 +0000
+++ b/MySql.Data/Provider/Source/dataadapter.cs	2010-07-16 14:54:00 +0000
@@ -125,18 +125,74 @@
 
 		#endregion
 
+        /// <summary>
+        /// Open connection if it was closed.
+        /// Necessary to workaround "connection must be open and valid" error
+        /// with batched updates.
+        /// </summary>
+        /// <param name="state">Row state</param>
+        /// <param name="openedConnections"> list of opened connections 
+        /// If connection is opened by this function, the list is updated
+        /// </param>
+        /// <returns>true if connection was opened</returns>
+        private void OpenConnectionIfClosed(DataRowState state,
+            List<MySqlConnection> openedConnections)
+        {
+            MySqlCommand cmd = null;
+            switch (state)
+            {
+                case DataRowState.Added:
+                    cmd = InsertCommand;
+                    break;
+                case DataRowState.Deleted:
+                    cmd = DeleteCommand;
+                    break;
+                case DataRowState.Modified:
+                    cmd = UpdateCommand;
+                    break;
+                default:
+                    return;
+            }
+
+            if (cmd != null && cmd.Connection != null &&
+                cmd.Connection.connectionState == ConnectionState.Closed)
+            {
+                cmd.Connection.Open();
+                openedConnections.Add(cmd.Connection);
+            }
+        }
+
+
         protected override int Update(DataRow[] dataRows, DataTableMapping tableMapping)
         {
-            int ret = base.Update(dataRows, tableMapping);
-            // DbDataAdapter does automatically calls AcceptChanges on table.
-            // (even if  documentation states otherwise).
-            // Do AcceptsChanges() here, for SQL Server compatible behavior
-            // (see also Bug#5463)
-            foreach (DataRow row in dataRows)
-            {
-                row.Table.AcceptChanges();
-            }
-            return ret;
+            List<MySqlConnection> connectionsOpened = new List<MySqlConnection>();
+
+            try
+            {
+                foreach(DataRow row in dataRows)
+                {
+                    OpenConnectionIfClosed(row.RowState, connectionsOpened);
+                }
+
+                int ret = base.Update(dataRows, tableMapping);
+
+                // DbDataAdapter does automatically calls AcceptChanges on table.
+                // (even if  documentation states otherwise).
+                // Do AcceptsChanges() here, for SQL Server compatible behavior
+                // (see also Bug#5463)
+                foreach (DataRow row in dataRows)
+                {
+                    row.Table.AcceptChanges();
+                }
+                return ret;
+
+            }
+            finally 
+            {
+                foreach(MySqlConnection c in connectionsOpened)
+                    c.Close();
+            }
+
         }
 
         #region Batching Support

=== modified file 'MySql.Data/Tests/Source/DataAdapterTests.cs'
--- a/MySql.Data/Tests/Source/DataAdapterTests.cs	2010-07-08 20:21:58 +0000
+++ b/MySql.Data/Tests/Source/DataAdapterTests.cs	2010-07-12 14:38:02 +0000
@@ -898,6 +898,75 @@
         }
 
         /// <summary>
+        /// Bug #38411, using closed connection with data adapter.
+        /// </summary>
+        [Test]
+        public void BatchingConnectionClosed()
+        {
+            execSQL("CREATE TABLE Test (id INT, name VARCHAR(20), PRIMARY KEY(id))");
+
+            MySqlConnection c = new MySqlConnection(GetConnectionString(true));
+            MySqlConnection c2 = new MySqlConnection(GetConnectionString(true));
+            MySqlConnection c3 = new MySqlConnection(GetConnectionString(true));
+
+            MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM Test", c);
+            MySqlCommand ins = new MySqlCommand("INSERT INTO test (id, name) VALUES (?p1, ?p2)", c);
+            da.InsertCommand = ins;
+            ins.UpdatedRowSource = UpdateRowSource.None;
+            ins.Parameters.Add("?p1", MySqlDbType.Int32).SourceColumn = "id";
+            ins.Parameters.Add("?p2", MySqlDbType.VarChar, 20).SourceColumn = "name";
+
+            MySqlCommand del = new MySqlCommand("delete from test where id=?p1", c2);
+            da.DeleteCommand = del;
+            del.UpdatedRowSource = UpdateRowSource.None;
+            del.Parameters.Add("?p1", MySqlDbType.Int32).SourceColumn = "id";
+
+
+            MySqlCommand upd = new MySqlCommand("update test set id=?p1, name=?p2  where id=?p1", c3);
+            da.UpdateCommand = upd;
+            upd.UpdatedRowSource = UpdateRowSource.None;
+            upd.Parameters.Add("?p1", MySqlDbType.Int32).SourceColumn = "id";
+            upd.Parameters.Add("?p2", MySqlDbType.VarChar, 20).SourceColumn = "name";
+
+            DataTable dt = new DataTable();
+            da.Fill(dt);
+
+            for (int i = 1; i <= 100; i++)
+            {
+                DataRow row = dt.NewRow();
+                row["id"] = i;
+                row["name"] = "name " + i;
+                dt.Rows.Add(row);
+            }
+
+            da.UpdateBatchSize = 10;
+            da.Update(dt);
+
+            dt.Rows.Clear();
+            da.Fill(dt);
+            Assert.AreEqual(100, dt.Rows.Count);
+            for (int i = 0; i < 100; i++)
+            {
+                Assert.AreEqual(i + 1, dt.Rows[i]["id"]);
+                Assert.AreEqual("name " + (i + 1), dt.Rows[i]["name"]);
+            }
+
+            foreach (DataRow row in dt.Rows)
+            {
+                row["name"] = row["name"] + "_xxx";
+            }
+            da.Update(dt);
+            for (int i = 0; i < 100; i++)
+            {
+                dt.Rows[i].Delete();
+            }
+            da.Update(dt);
+            dt.Rows.Clear();
+            da.Fill(dt);
+            Assert.AreEqual(dt.Rows.Count, 0);
+
+        }
+        /// <summary>
         /// Bug#54895
         /// ConcurrencyException when trying to use UpdateRowSource.FirstReturnedRecord 
         /// with UpdateCommand and stored procedure.


Attachment: [text/bzr-bundle] bzr/reggie.burnett@oracle.com-20100719182911-4a4v5m9q0e5ji8q1.bundle
Thread
bzr commit into connector-net-6.1 branch (reggie.burnett:827) Reggie Burnett19 Jul