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
- RequestDescription.cs
- EventRecord.cs
- XmlLanguage.cs
- CallSiteHelpers.cs
- FormsAuthenticationModule.cs
- PrintDialog.cs
- NodeInfo.cs
- DetailsViewActionList.cs
- SingleObjectCollection.cs
- PaperSize.cs
- ImageAutomationPeer.cs
- ModelUIElement3D.cs
- SiteIdentityPermission.cs
- ObjectRef.cs
- RenderOptions.cs
- ProgressPage.cs
- ProviderCommandInfoUtils.cs
- XmlText.cs
- SqlWriter.cs
- ObjectQueryExecutionPlan.cs
- CmsInterop.cs
- ScriptingSectionGroup.cs
- NavigatorOutput.cs
- Vector3D.cs
- CompoundFileDeflateTransform.cs
- FlowLayout.cs
- EditCommandColumn.cs
- GrammarBuilderWildcard.cs
- FixedFindEngine.cs
- XmlDictionary.cs
- SafeCryptoHandles.cs
- InvokeHandlers.cs
- FontDriver.cs
- TargetControlTypeAttribute.cs
- EncryptedPackageFilter.cs
- FastEncoder.cs
- _AuthenticationState.cs
- ComAdminInterfaces.cs
- InternalBase.cs
- AbstractExpressions.cs
- TagMapCollection.cs
- RelationshipEndCollection.cs
- UInt64Storage.cs
- EventLog.cs
- Comparer.cs
- StrokeNodeData.cs
- COM2IProvidePropertyBuilderHandler.cs
- ScrollEvent.cs
- UnsafeNativeMethods.cs
- WorkflowQueue.cs
- ConfigXmlSignificantWhitespace.cs
- FastEncoder.cs
- Trigger.cs
- DesignBinding.cs
- XmlNamespaceManager.cs
- TraceContextEventArgs.cs
- AdditionalEntityFunctions.cs
- Stroke.cs
- DrawListViewItemEventArgs.cs
- IdnMapping.cs
- SqlCharStream.cs
- StreamReader.cs
- HostingEnvironmentException.cs
- CheckedListBox.cs
- SqlGenerator.cs
- ConfigurationPropertyCollection.cs
- PrintEvent.cs
- InteropAutomationProvider.cs
- TranslateTransform3D.cs
- DeviceOverridableAttribute.cs
- DesignerSerializerAttribute.cs
- xml.cs
- DataServiceKeyAttribute.cs
- _IPv6Address.cs
- DesigntimeLicenseContextSerializer.cs
- VisualBrush.cs
- ImageKeyConverter.cs
- CustomBindingElementCollection.cs
- Brushes.cs
- PeerCollaboration.cs
- SamlAdvice.cs
- UnconditionalPolicy.cs
- ErasingStroke.cs
- AbsoluteQuery.cs
- Command.cs
- Certificate.cs
- Types.cs
- GenericUriParser.cs
- CommandBindingCollection.cs
- XmlSchemaAttributeGroup.cs
- ConstructorNeedsTagAttribute.cs
- HttpCacheVaryByContentEncodings.cs
- ErrorEventArgs.cs
- ThreadLocal.cs
- ToolStripSystemRenderer.cs
- TextWriter.cs
- DynamicRendererThreadManager.cs
- GeometryModel3D.cs
- FileChangesMonitor.cs
- XmlSchemaObject.cs