Merge pull request #704 from jgagnon/master
[mono.git] / mcs / class / System.Data / System.Data.SqlClient / SqlCommandBuilder.cs
index f1640ff266775fb635d73e71a99b5a6719cbfa34..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,49 +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
+namespace System.Data.SqlClient
+{
        public sealed class SqlCommandBuilder : DbCommandBuilder
-#else
-       public sealed class SqlCommandBuilder : Component
-#endif // NET_2_0
        {
                #region Fields
 
-               bool disposed = false;
-
-               DataTable dbSchemaTable;
-               SqlDataAdapter adapter;
-               string quotePrefix;
-               string quoteSuffix;
-               string[] columnNames;
-               string tableName;
+               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})";
-
                #endregion // Fields
 
                #region Constructors
 
-               public SqlCommandBuilder () 
+               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)
@@ -90,381 +69,162 @@ 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)]
-#if !NET_2_0
-               [DataSysDescription ("The character used in a text command as the opening quote for quoting identifiers that contain special characters.")]
-#endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               public 
-#if NET_2_0
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public
                override
-#endif // NET_2_0
-                string QuotePrefix {
-                       get { return 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; 
+               string QuotePrefix {
+                       get {
+                               return base.QuotePrefix;
+                       }
+                       set {
+                               if (value != "[" && value != "\"")
+                                       throw new ArgumentException ("Only '[' " +
+                                               "and '\"' are allowed as value " +
+                                               "for the 'QuoteSuffix' property.");
+                               base.QuotePrefix = value;
                        }
                }
 
                [Browsable (false)]
-#if !NET_2_0
-               [DataSysDescription ("The character used in a text command as the closing quote for quoting identifiers that contain special characters. ")]
-#endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               public 
-#if NET_2_0
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public
                override
-#endif // NET_2_0
-                string QuoteSuffix {
-                       get { return quoteSuffix; }
+               string 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;
                        }
                }
 
-               private SqlCommand SourceCommand {
-                       get {
-                               if (adapter != null)
-                                       return adapter.SelectCommand;
-                               return null;
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               [Browsable (false)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               public override string CatalogSeparator {
+                       get { return _catalogSeparator; }
+                       set {
+                               if (value != _catalogSeparator)
+                                       throw new ArgumentException ("Only " +
+                                               "'.' is allowed as value " +
+                                               "for the 'CatalogSeparator' " +
+                                               "property.");
                        }
                }
 
-               #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") ||
-                                   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.");
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               [Browsable (false)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               public override string SchemaSeparator {
+                       get { return _schemaSeparator; }
+                       set {
+                               if (value != _schemaSeparator)
+                                       throw new ArgumentException ("Only " +
+                                               "'.' is allowed as value " +
+                                               "for the 'SchemaSeparator' " +
+                                               "property.");
                        }
-                       if (tableName == String.Empty)
-                               throw new InvalidOperationException ("Dynamic SQL generation is not supported with no base table.");
-                       dbSchemaTable = schemaTable;
                }
 
-               private SqlCommand CreateDeleteCommand ()
-               {
-                       // 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 columns = new StringBuilder ();
-                       StringBuilder whereClause = new StringBuilder ();
-                       string dsColumnName = String.Empty;
-                       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) {
-                                       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 ");
-                               }
-
-                               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 (")");
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               [Browsable (false)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               public override CatalogLocation CatalogLocation {
+                       get { return _catalogLocation; }
+                       set {
+                               if (value != CatalogLocation.Start)
+                                       throw new ArgumentException ("Only " +
+                                               "'Start' is allowed as value " +
+                                               "for the 'CatalogLocation' " +
+                                               "property.");
                        }
-                       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 ()
-               {
-                       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 ();
-                       string dsColumnName = String.Empty;
 
-                       int parmIndex = 1;
-                       foreach (DataRow schemaRow in dbSchemaTable.Rows) {
-                               if (!IncludedInInsert (schemaRow))
-                                       continue;
-
-                               if (parmIndex > 1) {
-                                       columns.Append (", ");
-                                       values.Append (", ");
-                               }
-
-                               SqlParameter parameter = insertCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
-                               parameter.SourceVersion = DataRowVersion.Current;
-
-                               columns.Append (GetQuotedString (parameter.SourceColumn));
-                               values.Append (parameter.ParameterName);
-                       }
+               #endregion // Properties
 
-                       sql = String.Format ("{0} ({1}) VALUES ({2})", command, columns.ToString (), values.ToString ());
-                       insertCommand.CommandText = sql;
-                       return insertCommand;
-               }
+               #region Methods
 
-               private void CreateNewCommand (ref SqlCommand command)
+                               
+               public static void DeriveParameters (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 ();
+                       command.DeriveParameters ();
                }
 
-               private SqlCommand CreateUpdateCommand ()
-               {
-                       // 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;
-                       string dsColumnName = String.Empty;
-                       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 = 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) {
-                                       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 ");
-                               }
-                                       
-                               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 (int parmIndex, DataRow schemaRow)
+               public
+               new
+               SqlCommand GetDeleteCommand ()
                {
-                       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);
+                       return (SqlCommand) base.GetDeleteCommand (false);
                }
 
-               public static void DeriveParameters (SqlCommand command)
+               public
+               new
+               SqlCommand GetInsertCommand ()
                {
-                       command.DeriveParameters ();
+                       return (SqlCommand) base.GetInsertCommand (false);
                }
 
-               protected override void Dispose (bool disposing)
+               public 
+               new
+               SqlCommand GetUpdateCommand ()
                {
-                       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;
-                       }
+                       return (SqlCommand) base.GetUpdateCommand (false);
                }
 
-               public 
-#if NET_2_0
-               new
-#endif // NET_2_0
-                SqlCommand GetDeleteCommand ()
+               public new SqlCommand GetUpdateCommand (bool useColumnsForParameterNames)
                {
-                       BuildCache (true);
-                       if (deleteCommand == null)
-                               return CreateDeleteCommand ();
-                       return deleteCommand;
+                       return (SqlCommand) base.GetUpdateCommand (useColumnsForParameterNames);
                }
 
-               public 
-#if NET_2_0
-               new
-#endif // NET_2_0
-                SqlCommand GetInsertCommand ()
+               public new SqlCommand GetDeleteCommand (bool useColumnsForParameterNames)
                {
-                       BuildCache (true);
-                       if (insertCommand == null)
-                               return CreateInsertCommand ();
-                       return insertCommand;
+                       return (SqlCommand) base.GetDeleteCommand (useColumnsForParameterNames);
                }
 
-               private string GetQuotedString (string value)
+               public new SqlCommand GetInsertCommand (bool useColumnsForParameterNames)
                {
-                       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 (useColumnsForParameterNames);
                }
+               
+               public override string QuoteIdentifier (string unquotedIdentifier)
+               {
+                       if (unquotedIdentifier == null)
+                               throw new ArgumentNullException ("unquotedIdentifier");
 
-               public 
-#if NET_2_0
-               new
-#endif // NET_2_0
-                SqlCommand GetUpdateCommand ()
+                       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)
                {
-                       BuildCache (true);
-                       if (updateCommand == null)
-                               return CreateUpdateCommand ();
-                       return updateCommand;
+                       return base.UnquoteIdentifier (quotedIdentifier);
                }
 
                private bool IncludedInInsert (DataRow schemaRow)
@@ -511,85 +271,88 @@ namespace System.Data.SqlClient {
                        return true;
                }
 
-               [MonoTODO ("Figure out what else needs to be cleaned up when we refresh.")]
-               public 
-#if NET_2_0
-               override
-#endif // NET_2_0
-                void RefreshSchema () 
+
+               protected override void ApplyParameterInfo (DbParameter parameter,
+                                                           DataRow datarow,
+                                                           StatementType statementType,
+                                                           bool whereClause)
+               {
+                       SqlParameter sqlParam = (SqlParameter) parameter;
+                       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;
+                       }
+
+                       object scale = datarow ["NumericScale"];
+                       if (scale != DBNull.Value) {
+                               short val = ((short) scale);
+                               if (val < byte.MaxValue && val >= byte.MinValue)
+                                       sqlParam.Scale = (byte) val;
+                       }
+               }
+
+               protected override
+               string GetParameterName (int parameterOrdinal)
+               {
+                       return String.Format ("@p{0}",  parameterOrdinal);
+               }
+
+               protected override
+               string GetParameterName (string parameterName)
+               {
+                       return String.Format ("@{0}", parameterName);
+               }
+
+               protected override string GetParameterPlaceholder (int parameterOrdinal)
                {
-                       tableName = String.Empty;
-                       dbSchemaTable = null;
-                       CreateNewCommand (ref deleteCommand);
-                       CreateNewCommand (ref updateCommand);
-                       CreateNewCommand (ref insertCommand);
+                       return GetParameterName (parameterOrdinal);
                }
 
-#if NET_2_0
-                [MonoTODO]
-                protected override void ApplyParameterInfo (DbParameter dbParameter,
-                                                           DataRow row,
-                                                           StatementType statementType,
-                                                           bool whereClause)
-                {
-                        throw new NotImplementedException ();
-                }
-
-                [MonoTODO]
-                protected override string GetParameterName (int position)
-                {
-                        throw new NotImplementedException ();                        
-                }
-
-                [MonoTODO]
-                protected override string GetParameterName (string parameterName)
-                {
-                        throw new NotImplementedException ();                        
-                }
-                
-
-                [MonoTODO]
-                protected override string GetParameterPlaceholder (int position)
-                {
-                        throw new NotImplementedException ();                        
-                }
-                
-#endif // NET_2_0
                #endregion // Methods
 
                #region Event Handlers
 
-               private void RowUpdatingHandler (object sender, SqlRowUpdatingEventArgs args)
+               void RowUpdatingHandler (object sender, SqlRowUpdatingEventArgs args)
+               {
+                       base.RowUpdatingHandler (args);
+               }
+
+               protected override void SetRowUpdatingHandler (DbDataAdapter adapter)
                {
-                       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;
+                               SqlDataAdapter sda = adapter as SqlDataAdapter;
+                               if (sda == null) {
+                                       throw new InvalidOperationException ("Adapter needs to be a SqlDataAdapter");
                                }
-                       } catch (Exception e) {
-                               args.Errors = e;
-                               args.Status = UpdateStatus.ErrorsOccurred;
-                       }               \r
+                               
+                               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 (CommandBehavior.KeyInfo | CommandBehavior.SchemaOnly))
+                               return rdr.GetSchemaTable ();
                }
 
-#if NET_2_0
-                [MonoTODO]
-                protected override void SetRowUpdatingHandler (DbDataAdapter adapter)
-                {
-                        throw new NotImplementedException ();
-                }
-#endif // NET_2_0
+               protected override DbCommand InitializeCommand (DbCommand command)
+               {
+                       if (command == null) {
+                               command = new SqlCommand ();
+                       } else {
+                               command.CommandTimeout = 30;
+                               command.Transaction = null;
+                               command.CommandType = CommandType.Text;
+                               command.UpdatedRowSource = UpdateRowSource.None;
+                       }
+                       return command;
+               }
 
                #endregion // Event Handlers
        }
 }
-