Back to index

lightning-sunbird  0.9+nobinonly
morkRow.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 _MORKROW_
00051 #include "morkRow.h"
00052 #endif
00053 
00054 #ifndef _MORKENV_
00055 #include "morkEnv.h"
00056 #endif
00057 
00058 #ifndef _MORKROWSPACE_
00059 #include "morkRowSpace.h"
00060 #endif
00061 
00062 #ifndef _MORKPOOL_
00063 #include "morkPool.h"
00064 #endif
00065 
00066 #ifndef _MORKROWOBJECT_
00067 #include "morkRowObject.h"
00068 #endif
00069 
00070 #ifndef _MORKCELLOBJECT_
00071 #include "morkCellObject.h"
00072 #endif
00073 
00074 #ifndef _MORKCELL_
00075 #include "morkCell.h"
00076 #endif
00077 
00078 #ifndef _MORKSTORE_
00079 #include "morkStore.h"
00080 #endif
00081 
00082 #ifndef _MORKROWCELLCURSOR_
00083 #include "morkRowCellCursor.h"
00084 #endif
00085 
00086 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00087 
00088 
00089 // notifications regarding row changes:
00090 
00091 void morkRow::NoteRowAddCol(morkEnv* ev, mork_column inColumn)
00092 {
00093   if ( !this->IsRowRewrite() )
00094   {
00095     mork_delta newDelta;
00096     morkDelta_Init(newDelta, inColumn, morkChange_kAdd);
00097     
00098     if ( newDelta != mRow_Delta ) // not repeating existing data?
00099     {
00100       if ( this->HasRowDelta() ) // already have one change recorded?
00101         this->SetRowRewrite(); // just plan to write all row cells
00102       else
00103         this->SetRowDelta(inColumn, morkChange_kAdd);
00104     }
00105   }
00106   else
00107     this->ClearRowDelta();
00108 }
00109 
00110 void morkRow::NoteRowCutCol(morkEnv* ev, mork_column inColumn)
00111 {
00112   if ( !this->IsRowRewrite() )
00113   {
00114     mork_delta newDelta;
00115     morkDelta_Init(newDelta, inColumn, morkChange_kCut);
00116     
00117     if ( newDelta != mRow_Delta ) // not repeating existing data?
00118     {
00119       if ( this->HasRowDelta() ) // already have one change recorded?
00120         this->SetRowRewrite(); // just plan to write all row cells
00121       else
00122         this->SetRowDelta(inColumn, morkChange_kCut);
00123     }
00124   }
00125   else
00126     this->ClearRowDelta();
00127 }
00128 
00129 void morkRow::NoteRowSetCol(morkEnv* ev, mork_column inColumn)
00130 {
00131   if ( !this->IsRowRewrite() )
00132   {
00133     if ( this->HasRowDelta() ) // already have one change recorded?
00134       this->SetRowRewrite(); // just plan to write all row cells
00135     else
00136       this->SetRowDelta(inColumn, morkChange_kSet);
00137   }
00138   else
00139     this->ClearRowDelta();
00140 }
00141 
00142 void morkRow::NoteRowSetAll(morkEnv* ev)
00143 {
00144   this->SetRowRewrite(); // just plan to write all row cells
00145   this->ClearRowDelta();
00146 }
00147 
00148 mork_u2
00149 morkRow::AddRowGcUse(morkEnv* ev)
00150 {
00151   if ( this->IsRow() )
00152   {
00153     if ( mRow_GcUses < morkRow_kMaxGcUses ) // not already maxed out?
00154       ++mRow_GcUses;
00155   }
00156   else
00157     this->NonRowTypeError(ev);
00158     
00159   return mRow_GcUses;
00160 }
00161 
00162 mork_u2
00163 morkRow::CutRowGcUse(morkEnv* ev)
00164 {
00165   if ( this->IsRow() )
00166   {
00167     if ( mRow_GcUses ) // any outstanding uses to cut?
00168     {
00169       if ( mRow_GcUses < morkRow_kMaxGcUses ) // not frozen at max?
00170         --mRow_GcUses;
00171     }
00172     else
00173       this->GcUsesUnderflowWarning(ev);
00174   }
00175   else
00176     this->NonRowTypeError(ev);
00177     
00178   return mRow_GcUses;
00179 }
00180 
00181 /*static*/ void
00182 morkRow::GcUsesUnderflowWarning(morkEnv* ev)
00183 {
00184   ev->NewWarning("mRow_GcUses underflow");
00185 }
00186 
00187 
00188 /*static*/ void
00189 morkRow::NonRowTypeError(morkEnv* ev)
00190 {
00191   ev->NewError("non morkRow");
00192 }
00193 
00194 /*static*/ void
00195 morkRow::NonRowTypeWarning(morkEnv* ev)
00196 {
00197   ev->NewWarning("non morkRow");
00198 }
00199 
00200 /*static*/ void
00201 morkRow::LengthBeyondMaxError(morkEnv* ev)
00202 {
00203   ev->NewError("mRow_Length over max");
00204 }
00205 
00206 /*static*/ void
00207 morkRow::ZeroColumnError(morkEnv* ev)
00208 {
00209   ev->NewError(" zero mork_column");
00210 }
00211 
00212 /*static*/ void
00213 morkRow::NilCellsError(morkEnv* ev)
00214 {
00215   ev->NewError("nil mRow_Cells");
00216 }
00217 
00218 void
00219 morkRow::InitRow(morkEnv* ev, const mdbOid* inOid, morkRowSpace* ioSpace,
00220   mork_size inLength, morkPool* ioPool)
00221   // if inLength is nonzero, cells will be allocated from ioPool
00222 {
00223   if ( ioSpace && ioPool && inOid )
00224   {
00225     if ( inLength <= morkRow_kMaxLength )
00226     {
00227       if ( inOid->mOid_Id != morkRow_kMinusOneRid )
00228       {
00229         mRow_Space = ioSpace;
00230         mRow_Object = 0;
00231         mRow_Cells = 0;
00232         mRow_Oid = *inOid;
00233 
00234         mRow_Length = (mork_u2) inLength;
00235         mRow_Seed = (mork_u2) (mork_ip) this; // "random" assignment
00236 
00237         mRow_GcUses = 0;
00238         mRow_Pad = 0;
00239         mRow_Flags = 0;
00240         mRow_Tag = morkRow_kTag;
00241         
00242         morkZone* zone = &ioSpace->mSpace_Store->mStore_Zone;
00243 
00244         if ( inLength )
00245           mRow_Cells = ioPool->NewCells(ev, inLength, zone);
00246 
00247         if ( this->MaybeDirtySpaceStoreAndRow() ) // new row might dirty store
00248         {
00249           this->SetRowRewrite();
00250           this->NoteRowSetAll(ev);
00251         }
00252       }
00253       else
00254         ioSpace->MinusOneRidError(ev);
00255     }
00256     else
00257       this->LengthBeyondMaxError(ev);
00258   }
00259   else
00260     ev->NilPointerError();
00261 }
00262 
00263 morkRowObject*
00264 morkRow::AcquireRowObject(morkEnv* ev, morkStore* ioStore)
00265 {
00266   morkRowObject* ro = mRow_Object;
00267   if ( ro ) // need new row object?
00268     ro->AddRef();
00269   else
00270   {
00271     nsIMdbHeap* heap = ioStore->mPort_Heap;
00272     ro = new(*heap, ev)
00273       morkRowObject(ev, morkUsage::kHeap, heap, this, ioStore);
00274 
00275     morkRowObject::SlotWeakRowObject(ro, ev, &mRow_Object);
00276     ro->AddRef();
00277   }
00278   return ro;
00279 }
00280 
00281 nsIMdbRow*
00282 morkRow::AcquireRowHandle(morkEnv* ev, morkStore* ioStore)
00283 {
00284   return AcquireRowObject(ev, ioStore);
00285 }
00286 
00287 nsIMdbCell*
00288 morkRow::AcquireCellHandle(morkEnv* ev, morkCell* ioCell,
00289   mdb_column inCol, mork_pos inPos)
00290 {
00291   nsIMdbHeap* heap = ev->mEnv_Heap;
00292   morkCellObject* cellObj = new(*heap, ev)
00293     morkCellObject(ev, morkUsage::kHeap, heap, this, ioCell, inCol, inPos);
00294   if ( cellObj )
00295   {
00296     nsIMdbCell* cellHandle = cellObj->AcquireCellHandle(ev);
00297 //    cellObj->CutStrongRef(ev->AsMdbEnv());
00298     return cellHandle;
00299   }
00300   return (nsIMdbCell*) 0;
00301 }
00302 
00303 mork_count
00304 morkRow::CountOverlap(morkEnv* ev, morkCell* ioVector, mork_fill inFill)
00305   // Count cells in ioVector that change existing cells in this row when
00306   // ioVector is added to the row (as in TakeCells()).   This is the set
00307   // of cells with the same columns in ioVector and mRow_Cells, which do
00308   // not have exactly the same value in mCell_Atom, and which do not both
00309   // have change status equal to morkChange_kCut (because cutting a cut
00310   // cell still yields a cell that has been cut).  CountOverlap() also
00311   // modifies the change attribute of any cell in ioVector to kDup when
00312   // the change was previously kCut and the same column cell was found
00313   // in this row with change also equal to kCut; this tells callers later
00314   // they need not look for that cell in the row again on a second pass.
00315 {
00316   mork_count outCount = 0;
00317   mork_pos pos = 0; // needed by GetCell()
00318   morkCell* cells = ioVector;
00319   morkCell* end = cells + inFill;
00320   --cells; // prepare for preincrement
00321   while ( ++cells < end && ev->Good() )
00322   {
00323     mork_column col = cells->GetColumn();
00324     
00325     morkCell* old = this->GetCell(ev, col, &pos);
00326     if ( old ) // same column?
00327     {
00328       mork_change newChg = cells->GetChange();
00329       mork_change oldChg = old->GetChange();
00330       if ( newChg != morkChange_kCut || oldChg != newChg ) // not cut+cut?
00331       {
00332         if ( cells->mCell_Atom != old->mCell_Atom ) // not same atom?
00333           ++outCount; // cells will replace old significantly when added
00334       }
00335       else
00336         cells->SetColumnAndChange(col, morkChange_kDup); // note dup status
00337     }
00338   }
00339   return outCount;
00340 }
00341 
00342 void
00343 morkRow::MergeCells(morkEnv* ev, morkCell* ioVector,
00344   mork_fill inVecLength, mork_fill inOldRowFill, mork_fill inOverlap)
00345   // MergeCells() is the part of TakeCells() that does the insertion.
00346   // inOldRowFill is the old value of mRow_Length, and inOverlap is the
00347   // number of cells in the intersection that must be updated.
00348 {
00349   morkCell* newCells = mRow_Cells + inOldRowFill; // 1st new cell in row
00350   morkCell* newEnd = newCells + mRow_Length; // one past last cell
00351 
00352   morkCell* srcCells = ioVector;
00353   morkCell* srcEnd = srcCells + inVecLength;
00354   
00355   --srcCells; // prepare for preincrement
00356   while ( ++srcCells < srcEnd && ev->Good() )
00357   {
00358     mork_change srcChg = srcCells->GetChange();
00359     if ( srcChg != morkChange_kDup ) // anything to be done?
00360     {
00361       morkCell* dstCell = 0;
00362       if ( inOverlap )
00363       {
00364         mork_pos pos = 0; // needed by GetCell()
00365         dstCell = this->GetCell(ev, srcCells->GetColumn(), &pos);
00366       }
00367       if ( dstCell )
00368       {
00369         --inOverlap; // one fewer intersections to resolve
00370         // swap the atoms in the cells to avoid ref counting here:
00371         morkAtom* dstAtom = dstCell->mCell_Atom;
00372         *dstCell = *srcCells; // bitwise copy, taking src atom
00373         srcCells->mCell_Atom = dstAtom; // forget cell ref, if any
00374       }
00375       else if ( newCells < newEnd ) // another new cell exists?
00376       {
00377         dstCell = newCells++; // alloc another new cell
00378         // take atom from source cell, transferring ref to this row:
00379         *dstCell = *srcCells; // bitwise copy, taking src atom
00380         srcCells->mCell_Atom = 0; // forget cell ref, if any
00381       }
00382       else // oops, we ran out...
00383         ev->NewError("out of new cells");
00384     }
00385   }
00386 }
00387 
00388 void
00389 morkRow::TakeCells(morkEnv* ev, morkCell* ioVector, mork_fill inVecLength,
00390   morkStore* ioStore)
00391 {
00392   if ( ioVector && inVecLength && ev->Good() )
00393   {
00394     ++mRow_Seed; // intend to change structure of mRow_Cells
00395     mork_size length = (mork_size) mRow_Length;
00396     
00397     mork_count overlap = this->CountOverlap(ev, ioVector, inVecLength);
00398 
00399     mork_size growth = inVecLength - overlap; // cells to add
00400     mork_size newLength = length + growth;
00401     
00402     if ( growth && ev->Good() ) // need to add any cells?
00403     {
00404       morkZone* zone = &ioStore->mStore_Zone;
00405       morkPool* pool = ioStore->StorePool();
00406       if ( !pool->AddRowCells(ev, this, length + growth, zone) )
00407         ev->NewError("cannot take cells");
00408     }
00409     if ( ev->Good() )
00410     {
00411       if ( mRow_Length >= newLength )
00412         this->MergeCells(ev, ioVector, inVecLength, length, overlap);
00413       else
00414         ev->NewError("not enough new cells");
00415     }
00416   }
00417 }
00418 
00419 mork_bool morkRow::MaybeDirtySpaceStoreAndRow()
00420 {
00421   morkRowSpace* rowSpace = mRow_Space;
00422   if ( rowSpace )
00423   {
00424     morkStore* store = rowSpace->mSpace_Store;
00425     if ( store && store->mStore_CanDirty )
00426     {
00427       store->SetStoreDirty();
00428       rowSpace->mSpace_CanDirty = morkBool_kTrue;
00429     }
00430     
00431     if ( rowSpace->mSpace_CanDirty )
00432     {
00433       this->SetRowDirty();
00434       rowSpace->SetRowSpaceDirty();
00435       return morkBool_kTrue;
00436     }
00437   }
00438   return morkBool_kFalse;
00439 }
00440 
00441 morkCell*
00442 morkRow::NewCell(morkEnv* ev, mdb_column inColumn,
00443   mork_pos* outPos, morkStore* ioStore)
00444 {
00445   ++mRow_Seed; // intend to change structure of mRow_Cells
00446   mork_size length = (mork_size) mRow_Length;
00447   *outPos = (mork_pos) length;
00448   morkPool* pool = ioStore->StorePool();
00449   morkZone* zone = &ioStore->mStore_Zone;
00450   
00451   mork_bool canDirty = this->MaybeDirtySpaceStoreAndRow();
00452   
00453   if ( pool->AddRowCells(ev, this, length + 1, zone) )
00454   {
00455     morkCell* cell = mRow_Cells + length;
00456     // next line equivalent to inline morkCell::SetCellDirty():
00457     if ( canDirty )
00458       cell->SetCellColumnDirty(inColumn);
00459     else
00460       cell->SetCellColumnClean(inColumn);
00461       
00462     if ( canDirty && !this->IsRowRewrite() )
00463       this->NoteRowAddCol(ev, inColumn);
00464       
00465     return cell;
00466   }
00467     
00468   return (morkCell*) 0;
00469 }
00470 
00471 
00472 
00473 void morkRow::SeekColumn(morkEnv* ev, mdb_pos inPos, 
00474   mdb_column* outColumn, mdbYarn* outYarn)
00475 {
00476   morkCell* cells = mRow_Cells;
00477   if ( cells && inPos < mRow_Length && inPos >= 0 )
00478   {
00479     morkCell* c = cells + inPos;
00480     if ( outColumn )
00481        *outColumn = c->GetColumn();
00482     if ( outYarn )
00483        c->mCell_Atom->GetYarn(outYarn); // nil atom works okay here
00484   }
00485   else
00486   {
00487     if ( outColumn )
00488        *outColumn = 0;
00489     if ( outYarn )
00490        ((morkAtom*) 0)->GetYarn(outYarn); // yes this will work
00491   }
00492 }
00493 
00494 void
00495 morkRow::NextColumn(morkEnv* ev, mdb_column* ioColumn, mdbYarn* outYarn)
00496 {
00497   morkCell* cells = mRow_Cells;
00498   if ( cells )
00499   {
00500        mork_column last = 0;
00501        mork_column inCol = *ioColumn;
00502     morkCell* end = cells + mRow_Length;
00503     while ( cells < end )
00504     {
00505       if ( inCol == last ) // found column?
00506       {
00507                   if ( outYarn )
00508                      cells->mCell_Atom->GetYarn(outYarn); // nil atom works okay here
00509         *ioColumn = cells->GetColumn();
00510         return;  // stop, we are done
00511       }
00512       else
00513       {
00514         last = cells->GetColumn();
00515         ++cells;
00516       }
00517     }
00518   }
00519        *ioColumn = 0;
00520   if ( outYarn )
00521        ((morkAtom*) 0)->GetYarn(outYarn); // yes this will work
00522 }
00523 
00524 morkCell*
00525 morkRow::CellAt(morkEnv* ev, mork_pos inPos) const
00526 {
00527   MORK_USED_1(ev);
00528   morkCell* cells = mRow_Cells;
00529   if ( cells && inPos < mRow_Length && inPos >= 0 )
00530   {
00531     return cells + inPos;
00532   }
00533   return (morkCell*) 0;
00534 }
00535 
00536 morkCell*
00537 morkRow::GetCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos) const
00538 {
00539   MORK_USED_1(ev);
00540   morkCell* cells = mRow_Cells;
00541   if ( cells )
00542   {
00543     morkCell* end = cells + mRow_Length;
00544     while ( cells < end )
00545     {
00546       mork_column col = cells->GetColumn();
00547       if ( col == inColumn ) // found the desired column?
00548       {
00549         *outPos = cells - mRow_Cells;
00550         return cells;
00551       }
00552       else
00553         ++cells;
00554     }
00555   }
00556   *outPos = -1;
00557   return (morkCell*) 0;
00558 }
00559 
00560 mork_aid
00561 morkRow::GetCellAtomAid(morkEnv* ev, mdb_column inColumn) const
00562   // GetCellAtomAid() finds the cell with column inColumn, and sees if the
00563   // atom has a token ID, and returns the atom's ID if there is one.  Or
00564   // else zero is returned if there is no such column, or no atom, or if
00565   // the atom has no ID to return.  This method is intended to support
00566   // efficient updating of column indexes for rows in a row space.
00567 {
00568   if ( this && this->IsRow() )
00569   {
00570     morkCell* cells = mRow_Cells;
00571     if ( cells )
00572     {
00573       morkCell* end = cells + mRow_Length;
00574       while ( cells < end )
00575       {
00576         mork_column col = cells->GetColumn();
00577         if ( col == inColumn ) // found desired column?
00578         {
00579           morkAtom* atom = cells->mCell_Atom;
00580           if ( atom && atom->IsBook() )
00581             return ((morkBookAtom*) atom)->mBookAtom_Id;
00582           else
00583             return 0;
00584         }
00585         else
00586           ++cells;
00587       }
00588     }
00589   }
00590   else
00591     this->NonRowTypeError(ev);
00592 
00593   return 0;
00594 }
00595 
00596 void
00597 morkRow::EmptyAllCells(morkEnv* ev)
00598 {
00599   morkCell* cells = mRow_Cells;
00600   if ( cells )
00601   {
00602     morkStore* store = this->GetRowSpaceStore(ev);
00603     if ( store )
00604     {
00605       if ( this->MaybeDirtySpaceStoreAndRow() )
00606       {
00607         this->SetRowRewrite();
00608         this->NoteRowSetAll(ev);
00609       }
00610       morkPool* pool = store->StorePool();
00611       morkCell* end = cells + mRow_Length;
00612       --cells; // prepare for preincrement:
00613       while ( ++cells < end )
00614       {
00615         if ( cells->mCell_Atom )
00616           cells->SetAtom(ev, (morkAtom*) 0, pool);
00617       }
00618     }
00619   }
00620 }
00621 
00622 void 
00623 morkRow::cut_all_index_entries(morkEnv* ev)
00624 {
00625   morkRowSpace* rowSpace = mRow_Space;
00626   if ( rowSpace->mRowSpace_IndexCount ) // any indexes?
00627   {
00628     morkCell* cells = mRow_Cells;
00629     if ( cells )
00630     {
00631       morkCell* end = cells + mRow_Length;
00632       --cells; // prepare for preincrement:
00633       while ( ++cells < end )
00634       {
00635         morkAtom* atom = cells->mCell_Atom;
00636         if ( atom )
00637         {
00638           mork_aid atomAid = atom->GetBookAtomAid();
00639           if ( atomAid )
00640           {
00641             mork_column col = cells->GetColumn();
00642             morkAtomRowMap* map = rowSpace->FindMap(ev, col);
00643             if ( map ) // cut row from index for this column?
00644               map->CutAid(ev, atomAid);
00645           }
00646         }
00647       }
00648     }
00649   }
00650 }
00651 
00652 void
00653 morkRow::CutAllColumns(morkEnv* ev)
00654 {
00655   morkStore* store = this->GetRowSpaceStore(ev);
00656   if ( store )
00657   {
00658     if ( this->MaybeDirtySpaceStoreAndRow() )
00659     {
00660       this->SetRowRewrite();
00661       this->NoteRowSetAll(ev);
00662     }
00663     morkRowSpace* rowSpace = mRow_Space;
00664     if ( rowSpace->mRowSpace_IndexCount ) // any indexes?
00665       this->cut_all_index_entries(ev);
00666   
00667     morkPool* pool = store->StorePool();
00668     pool->CutRowCells(ev, this, /*newSize*/ 0, &store->mStore_Zone);
00669   }
00670 }
00671 
00672 void
00673 morkRow::SetRow(morkEnv* ev, const morkRow* inSourceRow)
00674 {  
00675   // note inSourceRow might be in another DB, with a different store...
00676   morkStore* store = this->GetRowSpaceStore(ev);
00677   morkStore* srcStore = inSourceRow->GetRowSpaceStore(ev);
00678   if ( store && srcStore )
00679   {
00680     if ( this->MaybeDirtySpaceStoreAndRow() )
00681     {
00682       this->SetRowRewrite();
00683       this->NoteRowSetAll(ev);
00684     }
00685     morkRowSpace* rowSpace = mRow_Space;
00686     mork_count indexes = rowSpace->mRowSpace_IndexCount; // any indexes?
00687     
00688     mork_bool sameStore = ( store == srcStore ); // identical stores?
00689     morkPool* pool = store->StorePool();
00690     if ( pool->CutRowCells(ev, this, /*newSize*/ 0, &store->mStore_Zone) )
00691     {
00692       mork_fill fill = inSourceRow->mRow_Length;
00693       if ( pool->AddRowCells(ev, this, fill, &store->mStore_Zone) )
00694       {
00695         morkCell* dst = mRow_Cells;
00696         morkCell* dstEnd = dst + mRow_Length;
00697         
00698         const morkCell* src = inSourceRow->mRow_Cells;
00699         const morkCell* srcEnd = src + fill;
00700         --dst; --src; // prepare both for preincrement:
00701         
00702         while ( ++dst < dstEnd && ++src < srcEnd && ev->Good() )
00703         {
00704           morkAtom* atom = src->mCell_Atom;
00705           mork_column dstCol = src->GetColumn();
00706           // Note we modify the mCell_Atom slot directly instead of using
00707           // morkCell::SetAtom(), because we know it starts equal to nil.
00708           
00709           if ( sameStore ) // source and dest in same store?
00710           {
00711             // next line equivalent to inline morkCell::SetCellDirty():
00712             dst->SetCellColumnDirty(dstCol);
00713             dst->mCell_Atom = atom;
00714             if ( atom ) // another ref to non-nil atom?
00715               atom->AddCellUse(ev);
00716           }
00717           else // need to dup items from src store in a dest store
00718           {
00719             dstCol = store->CopyToken(ev, dstCol, srcStore);
00720             if ( dstCol )
00721             {
00722               // next line equivalent to inline morkCell::SetCellDirty():
00723               dst->SetCellColumnDirty(dstCol);
00724               atom = store->CopyAtom(ev, atom);
00725               dst->mCell_Atom = atom;
00726               if ( atom ) // another ref?
00727                 atom->AddCellUse(ev);
00728             }
00729           }
00730           if ( indexes && atom )
00731           {
00732             mork_aid atomAid = atom->GetBookAtomAid();
00733             if ( atomAid )
00734             {
00735               morkAtomRowMap* map = rowSpace->FindMap(ev, dstCol);
00736               if ( map )
00737                 map->AddAid(ev, atomAid, this);
00738             }
00739           }
00740         }
00741       }
00742     }
00743   }
00744 }
00745 
00746 void
00747 morkRow::AddRow(morkEnv* ev, const morkRow* inSourceRow)
00748 {
00749   if ( mRow_Length ) // any existing cells we might need to keep?
00750   {
00751     ev->StubMethodOnlyError();
00752   }
00753   else
00754     this->SetRow(ev, inSourceRow); // just exactly duplicate inSourceRow
00755 }
00756 
00757 void
00758 morkRow::OnZeroRowGcUse(morkEnv* ev)
00759 // OnZeroRowGcUse() is called when CutRowGcUse() returns zero.
00760 {
00761   MORK_USED_1(ev);
00762   // ev->NewWarning("need to implement OnZeroRowGcUse");
00763 }
00764 
00765 void
00766 morkRow::DirtyAllRowContent(morkEnv* ev)
00767 {
00768   MORK_USED_1(ev);
00769 
00770   if ( this->MaybeDirtySpaceStoreAndRow() )
00771   {
00772     this->SetRowRewrite();
00773     this->NoteRowSetAll(ev);
00774   }
00775   morkCell* cells = mRow_Cells;
00776   if ( cells )
00777   {
00778     morkCell* end = cells + mRow_Length;
00779     --cells; // prepare for preincrement:
00780     while ( ++cells < end )
00781     {
00782       cells->SetCellDirty();
00783     }
00784   }
00785 }
00786 
00787 morkStore*
00788 morkRow::GetRowSpaceStore(morkEnv* ev) const
00789 {
00790   morkRowSpace* rowSpace = mRow_Space;
00791   if ( rowSpace )
00792   {
00793     morkStore* store = rowSpace->mSpace_Store;
00794     if ( store )
00795     {
00796       if ( store->IsStore() )
00797       {
00798         return store;
00799       }
00800       else
00801         store->NonStoreTypeError(ev);
00802     }
00803     else
00804       ev->NilPointerError();
00805   }
00806   else
00807     ev->NilPointerError();
00808     
00809   return (morkStore*) 0;
00810 }
00811 
00812 void morkRow::CutColumn(morkEnv* ev, mdb_column inColumn)
00813 {
00814   mork_pos pos = -1;
00815   morkCell* cell = this->GetCell(ev, inColumn, &pos);
00816   if ( cell ) 
00817   {
00818     morkStore* store = this->GetRowSpaceStore(ev);
00819     if ( store )
00820     {
00821       if ( this->MaybeDirtySpaceStoreAndRow() && !this->IsRowRewrite() )
00822         this->NoteRowCutCol(ev, inColumn);
00823         
00824       morkRowSpace* rowSpace = mRow_Space;
00825       morkAtomRowMap* map = ( rowSpace->mRowSpace_IndexCount )?
00826         rowSpace->FindMap(ev, inColumn) : (morkAtomRowMap*) 0;
00827       if ( map ) // this row attribute is indexed by row space?
00828       {
00829         morkAtom* oldAtom = cell->mCell_Atom;
00830         if ( oldAtom ) // need to cut an entry from the index?
00831         {
00832           mork_aid oldAid = oldAtom->GetBookAtomAid();
00833           if ( oldAid ) // cut old row attribute from row index in space?
00834             map->CutAid(ev, oldAid);
00835         }
00836       }
00837       
00838       morkPool* pool = store->StorePool();
00839       cell->SetAtom(ev, (morkAtom*) 0, pool);
00840       
00841       mork_fill fill = mRow_Length; // should not be zero
00842       MORK_ASSERT(fill);
00843       if ( fill ) // index < fill for last cell exists?
00844       {
00845         mork_fill last = fill - 1; // index of last cell in row
00846         
00847         if ( pos < (mork_pos)last ) // need to move cells following cut cell?
00848         {
00849           morkCell* lastCell = mRow_Cells + last;
00850           mork_count after = last - pos; // cell count after cut cell
00851           morkCell* next = cell + 1; // next cell after cut cell
00852           MORK_MEMMOVE(cell, next, after * sizeof(morkCell));
00853           lastCell->SetColumnAndChange(0, 0);
00854           lastCell->mCell_Atom = 0;
00855         }
00856         
00857         if ( ev->Good() )
00858           pool->CutRowCells(ev, this, fill - 1, &store->mStore_Zone);
00859       }
00860     }
00861   }
00862 }
00863 
00864 morkAtom* morkRow::GetColumnAtom(morkEnv* ev, mdb_column inColumn)
00865 {
00866   if ( ev->Good() )
00867   {
00868     mork_pos pos = -1;
00869     morkCell* cell = this->GetCell(ev, inColumn, &pos);
00870     if ( cell )
00871        return cell->mCell_Atom;
00872   }
00873   return (morkAtom*) 0;
00874 }
00875 
00876 void morkRow::AddColumn(morkEnv* ev, mdb_column inColumn,
00877   const mdbYarn* inYarn, morkStore* ioStore)
00878 {
00879   if ( ev->Good() )
00880   {
00881     mork_pos pos = -1;
00882     morkCell* cell = this->GetCell(ev, inColumn, &pos);
00883     morkCell* oldCell = cell; // need to know later whether new
00884     if ( !cell ) // column does not yet exist?
00885       cell = this->NewCell(ev, inColumn, &pos, ioStore);
00886     
00887     if ( cell )
00888     {
00889       morkAtom* oldAtom = cell->mCell_Atom;
00890 
00891       morkAtom* atom = ioStore->YarnToAtom(ev, inYarn, PR_TRUE /* create */);
00892       if ( atom && atom != oldAtom )
00893       {
00894         morkRowSpace* rowSpace = mRow_Space;
00895         morkAtomRowMap* map = ( rowSpace->mRowSpace_IndexCount )?
00896           rowSpace->FindMap(ev, inColumn) : (morkAtomRowMap*) 0;
00897         
00898         if ( map ) // inColumn is indexed by row space?
00899         {
00900           if ( oldAtom && oldAtom != atom ) // cut old cell from index?
00901           {
00902             mork_aid oldAid = oldAtom->GetBookAtomAid();
00903             if ( oldAid ) // cut old row attribute from row index in space?
00904               map->CutAid(ev, oldAid);
00905           }
00906         }
00907         
00908         cell->SetAtom(ev, atom, ioStore->StorePool()); // refcounts atom
00909 
00910         if ( oldCell ) // we changed a pre-existing cell in the row?
00911         {
00912           ++mRow_Seed;
00913           if ( this->MaybeDirtySpaceStoreAndRow() && !this->IsRowRewrite() )
00914             this->NoteRowAddCol(ev, inColumn);
00915         }
00916 
00917         if ( map ) // inColumn is indexed by row space?
00918         {
00919           mork_aid newAid = atom->GetBookAtomAid();
00920           if ( newAid ) // add new row attribute to row index in space?
00921             map->AddAid(ev, newAid, this);
00922         }
00923       }
00924     }
00925   }
00926 }
00927 
00928 morkRowCellCursor*
00929 morkRow::NewRowCellCursor(morkEnv* ev, mdb_pos inPos)
00930 {
00931   morkRowCellCursor* outCursor = 0;
00932   if ( ev->Good() )
00933   {
00934     morkStore* store = this->GetRowSpaceStore(ev);
00935     if ( store )
00936     {
00937       morkRowObject* rowObj = this->AcquireRowObject(ev, store);
00938       if ( rowObj )
00939       {
00940         nsIMdbHeap* heap = store->mPort_Heap;
00941         morkRowCellCursor* cursor = new(*heap, ev)
00942           morkRowCellCursor(ev, morkUsage::kHeap, heap, rowObj);
00943          
00944         if ( cursor )
00945         {
00946           if ( ev->Good() )
00947           {
00948             cursor->mCursor_Pos = inPos;
00949             outCursor = cursor;
00950           }
00951           else
00952             cursor->CutStrongRef(ev->mEnv_SelfAsMdbEnv);
00953         }
00954         rowObj->Release(); // always cut ref (cursor has its own)
00955       }
00956     }
00957   }
00958   return outCursor;
00959 }
00960 
00961 
00962 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00963