[Task] Add an extra check in Task.WaitAny to make sure the index returned is valid
[mono.git] / mcs / class / System.Data / System.Data.Common / DbCommandBuilder.cs
index 58cda0aab235f360f23c08c2e5503d7fd460f510..bf5e54a6caf8af4069454bb4d3392d8a67513117 100644 (file)
 // Copyright (C) Tim Coleman, 2003
 //
 
-#if NET_1_2
+//
+// Copyright (C) 2004 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
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if NET_2_0 || TARGET_JVM
 
 using System.ComponentModel;
 using System.Data;
+using System.Globalization;
+using System.Text;
 
 namespace System.Data.Common {
        public abstract class DbCommandBuilder : Component
        {
-               #region Constructors
+               bool _setAllValues;
+               bool _disposed;
+
+               DataTable _dbSchemaTable;
+               DbDataAdapter _dbDataAdapter;
+               private CatalogLocation _catalogLocation = CatalogLocation.Start;
+               private ConflictOption _conflictOption = ConflictOption.CompareAllSearchableValues;
+
+               private string _tableName;
+               private string _catalogSeparator;
+               private string _quotePrefix;
+               private string _quoteSuffix;
+               private string _schemaSeparator;
+               private DbCommand _dbCommand;
+
+               DbCommand _deleteCommand;
+               DbCommand _insertCommand;
+               DbCommand _updateCommand;
+
+               static readonly string SEPARATOR_DEFAULT = ".";
+               // Used to construct WHERE clauses
+               static readonly string clause1 = "({0} = 1 AND {1} IS NULL)";
+               static readonly string clause2 = "({0} = {1})";
 
-               [MonoTODO]
                protected DbCommandBuilder ()
                {
                }
 
-               #endregion // Constructors
+               private void BuildCache (bool closeConnection)
+               {
+                       DbCommand sourceCommand = SourceCommand;
+                       if (sourceCommand == null)
+                               throw new InvalidOperationException ("The DataAdapter.SelectCommand property needs to be initialized.");
+                       DbConnection 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 ();
+       
+                               DbDataReader reader = sourceCommand.ExecuteReader (CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo);
+                               _dbSchemaTable = reader.GetSchemaTable ();
+                               reader.Close ();
+                               if (closeConnection)
+                                       connection.Close ();    
+                               BuildInformation (_dbSchemaTable);
+                       }
+               }
+               
+               private string QuotedTableName {
+                       get { return GetQuotedString (_tableName); }
+               }
 
-               #region Properties
+               bool IsCommandGenerated {
+                       get {
+                               return (_insertCommand != null || _updateCommand != null || _deleteCommand != null);
+                       }
+               }
 
-               [MonoTODO]
-               public virtual CatalogLocation CatalogLocation {
-                       get { throw new NotImplementedException (); }
-                       set { throw new NotImplementedException (); }
+               private string GetQuotedString (string value)
+               {
+                       if (value == String.Empty || value == null)
+                               return value;
+
+                       string prefix = QuotePrefix;
+                       string suffix = QuoteSuffix;
+
+                       if (prefix.Length == 0 && suffix.Length == 0)
+                               return value;
+                       return String.Format ("{0}{1}{2}", prefix, value, suffix);
                }
 
-               [MonoTODO]
-               public virtual string CatalogSeparator {
-                       get { throw new NotImplementedException (); }
-                       set { throw new NotImplementedException (); }
+               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;
                }
 
-               [MonoTODO]
-               public virtual ConflictOptions ConflictDetection {
-                       get { throw new NotImplementedException (); }
-                       set { throw new NotImplementedException (); }
+               private bool IncludedInInsert (DataRow schemaRow)
+               {
+                       // If the parameter has one of these properties, then we don't include it in the insert:
+                       // AutoIncrement, Hidden, Expression, RowVersion, ReadOnly
+
+                       if (!schemaRow.IsNull ("IsAutoIncrement") && (bool) schemaRow ["IsAutoIncrement"])
+                               return false;
+//                     if (!schemaRow.IsNull ("IsHidden") && (bool) schemaRow ["IsHidden"])
+//                             return false;
+                       if (!schemaRow.IsNull ("IsExpression") && (bool) schemaRow ["IsExpression"])
+                               return false;
+                       if (!schemaRow.IsNull ("IsRowVersion") && (bool) schemaRow ["IsRowVersion"])
+                               return false;
+                       if (!schemaRow.IsNull ("IsReadOnly") && (bool) schemaRow ["IsReadOnly"])
+                               return false;
+                       return true;
                }
 
-               [MonoTODO]
-               public DbDataAdapter DataAdapter {
-                       get { throw new NotImplementedException (); }
-                       set { throw new NotImplementedException (); }
+               private bool IncludedInUpdate (DataRow schemaRow)
+               {
+                       // If the parameter has one of these properties, then we don't include it in the insert:
+                       // AutoIncrement, Hidden, RowVersion
+
+                       if (!schemaRow.IsNull ("IsAutoIncrement") && (bool) schemaRow ["IsAutoIncrement"])
+                               return false;
+//                     if (!schemaRow.IsNull ("IsHidden") && (bool) schemaRow ["IsHidden"])
+//                             return false;
+                       if (!schemaRow.IsNull ("IsRowVersion") && (bool) schemaRow ["IsRowVersion"])
+                               return false;
+                       if (!schemaRow.IsNull ("IsExpression") && (bool) schemaRow ["IsExpression"])
+                               return false;
+                       if (!schemaRow.IsNull ("IsReadOnly") && (bool) schemaRow ["IsReadOnly"])
+                               return false;
+
+                       return true;
                }
 
-               protected abstract DbProviderFactory ProviderFactory { get; }
+               private bool IncludedInWhereClause (DataRow schemaRow)
+               {
+                       if ((bool) schemaRow ["IsLong"])
+                               return false;
+                       return true;
+               }
 
-               [MonoTODO]
-               public virtual string QuotePrefix {
-                       get { throw new NotImplementedException (); }
-                       set { throw new NotImplementedException (); }
+               private DbCommand 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 (!schemaRow.IsNull ("IsExpression") && (bool)schemaRow["IsExpression"] == true)
+                                       continue;
+                               if (!IncludedInWhereClause (schemaRow)) 
+                                       continue;
+
+                               if (whereClause.Length > 0) 
+                                       whereClause.Append (" AND ");
+
+                               bool isKey = (bool) schemaRow ["IsKey"];
+                               DbParameter parameter = null;
+                               string sourceColumnName;
+
+                               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.CreateParameter ();
+                                       if (option) {
+                                               parameter.ParameterName = String.Format ("@IsNull_{0}",
+                                                                                        schemaRow ["BaseColumnName"]);
+                                       } else {
+                                               parameter.ParameterName = String.Format ("@p{0}", parmIndex++);
+                                       }
+                                       parameter.Value = 1;
+                                       parameter.DbType = DbType.Int32;
+                                       // This should be set for nullcheckparam
+                                       sourceColumnName = (string) schemaRow ["BaseColumnName"];
+                                       parameter.SourceColumn = sourceColumnName;
+                                       parameter.SourceColumnNullMapping = true;
+                                       parameter.SourceVersion = DataRowVersion.Original;
+                                       _deleteCommand.Parameters.Add (parameter);
+                                       
+                                       whereClause.Append ("(");
+                                       whereClause.Append (String.Format (clause1, parameter.ParameterName, 
+                                                                          GetQuotedString (sourceColumnName)));
+                                       whereClause.Append (" OR ");
+                               }
+
+                               if (option)
+                                       parameter = CreateParameter (_deleteCommand, schemaRow, true);
+                               else 
+                                       parameter = CreateParameter (_deleteCommand, parmIndex++, schemaRow);
+                               
+                               parameter.SourceVersion = DataRowVersion.Original;
+                               ApplyParameterInfo (parameter, schemaRow, StatementType.Delete, true);
+                               //parameter.IsNullable = allowNull;
+
+                               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;
+                       _dbCommand = _deleteCommand;
+                       return _deleteCommand;
                }
 
-               [MonoTODO]
-               public virtual string QuoteSuffix {
-                       get { throw new NotImplementedException (); }
-                       set { throw new NotImplementedException (); }
+               private DbCommand CreateInsertCommand (bool option, DataRow row)
+               {
+                       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;
+                       DbParameter parameter = null;
+                       foreach (DataRow schemaRow in _dbSchemaTable.Rows) {
+                               if (!IncludedInInsert (schemaRow))
+                                       continue;
+
+                               if (columns.Length > 0) {
+                                       columns.Append (", ");
+                                       values.Append (", ");
+                               }
+
+                               if (option)
+                                       parameter = CreateParameter (_insertCommand, schemaRow, false);
+                               else 
+                                       parameter = CreateParameter (_insertCommand, parmIndex++, schemaRow);                   
+                               parameter.SourceVersion = DataRowVersion.Current;
+                               ApplyParameterInfo (parameter, schemaRow, StatementType.Insert, false);
+                               
+                               columns.Append (GetQuotedString (parameter.SourceColumn));
+
+                               // Workaround for columns that may have a default/bound value and for now, 
+                               // the framework, don't provide a mechanism to read these values yet
+                               // AllowDBNull and DataRow is used to workaround #385028 by using DEFAULT 
+                               string colName = schemaRow ["ColumnName"] as string;
+                               bool allowDBNull = !schemaRow.IsNull ("AllowDBNull") & (bool) schemaRow ["AllowDBNull"];
+                               if (!allowDBNull && row != null &&
+                                   (row [colName] == DBNull.Value || row [colName] == null)) {
+                                       values.Append ("DEFAULT");
+                               } else {
+                                       values.Append (parameter.ParameterName);
+                               }
+                       }
+
+                       sql = String.Format ("{0} ({1}) VALUES ({2})", command, columns.ToString (), values.ToString ());
+                       _insertCommand.CommandText = sql;
+                       _dbCommand = _insertCommand;
+                       return _insertCommand;
                }
 
-               [MonoTODO]
-               public SchemaLocation SchemaLocation {
-                       get { throw new NotImplementedException (); }
-                       set { throw new NotImplementedException (); }
+               private void CreateNewCommand (ref DbCommand command)
+               {
+                       DbCommand 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 ();
                }
 
-               [MonoTODO]
-               public virtual string SchemaSeparator {
-                       get { throw new NotImplementedException (); }
-                       set { throw new NotImplementedException (); }
+               private DbCommand 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;
+                       DbParameter parameter = null;
+
+                       // First, create the X=Y list for UPDATE
+                       foreach (DataRow schemaRow in _dbSchemaTable.Rows) {
+                               if (!IncludedInUpdate (schemaRow))
+                                       continue;
+                               if (columns.Length > 0) 
+                                       columns.Append (", ");
+
+                               if (option)
+                                       parameter = CreateParameter (_updateCommand, schemaRow, false);
+                               else 
+                                       parameter = CreateParameter (_updateCommand, parmIndex++, schemaRow);
+                               parameter.SourceVersion = DataRowVersion.Current;
+                               ApplyParameterInfo (parameter, schemaRow, StatementType.Update, false);
+                               //parameter.IsNullable = (bool) schemaRow ["AllowDBNull"];
+                               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 (!schemaRow.IsNull ("IsExpression") && (bool) schemaRow ["IsExpression"] == true)
+                                       continue;
+
+                               if (!IncludedInWhereClause (schemaRow)) 
+                                       continue;
+
+                               if (whereClause.Length > 0) 
+                                       whereClause.Append (" AND ");
+
+                               bool isKey = (bool) schemaRow ["IsKey"];
+                               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.CreateParameter ();
+                                       if (option) {
+                                               parameter.ParameterName = String.Format ("@IsNull_{0}",
+                                                                                        schemaRow ["BaseColumnName"]);
+                                       } else {
+                                               parameter.ParameterName = String.Format ("@p{0}", parmIndex++);
+                                       }
+                                       parameter.DbType = DbType.Int32;
+                                       parameter.Value = 1;
+                                       parameter.SourceColumn = (string) schemaRow ["BaseColumnName"];
+                                       parameter.SourceColumnNullMapping = true;
+                                       parameter.SourceVersion = DataRowVersion.Original;
+                                       whereClause.Append ("(");
+                                       whereClause.Append (String.Format (clause1, parameter.ParameterName,
+                                                                          GetQuotedString ((string) schemaRow ["BaseColumnName"])));
+                                       whereClause.Append (" OR ");
+                                       _updateCommand.Parameters.Add (parameter);
+                               }
+
+                               if (option)
+                                       parameter = CreateParameter (_updateCommand, schemaRow, true);
+                               else 
+                                       parameter = CreateParameter (_updateCommand, parmIndex++, schemaRow);
+                               parameter.SourceVersion = DataRowVersion.Original;
+                               //parameter.IsNullable = allowNull;
+                               ApplyParameterInfo (parameter, schemaRow, StatementType.Update, true);
+
+                               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;
+                       _dbCommand = _updateCommand;
+                       return _updateCommand;
                }
 
-               #endregion // Properties
+               private DbParameter CreateParameter (DbCommand _dbCommand, DataRow schemaRow, bool whereClause)
+               {
+                       string sourceColumn = (string) schemaRow ["BaseColumnName"];
+                       DbParameter parameter = _dbCommand.CreateParameter ();
+                       if (whereClause)
+                               parameter.ParameterName = GetParameterName ("Original_" + sourceColumn);
+                       else
+                               parameter.ParameterName = GetParameterName (sourceColumn);
+                       parameter.SourceColumn = sourceColumn;
+                       //parameter.Size = (int) schemaRow ["ColumnSize"];
+                       _dbCommand.Parameters.Add (parameter);
+                       return parameter;
+               }
 
-               #region Methods
+               private DbParameter CreateParameter (DbCommand _dbCommand, int paramIndex, DataRow schemaRow)
+               {
+                       string sourceColumn = (string) schemaRow ["BaseColumnName"];
+                       DbParameter parameter = _dbCommand.CreateParameter ();
+                       parameter.ParameterName = GetParameterName (paramIndex);
+                       parameter.SourceColumn = sourceColumn;
+                       //parameter.Size = (int) schemaRow ["ColumnSize"];
+                       _dbCommand.Parameters.Add (parameter);
+                       return parameter;
+               }
+               
+               [DefaultValue (CatalogLocation.Start)]
+               public virtual CatalogLocation CatalogLocation {
+                       get { return _catalogLocation; }
+                       set {
+                               CheckEnumValue (typeof (CatalogLocation),
+                                       (int) value);
+                               _catalogLocation = value;
+                       }
+               }
 
-               protected abstract void ApplyParameterInfo (IDbDataParameter p, DataRow row);
+               [DefaultValue (".")]
+               public virtual string CatalogSeparator {
+                       get {
+                               if (_catalogSeparator == null || _catalogSeparator.Length == 0)
+                                       return SEPARATOR_DEFAULT;
+                               return _catalogSeparator;
+                       }
+                       set { _catalogSeparator = value; }
+               }
 
-               [MonoTODO]
-               protected virtual void BuildCache (bool closeConnection, DataRow dataRow)
-               {
-                       throw new NotImplementedException ();
+               [DefaultValue (ConflictOption.CompareAllSearchableValues)]
+               public virtual ConflictOption ConflictOption {
+                       get { return _conflictOption; }
+                       set {
+                               CheckEnumValue (typeof (ConflictOption),
+                                       (int) value);
+                               _conflictOption = value;
+                       }
                }
 
-               [MonoTODO]
-               protected override void Dispose (bool disposing)
-               {
-                       throw new NotImplementedException ();
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               [Browsable (false)]
+               public DbDataAdapter DataAdapter {
+                       get { return _dbDataAdapter; }
+                       set {  if (value != null) 
+                               SetRowUpdatingHandler (value);
+                               _dbDataAdapter = value; 
+                       }
                }
 
-               [MonoTODO]
-               public static Delegate FindBUilder (MulticastDelegate mcd)
-               {
-                       throw new NotImplementedException ();
+               [DefaultValue ("")]
+               public virtual string QuotePrefix {
+                       get {
+                               if (_quotePrefix == null)
+                                       return string.Empty;
+                               return _quotePrefix;
+                       }
+                       set {
+                               if (IsCommandGenerated)
+                                       throw new InvalidOperationException (
+                                               "QuotePrefix cannot be set after " +
+                                               "an Insert, Update or Delete command " +
+                                               "has been generated.");
+                               _quotePrefix = value;
+                       }
+               }
+
+               [DefaultValue ("")]
+               public virtual string QuoteSuffix {
+                       get {
+                               if (_quoteSuffix == null)
+                                       return string.Empty;
+                               return _quoteSuffix;
+                       }
+                       set {
+                               if (IsCommandGenerated)
+                                       throw new InvalidOperationException (
+                                               "QuoteSuffix cannot be set after " +
+                                               "an Insert, Update or Delete command " +
+                                               "has been generated.");
+                               _quoteSuffix = value;
+                       }
+               }
+
+               [DefaultValue (".")]
+               public virtual string SchemaSeparator {
+                       get {
+                               if (_schemaSeparator == null || _schemaSeparator.Length == 0)
+                                       return SEPARATOR_DEFAULT;
+                               return _schemaSeparator;
+                       }
+                       set { _schemaSeparator = value; }
+               }
+
+               [DefaultValue (false)]
+               public bool SetAllValues {
+                       get { return _setAllValues; }
+                       set { _setAllValues = value; }
+               }
+
+               private DbCommand SourceCommand {
+                       get {
+                               if (_dbDataAdapter != null)
+                                       return _dbDataAdapter.SelectCommand;
+                               return null;
+                       }
                }
 
-               [MonoTODO]
-               public virtual string FormatLiteral (DbConnection connection, string dataTypeName, object value)
+               protected abstract void ApplyParameterInfo (DbParameter parameter, 
+                                                           DataRow row, 
+                                                           StatementType statementType, 
+                                                           bool whereClause);
+
+               protected override void Dispose (bool disposing)
                {
-                       throw new NotImplementedException ();
+                       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;
+                       }
                }
 
-               [MonoTODO]
                public DbCommand GetDeleteCommand ()
                {
-                       throw new NotImplementedException ();
+                       return GetDeleteCommand (false);
                }
 
-               [MonoTODO]
-               public DbCommand GetDeleteCommand (DataRow dataRow)
+               public DbCommand GetDeleteCommand (bool option)
                {
-                       throw new NotImplementedException ();
+                       BuildCache (true);
+                       if (_deleteCommand == null || option)
+                               return CreateDeleteCommand (option);
+                       return _deleteCommand;
                }
 
-               [MonoTODO]
                public DbCommand GetInsertCommand ()
                {
-                       throw new NotImplementedException ();
+                       return GetInsertCommand (false, null);
                }
 
-               [MonoTODO]
-               public DbCommand GetInsertCommand (DataRow dataRow)
+               public DbCommand GetInsertCommand (bool option)
                {
-                       throw new NotImplementedException ();
+                       return GetInsertCommand (option, null);
                }
 
-               protected abstract string GetParameterName (int parameterOrdinal);
-               protected abstract string GetParameterPlaceholder (int parameterOrdinal);
-
-               [MonoTODO]
-               protected DbCommand GetSelectCommand ()
+               internal DbCommand GetInsertCommand (bool option, DataRow row)
                {
-                       throw new NotImplementedException ();
+                       BuildCache (true);
+                       if (_insertCommand == null || option)
+                               return CreateInsertCommand (option, row);
+                       return _insertCommand;
                }
 
-               [MonoTODO]
                public DbCommand GetUpdateCommand ()
                {
-                       throw new NotImplementedException ();
+                       return GetUpdateCommand (false);
                }
 
-               [MonoTODO]
-               public DbCommand GetUpdateCommand (DataRow dataRow)
+               public DbCommand GetUpdateCommand (bool option)
                {
-                       throw new NotImplementedException ();
+                       BuildCache (true);
+                       if (_updateCommand == null || option)
+                               return CreateUpdateCommand (option);
+                       return _updateCommand;
                }
 
-               [MonoTODO]
                protected virtual DbCommand InitializeCommand (DbCommand command)
                {
-                       throw new NotImplementedException ();
-               }
+                       if (_dbCommand == null) {
+                               _dbCommand = SourceCommand;
+                       } else {
+                               _dbCommand.CommandTimeout = 30;
+                               _dbCommand.Transaction = null;
+                               _dbCommand.CommandType = CommandType.Text;
+                               _dbCommand.UpdatedRowSource = UpdateRowSource.None;
+                       }
+                       return _dbCommand;
 
-               [MonoTODO]
-               protected internal static string[] ParseProcedureName (string procedure)
-               {
-                       throw new NotImplementedException ();
                }
 
-               [MonoTODO]
                public virtual string QuoteIdentifier (string unquotedIdentifier)
                {
-                       throw new NotImplementedException ();
+                       throw new NotSupportedException ();
                }
 
-               [MonoTODO]
-               public virtual void RefreshSchema ()
+               public virtual string UnquoteIdentifier (string quotedIdentifier)
                {
-                       throw new NotImplementedException ();
+                       if (quotedIdentifier == null) {
+                               throw new ArgumentNullException ("Quoted identifier parameter cannot be null");
+                       }
+                       string unquotedIdentifier = quotedIdentifier.Trim ();
+                       if (unquotedIdentifier.StartsWith (this.QuotePrefix)) {
+                               unquotedIdentifier = unquotedIdentifier.Remove (0, 1);
+                       }
+                       if (unquotedIdentifier.EndsWith (this.QuoteSuffix)) {
+                               unquotedIdentifier = unquotedIdentifier.Remove (unquotedIdentifier.Length - 1, 1);
+                       }
+                       return unquotedIdentifier;
                }
 
-               [MonoTODO]
-               public virtual void ResolveObjectName (DbConnection connection, string objectType, string[] identifierParts)
+               public virtual void RefreshSchema ()
                {
-                       throw new NotImplementedException ();
+                       _tableName = String.Empty;
+                       _dbSchemaTable = null;
+                       _deleteCommand = null;
+                       _updateCommand = null;
+                       _insertCommand = null;
                }
 
-               [MonoTODO]
-               protected void RowUpdatingHandler (object sender, RowUpdatingEventArgs rowUpdatingEvent)
+               protected void RowUpdatingHandler (RowUpdatingEventArgs args)
                {
-                       throw new NotImplementedException ();
+                       if (args.Command != null)
+                               return;
+                       try {
+                               switch (args.StatementType) {
+                               case StatementType.Insert:
+                                       args.Command = GetInsertCommand (false, args.Row);
+                                       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;
+                       }
                }
 
+               protected abstract string GetParameterName (int parameterOrdinal);
+               protected abstract string GetParameterName (String parameterName);
+               protected abstract string GetParameterPlaceholder (int parameterOrdinal);
+
                protected abstract void SetRowUpdatingHandler (DbDataAdapter adapter);
 
-               [MonoTODO]
-               public virtual object UnformatLiteral (DbConnection connection, string dataTypeName, string literalValue)
+               protected virtual DataTable GetSchemaTable (DbCommand cmd)
                {
-                       throw new NotImplementedException ();
+                       using (DbDataReader rdr = cmd.ExecuteReader ())
+                               return rdr.GetSchemaTable ();
                }
 
-               [MonoTODO]
-               public virtual string UnquoteIdentifier (string quotedIdentifier)
+               static void CheckEnumValue (Type type, int value)
                {
-                       throw new NotImplementedException ();
+                       if (Enum.IsDefined (type, value))
+                               return;
+
+                       string typename = type.Name;
+                       string msg = string.Format (CultureInfo.CurrentCulture,
+                               "Value {0} is not valid for {1}.", value,
+                               typename);
+                       throw new ArgumentOutOfRangeException (typename, msg);
                }
-
-               #endregion // Methods
        }
 }