Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Data / System / Data / Selection.cs / 4 / 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); } } } // 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
- TemplateKey.cs
- TransportSecurityProtocolFactory.cs
- AstNode.cs
- RuntimeHelpers.cs
- ColorPalette.cs
- SynchronizedPool.cs
- CoreSwitches.cs
- EventArgs.cs
- _Rfc2616CacheValidators.cs
- TransformCollection.cs
- StrokeIntersection.cs
- BitmapEffectInputConnector.cs
- ToolStripDropDownButton.cs
- SocketStream.cs
- SqlConnectionHelper.cs
- HyperLinkField.cs
- OdbcError.cs
- ByteAnimation.cs
- SynchronizedRandom.cs
- DataGridTableCollection.cs
- ButtonChrome.cs
- Debug.cs
- NTAccount.cs
- TextFormattingConverter.cs
- ArgIterator.cs
- AccessDataSourceDesigner.cs
- Component.cs
- PseudoWebRequest.cs
- MemberInfoSerializationHolder.cs
- filewebrequest.cs
- TypeConverterHelper.cs
- _PooledStream.cs
- ImageButton.cs
- PasswordBoxAutomationPeer.cs
- Win32NamedPipes.cs
- MembershipUser.cs
- hwndwrapper.cs
- DateTimeFormatInfo.cs
- PrimitiveSchema.cs
- ChangeToolStripParentVerb.cs
- PropertyPathWorker.cs
- SchemaElement.cs
- MonikerSyntaxException.cs
- FrameworkTemplate.cs
- SqlStream.cs
- XamlPoint3DCollectionSerializer.cs
- XamlToRtfParser.cs
- FlowDocumentView.cs
- Module.cs
- HealthMonitoringSectionHelper.cs
- InternalRelationshipCollection.cs
- DataSpaceManager.cs
- ConfigurationStrings.cs
- ThemeConfigurationDialog.cs
- TextBox.cs
- ISAPIWorkerRequest.cs
- SqlDataSourceCache.cs
- ApplicationId.cs
- TableItemStyle.cs
- Repeater.cs
- SqlProcedureAttribute.cs
- AttributeProviderAttribute.cs
- CatalogPartChrome.cs
- WindowsStatusBar.cs
- HtmlTernaryTree.cs
- Currency.cs
- AmbientLight.cs
- SecurityException.cs
- SystemInfo.cs
- WebBrowsableAttribute.cs
- PasswordRecovery.cs
- SignatureToken.cs
- NativeWrapper.cs
- _LazyAsyncResult.cs
- IDictionary.cs
- XmlnsCache.cs
- XmlQueryContext.cs
- CFGGrammar.cs
- SlotInfo.cs
- XmlSerializationReader.cs
- TemplateControlBuildProvider.cs
- OracleSqlParser.cs
- DesignSurface.cs
- ReadOnlyAttribute.cs
- XmlEncoding.cs
- ArrayExtension.cs
- CapabilitiesSection.cs
- ToolboxItem.cs
- DefaultSerializationProviderAttribute.cs
- ListViewGroupConverter.cs
- Error.cs
- HandlerWithFactory.cs
- LogFlushAsyncResult.cs
- Process.cs
- RoleManagerModule.cs
- EnumConverter.cs
- EdmConstants.cs
- ScrollChrome.cs
- ActivityBuilderHelper.cs
- TextMetrics.cs