From: Date: March 2 2007 11:15pm Subject: Connector/NET commit: r627 - in branches/5.0: . Driver/Source TestSuite List-Archive: http://lists.mysql.com/commits/21066 X-Bug: 25569 Message-Id: <200703022215.l22MFl5R017068@bk-internal.mysql.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modified: branches/5.0/CHANGES branches/5.0/Driver/Source/CommandBuilder.cs branches/5.0/Driver/Source/Resources.Designer.cs branches/5.0/Driver/Source/Resources.resx branches/5.0/TestSuite/CommandBuilderTests.cs Log: Bug #25569 UpdateRowSource.FirstReturnedRecord does not work Fixed this by exposing a property on the command builder where the user can request that generated keys be returned and then applying a final select later in the process. Thanks go to Lynn Eriksen for some good feedback on this bug and for submitting an idea for how it could be fixed. Modified: branches/5.0/CHANGES =================================================================== --- branches/5.0/CHANGES 2007-03-02 19:14:21 UTC (rev 626) +++ branches/5.0/CHANGES 2007-03-02 22:15:46 UTC (rev 627) @@ -3,6 +3,7 @@ Bugs fixed ---------- Bug #25605 BINARY and VARBINARY is returned as a string + Bug #25569 UpdateRowSource.FirstReturnedRecord does not work Version 5.0.4 2-28-2007 Modified: branches/5.0/Driver/Source/CommandBuilder.cs =================================================================== --- branches/5.0/Driver/Source/CommandBuilder.cs 2007-03-02 19:14:21 UTC (rev 626) +++ branches/5.0/Driver/Source/CommandBuilder.cs 2007-03-02 22:15:46 UTC (rev 627) @@ -30,32 +30,36 @@ namespace MySql.Data.MySqlClient { - /// + /// #if !PocketPC - [ToolboxItem(false)] - [System.ComponentModel.DesignerCategory("Code")] + [ToolboxItem(false)] + [System.ComponentModel.DesignerCategory("Code")] #endif - public sealed class MySqlCommandBuilder : DbCommandBuilder - { - #region Constructors + public sealed class MySqlCommandBuilder : DbCommandBuilder + { + private string finalSelect; + private bool returnGeneratedIds; - /// - public MySqlCommandBuilder() - { - QuotePrefix = QuoteSuffix = "`"; - } + #region Constructors - /// - public MySqlCommandBuilder(MySqlDataAdapter adapter) : this() - { - DataAdapter = adapter; - } + /// + public MySqlCommandBuilder() + { + QuotePrefix = QuoteSuffix = "`"; + } - #endregion + /// + public MySqlCommandBuilder(MySqlDataAdapter adapter) + : this() + { + DataAdapter = adapter; + } - #region Properties + #endregion - /// + #region Properties + + /// public new MySqlDataAdapter DataAdapter { get { return (MySqlDataAdapter)base.DataAdapter; } @@ -70,29 +74,41 @@ } } - #endregion + /// + /// Indicates whether the command builder should generate a SELECT statement + /// to populate any autogenerated fields. We provide this property rather + /// than rely on the MySqlCommand.UpdatedRowSource property since a user should + /// still be able to write a custom insert command and not have our work interfere. + /// + public bool ReturnGeneratedIdentifiers + { + get { return returnGeneratedIds; } + set { returnGeneratedIds = value; } + } - #region Public Methods + #endregion - /// - /// Retrieves parameter information from the stored procedure specified - /// in the MySqlCommand and populates the Parameters collection of the - /// specified MySqlCommand object. - /// This method is not currently supported since stored procedures are - /// not available in MySql. - /// - /// The MySqlCommand referencing the stored - /// procedure from which the parameter information is to be derived. - /// The derived parameters are added to the Parameters collection of the - /// MySqlCommand. - /// The command text is not - /// a valid stored procedure name. - public static void DeriveParameters(MySqlCommand command) - { - if (!command.Connection.driver.Version.isAtLeast(5,0,0)) - throw new MySqlException("DeriveParameters is not supported on MySQL versions " + - "prior to 5.0"); + #region Public Methods + /// + /// Retrieves parameter information from the stored procedure specified + /// in the MySqlCommand and populates the Parameters collection of the + /// specified MySqlCommand object. + /// This method is not currently supported since stored procedures are + /// not available in MySql. + /// + /// The MySqlCommand referencing the stored + /// procedure from which the parameter information is to be derived. + /// The derived parameters are added to the Parameters collection of the + /// MySqlCommand. + /// The command text is not + /// a valid stored procedure name. + public static void DeriveParameters(MySqlCommand command) + { + if (!command.Connection.driver.Version.isAtLeast(5, 0, 0)) + throw new MySqlException("DeriveParameters is not supported on MySQL versions " + + "prior to 5.0"); + // retrieve the proc definitino from the cache. string spName = command.CommandText; if (spName.IndexOf(".") == -1) @@ -145,12 +161,13 @@ return (MySqlCommand)GetInsertCommand(false); } - /// - public override void RefreshSchema() - { + /// + public override void RefreshSchema() + { base.RefreshSchema(); - } - #endregion + finalSelect = null; + } + #endregion /// @@ -158,20 +175,20 @@ /// /// /// - protected override string GetParameterName(string columnName) - { - StringBuilder sb = new StringBuilder(columnName); - sb.Replace(" ", ""); - sb.Replace("/", "_per_"); - sb.Replace("-", "_"); - sb.Replace(")", "_cb_"); - sb.Replace("(", "_ob_"); - sb.Replace("%", "_pct_"); - sb.Replace("<", "_lt_"); - sb.Replace(">", "_gt_"); - sb.Replace(".", "_pt_"); - return sb.ToString(); - } + protected override string GetParameterName(string columnName) + { + StringBuilder sb = new StringBuilder(columnName); + sb.Replace(" ", ""); + sb.Replace("/", "_per_"); + sb.Replace("-", "_"); + sb.Replace(")", "_cb_"); + sb.Replace("(", "_ob_"); + sb.Replace("%", "_pct_"); + sb.Replace("<", "_lt_"); + sb.Replace(">", "_gt_"); + sb.Replace(".", "_pt_"); + return sb.ToString(); + } protected override DbCommand InitializeCommand(DbCommand command) { @@ -179,7 +196,7 @@ } - protected override void ApplyParameterInfo(DbParameter parameter, DataRow row, + protected override void ApplyParameterInfo(DbParameter parameter, DataRow row, StatementType statementType, bool whereClause) { ((MySqlParameter)parameter).MySqlDbType = (MySqlDbType)row["ProviderType"]; @@ -208,7 +225,42 @@ private void RowUpdating(object sender, MySqlRowUpdatingEventArgs args) { base.RowUpdatingHandler(args); + + if (args.StatementType != StatementType.Insert) return; + + if (ReturnGeneratedIdentifiers) + { + if (args.Command.UpdatedRowSource != UpdateRowSource.None) + throw new InvalidOperationException( + Resources.MixingUpdatedRowSource); + args.Command.UpdatedRowSource = UpdateRowSource.FirstReturnedRecord; + if (finalSelect == null) + CreateFinalSelect(); + } + + args.Command.CommandText += finalSelect; } + /// + /// We only need to return the single auto generated column since the base + /// ADO.Net classes will take care of mapping it onto the datarow for us. + /// + private void CreateFinalSelect() + { + StringBuilder select = new StringBuilder(";SELECT last_insert_id() AS "); + + DataTable dt = GetSchemaTable(DataAdapter.SelectCommand); + + foreach (DataRow row in dt.Rows) + { + if (!(bool)row["IsAutoIncrement"]) + continue; + + select.AppendFormat("`{0}`", row["ColumnName"]); + break; + } + + finalSelect = select.ToString(); + } } } Modified: branches/5.0/Driver/Source/Resources.Designer.cs =================================================================== --- branches/5.0/Driver/Source/Resources.Designer.cs 2007-03-02 19:14:21 UTC (rev 626) +++ branches/5.0/Driver/Source/Resources.Designer.cs 2007-03-02 22:15:46 UTC (rev 627) @@ -331,6 +331,15 @@ } /// + /// Looks up a localized string similar to When MySqlCommandBuilder.ReturnGeneratedIdentifiers is true, MySqlCommand.UpdatedRowSource must be set to None.. + /// + internal static string MixingUpdatedRowSource { + get { + return ResourceManager.GetString("MixingUpdatedRowSource", resourceCulture); + } + } + + /// /// Looks up a localized string similar to NamedPipeStream does not support seeking. /// internal static string NamedPipeNoSeek { Modified: branches/5.0/Driver/Source/Resources.resx =================================================================== --- branches/5.0/Driver/Source/Resources.resx 2007-03-02 19:14:21 UTC (rev 626) +++ branches/5.0/Driver/Source/Resources.resx 2007-03-02 22:15:46 UTC (rev 627) @@ -318,4 +318,7 @@ Parameter '{0}' must be defined. + + When MySqlCommandBuilder.ReturnGeneratedIdentifiers is true, MySqlCommand.UpdatedRowSource must be set to None. + \ No newline at end of file Modified: branches/5.0/TestSuite/CommandBuilderTests.cs =================================================================== --- branches/5.0/TestSuite/CommandBuilderTests.cs 2007-03-02 19:14:21 UTC (rev 626) +++ branches/5.0/TestSuite/CommandBuilderTests.cs 2007-03-02 22:15:46 UTC (rev 627) @@ -273,7 +273,7 @@ DataTable dt = new DataTable(); da.Fill(dt); dt.Columns[0].AutoIncrement = true; - //Assert.IsTrue(dt.Columns[0].AutoIncrement); + Assert.IsTrue(dt.Columns[0].AutoIncrement); dt.Columns[0].AutoIncrementSeed = -1; dt.Columns[0].AutoIncrementStep = -1; DataRow row = dt.NewRow(); @@ -294,5 +294,45 @@ Assert.AreEqual(1, dt.Rows[0]["id"]); Assert.AreEqual("Test", dt.Rows[0]["name"]); } + + /// + /// Bug #25569 UpdateRowSource.FirstReturnedRecord does not work + /// + [Test] + public void AutoIncrementColumnsOnInsert2() + { + execSQL("DROP TABLE IF EXISTS test"); + execSQL("CREATE TABLE test (id INT UNSIGNED NOT NULL " + + "AUTO_INCREMENT PRIMARY KEY, name VARCHAR(20))"); + MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM test", conn); + MySqlCommandBuilder cb = new MySqlCommandBuilder(da); + cb.ReturnGeneratedIdentifiers = true; + + DataTable dt = new DataTable(); + da.Fill(dt); + dt.Rows.Clear(); + + try + { + DataRow row = dt.NewRow(); + row["name"] = "Test"; + dt.Rows.Add(row); + da.Update(dt); + Assert.AreEqual(1, dt.Rows[0]["id"]); + + row = dt.NewRow(); + row["name"] = "Test2"; + dt.Rows.Add(row); + da.Update(dt); + Assert.AreEqual(2, dt.Rows[1]["id"]); + } + catch (Exception ex) + { + Assert.Fail(ex.Message); + } + + Assert.AreEqual(1, dt.Rows[0]["id"]); + } + } }