summaryrefslogtreecommitdiff
path: root/db/mork/src/morkStore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'db/mork/src/morkStore.cpp')
-rw-r--r--db/mork/src/morkStore.cpp2290
1 files changed, 2290 insertions, 0 deletions
diff --git a/db/mork/src/morkStore.cpp b/db/mork/src/morkStore.cpp
new file mode 100644
index 0000000000..47f145c83b
--- /dev/null
+++ b/db/mork/src/morkStore.cpp
@@ -0,0 +1,2290 @@
+/* -*- 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 _MORKBLOB_
+#include "morkBlob.h"
+#endif
+
+#ifndef _MORKMAP_
+#include "morkMap.h"
+#endif
+
+#ifndef _MORKENV_
+#include "morkEnv.h"
+#endif
+
+#ifndef _MORKSTORE_
+#include "morkStore.h"
+#endif
+
+#ifndef _MORKFACTORY_
+#include "morkFactory.h"
+#endif
+
+#ifndef _MORKNODEMAP_
+#include "morkNodeMap.h"
+#endif
+
+#ifndef _MORKROW_
+#include "morkRow.h"
+#endif
+
+#ifndef _MORKTHUMB_
+#include "morkThumb.h"
+#endif
+// #ifndef _MORKFILE_
+// #include "morkFile.h"
+// #endif
+
+#ifndef _MORKBUILDER_
+#include "morkBuilder.h"
+#endif
+
+#ifndef _MORKATOMSPACE_
+#include "morkAtomSpace.h"
+#endif
+
+#ifndef _MORKSTREAM_
+#include "morkStream.h"
+#endif
+
+#ifndef _MORKATOMSPACE_
+#include "morkAtomSpace.h"
+#endif
+
+#ifndef _MORKROWSPACE_
+#include "morkRowSpace.h"
+#endif
+
+#ifndef _MORKPORTTABLECURSOR_
+#include "morkPortTableCursor.h"
+#endif
+
+#ifndef _MORKTABLE_
+#include "morkTable.h"
+#endif
+
+#ifndef _MORKROWMAP_
+#include "morkRowMap.h"
+#endif
+
+#ifndef _MORKPARSER_
+#include "morkParser.h"
+#endif
+
+#include "nsCOMPtr.h"
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkStore::CloseMorkNode(morkEnv* ev) // ClosePort() only if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseStore(ev);
+ this->MarkShut();
+ }
+}
+
+/*public non-poly*/ void
+morkStore::ClosePort(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this->IsNode() )
+ {
+ morkFactory::SlotWeakFactory((morkFactory*) 0, ev, &mPort_Factory);
+ nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mPort_Heap);
+ this->CloseObject(ev);
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+}
+
+/*public virtual*/
+morkStore::~morkStore() // assert CloseStore() executed earlier
+{
+ MOZ_COUNT_DTOR(morkStore);
+ if (IsOpenNode())
+ CloseMorkNode(mMorkEnv);
+ MORK_ASSERT(this->IsShutNode());
+ MORK_ASSERT(mStore_File==0);
+ MORK_ASSERT(mStore_InStream==0);
+ MORK_ASSERT(mStore_OutStream==0);
+ MORK_ASSERT(mStore_Builder==0);
+ MORK_ASSERT(mStore_OidAtomSpace==0);
+ MORK_ASSERT(mStore_GroundAtomSpace==0);
+ MORK_ASSERT(mStore_GroundColumnSpace==0);
+ MORK_ASSERT(mStore_RowSpaces.IsShutNode());
+ MORK_ASSERT(mStore_AtomSpaces.IsShutNode());
+ MORK_ASSERT(mStore_Pool.IsShutNode());
+}
+
+/*public non-poly*/
+morkStore::morkStore(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioNodeHeap, // the heap (if any) for this node instance
+ morkFactory* inFactory, // the factory for this
+ nsIMdbHeap* ioPortHeap // the heap to hold all content in the port
+ )
+: morkObject(ev, inUsage, ioNodeHeap, morkColor_kNone, (morkHandle*) 0)
+, mPort_Env( ev )
+, mPort_Factory( 0 )
+, mPort_Heap( 0 )
+, mStore_OidAtomSpace( 0 )
+, mStore_GroundAtomSpace( 0 )
+, mStore_GroundColumnSpace( 0 )
+
+, mStore_File( 0 )
+, mStore_InStream( 0 )
+, mStore_Builder( 0 )
+, mStore_OutStream( 0 )
+
+, mStore_RowSpaces(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap)
+, mStore_AtomSpaces(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap)
+, mStore_Zone(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap)
+, mStore_Pool(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap)
+
+, mStore_CommitGroupIdentity( 0 )
+
+, mStore_FirstCommitGroupPos( 0 )
+, mStore_SecondCommitGroupPos( 0 )
+
+// disable auto-assignment of atom IDs until someone knows it is okay:
+, mStore_CanAutoAssignAtomIdentity( morkBool_kFalse )
+, mStore_CanDirty( morkBool_kFalse ) // not until the store is open
+, mStore_CanWriteIncremental( morkBool_kTrue ) // always with few exceptions
+{
+ MOZ_COUNT_CTOR(morkStore);
+ if ( ev->Good() )
+ {
+ if ( inFactory && ioPortHeap )
+ {
+ morkFactory::SlotWeakFactory(inFactory, ev, &mPort_Factory);
+ nsIMdbHeap_SlotStrongHeap(ioPortHeap, ev, &mPort_Heap);
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kPort;
+ }
+ else
+ ev->NilPointerError();
+ }
+ if ( ev->Good() )
+ {
+ mNode_Derived = morkDerived_kStore;
+
+ }
+}
+
+NS_IMPL_ISUPPORTS_INHERITED(morkStore, morkObject, nsIMdbStore)
+
+/*public non-poly*/ void
+morkStore::CloseStore(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this->IsNode() )
+ {
+
+ nsIMdbFile* file = mStore_File;
+ file->AddRef();
+
+ morkFactory::SlotWeakFactory((morkFactory*) 0, ev, &mPort_Factory);
+ nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mPort_Heap);
+ morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev,
+ &mStore_OidAtomSpace);
+ morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev,
+ &mStore_GroundAtomSpace);
+ morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev,
+ &mStore_GroundColumnSpace);
+ mStore_RowSpaces.CloseMorkNode(ev);
+ mStore_AtomSpaces.CloseMorkNode(ev);
+ morkBuilder::SlotStrongBuilder((morkBuilder*) 0, ev, &mStore_Builder);
+
+ nsIMdbFile_SlotStrongFile((nsIMdbFile*) 0, ev,
+ &mStore_File);
+
+ file->Release();
+
+ morkStream::SlotStrongStream((morkStream*) 0, ev, &mStore_InStream);
+ morkStream::SlotStrongStream((morkStream*) 0, ev, &mStore_OutStream);
+
+ mStore_Pool.CloseMorkNode(ev);
+ mStore_Zone.CloseMorkNode(ev);
+ this->ClosePort(ev);
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+
+mork_bool morkStore::DoPreferLargeOverCompressCommit(morkEnv* ev)
+ // true when mStore_CanWriteIncremental && store has file large enough
+{
+ nsIMdbFile* file = mStore_File;
+ if ( file && mStore_CanWriteIncremental )
+ {
+ mdb_pos fileEof = 0;
+ file->Eof(ev->AsMdbEnv(), &fileEof);
+ if ( ev->Good() && fileEof > 128 )
+ return morkBool_kTrue;
+ }
+ return morkBool_kFalse;
+}
+
+mork_percent morkStore::PercentOfStoreWasted(morkEnv* ev)
+{
+ mork_percent outPercent = 0;
+ nsIMdbFile* file = mStore_File;
+
+ if ( file )
+ {
+ mork_pos firstPos = mStore_FirstCommitGroupPos;
+ mork_pos secondPos = mStore_SecondCommitGroupPos;
+ if ( firstPos || secondPos )
+ {
+ if ( firstPos < 512 && secondPos > firstPos )
+ firstPos = secondPos; // better approximation of first commit
+
+ mork_pos fileLength = 0;
+ file->Eof(ev->AsMdbEnv(), &fileLength); // end of file
+ if ( ev->Good() && fileLength > firstPos )
+ {
+ mork_size groupContent = fileLength - firstPos;
+ outPercent = ( groupContent * 100 ) / fileLength;
+ }
+ }
+ }
+ else
+ this->NilStoreFileError(ev);
+
+ return outPercent;
+}
+
+void
+morkStore::SetStoreAndAllSpacesCanDirty(morkEnv* ev, mork_bool inCanDirty)
+{
+ mStore_CanDirty = inCanDirty;
+
+ mork_change* c = 0;
+ mork_scope* key = 0; // ignore keys in maps
+
+ if ( ev->Good() )
+ {
+ morkAtomSpaceMapIter asi(ev, &mStore_AtomSpaces);
+
+ morkAtomSpace* atomSpace = 0; // old val node in the map
+
+ for ( c = asi.FirstAtomSpace(ev, key, &atomSpace); c && ev->Good();
+ c = asi.NextAtomSpace(ev, key, &atomSpace) )
+ {
+ if ( atomSpace )
+ {
+ if ( atomSpace->IsAtomSpace() )
+ atomSpace->mSpace_CanDirty = inCanDirty;
+ else
+ atomSpace->NonAtomSpaceTypeError(ev);
+ }
+ else
+ ev->NilPointerError();
+ }
+ }
+
+ if ( ev->Good() )
+ {
+ morkRowSpaceMapIter rsi(ev, &mStore_RowSpaces);
+ morkRowSpace* rowSpace = 0; // old val node in the map
+
+ for ( c = rsi.FirstRowSpace(ev, key, &rowSpace); c && ev->Good();
+ c = rsi.NextRowSpace(ev, key, &rowSpace) )
+ {
+ if ( rowSpace )
+ {
+ if ( rowSpace->IsRowSpace() )
+ rowSpace->mSpace_CanDirty = inCanDirty;
+ else
+ rowSpace->NonRowSpaceTypeError(ev);
+ }
+ }
+ }
+}
+
+void
+morkStore::RenumberAllCollectableContent(morkEnv* ev)
+{
+ MORK_USED_1(ev);
+ // do nothing currently
+}
+
+nsIMdbStore*
+morkStore::AcquireStoreHandle(morkEnv* ev)
+{
+ return this;
+}
+
+
+morkFarBookAtom*
+morkStore::StageAliasAsFarBookAtom(morkEnv* ev, const morkMid* inMid,
+ morkAtomSpace* ioSpace, mork_cscode inForm)
+{
+ if ( inMid && inMid->mMid_Buf )
+ {
+ const morkBuf* buf = inMid->mMid_Buf;
+ mork_size length = buf->mBuf_Fill;
+ if ( length <= morkBookAtom_kMaxBodySize )
+ {
+ mork_aid dummyAid = 1;
+ //mStore_BookAtom.InitMaxBookAtom(ev, *buf,
+ // inForm, ioSpace, dummyAid);
+
+ mStore_FarBookAtom.InitFarBookAtom(ev, *buf,
+ inForm, ioSpace, dummyAid);
+ return &mStore_FarBookAtom;
+ }
+ }
+ else
+ ev->NilPointerError();
+
+ return (morkFarBookAtom*) 0;
+}
+
+morkFarBookAtom*
+morkStore::StageYarnAsFarBookAtom(morkEnv* ev, const mdbYarn* inYarn,
+ morkAtomSpace* ioSpace)
+{
+ if ( inYarn && inYarn->mYarn_Buf )
+ {
+ mork_size length = inYarn->mYarn_Fill;
+ if ( length <= morkBookAtom_kMaxBodySize )
+ {
+ morkBuf buf(inYarn->mYarn_Buf, length);
+ mork_aid dummyAid = 1;
+ //mStore_BookAtom.InitMaxBookAtom(ev, buf,
+ // inYarn->mYarn_Form, ioSpace, dummyAid);
+ mStore_FarBookAtom.InitFarBookAtom(ev, buf,
+ inYarn->mYarn_Form, ioSpace, dummyAid);
+ return &mStore_FarBookAtom;
+ }
+ }
+ else
+ ev->NilPointerError();
+
+ return (morkFarBookAtom*) 0;
+}
+
+morkFarBookAtom*
+morkStore::StageStringAsFarBookAtom(morkEnv* ev, const char* inString,
+ mork_cscode inForm, morkAtomSpace* ioSpace)
+{
+ if ( inString )
+ {
+ mork_size length = MORK_STRLEN(inString);
+ if ( length <= morkBookAtom_kMaxBodySize )
+ {
+ morkBuf buf(inString, length);
+ mork_aid dummyAid = 1;
+ //mStore_BookAtom.InitMaxBookAtom(ev, buf, inForm, ioSpace, dummyAid);
+ mStore_FarBookAtom.InitFarBookAtom(ev, buf, inForm, ioSpace, dummyAid);
+ return &mStore_FarBookAtom;
+ }
+ }
+ else
+ ev->NilPointerError();
+
+ return (morkFarBookAtom*) 0;
+}
+
+morkAtomSpace* morkStore::LazyGetOidAtomSpace(morkEnv* ev)
+{
+ MORK_USED_1(ev);
+ if ( !mStore_OidAtomSpace )
+ {
+ }
+ return mStore_OidAtomSpace;
+}
+
+morkAtomSpace* morkStore::LazyGetGroundAtomSpace(morkEnv* ev)
+{
+ if ( !mStore_GroundAtomSpace )
+ {
+ mork_scope atomScope = morkStore_kValueSpaceScope;
+ nsIMdbHeap* heap = mPort_Heap;
+ morkAtomSpace* space = new(*heap, ev)
+ morkAtomSpace(ev, morkUsage::kHeap, atomScope, this, heap, heap);
+
+ if ( space ) // successful space creation?
+ {
+ this->MaybeDirtyStore();
+
+ mStore_GroundAtomSpace = space; // transfer strong ref to this slot
+ mStore_AtomSpaces.AddAtomSpace(ev, space);
+ }
+ }
+ return mStore_GroundAtomSpace;
+}
+
+morkAtomSpace* morkStore::LazyGetGroundColumnSpace(morkEnv* ev)
+{
+ if ( !mStore_GroundColumnSpace )
+ {
+ mork_scope atomScope = morkStore_kGroundColumnSpace;
+ nsIMdbHeap* heap = mPort_Heap;
+ morkAtomSpace* space = new(*heap, ev)
+ morkAtomSpace(ev, morkUsage::kHeap, atomScope, this, heap, heap);
+
+ if ( space ) // successful space creation?
+ {
+ this->MaybeDirtyStore();
+
+ mStore_GroundColumnSpace = space; // transfer strong ref to this slot
+ mStore_AtomSpaces.AddAtomSpace(ev, space);
+ }
+ }
+ return mStore_GroundColumnSpace;
+}
+
+morkStream* morkStore::LazyGetInStream(morkEnv* ev)
+{
+ if ( !mStore_InStream )
+ {
+ nsIMdbFile* file = mStore_File;
+ if ( file )
+ {
+ morkStream* stream = new(*mPort_Heap, ev)
+ morkStream(ev, morkUsage::kHeap, mPort_Heap, file,
+ morkStore_kStreamBufSize, /*frozen*/ morkBool_kTrue);
+ if ( stream )
+ {
+ this->MaybeDirtyStore();
+ mStore_InStream = stream; // transfer strong ref to this slot
+ }
+ }
+ else
+ this->NilStoreFileError(ev);
+ }
+ return mStore_InStream;
+}
+
+morkStream* morkStore::LazyGetOutStream(morkEnv* ev)
+{
+ if ( !mStore_OutStream )
+ {
+ nsIMdbFile* file = mStore_File;
+ if ( file )
+ {
+ morkStream* stream = new(*mPort_Heap, ev)
+ morkStream(ev, morkUsage::kHeap, mPort_Heap, file,
+ morkStore_kStreamBufSize, /*frozen*/ morkBool_kFalse);
+ if ( stream )
+ {
+ this->MaybeDirtyStore();
+ mStore_InStream = stream; // transfer strong ref to this slot
+ }
+ }
+ else
+ this->NilStoreFileError(ev);
+ }
+ return mStore_OutStream;
+}
+
+void
+morkStore::ForgetBuilder(morkEnv* ev)
+{
+ if ( mStore_Builder )
+ morkBuilder::SlotStrongBuilder((morkBuilder*) 0, ev, &mStore_Builder);
+ if ( mStore_InStream )
+ morkStream::SlotStrongStream((morkStream*) 0, ev, &mStore_InStream);
+}
+
+morkBuilder* morkStore::LazyGetBuilder(morkEnv* ev)
+{
+ if ( !mStore_Builder )
+ {
+ morkStream* stream = this->LazyGetInStream(ev);
+ if ( stream )
+ {
+ nsIMdbHeap* heap = mPort_Heap;
+ morkBuilder* builder = new(*heap, ev)
+ morkBuilder(ev, morkUsage::kHeap, heap, stream,
+ morkBuilder_kDefaultBytesPerParseSegment, heap, this);
+ if ( builder )
+ {
+ mStore_Builder = builder; // transfer strong ref to this slot
+ }
+ }
+ }
+ return mStore_Builder;
+}
+
+morkRowSpace*
+morkStore::LazyGetRowSpace(morkEnv* ev, mdb_scope inRowScope)
+{
+ morkRowSpace* outSpace = mStore_RowSpaces.GetRowSpace(ev, inRowScope);
+ if ( !outSpace && ev->Good() ) // try to make new space?
+ {
+ nsIMdbHeap* heap = mPort_Heap;
+ outSpace = new(*heap, ev)
+ morkRowSpace(ev, morkUsage::kHeap, inRowScope, this, heap, heap);
+
+ if ( outSpace ) // successful space creation?
+ {
+ this->MaybeDirtyStore();
+
+ // note adding to node map creates its own strong ref...
+ if ( mStore_RowSpaces.AddRowSpace(ev, outSpace) )
+ outSpace->CutStrongRef(ev); // ...so we can drop our strong ref
+ }
+ }
+ return outSpace;
+}
+
+morkAtomSpace*
+morkStore::LazyGetAtomSpace(morkEnv* ev, mdb_scope inAtomScope)
+{
+ morkAtomSpace* outSpace = mStore_AtomSpaces.GetAtomSpace(ev, inAtomScope);
+ if ( !outSpace && ev->Good() ) // try to make new space?
+ {
+ if ( inAtomScope == morkStore_kValueSpaceScope )
+ outSpace = this->LazyGetGroundAtomSpace(ev);
+
+ else if ( inAtomScope == morkStore_kGroundColumnSpace )
+ outSpace = this->LazyGetGroundColumnSpace(ev);
+ else
+ {
+ nsIMdbHeap* heap = mPort_Heap;
+ outSpace = new(*heap, ev)
+ morkAtomSpace(ev, morkUsage::kHeap, inAtomScope, this, heap, heap);
+
+ if ( outSpace ) // successful space creation?
+ {
+ this->MaybeDirtyStore();
+
+ // note adding to node map creates its own strong ref...
+ if ( mStore_AtomSpaces.AddAtomSpace(ev, outSpace) )
+ outSpace->CutStrongRef(ev); // ...so we can drop our strong ref
+ }
+ }
+ }
+ return outSpace;
+}
+
+/*static*/ void
+morkStore::NonStoreTypeError(morkEnv* ev)
+{
+ ev->NewError("non morkStore");
+}
+
+/*static*/ void
+morkStore::NilStoreFileError(morkEnv* ev)
+{
+ ev->NewError("nil mStore_File");
+}
+
+/*static*/ void
+morkStore::CannotAutoAssignAtomIdentityError(morkEnv* ev)
+{
+ ev->NewError("false mStore_CanAutoAssignAtomIdentity");
+}
+
+
+mork_bool
+morkStore::OpenStoreFile(morkEnv* ev, mork_bool inFrozen,
+ // const char* inFilePath,
+ nsIMdbFile* ioFile, // db abstract file interface
+ const mdbOpenPolicy* inOpenPolicy)
+{
+ MORK_USED_2(inOpenPolicy,inFrozen);
+ nsIMdbFile_SlotStrongFile(ioFile, ev, &mStore_File);
+
+ // if ( ev->Good() )
+ // {
+ // morkFile* file = morkFile::OpenOldFile(ev, mPort_Heap,
+ // inFilePath, inFrozen);
+ // if ( ioFile )
+ // {
+ // if ( ev->Good() )
+ // morkFile::SlotStrongFile(file, ev, &mStore_File);
+ // else
+ // file->CutStrongRef(ev);
+ //
+ // }
+ // }
+ return ev->Good();
+}
+
+mork_bool
+morkStore::CreateStoreFile(morkEnv* ev,
+ // const char* inFilePath,
+ nsIMdbFile* ioFile, // db abstract file interface
+ const mdbOpenPolicy* inOpenPolicy)
+{
+ MORK_USED_1(inOpenPolicy);
+ nsIMdbFile_SlotStrongFile(ioFile, ev, &mStore_File);
+
+ return ev->Good();
+}
+
+morkAtom*
+morkStore::CopyAtom(morkEnv* ev, const morkAtom* inAtom)
+// copy inAtom (from some other store) over to this store
+{
+ morkAtom* outAtom = 0;
+ if ( inAtom )
+ {
+ mdbYarn yarn;
+ if ( morkAtom::AliasYarn(inAtom, &yarn) )
+ outAtom = this->YarnToAtom(ev, &yarn, true /* create */);
+ }
+ return outAtom;
+}
+
+morkAtom*
+morkStore::YarnToAtom(morkEnv* ev, const mdbYarn* inYarn, bool createIfMissing /* = true */)
+{
+ morkAtom* outAtom = 0;
+ if ( ev->Good() )
+ {
+ morkAtomSpace* groundSpace = this->LazyGetGroundAtomSpace(ev);
+ if ( groundSpace )
+ {
+ morkFarBookAtom* keyAtom =
+ this->StageYarnAsFarBookAtom(ev, inYarn, groundSpace);
+
+ if ( keyAtom )
+ {
+ morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
+ outAtom = map->GetAtom(ev, keyAtom);
+ if ( !outAtom && createIfMissing)
+ {
+ this->MaybeDirtyStore();
+ outAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
+ }
+ }
+ else if ( ev->Good() )
+ {
+ morkBuf b(inYarn->mYarn_Buf, inYarn->mYarn_Fill);
+ morkZone* z = &mStore_Zone;
+ outAtom = mStore_Pool.NewAnonAtom(ev, b, inYarn->mYarn_Form, z);
+ }
+ }
+ }
+ return outAtom;
+}
+
+mork_bool
+morkStore::MidToOid(morkEnv* ev, const morkMid& inMid, mdbOid* outOid)
+{
+ *outOid = inMid.mMid_Oid;
+ const morkBuf* buf = inMid.mMid_Buf;
+ if ( buf && !outOid->mOid_Scope )
+ {
+ if ( buf->mBuf_Fill <= morkBookAtom_kMaxBodySize )
+ {
+ if ( buf->mBuf_Fill == 1 )
+ {
+ mork_u1* name = (mork_u1*) buf->mBuf_Body;
+ if ( name )
+ {
+ outOid->mOid_Scope = (mork_scope) *name;
+ return ev->Good();
+ }
+ }
+ morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev);
+ if ( groundSpace )
+ {
+ mork_cscode form = 0; // default
+ mork_aid aid = 1; // dummy
+ mStore_FarBookAtom.InitFarBookAtom(ev, *buf, form, groundSpace, aid);
+ morkFarBookAtom* keyAtom = &mStore_FarBookAtom;
+ morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
+ morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom);
+ if ( bookAtom )
+ outOid->mOid_Scope = bookAtom->mBookAtom_Id;
+ else
+ {
+ this->MaybeDirtyStore();
+ bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
+ if ( bookAtom )
+ {
+ outOid->mOid_Scope = bookAtom->mBookAtom_Id;
+ bookAtom->MakeCellUseForever(ev);
+ }
+ }
+ }
+ }
+ }
+ return ev->Good();
+}
+
+morkRow*
+morkStore::MidToRow(morkEnv* ev, const morkMid& inMid)
+{
+ mdbOid tempOid;
+ this->MidToOid(ev, inMid, &tempOid);
+ return this->OidToRow(ev, &tempOid);
+}
+
+morkTable*
+morkStore::MidToTable(morkEnv* ev, const morkMid& inMid)
+{
+ mdbOid tempOid;
+ this->MidToOid(ev, inMid, &tempOid);
+ return this->OidToTable(ev, &tempOid, /*metarow*/ (mdbOid*) 0);
+}
+
+mork_bool
+morkStore::MidToYarn(morkEnv* ev, const morkMid& inMid, mdbYarn* outYarn)
+{
+ mdbOid tempOid;
+ this->MidToOid(ev, inMid, &tempOid);
+ return this->OidToYarn(ev, tempOid, outYarn);
+}
+
+mork_bool
+morkStore::OidToYarn(morkEnv* ev, const mdbOid& inOid, mdbYarn* outYarn)
+{
+ morkBookAtom* atom = 0;
+
+ morkAtomSpace* atomSpace = mStore_AtomSpaces.GetAtomSpace(ev, inOid.mOid_Scope);
+ if ( atomSpace )
+ {
+ morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids;
+ atom = map->GetAid(ev, (mork_aid) inOid.mOid_Id);
+ }
+ atom->GetYarn(outYarn); // note this is safe even when atom==nil
+
+ return ev->Good();
+}
+
+morkBookAtom*
+morkStore::MidToAtom(morkEnv* ev, const morkMid& inMid)
+{
+ morkBookAtom* outAtom = 0;
+ mdbOid oid;
+ if ( this->MidToOid(ev, inMid, &oid) )
+ {
+ morkAtomSpace* atomSpace = mStore_AtomSpaces.GetAtomSpace(ev, oid.mOid_Scope);
+ if ( atomSpace )
+ {
+ morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids;
+ outAtom = map->GetAid(ev, (mork_aid) oid.mOid_Id);
+ }
+ }
+ return outAtom;
+}
+
+/*static*/ void
+morkStore::SmallTokenToOneByteYarn(morkEnv* ev, mdb_token inToken,
+ mdbYarn* outYarn)
+{
+ MORK_USED_1(ev);
+ if ( outYarn->mYarn_Buf && outYarn->mYarn_Size ) // any space in yarn at all?
+ {
+ mork_u1* buf = (mork_u1*) outYarn->mYarn_Buf; // for byte arithmetic
+ buf[ 0 ] = (mork_u1) inToken; // write the single byte
+ outYarn->mYarn_Fill = 1;
+ outYarn->mYarn_More = 0;
+ }
+ else // just record we could not write the single byte
+ {
+ outYarn->mYarn_More = 1;
+ outYarn->mYarn_Fill = 0;
+ }
+}
+
+void
+morkStore::TokenToString(morkEnv* ev, mdb_token inToken, mdbYarn* outTokenName)
+{
+ if ( inToken > morkAtomSpace_kMaxSevenBitAid )
+ {
+ morkBookAtom* atom = 0;
+ morkAtomSpace* space = mStore_GroundColumnSpace;
+ if ( space )
+ atom = space->mAtomSpace_AtomAids.GetAid(ev, (mork_aid) inToken);
+
+ atom->GetYarn(outTokenName); // note this is safe even when atom==nil
+ }
+ else // token is an "immediate" single byte string representation?
+ this->SmallTokenToOneByteYarn(ev, inToken, outTokenName);
+}
+
+// void
+// morkStore::SyncTokenIdChange(morkEnv* ev, const morkBookAtom* inAtom,
+// const mdbOid* inOid)
+// {
+// mork_token mStore_MorkNoneToken; // token for "mork:none" // fill=9
+// mork_column mStore_CharsetToken; // token for "charset" // fill=7
+// mork_column mStore_AtomScopeToken; // token for "atomScope" // fill=9
+// mork_column mStore_RowScopeToken; // token for "rowScope" // fill=8
+// mork_column mStore_TableScopeToken; // token for "tableScope" // fill=10
+// mork_column mStore_ColumnScopeToken; // token for "columnScope" // fill=11
+// mork_kind mStore_TableKindToken; // token for "tableKind" // fill=9
+// ---------------------ruler-for-token-length-above---123456789012
+//
+// if ( inOid->mOid_Scope == morkStore_kColumnSpaceScope && inAtom->IsWeeBook() )
+// {
+// const mork_u1* body = ((const morkWeeBookAtom*) inAtom)->mWeeBookAtom_Body;
+// mork_size size = inAtom->mAtom_Size;
+//
+// if ( size >= 7 && size <= 11 )
+// {
+// if ( size == 9 )
+// {
+// if ( *body == 'm' )
+// {
+// if ( MORK_MEMCMP(body, "mork:none", 9) == 0 )
+// mStore_MorkNoneToken = inAtom->mBookAtom_Id;
+// }
+// else if ( *body == 'a' )
+// {
+// if ( MORK_MEMCMP(body, "atomScope", 9) == 0 )
+// mStore_AtomScopeToken = inAtom->mBookAtom_Id;
+// }
+// else if ( *body == 't' )
+// {
+// if ( MORK_MEMCMP(body, "tableKind", 9) == 0 )
+// mStore_TableKindToken = inAtom->mBookAtom_Id;
+// }
+// }
+// else if ( size == 7 && *body == 'c' )
+// {
+// if ( MORK_MEMCMP(body, "charset", 7) == 0 )
+// mStore_CharsetToken = inAtom->mBookAtom_Id;
+// }
+// else if ( size == 8 && *body == 'r' )
+// {
+// if ( MORK_MEMCMP(body, "rowScope", 8) == 0 )
+// mStore_RowScopeToken = inAtom->mBookAtom_Id;
+// }
+// else if ( size == 10 && *body == 't' )
+// {
+// if ( MORK_MEMCMP(body, "tableScope", 10) == 0 )
+// mStore_TableScopeToken = inAtom->mBookAtom_Id;
+// }
+// else if ( size == 11 && *body == 'c' )
+// {
+// if ( MORK_MEMCMP(body, "columnScope", 11) == 0 )
+// mStore_ColumnScopeToken = inAtom->mBookAtom_Id;
+// }
+// }
+// }
+// }
+
+morkAtom*
+morkStore::AddAlias(morkEnv* ev, const morkMid& inMid, mork_cscode inForm)
+{
+ morkBookAtom* outAtom = 0;
+ if ( ev->Good() )
+ {
+ const mdbOid* oid = &inMid.mMid_Oid;
+ morkAtomSpace* atomSpace = this->LazyGetAtomSpace(ev, oid->mOid_Scope);
+ if ( atomSpace )
+ {
+ morkFarBookAtom* keyAtom =
+ this->StageAliasAsFarBookAtom(ev, &inMid, atomSpace, inForm);
+ if ( keyAtom )
+ {
+ morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids;
+ outAtom = map->GetAid(ev, (mork_aid) oid->mOid_Id);
+ if ( outAtom )
+ {
+ if ( !outAtom->EqualFormAndBody(ev, keyAtom) )
+ ev->NewError("duplicate alias ID");
+ }
+ else
+ {
+ this->MaybeDirtyStore();
+ keyAtom->mBookAtom_Id = oid->mOid_Id;
+ outAtom = atomSpace->MakeBookAtomCopyWithAid(ev,
+ *keyAtom, (mork_aid) oid->mOid_Id);
+
+ // if ( outAtom && outAtom->IsWeeBook() )
+ // {
+ // if ( oid->mOid_Scope == morkStore_kColumnSpaceScope )
+ // {
+ // mork_size size = outAtom->mAtom_Size;
+ // if ( size >= 7 && size <= 11 )
+ // this->SyncTokenIdChange(ev, outAtom, oid);
+ // }
+ // }
+ }
+ }
+ }
+ }
+ return outAtom;
+}
+
+#define morkStore_kMaxCopyTokenSize 512 /* if larger, cannot be copied */
+
+mork_token
+morkStore::CopyToken(morkEnv* ev, mdb_token inToken, morkStore* inStore)
+// copy inToken from inStore over to this store
+{
+ mork_token outToken = 0;
+ if ( inStore == this ) // same store?
+ outToken = inToken; // just return token unchanged
+ else
+ {
+ char yarnBuf[ morkStore_kMaxCopyTokenSize ];
+ mdbYarn yarn;
+ yarn.mYarn_Buf = yarnBuf;
+ yarn.mYarn_Fill = 0;
+ yarn.mYarn_Size = morkStore_kMaxCopyTokenSize;
+ yarn.mYarn_More = 0;
+ yarn.mYarn_Form = 0;
+ yarn.mYarn_Grow = 0;
+
+ inStore->TokenToString(ev, inToken, &yarn);
+ if ( ev->Good() )
+ {
+ morkBuf buf(yarn.mYarn_Buf, yarn.mYarn_Fill);
+ outToken = this->BufToToken(ev, &buf);
+ }
+ }
+ return outToken;
+}
+
+mork_token
+morkStore::BufToToken(morkEnv* ev, const morkBuf* inBuf)
+{
+ mork_token outToken = 0;
+ if ( ev->Good() )
+ {
+ const mork_u1* s = (const mork_u1*) inBuf->mBuf_Body;
+ mork_bool nonAscii = ( *s > 0x7F );
+ mork_size length = inBuf->mBuf_Fill;
+ if ( nonAscii || length > 1 ) // more than one byte?
+ {
+ mork_cscode form = 0; // default charset
+ morkAtomSpace* space = this->LazyGetGroundColumnSpace(ev);
+ if ( space )
+ {
+ morkFarBookAtom* keyAtom = 0;
+ if ( length <= morkBookAtom_kMaxBodySize )
+ {
+ mork_aid aid = 1; // dummy
+ //mStore_BookAtom.InitMaxBookAtom(ev, *inBuf, form, space, aid);
+ mStore_FarBookAtom.InitFarBookAtom(ev, *inBuf, form, space, aid);
+ keyAtom = &mStore_FarBookAtom;
+ }
+ if ( keyAtom )
+ {
+ morkAtomBodyMap* map = &space->mAtomSpace_AtomBodies;
+ morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom);
+ if ( bookAtom )
+ outToken = bookAtom->mBookAtom_Id;
+ else
+ {
+ this->MaybeDirtyStore();
+ bookAtom = space->MakeBookAtomCopy(ev, *keyAtom);
+ if ( bookAtom )
+ {
+ outToken = bookAtom->mBookAtom_Id;
+ bookAtom->MakeCellUseForever(ev);
+ }
+ }
+ }
+ }
+ }
+ else // only a single byte in inTokenName string:
+ outToken = *s;
+ }
+
+ return outToken;
+}
+
+mork_token
+morkStore::StringToToken(morkEnv* ev, const char* inTokenName)
+{
+ mork_token outToken = 0;
+ if ( ev->Good() )
+ {
+ const mork_u1* s = (const mork_u1*) inTokenName;
+ mork_bool nonAscii = ( *s > 0x7F );
+ if ( nonAscii || ( *s && s[ 1 ] ) ) // more than one byte?
+ {
+ mork_cscode form = 0; // default charset
+ morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev);
+ if ( groundSpace )
+ {
+ morkFarBookAtom* keyAtom =
+ this->StageStringAsFarBookAtom(ev, inTokenName, form, groundSpace);
+ if ( keyAtom )
+ {
+ morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
+ morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom);
+ if ( bookAtom )
+ outToken = bookAtom->mBookAtom_Id;
+ else
+ {
+ this->MaybeDirtyStore();
+ bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
+ if ( bookAtom )
+ {
+ outToken = bookAtom->mBookAtom_Id;
+ bookAtom->MakeCellUseForever(ev);
+ }
+ }
+ }
+ }
+ }
+ else // only a single byte in inTokenName string:
+ outToken = *s;
+ }
+
+ return outToken;
+}
+
+mork_token
+morkStore::QueryToken(morkEnv* ev, const char* inTokenName)
+{
+ mork_token outToken = 0;
+ if ( ev->Good() )
+ {
+ const mork_u1* s = (const mork_u1*) inTokenName;
+ mork_bool nonAscii = ( *s > 0x7F );
+ if ( nonAscii || ( *s && s[ 1 ] ) ) // more than one byte?
+ {
+ mork_cscode form = 0; // default charset
+ morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev);
+ if ( groundSpace )
+ {
+ morkFarBookAtom* keyAtom =
+ this->StageStringAsFarBookAtom(ev, inTokenName, form, groundSpace);
+ if ( keyAtom )
+ {
+ morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
+ morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom);
+ if ( bookAtom )
+ {
+ outToken = bookAtom->mBookAtom_Id;
+ bookAtom->MakeCellUseForever(ev);
+ }
+ }
+ }
+ }
+ else // only a single byte in inTokenName string:
+ outToken = *s;
+ }
+
+ return outToken;
+}
+
+mork_bool
+morkStore::HasTableKind(morkEnv* ev, mdb_scope inRowScope,
+ mdb_kind inTableKind, mdb_count* outTableCount)
+{
+ MORK_USED_2(inRowScope,inTableKind);
+ mork_bool outBool = morkBool_kFalse;
+ mdb_count tableCount = 0;
+
+ ev->StubMethodOnlyError();
+
+ if ( outTableCount )
+ *outTableCount = tableCount;
+ return outBool;
+}
+
+morkTable*
+morkStore::GetTableKind(morkEnv* ev, mdb_scope inRowScope,
+ mdb_kind inTableKind, mdb_count* outTableCount,
+ mdb_bool* outMustBeUnique)
+{
+ morkTable* outTable = 0;
+ if ( ev->Good() )
+ {
+ morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope);
+ if ( rowSpace )
+ {
+ outTable = rowSpace->FindTableByKind(ev, inTableKind);
+ if ( outTable )
+ {
+ if ( outTableCount )
+ *outTableCount = outTable->GetRowCount();
+ if ( outMustBeUnique )
+ *outMustBeUnique = outTable->IsTableUnique();
+ }
+ }
+ }
+ return outTable;
+}
+
+morkRow*
+morkStore::FindRow(morkEnv* ev, mdb_scope inScope, mdb_column inColumn,
+ const mdbYarn* inYarn)
+{
+ morkRow* outRow = 0;
+ if ( ev->Good() )
+ {
+ morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inScope);
+ if ( rowSpace )
+ {
+ outRow = rowSpace->FindRow(ev, inColumn, inYarn);
+ }
+ }
+ return outRow;
+}
+
+morkRow*
+morkStore::GetRow(morkEnv* ev, const mdbOid* inOid)
+{
+ morkRow* outRow = 0;
+ if ( ev->Good() )
+ {
+ morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
+ if ( rowSpace )
+ {
+ outRow = rowSpace->mRowSpace_Rows.GetOid(ev, inOid);
+ }
+ }
+ return outRow;
+}
+
+morkTable*
+morkStore::GetTable(morkEnv* ev, const mdbOid* inOid)
+{
+ morkTable* outTable = 0;
+ if ( ev->Good() )
+ {
+ morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
+ if ( rowSpace )
+ {
+ outTable = rowSpace->FindTableByTid(ev, inOid->mOid_Id);
+ }
+ }
+ return outTable;
+}
+
+morkTable*
+morkStore::NewTable(morkEnv* ev, mdb_scope inRowScope,
+ mdb_kind inTableKind, mdb_bool inMustBeUnique,
+ const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying
+{
+ morkTable* outTable = 0;
+ if ( ev->Good() )
+ {
+ morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope);
+ if ( rowSpace )
+ outTable = rowSpace->NewTable(ev, inTableKind, inMustBeUnique,
+ inOptionalMetaRowOid);
+ }
+ return outTable;
+}
+
+morkPortTableCursor*
+morkStore::GetPortTableCursor(morkEnv* ev, mdb_scope inRowScope,
+ mdb_kind inTableKind)
+{
+ morkPortTableCursor* outCursor = 0;
+ if ( ev->Good() )
+ {
+ nsIMdbHeap* heap = mPort_Heap;
+ outCursor = new(*heap, ev)
+ morkPortTableCursor(ev, morkUsage::kHeap, heap, this,
+ inRowScope, inTableKind, heap);
+ }
+ NS_IF_ADDREF(outCursor);
+ return outCursor;
+}
+
+morkRow*
+morkStore::NewRow(morkEnv* ev, mdb_scope inRowScope)
+{
+ morkRow* outRow = 0;
+ if ( ev->Good() )
+ {
+ morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope);
+ if ( rowSpace )
+ outRow = rowSpace->NewRow(ev);
+ }
+ return outRow;
+}
+
+morkRow*
+morkStore::NewRowWithOid(morkEnv* ev, const mdbOid* inOid)
+{
+ morkRow* outRow = 0;
+ if ( ev->Good() )
+ {
+ morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
+ if ( rowSpace )
+ outRow = rowSpace->NewRowWithOid(ev, inOid);
+ }
+ return outRow;
+}
+
+morkRow*
+morkStore::OidToRow(morkEnv* ev, const mdbOid* inOid)
+ // OidToRow() finds old row with oid, or makes new one if not found.
+{
+ morkRow* outRow = 0;
+ if ( ev->Good() )
+ {
+ morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
+ if ( rowSpace )
+ {
+ outRow = rowSpace->mRowSpace_Rows.GetOid(ev, inOid);
+ if ( !outRow && ev->Good() )
+ outRow = rowSpace->NewRowWithOid(ev, inOid);
+ }
+ }
+ return outRow;
+}
+
+morkTable*
+morkStore::OidToTable(morkEnv* ev, const mdbOid* inOid,
+ const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying
+ // OidToTable() finds old table with oid, or makes new one if not found.
+{
+ morkTable* outTable = 0;
+ if ( ev->Good() )
+ {
+ morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
+ if ( rowSpace )
+ {
+ outTable = rowSpace->mRowSpace_Tables.GetTable(ev, inOid->mOid_Id);
+ if ( !outTable && ev->Good() )
+ {
+ mork_kind tableKind = morkStore_kNoneToken;
+ outTable = rowSpace->NewTableWithTid(ev, inOid->mOid_Id, tableKind,
+ inOptionalMetaRowOid);
+ }
+ }
+ }
+ return outTable;
+}
+
+// { ===== begin nsIMdbObject methods =====
+
+// { ----- begin ref counting for well-behaved cyclic graphs -----
+NS_IMETHODIMP
+morkStore::GetWeakRefCount(nsIMdbEnv* mev, // weak refs
+ mdb_count* outCount)
+{
+ *outCount = WeakRefsOnly();
+ return NS_OK;
+}
+NS_IMETHODIMP
+morkStore::GetStrongRefCount(nsIMdbEnv* mev, // strong refs
+ mdb_count* outCount)
+{
+ *outCount = StrongRefsOnly();
+ return NS_OK;
+}
+// ### TODO - clean up this cast, if required
+NS_IMETHODIMP
+morkStore::AddWeakRef(nsIMdbEnv* mev)
+{
+ morkEnv *ev = morkEnv::FromMdbEnv(mev);
+ // XXX Casting mork_refs to nsresult
+ return static_cast<nsresult>(morkNode::AddWeakRef(ev));
+}
+#ifndef _MSC_VER
+NS_IMETHODIMP_(mork_uses)
+morkStore::AddStrongRef(morkEnv* mev)
+{
+ return AddRef();
+}
+#endif
+NS_IMETHODIMP_(mork_uses)
+morkStore::AddStrongRef(nsIMdbEnv* mev)
+{
+ return AddRef();
+}
+NS_IMETHODIMP
+morkStore::CutWeakRef(nsIMdbEnv* mev)
+{
+ morkEnv *ev = morkEnv::FromMdbEnv(mev);
+ // XXX Casting mork_refs to nsresult
+ return static_cast<nsresult>(morkNode::CutWeakRef(ev));
+}
+#ifndef _MSC_VER
+NS_IMETHODIMP_(mork_uses)
+morkStore::CutStrongRef(morkEnv* mev)
+{
+ return Release();
+}
+#endif
+NS_IMETHODIMP
+morkStore::CutStrongRef(nsIMdbEnv* mev)
+{
+ // XXX Casting nsrefcnt to nsresult
+ return static_cast<nsresult>(Release());
+}
+
+NS_IMETHODIMP
+morkStore::CloseMdbObject(nsIMdbEnv* mev)
+{
+ morkEnv *ev = morkEnv::FromMdbEnv(mev);
+ CloseMorkNode(ev);
+ Release();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+morkStore::IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen)
+{
+ *outOpen = IsOpenNode();
+ return NS_OK;
+}
+// } ----- end ref counting -----
+
+// } ===== end nsIMdbObject methods =====
+
+// { ===== begin nsIMdbPort methods =====
+
+// { ----- begin attribute methods -----
+NS_IMETHODIMP
+morkStore::GetIsPortReadonly(nsIMdbEnv* mev, mdb_bool* outBool)
+{
+ nsresult outErr = NS_OK;
+ mdb_bool isReadOnly = morkBool_kFalse;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ ev->StubMethodOnlyError();
+ outErr = ev->AsErr();
+ }
+ if ( outBool )
+ *outBool = isReadOnly;
+ return outErr;
+}
+
+morkEnv*
+morkStore::CanUseStore(nsIMdbEnv* mev, mork_bool inMutable,
+ nsresult* outErr) const
+{
+ morkEnv* outEnv = 0;
+ morkEnv* ev = morkEnv::FromMdbEnv(mev);
+ if ( ev )
+ {
+ if (IsStore())
+ outEnv = ev;
+ else
+ NonStoreTypeError(ev);
+ *outErr = ev->AsErr();
+ }
+ MORK_ASSERT(outEnv);
+ return outEnv;
+}
+
+NS_IMETHODIMP
+morkStore::GetIsStore(nsIMdbEnv* mev, mdb_bool* outBool)
+{
+ MORK_USED_1(mev);
+ if ( outBool )
+ *outBool = morkBool_kTrue;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+morkStore::GetIsStoreAndDirty(nsIMdbEnv* mev, mdb_bool* outBool)
+{
+ nsresult outErr = NS_OK;
+ mdb_bool isStoreAndDirty = morkBool_kFalse;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ ev->StubMethodOnlyError();
+ outErr = ev->AsErr();
+ }
+ if ( outBool )
+ *outBool = isStoreAndDirty;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::GetUsagePolicy(nsIMdbEnv* mev,
+ mdbUsagePolicy* ioUsagePolicy)
+{
+ MORK_USED_1(ioUsagePolicy);
+ nsresult outErr = NS_OK;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ ev->StubMethodOnlyError();
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::SetUsagePolicy(nsIMdbEnv* mev,
+ const mdbUsagePolicy* inUsagePolicy)
+{
+ MORK_USED_1(inUsagePolicy);
+ nsresult outErr = NS_OK;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ // ev->StubMethodOnlyError(); // okay to do nothing?
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+// } ----- end attribute methods -----
+
+// { ----- begin memory policy methods -----
+NS_IMETHODIMP
+morkStore::IdleMemoryPurge( // do memory management already scheduled
+ nsIMdbEnv* mev, // context
+ mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed
+{
+ nsresult outErr = NS_OK;
+ mdb_size estimatedBytesFreed = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ // ev->StubMethodOnlyError(); // okay to do nothing?
+ outErr = ev->AsErr();
+ }
+ if ( outEstimatedBytesFreed )
+ *outEstimatedBytesFreed = estimatedBytesFreed;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::SessionMemoryPurge( // request specific footprint decrease
+ nsIMdbEnv* mev, // context
+ mdb_size inDesiredBytesFreed, // approximate number of bytes wanted
+ mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed
+{
+ MORK_USED_1(inDesiredBytesFreed);
+ nsresult outErr = NS_OK;
+ mdb_size estimate = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ // ev->StubMethodOnlyError(); // okay to do nothing?
+ outErr = ev->AsErr();
+ }
+ if ( outEstimatedBytesFreed )
+ *outEstimatedBytesFreed = estimate;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::PanicMemoryPurge( // desperately free all possible memory
+ nsIMdbEnv* mev, // context
+ mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed
+{
+ nsresult outErr = NS_OK;
+ mdb_size estimate = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ // ev->StubMethodOnlyError(); // okay to do nothing?
+ outErr = ev->AsErr();
+ }
+ if ( outEstimatedBytesFreed )
+ *outEstimatedBytesFreed = estimate;
+ return outErr;
+}
+// } ----- end memory policy methods -----
+
+// { ----- begin filepath methods -----
+NS_IMETHODIMP
+morkStore::GetPortFilePath(
+ nsIMdbEnv* mev, // context
+ mdbYarn* outFilePath, // name of file holding port content
+ mdbYarn* outFormatVersion) // file format description
+{
+ nsresult outErr = NS_OK;
+ if ( outFormatVersion )
+ outFormatVersion->mYarn_Fill = 0;
+ if ( outFilePath )
+ outFilePath->mYarn_Fill = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ if ( mStore_File )
+ mStore_File->Path(mev, outFilePath);
+ else
+ NilStoreFileError(ev);
+
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::GetPortFile(
+ nsIMdbEnv* mev, // context
+ nsIMdbFile** acqFile) // acquire file used by port or store
+{
+ nsresult outErr = NS_OK;
+ if ( acqFile )
+ *acqFile = 0;
+
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+
+ if ( mStore_File )
+ {
+ if ( acqFile )
+ {
+ mStore_File->AddRef();
+ if ( ev->Good() )
+ *acqFile = mStore_File;
+ }
+ }
+ else
+ NilStoreFileError(ev);
+
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+// } ----- end filepath methods -----
+
+// { ----- begin export methods -----
+NS_IMETHODIMP
+morkStore::BestExportFormat( // determine preferred export format
+ nsIMdbEnv* mev, // context
+ mdbYarn* outFormatVersion) // file format description
+{
+ nsresult outErr = NS_OK;
+ if ( outFormatVersion )
+ outFormatVersion->mYarn_Fill = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ ev->StubMethodOnlyError();
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::CanExportToFormat( // can export content in given specific format?
+ nsIMdbEnv* mev, // context
+ const char* inFormatVersion, // file format description
+ mdb_bool* outCanExport) // whether ExportSource() might succeed
+{
+ MORK_USED_1(inFormatVersion);
+ mdb_bool canExport = morkBool_kFalse;
+ nsresult outErr = NS_OK;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ ev->StubMethodOnlyError();
+ outErr = ev->AsErr();
+ }
+ if ( outCanExport )
+ *outCanExport = canExport;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::ExportToFormat( // export content in given specific format
+ nsIMdbEnv* mev, // context
+ // const char* inFilePath, // the file to receive exported content
+ nsIMdbFile* ioFile, // destination abstract file interface
+ const char* inFormatVersion, // file format description
+ nsIMdbThumb** acqThumb) // acquire thumb for incremental export
+// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+// then the export will be finished.
+{
+ nsresult outErr = NS_OK;
+ nsIMdbThumb* outThumb = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ if ( ioFile && inFormatVersion && acqThumb )
+ {
+ ev->StubMethodOnlyError();
+ }
+ else
+ ev->NilPointerError();
+
+ outErr = ev->AsErr();
+ }
+ if ( acqThumb )
+ *acqThumb = outThumb;
+ return outErr;
+}
+
+// } ----- end export methods -----
+
+// { ----- begin token methods -----
+NS_IMETHODIMP
+morkStore::TokenToString( // return a string name for an integer token
+ nsIMdbEnv* mev, // context
+ mdb_token inToken, // token for inTokenName inside this port
+ mdbYarn* outTokenName) // the type of table to access
+{
+ nsresult outErr = NS_OK;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ TokenToString(ev, inToken, outTokenName);
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::StringToToken( // return an integer token for scope name
+ nsIMdbEnv* mev, // context
+ const char* inTokenName, // Latin1 string to tokenize if possible
+ mdb_token* outToken) // token for inTokenName inside this port
+ // String token zero is never used and never supported. If the port
+ // is a mutable store, then StringToToken() to create a new
+ // association of inTokenName with a new integer token if possible.
+ // But a readonly port will return zero for an unknown scope name.
+{
+ nsresult outErr = NS_OK;
+ mdb_token token = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ token = StringToToken(ev, inTokenName);
+ outErr = ev->AsErr();
+ }
+ if ( outToken )
+ *outToken = token;
+ return outErr;
+}
+
+
+NS_IMETHODIMP
+morkStore::QueryToken( // like StringToToken(), but without adding
+ nsIMdbEnv* mev, // context
+ const char* inTokenName, // Latin1 string to tokenize if possible
+ mdb_token* outToken) // token for inTokenName inside this port
+ // QueryToken() will return a string token if one already exists,
+ // but unlike StringToToken(), will not assign a new token if not
+ // already in use.
+{
+ nsresult outErr = NS_OK;
+ mdb_token token = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ token = QueryToken(ev, inTokenName);
+ outErr = ev->AsErr();
+ }
+ if ( outToken )
+ *outToken = token;
+ return outErr;
+}
+
+
+// } ----- end token methods -----
+
+// { ----- begin row methods -----
+NS_IMETHODIMP
+morkStore::HasRow( // contains a row with the specified oid?
+ nsIMdbEnv* mev, // context
+ const mdbOid* inOid, // hypothetical row oid
+ mdb_bool* outHasRow) // whether GetRow() might succeed
+{
+ nsresult outErr = NS_OK;
+ mdb_bool hasRow = morkBool_kFalse;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ morkRow* row = GetRow(ev, inOid);
+ if ( row )
+ hasRow = morkBool_kTrue;
+
+ outErr = ev->AsErr();
+ }
+ if ( outHasRow )
+ *outHasRow = hasRow;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::GetRow( // access one row with specific oid
+ nsIMdbEnv* mev, // context
+ const mdbOid* inOid, // hypothetical row oid
+ nsIMdbRow** acqRow) // acquire specific row (or null)
+{
+ nsresult outErr = NS_OK;
+ nsIMdbRow* outRow = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ morkRow* row = GetRow(ev, inOid);
+ if ( row && ev->Good() )
+ outRow = row->AcquireRowHandle(ev, this);
+
+ outErr = ev->AsErr();
+ }
+ if ( acqRow )
+ *acqRow = outRow;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::GetRowRefCount( // get number of tables that contain a row
+ nsIMdbEnv* mev, // context
+ const mdbOid* inOid, // hypothetical row oid
+ mdb_count* outRefCount) // number of tables containing inRowKey
+{
+ nsresult outErr = NS_OK;
+ mdb_count count = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ morkRow* row = GetRow(ev, inOid);
+ if ( row && ev->Good() )
+ count = row->mRow_GcUses;
+
+ outErr = ev->AsErr();
+ }
+ if ( outRefCount )
+ *outRefCount = count;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::FindRow(nsIMdbEnv* mev, // search for row with matching cell
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_column inColumn, // the column to search (and maintain an index)
+ const mdbYarn* inTargetCellValue, // cell value for which to search
+ mdbOid* outRowOid, // out row oid on match (or {0,-1} for no match)
+ nsIMdbRow** acqRow) // acquire matching row (or nil for no match)
+ // FindRow() searches for one row that has a cell in column inColumn with
+ // a contained value with the same form (i.e. charset) and is byte-wise
+ // identical to the blob described by yarn inTargetCellValue. Both content
+ // and form of the yarn must be an exact match to find a matching row.
+ //
+ // (In other words, both a yarn's blob bytes and form are significant. The
+ // form is not expected to vary in columns used for identity anyway. This
+ // is intended to make the cost of FindRow() cheaper for MDB implementors,
+ // since any cell value atomization performed internally must necessarily
+ // make yarn form significant in order to avoid data loss in atomization.)
+ //
+ // FindRow() can lazily create an index on attribute inColumn for all rows
+ // with that attribute in row space scope inRowScope, so that subsequent
+ // calls to FindRow() will perform faster. Such an index might or might
+ // not be persistent (but this seems desirable if it is cheap to do so).
+ // Note that lazy index creation in readonly DBs is not very feasible.
+ //
+ // This FindRow() interface assumes that attribute inColumn is effectively
+ // an alternative means of unique identification for a row in a rowspace,
+ // so correct behavior is only guaranteed when no duplicates for this col
+ // appear in the given set of rows. (If more than one row has the same cell
+ // value in this column, no more than one will be found; and cutting one of
+ // two duplicate rows can cause the index to assume no other such row lives
+ // in the row space, so future calls return nil for negative search results
+ // even though some duplicate row might still live within the rowspace.)
+ //
+ // In other words, the FindRow() implementation is allowed to assume simple
+ // hash tables mapping unqiue column keys to associated row values will be
+ // sufficient, where any duplication is not recorded because only one copy
+ // of a given key need be remembered. Implementors are not required to sort
+ // all rows by the specified column.
+{
+ nsresult outErr = NS_OK;
+ nsIMdbRow* outRow = 0;
+ mdbOid rowOid;
+ rowOid.mOid_Scope = 0;
+ rowOid.mOid_Id = (mdb_id) -1;
+
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ morkRow* row = FindRow(ev, inRowScope, inColumn, inTargetCellValue);
+ if ( row && ev->Good() )
+ {
+ rowOid = row->mRow_Oid;
+ if ( acqRow )
+ outRow = row->AcquireRowHandle(ev, this);
+ }
+ outErr = ev->AsErr();
+ }
+ if ( acqRow )
+ *acqRow = outRow;
+ if ( outRowOid )
+ *outRowOid = rowOid;
+
+ return outErr;
+}
+
+// } ----- end row methods -----
+
+// { ----- begin table methods -----
+NS_IMETHODIMP
+morkStore::HasTable( // supports a table with the specified oid?
+ nsIMdbEnv* mev, // context
+ const mdbOid* inOid, // hypothetical table oid
+ mdb_bool* outHasTable) // whether GetTable() might succeed
+{
+ nsresult outErr = NS_OK;
+ mork_bool hasTable = morkBool_kFalse;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ morkTable* table = GetTable(ev, inOid);
+ if ( table )
+ hasTable = morkBool_kTrue;
+
+ outErr = ev->AsErr();
+ }
+ if ( outHasTable )
+ *outHasTable = hasTable;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::GetTable( // access one table with specific oid
+ nsIMdbEnv* mev, // context
+ const mdbOid* inOid, // hypothetical table oid
+ nsIMdbTable** acqTable) // acquire specific table (or null)
+{
+ nsresult outErr = NS_OK;
+ nsIMdbTable* outTable = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ morkTable* table = GetTable(ev, inOid);
+ if ( table && ev->Good() )
+ outTable = table->AcquireTableHandle(ev);
+ outErr = ev->AsErr();
+ }
+ if ( acqTable )
+ *acqTable = outTable;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::HasTableKind( // supports a table of the specified type?
+ nsIMdbEnv* mev, // context
+ mdb_scope inRowScope, // rid scope for row ids
+ mdb_kind inTableKind, // the type of table to access
+ mdb_count* outTableCount, // current number of such tables
+ mdb_bool* outSupportsTable) // whether GetTableKind() might succeed
+{
+ nsresult outErr = NS_OK;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ *outSupportsTable = HasTableKind(ev, inRowScope,
+ inTableKind, outTableCount);
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::GetTableKind( // access one (random) table of specific type
+ nsIMdbEnv* mev, // context
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_kind inTableKind, // the type of table to access
+ mdb_count* outTableCount, // current number of such tables
+ mdb_bool* outMustBeUnique, // whether port can hold only one of these
+ nsIMdbTable** acqTable) // acquire scoped collection of rows
+{
+ nsresult outErr = NS_OK;
+ nsIMdbTable* outTable = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ morkTable* table = GetTableKind(ev, inRowScope,
+ inTableKind, outTableCount, outMustBeUnique);
+ if ( table && ev->Good() )
+ outTable = table->AcquireTableHandle(ev);
+ outErr = ev->AsErr();
+ }
+ if ( acqTable )
+ *acqTable = outTable;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::GetPortTableCursor( // get cursor for all tables of specific type
+ nsIMdbEnv* mev, // context
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_kind inTableKind, // the type of table to access
+ nsIMdbPortTableCursor** acqCursor) // all such tables in the port
+{
+ nsresult outErr = NS_OK;
+ nsIMdbPortTableCursor* outCursor = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ morkPortTableCursor* cursor =
+ GetPortTableCursor(ev, inRowScope,
+ inTableKind);
+ if ( cursor && ev->Good() )
+ outCursor = cursor;
+
+ outErr = ev->AsErr();
+ }
+ if ( acqCursor )
+ *acqCursor = outCursor;
+ return outErr;
+}
+// } ----- end table methods -----
+
+// { ----- begin commit methods -----
+
+NS_IMETHODIMP
+morkStore::ShouldCompress( // store wastes at least inPercentWaste?
+ nsIMdbEnv* mev, // context
+ mdb_percent inPercentWaste, // 0..100 percent file size waste threshold
+ mdb_percent* outActualWaste, // 0..100 percent of file actually wasted
+ mdb_bool* outShould) // true when about inPercentWaste% is wasted
+{
+ mdb_percent actualWaste = 0;
+ mdb_bool shouldCompress = morkBool_kFalse;
+ nsresult outErr = NS_OK;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ actualWaste = PercentOfStoreWasted(ev);
+ if ( inPercentWaste > 100 )
+ inPercentWaste = 100;
+ shouldCompress = ( actualWaste >= inPercentWaste );
+ outErr = ev->AsErr();
+ }
+ if ( outActualWaste )
+ *outActualWaste = actualWaste;
+ if ( outShould )
+ *outShould = shouldCompress;
+ return outErr;
+}
+
+
+// } ===== end nsIMdbPort methods =====
+
+NS_IMETHODIMP
+morkStore::NewTable( // make one new table of specific type
+ nsIMdbEnv* mev, // context
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_kind inTableKind, // the type of table to access
+ mdb_bool inMustBeUnique, // whether store can hold only one of these
+ const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
+ nsIMdbTable** acqTable) // acquire scoped collection of rows
+{
+ nsresult outErr = NS_OK;
+ nsIMdbTable* outTable = 0;
+ morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ morkTable* table = NewTable(ev, inRowScope,
+ inTableKind, inMustBeUnique, inOptionalMetaRowOid);
+ if ( table && ev->Good() )
+ outTable = table->AcquireTableHandle(ev);
+ outErr = ev->AsErr();
+ }
+ if ( acqTable )
+ *acqTable = outTable;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::NewTableWithOid( // make one new table of specific type
+ nsIMdbEnv* mev, // context
+ const mdbOid* inOid, // caller assigned oid
+ mdb_kind inTableKind, // the type of table to access
+ mdb_bool inMustBeUnique, // whether store can hold only one of these
+ const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
+ nsIMdbTable** acqTable) // acquire scoped collection of rows
+{
+ nsresult outErr = NS_OK;
+ nsIMdbTable* outTable = 0;
+ morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ morkTable* table = OidToTable(ev, inOid,
+ inOptionalMetaRowOid);
+ if ( table && ev->Good() )
+ {
+ table->mTable_Kind = inTableKind;
+ if ( inMustBeUnique )
+ table->SetTableUnique();
+ outTable = table->AcquireTableHandle(ev);
+ }
+ outErr = ev->AsErr();
+ }
+ if ( acqTable )
+ *acqTable = outTable;
+ return outErr;
+}
+// } ----- end table methods -----
+
+// { ----- begin row scope methods -----
+NS_IMETHODIMP
+morkStore::RowScopeHasAssignedIds(nsIMdbEnv* mev,
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
+ mdb_bool* outStoreAssigned) // nonzero if store db assigned specified
+{
+ NS_ASSERTION(false, " not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkStore::SetCallerAssignedIds(nsIMdbEnv* mev,
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
+ mdb_bool* outStoreAssigned) // nonzero if store db assigned specified
+{
+ NS_ASSERTION(false, " not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkStore::SetStoreAssignedIds(nsIMdbEnv* mev,
+ mdb_scope inRowScope, // row scope for row ids
+ mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
+ mdb_bool* outStoreAssigned) // nonzero if store db assigned specified
+{
+ NS_ASSERTION(false, " not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+// } ----- end row scope methods -----
+
+// { ----- begin row methods -----
+NS_IMETHODIMP
+morkStore::NewRowWithOid(nsIMdbEnv* mev, // new row w/ caller assigned oid
+ const mdbOid* inOid, // caller assigned oid
+ nsIMdbRow** acqRow) // create new row
+{
+ nsresult outErr = NS_OK;
+ nsIMdbRow* outRow = 0;
+ morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ morkRow* row = NewRowWithOid(ev, inOid);
+ if ( row && ev->Good() )
+ outRow = row->AcquireRowHandle(ev, this);
+
+ outErr = ev->AsErr();
+ }
+ if ( acqRow )
+ *acqRow = outRow;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::NewRow(nsIMdbEnv* mev, // new row with db assigned oid
+ mdb_scope inRowScope, // row scope for row ids
+ nsIMdbRow** acqRow) // create new row
+// Note this row must be added to some table or cell child before the
+// store is closed in order to make this row persist across sesssions.
+{
+ nsresult outErr = NS_OK;
+ nsIMdbRow* outRow = 0;
+ morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ morkRow* row = NewRow(ev, inRowScope);
+ if ( row && ev->Good() )
+ outRow = row->AcquireRowHandle(ev, this);
+
+ outErr = ev->AsErr();
+ }
+ if ( acqRow )
+ *acqRow = outRow;
+ return outErr;
+}
+// } ----- end row methods -----
+
+// { ----- begin inport/export methods -----
+NS_IMETHODIMP
+morkStore::ImportContent( // import content from port
+ nsIMdbEnv* mev, // context
+ mdb_scope inRowScope, // scope for rows (or zero for all?)
+ nsIMdbPort* ioPort, // the port with content to add to store
+ nsIMdbThumb** acqThumb) // acquire thumb for incremental import
+// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+// then the import will be finished.
+{
+ NS_ASSERTION(false, " not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkStore::ImportFile( // import content from port
+ nsIMdbEnv* mev, // context
+ nsIMdbFile* ioFile, // the file with content to add to store
+ nsIMdbThumb** acqThumb) // acquire thumb for incremental import
+// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+// then the import will be finished.
+{
+ NS_ASSERTION(false, " not implemented");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+// } ----- end inport/export methods -----
+
+// { ----- begin hinting methods -----
+NS_IMETHODIMP
+morkStore::ShareAtomColumnsHint( // advise re shared col content atomizing
+ nsIMdbEnv* mev, // context
+ mdb_scope inScopeHint, // zero, or suggested shared namespace
+ const mdbColumnSet* inColumnSet) // cols desired tokenized together
+{
+ MORK_USED_2(inColumnSet,inScopeHint);
+ nsresult outErr = NS_OK;
+ morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ // ev->StubMethodOnlyError(); // okay to do nothing for a hint method
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::AvoidAtomColumnsHint( // advise col w/ poor atomizing prospects
+ nsIMdbEnv* mev, // context
+ const mdbColumnSet* inColumnSet) // cols with poor atomizing prospects
+{
+ MORK_USED_1(inColumnSet);
+ nsresult outErr = NS_OK;
+ morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ // ev->StubMethodOnlyError(); // okay to do nothing for a hint method
+ outErr = ev->AsErr();
+ }
+ return outErr;
+}
+// } ----- end hinting methods -----
+
+// { ----- begin commit methods -----
+NS_IMETHODIMP
+morkStore::LargeCommit( // save important changes if at all possible
+ nsIMdbEnv* mev, // context
+ nsIMdbThumb** acqThumb) // acquire thumb for incremental commit
+// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+// then the commit will be finished. Note the store is effectively write
+// locked until commit is finished or canceled through the thumb instance.
+// Until the commit is done, the store will report it has readonly status.
+{
+ nsresult outErr = NS_OK;
+ nsIMdbThumb* outThumb = 0;
+ morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+
+ morkThumb* thumb = 0;
+ // morkFile* file = store->mStore_File;
+ if ( DoPreferLargeOverCompressCommit(ev) )
+ {
+ thumb = morkThumb::Make_LargeCommit(ev, mPort_Heap, this);
+ }
+ else
+ {
+ mork_bool doCollect = morkBool_kFalse;
+ thumb = morkThumb::Make_CompressCommit(ev, mPort_Heap, this, doCollect);
+ }
+
+ if ( thumb )
+ {
+ outThumb = thumb;
+ thumb->AddRef();
+ }
+
+ outErr = ev->AsErr();
+ }
+ if ( acqThumb )
+ *acqThumb = outThumb;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::SessionCommit( // save all changes if large commits delayed
+ nsIMdbEnv* mev, // context
+ nsIMdbThumb** acqThumb) // acquire thumb for incremental commit
+// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+// then the commit will be finished. Note the store is effectively write
+// locked until commit is finished or canceled through the thumb instance.
+// Until the commit is done, the store will report it has readonly status.
+{
+ nsresult outErr = NS_OK;
+ nsIMdbThumb* outThumb = 0;
+ morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+
+ morkThumb* thumb = 0;
+ if ( DoPreferLargeOverCompressCommit(ev) )
+ {
+ thumb = morkThumb::Make_LargeCommit(ev, mPort_Heap, this);
+ }
+ else
+ {
+ mork_bool doCollect = morkBool_kFalse;
+ thumb = morkThumb::Make_CompressCommit(ev, mPort_Heap, this, doCollect);
+ }
+
+ if ( thumb )
+ {
+ outThumb = thumb;
+ thumb->AddRef();
+ }
+ outErr = ev->AsErr();
+ }
+ if ( acqThumb )
+ *acqThumb = outThumb;
+ return outErr;
+}
+
+NS_IMETHODIMP
+morkStore::CompressCommit( // commit and make db smaller if possible
+ nsIMdbEnv* mev, // context
+ nsIMdbThumb** acqThumb) // acquire thumb for incremental commit
+// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+// then the commit will be finished. Note the store is effectively write
+// locked until commit is finished or canceled through the thumb instance.
+// Until the commit is done, the store will report it has readonly status.
+{
+ nsresult outErr = NS_OK;
+ nsIMdbThumb* outThumb = 0;
+ morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
+ if ( ev )
+ {
+ mork_bool doCollect = morkBool_kFalse;
+ morkThumb* thumb = morkThumb::Make_CompressCommit(ev, mPort_Heap, this, doCollect);
+ if ( thumb )
+ {
+ outThumb = thumb;
+ thumb->AddRef();
+ mStore_CanWriteIncremental = morkBool_kTrue;
+ }
+
+ outErr = ev->AsErr();
+ }
+ if ( acqThumb )
+ *acqThumb = outThumb;
+ return outErr;
+}
+
+// } ----- end commit methods -----
+
+// } ===== end nsIMdbStore methods =====
+
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+