summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/db/mork/morkTable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/db/mork/morkTable.cpp')
-rw-r--r--comm/mailnews/db/mork/morkTable.cpp1415
1 files changed, 1415 insertions, 0 deletions
diff --git a/comm/mailnews/db/mork/morkTable.cpp b/comm/mailnews/db/mork/morkTable.cpp
new file mode 100644
index 0000000000..ee27ff1328
--- /dev/null
+++ b/comm/mailnews/db/mork/morkTable.cpp
@@ -0,0 +1,1415 @@
+/* -*- 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 _MORKMAP_
+# include "morkMap.h"
+#endif
+
+#ifndef _MORKENV_
+# include "morkEnv.h"
+#endif
+
+#ifndef _MORKTABLE_
+# include "morkTable.h"
+#endif
+
+#ifndef _MORKSTORE_
+# include "morkStore.h"
+#endif
+
+#ifndef _MORKROWSPACE_
+# include "morkRowSpace.h"
+#endif
+
+#ifndef _MORKARRAY_
+# include "morkArray.h"
+#endif
+
+#ifndef _MORKROW_
+# include "morkRow.h"
+#endif
+
+#ifndef _MORKTABLEROWCURSOR_
+# include "morkTableRowCursor.h"
+#endif
+
+#ifndef _MORKROWOBJECT_
+# include "morkRowObject.h"
+#endif
+
+// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void morkTable::CloseMorkNode(
+ morkEnv* ev) /*i*/ // CloseTable() only if open
+{
+ if (this->IsOpenNode()) {
+ morkObject::CloseMorkNode(ev); // give base class a chance.
+ this->MarkClosing();
+ this->CloseTable(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkTable::~morkTable() /*i*/ // assert CloseTable() executed earlier
+{
+ CloseMorkNode(mMorkEnv);
+ MORK_ASSERT(this->IsShutNode());
+ MORK_ASSERT(mTable_Store == 0);
+ MORK_ASSERT(mTable_RowSpace == 0);
+}
+
+/*public non-poly*/
+morkTable::morkTable(
+ morkEnv* ev, /*i*/
+ const morkUsage& inUsage, nsIMdbHeap* ioHeap, morkStore* ioStore,
+ nsIMdbHeap* ioSlotHeap, morkRowSpace* ioRowSpace,
+ const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
+ mork_tid inTid, mork_kind inKind, mork_bool inMustBeUnique)
+ : morkObject(ev, inUsage, ioHeap, (mork_color)inTid, (morkHandle*)0),
+ mTable_Store(0),
+ mTable_RowSpace(0),
+ mTable_MetaRow(0)
+
+ ,
+ mTable_RowMap(0)
+ // , mTable_RowMap(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap,
+ // morkTable_kStartRowMapSlotCount)
+ ,
+ mTable_RowArray(ev, morkUsage::kMember, (nsIMdbHeap*)0,
+ morkTable_kStartRowArraySize, ioSlotHeap)
+
+ ,
+ mTable_ChangeList(),
+ mTable_ChangesCount(0),
+ mTable_ChangesMax(3) // any very small number greater than zero
+
+ ,
+ mTable_Kind(inKind)
+
+ ,
+ mTable_Flags(0),
+ mTable_Priority(morkPriority_kLo) // NOT high priority
+ ,
+ mTable_GcUses(0),
+ mTable_Pad(0) {
+ this->mLink_Next = 0;
+ this->mLink_Prev = 0;
+
+ if (ev->Good()) {
+ if (ioStore && ioSlotHeap && ioRowSpace) {
+ if (inKind) {
+ if (inMustBeUnique) this->SetTableUnique();
+ mTable_Store = ioStore;
+ mTable_RowSpace = ioRowSpace;
+ if (inOptionalMetaRowOid)
+ mTable_MetaRowOid = *inOptionalMetaRowOid;
+ else {
+ mTable_MetaRowOid.mOid_Scope = 0;
+ mTable_MetaRowOid.mOid_Id = morkRow_kMinusOneRid;
+ }
+ if (ev->Good()) {
+ if (this->MaybeDirtySpaceStoreAndTable())
+ this->SetTableRewrite(); // everything is dirty
+
+ mNode_Derived = morkDerived_kTable;
+ }
+ this->MaybeDirtySpaceStoreAndTable(); // new table might dirty store
+ } else
+ ioRowSpace->ZeroKindError(ev);
+ } else
+ ev->NilPointerError();
+ }
+}
+
+NS_IMPL_ISUPPORTS_INHERITED(morkTable, morkObject, nsIMdbTable)
+
+/*public non-poly*/ void morkTable::CloseTable(
+ morkEnv* ev) /*i*/ // called by CloseMorkNode();
+{
+ if (this->IsNode()) {
+ morkRowMap::SlotStrongRowMap((morkRowMap*)0, ev, &mTable_RowMap);
+ // mTable_RowMap.CloseMorkNode(ev);
+ mTable_RowArray.CloseMorkNode(ev);
+ mTable_Store = 0;
+ mTable_RowSpace = 0;
+ this->MarkShut();
+ } else
+ this->NonNodeError(ev);
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+// { ===== begin nsIMdbCollection methods =====
+
+// { ----- begin attribute methods -----
+NS_IMETHODIMP
+morkTable::GetSeed(nsIMdbEnv* mev,
+ mdb_seed* outSeed) // member change count
+{
+ nsresult outErr = NS_OK;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ *outSeed = mTable_RowArray.mArray_Seed;
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::GetCount(nsIMdbEnv* mev,
+ mdb_count* outCount) // member count
+{
+ NS_ENSURE_ARG_POINTER(outCount);
+ *outCount = mTable_RowArray.mArray_Fill;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+morkTable::GetPort(nsIMdbEnv* mev,
+ nsIMdbPort** acqPort) // collection container
+{
+ (void)morkEnv::FromMdbEnv(mev);
+ NS_ENSURE_ARG_POINTER(acqPort);
+ *acqPort = mTable_Store;
+ return NS_OK;
+}
+// } ----- end attribute methods -----
+
+// { ----- begin cursor methods -----
+NS_IMETHODIMP
+morkTable::GetCursor( // make a cursor starting iter at inMemberPos
+ nsIMdbEnv* mev, // context
+ mdb_pos inMemberPos, // zero-based ordinal pos of member in collection
+ nsIMdbCursor** acqCursor) // acquire new cursor instance
+{
+ return this->GetTableRowCursor(mev, inMemberPos,
+ (nsIMdbTableRowCursor**)acqCursor);
+}
+// } ----- end cursor methods -----
+
+// { ----- begin ID methods -----
+NS_IMETHODIMP
+morkTable::GetOid(nsIMdbEnv* mev,
+ mdbOid* outOid) // read object identity
+{
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ GetTableOid(ev, outOid);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+morkTable::BecomeContent(nsIMdbEnv* mev,
+ const mdbOid* inOid) // exchange content
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+ // remember table->MaybeDirtySpaceStoreAndTable();
+}
+
+// } ----- end ID methods -----
+
+// { ----- begin activity dropping methods -----
+NS_IMETHODIMP
+morkTable::DropActivity( // tell collection usage no longer expected
+ nsIMdbEnv* mev) {
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// } ----- end activity dropping methods -----
+
+// } ===== end nsIMdbCollection methods =====
+
+// { ===== begin nsIMdbTable methods =====
+
+// { ----- begin attribute methods -----
+
+NS_IMETHODIMP
+morkTable::SetTablePriority(nsIMdbEnv* mev, mdb_priority inPrio) {
+ nsresult outErr = NS_OK;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ if (inPrio > morkPriority_kMax) inPrio = morkPriority_kMax;
+
+ mTable_Priority = inPrio;
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::GetTablePriority(nsIMdbEnv* mev, mdb_priority* outPrio) {
+ nsresult outErr = NS_OK;
+ mork_priority prio = 0;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ prio = mTable_Priority;
+ if (prio > morkPriority_kMax) {
+ prio = morkPriority_kMax;
+ mTable_Priority = prio;
+ }
+ outErr = ev->AsErr();
+ }
+ if (outPrio) *outPrio = prio;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::GetTableBeVerbose(nsIMdbEnv* mev, mdb_bool* outBeVerbose) {
+ NS_ENSURE_ARG_POINTER(outBeVerbose);
+ *outBeVerbose = IsTableVerbose();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+morkTable::SetTableBeVerbose(nsIMdbEnv* mev, mdb_bool inBeVerbose) {
+ nsresult outErr = NS_OK;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ if (inBeVerbose)
+ SetTableVerbose();
+ else
+ ClearTableVerbose();
+
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::GetTableIsUnique(nsIMdbEnv* mev, mdb_bool* outIsUnique) {
+ NS_ENSURE_ARG_POINTER(outIsUnique);
+ *outIsUnique = IsTableUnique();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+morkTable::GetTableKind(nsIMdbEnv* mev, mdb_kind* outTableKind) {
+ NS_ENSURE_ARG_POINTER(outTableKind);
+ *outTableKind = mTable_Kind;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+morkTable::GetRowScope(nsIMdbEnv* mev, mdb_scope* outRowScope) {
+ nsresult outErr = NS_OK;
+ mdb_scope rowScope = 0;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ if (mTable_RowSpace)
+ rowScope = mTable_RowSpace->SpaceScope();
+ else
+ NilRowSpaceError(ev);
+
+ outErr = ev->AsErr();
+ }
+ if (outRowScope) *outRowScope = rowScope;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::GetMetaRow(
+ nsIMdbEnv* mev,
+ const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
+ mdbOid* outOid, // output meta row oid, can be nil to suppress output
+ nsIMdbRow** acqRow) // acquire table's unique singleton meta row
+// The purpose of a meta row is to support the persistent recording of
+// meta info about a table as cells put into the distinguished meta row.
+// Each table has exactly one meta row, which is not considered a member
+// of the collection of rows inside the table. The only way to tell
+// whether a row is a meta row is by the fact that it is returned by this
+// GetMetaRow() method from some table. Otherwise nothing distinguishes
+// a meta row from any other row. A meta row can be used anyplace that
+// any other row can be used, and can even be put into other tables (or
+// the same table) as a table member, if this is useful for some reason.
+// The first attempt to access a table's meta row using GetMetaRow() will
+// cause the meta row to be created if it did not already exist. When the
+// meta row is created, it will have the row oid that was previously
+// requested for this table's meta row; or if no oid was ever explicitly
+// specified for this meta row, then a unique oid will be generated in
+// the row scope named "metaScope" (so obviously MDB clients should not
+// manually allocate any row IDs from that special meta scope namespace).
+// The meta row oid can be specified either when the table is created, or
+// else the first time that GetMetaRow() is called, by passing a non-nil
+// pointer to an oid for parameter inOptionalMetaRowOid. The meta row's
+// actual oid is returned in outOid (if this is a non-nil pointer), and
+// it will be different from inOptionalMetaRowOid when the meta row was
+// already given a different oid earlier.
+{
+ nsresult outErr = NS_OK;
+ nsIMdbRow* outRow = 0;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ morkRow* row = GetMetaRow(ev, inOptionalMetaRowOid);
+ if (row && ev->Good()) {
+ if (outOid) *outOid = row->mRow_Oid;
+
+ outRow = row->AcquireRowHandle(ev, mTable_Store);
+ }
+ outErr = ev->AsErr();
+ }
+ if (acqRow) *acqRow = outRow;
+
+ if (ev->Bad() && outOid) {
+ outOid->mOid_Scope = 0;
+ outOid->mOid_Id = morkRow_kMinusOneRid;
+ }
+ return outErr;
+}
+
+// } ----- end attribute methods -----
+
+// { ----- begin cursor methods -----
+NS_IMETHODIMP
+morkTable::GetTableRowCursor( // make a cursor, starting iteration at inRowPos
+ nsIMdbEnv* mev, // context
+ mdb_pos inRowPos, // zero-based ordinal position of row in table
+ nsIMdbTableRowCursor** acqCursor) // acquire new cursor instance
+{
+ nsresult outErr = NS_OK;
+ nsIMdbTableRowCursor* outCursor = 0;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ morkTableRowCursor* cursor = NewTableRowCursor(ev, inRowPos);
+ if (cursor) {
+ if (ev->Good()) {
+ // cursor->mCursor_Seed = (mork_seed) inRowPos;
+ outCursor = cursor;
+ outCursor->AddRef();
+ }
+ }
+
+ outErr = ev->AsErr();
+ }
+ if (acqCursor) *acqCursor = outCursor;
+ return outErr;
+}
+// } ----- end row position methods -----
+
+// { ----- begin row position methods -----
+NS_IMETHODIMP
+morkTable::PosToOid( // get row member for a table position
+ nsIMdbEnv* mev, // context
+ mdb_pos inRowPos, // zero-based ordinal position of row in table
+ mdbOid* outOid) // row oid at the specified position
+{
+ nsresult outErr = NS_OK;
+ mdbOid roid;
+ roid.mOid_Scope = 0;
+ roid.mOid_Id = (mork_id)-1;
+
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ morkRow* row = SafeRowAt(ev, inRowPos);
+ if (row) roid = row->mRow_Oid;
+
+ outErr = ev->AsErr();
+ }
+ if (outOid) *outOid = roid;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::OidToPos( // test for the table position of a row member
+ nsIMdbEnv* mev, // context
+ const mdbOid* inOid, // row to find in table
+ mdb_pos* outPos) // zero-based ordinal position of row in table
+{
+ nsresult outErr = NS_OK;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ mork_pos pos = ArrayHasOid(ev, inOid);
+ if (outPos) *outPos = pos;
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::PosToRow( // get row member for a table position
+ nsIMdbEnv* mev, // context
+ mdb_pos inRowPos, // zero-based ordinal position of row in table
+ nsIMdbRow** acqRow) // acquire row at table position inRowPos
+{
+ nsresult outErr = NS_OK;
+ nsIMdbRow* outRow = 0;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ morkRow* row = SafeRowAt(ev, inRowPos);
+ if (row && mTable_Store) outRow = row->AcquireRowHandle(ev, mTable_Store);
+
+ outErr = ev->AsErr();
+ }
+ if (acqRow) *acqRow = outRow;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::RowToPos( // test for the table position of a row member
+ nsIMdbEnv* mev, // context
+ nsIMdbRow* ioRow, // row to find in table
+ mdb_pos* outPos) // zero-based ordinal position of row in table
+{
+ nsresult outErr = NS_OK;
+ mork_pos pos = -1;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ morkRowObject* row = (morkRowObject*)ioRow;
+ pos = ArrayHasOid(ev, &row->mRowObject_Row->mRow_Oid);
+ outErr = ev->AsErr();
+ }
+ if (outPos) *outPos = pos;
+ return outErr;
+}
+
+// Note that HasRow() performs the inverse oid->pos mapping
+// } ----- end row position methods -----
+
+// { ----- begin oid set methods -----
+NS_IMETHODIMP
+morkTable::AddOid( // make sure the row with inOid is a table member
+ nsIMdbEnv* mev, // context
+ const mdbOid* inOid) // row to ensure membership in table
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkTable::HasOid( // test for the table position of a row member
+ nsIMdbEnv* mev, // context
+ const mdbOid* inOid, // row to find in table
+ mdb_bool* outHasOid) // whether inOid is a member row
+{
+ nsresult outErr = NS_OK;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ if (outHasOid) *outHasOid = MapHasOid(ev, inOid);
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::CutOid( // make sure the row with inOid is not a member
+ nsIMdbEnv* mev, // context
+ const mdbOid* inOid) // row to remove from table
+{
+ nsresult outErr = NS_OK;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ if (inOid && mTable_Store) {
+ morkRow* row = mTable_Store->GetRow(ev, inOid);
+ if (row) CutRow(ev, row);
+ } else
+ ev->NilPointerError();
+
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+// } ----- end oid set methods -----
+
+// { ----- begin row set methods -----
+NS_IMETHODIMP
+morkTable::NewRow( // create a new row instance in table
+ nsIMdbEnv* mev, // context
+ mdbOid* ioOid, // please use zero (unbound) rowId for db-assigned IDs
+ nsIMdbRow** acqRow) // create new row
+{
+ nsresult outErr = NS_OK;
+ nsIMdbRow* outRow = 0;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ if (ioOid && mTable_Store) {
+ morkRow* row = 0;
+ if (ioOid->mOid_Id == morkRow_kMinusOneRid)
+ row = mTable_Store->NewRow(ev, ioOid->mOid_Scope);
+ else
+ row = mTable_Store->NewRowWithOid(ev, ioOid);
+
+ if (row && AddRow(ev, row))
+ outRow = row->AcquireRowHandle(ev, mTable_Store);
+ } else
+ ev->NilPointerError();
+
+ outErr = ev->AsErr();
+ }
+ if (acqRow) *acqRow = outRow;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::AddRow( // make sure the row with inOid is a table member
+ nsIMdbEnv* mev, // context
+ nsIMdbRow* ioRow) // row to ensure membership in table
+{
+ nsresult outErr = NS_OK;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ morkRowObject* rowObj = (morkRowObject*)ioRow;
+ morkRow* row = rowObj->mRowObject_Row;
+ AddRow(ev, row);
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::HasRow( // test for the table position of a row member
+ nsIMdbEnv* mev, // context
+ nsIMdbRow* ioRow, // row to find in table
+ mdb_bool* outBool) // zero-based ordinal position of row in table
+{
+ nsresult outErr = NS_OK;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ morkRowObject* rowObj = (morkRowObject*)ioRow;
+ morkRow* row = rowObj->mRowObject_Row;
+ if (outBool) *outBool = MapHasOid(ev, &row->mRow_Oid);
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::CutRow( // make sure the row with inOid is not a member
+ nsIMdbEnv* mev, // context
+ nsIMdbRow* ioRow) // row to remove from table
+{
+ nsresult outErr = NS_OK;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ morkRowObject* rowObj = (morkRowObject*)ioRow;
+ morkRow* row = rowObj->mRowObject_Row;
+ CutRow(ev, row);
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::CutAllRows( // remove all rows from the table
+ nsIMdbEnv* mev) // context
+{
+ nsresult outErr = NS_OK;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ CutAllRows(ev);
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+// } ----- end row set methods -----
+
+// { ----- begin searching methods -----
+NS_IMETHODIMP
+morkTable::FindRowMatches( // search variable number of sorted cols
+ nsIMdbEnv* mev, // context
+ const mdbYarn* inPrefix, // content to find as prefix in row's column cell
+ nsIMdbTableRowCursor** acqCursor) // set of matching rows
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkTable::GetSearchColumns( // query columns used by FindRowMatches()
+ nsIMdbEnv* mev, // context
+ mdb_count* outCount, // context
+ mdbColumnSet* outColSet) // caller supplied space to put columns
+// GetSearchColumns() returns the columns actually searched when the
+// FindRowMatches() method is called. No more than mColumnSet_Count
+// slots of mColumnSet_Columns will be written, since mColumnSet_Count
+// indicates how many slots are present in the column array. The
+// actual number of search column used by the table is returned in
+// the outCount parameter; if this number exceeds mColumnSet_Count,
+// then a caller needs a bigger array to read the entire column set.
+// The minimum of mColumnSet_Count and outCount is the number slots
+// in mColumnSet_Columns that were actually written by this method.
+//
+// Callers are expected to change this set of columns by calls to
+// nsIMdbTable::SearchColumnsHint() or SetSearchSorting(), or both.
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+// } ----- end searching methods -----
+
+// { ----- begin hinting methods -----
+NS_IMETHODIMP
+morkTable::SearchColumnsHint( // advise re future expected search cols
+ nsIMdbEnv* mev, // context
+ const mdbColumnSet* inColumnSet) // columns likely to be searched
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkTable::SortColumnsHint( // advise re future expected sort columns
+ nsIMdbEnv* mev, // context
+ const mdbColumnSet* inColumnSet) // columns for likely sort requests
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkTable::StartBatchChangeHint( // advise before many adds and cuts
+ nsIMdbEnv* mev, // context
+ const void* inLabel) // intend unique address to match end call
+// If batch starts nest by virtue of nesting calls in the stack, then
+// the address of a local variable makes a good batch start label that
+// can be used at batch end time, and such addresses remain unique.
+{
+ // we don't do anything here.
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+morkTable::EndBatchChangeHint( // advise before many adds and cuts
+ nsIMdbEnv* mev, // context
+ const void* inLabel) // label matching start label
+// Suppose a table is maintaining one or many sort orders for a table,
+// so that every row added to the table must be inserted in each sort,
+// and every row cut must be removed from each sort. If a db client
+// intends to make many such changes before needing any information
+// about the order or positions of rows inside a table, then a client
+// might tell the table to start batch changes in order to disable
+// sorting of rows for the interim. Presumably a table will then do
+// a full sort of all rows at need when the batch changes end, or when
+// a surprise request occurs for row position during batch changes.
+{
+ // we don't do anything here.
+ return NS_OK;
+}
+// } ----- end hinting methods -----
+
+// { ----- begin sorting methods -----
+// sorting: note all rows are assumed sorted by row ID as a secondary
+// sort following the primary column sort, when table rows are sorted.
+
+NS_IMETHODIMP
+morkTable::CanSortColumn( // query which column is currently used for sorting
+ nsIMdbEnv* mev, // context
+ mdb_column inColumn, // column to query sorting potential
+ mdb_bool* outCanSort) // whether the column can be sorted
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkTable::GetSorting( // view same table in particular sorting
+ nsIMdbEnv* mev, // context
+ mdb_column inColumn, // requested new column for sorting table
+ nsIMdbSorting** acqSorting) // acquire sorting for column
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkTable::SetSearchSorting( // use this sorting in FindRowMatches()
+ nsIMdbEnv* mev, // context
+ mdb_column inColumn, // often same as nsIMdbSorting::GetSortColumn()
+ nsIMdbSorting* ioSorting) // requested sorting for some column
+// SetSearchSorting() attempts to inform the table that ioSorting
+// should be used during calls to FindRowMatches() for searching
+// the column which is actually sorted by ioSorting. This method
+// is most useful in conjunction with nsIMdbSorting::SetCompare(),
+// because otherwise a caller would not be able to override the
+// comparison ordering method used during searches. Note that some
+// database implementations might be unable to use an arbitrarily
+// specified sort order, either due to schema or runtime interface
+// constraints, in which case ioSorting might not actually be used.
+// Presumably ioSorting is an instance that was returned from some
+// earlier call to nsIMdbTable::GetSorting(). A caller can also
+// use nsIMdbTable::SearchColumnsHint() to specify desired change
+// in which columns are sorted and searched by FindRowMatches().
+//
+// A caller can pass a nil pointer for ioSorting to request that
+// column inColumn no longer be used at all by FindRowMatches().
+// But when ioSorting is non-nil, then inColumn should match the
+// column actually sorted by ioSorting; when these do not agree,
+// implementations are instructed to give precedence to the column
+// specified by ioSorting (so this means callers might just pass
+// zero for inColumn when ioSorting is also provided, since then
+// inColumn is both redundant and ignored).
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// } ----- end sorting methods -----
+
+// { ----- begin moving methods -----
+// moving a row does nothing unless a table is currently unsorted
+
+NS_IMETHODIMP
+morkTable::MoveOid( // change position of row in unsorted table
+ nsIMdbEnv* mev, // context
+ const mdbOid* inOid, // row oid to find in table
+ mdb_pos inHintFromPos, // suggested hint regarding start position
+ mdb_pos inToPos, // desired new position for row inOid
+ mdb_pos* outActualPos) // actual new position of row in table
+{
+ nsresult outErr = NS_OK;
+ mdb_pos actualPos = -1; // meaning it was never found in table
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ if (inOid && mTable_Store) {
+ morkRow* row = mTable_Store->GetRow(ev, inOid);
+ if (row) actualPos = MoveRow(ev, row, inHintFromPos, inToPos);
+ } else
+ ev->NilPointerError();
+
+ outErr = ev->AsErr();
+ }
+ if (outActualPos) *outActualPos = actualPos;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkTable::MoveRow( // change position of row in unsorted table
+ nsIMdbEnv* mev, // context
+ nsIMdbRow* ioRow, // row oid to find in table
+ mdb_pos inHintFromPos, // suggested hint regarding start position
+ mdb_pos inToPos, // desired new position for row ioRow
+ mdb_pos* outActualPos) // actual new position of row in table
+{
+ mdb_pos actualPos = -1; // meaning it was never found in table
+ nsresult outErr = NS_OK;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if (ev) {
+ morkRowObject* rowObj = (morkRowObject*)ioRow;
+ morkRow* row = rowObj->mRowObject_Row;
+ actualPos = MoveRow(ev, row, inHintFromPos, inToPos);
+ outErr = ev->AsErr();
+ }
+ if (outActualPos) *outActualPos = actualPos;
+ return outErr;
+}
+// } ----- end moving methods -----
+
+// { ----- begin index methods -----
+NS_IMETHODIMP
+morkTable::AddIndex( // create a sorting index for column if possible
+ nsIMdbEnv* mev, // context
+ mdb_column inColumn, // the column to sort by index
+ nsIMdbThumb** acqThumb) // acquire thumb for incremental index building
+// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+// then the index addition will be finished.
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkTable::CutIndex( // stop supporting a specific column index
+ nsIMdbEnv* mev, // context
+ mdb_column inColumn, // the column with index to be removed
+ nsIMdbThumb** acqThumb) // acquire thumb for incremental index destroy
+// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+// then the index removal will be finished.
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkTable::HasIndex( // query for current presence of a column index
+ nsIMdbEnv* mev, // context
+ mdb_column inColumn, // the column to investigate
+ mdb_bool* outHasIndex) // whether column has index for this column
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkTable::EnableIndexOnSort( // create an index for col on first sort
+ nsIMdbEnv* mev, // context
+ mdb_column inColumn) // the column to index if ever sorted
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkTable::QueryIndexOnSort( // check whether index on sort is enabled
+ nsIMdbEnv* mev, // context
+ mdb_column inColumn, // the column to investigate
+ mdb_bool* outIndexOnSort) // whether column has index-on-sort enabled
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkTable::DisableIndexOnSort( // prevent future index creation on sort
+ nsIMdbEnv* mev, // context
+ mdb_column inColumn) // the column to index if ever sorted
+{
+ NS_ASSERTION(false, "not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+// } ----- end index methods -----
+
+// } ===== end nsIMdbTable methods =====
+
+// we override these so that we'll use the xpcom add and release ref.
+#ifndef _MSC_VER
+mork_refs morkTable::AddStrongRef(nsIMdbEnv* ev) { return (mork_refs)AddRef(); }
+#endif
+
+mork_refs morkTable::AddStrongRef(morkEnv* ev) { return (mork_refs)AddRef(); }
+
+#ifndef _MSC_VER
+nsresult morkTable::CutStrongRef(nsIMdbEnv* ev) { return (nsresult)Release(); }
+#endif
+
+mork_refs morkTable::CutStrongRef(morkEnv* ev) { return (mork_refs)Release(); }
+
+mork_u2 morkTable::AddTableGcUse(morkEnv* ev) {
+ MORK_USED_1(ev);
+ if (mTable_GcUses < morkTable_kMaxTableGcUses) // not already maxed out?
+ ++mTable_GcUses;
+
+ return mTable_GcUses;
+}
+
+mork_u2 morkTable::CutTableGcUse(morkEnv* ev) {
+ if (mTable_GcUses) // any outstanding uses to cut?
+ {
+ if (mTable_GcUses < morkTable_kMaxTableGcUses) // not frozen at max?
+ --mTable_GcUses;
+ } else
+ this->TableGcUsesUnderflowWarning(ev);
+
+ return mTable_GcUses;
+}
+
+// table dirty handling more complex than morkNode::SetNodeDirty() etc.
+
+void morkTable::SetTableClean(morkEnv* ev) {
+ if (mTable_ChangeList.HasListMembers()) {
+ nsIMdbHeap* heap = mTable_Store->mPort_Heap;
+ mTable_ChangeList.CutAndZapAllListMembers(ev, heap); // forget changes
+ }
+ mTable_ChangesCount = 0;
+
+ mTable_Flags = 0;
+ this->SetNodeClean();
+}
+
+// notifications regarding table changes:
+
+void morkTable::NoteTableMoveRow(morkEnv* ev, morkRow* ioRow, mork_pos inPos) {
+ nsIMdbHeap* heap = mTable_Store->mPort_Heap;
+ if (this->IsTableRewrite() || this->HasChangeOverflow())
+ this->NoteTableSetAll(ev);
+ else {
+ morkTableChange* tableChange =
+ new (*heap, ev) morkTableChange(ev, ioRow, inPos);
+ if (tableChange) {
+ if (ev->Good()) {
+ mTable_ChangeList.PushTail(tableChange);
+ ++mTable_ChangesCount;
+ } else {
+ tableChange->ZapOldNext(ev, heap);
+ this->SetTableRewrite(); // just plan to write all table rows
+ }
+ }
+ }
+}
+
+void morkTable::note_row_move(morkEnv* ev, morkRow* ioRow, mork_pos inNewPos) {
+ if (this->IsTableRewrite() || this->HasChangeOverflow())
+ this->NoteTableSetAll(ev);
+ else {
+ nsIMdbHeap* heap = mTable_Store->mPort_Heap;
+ morkTableChange* tableChange =
+ new (*heap, ev) morkTableChange(ev, ioRow, inNewPos);
+ if (tableChange) {
+ if (ev->Good()) {
+ mTable_ChangeList.PushTail(tableChange);
+ ++mTable_ChangesCount;
+ } else {
+ tableChange->ZapOldNext(ev, heap);
+ this->NoteTableSetAll(ev);
+ }
+ }
+ }
+}
+
+void morkTable::note_row_change(morkEnv* ev, mork_change inChange,
+ morkRow* ioRow) {
+ if (this->IsTableRewrite() || this->HasChangeOverflow())
+ this->NoteTableSetAll(ev);
+ else {
+ nsIMdbHeap* heap = mTable_Store->mPort_Heap;
+ morkTableChange* tableChange =
+ new (*heap, ev) morkTableChange(ev, inChange, ioRow);
+ if (tableChange) {
+ if (ev->Good()) {
+ mTable_ChangeList.PushTail(tableChange);
+ ++mTable_ChangesCount;
+ } else {
+ tableChange->ZapOldNext(ev, heap);
+ this->NoteTableSetAll(ev);
+ }
+ }
+ }
+}
+
+void morkTable::NoteTableSetAll(morkEnv* ev) {
+ if (mTable_ChangeList.HasListMembers()) {
+ nsIMdbHeap* heap = mTable_Store->mPort_Heap;
+ mTable_ChangeList.CutAndZapAllListMembers(ev, heap); // forget changes
+ }
+ mTable_ChangesCount = 0;
+ this->SetTableRewrite();
+}
+
+/*static*/ void morkTable::TableGcUsesUnderflowWarning(morkEnv* ev) {
+ ev->NewWarning("mTable_GcUses underflow");
+}
+
+/*static*/ void morkTable::NonTableTypeError(morkEnv* ev) {
+ ev->NewError("non morkTable");
+}
+
+/*static*/ void morkTable::NonTableTypeWarning(morkEnv* ev) {
+ ev->NewWarning("non morkTable");
+}
+
+/*static*/ void morkTable::NilRowSpaceError(morkEnv* ev) {
+ ev->NewError("nil mTable_RowSpace");
+}
+
+mork_bool morkTable::MaybeDirtySpaceStoreAndTable() {
+ morkRowSpace* rowSpace = mTable_RowSpace;
+ if (rowSpace) {
+ morkStore* store = rowSpace->mSpace_Store;
+ if (store && store->mStore_CanDirty) {
+ store->SetStoreDirty();
+ rowSpace->mSpace_CanDirty = morkBool_kTrue;
+ }
+
+ if (rowSpace->mSpace_CanDirty) // first time being dirtied?
+ {
+ if (this->IsTableClean()) {
+ mork_count rowCount = this->GetRowCount();
+ mork_count oneThird = rowCount / 4; // one third of rows
+ if (oneThird > 0x07FFF) // more than half max u2?
+ oneThird = 0x07FFF;
+
+ mTable_ChangesMax = (mork_u2)oneThird;
+ }
+ this->SetTableDirty();
+ rowSpace->SetRowSpaceDirty();
+
+ return morkBool_kTrue;
+ }
+ }
+ return morkBool_kFalse;
+}
+
+morkRow* morkTable::GetMetaRow(morkEnv* ev,
+ const mdbOid* inOptionalMetaRowOid) {
+ morkRow* outRow = mTable_MetaRow;
+ if (!outRow) {
+ morkStore* store = mTable_Store;
+ mdbOid* oid = &mTable_MetaRowOid;
+ if (inOptionalMetaRowOid && !oid->mOid_Scope) *oid = *inOptionalMetaRowOid;
+
+ if (oid->mOid_Scope) // oid already recorded in table?
+ outRow = store->OidToRow(ev, oid);
+ else {
+ outRow = store->NewRow(ev, morkStore_kMetaScope);
+ if (outRow) // need to record new oid in table?
+ *oid = outRow->mRow_Oid;
+ }
+ mTable_MetaRow = outRow;
+ if (outRow) // need to note another use of this row?
+ {
+ outRow->AddRowGcUse(ev);
+
+ this->SetTableNewMeta();
+ if (this->IsTableClean()) // catch dirty status of meta row?
+ this->MaybeDirtySpaceStoreAndTable();
+ }
+ }
+
+ return outRow;
+}
+
+void morkTable::GetTableOid(morkEnv* ev, mdbOid* outOid) {
+ morkRowSpace* space = mTable_RowSpace;
+ if (space) {
+ outOid->mOid_Scope = space->SpaceScope();
+ outOid->mOid_Id = this->TableId();
+ } else
+ this->NilRowSpaceError(ev);
+}
+
+nsIMdbTable* morkTable::AcquireTableHandle(morkEnv* ev) {
+ AddRef();
+ return this;
+}
+
+mork_pos morkTable::ArrayHasOid(morkEnv* ev, const mdbOid* inOid) {
+ MORK_USED_1(ev);
+ mork_count count = mTable_RowArray.mArray_Fill;
+ mork_pos pos = -1;
+ while (++pos < (mork_pos)count) {
+ morkRow* row = (morkRow*)mTable_RowArray.At(pos);
+ MORK_ASSERT(row);
+ if (row && row->EqualOid(inOid)) {
+ return pos;
+ }
+ }
+ return -1;
+}
+
+mork_bool morkTable::MapHasOid(morkEnv* ev, const mdbOid* inOid) {
+ if (mTable_RowMap)
+ return (mTable_RowMap->GetOid(ev, inOid) != 0);
+ else
+ return (ArrayHasOid(ev, inOid) >= 0);
+}
+
+void morkTable::build_row_map(morkEnv* ev) {
+ morkRowMap* map = mTable_RowMap;
+ if (!map) {
+ mork_count count = mTable_RowArray.mArray_Fill + 3;
+ nsIMdbHeap* heap = mTable_Store->mPort_Heap;
+ map = new (*heap, ev) morkRowMap(ev, morkUsage::kHeap, heap, heap, count);
+ if (map) {
+ if (ev->Good()) {
+ mTable_RowMap = map; // put strong ref here
+ count = mTable_RowArray.mArray_Fill;
+ mork_pos pos = -1;
+ while (++pos < (mork_pos)count) {
+ morkRow* row = (morkRow*)mTable_RowArray.At(pos);
+ if (row && row->IsRow())
+ map->AddRow(ev, row);
+ else
+ row->NonRowTypeError(ev);
+ }
+ } else
+ map->CutStrongRef(ev);
+ }
+ }
+}
+
+morkRow* morkTable::find_member_row(morkEnv* ev, morkRow* ioRow) {
+ if (mTable_RowMap)
+ return mTable_RowMap->GetRow(ev, ioRow);
+ else {
+ mork_count count = mTable_RowArray.mArray_Fill;
+ mork_pos pos = -1;
+ while (++pos < (mork_pos)count) {
+ morkRow* row = (morkRow*)mTable_RowArray.At(pos);
+ if (row == ioRow) return row;
+ }
+ }
+ return (morkRow*)0;
+}
+
+mork_pos morkTable::MoveRow(
+ morkEnv* ev, morkRow* ioRow, // change row position
+ mork_pos inHintFromPos, // suggested hint regarding start position
+ mork_pos inToPos) // desired new position for row ioRow
+// MoveRow() returns the actual position of ioRow afterwards; this
+// position is -1 if and only if ioRow was not found as a member.
+{
+ mork_pos outPos = -1; // means ioRow was not a table member
+ mork_bool canDirty = (this->IsTableClean())
+ ? this->MaybeDirtySpaceStoreAndTable()
+ : morkBool_kTrue;
+
+ morkRow** rows = (morkRow**)mTable_RowArray.mArray_Slots;
+ mork_count count = mTable_RowArray.mArray_Fill;
+ if (count && rows && ev->Good()) // any members at all? no errors?
+ {
+ mork_pos lastPos = count - 1; // index of last row slot
+
+ if (inToPos > lastPos) // beyond last used array slot?
+ inToPos = lastPos; // put row into last available slot
+ else if (inToPos < 0) // before first usable slot?
+ inToPos = 0; // put row in very first slow
+
+ if (inHintFromPos > lastPos) // beyond last used array slot?
+ inHintFromPos = lastPos; // seek row in last available slot
+ else if (inHintFromPos < 0) // before first usable slot?
+ inHintFromPos = 0; // seek row in very first slow
+
+ morkRow** fromSlot = 0; // becomes nonzero of ioRow is ever found
+ morkRow** rowsEnd = rows + count; // one past last used array slot
+
+ if (inHintFromPos <= 0) // start of table? just scan for row?
+ {
+ morkRow** cursor = rows - 1; // before first array slot
+ while (++cursor < rowsEnd) {
+ if (*cursor == ioRow) {
+ fromSlot = cursor;
+ break; // end while loop
+ }
+ }
+ } else // search near the start position and work outwards
+ {
+ morkRow** lo = rows + inHintFromPos; // lowest search point
+ morkRow** hi = lo; // highest search point starts at lowest point
+
+ // Seek ioRow in spiral widening search below and above inHintFromPos.
+ // This is faster when inHintFromPos is at all accurate, but is slower
+ // than a straightforward scan when inHintFromPos is nearly random.
+
+ while (lo >= rows || hi < rowsEnd) // keep searching?
+ {
+ if (lo >= rows) // low direction search still feasible?
+ {
+ if (*lo == ioRow) // actually found the row?
+ {
+ fromSlot = lo;
+ break; // end while loop
+ }
+ --lo; // advance further lower
+ }
+ if (hi < rowsEnd) // high direction search still feasible?
+ {
+ if (*hi == ioRow) // actually found the row?
+ {
+ fromSlot = hi;
+ break; // end while loop
+ }
+ ++hi; // advance further higher
+ }
+ }
+ }
+
+ if (fromSlot) // ioRow was found as a table member?
+ {
+ outPos = fromSlot - rows; // actual position where row was found
+ if (outPos != inToPos) // actually need to move this row?
+ {
+ morkRow** toSlot = rows + inToPos; // slot where row must go
+
+ ++mTable_RowArray.mArray_Seed; // we modify the array now:
+
+ if (fromSlot < toSlot) // row is moving upwards?
+ {
+ morkRow** up = fromSlot; // leading pointer going upward
+ while (++up <= toSlot) // have not gone above destination?
+ {
+ *fromSlot = *up; // shift down one
+ fromSlot = up; // shift trailing pointer up
+ }
+ } else // ( fromSlot > toSlot ) // row is moving downwards
+ {
+ morkRow** down = fromSlot; // leading pointer going downward
+ while (--down >= toSlot) // have not gone below destination?
+ {
+ *fromSlot = *down; // shift up one
+ fromSlot = down; // shift trailing pointer
+ }
+ }
+ *toSlot = ioRow;
+ outPos = inToPos; // okay, we actually moved the row here
+
+ if (canDirty) this->note_row_move(ev, ioRow, inToPos);
+ }
+ }
+ }
+ return outPos;
+}
+
+mork_bool morkTable::AddRow(morkEnv* ev, morkRow* ioRow) {
+ morkRow* row = this->find_member_row(ev, ioRow);
+ if (!row && ev->Good()) {
+ mork_bool canDirty = (this->IsTableClean())
+ ? this->MaybeDirtySpaceStoreAndTable()
+ : morkBool_kTrue;
+
+ mork_pos pos = mTable_RowArray.AppendSlot(ev, ioRow);
+ if (ev->Good() && pos >= 0) {
+ ioRow->AddRowGcUse(ev);
+ if (mTable_RowMap) {
+ if (mTable_RowMap->AddRow(ev, ioRow)) {
+ // okay, anything else?
+ } else
+ mTable_RowArray.CutSlot(ev, pos);
+ } else if (mTable_RowArray.mArray_Fill >= morkTable_kMakeRowMapThreshold)
+ this->build_row_map(ev);
+
+ if (canDirty && ev->Good()) this->NoteTableAddRow(ev, ioRow);
+ }
+ }
+ return ev->Good();
+}
+
+mork_bool morkTable::CutRow(morkEnv* ev, morkRow* ioRow) {
+ morkRow* row = this->find_member_row(ev, ioRow);
+ if (row) {
+ mork_bool canDirty = (this->IsTableClean())
+ ? this->MaybeDirtySpaceStoreAndTable()
+ : morkBool_kTrue;
+
+ mork_count count = mTable_RowArray.mArray_Fill;
+ morkRow** rowSlots = (morkRow**)mTable_RowArray.mArray_Slots;
+ if (rowSlots) // array has vector as expected?
+ {
+ mork_pos pos = -1;
+ morkRow** end = rowSlots + count;
+ morkRow** slot = rowSlots - 1; // prepare for preincrement:
+ while (++slot < end) // another slot to check?
+ {
+ if (*slot == row) // found the slot containing row?
+ {
+ pos = slot - rowSlots; // record absolute position
+ break; // end while loop
+ }
+ }
+ if (pos >= 0) // need to cut if from the array?
+ mTable_RowArray.CutSlot(ev, pos);
+ else
+ ev->NewWarning("row not found in array");
+ } else
+ mTable_RowArray.NilSlotsAddressError(ev);
+
+ if (mTable_RowMap) mTable_RowMap->CutRow(ev, ioRow);
+
+ if (canDirty) this->NoteTableCutRow(ev, ioRow);
+
+ if (ioRow->CutRowGcUse(ev) == 0) ioRow->OnZeroRowGcUse(ev);
+ }
+ return ev->Good();
+}
+
+mork_bool morkTable::CutAllRows(morkEnv* ev) {
+ if (this->MaybeDirtySpaceStoreAndTable()) {
+ this->SetTableRewrite(); // everything is dirty
+ this->NoteTableSetAll(ev);
+ }
+
+ if (ev->Good()) {
+ mTable_RowArray.CutAllSlots(ev);
+ if (mTable_RowMap) {
+ morkRowMapIter i(ev, mTable_RowMap);
+ mork_change* c = 0;
+ morkRow* r = 0;
+
+ for (c = i.FirstRow(ev, &r); c; c = i.NextRow(ev, &r)) {
+ if (r) {
+ if (r->CutRowGcUse(ev) == 0) r->OnZeroRowGcUse(ev);
+
+ i.CutHereRow(ev, (morkRow**)0);
+ } else
+ ev->NewWarning("nil row in table map");
+ }
+ }
+ }
+ return ev->Good();
+}
+
+morkTableRowCursor* morkTable::NewTableRowCursor(morkEnv* ev,
+ mork_pos inRowPos) {
+ morkTableRowCursor* outCursor = 0;
+ if (ev->Good()) {
+ nsIMdbHeap* heap = mTable_Store->mPort_Heap;
+ morkTableRowCursor* cursor = new (*heap, ev)
+ morkTableRowCursor(ev, morkUsage::kHeap, heap, this, inRowPos);
+ if (cursor) {
+ if (ev->Good())
+ outCursor = cursor;
+ else
+ cursor->CutStrongRef((nsIMdbEnv*)ev);
+ }
+ }
+ return outCursor;
+}
+
+// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+morkTableChange::morkTableChange(morkEnv* ev, mork_change inChange,
+ morkRow* ioRow)
+ // use this constructor for inChange == morkChange_kAdd or morkChange_kCut
+ : morkNext(),
+ mTableChange_Row(ioRow),
+ mTableChange_Pos(morkTableChange_kNone) {
+ if (ioRow) {
+ if (ioRow->IsRow()) {
+ if (inChange == morkChange_kAdd)
+ mTableChange_Pos = morkTableChange_kAdd;
+ else if (inChange == morkChange_kCut)
+ mTableChange_Pos = morkTableChange_kCut;
+ else
+ this->UnknownChangeError(ev);
+ } else
+ ioRow->NonRowTypeError(ev);
+ } else
+ ev->NilPointerError();
+}
+
+morkTableChange::morkTableChange(morkEnv* ev, morkRow* ioRow, mork_pos inPos)
+ // use this constructor when the row is moved
+ : morkNext(), mTableChange_Row(ioRow), mTableChange_Pos(inPos) {
+ if (ioRow) {
+ if (ioRow->IsRow()) {
+ if (inPos < 0) this->NegativeMovePosError(ev);
+ } else
+ ioRow->NonRowTypeError(ev);
+ } else
+ ev->NilPointerError();
+}
+
+void morkTableChange::UnknownChangeError(morkEnv* ev) const
+// morkChange_kAdd or morkChange_kCut
+{
+ ev->NewError("mTableChange_Pos neither kAdd nor kCut");
+}
+
+void morkTableChange::NegativeMovePosError(morkEnv* ev) const
+// move must be non-neg position
+{
+ ev->NewError("negative mTableChange_Pos for row move");
+}
+
+// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+morkTableMap::~morkTableMap() {}
+
+morkTableMap::morkTableMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
+#ifdef MORK_BEAD_OVER_NODE_MAPS
+ : morkBeadMap(ev, inUsage, ioHeap, ioSlotHeap)
+#else /*MORK_BEAD_OVER_NODE_MAPS*/
+ : morkNodeMap(ev, inUsage, ioHeap, ioSlotHeap)
+#endif /*MORK_BEAD_OVER_NODE_MAPS*/
+{
+ if (ev->Good()) mNode_Derived = morkDerived_kTableMap;
+}
+
+// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789