/// <devdoc> /// <para>Finds and updates a specific row. If no matching /// row is found, a new row is created using the given values.</para> /// </devdoc> public DataRow LoadDataRow(object[] values, LoadOption loadOption) { IntPtr hscp; Bid.ScopeEnter(out hscp, "<ds.DataTable.LoadDataRow|API> %d#, loadOption=%d{ds.LoadOption}\n", ObjectID, (int)loadOption); try { Index indextoUse = null; if (this.primaryKey != null) { if (loadOption == LoadOption.Upsert) { // CurrentVersion, and Deleted if (loadIndexwithCurrentDeleted == null) { loadIndexwithCurrentDeleted = this.primaryKey.Key.GetSortIndex(DataViewRowState.CurrentRows |DataViewRowState.Deleted); Debug.Assert(loadIndexwithCurrentDeleted != null, "loadIndexwithCurrentDeleted should not be null" ); if (loadIndexwithCurrentDeleted != null) { loadIndexwithCurrentDeleted.AddRef(); } } indextoUse = loadIndexwithCurrentDeleted; } else {// CurrentVersion, and Deleted : OverwriteRow, PreserveCurrentValues if (loadIndexwithOriginalAdded == null) { loadIndexwithOriginalAdded = this.primaryKey.Key.GetSortIndex(DataViewRowState.OriginalRows |DataViewRowState.Added); Debug.Assert(loadIndexwithOriginalAdded != null, "loadIndexwithOriginalAdded should not be null"); if (loadIndexwithOriginalAdded != null) { loadIndexwithOriginalAdded.AddRef(); } } indextoUse = loadIndexwithOriginalAdded; } // not expecting LiveIndexes to clear the index we use between calls to LoadDataRow Debug.Assert(2 <= indextoUse.RefCount, "bad indextoUse.RefCount"); } if(inDataLoad && !AreIndexEventsSuspended) { // we do not want to fire any listchanged in new Load/Fill SuspendIndexEvents();// so suspend events here(not suspended == table already has some rows initially) } DataRow dataRow = LoadRow(values, loadOption, indextoUse);// if indextoUse == null, it means we dont have PK, // so LoadRow will take care of just adding the row to end return dataRow; } finally { Bid.ScopeLeave(ref hscp); } }
// Based on the required sorting and candidate columns settings, create a new index; Should be called only when there is no existing index to be reused private void CreateIndex() { if (index == null) { if (nCandidates == 0) { index = new Index(table, IndexFields, recordStates, null); index.AddRef(); } else { int i; int lenCanColumns = candidateColumns.Length; int lenIndexDesc = IndexFields.Length; bool equalsOperator = true; for (i=0; i<lenCanColumns; i++) { if (candidateColumns[i] != null) { if (!candidateColumns[i].equalsOperator) { equalsOperator = false; break; } } } int j=0; for (i=0; i < lenIndexDesc; i++) { ColumnInfo candidateColumn = candidateColumns[IndexFields[i].Column.Ordinal]; if (candidateColumn != null) { candidateColumn.flag = true; j++; } } int indexNotInCandidates = lenIndexDesc - j; int candidatesNotInIndex = nCandidates - j; IndexField[] ndxFields = new IndexField[nCandidates + indexNotInCandidates]; if (equalsOperator) { j=0; for (i=0; i<lenCanColumns; i++) { if (candidateColumns[i] != null) { ndxFields[j++] = new IndexField(this.table.Columns[i], isDescending: false); candidateColumns[i].flag = false;// this means it is processed } } for (i=0; i<lenIndexDesc; i++) { ColumnInfo canColumn = candidateColumns[IndexFields[i].Column.Ordinal]; if (canColumn == null || canColumn.flag) { // if sort column is not a filter col , or not processed ndxFields[j++] = IndexFields[i]; if (canColumn != null) { canColumn.flag = false; } } } for(i = 0; i < candidateColumns.Length; i++) { if (candidateColumns[i] != null) { candidateColumns[i].flag = false;// same as before, it is false when it returns } } // Debug.Assert(j == candidatesNotInIndex, "Whole ndxDesc should be filled!"); index = new Index(table, ndxFields, recordStates, null); if (!IsOperatorIn(this.expression)) { // if the expression contains an 'IN' operator, the index will not be shared // therefore we do not need to index.AddRef, also table would track index consuming more memory until first write index.AddRef(); } matchedCandidates = nCandidates; } else { for (i=0; i<lenIndexDesc; i++) { ndxFields[i] = IndexFields[i]; ColumnInfo canColumn = candidateColumns[IndexFields[i].Column.Ordinal]; if (canColumn != null) canColumn.flag = true; } j=i; for (i=0; i<lenCanColumns; i++) { if (candidateColumns[i] != null) { if(!candidateColumns[i].flag) { ndxFields[j++] = new IndexField(this.table.Columns[i], isDescending: false); } else { candidateColumns[i].flag = false; } } } // Debug.Assert(j == nCandidates+indexNotInCandidates, "Whole ndxDesc should be filled!"); index = new Index(table, ndxFields, recordStates, null); matchedCandidates = 0; if (this.linearExpression != this.expression) { IndexField[] fields = index.IndexFields; while (matchedCandidates < j) { // [....] : j = index.IndexDesc.Length ColumnInfo canColumn = candidateColumns[fields[matchedCandidates].Column.Ordinal]; if (canColumn == null || canColumn.expr == null) break; matchedCandidates++; if (!canColumn.equalsOperator) break; } } for(i = 0; i < candidateColumns.Length; i++) { if (candidateColumns[i] != null) { candidateColumns[i].flag = false;// same as before, it is false when it returns } } } } } }
internal Index GetIndex(IndexField[] indexDesc, DataViewRowState recordStates, IFilter rowFilter) { indexesLock.AcquireReaderLock(-1); try { for (int i = 0; i < indexes.Count; i++) { Index index = indexes[i]; if (index != null) { if (index.Equal(indexDesc, recordStates, rowFilter)) { return index; } } } } finally { indexesLock.ReleaseReaderLock(); } Index ndx = new Index(this, indexDesc, recordStates, rowFilter); ndx.AddRef(); return ndx; }
internal Index GetIndex(IndexField[] indexDesc, DataViewRowState recordStates, IFilter rowFilter) { _indexesLock.EnterUpgradeableReadLock(); try { for (int i = 0; i < _indexes.Count; i++) { Index index = _indexes[i]; if (index != null) { if (index.Equal(indexDesc, recordStates, rowFilter)) { return index; } } } } finally { _indexesLock.ExitUpgradeableReadLock(); } Index ndx = new Index(this, indexDesc, recordStates, rowFilter); ndx.AddRef(); return ndx; }