Merge pull request #704 from jgagnon/master
[mono.git] / mcs / class / System.Data / System.Data.SqlClient / SqlCommandBuilder.cs
index b9e6301b0cc191ee7f0bebaec2889a36b850f226..3ee48a6e9eabb706f2340f15cb3ed33268b2238b 100644 (file)
@@ -3,12 +3,13 @@
 //
 // Author:
 //   Tim Coleman (tim@timcoleman.com)
+//   Veerapuram Varadhan (vvaradhan@novell.com)
 //
 // Copyright (C) Tim Coleman, 2002
 //
 
 //
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004, 2009 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -35,56 +36,27 @@ using System.Collections;
 using System.ComponentModel;
 using System.Data;
 using System.Data.Common;
+using System.Data.SqlTypes;
 using System.Text;
 
 namespace System.Data.SqlClient
 {
-#if NET_2_0
        public sealed class SqlCommandBuilder : DbCommandBuilder
-#else
-       public sealed class SqlCommandBuilder : Component
-#endif // NET_2_0
        {
                #region Fields
 
-               bool disposed;
-
-               DataTable dbSchemaTable;
-               SqlDataAdapter adapter;
-               string quotePrefix;
-               string quoteSuffix;
-               string tableName;
-#if NET_2_0
-               string _catalogSeperator = ".";
-               string _schemaSeperator = ".";
-               CatalogLocation _catalogLocation = CatalogLocation.Start;
-#endif
+               readonly string _catalogSeparator = ".";
+               readonly string _schemaSeparator = ".";
+               readonly CatalogLocation _catalogLocation = CatalogLocation.Start;
        
-               SqlCommand deleteCommand;
-               SqlCommand insertCommand;
-               SqlCommand updateCommand;
-
-               // Used to construct WHERE clauses
-               static readonly string clause1 = "({0} = 1 AND {1} IS NULL)";
-               static readonly string clause2 = "({0} = {1})";
-
-               private SqlRowUpdatingEventHandler rowUpdatingHandler;
-
                #endregion // Fields
 
                #region Constructors
 
                public SqlCommandBuilder ()
                {
-                       dbSchemaTable = null;
-                       adapter = null;
-#if NET_2_0
-                       quoteSuffix = "]";
-                       quotePrefix = "[";
-#else
-                       quoteSuffix = String.Empty;
-                       quotePrefix = String.Empty;
-#endif
+                       QuoteSuffix = "]";
+                       QuotePrefix = "[";
                }
 
                public SqlCommandBuilder (SqlDataAdapter adapter)
@@ -97,499 +69,163 @@ namespace System.Data.SqlClient
 
                #region Properties
 
-#if !NET_2_0
-               [DataSysDescription ("The DataAdapter for which to automatically generate SqlCommands")]
-#endif
                [DefaultValue (null)]
                public new SqlDataAdapter DataAdapter {
-                       get { return adapter; }
-                       set { 
-                               if (adapter != null)
-                                       adapter.RowUpdating -= new SqlRowUpdatingEventHandler (RowUpdatingHandler);
-
-                               adapter = value; 
-                               if (adapter != null)
-                                       adapter.RowUpdating += new SqlRowUpdatingEventHandler (RowUpdatingHandler);
+                       get { 
+                               return (SqlDataAdapter)base.DataAdapter;
+                       } set {
+                               base.DataAdapter = value;
                        }
                }
 
-               private string QuotedTableName {
-                       get { return GetQuotedString (tableName); }
-               }
-
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-#if !NET_2_0
-               [DataSysDescription ("The character used in a text command as the opening quote for quoting identifiers that contain special characters.")]
-#else
                [EditorBrowsable (EditorBrowsableState.Never)]
-#endif // NET_2_0
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                string QuotePrefix {
-                       get { return quotePrefix; }
+                       get {
+                               return base.QuotePrefix;
+                       }
                        set {
-                               if (dbSchemaTable != null)
-                                       throw new InvalidOperationException ("The QuotePrefix and QuoteSuffix properties cannot be changed once an Insert, Update, or Delete command has been generated.");
-                               quotePrefix = value; 
+                               if (value != "[" && value != "\"")
+                                       throw new ArgumentException ("Only '[' " +
+                                               "and '\"' are allowed as value " +
+                                               "for the 'QuoteSuffix' property.");
+                               base.QuotePrefix = value;
                        }
                }
 
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-#if !NET_2_0
-               [DataSysDescription ("The character used in a text command as the closing quote for quoting identifiers that contain special characters. ")]
-#else
                [EditorBrowsable (EditorBrowsableState.Never)]
-#endif // NET_2_0
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                string QuoteSuffix {
-                       get { return quoteSuffix; }
+                       get {
+                               return base.QuoteSuffix;
+                       }
                        set {
-                               if (dbSchemaTable != null)
-                                       throw new InvalidOperationException ("The QuotePrefix and QuoteSuffix properties cannot be changed once an Insert, Update, or Delete command has been generated.");
-                               quoteSuffix = value; 
+                               if (value != "]" && value != "\"")
+                                       throw new ArgumentException ("Only ']' " +
+                                               "and '\"' are allowed as value " +
+                                               "for the 'QuoteSuffix' property.");
+                               base.QuoteSuffix = value;
                        }
                }
 
-#if NET_2_0
                [EditorBrowsable (EditorBrowsableState.Never)]
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-#if !NET_2_0
-               [DefaultValue (".")]
-#endif
                public override string CatalogSeparator {
-                       get { return _catalogSeperator; }
-                       set { if (value != null) _catalogSeperator = value; }
+                       get { return _catalogSeparator; }
+                       set {
+                               if (value != _catalogSeparator)
+                                       throw new ArgumentException ("Only " +
+                                               "'.' is allowed as value " +
+                                               "for the 'CatalogSeparator' " +
+                                               "property.");
+                       }
                }
 
                [EditorBrowsable (EditorBrowsableState.Never)]
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-#if !NET_2_0
-               [DefaultValue (".")]
-#endif
                public override string SchemaSeparator {
-                       get { return _schemaSeperator; }
-                       set {  if (value != null) _schemaSeperator = value; }
+                       get { return _schemaSeparator; }
+                       set {
+                               if (value != _schemaSeparator)
+                                       throw new ArgumentException ("Only " +
+                                               "'.' is allowed as value " +
+                                               "for the 'SchemaSeparator' " +
+                                               "property.");
+                       }
                }
 
                [EditorBrowsable (EditorBrowsableState.Never)]
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-#if !NET_2_0
-               [DefaultValue (CatalogLocation.Start)]
-#endif
                public override CatalogLocation CatalogLocation {
                        get { return _catalogLocation; }
-                       set { _catalogLocation = value; }
+                       set {
+                               if (value != CatalogLocation.Start)
+                                       throw new ArgumentException ("Only " +
+                                               "'Start' is allowed as value " +
+                                               "for the 'CatalogLocation' " +
+                                               "property.");
+                       }
                }
 
-#endif // NET_2_0
 
-               private SqlCommand SourceCommand {
-                       get {
-                               if (adapter != null)
-                                       return adapter.SelectCommand;
-                               return null;
-                       }
-               }
 
                #endregion // Properties
 
                #region Methods
 
-               private void BuildCache (bool closeConnection)
-               {
-                       SqlCommand sourceCommand = SourceCommand;
-                       if (sourceCommand == null)
-                               throw new InvalidOperationException ("The DataAdapter.SelectCommand property needs to be initialized.");
-                       SqlConnection connection = sourceCommand.Connection;
-                       if (connection == null)
-                               throw new InvalidOperationException ("The DataAdapter.SelectCommand.Connection property needs to be initialized.");
                                
-                       if (dbSchemaTable == null) {
-                               if (connection.State == ConnectionState.Open)
-                                       closeConnection = false;        
-                               else
-                                       connection.Open ();
-       
-                               SqlDataReader reader = sourceCommand.ExecuteReader (CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo);
-                               dbSchemaTable = reader.GetSchemaTable ();
-                               reader.Close ();
-                               if (closeConnection)
-                                       connection.Close ();    
-                               BuildInformation (dbSchemaTable);
-                       }
-               }
-               
-               private void BuildInformation (DataTable schemaTable)
-               {
-                       tableName = String.Empty;
-                       foreach (DataRow schemaRow in schemaTable.Rows) {
-                               if (schemaRow.IsNull ("BaseTableName") ||
-                                   (string) schemaRow ["BaseTableName"] == String.Empty)
-                                       continue;
-
-                               if (tableName == String.Empty) 
-                                       tableName = (string) schemaRow ["BaseTableName"];
-                               else if (tableName != (string) schemaRow["BaseTableName"])
-                                       throw new InvalidOperationException ("Dynamic SQL generation is not supported against multiple base tables.");
-                       }
-                       if (tableName == String.Empty)
-                               throw new InvalidOperationException ("Dynamic SQL generation is not supported with no base table.");
-                       dbSchemaTable = schemaTable;
-               }
-
-               private SqlCommand CreateDeleteCommand (bool option)
-               {
-                       // If no table was found, then we can't do an delete
-                       if (QuotedTableName == String.Empty)
-                               return null;
-
-                       CreateNewCommand (ref deleteCommand);
-
-                       string command = String.Format ("DELETE FROM {0}", QuotedTableName);
-                       StringBuilder whereClause = new StringBuilder ();
-                       bool keyFound = false;
-                       int parmIndex = 1;
-
-                       foreach (DataRow schemaRow in dbSchemaTable.Rows) {
-                               if ((bool)schemaRow["IsExpression"] == true)
-                                       continue;
-                               if (!IncludedInWhereClause (schemaRow)) 
-                                       continue;
-
-                               if (whereClause.Length > 0) 
-                                       whereClause.Append (" AND ");
-
-                               bool isKey = (bool) schemaRow ["IsKey"];
-                               SqlParameter parameter = null;
-
-                               if (isKey)
-                                       keyFound = true;
-
-                               //ms.net 1.1 generates the null check for columns even if AllowDBNull is false
-                               //while ms.net 2.0 does not. Anyways, since both forms are logically equivalent
-                               //following the 2.0 approach
-                               bool allowNull = (bool) schemaRow ["AllowDBNull"];
-                               if (!isKey && allowNull) {
-                                       if (option) {
-                                               parameter = deleteCommand.Parameters.Add (String.Format ("@{0}",
-                                                                                                        schemaRow ["BaseColumnName"]),
-                                                                                         SqlDbType.Int);
-                                       } else {
-                                               parameter = deleteCommand.Parameters.Add (String.Format ("@p{0}", parmIndex++),
-                                                                                         SqlDbType.Int);
-                                       }
-                                       String sourceColumnName = (string) schemaRow ["BaseColumnName"];
-                                       parameter.Value = 1;
-
-                                       whereClause.Append ("(");
-                                       whereClause.Append (String.Format (clause1, parameter.ParameterName, 
-                                                                       GetQuotedString (sourceColumnName)));
-                                       whereClause.Append (" OR ");
-                               }
-
-                               if (option) {
-                                       parameter = deleteCommand.Parameters.Add (CreateParameter (schemaRow));
-                               } else {
-                                       parameter = deleteCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
-                               }
-                               parameter.SourceVersion = DataRowVersion.Original;
-
-                               whereClause.Append (String.Format (clause2, GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
-
-                               if (!isKey && allowNull)
-                                       whereClause.Append (")");
-                       }
-                       if (!keyFound)
-                               throw new InvalidOperationException ("Dynamic SQL generation for the DeleteCommand is not supported against a SelectCommand that does not return any key column information.");
-
-                       // We're all done, so bring it on home
-                       string sql = String.Format ("{0} WHERE ({1})", command, whereClause.ToString ());
-                       deleteCommand.CommandText = sql;
-                       return deleteCommand;
-               }
-
-               private SqlCommand CreateInsertCommand (bool option)
-               {
-                       if (QuotedTableName == String.Empty)
-                               return null;
-
-                       CreateNewCommand (ref insertCommand);
-
-                       string command = String.Format ("INSERT INTO {0}", QuotedTableName);
-                       string sql;
-                       StringBuilder columns = new StringBuilder ();
-                       StringBuilder values = new StringBuilder ();
-
-                       int parmIndex = 1;
-                       foreach (DataRow schemaRow in dbSchemaTable.Rows) {
-                               if (!IncludedInInsert (schemaRow))
-                                       continue;
-
-                               if (parmIndex > 1) {
-                                       columns.Append (", ");
-                                       values.Append (", ");
-                               }
-
-                               SqlParameter parameter = null;
-                               if (option) {
-                                       parameter = insertCommand.Parameters.Add (CreateParameter (schemaRow));
-                               } else {
-                                       parameter = insertCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
-                               }
-                               parameter.SourceVersion = DataRowVersion.Current;
-
-                               columns.Append (GetQuotedString (parameter.SourceColumn));
-                               values.Append (parameter.ParameterName);
-                       }
-
-                       sql = String.Format ("{0} ({1}) VALUES ({2})", command, columns.ToString (), values.ToString ());
-                       insertCommand.CommandText = sql;
-                       return insertCommand;
-               }
-
-               private void CreateNewCommand (ref SqlCommand command)
-               {
-                       SqlCommand sourceCommand = SourceCommand;
-                       if (command == null) {
-                               command = sourceCommand.Connection.CreateCommand ();
-                               command.CommandTimeout = sourceCommand.CommandTimeout;
-                               command.Transaction = sourceCommand.Transaction;
-                       }
-                       command.CommandType = CommandType.Text;
-                       command.UpdatedRowSource = UpdateRowSource.None;
-                       command.Parameters.Clear ();
-               }
-
-               private SqlCommand CreateUpdateCommand (bool option)
-               {
-                       // If no table was found, then we can't do an update
-                       if (QuotedTableName == String.Empty)
-                               return null;
-
-                       CreateNewCommand (ref updateCommand);
-
-                       string command = String.Format ("UPDATE {0} SET ", QuotedTableName);
-                       StringBuilder columns = new StringBuilder ();
-                       StringBuilder whereClause = new StringBuilder ();
-                       int parmIndex = 1;
-                       bool keyFound = false;
-
-                       // First, create the X=Y list for UPDATE
-                       foreach (DataRow schemaRow in dbSchemaTable.Rows) {
-                               if (!IncludedInUpdate (schemaRow))
-                                       continue;
-                               if (columns.Length > 0) 
-                                       columns.Append (", ");
-
-                               SqlParameter parameter = null;
-                               if (option) {
-                                       parameter = updateCommand.Parameters.Add (CreateParameter (schemaRow));
-                               } else {
-                                       parameter = updateCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
-                               }
-                               parameter.SourceVersion = DataRowVersion.Current;
-
-                               columns.Append (String.Format ("{0} = {1}", GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
-                       }
-
-                       // Now, create the WHERE clause.  This may be optimizable, but it would be ugly to incorporate
-                       // into the loop above.  "Premature optimization is the root of all evil." -- Knuth
-                       foreach (DataRow schemaRow in dbSchemaTable.Rows) {
-                               if ((bool)schemaRow["IsExpression"] == true)
-                                       continue;
-
-                               if (!IncludedInWhereClause (schemaRow)) 
-                                       continue;
-
-                               if (whereClause.Length > 0) 
-                                       whereClause.Append (" AND ");
-
-                               bool isKey = (bool) schemaRow ["IsKey"];
-                               SqlParameter parameter = null;
-
-
-                               if (isKey)
-                                       keyFound = true;
-
-                               //ms.net 1.1 generates the null check for columns even if AllowDBNull is false
-                               //while ms.net 2.0 does not. Anyways, since both forms are logically equivalent
-                               //following the 2.0 approach
-                               bool allowNull = (bool) schemaRow ["AllowDBNull"];
-                               if (!isKey && allowNull) {
-                                       if (option) {
-                                               parameter = updateCommand.Parameters.Add (String.Format ("@{0}",
-                                                                                                        schemaRow ["BaseColumnName"]),
-                                                                                         SqlDbType.Int);
-                                       } else {
-                                               parameter = updateCommand.Parameters.Add (String.Format ("@p{0}", parmIndex++),
-                                                                                         SqlDbType.Int);
-                                       }
-                                       parameter.Value = 1;
-                                       whereClause.Append ("(");
-                                       whereClause.Append (String.Format (clause1, parameter.ParameterName,
-                                                                       GetQuotedString ((string) schemaRow ["BaseColumnName"])));
-                                       whereClause.Append (" OR ");
-                               }
-
-                               if (option) {
-                                       parameter = updateCommand.Parameters.Add (CreateParameter (schemaRow));
-                               } else {
-                                       parameter = updateCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
-                               }
-                               parameter.SourceVersion = DataRowVersion.Original;
-
-                               whereClause.Append (String.Format (clause2, GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
-
-                               if (!isKey && allowNull)
-                                       whereClause.Append (")");
-                       }
-                       if (!keyFound)
-                               throw new InvalidOperationException ("Dynamic SQL generation for the UpdateCommand is not supported against a SelectCommand that does not return any key column information.");
-
-                       // We're all done, so bring it on home
-                       string sql = String.Format ("{0}{1} WHERE ({2})", command, columns.ToString (), whereClause.ToString ());
-                       updateCommand.CommandText = sql;
-                       return updateCommand;
-               }
-
-               private SqlParameter CreateParameter (DataRow schemaRow)
-               {
-                       string sourceColumn = (string) schemaRow ["BaseColumnName"];
-                       string name = String.Format ("@{0}", sourceColumn);
-                       SqlDbType sqlDbType = (SqlDbType) schemaRow ["ProviderType"];
-                       int size = (int) schemaRow ["ColumnSize"];
-
-                       return new SqlParameter (name, sqlDbType, size, sourceColumn);
-               }
-
-               private SqlParameter CreateParameter (int parmIndex, DataRow schemaRow)
-               {
-                       string name = String.Format ("@p{0}", parmIndex);
-                       string sourceColumn = (string) schemaRow ["BaseColumnName"];
-                       SqlDbType sqlDbType = (SqlDbType) schemaRow ["ProviderType"];
-                       int size = (int) schemaRow ["ColumnSize"];
-
-                       return new SqlParameter (name, sqlDbType, size, sourceColumn);
-               }
-
                public static void DeriveParameters (SqlCommand command)
                {
                        command.DeriveParameters ();
                }
 
-#if NET_2_0
-               new
-#else
-               protected override
-#endif
-               void Dispose (bool disposing)
-               {
-                       if (!disposed) {
-                               if (disposing) {
-                                       if (insertCommand != null)
-                                               insertCommand.Dispose ();
-                                       if (deleteCommand != null)
-                                               deleteCommand.Dispose ();
-                                       if (updateCommand != null)
-                                               updateCommand.Dispose ();
-                                       if (dbSchemaTable != null)
-                                               dbSchemaTable.Dispose ();
-                               }
-                               disposed = true;
-                       }
-               }
 
-               public 
-#if NET_2_0
+               public
                new
-#endif // NET_2_0
                SqlCommand GetDeleteCommand ()
                {
-                       BuildCache (true);
-                       if (deleteCommand == null)
-                               return CreateDeleteCommand (false);
-                       return deleteCommand;
+                       return (SqlCommand) base.GetDeleteCommand (false);
                }
 
                public
-#if NET_2_0
                new
-#endif // NET_2_0
                SqlCommand GetInsertCommand ()
                {
-                       BuildCache (true);
-                       if (insertCommand == null)
-                               return CreateInsertCommand (false);
-                       return insertCommand;
-               }
-
-               private string GetQuotedString (string value)
-               {
-                       if (value == String.Empty || value == null)
-                               return value;
-                       if (quotePrefix == String.Empty && quoteSuffix == String.Empty)
-                               return value;
-                       return String.Format ("{0}{1}{2}", quotePrefix, value, quoteSuffix);
+                       return (SqlCommand) base.GetInsertCommand (false);
                }
 
                public 
-#if NET_2_0
                new
-#endif // NET_2_0
                SqlCommand GetUpdateCommand ()
                {
-                       BuildCache (true);
-                       if (updateCommand == null)
-                               return CreateUpdateCommand (false);
-                       return updateCommand;
+                       return (SqlCommand) base.GetUpdateCommand (false);
                }
 
-#if NET_2_0
                public new SqlCommand GetUpdateCommand (bool useColumnsForParameterNames)
                {
-                       BuildCache (true);
-                       if (updateCommand == null)
-                               return CreateUpdateCommand (useColumnsForParameterNames);
-                       return updateCommand;
+                       return (SqlCommand) base.GetUpdateCommand (useColumnsForParameterNames);
                }
 
                public new SqlCommand GetDeleteCommand (bool useColumnsForParameterNames)
                {
-                       BuildCache (true);
-                       if (deleteCommand == null)
-                               return CreateDeleteCommand (useColumnsForParameterNames);
-                       return deleteCommand;
+                       return (SqlCommand) base.GetDeleteCommand (useColumnsForParameterNames);
                }
 
                public new SqlCommand GetInsertCommand (bool useColumnsForParameterNames)
                {
-                       BuildCache (true);
-                       if (insertCommand == null)
-                               return CreateInsertCommand (useColumnsForParameterNames);
-                       return insertCommand;
+                       return (SqlCommand) base.GetInsertCommand (useColumnsForParameterNames);
                }
                
                public override string QuoteIdentifier (string unquotedIdentifier)
                {
-                       return base.QuoteIdentifier (unquotedIdentifier);
+                       if (unquotedIdentifier == null)
+                               throw new ArgumentNullException ("unquotedIdentifier");
+
+                       string prefix = QuotePrefix;
+                       string suffix = QuoteSuffix;
+
+                       if ((prefix == "[" && suffix != "]") || (prefix == "\"" && suffix != "\""))
+                               throw new ArgumentException ("The QuotePrefix " +
+                                       "and QuoteSuffix properties do not match.");
+
+                       string escaped = unquotedIdentifier.Replace (suffix,
+                               suffix + suffix);
+                       return string.Concat (prefix, escaped, suffix);
                }
                
                public override string UnquoteIdentifier (string quotedIdentifier)
                {
                        return base.UnquoteIdentifier (quotedIdentifier);
                }
-               
-#endif // NET_2_0
 
                private bool IncludedInInsert (DataRow schemaRow)
                {
@@ -635,44 +271,38 @@ namespace System.Data.SqlClient
                        return true;
                }
 
-#if NET_2_0
-               new
-#else
-               public
-#endif
-               void RefreshSchema () 
-               {
-                       // FIXME: "Figure out what else needs to be cleaned up when we refresh."
-                       tableName = String.Empty;
-                       dbSchemaTable = null;
-                       CreateNewCommand (ref deleteCommand);
-                       CreateNewCommand (ref updateCommand);
-                       CreateNewCommand (ref insertCommand);
-               }
 
-#if NET_2_0
                protected override void ApplyParameterInfo (DbParameter parameter,
                                                            DataRow datarow,
                                                            StatementType statementType,
                                                            bool whereClause)
                {
                        SqlParameter sqlParam = (SqlParameter) parameter;
-                       sqlParam.Size = int.Parse (datarow ["ColumnSize"].ToString ());
-                       if (datarow ["NumericPrecision"] != DBNull.Value) {
-                               sqlParam.Precision = byte.Parse (datarow ["NumericPrecision"].ToString ());
+                       sqlParam.SqlDbType = (SqlDbType) datarow ["ProviderType"];
+
+                       object precision = datarow ["NumericPrecision"];
+                       if (precision != DBNull.Value) {
+                               short val = (short) precision;
+                               if (val < byte.MaxValue && val >= byte.MinValue)
+                                       sqlParam.Precision = (byte) val;
                        }
-                       if (datarow ["NumericScale"] != DBNull.Value) {
-                               sqlParam.Scale = byte.Parse (datarow ["NumericScale"].ToString ());
+
+                       object scale = datarow ["NumericScale"];
+                       if (scale != DBNull.Value) {
+                               short val = ((short) scale);
+                               if (val < byte.MaxValue && val >= byte.MinValue)
+                                       sqlParam.Scale = (byte) val;
                        }
-                       sqlParam.SqlDbType = (SqlDbType) datarow ["ProviderType"];
                }
 
-               protected override string GetParameterName (int parameterOrdinal)
+               protected override
+               string GetParameterName (int parameterOrdinal)
                {
                        return String.Format ("@p{0}",  parameterOrdinal);
                }
 
-               protected override string GetParameterName (string parameterName)
+               protected override
+               string GetParameterName (string parameterName)
                {
                        return String.Format ("@{0}", parameterName);
                }
@@ -681,47 +311,32 @@ namespace System.Data.SqlClient
                {
                        return GetParameterName (parameterOrdinal);
                }
-#endif // NET_2_0
 
                #endregion // Methods
 
                #region Event Handlers
 
-               private void RowUpdatingHandler (object sender, SqlRowUpdatingEventArgs args)
+               void RowUpdatingHandler (object sender, SqlRowUpdatingEventArgs args)
                {
-                       if (args.Command != null)
-                               return;
-                       try {
-                               switch (args.StatementType) {
-                               case StatementType.Insert:
-                                       args.Command = GetInsertCommand ();
-                                       break;
-                               case StatementType.Update:
-                                       args.Command = GetUpdateCommand ();
-                                       break;
-                               case StatementType.Delete:
-                                       args.Command = GetDeleteCommand ();
-                                       break;
-                               }
-                       } catch (Exception e) {
-                               args.Errors = e;
-                               args.Status = UpdateStatus.ErrorsOccurred;
-                       }
+                       base.RowUpdatingHandler (args);
                }
 
-#if NET_2_0
                protected override void SetRowUpdatingHandler (DbDataAdapter adapter)
                {
-                       if (!(adapter is SqlDataAdapter)) {
-                               throw new InvalidOperationException ("Adapter needs to be a SqlDataAdapter");
-                       }
-                       rowUpdatingHandler = new SqlRowUpdatingEventHandler (RowUpdatingHandler);
-                       ((SqlDataAdapter) adapter).RowUpdating += rowUpdatingHandler;
+                               SqlDataAdapter sda = adapter as SqlDataAdapter;
+                               if (sda == null) {
+                                       throw new InvalidOperationException ("Adapter needs to be a SqlDataAdapter");
+                               }
+                               
+                               if (sda != base.DataAdapter)
+                                       sda.RowUpdating += new SqlRowUpdatingEventHandler (RowUpdatingHandler);
+                               else
+                                       sda.RowUpdating -= new SqlRowUpdatingEventHandler (RowUpdatingHandler);;
                }
 
                protected override DataTable GetSchemaTable (DbCommand srcCommand)
                {
-                       using (SqlDataReader rdr = (SqlDataReader) srcCommand.ExecuteReader ())
+                       using (SqlDataReader rdr = (SqlDataReader) srcCommand.ExecuteReader (CommandBehavior.KeyInfo | CommandBehavior.SchemaOnly))
                                return rdr.GetSchemaTable ();
                }
 
@@ -737,7 +352,6 @@ namespace System.Data.SqlClient
                        }
                        return command;
                }
-#endif // NET_2_0
 
                #endregion // Event Handlers
        }