summaryrefslogtreecommitdiff
path: root/db/mork/src/morkRow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'db/mork/src/morkRow.cpp')
-rw-r--r--db/mork/src/morkRow.cpp933
1 files changed, 933 insertions, 0 deletions
diff --git a/db/mork/src/morkRow.cpp b/db/mork/src/morkRow.cpp
new file mode 100644
index 0000000000..ede1bf646f
--- /dev/null
+++ b/db/mork/src/morkRow.cpp
@@ -0,0 +1,933 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _MDB_
+#include "mdb.h"
+#endif
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKNODE_
+#include "morkNode.h"
+#endif
+
+#ifndef _MORKROW_
+#include "morkRow.h"
+#endif
+
+#ifndef _MORKENV_
+#include "morkEnv.h"
+#endif
+
+#ifndef _MORKROWSPACE_
+#include "morkRowSpace.h"
+#endif
+
+#ifndef _MORKPOOL_
+#include "morkPool.h"
+#endif
+
+#ifndef _MORKROWOBJECT_
+#include "morkRowObject.h"
+#endif
+
+#ifndef _MORKCELLOBJECT_
+#include "morkCellObject.h"
+#endif
+
+#ifndef _MORKCELL_
+#include "morkCell.h"
+#endif
+
+#ifndef _MORKSTORE_
+#include "morkStore.h"
+#endif
+
+#ifndef _MORKROWCELLCURSOR_
+#include "morkRowCellCursor.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+
+// notifications regarding row changes:
+
+void morkRow::NoteRowAddCol(morkEnv* ev, mork_column inColumn)
+{
+ if ( !this->IsRowRewrite() )
+ {
+ mork_delta newDelta;
+ morkDelta_Init(newDelta, inColumn, morkChange_kAdd);
+
+ if ( newDelta != mRow_Delta ) // not repeating existing data?
+ {
+ if ( this->HasRowDelta() ) // already have one change recorded?
+ this->SetRowRewrite(); // just plan to write all row cells
+ else
+ this->SetRowDelta(inColumn, morkChange_kAdd);
+ }
+ }
+ else
+ this->ClearRowDelta();
+}
+
+void morkRow::NoteRowCutCol(morkEnv* ev, mork_column inColumn)
+{
+ if ( !this->IsRowRewrite() )
+ {
+ mork_delta newDelta;
+ morkDelta_Init(newDelta, inColumn, morkChange_kCut);
+
+ if ( newDelta != mRow_Delta ) // not repeating existing data?
+ {
+ if ( this->HasRowDelta() ) // already have one change recorded?
+ this->SetRowRewrite(); // just plan to write all row cells
+ else
+ this->SetRowDelta(inColumn, morkChange_kCut);
+ }
+ }
+ else
+ this->ClearRowDelta();
+}
+
+void morkRow::NoteRowSetCol(morkEnv* ev, mork_column inColumn)
+{
+ if ( !this->IsRowRewrite() )
+ {
+ if ( this->HasRowDelta() ) // already have one change recorded?
+ this->SetRowRewrite(); // just plan to write all row cells
+ else
+ this->SetRowDelta(inColumn, morkChange_kSet);
+ }
+ else
+ this->ClearRowDelta();
+}
+
+void morkRow::NoteRowSetAll(morkEnv* ev)
+{
+ this->SetRowRewrite(); // just plan to write all row cells
+ this->ClearRowDelta();
+}
+
+mork_u2
+morkRow::AddRowGcUse(morkEnv* ev)
+{
+ if ( this->IsRow() )
+ {
+ if ( mRow_GcUses < morkRow_kMaxGcUses ) // not already maxed out?
+ ++mRow_GcUses;
+ }
+ else
+ this->NonRowTypeError(ev);
+
+ return mRow_GcUses;
+}
+
+mork_u2
+morkRow::CutRowGcUse(morkEnv* ev)
+{
+ if ( this->IsRow() )
+ {
+ if ( mRow_GcUses ) // any outstanding uses to cut?
+ {
+ if ( mRow_GcUses < morkRow_kMaxGcUses ) // not frozen at max?
+ --mRow_GcUses;
+ }
+ else
+ this->GcUsesUnderflowWarning(ev);
+ }
+ else
+ this->NonRowTypeError(ev);
+
+ return mRow_GcUses;
+}
+
+/*static*/ void
+morkRow::GcUsesUnderflowWarning(morkEnv* ev)
+{
+ ev->NewWarning("mRow_GcUses underflow");
+}
+
+
+/*static*/ void
+morkRow::NonRowTypeError(morkEnv* ev)
+{
+ ev->NewError("non morkRow");
+}
+
+/*static*/ void
+morkRow::NonRowTypeWarning(morkEnv* ev)
+{
+ ev->NewWarning("non morkRow");
+}
+
+/*static*/ void
+morkRow::LengthBeyondMaxError(morkEnv* ev)
+{
+ ev->NewError("mRow_Length over max");
+}
+
+/*static*/ void
+morkRow::ZeroColumnError(morkEnv* ev)
+{
+ ev->NewError(" zero mork_column");
+}
+
+/*static*/ void
+morkRow::NilCellsError(morkEnv* ev)
+{
+ ev->NewError("nil mRow_Cells");
+}
+
+void
+morkRow::InitRow(morkEnv* ev, const mdbOid* inOid, morkRowSpace* ioSpace,
+ mork_size inLength, morkPool* ioPool)
+ // if inLength is nonzero, cells will be allocated from ioPool
+{
+ if ( ioSpace && ioPool && inOid )
+ {
+ if ( inLength <= morkRow_kMaxLength )
+ {
+ if ( inOid->mOid_Id != morkRow_kMinusOneRid )
+ {
+ mRow_Space = ioSpace;
+ mRow_Object = 0;
+ mRow_Cells = 0;
+ mRow_Oid = *inOid;
+
+ mRow_Length = (mork_u2) inLength;
+ mRow_Seed = (mork_u2) (mork_ip) this; // "random" assignment
+
+ mRow_GcUses = 0;
+ mRow_Pad = 0;
+ mRow_Flags = 0;
+ mRow_Tag = morkRow_kTag;
+
+ morkZone* zone = &ioSpace->mSpace_Store->mStore_Zone;
+
+ if ( inLength )
+ mRow_Cells = ioPool->NewCells(ev, inLength, zone);
+
+ if ( this->MaybeDirtySpaceStoreAndRow() ) // new row might dirty store
+ {
+ this->SetRowRewrite();
+ this->NoteRowSetAll(ev);
+ }
+ }
+ else
+ ioSpace->MinusOneRidError(ev);
+ }
+ else
+ this->LengthBeyondMaxError(ev);
+ }
+ else
+ ev->NilPointerError();
+}
+
+morkRowObject*
+morkRow::AcquireRowObject(morkEnv* ev, morkStore* ioStore)
+{
+ morkRowObject* ro = mRow_Object;
+ if ( ro ) // need new row object?
+ ro->AddRef();
+ else
+ {
+ nsIMdbHeap* heap = ioStore->mPort_Heap;
+ ro = new(*heap, ev)
+ morkRowObject(ev, morkUsage::kHeap, heap, this, ioStore);
+ if ( !ro )
+ return (morkRowObject*) 0;
+
+ morkRowObject::SlotWeakRowObject(ro, ev, &mRow_Object);
+ ro->AddRef();
+ }
+ return ro;
+}
+
+nsIMdbRow*
+morkRow::AcquireRowHandle(morkEnv* ev, morkStore* ioStore)
+{
+ return AcquireRowObject(ev, ioStore);
+}
+
+nsIMdbCell*
+morkRow::AcquireCellHandle(morkEnv* ev, morkCell* ioCell,
+ mdb_column inCol, mork_pos inPos)
+{
+ nsIMdbHeap* heap = ev->mEnv_Heap;
+ morkCellObject* cellObj = new(*heap, ev)
+ morkCellObject(ev, morkUsage::kHeap, heap, this, ioCell, inCol, inPos);
+ if ( cellObj )
+ {
+ nsIMdbCell* cellHandle = cellObj->AcquireCellHandle(ev);
+// cellObj->CutStrongRef(ev->AsMdbEnv());
+ return cellHandle;
+ }
+ return (nsIMdbCell*) 0;
+}
+
+mork_count
+morkRow::CountOverlap(morkEnv* ev, morkCell* ioVector, mork_fill inFill)
+ // Count cells in ioVector that change existing cells in this row when
+ // ioVector is added to the row (as in TakeCells()). This is the set
+ // of cells with the same columns in ioVector and mRow_Cells, which do
+ // not have exactly the same value in mCell_Atom, and which do not both
+ // have change status equal to morkChange_kCut (because cutting a cut
+ // cell still yields a cell that has been cut). CountOverlap() also
+ // modifies the change attribute of any cell in ioVector to kDup when
+ // the change was previously kCut and the same column cell was found
+ // in this row with change also equal to kCut; this tells callers later
+ // they need not look for that cell in the row again on a second pass.
+{
+ mork_count outCount = 0;
+ mork_pos pos = 0; // needed by GetCell()
+ morkCell* cells = ioVector;
+ morkCell* end = cells + inFill;
+ --cells; // prepare for preincrement
+ while ( ++cells < end && ev->Good() )
+ {
+ mork_column col = cells->GetColumn();
+
+ morkCell* old = this->GetCell(ev, col, &pos);
+ if ( old ) // same column?
+ {
+ mork_change newChg = cells->GetChange();
+ mork_change oldChg = old->GetChange();
+ if ( newChg != morkChange_kCut || oldChg != newChg ) // not cut+cut?
+ {
+ if ( cells->mCell_Atom != old->mCell_Atom ) // not same atom?
+ ++outCount; // cells will replace old significantly when added
+ }
+ else
+ cells->SetColumnAndChange(col, morkChange_kDup); // note dup status
+ }
+ }
+ return outCount;
+}
+
+void
+morkRow::MergeCells(morkEnv* ev, morkCell* ioVector,
+ mork_fill inVecLength, mork_fill inOldRowFill, mork_fill inOverlap)
+ // MergeCells() is the part of TakeCells() that does the insertion.
+ // inOldRowFill is the old value of mRow_Length, and inOverlap is the
+ // number of cells in the intersection that must be updated.
+{
+ morkCell* newCells = mRow_Cells + inOldRowFill; // 1st new cell in row
+ morkCell* newEnd = newCells + mRow_Length; // one past last cell
+
+ morkCell* srcCells = ioVector;
+ morkCell* srcEnd = srcCells + inVecLength;
+
+ --srcCells; // prepare for preincrement
+ while ( ++srcCells < srcEnd && ev->Good() )
+ {
+ mork_change srcChg = srcCells->GetChange();
+ if ( srcChg != morkChange_kDup ) // anything to be done?
+ {
+ morkCell* dstCell = 0;
+ if ( inOverlap )
+ {
+ mork_pos pos = 0; // needed by GetCell()
+ dstCell = this->GetCell(ev, srcCells->GetColumn(), &pos);
+ }
+ if ( dstCell )
+ {
+ --inOverlap; // one fewer intersections to resolve
+ // swap the atoms in the cells to avoid ref counting here:
+ morkAtom* dstAtom = dstCell->mCell_Atom;
+ *dstCell = *srcCells; // bitwise copy, taking src atom
+ srcCells->mCell_Atom = dstAtom; // forget cell ref, if any
+ }
+ else if ( newCells < newEnd ) // another new cell exists?
+ {
+ dstCell = newCells++; // alloc another new cell
+ // take atom from source cell, transferring ref to this row:
+ *dstCell = *srcCells; // bitwise copy, taking src atom
+ srcCells->mCell_Atom = 0; // forget cell ref, if any
+ }
+ else // oops, we ran out...
+ ev->NewError("out of new cells");
+ }
+ }
+}
+
+void
+morkRow::TakeCells(morkEnv* ev, morkCell* ioVector, mork_fill inVecLength,
+ morkStore* ioStore)
+{
+ if ( ioVector && inVecLength && ev->Good() )
+ {
+ ++mRow_Seed; // intend to change structure of mRow_Cells
+ mork_size length = (mork_size) mRow_Length;
+
+ mork_count overlap = this->CountOverlap(ev, ioVector, inVecLength);
+
+ mork_size growth = inVecLength - overlap; // cells to add
+ mork_size newLength = length + growth;
+
+ if ( growth && ev->Good() ) // need to add any cells?
+ {
+ morkZone* zone = &ioStore->mStore_Zone;
+ morkPool* pool = ioStore->StorePool();
+ if ( !pool->AddRowCells(ev, this, length + growth, zone) )
+ ev->NewError("cannot take cells");
+ }
+ if ( ev->Good() )
+ {
+ if ( mRow_Length >= newLength )
+ this->MergeCells(ev, ioVector, inVecLength, length, overlap);
+ else
+ ev->NewError("not enough new cells");
+ }
+ }
+}
+
+mork_bool morkRow::MaybeDirtySpaceStoreAndRow()
+{
+ morkRowSpace* rowSpace = mRow_Space;
+ if ( rowSpace )
+ {
+ morkStore* store = rowSpace->mSpace_Store;
+ if ( store && store->mStore_CanDirty )
+ {
+ store->SetStoreDirty();
+ rowSpace->mSpace_CanDirty = morkBool_kTrue;
+ }
+
+ if ( rowSpace->mSpace_CanDirty )
+ {
+ this->SetRowDirty();
+ rowSpace->SetRowSpaceDirty();
+ return morkBool_kTrue;
+ }
+ }
+ return morkBool_kFalse;
+}
+
+morkCell*
+morkRow::NewCell(morkEnv* ev, mdb_column inColumn,
+ mork_pos* outPos, morkStore* ioStore)
+{
+ ++mRow_Seed; // intend to change structure of mRow_Cells
+ mork_size length = (mork_size) mRow_Length;
+ *outPos = (mork_pos) length;
+ morkPool* pool = ioStore->StorePool();
+ morkZone* zone = &ioStore->mStore_Zone;
+
+ mork_bool canDirty = this->MaybeDirtySpaceStoreAndRow();
+
+ if ( pool->AddRowCells(ev, this, length + 1, zone) )
+ {
+ morkCell* cell = mRow_Cells + length;
+ // next line equivalent to inline morkCell::SetCellDirty():
+ if ( canDirty )
+ cell->SetCellColumnDirty(inColumn);
+ else
+ cell->SetCellColumnClean(inColumn);
+
+ if ( canDirty && !this->IsRowRewrite() )
+ this->NoteRowAddCol(ev, inColumn);
+
+ return cell;
+ }
+
+ return (morkCell*) 0;
+}
+
+
+
+void morkRow::SeekColumn(morkEnv* ev, mdb_pos inPos,
+ mdb_column* outColumn, mdbYarn* outYarn)
+{
+ morkCell* cells = mRow_Cells;
+ if ( cells && inPos < mRow_Length && inPos >= 0 )
+ {
+ morkCell* c = cells + inPos;
+ if ( outColumn )
+ *outColumn = c->GetColumn();
+ if ( outYarn )
+ c->mCell_Atom->GetYarn(outYarn); // nil atom works okay here
+ }
+ else
+ {
+ if ( outColumn )
+ *outColumn = 0;
+ if ( outYarn )
+ ((morkAtom*) 0)->GetYarn(outYarn); // yes this will work
+ }
+}
+
+void
+morkRow::NextColumn(morkEnv* ev, mdb_column* ioColumn, mdbYarn* outYarn)
+{
+ morkCell* cells = mRow_Cells;
+ if ( cells )
+ {
+ mork_column last = 0;
+ mork_column inCol = *ioColumn;
+ morkCell* end = cells + mRow_Length;
+ while ( cells < end )
+ {
+ if ( inCol == last ) // found column?
+ {
+ if ( outYarn )
+ cells->mCell_Atom->GetYarn(outYarn); // nil atom works okay here
+ *ioColumn = cells->GetColumn();
+ return; // stop, we are done
+ }
+ else
+ {
+ last = cells->GetColumn();
+ ++cells;
+ }
+ }
+ }
+ *ioColumn = 0;
+ if ( outYarn )
+ ((morkAtom*) 0)->GetYarn(outYarn); // yes this will work
+}
+
+morkCell*
+morkRow::CellAt(morkEnv* ev, mork_pos inPos) const
+{
+ MORK_USED_1(ev);
+ morkCell* cells = mRow_Cells;
+ if ( cells && inPos < mRow_Length && inPos >= 0 )
+ {
+ return cells + inPos;
+ }
+ return (morkCell*) 0;
+}
+
+morkCell*
+morkRow::GetCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos) const
+{
+ MORK_USED_1(ev);
+ morkCell* cells = mRow_Cells;
+ if ( cells )
+ {
+ morkCell* end = cells + mRow_Length;
+ while ( cells < end )
+ {
+ mork_column col = cells->GetColumn();
+ if ( col == inColumn ) // found the desired column?
+ {
+ *outPos = cells - mRow_Cells;
+ return cells;
+ }
+ else
+ ++cells;
+ }
+ }
+ *outPos = -1;
+ return (morkCell*) 0;
+}
+
+mork_aid
+morkRow::GetCellAtomAid(morkEnv* ev, mdb_column inColumn) const
+ // GetCellAtomAid() finds the cell with column inColumn, and sees if the
+ // atom has a token ID, and returns the atom's ID if there is one. Or
+ // else zero is returned if there is no such column, or no atom, or if
+ // the atom has no ID to return. This method is intended to support
+ // efficient updating of column indexes for rows in a row space.
+{
+ if (this->IsRow())
+ {
+ morkCell* cells = mRow_Cells;
+ if ( cells )
+ {
+ morkCell* end = cells + mRow_Length;
+ while ( cells < end )
+ {
+ mork_column col = cells->GetColumn();
+ if ( col == inColumn ) // found desired column?
+ {
+ morkAtom* atom = cells->mCell_Atom;
+ if ( atom && atom->IsBook() )
+ return ((morkBookAtom*) atom)->mBookAtom_Id;
+ else
+ return 0;
+ }
+ else
+ ++cells;
+ }
+ }
+ }
+ else
+ this->NonRowTypeError(ev);
+
+ return 0;
+}
+
+void
+morkRow::EmptyAllCells(morkEnv* ev)
+{
+ morkCell* cells = mRow_Cells;
+ if ( cells )
+ {
+ morkStore* store = this->GetRowSpaceStore(ev);
+ if ( store )
+ {
+ if ( this->MaybeDirtySpaceStoreAndRow() )
+ {
+ this->SetRowRewrite();
+ this->NoteRowSetAll(ev);
+ }
+ morkPool* pool = store->StorePool();
+ morkCell* end = cells + mRow_Length;
+ --cells; // prepare for preincrement:
+ while ( ++cells < end )
+ {
+ if ( cells->mCell_Atom )
+ cells->SetAtom(ev, (morkAtom*) 0, pool);
+ }
+ }
+ }
+}
+
+void
+morkRow::cut_all_index_entries(morkEnv* ev)
+{
+ morkRowSpace* rowSpace = mRow_Space;
+ if ( rowSpace->mRowSpace_IndexCount ) // any indexes?
+ {
+ morkCell* cells = mRow_Cells;
+ if ( cells )
+ {
+ morkCell* end = cells + mRow_Length;
+ --cells; // prepare for preincrement:
+ while ( ++cells < end )
+ {
+ morkAtom* atom = cells->mCell_Atom;
+ if ( atom )
+ {
+ mork_aid atomAid = atom->GetBookAtomAid();
+ if ( atomAid )
+ {
+ mork_column col = cells->GetColumn();
+ morkAtomRowMap* map = rowSpace->FindMap(ev, col);
+ if ( map ) // cut row from index for this column?
+ map->CutAid(ev, atomAid);
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+morkRow::CutAllColumns(morkEnv* ev)
+{
+ morkStore* store = this->GetRowSpaceStore(ev);
+ if ( store )
+ {
+ if ( this->MaybeDirtySpaceStoreAndRow() )
+ {
+ this->SetRowRewrite();
+ this->NoteRowSetAll(ev);
+ }
+ morkRowSpace* rowSpace = mRow_Space;
+ if ( rowSpace->mRowSpace_IndexCount ) // any indexes?
+ this->cut_all_index_entries(ev);
+
+ morkPool* pool = store->StorePool();
+ pool->CutRowCells(ev, this, /*newSize*/ 0, &store->mStore_Zone);
+ }
+}
+
+void
+morkRow::SetRow(morkEnv* ev, const morkRow* inSourceRow)
+{
+ // note inSourceRow might be in another DB, with a different store...
+ morkStore* store = this->GetRowSpaceStore(ev);
+ morkStore* srcStore = inSourceRow->GetRowSpaceStore(ev);
+ if ( store && srcStore )
+ {
+ if ( this->MaybeDirtySpaceStoreAndRow() )
+ {
+ this->SetRowRewrite();
+ this->NoteRowSetAll(ev);
+ }
+ morkRowSpace* rowSpace = mRow_Space;
+ mork_count indexes = rowSpace->mRowSpace_IndexCount; // any indexes?
+
+ mork_bool sameStore = ( store == srcStore ); // identical stores?
+ morkPool* pool = store->StorePool();
+ if ( pool->CutRowCells(ev, this, /*newSize*/ 0, &store->mStore_Zone) )
+ {
+ mork_fill fill = inSourceRow->mRow_Length;
+ if ( pool->AddRowCells(ev, this, fill, &store->mStore_Zone) )
+ {
+ morkCell* dst = mRow_Cells;
+ morkCell* dstEnd = dst + mRow_Length;
+
+ const morkCell* src = inSourceRow->mRow_Cells;
+ const morkCell* srcEnd = src + fill;
+ --dst; --src; // prepare both for preincrement:
+
+ while ( ++dst < dstEnd && ++src < srcEnd && ev->Good() )
+ {
+ morkAtom* atom = src->mCell_Atom;
+ mork_column dstCol = src->GetColumn();
+ // Note we modify the mCell_Atom slot directly instead of using
+ // morkCell::SetAtom(), because we know it starts equal to nil.
+
+ if ( sameStore ) // source and dest in same store?
+ {
+ // next line equivalent to inline morkCell::SetCellDirty():
+ dst->SetCellColumnDirty(dstCol);
+ dst->mCell_Atom = atom;
+ if ( atom ) // another ref to non-nil atom?
+ atom->AddCellUse(ev);
+ }
+ else // need to dup items from src store in a dest store
+ {
+ dstCol = store->CopyToken(ev, dstCol, srcStore);
+ if ( dstCol )
+ {
+ // next line equivalent to inline morkCell::SetCellDirty():
+ dst->SetCellColumnDirty(dstCol);
+ atom = store->CopyAtom(ev, atom);
+ dst->mCell_Atom = atom;
+ if ( atom ) // another ref?
+ atom->AddCellUse(ev);
+ }
+ }
+ if ( indexes && atom )
+ {
+ mork_aid atomAid = atom->GetBookAtomAid();
+ if ( atomAid )
+ {
+ morkAtomRowMap* map = rowSpace->FindMap(ev, dstCol);
+ if ( map )
+ map->AddAid(ev, atomAid, this);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+morkRow::AddRow(morkEnv* ev, const morkRow* inSourceRow)
+{
+ if ( mRow_Length ) // any existing cells we might need to keep?
+ {
+ ev->StubMethodOnlyError();
+ }
+ else
+ this->SetRow(ev, inSourceRow); // just exactly duplicate inSourceRow
+}
+
+void
+morkRow::OnZeroRowGcUse(morkEnv* ev)
+// OnZeroRowGcUse() is called when CutRowGcUse() returns zero.
+{
+ MORK_USED_1(ev);
+ // ev->NewWarning("need to implement OnZeroRowGcUse");
+}
+
+void
+morkRow::DirtyAllRowContent(morkEnv* ev)
+{
+ MORK_USED_1(ev);
+
+ if ( this->MaybeDirtySpaceStoreAndRow() )
+ {
+ this->SetRowRewrite();
+ this->NoteRowSetAll(ev);
+ }
+ morkCell* cells = mRow_Cells;
+ if ( cells )
+ {
+ morkCell* end = cells + mRow_Length;
+ --cells; // prepare for preincrement:
+ while ( ++cells < end )
+ {
+ cells->SetCellDirty();
+ }
+ }
+}
+
+morkStore*
+morkRow::GetRowSpaceStore(morkEnv* ev) const
+{
+ morkRowSpace* rowSpace = mRow_Space;
+ if ( rowSpace )
+ {
+ morkStore* store = rowSpace->mSpace_Store;
+ if ( store )
+ {
+ if ( store->IsStore() )
+ {
+ return store;
+ }
+ else
+ store->NonStoreTypeError(ev);
+ }
+ else
+ ev->NilPointerError();
+ }
+ else
+ ev->NilPointerError();
+
+ return (morkStore*) 0;
+}
+
+void morkRow::CutColumn(morkEnv* ev, mdb_column inColumn)
+{
+ mork_pos pos = -1;
+ morkCell* cell = this->GetCell(ev, inColumn, &pos);
+ if ( cell )
+ {
+ morkStore* store = this->GetRowSpaceStore(ev);
+ if ( store )
+ {
+ if ( this->MaybeDirtySpaceStoreAndRow() && !this->IsRowRewrite() )
+ this->NoteRowCutCol(ev, inColumn);
+
+ morkRowSpace* rowSpace = mRow_Space;
+ morkAtomRowMap* map = ( rowSpace->mRowSpace_IndexCount )?
+ rowSpace->FindMap(ev, inColumn) : (morkAtomRowMap*) 0;
+ if ( map ) // this row attribute is indexed by row space?
+ {
+ morkAtom* oldAtom = cell->mCell_Atom;
+ if ( oldAtom ) // need to cut an entry from the index?
+ {
+ mork_aid oldAid = oldAtom->GetBookAtomAid();
+ if ( oldAid ) // cut old row attribute from row index in space?
+ map->CutAid(ev, oldAid);
+ }
+ }
+
+ morkPool* pool = store->StorePool();
+ cell->SetAtom(ev, (morkAtom*) 0, pool);
+
+ mork_fill fill = mRow_Length; // should not be zero
+ MORK_ASSERT(fill);
+ if ( fill ) // index < fill for last cell exists?
+ {
+ mork_fill last = fill - 1; // index of last cell in row
+
+ if ( pos < (mork_pos)last ) // need to move cells following cut cell?
+ {
+ morkCell* lastCell = mRow_Cells + last;
+ mork_count after = last - pos; // cell count after cut cell
+ morkCell* next = cell + 1; // next cell after cut cell
+ MORK_MEMMOVE(cell, next, after * sizeof(morkCell));
+ lastCell->SetColumnAndChange(0, 0);
+ lastCell->mCell_Atom = 0;
+ }
+
+ if ( ev->Good() )
+ pool->CutRowCells(ev, this, fill - 1, &store->mStore_Zone);
+ }
+ }
+ }
+}
+
+morkAtom* morkRow::GetColumnAtom(morkEnv* ev, mdb_column inColumn)
+{
+ if ( ev->Good() )
+ {
+ mork_pos pos = -1;
+ morkCell* cell = this->GetCell(ev, inColumn, &pos);
+ if ( cell )
+ return cell->mCell_Atom;
+ }
+ return (morkAtom*) 0;
+}
+
+void morkRow::AddColumn(morkEnv* ev, mdb_column inColumn,
+ const mdbYarn* inYarn, morkStore* ioStore)
+{
+ if ( ev->Good() )
+ {
+ mork_pos pos = -1;
+ morkCell* cell = this->GetCell(ev, inColumn, &pos);
+ morkCell* oldCell = cell; // need to know later whether new
+ if ( !cell ) // column does not yet exist?
+ cell = this->NewCell(ev, inColumn, &pos, ioStore);
+
+ if ( cell )
+ {
+ morkAtom* oldAtom = cell->mCell_Atom;
+
+ morkAtom* atom = ioStore->YarnToAtom(ev, inYarn, true /* create */);
+ if ( atom && atom != oldAtom )
+ {
+ morkRowSpace* rowSpace = mRow_Space;
+ morkAtomRowMap* map = ( rowSpace->mRowSpace_IndexCount )?
+ rowSpace->FindMap(ev, inColumn) : (morkAtomRowMap*) 0;
+
+ if ( map ) // inColumn is indexed by row space?
+ {
+ if ( oldAtom && oldAtom != atom ) // cut old cell from index?
+ {
+ mork_aid oldAid = oldAtom->GetBookAtomAid();
+ if ( oldAid ) // cut old row attribute from row index in space?
+ map->CutAid(ev, oldAid);
+ }
+ }
+
+ cell->SetAtom(ev, atom, ioStore->StorePool()); // refcounts atom
+
+ if ( oldCell ) // we changed a pre-existing cell in the row?
+ {
+ ++mRow_Seed;
+ if ( this->MaybeDirtySpaceStoreAndRow() && !this->IsRowRewrite() )
+ this->NoteRowAddCol(ev, inColumn);
+ }
+
+ if ( map ) // inColumn is indexed by row space?
+ {
+ mork_aid newAid = atom->GetBookAtomAid();
+ if ( newAid ) // add new row attribute to row index in space?
+ map->AddAid(ev, newAid, this);
+ }
+ }
+ }
+ }
+}
+
+morkRowCellCursor*
+morkRow::NewRowCellCursor(morkEnv* ev, mdb_pos inPos)
+{
+ morkRowCellCursor* outCursor = 0;
+ if ( ev->Good() )
+ {
+ morkStore* store = this->GetRowSpaceStore(ev);
+ if ( store )
+ {
+ morkRowObject* rowObj = this->AcquireRowObject(ev, store);
+ if ( rowObj )
+ {
+ nsIMdbHeap* heap = store->mPort_Heap;
+ morkRowCellCursor* cursor = new(*heap, ev)
+ morkRowCellCursor(ev, morkUsage::kHeap, heap, rowObj);
+
+ if ( cursor )
+ {
+ if ( ev->Good() )
+ {
+ cursor->mRowCellCursor_Col = inPos;
+ outCursor = cursor;
+ }
+ else
+ cursor->CutStrongRef(ev->mEnv_SelfAsMdbEnv);
+ }
+ rowObj->Release(); // always cut ref (cursor has its own)
+ }
+ }
+ }
+ return outCursor;
+}
+
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+