Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Data / System / Data / Selection.cs / 1305376 / Selection.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //[....] //----------------------------------------------------------------------------- namespace System.Data { using System; using System.Diagnostics; using System.ComponentModel; using System.Collections.Generic; using System.Threading; internal struct IndexField { public readonly DataColumn Column; public readonly bool IsDescending; // false = Asc; true = Desc what is default value for this? internal IndexField(DataColumn column, bool isDescending) { Column = column; IsDescending = isDescending; } } internal sealed class Index { private sealed class IndexTree : RBTree{ private readonly Index _index; internal IndexTree(Index index) : base(TreeAccessMethod.KEY_SEARCH_AND_INDEX) { _index = index; } protected override int CompareNode (int record1, int record2) { return _index.CompareRecords(record1, record2); } protected override int CompareSateliteTreeNode (int record1, int record2) { return _index.CompareDuplicateRecords(record1, record2); } } // these constants are used to patch a DataRow when the record and Row are known, but don't match private const int DoNotReplaceCompareRecord = 0; private const int ReplaceNewRecordForCompare = 1; private const int ReplaceOldRecordForCompare = 2; private readonly DataTable table; internal readonly int[] IndexDesc; internal readonly IndexField[] IndexFields; /// Allow a user implemented comparision of two DataRow ///User must use correct DataRowVersion in comparison or index corruption will happen private readonly System.Comparison_comparison; private readonly DataViewRowState recordStates; private WeakReference rowFilter; private IndexTree records; private int recordCount; private int refCount; private Listeners _listeners; private bool suspendEvents; private readonly static object[] zeroObjects = new object[0]; private readonly bool isSharable; private readonly bool _hasRemoteAggregate; internal const Int32 MaskBits = unchecked((int)0x7FFFFFFF); private static int _objectTypeCount; // Bid counter private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); public Index(DataTable table, IndexField[] indexFields, DataViewRowState recordStates, IFilter rowFilter) : this(table, null, indexFields, recordStates, rowFilter) { } public Index(DataTable table, int[] ndexDesc, IndexField[] indexFields, DataViewRowState recordStates, IFilter rowFilter) : this(table, ndexDesc, indexFields, null, recordStates, rowFilter) { } public Index(DataTable table, System.Comparison comparison, DataViewRowState recordStates, IFilter rowFilter) : this(table, null, GetAllFields(table.Columns), comparison, recordStates, rowFilter) { } // for the delegate methods, we don't know what the dependent columns are - so all columns are dependent private static IndexField[] GetAllFields(DataColumnCollection columns) { IndexField[] fields = new IndexField[columns.Count]; for(int i = 0; i < fields.Length; ++i) { fields[i] = new IndexField(columns[i], false); } return fields; } private Index(DataTable table, int[] ndexDesc, IndexField[] indexFields, System.Comparison comparison, DataViewRowState recordStates, IFilter rowFilter) { Bid.Trace(" %d#, table=%d, recordStates=%d{ds.DataViewRowState}\n", ObjectID, (table != null) ? table.ObjectID : 0, (int)recordStates); Debug.Assert(indexFields != null); Debug.Assert(null != table, "null table"); if ((recordStates & (~(DataViewRowState.CurrentRows | DataViewRowState.OriginalRows))) != 0) { throw ExceptionBuilder.RecordStateRange(); } this.table = table; _listeners = new Listeners (ObjectID, delegate(DataViewListener listener) { return (null != listener); }); IndexDesc = ndexDesc; IndexFields = indexFields; if (null == ndexDesc) { IndexDesc = Select.ConvertIndexFieldtoIndexDesc(indexFields); } this.recordStates = recordStates; _comparison = comparison; DataColumnCollection columns = table.Columns; isSharable = (rowFilter == null) && (comparison == null); // a filter or comparison make an index unsharable if (null != rowFilter) { this.rowFilter = new WeakReference(rowFilter); DataExpression expr = (rowFilter as DataExpression); if (null != expr) { _hasRemoteAggregate = expr.HasRemoteAggregate(); } } InitRecords(rowFilter); // do not AddRef in ctor, every caller should be responsible to AddRef it // if caller does not AddRef, it is expected to be a one-time read operation because the index won't be maintained on writes } public bool Equal(IndexField[] indexDesc, DataViewRowState recordStates, IFilter rowFilter) { if ( !isSharable || IndexFields.Length != indexDesc.Length || this.recordStates != recordStates || null != rowFilter ) { return false; } for (int loop = 0; loop < IndexFields.Length; loop++) { if (IndexFields[loop].Column!= indexDesc[loop].Column || IndexFields[loop].IsDescending != indexDesc[loop].IsDescending) { return false; } } return true; } internal bool HasRemoteAggregate { get { return _hasRemoteAggregate; } } internal int ObjectID { get { return _objectID; } } public DataViewRowState RecordStates { get { return recordStates; } } public IFilter RowFilter { get { return (IFilter)((null != rowFilter) ? rowFilter.Target : null); } } public int GetRecord(int recordIndex) { Debug.Assert (recordIndex >= 0 && recordIndex < recordCount, "recordIndex out of range"); return records[recordIndex]; } public bool HasDuplicates { get { return records.HasDuplicates; } } public int RecordCount { get { return recordCount; } } public bool IsSharable { get { return isSharable; } } private bool AcceptRecord(int record) { return AcceptRecord(record, RowFilter); } private bool AcceptRecord(int record, IFilter filter) { Bid.Trace(" %d#, record=%d\n", ObjectID, record); if (filter == null) return true; DataRow row = table.recordManager[record]; if (row == null) return true; // DataRowVersion version = DataRowVersion.Default; if (row.oldRecord == record) { version = DataRowVersion.Original; } else if (row.newRecord == record) { version = DataRowVersion.Current; } else if (row.tempRecord == record) { version = DataRowVersion.Proposed; } return filter.Invoke(row, version); } /// Only call from inside a lock(this) internal void ListChangedAdd(DataViewListener listener) { _listeners.Add(listener); } ///Only call from inside a lock(this) internal void ListChangedRemove(DataViewListener listener) { _listeners.Remove(listener); } public int RefCount { get { return refCount; } } public void AddRef() { Bid.Trace("%d#\n", ObjectID); LockCookie lc = table.indexesLock.UpgradeToWriterLock(-1); try { Debug.Assert(0 <= refCount, "AddRef on disposed index"); Debug.Assert(null != records, "null records"); if (refCount == 0) { table.ShadowIndexCopy(); table.indexes.Add(this); } refCount++; } finally { table.indexesLock.DowngradeFromWriterLock(ref lc); } } public int RemoveRef() { Bid.Trace(" %d#\n", ObjectID); int count; LockCookie lc = table.indexesLock.UpgradeToWriterLock(-1); try { count = --refCount; if (refCount <= 0) { table.ShadowIndexCopy(); bool flag = table.indexes.Remove(this); Debug.Assert(flag, "Index did not exist in index collection"); } } finally { table.indexesLock.DowngradeFromWriterLock(ref lc); } return count; } private void ApplyChangeAction(int record, int action, int changeRecord) { if (action != 0) { if (action > 0) { if (AcceptRecord(record)) { InsertRecord(record, true); } } else if ((null != _comparison) && (-1 != record)) { // when removing a record, the DataRow has already been updated to the newer record // depending on changeRecord, either the new or old record needs be backdated to record // for Comparison to operate correctly DeleteRecord(GetIndex(record, changeRecord)); } else { // unnecessary codepath other than keeping original code path for redbits DeleteRecord(GetIndex(record)); } } } public bool CheckUnique() { #if DEBUG Debug.Assert(records.CheckUnique(records.root) != HasDuplicates, "CheckUnique difference"); #endif return !HasDuplicates; } // only used for main tree compare, not satalite tree private int CompareRecords(int record1, int record2) { if (null != _comparison) { return CompareDataRows(record1, record2); } if (0 < IndexFields.Length) { for (int i = 0; i < IndexFields.Length; i++) { int c = IndexFields[i].Column.Compare(record1, record2); if (c != 0) { return (IndexFields[i].IsDescending ? -c : c); } } return 0; } else { Debug.Assert(null != table.recordManager[record1], "record1 no datarow"); Debug.Assert(null != table.recordManager[record2], "record2 no datarow"); // DataRow needs to always patched appropriately via GetIndex(int,int) //table.recordManager.VerifyRecord(record1, table.recordManager[record1]); //table.recordManager.VerifyRecord(record2, table.recordManager[record2]); // Need to use compare because subtraction will wrap // to positive for very large neg numbers, etc. return table.Rows.IndexOf(table.recordManager[record1]).CompareTo(table.Rows.IndexOf(table.recordManager[record2])); } } private int CompareDataRows(int record1, int record2) { table.recordManager.VerifyRecord(record1, table.recordManager[record1]); table.recordManager.VerifyRecord(record2, table.recordManager[record2]); return _comparison(table.recordManager[record1], table.recordManager[record2]); } // PS: same as previous CompareRecords, except it compares row state if needed // only used for satalite tree compare private int CompareDuplicateRecords(int record1, int record2) { #if DEBUG if (null != _comparison) { Debug.Assert(0 == CompareDataRows(record1, record2), "duplicate record not a duplicate by user function"); } else if (record1 != record2) { for (int i = 0; i < IndexFields.Length; i++) { int c = IndexFields[i].Column.Compare(record1, record2); Debug.Assert(0 == c, "duplicate record not a duplicate"); } } #endif Debug.Assert(null != table.recordManager[record1], "record1 no datarow"); Debug.Assert(null != table.recordManager[record2], "record2 no datarow"); // DataRow needs to always patched appropriately via GetIndex(int,int) //table.recordManager.VerifyRecord(record1, table.recordManager[record1]); //table.recordManager.VerifyRecord(record2, table.recordManager[record2]); if (null == table.recordManager[record1]) { return ((null == table.recordManager[record2]) ? 0 : -1); } else if (null == table.recordManager[record2]) { return 1; } // Need to use compare because subtraction will wrap // to positive for very large neg numbers, etc. int diff = table.recordManager[record1].rowID.CompareTo(table.recordManager[record2].rowID); // if they're two records in the same row, we need to be able to distinguish them. if ((diff == 0) && (record1 != record2)) { diff = ((int)table.recordManager[record1].GetRecordState(record1)).CompareTo((int)table.recordManager[record2].GetRecordState(record2)); } return diff; } private int CompareRecordToKey(int record1, object[] vals) { for (int i = 0; i < IndexFields.Length; i++) { int c = IndexFields[i].Column.CompareValueTo(record1, vals[i]); if (c != 0) { return (IndexFields[i].IsDescending ? -c : c); } } return 0; } // DeleteRecordFromIndex deletes the given record from index and does not fire any Event. IT SHOULD NOT FIRE EVENT // I added this since I can not use existing DeleteRecord which is not silent operation public void DeleteRecordFromIndex(int recordIndex) { // this is for expression use, to maintain expression columns's sort , filter etc. do not fire event DeleteRecord(recordIndex, false); } // old and existing DeleteRecord behavior, we can not use this for silently deleting private void DeleteRecord(int recordIndex) { DeleteRecord(recordIndex, true); } private void DeleteRecord(int recordIndex, bool fireEvent) { Bid.Trace(" %d#, recordIndex=%d, fireEvent=%d{bool}\n", ObjectID, recordIndex, fireEvent); if (recordIndex >= 0) { recordCount--; int record = records.DeleteByIndex(recordIndex); MaintainDataView(ListChangedType.ItemDeleted, record, !fireEvent); if (fireEvent) { // 1) Webdata 104939 do not fix this, it would be breaking change // 2) newRecord = -1, oldrecord = recordIndex; OnListChanged(ListChangedType.ItemDeleted, recordIndex); } } } // SQLBU 428961: Serious performance issue when creating DataView // this improves performance by allowing DataView to iterating instead of computing for records over index // this will also allow Linq over DataSet to enumerate over the index // avoid boxing by returning RBTreeEnumerator (a struct) instead of IEnumerator public RBTree .RBTreeEnumerator GetEnumerator(int startIndex) { return new IndexTree.RBTreeEnumerator(records, startIndex); } // What it actually does is find the index in the records[] that // this record inhabits, and if it doesn't, suggests what index it would // inhabit while setting the high bit. // public int GetIndex(int record) { int index = records.GetIndexByKey(record); return index; } /// /// When searching by value for a specific record, the DataRow may require backdating to reflect the appropriate state /// otherwise on Delete of a DataRow in the Added state, would result in the private int GetIndex(int record, int changeRecord) { Debug.Assert(null != _comparison, "missing comparison"); int index; DataRow row = table.recordManager[record]; int a = row.newRecord; int b = row.oldRecord; try { switch(changeRecord) { case ReplaceNewRecordForCompare: row.newRecord = record; break; case ReplaceOldRecordForCompare: row.oldRecord = record; break; } table.recordManager.VerifyRecord(record, row); index = records.GetIndexByKey(record); } finally { switch(changeRecord) { case ReplaceNewRecordForCompare: Debug.Assert(record == row.newRecord, "newRecord has change during GetIndex"); row.newRecord = a; break; case ReplaceOldRecordForCompare: Debug.Assert(record == row.oldRecord, "oldRecord has change during GetIndex"); row.oldRecord = b; break; } #if DEBUG if (-1 != a) { table.recordManager.VerifyRecord(a, row); } #endif } return index; } public object[] GetUniqueKeyValues() { if (IndexFields == null || IndexFields.Length == 0) { return zeroObjects; } Listwhere the row /// reflection record would be in the Detatched instead of Added state. ///
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- PropertyMetadata.cs
- HtmlWindowCollection.cs
- XXXInfos.cs
- InfoCardSymmetricCrypto.cs
- Root.cs
- Inflater.cs
- URL.cs
- Visual3D.cs
- BulletedListDesigner.cs
- StructuralCache.cs
- ReadOnlyMetadataCollection.cs
- ImportException.cs
- GCHandleCookieTable.cs
- DataPagerFieldItem.cs
- MaskedTextBoxTextEditorDropDown.cs
- Canvas.cs
- FocusTracker.cs
- XmlSigningNodeWriter.cs
- controlskin.cs
- WizardForm.cs
- ApplicationHost.cs
- IdleTimeoutMonitor.cs
- QuaternionRotation3D.cs
- DelegatingConfigHost.cs
- InstanceView.cs
- RuntimeHelpers.cs
- DataObjectEventArgs.cs
- GlyphsSerializer.cs
- RoutedUICommand.cs
- ContentControl.cs
- ResourceContainer.cs
- XmlDocumentSurrogate.cs
- SqlStream.cs
- EventRoute.cs
- SystemIPAddressInformation.cs
- ClientUtils.cs
- DbBuffer.cs
- MobileListItem.cs
- TypeConverterAttribute.cs
- PerformanceCounterManager.cs
- DesignSurfaceManager.cs
- XmlAutoDetectWriter.cs
- SystemGatewayIPAddressInformation.cs
- PrivilegeNotHeldException.cs
- AppDomainManager.cs
- XPathNodeIterator.cs
- InterleavedZipPartStream.cs
- NavigationProperty.cs
- ModelService.cs
- MetaModel.cs
- TemplateParser.cs
- ObjectAnimationUsingKeyFrames.cs
- assemblycache.cs
- CreateDataSourceDialog.cs
- Listbox.cs
- XmlCodeExporter.cs
- RemotingSurrogateSelector.cs
- ClientSettings.cs
- LoginDesigner.cs
- SemanticBasicElement.cs
- GlyphingCache.cs
- Token.cs
- BasicHttpMessageCredentialType.cs
- RenderingBiasValidation.cs
- RecipientInfo.cs
- XmlReaderDelegator.cs
- Socket.cs
- VectorAnimationBase.cs
- TableDetailsRow.cs
- PageTextBox.cs
- PointHitTestParameters.cs
- EntityCommandCompilationException.cs
- Listbox.cs
- XmlSignificantWhitespace.cs
- WebPartEditorCancelVerb.cs
- BasicHttpBindingElement.cs
- ListView.cs
- wmiprovider.cs
- ImmutableClientRuntime.cs
- IISMapPath.cs
- HtmlHistory.cs
- CultureInfo.cs
- QilValidationVisitor.cs
- UTF7Encoding.cs
- ExpressionTextBox.xaml.cs
- AlternationConverter.cs
- CellCreator.cs
- wgx_sdk_version.cs
- validation.cs
- MILUtilities.cs
- SafeCloseHandleCritical.cs
- RequestSecurityTokenResponseCollection.cs
- UpdateExpressionVisitor.cs
- EnvironmentPermission.cs
- CodeObjectCreateExpression.cs
- DocumentApplicationJournalEntry.cs
- SettingsPropertyValueCollection.cs
- DesignBindingValueUIHandler.cs
- InternalControlCollection.cs
- XmlObjectSerializerWriteContext.cs