| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080 |
- //------------------------------------------------------------------------------
- // <copyright file="SchemaMapping.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">[....]</owner>
- //------------------------------------------------------------------------------
- namespace System.Data.ProviderBase {
- using System.Collections.Generic;
- using System.Data;
- using System.Data.Common;
- using System.Diagnostics;
- using System.Globalization;
- sealed internal class SchemaMapping {
- // DataColumns match in length and name order as the DataReader, no chapters
- private const int MapExactMatch = 0;
- // DataColumns has different length, but correct name order as the DataReader, no chapters
- private const int MapDifferentSize = 1;
- // DataColumns may have different length, but a differant name ordering as the DataReader, no chapters
- private const int MapReorderedValues = 2;
- // DataColumns may have different length, but correct name order as the DataReader, with chapters
- private const int MapChapters = 3;
- // DataColumns may have different length, but a differant name ordering as the DataReader, with chapters
- private const int MapChaptersReordered = 4;
- // map xml string data to DataColumn with DataType=typeof(SqlXml)
- private const int SqlXml = 1;
- // map xml string data to DataColumn with DataType=typeof(XmlDocument)
- private const int XmlDocument = 2;
- private readonly DataSet _dataSet; // the current dataset, may be null if we are only filling a DataTable
- private DataTable _dataTable; // the current DataTable, should never be null
- private readonly DataAdapter _adapter;
- private readonly DataReaderContainer _dataReader;
- private readonly DataTable _schemaTable; // will be null if Fill without schema
- private readonly DataTableMapping _tableMapping;
- // unique (generated) names based from DataReader.GetName(i)
- private readonly string[] _fieldNames;
- private readonly object[] _readerDataValues;
- private object[] _mappedDataValues; // array passed to dataRow.AddUpdate(), if needed
- private int[] _indexMap; // index map that maps dataValues -> _mappedDataValues, if needed
- private bool[] _chapterMap; // which DataReader indexes have chapters
- private int[] _xmlMap; // map which value in _readerDataValues to convert to a Xml datatype, (SqlXml/XmlDocument)
- private int _mappedMode; // modes as described as above
- private int _mappedLength;
- private readonly LoadOption _loadOption;
- internal SchemaMapping(DataAdapter adapter, DataSet dataset, DataTable datatable, DataReaderContainer dataReader, bool keyInfo,
- SchemaType schemaType, string sourceTableName, bool gettingData,
- DataColumn parentChapterColumn, object parentChapterValue) {
- Debug.Assert(null != adapter, "adapter");
- Debug.Assert(null != dataReader, "dataReader");
- Debug.Assert(0 < dataReader.FieldCount, "FieldCount");
- Debug.Assert(null != dataset || null != datatable, "SchemaMapping - null dataSet");
- Debug.Assert(SchemaType.Mapped == schemaType || SchemaType.Source == schemaType, "SetupSchema - invalid schemaType");
- _dataSet = dataset; // setting DataSet implies chapters are supported
- _dataTable = datatable; // setting only DataTable, not DataSet implies chapters are not supported
- _adapter = adapter;
- _dataReader = dataReader;
- if (keyInfo) {
- _schemaTable = dataReader.GetSchemaTable();
- }
- if (adapter.ShouldSerializeFillLoadOption()) {
- _loadOption = adapter.FillLoadOption;
- }
- else if (adapter.AcceptChangesDuringFill) {
- _loadOption = (LoadOption)4; // true
- }
- else {
- _loadOption = (LoadOption)5; //false
- }
- MissingMappingAction mappingAction;
- MissingSchemaAction schemaAction;
- if (SchemaType.Mapped == schemaType) {
- mappingAction = _adapter.MissingMappingAction;
- schemaAction = _adapter.MissingSchemaAction;
- if (!ADP.IsEmpty(sourceTableName)) { // MDAC 66034
- _tableMapping = _adapter.GetTableMappingBySchemaAction(sourceTableName, sourceTableName, mappingAction);
- }
- else if (null != _dataTable) {
- int index = _adapter.IndexOfDataSetTable(_dataTable.TableName);
- if (-1 != index) {
- _tableMapping = _adapter.TableMappings[index];
- }
- else {
- switch (mappingAction) {
- case MissingMappingAction.Passthrough:
- _tableMapping = new DataTableMapping(_dataTable.TableName, _dataTable.TableName);
- break;
- case MissingMappingAction.Ignore:
- _tableMapping = null;
- break;
- case MissingMappingAction.Error:
- throw ADP.MissingTableMappingDestination(_dataTable.TableName);
- default:
- throw ADP.InvalidMissingMappingAction(mappingAction);
- }
- }
- }
- }
- else if (SchemaType.Source == schemaType) {
- mappingAction = System.Data.MissingMappingAction.Passthrough;
- schemaAction = Data.MissingSchemaAction.Add;
- if (!ADP.IsEmpty(sourceTableName)) { // MDAC 66034
- _tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction(null, sourceTableName, sourceTableName, mappingAction);
- }
- else if (null != _dataTable) {
- int index = _adapter.IndexOfDataSetTable(_dataTable.TableName); // MDAC 66034
- if (-1 != index) {
- _tableMapping = _adapter.TableMappings[index];
- }
- else {
- _tableMapping = new DataTableMapping(_dataTable.TableName, _dataTable.TableName);
- }
- }
- }
- else {
- throw ADP.InvalidSchemaType(schemaType);
- }
- if (null != _tableMapping) {
- if (null == _dataTable) {
- _dataTable = _tableMapping.GetDataTableBySchemaAction(_dataSet, schemaAction);
- }
- if (null != _dataTable) {
- _fieldNames = GenerateFieldNames(dataReader);
- if (null == _schemaTable) {
- _readerDataValues = SetupSchemaWithoutKeyInfo(mappingAction, schemaAction, gettingData, parentChapterColumn, parentChapterValue);
- }
- else {
- _readerDataValues = SetupSchemaWithKeyInfo(mappingAction, schemaAction, gettingData, parentChapterColumn, parentChapterValue);
- }
- }
- // else (null == _dataTable) which means ignore (mapped to nothing)
- }
- }
- internal DataReaderContainer DataReader {
- get {
- return _dataReader;
- }
- }
- internal DataTable DataTable {
- get {
- return _dataTable;
- }
- }
- internal object[] DataValues {
- get {
- return _readerDataValues;
- }
- }
- internal void ApplyToDataRow(DataRow dataRow) {
- DataColumnCollection columns = dataRow.Table.Columns;
- _dataReader.GetValues(_readerDataValues);
- object[] mapped = GetMappedValues();
- bool[] readOnly = new bool[mapped.Length];
- for (int i = 0; i < readOnly.Length; ++i) {
- readOnly[i] = columns[i].ReadOnly;
- }
- try {
- try {
- // allow all columns to be written to
- for (int i = 0; i < readOnly.Length; ++i) {
- if (0 == columns[i].Expression.Length) { // WebData 110773
- columns[i].ReadOnly = false;
- }
- }
- for(int i = 0; i < mapped.Length; ++i) {
- if (null != mapped[i]) { // MDAC 72659
- dataRow[i] = mapped[i];
- }
- }
- }
- finally { // ReadOnly
- // reset readonly flag on all columns
- for (int i = 0; i < readOnly.Length; ++i) {
- if (0 == columns[i].Expression.Length) { // WebData 110773
- columns[i].ReadOnly = readOnly[i];
- }
- }
- }
- }
- finally { // FreeDataRowChapters
- if (null != _chapterMap) {
- FreeDataRowChapters();
- }
- }
- }
- private void MappedChapterIndex() { // mode 4
- int length = _mappedLength;
- for (int i = 0; i < length; i++) {
- int k = _indexMap[i];
- if (0 <= k) {
- _mappedDataValues[k] = _readerDataValues[i]; // from reader to dataset
- if (_chapterMap[i]) {
- _mappedDataValues[k] = null; // InvalidCast from DataReader to AutoIncrement DataColumn
- }
- }
- }
- }
- private void MappedChapter() { // mode 3
- int length = _mappedLength;
- for (int i = 0; i < length; i++) {
- _mappedDataValues[i] = _readerDataValues[i]; // from reader to dataset
- if (_chapterMap[i]) {
- _mappedDataValues[i] = null; // InvalidCast from DataReader to AutoIncrement DataColumn
- }
- }
- }
- private void MappedIndex() { // mode 2
- Debug.Assert(_mappedLength == _indexMap.Length, "incorrect precomputed length");
- int length = _mappedLength;
- for (int i = 0; i < length; i++) {
- int k = _indexMap[i];
- if (0 <= k) {
- _mappedDataValues[k] = _readerDataValues[i]; // from reader to dataset
- }
- }
- }
- private void MappedValues() { // mode 1
- Debug.Assert(_mappedLength == Math.Min(_readerDataValues.Length, _mappedDataValues.Length), "incorrect precomputed length");
- int length = _mappedLength;
- for (int i = 0; i < length; ++i) {
- _mappedDataValues[i] = _readerDataValues[i]; // from reader to dataset
- };
- }
- private object[] GetMappedValues() { // mode 0
- if (null != _xmlMap) {
- for(int i = 0; i < _xmlMap.Length; ++i) {
- if (0 != _xmlMap[i]) {
- // get the string/SqlString xml value
- string xml = _readerDataValues[i] as string;
- if ((null == xml) && (_readerDataValues[i] is System.Data.SqlTypes.SqlString)) {
- System.Data.SqlTypes.SqlString x = (System.Data.SqlTypes.SqlString)_readerDataValues[i];
- if (!x.IsNull) {
- xml = x.Value;
- }
- else {
- switch(_xmlMap[i]) {
- case SqlXml:
- // map strongly typed SqlString.Null to SqlXml.Null
- _readerDataValues[i] = System.Data.SqlTypes.SqlXml.Null;
- break;
- default:
- _readerDataValues[i] = DBNull.Value;
- break;
- }
- }
- }
- if (null != xml) {
- switch(_xmlMap[i]) {
- case SqlXml: // turn string into a SqlXml value for DataColumn
- System.Xml.XmlReaderSettings settings = new System.Xml.XmlReaderSettings();
- settings.ConformanceLevel = System.Xml.ConformanceLevel.Fragment;
- System.Xml.XmlReader reader = System.Xml.XmlReader.Create(new System.IO.StringReader(xml), settings, (string)null);
- _readerDataValues[i] = new System.Data.SqlTypes.SqlXml(reader);
- break;
- case XmlDocument: // turn string into XmlDocument value for DataColumn
- System.Xml.XmlDocument document = new System.Xml.XmlDocument();
- document.LoadXml(xml);
- _readerDataValues[i] = document;
- break;
- }
- // default: let value fallthrough to DataSet which may fail with ArgumentException
- }
- }
- }
- }
- switch(_mappedMode) {
- default:
- case MapExactMatch:
- Debug.Assert(0 == _mappedMode, "incorrect mappedMode");
- Debug.Assert((null == _chapterMap) && (null == _indexMap) && (null == _mappedDataValues), "incorrect MappedValues");
- return _readerDataValues; // from reader to dataset
- case MapDifferentSize:
- Debug.Assert((null == _chapterMap) && (null == _indexMap) && (null != _mappedDataValues), "incorrect MappedValues");
- MappedValues();
- break;
- case MapReorderedValues:
- Debug.Assert((null == _chapterMap) && (null != _indexMap) && (null != _mappedDataValues), "incorrect MappedValues");
- MappedIndex();
- break;
- case MapChapters:
- Debug.Assert((null != _chapterMap) && (null == _indexMap) && (null != _mappedDataValues), "incorrect MappedValues");
- MappedChapter();
- break;
- case MapChaptersReordered:
- Debug.Assert((null != _chapterMap) && (null != _indexMap) && (null != _mappedDataValues), "incorrect MappedValues");
- MappedChapterIndex();
- break;
- }
- return _mappedDataValues;
- }
- internal void LoadDataRowWithClear() {
- // for FillErrorEvent to ensure no values leftover from previous row
- for (int i = 0; i < _readerDataValues.Length; ++i) {
- _readerDataValues[i] = null;
- }
- LoadDataRow();
- }
- internal void LoadDataRow() {
- try {
- _dataReader.GetValues(_readerDataValues);
- object[] mapped = GetMappedValues();
- DataRow dataRow;
- switch(_loadOption) {
- case LoadOption.OverwriteChanges:
- case LoadOption.PreserveChanges:
- case LoadOption.Upsert:
- dataRow = _dataTable.LoadDataRow(mapped, _loadOption);
- break;
- case (LoadOption)4: // true
- dataRow = _dataTable.LoadDataRow(mapped, true);
- break;
- case (LoadOption)5: // false
- dataRow = _dataTable.LoadDataRow(mapped, false);
- break;
- default:
- Debug.Assert(false, "unexpected LoadOption");
- throw ADP.InvalidLoadOption(_loadOption);
- }
- if ((null != _chapterMap) && (null != _dataSet)) {
- LoadDataRowChapters(dataRow); // MDAC 70772
- }
- }
- finally {
- if (null != _chapterMap) {
- FreeDataRowChapters(); // MDAC 71900
- }
- }
- }
- private void FreeDataRowChapters() {
- for(int i = 0; i < _chapterMap.Length; ++i) {
- if (_chapterMap[i]) {
- IDisposable disposable = (_readerDataValues[i] as IDisposable);
- if (null != disposable) {
- _readerDataValues[i] = null;
- disposable.Dispose();
- }
- }
- }
- }
- internal int LoadDataRowChapters(DataRow dataRow) {
- int datarowadded = 0;
- int rowLength = _chapterMap.Length;
- for(int i = 0; i < rowLength; ++i) {
- if (_chapterMap[i]) {
- object readerValue = _readerDataValues[i];
- if ((null != readerValue) && !Convert.IsDBNull(readerValue)) { // MDAC 70441
- _readerDataValues[i] = null;
- using (IDataReader nestedReader = (IDataReader) readerValue) {
- if (!nestedReader.IsClosed) {
- Debug.Assert(null != _dataSet, "if chapters, then Fill(DataSet,...) not Fill(DataTable,...)");
- object parentChapterValue;
- DataColumn parentChapterColumn;
- if (null == _indexMap) {
- parentChapterColumn = _dataTable.Columns[i];
- parentChapterValue = dataRow[parentChapterColumn];
- }
- else {
- parentChapterColumn = _dataTable.Columns[_indexMap[i]];
- parentChapterValue = dataRow[parentChapterColumn];
- }
- // correct on Fill, not FillFromReader
- string chapterTableName = _tableMapping.SourceTable + _fieldNames[i]; // MDAC 70908
- DataReaderContainer readerHandler = DataReaderContainer.Create(nestedReader, _dataReader.ReturnProviderSpecificTypes);
- datarowadded += _adapter.FillFromReader(_dataSet, null, chapterTableName, readerHandler, 0, 0, parentChapterColumn, parentChapterValue);
- }
- }
- }
- }
- }
- return datarowadded;
- }
- private int[] CreateIndexMap(int count, int index) {
- int[] values = new int[count];
- for (int i = 0; i < index; ++i) {
- values[i] = i;
- }
- return values;
- }
- private static string[] GenerateFieldNames(DataReaderContainer dataReader) {
- string[] fieldNames = new string[dataReader.FieldCount];
- for(int i = 0; i < fieldNames.Length; ++i) {
- fieldNames[i] = dataReader.GetName(i);
- }
- ADP.BuildSchemaTableInfoTableNames(fieldNames);
- return fieldNames;
- }
- private DataColumn[] ResizeColumnArray(DataColumn[] rgcol, int len) {
- Debug.Assert(rgcol != null, "invalid call to ResizeArray");
- Debug.Assert(len <= rgcol.Length, "invalid len passed to ResizeArray");
- DataColumn[] tmp = new DataColumn[len];
- Array.Copy(rgcol, tmp, len);
- return tmp;
- }
- private void AddItemToAllowRollback(ref List<object> items, object value) {
- if (null == items) {
- items = new List<object>();
- }
- items.Add(value);
- }
- private void RollbackAddedItems(List<object> items) {
- if (null != items) {
- for (int i = items.Count-1; 0 <= i; --i) {
- // remove columns that were added now that we are failing
- if (null != items[i]) {
- DataColumn column = (items[i] as DataColumn);
- if (null != column) {
- if (null != column.Table) {
- column.Table.Columns.Remove(column);
- }
- }
- else {
- DataTable table = (items[i] as DataTable);
- if (null != table) {
- if (null != table.DataSet) {
- table.DataSet.Tables.Remove(table);
- }
- }
- }
- }
- }
- }
- }
- private object[] SetupSchemaWithoutKeyInfo(MissingMappingAction mappingAction, MissingSchemaAction schemaAction, bool gettingData, DataColumn parentChapterColumn, object chapterValue) {
- int[] columnIndexMap = null;
- bool[] chapterIndexMap = null;
- int mappingCount = 0;
- int count = _dataReader.FieldCount;
- object[] dataValues = null;
- List<object> addedItems = null;
- try {
- DataColumnCollection columnCollection = _dataTable.Columns;
- columnCollection.EnsureAdditionalCapacity(count + (chapterValue != null ? 1 : 0));
- // We can always just create column if there are no existing column or column mappings, and the mapping action is passthrough
- bool alwaysCreateColumns = ((_dataTable.Columns.Count == 0) && ((_tableMapping.ColumnMappings == null) || (_tableMapping.ColumnMappings.Count == 0)) && (mappingAction == MissingMappingAction.Passthrough));
- for (int i = 0; i < count; ++i) {
- bool ischapter = false;
- Type fieldType = _dataReader.GetFieldType(i);
- if (null == fieldType) {
- throw ADP.MissingDataReaderFieldType(i);
- }
- // if IDataReader, hierarchy exists and we will use an Int32,AutoIncrementColumn in this table
- if (typeof(IDataReader).IsAssignableFrom(fieldType)) {
- if (null == chapterIndexMap) {
- chapterIndexMap = new bool[count];
- }
- chapterIndexMap[i] = ischapter = true;
- fieldType = typeof(Int32);
- }
- else if (typeof(System.Data.SqlTypes.SqlXml).IsAssignableFrom(fieldType)) {
- if (null == _xmlMap) { // map to DataColumn with DataType=typeof(SqlXml)
- _xmlMap = new int[count];
- }
- _xmlMap[i] = SqlXml; // track its xml data
- }
- else if (typeof(System.Xml.XmlReader).IsAssignableFrom(fieldType)) {
- fieldType = typeof(String); // map to DataColumn with DataType=typeof(string)
- if (null == _xmlMap) {
- _xmlMap = new int[count];
- }
- _xmlMap[i] = XmlDocument; // track its xml data
- }
- DataColumn dataColumn;
- if (alwaysCreateColumns) {
- dataColumn = DataColumnMapping.CreateDataColumnBySchemaAction(_fieldNames[i], _fieldNames[i], _dataTable, fieldType, schemaAction);
- }
- else {
- dataColumn = _tableMapping.GetDataColumn(_fieldNames[i], fieldType, _dataTable, mappingAction, schemaAction);
- }
- if (null == dataColumn) {
- if (null == columnIndexMap) {
- columnIndexMap = CreateIndexMap(count, i);
- }
- columnIndexMap[i] = -1;
- continue; // null means ignore (mapped to nothing)
- }
- else if ((null != _xmlMap) && (0 != _xmlMap[i])) {
- if (typeof(System.Data.SqlTypes.SqlXml) == dataColumn.DataType) {
- _xmlMap[i] = SqlXml;
- }
- else if (typeof(System.Xml.XmlDocument) == dataColumn.DataType) {
- _xmlMap[i] = XmlDocument;
- }
- else {
- _xmlMap[i] = 0; // datacolumn is not a specific Xml dataType, i.e. string
- int total = 0;
- for(int x = 0; x < _xmlMap.Length; ++x) {
- total += _xmlMap[x];
- }
- if (0 == total) { // not mapping to a specific Xml datatype, get rid of the map
- _xmlMap = null;
- }
- }
- }
- if (null == dataColumn.Table) {
- if (ischapter) {
- dataColumn.AllowDBNull = false;
- dataColumn.AutoIncrement = true;
- dataColumn.ReadOnly = true;
- }
- AddItemToAllowRollback(ref addedItems, dataColumn);
- columnCollection.Add(dataColumn);
- }
- else if (ischapter && !dataColumn.AutoIncrement) {
- throw ADP.FillChapterAutoIncrement();
- }
- if (null != columnIndexMap) {
- columnIndexMap[i] = dataColumn.Ordinal;
- }
- else if (i != dataColumn.Ordinal) {
- columnIndexMap = CreateIndexMap(count, i);
- columnIndexMap[i] = dataColumn.Ordinal;
- }
- // else i == dataColumn.Ordinal and columnIndexMap can be optimized out
- mappingCount++;
- }
- bool addDataRelation = false;
- DataColumn chapterColumn = null;
- if (null != chapterValue) { // add the extra column in the child table
- Type fieldType = chapterValue.GetType();
- chapterColumn = _tableMapping.GetDataColumn(_tableMapping.SourceTable, fieldType, _dataTable, mappingAction, schemaAction);
- if (null != chapterColumn) {
- if (null == chapterColumn.Table) {
- AddItemToAllowRollback(ref addedItems, chapterColumn);
- columnCollection.Add(chapterColumn);
- addDataRelation = (null != parentChapterColumn);
- }
- mappingCount++;
- }
- }
- if (0 < mappingCount) {
- if ((null != _dataSet) && (null == _dataTable.DataSet)) {
- // Allowed to throw exception if DataTable is from wrong DataSet
- AddItemToAllowRollback(ref addedItems, _dataTable);
- _dataSet.Tables.Add(_dataTable);
- }
- if (gettingData) {
- if (null == columnCollection) {
- columnCollection = _dataTable.Columns;
- }
- _indexMap = columnIndexMap;
- _chapterMap = chapterIndexMap;
- dataValues = SetupMapping(count, columnCollection, chapterColumn, chapterValue);
- }
- else {
- // debug only, but for retail debug ability
- _mappedMode = -1;
- }
- }
- else {
- _dataTable = null;
- }
- if (addDataRelation) {
- AddRelation(parentChapterColumn, chapterColumn);
- }
- }
- catch (Exception e) {
- //
- if (ADP.IsCatchableOrSecurityExceptionType(e)) {
- RollbackAddedItems(addedItems);
- }
- throw;
- }
- return dataValues;
- }
- private object[] SetupSchemaWithKeyInfo(MissingMappingAction mappingAction, MissingSchemaAction schemaAction, bool gettingData, DataColumn parentChapterColumn, object chapterValue) {
- // must sort rows from schema table by ordinal because Jet is sorted by coumn name
- DbSchemaRow[] schemaRows = DbSchemaRow.GetSortedSchemaRows(_schemaTable, _dataReader.ReturnProviderSpecificTypes); // MDAC 60609
- Debug.Assert(null != schemaRows, "SchemaSetup - null DbSchemaRow[]");
- Debug.Assert(_dataReader.FieldCount <= schemaRows.Length, "unexpected fewer rows in Schema than FieldCount");
- if (0 == schemaRows.Length) {
- _dataTable = null;
- return (object[])null;
- }
- // Everett behavior, always add a primary key if a primary key didn't exist before
- // Whidbey behavior, same as Everett unless using LoadOption then add primary key only if no columns previously existed
- bool addPrimaryKeys = (((0 == _dataTable.PrimaryKey.Length) && ((4 <= (int)_loadOption) || (0 == _dataTable.Rows.Count)))
- || (0 == _dataTable.Columns.Count)); // MDAC 67033
- DataColumn[] keys = null;
- int keyCount = 0;
- bool isPrimary = true; // assume key info (if any) is about a primary key
- string keyBaseTable = null;
- string commonBaseTable = null;
- bool keyFromMultiTable = false;
- bool commonFromMultiTable = false;
- int[] columnIndexMap = null;
- bool[] chapterIndexMap = null;
- int mappingCount = 0;
- object[] dataValues = null;
- List<object> addedItems = null;
- DataColumnCollection columnCollection = _dataTable.Columns;
- try {
- for(int sortedIndex = 0; sortedIndex < schemaRows.Length; ++sortedIndex) {
- DbSchemaRow schemaRow = schemaRows[sortedIndex];
- int unsortedIndex = schemaRow.UnsortedIndex; // MDAC 67050
- bool ischapter = false;
- Type fieldType = schemaRow.DataType;
- if (null == fieldType) {
- fieldType = _dataReader.GetFieldType(sortedIndex);
- }
- if (null == fieldType) {
- throw ADP.MissingDataReaderFieldType(sortedIndex);
- }
- // if IDataReader, hierarchy exists and we will use an Int32,AutoIncrementColumn in this table
- if (typeof(IDataReader).IsAssignableFrom(fieldType)) {
- if (null == chapterIndexMap) {
- chapterIndexMap = new bool[schemaRows.Length];
- }
- chapterIndexMap[unsortedIndex] = ischapter = true;
- fieldType = typeof(Int32);
- }
- else if (typeof(System.Data.SqlTypes.SqlXml).IsAssignableFrom(fieldType)) {
- if (null == _xmlMap) {
- _xmlMap = new int[schemaRows.Length];
- }
- _xmlMap[sortedIndex] = SqlXml;
- }
- else if (typeof(System.Xml.XmlReader).IsAssignableFrom(fieldType)) {
- fieldType = typeof(String);
- if (null == _xmlMap) {
- _xmlMap = new int[schemaRows.Length];
- }
- _xmlMap[sortedIndex] = XmlDocument;
- }
- DataColumn dataColumn = null;
- if (!schemaRow.IsHidden ) {
- dataColumn = _tableMapping.GetDataColumn(_fieldNames[sortedIndex], fieldType, _dataTable, mappingAction, schemaAction);
- }
- string basetable = /*schemaRow.BaseServerName+schemaRow.BaseCatalogName+schemaRow.BaseSchemaName+*/ schemaRow.BaseTableName;
- if (null == dataColumn) {
- if (null == columnIndexMap) {
- columnIndexMap = CreateIndexMap(schemaRows.Length, unsortedIndex);
- }
- columnIndexMap[unsortedIndex] = -1;
- // if the column is not mapped and it is a key, then don't add any key information
- if (schemaRow.IsKey) { // MDAC 90822
- #if DEBUG
- if (AdapterSwitches.DataSchema.TraceVerbose) {
- Debug.WriteLine("SetupSchema: partial primary key detected");
- }
- #endif
- // if the hidden key comes from a different table - don't throw away the primary key
- // example SELECT [T2].[ID], [T2].[ProdID], [T2].[VendorName] FROM [Vendor] AS [T2], [Prod] AS [T1] WHERE (([T1].[ProdID] = [T2].[ProdID]))
- if (keyFromMultiTable || (schemaRow.BaseTableName == keyBaseTable)) { // WebData 100376
- addPrimaryKeys = false; // don't add any future keys now
- keys = null; // get rid of any keys we've seen
- }
- }
- continue; // null means ignore (mapped to nothing)
- }
- else if ((null != _xmlMap) && (0 != _xmlMap[sortedIndex])) {
- if (typeof(System.Data.SqlTypes.SqlXml) == dataColumn.DataType) {
- _xmlMap[sortedIndex] = SqlXml;
- }
- else if (typeof(System.Xml.XmlDocument) == dataColumn.DataType) {
- _xmlMap[sortedIndex] = XmlDocument;
- }
- else {
- _xmlMap[sortedIndex] = 0; // datacolumn is not a specific Xml dataType, i.e. string
- int total = 0;
- for(int x = 0; x < _xmlMap.Length; ++x) {
- total += _xmlMap[x];
- }
- if (0 == total) { // not mapping to a specific Xml datatype, get rid of the map
- _xmlMap = null;
- }
- }
- }
- if (schemaRow.IsKey) {
- if (basetable != keyBaseTable) {
- if (null == keyBaseTable) {
- keyBaseTable = basetable;
- }
- else keyFromMultiTable = true;
- }
- }
- if (ischapter) {
- if (null == dataColumn.Table) {
- dataColumn.AllowDBNull = false;
- dataColumn.AutoIncrement = true;
- dataColumn.ReadOnly = true;
- }
- else if (!dataColumn.AutoIncrement) {
- throw ADP.FillChapterAutoIncrement();
- }
- }
- else {// MDAC 67033
- if (!commonFromMultiTable) {
- if ((basetable != commonBaseTable) && (!ADP.IsEmpty(basetable))) {
- if (null == commonBaseTable) {
- commonBaseTable = basetable;
- }
- else {
- commonFromMultiTable = true;
- }
- }
- }
- if (4 <= (int)_loadOption) {
- if (schemaRow.IsAutoIncrement && DataColumn.IsAutoIncrementType(fieldType)) {
- //
- dataColumn.AutoIncrement = true;
- if (!schemaRow.AllowDBNull) { // MDAC 71060
- dataColumn.AllowDBNull = false;
- }
- }
- // setup maxLength, only for string columns since this is all the DataSet supports
- if (fieldType == typeof(string)) {
- //@devnote: schemaRow.Size is count of characters for string columns, count of bytes otherwise
- dataColumn.MaxLength = schemaRow.Size>0?schemaRow.Size:-1;
- }
- if (schemaRow.IsReadOnly) {
- dataColumn.ReadOnly = true;
- }
- if (!schemaRow.AllowDBNull && (!schemaRow.IsReadOnly || schemaRow.IsKey)) { // MDAC 71060, 72252
- dataColumn.AllowDBNull = false;
- }
- if (schemaRow.IsUnique && !schemaRow.IsKey && !fieldType.IsArray) {
- // note, arrays are not comparable so only mark non-arrays as unique, ie timestamp columns
- // are unique, but not comparable
- dataColumn.Unique = true;
- if (!schemaRow.AllowDBNull) { // MDAC 71060
- dataColumn.AllowDBNull = false;
- }
- }
- }
- else if (null == dataColumn.Table) {
- dataColumn.AutoIncrement = schemaRow.IsAutoIncrement;
- dataColumn.AllowDBNull = schemaRow.AllowDBNull;
- dataColumn.ReadOnly = schemaRow.IsReadOnly;
- dataColumn.Unique = schemaRow.IsUnique;
- if (fieldType == typeof(string) || (fieldType == typeof(SqlTypes.SqlString))) {
- //@devnote: schemaRow.Size is count of characters for string columns, count of bytes otherwise
- dataColumn.MaxLength = schemaRow.Size;
- }
- }
- }
- if (null == dataColumn.Table) {
- if (4 > (int)_loadOption) {
- AddAdditionalProperties(dataColumn, schemaRow.DataRow);
- }
- AddItemToAllowRollback(ref addedItems, dataColumn);
- columnCollection.Add(dataColumn);
- }
- // The server sends us one key per table according to these rules.
- //
- // 1. If the table has a primary key, the server sends us this key.
- // 2. If the table has a primary key and a unique key, it sends us the primary key
- // 3. if the table has no primary key but has a unique key, it sends us the unique key
- //
- // In case 3, we will promote a unique key to a primary key IFF all the columns that compose
- // that key are not nullable since no columns in a primary key can be null. If one or more
- // of the keys is nullable, then we will add a unique constraint.
- //
- if (addPrimaryKeys && schemaRow.IsKey) { // MDAC 67033
- if (keys == null) {
- keys = new DataColumn[schemaRows.Length];
- }
- keys[keyCount++] = dataColumn;
- #if DEBUG
- if (AdapterSwitches.DataSchema.TraceVerbose) {
- Debug.WriteLine("SetupSchema: building list of " + ((isPrimary) ? "PrimaryKey" : "UniqueConstraint"));
- }
- #endif
- // see case 3 above, we do want dataColumn.AllowDBNull not schemaRow.AllowDBNull
- // otherwise adding PrimaryKey will change AllowDBNull to false
- if (isPrimary && dataColumn.AllowDBNull) { // MDAC 72241
- #if DEBUG
- if (AdapterSwitches.DataSchema.TraceVerbose) {
- Debug.WriteLine("SetupSchema: changing PrimaryKey into UniqueContraint");
- }
- #endif
- isPrimary = false;
- }
- }
- if (null != columnIndexMap) {
- columnIndexMap[unsortedIndex] = dataColumn.Ordinal;
- }
- else if (unsortedIndex != dataColumn.Ordinal) {
- columnIndexMap = CreateIndexMap(schemaRows.Length, unsortedIndex);
- columnIndexMap[unsortedIndex] = dataColumn.Ordinal;
- }
- mappingCount++;
- }
- bool addDataRelation = false;
- DataColumn chapterColumn = null;
- if (null != chapterValue) { // add the extra column in the child table
- Type fieldType = chapterValue.GetType();
- chapterColumn = _tableMapping.GetDataColumn(_tableMapping.SourceTable, fieldType, _dataTable, mappingAction, schemaAction);
- if (null != chapterColumn) {
- if (null == chapterColumn.Table) {
- chapterColumn.ReadOnly = true; // MDAC 71878
- chapterColumn.AllowDBNull = false;
- AddItemToAllowRollback(ref addedItems, chapterColumn);
- columnCollection.Add(chapterColumn);
- addDataRelation = (null != parentChapterColumn);
- }
- mappingCount++;
- }
- }
- if (0 < mappingCount) {
- if ((null != _dataSet) && null == _dataTable.DataSet) {
- AddItemToAllowRollback(ref addedItems, _dataTable);
- _dataSet.Tables.Add(_dataTable);
- }
- // setup the key
- if (addPrimaryKeys && (null != keys)) { // MDAC 67033
- if (keyCount < keys.Length) {
- keys = ResizeColumnArray(keys, keyCount);
- }
- // MDAC 66188
- if (isPrimary) {
- #if DEBUG
- if (AdapterSwitches.DataSchema.TraceVerbose) {
- Debug.WriteLine("SetupSchema: set_PrimaryKey");
- }
- #endif
- _dataTable.PrimaryKey = keys;
- }
- else {
- UniqueConstraint unique = new UniqueConstraint("", keys);
- ConstraintCollection constraints = _dataTable.Constraints;
- int constraintCount = constraints.Count;
- for (int i = 0; i < constraintCount; ++i) {
- if (unique.Equals(constraints[i])) {
- #if DEBUG
- if (AdapterSwitches.DataSchema.TraceVerbose) {
- Debug.WriteLine("SetupSchema: duplicate Contraint detected");
- }
- #endif
- unique = null;
- break;
- }
- }
- if (null != unique) {
- #if DEBUG
- if (AdapterSwitches.DataSchema.TraceVerbose) {
- Debug.WriteLine("SetupSchema: adding new UniqueConstraint");
- }
- #endif
- constraints.Add(unique);
- }
- }
- }
- if (!commonFromMultiTable && !ADP.IsEmpty(commonBaseTable) && ADP.IsEmpty(_dataTable.TableName)) {
- _dataTable.TableName = commonBaseTable;
- }
- if (gettingData) {
- _indexMap = columnIndexMap;
- _chapterMap = chapterIndexMap;
- dataValues = SetupMapping(schemaRows.Length, columnCollection, chapterColumn, chapterValue);
- }
- else {
- // debug only, but for retail debug ability
- _mappedMode = -1;
- }
- }
- else {
- _dataTable = null;
- }
- if (addDataRelation) {
- AddRelation(parentChapterColumn, chapterColumn);
- }
- }
- catch (Exception e) {
- if (ADP.IsCatchableOrSecurityExceptionType(e)) {
- RollbackAddedItems(addedItems);
- }
- throw;
- }
- return dataValues;
- }
- private void AddAdditionalProperties(DataColumn targetColumn, DataRow schemaRow) {
- DataColumnCollection columns = schemaRow.Table.Columns;
- DataColumn column;
- column = columns[SchemaTableOptionalColumn.DefaultValue];
- if (null != column) {
- targetColumn.DefaultValue = schemaRow[column];
- }
- column = columns[SchemaTableOptionalColumn.AutoIncrementSeed];
- if (null != column) {
- object value = schemaRow[column];
- if (DBNull.Value != value) {
- targetColumn.AutoIncrementSeed = ((IConvertible)value).ToInt64(CultureInfo.InvariantCulture);
- }
- }
- column = columns[SchemaTableOptionalColumn.AutoIncrementStep];
- if (null != column) {
- object value = schemaRow[column];
- if (DBNull.Value != value) {
- targetColumn.AutoIncrementStep = ((IConvertible)value).ToInt64(CultureInfo.InvariantCulture);
- }
- }
- column = columns[SchemaTableOptionalColumn.ColumnMapping];
- if (null != column) {
- object value = schemaRow[column];
- if (DBNull.Value != value) {
- targetColumn.ColumnMapping = (MappingType)((IConvertible)value).ToInt32(CultureInfo.InvariantCulture);
- }
- }
- column = columns[SchemaTableOptionalColumn.BaseColumnNamespace];
- if (null != column) {
- object value = schemaRow[column];
- if (DBNull.Value != value) {
- targetColumn.Namespace = ((IConvertible)value).ToString(CultureInfo.InvariantCulture);
- }
- }
- column = columns[SchemaTableOptionalColumn.Expression];
- if (null != column) {
- object value = schemaRow[column];
- if (DBNull.Value != value) {
- targetColumn.Expression = ((IConvertible)value).ToString(CultureInfo.InvariantCulture);
- }
- }
- }
- private void AddRelation(DataColumn parentChapterColumn, DataColumn chapterColumn) { // MDAC 71613
- if (null != _dataSet) {
- string name = /*parentChapterColumn.ColumnName + "_" +*/ chapterColumn.ColumnName; // MDAC 72815
- DataRelation relation = new DataRelation(name, new DataColumn[] { parentChapterColumn }, new DataColumn[] { chapterColumn }, false); // MDAC 71878
- int index = 1;
- string tmp = name;
- DataRelationCollection relations = _dataSet.Relations;
- while (-1 != relations.IndexOf(tmp)) {
- tmp = name + index;
- index++;
- }
- relation.RelationName = tmp;
- relations.Add(relation);
- }
- }
- private object[] SetupMapping(int count, DataColumnCollection columnCollection, DataColumn chapterColumn, object chapterValue) {
- object[] dataValues = new object[count];
- if (null == _indexMap) {
- int mappingCount = columnCollection.Count;
- bool hasChapters = (null != _chapterMap);
- if ((count != mappingCount) || hasChapters) {
- _mappedDataValues = new object[mappingCount];
- if (hasChapters) {
- _mappedMode = MapChapters;
- _mappedLength = count;
- }
- else {
- _mappedMode = MapDifferentSize;
- _mappedLength = Math.Min(count, mappingCount);
- }
- }
- else {
- _mappedMode = MapExactMatch; /* _mappedLength doesn't matter */
- }
- }
- else {
- _mappedDataValues = new object[columnCollection.Count];
- _mappedMode = ((null == _chapterMap) ? MapReorderedValues : MapChaptersReordered);
- _mappedLength = count;
- }
- if (null != chapterColumn) { // value from parent tracked into child table
- _mappedDataValues[chapterColumn.Ordinal] = chapterValue;
- }
- return dataValues;
- }
- }
- }
|