summaryrefslogtreecommitdiff
path: root/db/mork/src/morkTable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'db/mork/src/morkTable.cpp')
-rw-r--r--db/mork/src/morkTable.cpp1610
1 files changed, 1610 insertions, 0 deletions
diff --git a/db/mork/src/morkTable.cpp b/db/mork/src/morkTable.cpp
new file mode 100644
index 0000000000..aaa4bd50e4
--- /dev/null
+++ b/db/mork/src/morkTable.cpp
@@ -0,0 +1,1610 @@
+/* -*- 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
+
+//3456789_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 searchs. 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 thatn 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;
+}
+
+//3456789_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");
+}
+
+//3456789_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;
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+