/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef _MDB_ #include "mdb.h" #endif #ifndef _MORK_ #include "mork.h" #endif #ifndef _MORKNODE_ #include "morkNode.h" #endif #ifndef _MORKHANDLE_ #include "morkHandle.h" #endif #ifndef _MORKSTORE_ #include "morkStore.h" #endif #ifndef _MORKENV_ #include "morkEnv.h" #endif #ifndef _ORKINSTORE_ #include "orkinStore.h" #endif #ifndef _MORKTABLE_ #include "morkTable.h" #endif #ifndef _MORKPORTTABLECURSOR_ #include "morkPortTableCursor.h" #endif #ifndef _ORKINPORTTABLECURSOR_ #include "orkinPortTableCursor.h" #endif #ifndef _MORKROW_ #include "morkRow.h" #endif #ifndef _MORKROWOBJECT_ #include "morkRowObject.h" #endif #ifndef _MORKTHUMB_ #include "morkThumb.h" #endif // #ifndef _MORKFILE_ // #include "morkFile.h" // #endif #ifndef _ORKINTHUMB_ #include "orkinThumb.h" #endif //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 /* public virtual*/ orkinStore:: ~orkinStore() // morkHandle destructor does everything { } /*protected non-poly construction*/ orkinStore::orkinStore(morkEnv* ev, // morkUsage is morkUsage_kPool morkHandleFace* ioFace, // must not be nil, cookie for this handle morkStore* ioObject) // must not be nil, the object for this handle : morkHandle(ev, ioFace, ioObject, morkMagic_kStore) { // do not modify mNode_Derived; leave it equal to morkDerived_kHandle } /*static */ orkinStore* orkinStore::MakeStore(morkEnv* ev, morkStore* ioObject) { mork_bool isEnv = ev->IsEnv(); MORK_ASSERT(isEnv); if ( isEnv ) { morkHandleFace* face = ev->NewHandle(sizeof(orkinStore)); if ( face ) return new(face) orkinStore(ev, face, ioObject); else ev->OutOfMemoryError(); } return (orkinStore*) 0; } morkEnv* orkinStore::CanUseStore(nsIMdbEnv* mev, mork_bool inMutable, mdb_err* outErr) const { morkEnv* outEnv = 0; morkEnv* ev = morkEnv::FromMdbEnv(mev); if ( ev ) { morkStore* self = (morkStore*) this->GetGoodHandleObject(ev, inMutable, morkMagic_kStore, /*inClosedOkay*/ morkBool_kFalse); if ( self ) { if ( self->IsStore() ) outEnv = ev; else self->NonStoreTypeError(ev); } *outErr = ev->AsErr(); } MORK_ASSERT(outEnv); return outEnv; } // { ===== begin nsIMdbISupports methods ===== NS_IMPL_QUERY_INTERFACE0(orkinStore) /*virtual*/ nsrefcnt orkinStore::AddRef() // add strong ref with no { morkEnv* ev = mHandle_Env; if ( ev && ev->IsEnv() ) return this->Handle_AddStrongRef(ev->AsMdbEnv()); else return morkEnv_kNonEnvTypeError; } /*virtual*/ nsrefcnt orkinStore::Release() // cut strong ref { morkEnv* ev = mHandle_Env; if ( ev && ev->IsEnv() ) return this->Handle_CutStrongRef(ev->AsMdbEnv()); else return morkEnv_kNonEnvTypeError; } // } ===== end nsIMdbISupports methods ===== // { ===== begin nsIMdbObject methods ===== // { ----- begin attribute methods ----- /*virtual*/ mdb_err orkinStore::IsFrozenMdbObject(nsIMdbEnv* mev, mdb_bool* outIsReadonly) { return this->Handle_IsFrozenMdbObject(mev, outIsReadonly); } // same as nsIMdbPort::GetIsPortReadonly() when this object is inside a port. // } ----- end attribute methods ----- // { ----- begin factory methods ----- /*virtual*/ mdb_err orkinStore::GetMdbFactory(nsIMdbEnv* mev, nsIMdbFactory** acqFactory) { return this->Handle_GetMdbFactory(mev, acqFactory); } // } ----- end factory methods ----- // { ----- begin ref counting for well-behaved cyclic graphs ----- /*virtual*/ mdb_err orkinStore::GetWeakRefCount(nsIMdbEnv* mev, // weak refs mdb_count* outCount) { return this->Handle_GetWeakRefCount(mev, outCount); } /*virtual*/ mdb_err orkinStore::GetStrongRefCount(nsIMdbEnv* mev, // strong refs mdb_count* outCount) { return this->Handle_GetStrongRefCount(mev, outCount); } /*virtual*/ mdb_err orkinStore::AddWeakRef(nsIMdbEnv* mev) { return this->Handle_AddWeakRef(mev); } /*virtual*/ mdb_err orkinStore::AddStrongRef(nsIMdbEnv* mev) { return this->Handle_AddStrongRef(mev); } /*virtual*/ mdb_err orkinStore::CutWeakRef(nsIMdbEnv* mev) { return this->Handle_CutWeakRef(mev); } /*virtual*/ mdb_err orkinStore::CutStrongRef(nsIMdbEnv* mev) { return this->Handle_CutStrongRef(mev); } /*virtual*/ mdb_err orkinStore::CloseMdbObject(nsIMdbEnv* mev) { return this->Handle_CloseMdbObject(mev); } /*virtual*/ mdb_err orkinStore::IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen) { return this->Handle_IsOpenMdbObject(mev, outOpen); } // } ----- end ref counting ----- // } ===== end nsIMdbObject methods ===== // { ===== begin nsIMdbPort methods ===== // { ----- begin attribute methods ----- /*virtual*/ mdb_err orkinStore::GetIsPortReadonly(nsIMdbEnv* mev, mdb_bool* outBool) { mdb_err outErr = 0; 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; } /*virtual*/ mdb_err orkinStore::GetIsStore(nsIMdbEnv* mev, mdb_bool* outBool) { MORK_USED_1(mev); if ( outBool ) *outBool = morkBool_kTrue; return 0; } /*virtual*/ mdb_err orkinStore::GetIsStoreAndDirty(nsIMdbEnv* mev, mdb_bool* outBool) { mdb_err outErr = 0; 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; } /*virtual*/ mdb_err orkinStore::GetUsagePolicy(nsIMdbEnv* mev, mdbUsagePolicy* ioUsagePolicy) { MORK_USED_1(ioUsagePolicy); mdb_err outErr = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { ev->StubMethodOnlyError(); outErr = ev->AsErr(); } return outErr; } /*virtual*/ mdb_err orkinStore::SetUsagePolicy(nsIMdbEnv* mev, const mdbUsagePolicy* inUsagePolicy) { MORK_USED_1(inUsagePolicy); mdb_err outErr = 0; 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 ----- /*virtual*/ mdb_err orkinStore::IdleMemoryPurge( // do memory management already scheduled nsIMdbEnv* mev, // context mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed { mdb_err outErr = 0; 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; } /*virtual*/ mdb_err orkinStore::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); mdb_err outErr = 0; 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; } /*virtual*/ mdb_err orkinStore::PanicMemoryPurge( // desperately free all possible memory nsIMdbEnv* mev, // context mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed { mdb_err outErr = 0; 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 ----- /*virtual*/ mdb_err orkinStore::GetPortFilePath( nsIMdbEnv* mev, // context mdbYarn* outFilePath, // name of file holding port content mdbYarn* outFormatVersion) // file format description { mdb_err outErr = 0; if ( outFormatVersion ) outFormatVersion->mYarn_Fill = 0; if ( outFilePath ) outFilePath->mYarn_Fill = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkStore* store = (morkStore*) mHandle_Object; nsIMdbFile* file = store->mStore_File; if ( file ) file->Path(mev, outFilePath); else store->NilStoreFileError(ev); outErr = ev->AsErr(); } return outErr; } /*virtual*/ mdb_err orkinStore::GetPortFile( nsIMdbEnv* mev, // context nsIMdbFile** acqFile) // acquire file used by port or store { mdb_err outErr = 0; if ( acqFile ) *acqFile = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkStore* store = (morkStore*) mHandle_Object; nsIMdbFile* file = store->mStore_File; if ( file ) { if ( acqFile ) { file->AddStrongRef(mev); if ( ev->Good() ) *acqFile = file; } } else store->NilStoreFileError(ev); outErr = ev->AsErr(); } return outErr; } // } ----- end filepath methods ----- // { ----- begin export methods ----- /*virtual*/ mdb_err orkinStore::BestExportFormat( // determine preferred export format nsIMdbEnv* mev, // context mdbYarn* outFormatVersion) // file format description { mdb_err outErr = 0; if ( outFormatVersion ) outFormatVersion->mYarn_Fill = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { ev->StubMethodOnlyError(); outErr = ev->AsErr(); } return outErr; } /*virtual*/ mdb_err orkinStore::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; mdb_err outErr = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { ev->StubMethodOnlyError(); outErr = ev->AsErr(); } if ( outCanExport ) *outCanExport = canExport; return outErr; } /*virtual*/ mdb_err orkinStore::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. { mdb_err outErr = 0; 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 ----- /*virtual*/ mdb_err orkinStore::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 { mdb_err outErr = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { ((morkStore*) mHandle_Object)->TokenToString(ev, inToken, outTokenName); outErr = ev->AsErr(); } return outErr; } /*virtual*/ mdb_err orkinStore::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. { mdb_err outErr = 0; mdb_token token = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { token = ((morkStore*) mHandle_Object)->StringToToken(ev, inTokenName); outErr = ev->AsErr(); } if ( outToken ) *outToken = token; return outErr; } /*virtual*/ mdb_err orkinStore::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. { mdb_err outErr = 0; mdb_token token = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { token = ((morkStore*) mHandle_Object)->QueryToken(ev, inTokenName); outErr = ev->AsErr(); } if ( outToken ) *outToken = token; return outErr; } // } ----- end token methods ----- // { ----- begin row methods ----- /*virtual*/ mdb_err orkinStore::HasRow( // contains a row with the specified oid? nsIMdbEnv* mev, // context const mdbOid* inOid, // hypothetical row oid mdb_bool* outHasRow) // whether GetRow() might succeed { mdb_err outErr = 0; mdb_bool hasRow = morkBool_kFalse; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkStore* store = (morkStore*) mHandle_Object; morkRow* row = store->GetRow(ev, inOid); if ( row ) hasRow = morkBool_kTrue; outErr = ev->AsErr(); } if ( outHasRow ) *outHasRow = hasRow; return outErr; } /*virtual*/ mdb_err orkinStore::GetRow( // access one row with specific oid nsIMdbEnv* mev, // context const mdbOid* inOid, // hypothetical row oid nsIMdbRow** acqRow) // acquire specific row (or null) { mdb_err outErr = 0; nsIMdbRow* outRow = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkStore* store = (morkStore*) mHandle_Object; morkRow* row = store->GetRow(ev, inOid); if ( row && ev->Good() ) outRow = row->AcquireRowHandle(ev, store); outErr = ev->AsErr(); } if ( acqRow ) *acqRow = outRow; return outErr; } /*virtual*/ mdb_err orkinStore::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 { mdb_err outErr = 0; mdb_count count = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkStore* store = (morkStore*) mHandle_Object; morkRow* row = store->GetRow(ev, inOid); if ( row && ev->Good() ) count = row->mRow_GcUses; outErr = ev->AsErr(); } if ( outRefCount ) *outRefCount = count; return outErr; } /*virtual*/ mdb_err orkinStore::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. { mdb_err outErr = 0; 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 ) { morkStore* store = (morkStore*) mHandle_Object; morkRow* row = store->FindRow(ev, inRowScope, inColumn, inTargetCellValue); if ( row && ev->Good() ) { outRow = row->AcquireRowHandle(ev, store); if ( outRow ) rowOid = row->mRow_Oid; } outErr = ev->AsErr(); } if ( acqRow ) *acqRow = outRow; return outErr; } // } ----- end row methods ----- // { ----- begin table methods ----- /*virtual*/ mdb_err orkinStore::HasTable( // supports a table with the specified oid? nsIMdbEnv* mev, // context const mdbOid* inOid, // hypothetical table oid mdb_bool* outHasTable) // whether GetTable() might succeed { mdb_err outErr = 0; mork_bool hasTable = morkBool_kFalse; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkTable* table = ((morkStore*) mHandle_Object)->GetTable(ev, inOid); if ( table ) hasTable = morkBool_kTrue; outErr = ev->AsErr(); } if ( outHasTable ) *outHasTable = hasTable; return outErr; } /*virtual*/ mdb_err orkinStore::GetTable( // access one table with specific oid nsIMdbEnv* mev, // context const mdbOid* inOid, // hypothetical table oid nsIMdbTable** acqTable) // acquire specific table (or null) { mdb_err outErr = 0; nsIMdbTable* outTable = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkTable* table = ((morkStore*) mHandle_Object)->GetTable(ev, inOid); if ( table && ev->Good() ) outTable = table->AcquireTableHandle(ev); outErr = ev->AsErr(); } if ( acqTable ) *acqTable = outTable; return outErr; } /*virtual*/ mdb_err orkinStore::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 { mdb_err outErr = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { *outSupportsTable = ((morkStore*) mHandle_Object)->HasTableKind(ev, inRowScope, inTableKind, outTableCount); outErr = ev->AsErr(); } return outErr; } /*virtual*/ mdb_err orkinStore::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 { mdb_err outErr = 0; nsIMdbTable* outTable = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkTable* table = ((morkStore*) mHandle_Object)->GetTableKind(ev, inRowScope, inTableKind, outTableCount, outMustBeUnique); if ( table && ev->Good() ) outTable = table->AcquireTableHandle(ev); outErr = ev->AsErr(); } if ( acqTable ) *acqTable = outTable; return outErr; } /*virtual*/ mdb_err orkinStore::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 { mdb_err outErr = 0; nsIMdbPortTableCursor* outCursor = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkPortTableCursor* cursor = ((morkStore*) mHandle_Object)->GetPortTableCursor(ev, inRowScope, inTableKind); if ( cursor && ev->Good() ) outCursor = cursor->AcquirePortTableCursorHandle(ev); outErr = ev->AsErr(); } if ( acqCursor ) *acqCursor = outCursor; return outErr; } // } ----- end table methods ----- // { ----- begin commit methods ----- /*virtual*/ mdb_err orkinStore::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; mdb_err outErr = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { actualWaste = ((morkStore*) mHandle_Object)->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 ===== // { ===== begin nsIMdbStore methods ===== // { ----- begin table methods ----- /*virtual*/ mdb_err orkinStore::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 { mdb_err outErr = 0; nsIMdbTable* outTable = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkTable* table = ((morkStore*) mHandle_Object)->NewTable(ev, inRowScope, inTableKind, inMustBeUnique, inOptionalMetaRowOid); if ( table && ev->Good() ) outTable = table->AcquireTableHandle(ev); outErr = ev->AsErr(); } if ( acqTable ) *acqTable = outTable; return outErr; } /*virtual*/ mdb_err orkinStore::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 { mdb_err outErr = 0; nsIMdbTable* outTable = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkTable* table = ((morkStore*) mHandle_Object)->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 ----- /*virtual*/ mdb_err orkinStore::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 { MORK_USED_1(inRowScope); mdb_bool storeAssigned = morkBool_kFalse; mdb_bool callerAssigned = morkBool_kFalse; mdb_err outErr = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { ev->StubMethodOnlyError(); outErr = ev->AsErr(); } if ( outCallerAssigned ) *outCallerAssigned = callerAssigned; if ( outStoreAssigned ) *outStoreAssigned = storeAssigned; return outErr; } /*virtual*/ mdb_err orkinStore::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 { MORK_USED_1(inRowScope); mdb_bool storeAssigned = morkBool_kFalse; mdb_bool callerAssigned = morkBool_kFalse; mdb_err outErr = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { ev->StubMethodOnlyError(); outErr = ev->AsErr(); } if ( outCallerAssigned ) *outCallerAssigned = callerAssigned; if ( outStoreAssigned ) *outStoreAssigned = storeAssigned; return outErr; } /*virtual*/ mdb_err orkinStore::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 { MORK_USED_1(inRowScope); mdb_err outErr = 0; mdb_bool storeAssigned = morkBool_kFalse; mdb_bool callerAssigned = morkBool_kFalse; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { ev->StubMethodOnlyError(); outErr = ev->AsErr(); } if ( outCallerAssigned ) *outCallerAssigned = callerAssigned; if ( outStoreAssigned ) *outStoreAssigned = storeAssigned; return outErr; } // } ----- end row scope methods ----- // { ----- begin row methods ----- /*virtual*/ mdb_err orkinStore::NewRowWithOid(nsIMdbEnv* mev, // new row w/ caller assigned oid const mdbOid* inOid, // caller assigned oid nsIMdbRow** acqRow) // create new row { mdb_err outErr = 0; nsIMdbRow* outRow = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkStore* store = (morkStore*) mHandle_Object; morkRow* row = store->NewRowWithOid(ev, inOid); if ( row && ev->Good() ) outRow = row->AcquireRowHandle(ev, store); outErr = ev->AsErr(); } if ( acqRow ) *acqRow = outRow; return outErr; } /*virtual*/ mdb_err orkinStore::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. { mdb_err outErr = 0; nsIMdbRow* outRow = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkStore* store = (morkStore*) mHandle_Object; morkRow* row = store->NewRow(ev, inRowScope); if ( row && ev->Good() ) outRow = row->AcquireRowHandle(ev, store); outErr = ev->AsErr(); } if ( acqRow ) *acqRow = outRow; return outErr; } // } ----- end row methods ----- // { ----- begin inport/export methods ----- /*virtual*/ mdb_err orkinStore::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. { MORK_USED_2(inRowScope,ioPort); nsIMdbThumb* outThumb = 0; mdb_err outErr = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { ev->StubMethodOnlyError(); outErr = ev->AsErr(); } if ( acqThumb ) *acqThumb = outThumb; return outErr; } /*virtual*/ mdb_err orkinStore::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. { nsIMdbThumb* outThumb = 0; mdb_err outErr = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { if ( ioFile && acqThumb ) { ev->StubMethodOnlyError(); } else ev->NilPointerError(); outErr = ev->AsErr(); } if ( acqThumb ) *acqThumb = outThumb; return outErr; } // } ----- end inport/export methods ----- // { ----- begin hinting methods ----- /*virtual*/ mdb_err orkinStore::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); mdb_err outErr = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { // ev->StubMethodOnlyError(); // okay to do nothing for a hint method outErr = ev->AsErr(); } return outErr; } /*virtual*/ mdb_err orkinStore::AvoidAtomColumnsHint( // advise col w/ poor atomizing prospects nsIMdbEnv* mev, // context const mdbColumnSet* inColumnSet) // cols with poor atomizing prospects { MORK_USED_1(inColumnSet); mdb_err outErr = 0; morkEnv* ev = this->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 ----- /*virtual*/ mdb_err orkinStore::SmallCommit( // save minor changes if convenient and uncostly nsIMdbEnv* mev) // context { mdb_err outErr = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { // ev->StubMethodOnlyError(); // it's okay to do nothing for small commit outErr = ev->AsErr(); } return outErr; } /*virtual*/ mdb_err orkinStore::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. { mdb_err outErr = 0; nsIMdbThumb* outThumb = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkStore* store = (morkStore*) mHandle_Object; nsIMdbHeap* heap = store->mPort_Heap; morkThumb* thumb = 0; // morkFile* file = store->mStore_File; if ( store->DoPreferLargeOverCompressCommit(ev) ) { thumb = morkThumb::Make_LargeCommit(ev, heap, store); } else { mork_bool doCollect = morkBool_kFalse; thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect); } if ( thumb ) { outThumb = thumb; thumb->AddRef(); } outErr = ev->AsErr(); } if ( acqThumb ) *acqThumb = outThumb; return outErr; } /*virtual*/ mdb_err orkinStore::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. { mdb_err outErr = 0; nsIMdbThumb* outThumb = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkStore* store = (morkStore*) mHandle_Object; nsIMdbHeap* heap = store->mPort_Heap; morkThumb* thumb = 0; if ( store->DoPreferLargeOverCompressCommit(ev) ) { thumb = morkThumb::Make_LargeCommit(ev, heap, store); } else { mork_bool doCollect = morkBool_kFalse; thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect); } if ( thumb ) { outThumb = thumb; thumb->AddRef(); } outErr = ev->AsErr(); } if ( acqThumb ) *acqThumb = outThumb; return outErr; } /*virtual*/ mdb_err orkinStore::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. { mdb_err outErr = 0; nsIMdbThumb* outThumb = 0; morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); if ( ev ) { morkStore* store = (morkStore*) mHandle_Object; nsIMdbHeap* heap = store->mPort_Heap; mork_bool doCollect = morkBool_kFalse; morkThumb* thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect); if ( thumb ) { outThumb = thumb; thumb->AddRef(); store->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