X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Data%2FSystem.Data.SqlClient%2FSqlDataAdapter.cs;h=41564093e5c00ad2a7cf99df901c6b7bd189444f;hb=185609a22951a72e5cdaefe712c2183a0c8ded04;hp=a8bc4aef436ec07f0100ddd642a6843e8abee108;hpb=2d23bfcbce7a3f7e54dcd5911adb88b244baca35;p=mono.git diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlDataAdapter.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlDataAdapter.cs index a8bc4aef436..41564093e5c 100644 --- a/mcs/class/System.Data/System.Data.SqlClient/SqlDataAdapter.cs +++ b/mcs/class/System.Data/System.Data.SqlClient/SqlDataAdapter.cs @@ -33,6 +33,7 @@ // using System; +using System.Collections; using System.ComponentModel; using System.Data; using System.Data.Common; @@ -42,26 +43,304 @@ namespace System.Data.SqlClient { [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.SqlDataAdapterDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")] [ToolboxItemAttribute ("Microsoft.VSDesigner.Data.VS.SqlDataAdapterToolboxItem, "+ Consts.AssemblyMicrosoft_VSDesigner)] -#if NET_2_0 public sealed class SqlDataAdapter : DbDataAdapter, IDbDataAdapter, IDataAdapter, ICloneable -#else - public sealed class SqlDataAdapter : DbDataAdapter, IDbDataAdapter -#endif { + +#region Copy from old DataColumn + internal static bool CanAutoIncrement (Type type) + { + switch (Type.GetTypeCode (type)) { + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.Decimal: + return true; + } + + return false; + } +#endregion + +#region Copy from old DataAdapter + + private const string DefaultSourceColumnName = "Column"; + + internal FillErrorEventArgs CreateFillErrorEvent (DataTable dataTable, object[] values, Exception e) + { + FillErrorEventArgs args = new FillErrorEventArgs (dataTable, values); + args.Errors = e; + args.Continue = false; + return args; + } + + internal void OnFillErrorInternal (FillErrorEventArgs value) + { + OnFillError (value); + } + + // this method builds the schema for a given datatable. it returns a int array with + // "array[ordinal of datatable column] == index of source column in data reader". + // each column in the datatable has a mapping to a specific column in the datareader, + // the int array represents this match. + internal int[] BuildSchema (IDataReader reader, DataTable table, SchemaType schemaType) + { + return BuildSchema (reader, table, schemaType, MissingSchemaAction, + MissingMappingAction, TableMappings); + } + + /// + /// Creates or Modifies the schema of the given DataTable based on the schema of + /// the reader and the arguments passed. + /// + internal static int[] BuildSchema (IDataReader reader, DataTable table, + SchemaType schemaType, + MissingSchemaAction missingSchAction, + MissingMappingAction missingMapAction, + DataTableMappingCollection dtMapping + ) + { + int readerIndex = 0; + // FIXME : this fails if query has fewer columns than a table + int[] mapping = new int[table.Columns.Count]; // mapping the reader indexes to the datatable indexes + + for(int i=0; i < mapping.Length; i++) { + mapping[i] = -1; + } + + ArrayList primaryKey = new ArrayList (); + ArrayList sourceColumns = new ArrayList (); + bool createPrimaryKey = true; + + DataTable schemaTable = reader.GetSchemaTable (); + + DataColumn ColumnNameCol = schemaTable.Columns["ColumnName"]; + DataColumn DataTypeCol = schemaTable.Columns["DataType"]; + DataColumn IsAutoIncrementCol = schemaTable.Columns["IsAutoIncrement"]; + DataColumn AllowDBNullCol = schemaTable.Columns["AllowDBNull"]; + DataColumn IsReadOnlyCol = schemaTable.Columns["IsReadOnly"]; + DataColumn IsKeyCol = schemaTable.Columns["IsKey"]; + DataColumn IsUniqueCol = schemaTable.Columns["IsUnique"]; + DataColumn ColumnSizeCol = schemaTable.Columns["ColumnSize"]; + + foreach (DataRow schemaRow in schemaTable.Rows) { + // generate a unique column name in the source table. + string sourceColumnName; + string realSourceColumnName ; + if (ColumnNameCol == null || schemaRow.IsNull(ColumnNameCol) || + (string)schemaRow [ColumnNameCol] == String.Empty) { + sourceColumnName = DefaultSourceColumnName; + realSourceColumnName = DefaultSourceColumnName + "1"; + } else { + sourceColumnName = (string) schemaRow [ColumnNameCol]; + realSourceColumnName = sourceColumnName; + } + + for (int i = 1; sourceColumns.Contains (realSourceColumnName); i += 1) + realSourceColumnName = String.Format ("{0}{1}", sourceColumnName, i); + sourceColumns.Add(realSourceColumnName); + + // generate DataSetColumnName from DataTableMapping, if any + DataTableMapping tableMapping = null; + + //FIXME : The sourcetable name shud get passed as a parameter.. + int index = dtMapping.IndexOfDataSetTable (table.TableName); + string srcTable = (index != -1 ? dtMapping[index].SourceTable : table.TableName); + tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (dtMapping, ADP.IsEmpty (srcTable) ? " " : srcTable, table.TableName, missingMapAction); + if (tableMapping != null) { + table.TableName = tableMapping.DataSetTable; + // check to see if the column mapping exists + DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction(tableMapping.ColumnMappings, realSourceColumnName, missingMapAction); + if (columnMapping != null) { + Type columnType = schemaRow[DataTypeCol] as Type; + DataColumn col = columnType != null ? columnMapping.GetDataColumnBySchemaAction( + table , + columnType, + missingSchAction) : null; + + if (col != null) { + // if the column is not in the table - add it. + if (table.Columns.IndexOf(col) == -1) { + if (missingSchAction == MissingSchemaAction.Add + || missingSchAction == MissingSchemaAction.AddWithKey) + table.Columns.Add(col); + + int[] tmp = new int[mapping.Length + 1]; + Array.Copy(mapping,0,tmp,0,col.Ordinal); + Array.Copy(mapping,col.Ordinal,tmp,col.Ordinal + 1,mapping.Length - col.Ordinal); + mapping = tmp; + } + + if (missingSchAction == MissingSchemaAction.AddWithKey) { + object value = (AllowDBNullCol != null) ? schemaRow[AllowDBNullCol] : null; + bool allowDBNull = value is bool ? (bool)value : true; + + value = (IsKeyCol != null) ? schemaRow[IsKeyCol] : null; + bool isKey = value is bool ? (bool)value : false; + + value = (IsAutoIncrementCol != null) ? schemaRow[IsAutoIncrementCol] : null; + bool isAutoIncrement = value is bool ? (bool)value : false; + + value = (IsReadOnlyCol != null) ? schemaRow[IsReadOnlyCol] : null; + bool isReadOnly = value is bool ? (bool)value : false; + + value = (IsUniqueCol != null) ? schemaRow[IsUniqueCol] : null; + bool isUnique = value is bool ? (bool)value : false; + + col.AllowDBNull = allowDBNull; + // fill woth key info + if (isAutoIncrement && CanAutoIncrement(columnType)) { + col.AutoIncrement = true; + if (!allowDBNull) + col.AllowDBNull = false; + } + + if (columnType == DbTypes.TypeOfString) { + col.MaxLength = (ColumnSizeCol != null) ? (int)schemaRow[ColumnSizeCol] : 0; + } + + if (isReadOnly) + col.ReadOnly = true; + + if (!allowDBNull && (!isReadOnly || isKey)) + col.AllowDBNull = false; + if (isUnique && !isKey && !columnType.IsArray) { + col.Unique = true; + if (!allowDBNull) + col.AllowDBNull = false; + } + + // This might not be set by all DataProviders + bool isHidden = false; + if (schemaTable.Columns.Contains ("IsHidden")) { + value = schemaRow["IsHidden"]; + isHidden = ((value is bool) ? (bool)value : false); + } + + if (isKey && !isHidden) { + primaryKey.Add (col); + if (allowDBNull) + createPrimaryKey = false; + } + } + // add the ordinal of the column as a key and the index of the column in the datareader as a value. + mapping[col.Ordinal] = readerIndex++; + } + } + } + } + if (primaryKey.Count > 0) { + DataColumn[] colKey = (DataColumn[])(primaryKey.ToArray(typeof (DataColumn))); + if (createPrimaryKey) + table.PrimaryKey = colKey; + else { + UniqueConstraint uConstraint = new UniqueConstraint(colKey); + for (int i = 0; i < table.Constraints.Count; i++) { + if (table.Constraints[i].Equals(uConstraint)) { + uConstraint = null; + break; + } + } + + if (uConstraint != null) + table.Constraints.Add(uConstraint); + } + } + return mapping; + } + + internal int FillInternal (DataTable dataTable, IDataReader dataReader) + { + if (dataReader.FieldCount == 0) { + dataReader.Close (); + return 0; + } + + int count = 0; + + try { + string tableName = SetupSchema (SchemaType.Mapped, dataTable.TableName); + if (tableName != null) { + dataTable.TableName = tableName; + FillTable (dataTable, dataReader, 0, 0, ref count); + } + } finally { + dataReader.Close (); + } + + return count; + } + + internal bool FillTable (DataTable dataTable, IDataReader dataReader, int startRecord, int maxRecords, ref int counter) + { + if (dataReader.FieldCount == 0) + return false; + + int counterStart = counter; + + int[] mapping = BuildSchema (dataReader, dataTable, SchemaType.Mapped); + + int [] sortedMapping = new int [mapping.Length]; + int length = sortedMapping.Length; + for (int i = 0; i < sortedMapping.Length; i++) { + if (mapping [i] >= 0) + sortedMapping [mapping [i]] = i; + else + sortedMapping [--length] = i; + } + + for (int i = 0; i < startRecord; i++) { + dataReader.Read (); + } + + dataTable.BeginLoadData (); + object [] values = new object [length]; + while (dataReader.Read () && (maxRecords == 0 || (counter - counterStart) < maxRecords)) { + try { + for (int iColumn = 0; iColumn < values.Length; iColumn++) + values [iColumn] = dataReader [iColumn]; + dataTable.LoadDataRow (values, AcceptChangesDuringFill); + counter++; + } + catch (Exception e) { + object[] readerArray = new object [dataReader.FieldCount]; + object[] tableArray = new object [mapping.Length]; + // we get the values from the datareader + dataReader.GetValues (readerArray); + // copy from datareader columns to table columns according to given mapping + for (int i = 0; i < mapping.Length; i++) { + if (mapping [i] >= 0) { + tableArray [i] = readerArray [mapping [i]]; + } + } + FillErrorEventArgs args = CreateFillErrorEvent (dataTable, tableArray, e); + OnFillErrorInternal (args); + + // if args.Continue is not set to true or if a handler is not set, rethrow the error.. + if(!args.Continue) + throw e; + } + } + dataTable.EndLoadData (); + return true; + } + + internal string SetupSchema (SchemaType schemaType, string sourceTableName) + { + DataTableMapping tableMapping = null; + + if (schemaType == SchemaType.Mapped) { + tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, sourceTableName, sourceTableName, MissingMappingAction); + if (tableMapping != null) + return tableMapping.DataSetTable; + return null; + } else + return sourceTableName; + } +#endregion + #region Fields -#if !NET_2_0 - bool disposed; -#endif -#if ONLY_1_0 || ONLY_1_1 - SqlCommand _selectCommand; - SqlCommand _insertCommand; - SqlCommand _updateCommand; - SqlCommand _deleteCommand; -#endif -#if NET_2_0 int updateBatchSize; -#endif #endregion #region Constructors @@ -73,9 +352,7 @@ namespace System.Data.SqlClient { public SqlDataAdapter (SqlCommand selectCommand) { SelectCommand = selectCommand; -#if NET_2_0 UpdateBatchSize = 1; -#endif } public SqlDataAdapter (string selectCommandText, SqlConnection selectConnection) @@ -92,93 +369,21 @@ namespace System.Data.SqlClient { #region Properties -#if !NET_2_0 - [DataSysDescription ("Used during Update for deleted rows in DataSet.")] -#endif [DefaultValue (null)] [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DBCommandEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )] - public new SqlCommand DeleteCommand { - get { -#if NET_2_0 - return (SqlCommand)base.DeleteCommand; -#else - return _deleteCommand; -#endif - } - set { -#if NET_2_0 - base.DeleteCommand = value; -#else - _deleteCommand = value; -#endif - } - } + public new SqlCommand DeleteCommand { get; set; } -#if !NET_2_0 - [DataSysDescription ("Used during Update for new rows in DataSet.")] -#endif [DefaultValue (null)] [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DBCommandEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )] - public new SqlCommand InsertCommand { - get { -#if NET_2_0 - return (SqlCommand)base.InsertCommand; -#else - return _insertCommand; -#endif - } - set { -#if NET_2_0 - base.InsertCommand = value; -#else - _insertCommand = value; -#endif - } - } + public new SqlCommand InsertCommand { get; set; } -#if !NET_2_0 - [DataSysDescription ("Used during Fill/FillSchema.")] -#endif [DefaultValue (null)] [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DBCommandEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )] - public new SqlCommand SelectCommand { - get { -#if NET_2_0 - return (SqlCommand)base.SelectCommand; -#else - return _selectCommand; -#endif - } - set { -#if NET_2_0 - base.SelectCommand = value; -#else - _selectCommand = value; -#endif - } - } + public new SqlCommand SelectCommand { get; set; } -#if !NET_2_0 - [DataSysDescription ("Used during Update for modified rows in DataSet.")] -#endif [DefaultValue (null)] [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DBCommandEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )] - public new SqlCommand UpdateCommand { - get { -#if NET_2_0 - return (SqlCommand)base.UpdateCommand; -#else - return _updateCommand; -#endif - } - set { -#if NET_2_0 - base.UpdateCommand = value; -#else - _updateCommand = value; -#endif - } - } + public new SqlCommand UpdateCommand { get; set; } IDbCommand IDbDataAdapter.SelectCommand { get { return SelectCommand; } @@ -199,7 +404,6 @@ namespace System.Data.SqlClient { set { DeleteCommand = (SqlCommand) value; } } -#if NET_2_0 public override int UpdateBatchSize { get { return updateBatchSize; } set { @@ -208,7 +412,6 @@ namespace System.Data.SqlClient { updateBatchSize = value; } } -#endif #endregion // Properties @@ -225,19 +428,6 @@ namespace System.Data.SqlClient { return new SqlRowUpdatingEventArgs (dataRow, command, statementType, tableMapping); } -#if !NET_2_0 - protected override void Dispose (bool disposing) - { - if (!disposed) { - if (disposing) { - // Release managed resources - } - // Release unmanaged resources - disposed = true; - } - base.Dispose (disposing); - } -#endif protected override void OnRowUpdated (RowUpdatedEventArgs value) { @@ -251,15 +441,12 @@ namespace System.Data.SqlClient { RowUpdating (this, (SqlRowUpdatingEventArgs) value); } -#if NET_2_0 [MonoTODO] object ICloneable.Clone() { throw new NotImplementedException (); } -#endif -#if NET_2_0 // All the batch methods, should be implemented, if supported, // by individual providers @@ -298,19 +485,12 @@ namespace System.Data.SqlClient { { throw new NotImplementedException (); } -#endif #endregion // Methods #region Events and Delegates -#if ONLY_1_1 - [DataSysDescription ("Event triggered before every DataRow during Update.")] -#endif public event SqlRowUpdatedEventHandler RowUpdated; -#if ONLY_1_1 - [DataSysDescription ("Event triggered after every DataRow during Update.")] -#endif public event SqlRowUpdatingEventHandler RowUpdating; #endregion // Events and Delegates