Back to index

lightning-sunbird  0.9+nobinonly
morkTableRowCursor.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  *   Blake Ross (blake@blakeross.com)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #ifndef _MDB_
00040 #include "mdb.h"
00041 #endif
00042 
00043 #ifndef _MORK_
00044 #include "mork.h"
00045 #endif
00046 
00047 #ifndef _MORKNODE_
00048 #include "morkNode.h"
00049 #endif
00050 
00051 #ifndef _MORKENV_
00052 #include "morkEnv.h"
00053 #endif
00054 
00055 #ifndef _MORKCURSOR_
00056 #include "morkCursor.h"
00057 #endif
00058 
00059 #ifndef _MORKTABLEROWCURSOR_
00060 #include "morkTableRowCursor.h"
00061 #endif
00062 
00063 #ifndef _ORKINTABLEROWCURSOR_
00064 #include "orkinTableRowCursor.h"
00065 #endif
00066 
00067 #ifndef _MORKSTORE_
00068 #include "morkStore.h"
00069 #endif
00070 
00071 #ifndef _MORKTABLE_
00072 #include "morkTable.h"
00073 #endif
00074 
00075 #ifndef _MORKROW_
00076 #include "morkRow.h"
00077 #endif
00078 
00079 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00080 
00081 // ````` ````` ````` ````` ````` 
00082 // { ===== begin morkNode interface =====
00083 
00084 /*public virtual*/ void
00085 morkTableRowCursor::CloseMorkNode(morkEnv* ev) // CloseTableRowCursor() only if open
00086 {
00087   if ( this->IsOpenNode() )
00088   {
00089     this->MarkClosing();
00090     this->CloseTableRowCursor(ev);
00091     this->MarkShut();
00092   }
00093 }
00094 
00095 /*public virtual*/
00096 morkTableRowCursor::~morkTableRowCursor() // CloseTableRowCursor() executed earlier
00097 {
00098   CloseMorkNode(mMorkEnv);
00099   MORK_ASSERT(this->IsShutNode());
00100 }
00101 
00102 /*public non-poly*/
00103 morkTableRowCursor::morkTableRowCursor(morkEnv* ev,
00104   const morkUsage& inUsage,
00105   nsIMdbHeap* ioHeap, morkTable* ioTable, mork_pos inRowPos)
00106 : morkCursor(ev, inUsage, ioHeap)
00107 , mTableRowCursor_Table( 0 )
00108 {
00109   if ( ev->Good() )
00110   {
00111     if ( ioTable )
00112     {
00113       mCursor_Pos = inRowPos;
00114       mCursor_Seed = ioTable->TableSeed();
00115       morkTable::SlotWeakTable(ioTable, ev, &mTableRowCursor_Table);
00116       if ( ev->Good() )
00117         mNode_Derived = morkDerived_kTableRowCursor;
00118     }
00119     else
00120       ev->NilPointerError();
00121   }
00122 }
00123 
00124 NS_IMPL_ISUPPORTS_INHERITED1(morkTableRowCursor, morkCursor, nsIMdbTableRowCursor)
00125 /*public non-poly*/ void
00126 morkTableRowCursor::CloseTableRowCursor(morkEnv* ev) 
00127 {
00128   if ( this )
00129   {
00130     if ( this->IsNode() )
00131     {
00132       mCursor_Pos = -1;
00133       mCursor_Seed = 0;
00134       morkTable::SlotWeakTable((morkTable*) 0, ev, &mTableRowCursor_Table);
00135       this->CloseCursor(ev);
00136       this->MarkShut();
00137     }
00138     else
00139       this->NonNodeError(ev);
00140   }
00141   else
00142     ev->NilPointerError();
00143 }
00144 
00145 // } ===== end morkNode methods =====
00146 // ````` ````` ````` ````` ````` 
00147 // { ----- begin attribute methods -----
00148 /*virtual*/ mdb_err
00149 morkTableRowCursor::GetCount(nsIMdbEnv* mev, mdb_count* outCount)
00150 {
00151   mdb_err outErr = 0;
00152   mdb_count count = 0;
00153   morkEnv* ev = morkEnv::FromMdbEnv(mev);
00154   if ( ev )
00155   {
00156     count = GetMemberCount(ev);
00157     outErr = ev->AsErr();
00158   }
00159   if ( outCount )
00160     *outCount = count;
00161   return outErr;
00162 }
00163 
00164 /*virtual*/ mdb_err
00165 morkTableRowCursor::GetSeed(nsIMdbEnv* mev, mdb_seed* outSeed)
00166 {
00167   NS_ASSERTION(PR_FALSE, "not implemented");
00168   return NS_ERROR_NOT_IMPLEMENTED;
00169 }
00170 
00171 /*virtual*/ mdb_err
00172 morkTableRowCursor::SetPos(nsIMdbEnv* mev, mdb_pos inPos)
00173 {
00174   mCursor_Pos = inPos;
00175   return NS_OK;
00176 }
00177 
00178 /*virtual*/ mdb_err
00179 morkTableRowCursor::GetPos(nsIMdbEnv* mev, mdb_pos* outPos)
00180 {
00181   *outPos = mCursor_Pos;
00182   return NS_OK;
00183 }
00184 
00185 /*virtual*/ mdb_err
00186 morkTableRowCursor::SetDoFailOnSeedOutOfSync(nsIMdbEnv* mev, mdb_bool inFail)
00187 {
00188   mCursor_DoFailOnSeedOutOfSync = inFail;
00189   return NS_OK;
00190 }
00191 
00192 /*virtual*/ mdb_err
00193 morkTableRowCursor::GetDoFailOnSeedOutOfSync(nsIMdbEnv* mev, mdb_bool* outFail)
00194 {
00195   NS_ENSURE_ARG_POINTER(outFail);
00196   *outFail = mCursor_DoFailOnSeedOutOfSync;
00197   return NS_OK;
00198 }
00199 // } ----- end attribute methods -----
00200 
00201 
00202 // { ===== begin nsIMdbTableRowCursor methods =====
00203 
00204 // { ----- begin attribute methods -----
00205 
00206 NS_IMETHODIMP
00207 morkTableRowCursor::GetTable(nsIMdbEnv* mev, nsIMdbTable** acqTable)
00208 {
00209   mdb_err outErr = 0;
00210   nsIMdbTable* outTable = 0;
00211   morkEnv* ev = morkEnv::FromMdbEnv(mev);
00212   if ( ev )
00213   {
00214     if ( mTableRowCursor_Table )
00215       outTable = mTableRowCursor_Table->AcquireTableHandle(ev);
00216     
00217     outErr = ev->AsErr();
00218   }
00219   if ( acqTable )
00220     *acqTable = outTable;
00221   return outErr;
00222 }
00223 // } ----- end attribute methods -----
00224 
00225 // { ----- begin oid iteration methods -----
00226 NS_IMETHODIMP
00227 morkTableRowCursor::NextRowOid( // get row id of next row in the table
00228   nsIMdbEnv* mev, // context
00229   mdbOid* outOid, // out row oid
00230   mdb_pos* outRowPos)
00231 {
00232   mdb_err outErr = 0;
00233   mork_pos pos = -1;
00234   morkEnv* ev = morkEnv::FromMdbEnv(mev);
00235   if ( ev )
00236   {
00237     if ( outOid )
00238     {
00239       pos = NextRowOid(ev, outOid);
00240     }
00241     else
00242       ev->NilPointerError();
00243     outErr = ev->AsErr();
00244   }
00245   if ( outRowPos )
00246     *outRowPos = pos;
00247   return outErr;
00248 }
00249 
00250 NS_IMETHODIMP
00251 morkTableRowCursor::PrevRowOid( // get row id of previous row in the table
00252   nsIMdbEnv* mev, // context
00253   mdbOid* outOid, // out row oid
00254   mdb_pos* outRowPos)
00255 {
00256   mdb_err outErr = 0;
00257   mork_pos pos = -1;
00258   morkEnv* ev = morkEnv::FromMdbEnv(mev);
00259   if ( ev )
00260   {
00261     if ( outOid )
00262     {
00263       pos = PrevRowOid(ev, outOid);
00264     }
00265     else
00266       ev->NilPointerError();
00267     outErr = ev->AsErr();
00268   }
00269   if ( outRowPos )
00270     *outRowPos = pos;
00271   return outErr;
00272 }
00273 // } ----- end oid iteration methods -----
00274 
00275 // { ----- begin row iteration methods -----
00276 NS_IMETHODIMP
00277 morkTableRowCursor::NextRow( // get row cells from table for cells already in row
00278   nsIMdbEnv* mev, // context
00279   nsIMdbRow** acqRow, // acquire next row in table
00280   mdb_pos* outRowPos)
00281 {
00282   mdb_err outErr = 0;
00283   nsIMdbRow* outRow = 0;
00284   morkEnv* ev = morkEnv::FromMdbEnv(mev);
00285   if ( ev )
00286   {
00287       
00288     mdbOid oid; // place to put oid we intend to ignore
00289     morkRow* row = NextRow(ev, &oid, outRowPos);
00290     if ( row )
00291     {
00292       morkStore* store = row->GetRowSpaceStore(ev);
00293       if ( store )
00294         outRow = row->AcquireRowHandle(ev, store);
00295     }
00296     outErr = ev->AsErr();
00297   }
00298   if ( acqRow )
00299     *acqRow = outRow;
00300   return outErr;
00301 }
00302 
00303 NS_IMETHODIMP
00304 morkTableRowCursor::PrevRow( // get row cells from table for cells already in row
00305   nsIMdbEnv* mev, // context
00306   nsIMdbRow** acqRow, // acquire previous row in table
00307   mdb_pos* outRowPos)
00308 {
00309   mdb_err outErr = 0;
00310   nsIMdbRow* outRow = 0;
00311   morkEnv* ev = morkEnv::FromMdbEnv(mev);
00312   if ( ev )
00313   {
00314       
00315     mdbOid oid; // place to put oid we intend to ignore
00316     morkRow* row = PrevRow(ev, &oid, outRowPos);
00317     if ( row )
00318     {
00319       morkStore* store = row->GetRowSpaceStore(ev);
00320       if ( store )
00321         outRow = row->AcquireRowHandle(ev, store);
00322     }
00323     outErr = ev->AsErr();
00324   }
00325   if ( acqRow )
00326     *acqRow = outRow;
00327   return outErr;
00328 }
00329 
00330 // } ----- end row iteration methods -----
00331 
00332 
00333 // { ----- begin duplicate row removal methods -----
00334 NS_IMETHODIMP
00335 morkTableRowCursor::CanHaveDupRowMembers(nsIMdbEnv* mev, // cursor might hold dups?
00336   mdb_bool* outCanHaveDups)
00337 {
00338   mdb_err outErr = 0;
00339   mdb_bool canHaveDups = mdbBool_kFalse;
00340   
00341   morkEnv* ev = morkEnv::FromMdbEnv(mev);
00342   if ( ev )
00343   {
00344     canHaveDups = CanHaveDupRowMembers(ev);
00345     outErr = ev->AsErr();
00346   }
00347   if ( outCanHaveDups )
00348     *outCanHaveDups = canHaveDups;
00349   return outErr;
00350 }
00351   
00352 NS_IMETHODIMP
00353 morkTableRowCursor::MakeUniqueCursor( // clone cursor, removing duplicate rows
00354   nsIMdbEnv* mev, // context
00355   nsIMdbTableRowCursor** acqCursor)    // acquire clone with no dups
00356   // Note that MakeUniqueCursor() is never necessary for a cursor which was
00357   // created by table method nsIMdbTable::GetTableRowCursor(), because a table
00358   // never contains the same row as a member more than once.  However, a cursor
00359   // created by table method nsIMdbTable::FindRowMatches() might contain the
00360   // same row more than once, because the same row can generate a hit by more
00361   // than one column with a matching string prefix.  Note this method can
00362   // return the very same cursor instance with just an incremented refcount,
00363   // when the original cursor could not contain any duplicate rows (calling
00364   // CanHaveDupRowMembers() shows this case on a false return).  Otherwise
00365   // this method returns a different cursor instance.  Callers should not use
00366   // this MakeUniqueCursor() method lightly, because it tends to defeat the
00367   // purpose of lazy programming techniques, since it can force creation of
00368   // an explicit row collection in a new cursor's representation, in order to
00369   // inspect the row membership and remove any duplicates; this can have big
00370   // impact if a collection holds tens of thousands of rows or more, when
00371   // the original cursor with dups simply referenced rows indirectly by row
00372   // position ranges, without using an explicit row set representation.
00373   // Callers are encouraged to use nsIMdbCursor::GetCount() to determine
00374   // whether the row collection is very large (tens of thousands), and to
00375   // delay calling MakeUniqueCursor() when possible, until a user interface
00376   // element actually demands the creation of an explicit set representation.
00377 {
00378   mdb_err outErr = 0;
00379   nsIMdbTableRowCursor* outCursor = 0;
00380   
00381   morkEnv* ev = morkEnv::FromMdbEnv(mev);
00382   if ( ev )
00383   {
00384     AddRef();
00385     outCursor = this;
00386       
00387     outErr = ev->AsErr();
00388   }
00389   if ( acqCursor )
00390     *acqCursor = outCursor;
00391   return outErr;
00392 }
00393 // } ----- end duplicate row removal methods -----
00394 
00395 // } ===== end nsIMdbTableRowCursor methods =====
00396 
00397 
00398 /*static*/ void
00399 morkTableRowCursor::NonTableRowCursorTypeError(morkEnv* ev)
00400 {
00401   ev->NewError("non morkTableRowCursor");
00402 }
00403 
00404 
00405 mdb_pos
00406 morkTableRowCursor::NextRowOid(morkEnv* ev, mdbOid* outOid)
00407 {
00408   mdb_pos outPos = -1;
00409   (void) this->NextRow(ev, outOid, &outPos);
00410   return outPos;
00411 }
00412 
00413 mdb_pos
00414 morkTableRowCursor::PrevRowOid(morkEnv* ev, mdbOid* outOid)
00415 {
00416   mdb_pos outPos = -1;
00417   (void) this->PrevRow(ev, outOid, &outPos);
00418   return outPos;
00419 }
00420 
00421 mork_bool
00422 morkTableRowCursor::CanHaveDupRowMembers(morkEnv* ev)
00423 {
00424   return morkBool_kFalse; // false default is correct
00425 }
00426 
00427 mork_count
00428 morkTableRowCursor::GetMemberCount(morkEnv* ev)
00429 {
00430   morkTable* table = mTableRowCursor_Table;
00431   if ( table )
00432     return table->mTable_RowArray.mArray_Fill;
00433   else
00434     return 0;
00435 }
00436 
00437 morkRow*
00438 morkTableRowCursor::PrevRow(morkEnv* ev, mdbOid* outOid, mdb_pos* outPos)
00439 {
00440   morkRow* outRow = 0;
00441   mork_pos pos = -1;
00442   
00443   morkTable* table = mTableRowCursor_Table;
00444   if ( table )
00445   {
00446     if ( table->IsOpenNode() )
00447     {
00448       morkArray* array = &table->mTable_RowArray;
00449       pos = mCursor_Pos - 1;
00450         
00451       if ( pos >= 0 && pos < (mork_pos)(array->mArray_Fill) )
00452       {
00453         mCursor_Pos = pos; // update for next time
00454         morkRow* row = (morkRow*) array->At(pos);
00455         if ( row )
00456         {
00457           if ( row->IsRow() )
00458           {
00459             outRow = row;
00460             *outOid = row->mRow_Oid;
00461           }
00462           else
00463             row->NonRowTypeError(ev);
00464         }
00465         else
00466           ev->NilPointerError();
00467       }
00468       else
00469       {
00470         outOid->mOid_Scope = 0;
00471         outOid->mOid_Id = morkId_kMinusOne;
00472       }
00473     }
00474     else
00475       table->NonOpenNodeError(ev);
00476   }
00477   else
00478     ev->NilPointerError();
00479 
00480   *outPos = pos;
00481   return outRow;
00482 }
00483 
00484 morkRow*
00485 morkTableRowCursor::NextRow(morkEnv* ev, mdbOid* outOid, mdb_pos* outPos)
00486 {
00487   morkRow* outRow = 0;
00488   mork_pos pos = -1;
00489   
00490   morkTable* table = mTableRowCursor_Table;
00491   if ( table )
00492   {
00493     if ( table->IsOpenNode() )
00494     {
00495       morkArray* array = &table->mTable_RowArray;
00496       pos = mCursor_Pos;
00497       if ( pos < 0 )
00498         pos = 0;
00499       else
00500         ++pos;
00501         
00502       if ( pos < (mork_pos)(array->mArray_Fill) )
00503       {
00504         mCursor_Pos = pos; // update for next time
00505         morkRow* row = (morkRow*) array->At(pos);
00506         if ( row )
00507         {
00508           if ( row->IsRow() )
00509           {
00510             outRow = row;
00511             *outOid = row->mRow_Oid;
00512           }
00513           else
00514             row->NonRowTypeError(ev);
00515         }
00516         else
00517           ev->NilPointerError();
00518       }
00519       else
00520       {
00521         outOid->mOid_Scope = 0;
00522         outOid->mOid_Id = morkId_kMinusOne;
00523       }
00524     }
00525     else
00526       table->NonOpenNodeError(ev);
00527   }
00528   else
00529     ev->NilPointerError();
00530 
00531   *outPos = pos;
00532   return outRow;
00533 }
00534 
00535 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789