Back to index

lightning-sunbird  0.9+nobinonly
orkinTableRowCursor.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifndef _MDB_
00039 #include "mdb.h"
00040 #endif
00041 
00042 #ifndef _MORK_
00043 #include "mork.h"
00044 #endif
00045 
00046 #ifndef _MORKNODE_
00047 #include "morkNode.h"
00048 #endif
00049 
00050 #ifndef _MORKHANDLE_
00051 #include "morkHandle.h"
00052 #endif
00053 
00054 #ifndef _MORKFACTORY_
00055 #include "morkFactory.h"
00056 #endif
00057 
00058 #ifndef _ORKINFACTORY_
00059 #include "orkinFactory.h"
00060 #endif
00061 
00062 #ifndef _MORKTABLEROWCURSOR_
00063 #include "morkTableRowCursor.h"
00064 #endif
00065 
00066 #ifndef _ORKINTABLEROWCURSOR_
00067 #include "orkinTableRowCursor.h"
00068 #endif
00069 
00070 #ifndef _MORKROW_
00071 #include "morkRow.h"
00072 #endif
00073 
00074 #ifndef _MORKARRAY_
00075 #include "morkArray.h"
00076 #endif
00077 
00078 #ifndef _MORKTABLE_
00079 #include "morkTable.h"
00080 #endif
00081 
00082 #ifndef _ORKINTABLE_
00083 #include "orkinTable.h"
00084 #endif
00085 
00086 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00087 
00088 /* public virtual*/
00089 orkinTableRowCursor:: ~orkinTableRowCursor()
00090 // morkHandle destructor does everything
00091 {
00092 }
00093 
00094 /*protected non-poly construction*/
00095 orkinTableRowCursor::orkinTableRowCursor(morkEnv* ev, //  morkUsage_kPool
00096     morkHandleFace* ioFace,    // must not be nil, cookie for this handle
00097     morkTableRowCursor* ioObject)  // must not be nil, object for this handle
00098 : morkHandle(ev, ioFace, ioObject, morkMagic_kTableRowCursor)
00099 {
00100   // do not modify mNode_Derived; leave it equal to morkDerived_kHandle
00101 }
00102 
00103 
00104 /*static */ orkinTableRowCursor*
00105 orkinTableRowCursor::MakeTableRowCursor(morkEnv* ev,
00106    morkTableRowCursor* ioObject)
00107 {
00108   mork_bool isEnv = ev->IsEnv();
00109   MORK_ASSERT(isEnv);
00110   if ( isEnv )
00111   {
00112     morkHandleFace* face = ev->NewHandle(sizeof(orkinTableRowCursor));
00113     if ( face )
00114       return new(face) orkinTableRowCursor(ev, face, ioObject);
00115     else
00116       ev->OutOfMemoryError();
00117   }
00118     
00119   return (orkinTableRowCursor*) 0;
00120 }
00121 
00122 morkEnv*
00123 orkinTableRowCursor::CanUseTableRowCursor(nsIMdbEnv* mev,
00124   mork_bool inMutable, mdb_err* outErr) const
00125 {
00126   morkEnv* outEnv = 0;
00127   morkEnv* ev = morkEnv::FromMdbEnv(mev);
00128   if ( ev )
00129   {
00130     morkTableRowCursor* self = (morkTableRowCursor*)
00131       this->GetGoodHandleObject(ev, inMutable, morkMagic_kTableRowCursor,
00132         /*inClosedOkay*/ morkBool_kFalse);
00133     if ( self )
00134     {
00135       if ( self->IsTableRowCursor() )
00136       {
00137         morkTable* table = self->mTableRowCursor_Table;
00138         if ( table && table->IsOpenNode() )
00139         {
00140           outEnv = ev;
00141         }
00142       }
00143       else
00144         self->NonTableRowCursorTypeError(ev);
00145     }
00146     *outErr = ev->AsErr();
00147   }
00148   MORK_ASSERT(outEnv);
00149   return outEnv;
00150 }
00151 
00152 // { ===== begin nsIMdbISupports methods =====
00153 NS_IMPL_QUERY_INTERFACE1(orkinTableRowCursor, nsIMdbTableRowCursor)
00154 
00155 /*virtual*/ nsrefcnt
00156 orkinTableRowCursor::AddRef() // add strong ref with no
00157 {
00158   morkEnv* ev = mHandle_Env;
00159   if ( ev && ev->IsEnv() )
00160     return this->Handle_AddStrongRef(ev->AsMdbEnv());
00161   else
00162     return morkEnv_kNonEnvTypeError;
00163 }
00164 
00165 /*virtual*/ nsrefcnt
00166 orkinTableRowCursor::Release() // cut strong ref
00167 {
00168   morkEnv* ev = mHandle_Env;
00169   if ( ev && ev->IsEnv() )
00170     return this->Handle_CutStrongRef(ev->AsMdbEnv());
00171   else
00172     return morkEnv_kNonEnvTypeError;
00173 }
00174 // } ===== end nsIMdbObject methods =====
00175 
00176 
00177 // { ===== begin nsIMdbObject methods =====
00178 
00179 // { ----- begin attribute methods -----
00180 /*virtual*/ mdb_err
00181 orkinTableRowCursor::IsFrozenMdbObject(nsIMdbEnv* mev, mdb_bool* outIsReadonly)
00182 {
00183   return this->Handle_IsFrozenMdbObject(mev, outIsReadonly);
00184 }
00185 // same as nsIMdbPort::GetIsPortReadonly() when this object is inside a port.
00186 // } ----- end attribute methods -----
00187 
00188 // { ----- begin factory methods -----
00189 /*virtual*/ mdb_err
00190 orkinTableRowCursor::GetMdbFactory(nsIMdbEnv* mev, nsIMdbFactory** acqFactory)
00191 {
00192   return this->Handle_GetMdbFactory(mev, acqFactory);
00193 } 
00194 // } ----- end factory methods -----
00195 
00196 // { ----- begin ref counting for well-behaved cyclic graphs -----
00197 /*virtual*/ mdb_err
00198 orkinTableRowCursor::GetWeakRefCount(nsIMdbEnv* mev, // weak refs
00199   mdb_count* outCount)
00200 {
00201   return this->Handle_GetWeakRefCount(mev, outCount);
00202 }  
00203 /*virtual*/ mdb_err
00204 orkinTableRowCursor::GetStrongRefCount(nsIMdbEnv* mev, // strong refs
00205   mdb_count* outCount)
00206 {
00207   return this->Handle_GetStrongRefCount(mev, outCount);
00208 }
00209 
00210 /*virtual*/ mdb_err
00211 orkinTableRowCursor::AddWeakRef(nsIMdbEnv* mev)
00212 {
00213   return this->Handle_AddWeakRef(mev);
00214 }
00215 /*virtual*/ mdb_err
00216 orkinTableRowCursor::AddStrongRef(nsIMdbEnv* mev)
00217 {
00218   return this->Handle_AddStrongRef(mev);
00219 }
00220 
00221 /*virtual*/ mdb_err
00222 orkinTableRowCursor::CutWeakRef(nsIMdbEnv* mev)
00223 {
00224   return this->Handle_CutWeakRef(mev);
00225 }
00226 /*virtual*/ mdb_err
00227 orkinTableRowCursor::CutStrongRef(nsIMdbEnv* mev)
00228 {
00229   return this->Handle_CutStrongRef(mev);
00230 }
00231 
00232 /*virtual*/ mdb_err
00233 orkinTableRowCursor::CloseMdbObject(nsIMdbEnv* mev)
00234 {
00235   return this->Handle_CloseMdbObject(mev);
00236 }
00237 
00238 /*virtual*/ mdb_err
00239 orkinTableRowCursor::IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen)
00240 {
00241   return this->Handle_IsOpenMdbObject(mev, outOpen);
00242 }
00243 // } ----- end ref counting -----
00244 
00245 // } ===== end nsIMdbObject methods =====
00246 
00247 // { ===== begin nsIMdbCursor methods =====
00248 
00249 // { ----- begin attribute methods -----
00250 /*virtual*/ mdb_err
00251 orkinTableRowCursor::GetCount(nsIMdbEnv* mev, mdb_count* outCount)
00252 {
00253   mdb_err outErr = 0;
00254   mdb_count count = 0;
00255   morkEnv* ev =
00256     this->CanUseTableRowCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00257   if ( ev )
00258   {
00259     morkTableRowCursor* cursor = (morkTableRowCursor*) mHandle_Object;
00260     count = cursor->GetMemberCount(ev);
00261     outErr = ev->AsErr();
00262   }
00263   if ( outCount )
00264     *outCount = count;
00265   return outErr;
00266 }
00267 
00268 /*virtual*/ mdb_err
00269 orkinTableRowCursor::GetSeed(nsIMdbEnv* mev, mdb_seed* outSeed)
00270 {
00271   mdb_err outErr = 0;
00272   mdb_seed seed = 0;
00273   morkEnv* ev =
00274     this->CanUseTableRowCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00275   if ( ev )
00276   {
00277     ev->StubMethodOnlyError();
00278     outErr = ev->AsErr();
00279   }
00280   if ( outSeed )
00281     *outSeed = seed;
00282   return outErr;
00283 }
00284 
00285 /*virtual*/ mdb_err
00286 orkinTableRowCursor::SetPos(nsIMdbEnv* mev, mdb_pos inPos)
00287 {
00288   mdb_err outErr = 0;
00289   morkEnv* ev =
00290     this->CanUseTableRowCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00291   if ( ev )
00292   {
00293     morkTableRowCursor* cursor = (morkTableRowCursor*) mHandle_Object;
00294     cursor->mCursor_Pos = inPos;
00295     outErr = ev->AsErr();
00296   }
00297   return outErr;
00298 }
00299 
00300 /*virtual*/ mdb_err
00301 orkinTableRowCursor::GetPos(nsIMdbEnv* mev, mdb_pos* outPos)
00302 {
00303   mdb_err outErr = 0;
00304   mdb_pos pos = 0;
00305   morkEnv* ev =
00306     this->CanUseTableRowCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00307   if ( ev )
00308   {
00309     morkTableRowCursor* cursor = (morkTableRowCursor*) mHandle_Object;
00310     pos = cursor->mCursor_Pos;
00311     outErr = ev->AsErr();
00312   }
00313   if ( outPos )
00314     *outPos = pos;
00315   return outErr;
00316 }
00317 
00318 /*virtual*/ mdb_err
00319 orkinTableRowCursor::SetDoFailOnSeedOutOfSync(nsIMdbEnv* mev, mdb_bool inFail)
00320 {
00321   MORK_USED_1(inFail);
00322   mdb_err outErr = 0;
00323   morkEnv* ev =
00324     this->CanUseTableRowCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00325   if ( ev )
00326   {
00327     morkTableRowCursor* cursor = (morkTableRowCursor*) mHandle_Object;
00328     cursor->mCursor_DoFailOnSeedOutOfSync = inFail;
00329     outErr = ev->AsErr();
00330   }
00331   return outErr;
00332 }
00333 
00334 /*virtual*/ mdb_err
00335 orkinTableRowCursor::GetDoFailOnSeedOutOfSync(nsIMdbEnv* mev, mdb_bool* outFail)
00336 {
00337   mdb_bool fail = morkBool_kFalse;
00338   mdb_err outErr = 0;
00339   morkEnv* ev =
00340     this->CanUseTableRowCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00341   if ( ev )
00342   {
00343     morkTableRowCursor* cursor = (morkTableRowCursor*) mHandle_Object;
00344     fail = cursor->mCursor_DoFailOnSeedOutOfSync;
00345     outErr = ev->AsErr();
00346   }
00347   if ( outFail )
00348     *outFail = fail;
00349   return outErr;
00350 }
00351 // } ----- end attribute methods -----
00352 
00353 // } ===== end nsIMdbCursor methods =====
00354 
00355 
00356 // { ===== begin nsIMdbTableRowCursor methods =====
00357 
00358 // { ----- begin attribute methods -----
00359 
00360 /*virtual*/ mdb_err
00361 orkinTableRowCursor::GetTable(nsIMdbEnv* mev, nsIMdbTable** acqTable)
00362 {
00363   mdb_err outErr = 0;
00364   nsIMdbTable* outTable = 0;
00365   morkEnv* ev =
00366     this->CanUseTableRowCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00367   if ( ev )
00368   {
00369     morkTableRowCursor* cursor = (morkTableRowCursor*) mHandle_Object;
00370     morkTable* table = cursor->mTableRowCursor_Table;
00371     if ( table )
00372       outTable = table->AcquireTableHandle(ev);
00373     
00374     outErr = ev->AsErr();
00375   }
00376   if ( acqTable )
00377     *acqTable = outTable;
00378   return outErr;
00379 }
00380 // } ----- end attribute methods -----
00381 
00382 // { ----- begin oid iteration methods -----
00383 /*virtual*/ mdb_err
00384 orkinTableRowCursor::NextRowOid( // get row id of next row in the table
00385   nsIMdbEnv* mev, // context
00386   mdbOid* outOid, // out row oid
00387   mdb_pos* outRowPos)
00388 {
00389   mdb_err outErr = 0;
00390   mork_pos pos = -1;
00391   morkEnv* ev =
00392     this->CanUseTableRowCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00393   if ( ev )
00394   {
00395     if ( outOid )
00396     {
00397       pos = ((morkTableRowCursor*) mHandle_Object)->NextRowOid(ev, outOid);
00398     }
00399     else
00400       ev->NilPointerError();
00401     outErr = ev->AsErr();
00402   }
00403   if ( outRowPos )
00404     *outRowPos = pos;
00405   return outErr;
00406 }
00407 // } ----- end oid iteration methods -----
00408 
00409 // { ----- begin row iteration methods -----
00410 /*virtual*/ mdb_err
00411 orkinTableRowCursor::NextRow( // get row cells from table for cells already in row
00412   nsIMdbEnv* mev, // context
00413   nsIMdbRow** acqRow, // acquire next row in table
00414   mdb_pos* outRowPos)
00415 {
00416   mdb_err outErr = 0;
00417   nsIMdbRow* outRow = 0;
00418   morkEnv* ev =
00419     this->CanUseTableRowCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00420   if ( ev )
00421   {
00422     morkTableRowCursor* cursor = (morkTableRowCursor*) mHandle_Object;
00423       
00424     mdbOid oid; // place to put oid we intend to ignore
00425     morkRow* row = cursor->NextRow(ev, &oid, outRowPos);
00426     if ( row )
00427     {
00428       morkStore* store = row->GetRowSpaceStore(ev);
00429       if ( store )
00430         outRow = row->AcquireRowHandle(ev, store);
00431     }
00432     outErr = ev->AsErr();
00433   }
00434   if ( acqRow )
00435     *acqRow = outRow;
00436   return outErr;
00437 }
00438 // } ----- end row iteration methods -----
00439 
00440 
00441 // { ----- begin duplicate row removal methods -----
00442 /*virtual*/ mdb_err
00443 orkinTableRowCursor::CanHaveDupRowMembers(nsIMdbEnv* mev, // cursor might hold dups?
00444   mdb_bool* outCanHaveDups)
00445 {
00446   mdb_err outErr = 0;
00447   mdb_bool canHaveDups = mdbBool_kFalse;
00448   
00449   morkEnv* ev =
00450     this->CanUseTableRowCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00451   if ( ev )
00452   {
00453     morkTableRowCursor* cursor = (morkTableRowCursor*) mHandle_Object;
00454     canHaveDups = cursor->CanHaveDupRowMembers(ev);
00455     outErr = ev->AsErr();
00456   }
00457   if ( outCanHaveDups )
00458     *outCanHaveDups = canHaveDups;
00459   return outErr;
00460 }
00461   
00462 /*virtual*/ mdb_err
00463 orkinTableRowCursor::MakeUniqueCursor( // clone cursor, removing duplicate rows
00464   nsIMdbEnv* mev, // context
00465   nsIMdbTableRowCursor** acqCursor)    // acquire clone with no dups
00466   // Note that MakeUniqueCursor() is never necessary for a cursor which was
00467   // created by table method nsIMdbTable::GetTableRowCursor(), because a table
00468   // never contains the same row as a member more than once.  However, a cursor
00469   // created by table method nsIMdbTable::FindRowMatches() might contain the
00470   // same row more than once, because the same row can generate a hit by more
00471   // than one column with a matching string prefix.  Note this method can
00472   // return the very same cursor instance with just an incremented refcount,
00473   // when the original cursor could not contain any duplicate rows (calling
00474   // CanHaveDupRowMembers() shows this case on a false return).  Otherwise
00475   // this method returns a different cursor instance.  Callers should not use
00476   // this MakeUniqueCursor() method lightly, because it tends to defeat the
00477   // purpose of lazy programming techniques, since it can force creation of
00478   // an explicit row collection in a new cursor's representation, in order to
00479   // inspect the row membership and remove any duplicates; this can have big
00480   // impact if a collection holds tens of thousands of rows or more, when
00481   // the original cursor with dups simply referenced rows indirectly by row
00482   // position ranges, without using an explicit row set representation.
00483   // Callers are encouraged to use nsIMdbCursor::GetCount() to determine
00484   // whether the row collection is very large (tens of thousands), and to
00485   // delay calling MakeUniqueCursor() when possible, until a user interface
00486   // element actually demands the creation of an explicit set representation.
00487 {
00488   mdb_err outErr = 0;
00489   nsIMdbTableRowCursor* outCursor = 0;
00490   
00491   morkEnv* ev =
00492     this->CanUseTableRowCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00493   if ( ev )
00494   {
00495     if ( this->Handle_AddStrongRef(mev) == 0 )
00496       outCursor = this;
00497       
00498     outErr = ev->AsErr();
00499   }
00500   if ( acqCursor )
00501     *acqCursor = outCursor;
00502   return outErr;
00503 }
00504 // } ----- end duplicate row removal methods -----
00505 
00506 // } ===== end nsIMdbTableRowCursor methods =====
00507 
00508 
00509 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789