1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifndef _MDB_
7 # include "mdb.h"
8 #endif
9
10 #ifndef _MORK_
11 # include "mork.h"
12 #endif
13
14 #ifndef _MORKNODE_
15 # include "morkNode.h"
16 #endif
17
18 #ifndef _MORKMAP_
19 # include "morkMap.h"
20 #endif
21
22 #ifndef _MORKENV_
23 # include "morkEnv.h"
24 #endif
25
26 #ifndef _MORKTABLE_
27 # include "morkTable.h"
28 #endif
29
30 #ifndef _MORKSTORE_
31 # include "morkStore.h"
32 #endif
33
34 #ifndef _MORKROWSPACE_
35 # include "morkRowSpace.h"
36 #endif
37
38 #ifndef _MORKARRAY_
39 # include "morkArray.h"
40 #endif
41
42 #ifndef _MORKROW_
43 # include "morkRow.h"
44 #endif
45
46 #ifndef _MORKTABLEROWCURSOR_
47 # include "morkTableRowCursor.h"
48 #endif
49
50 #ifndef _MORKROWOBJECT_
51 # include "morkRowObject.h"
52 #endif
53
54 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
55
56 // ````` ````` ````` ````` `````
57 // { ===== begin morkNode interface =====
58
CloseMorkNode(morkEnv * ev)59 /*public virtual*/ void morkTable::CloseMorkNode(
60 morkEnv* ev) /*i*/ // CloseTable() only if open
61 {
62 if (this->IsOpenNode()) {
63 morkObject::CloseMorkNode(ev); // give base class a chance.
64 this->MarkClosing();
65 this->CloseTable(ev);
66 this->MarkShut();
67 }
68 }
69
70 /*public virtual*/
~morkTable()71 morkTable::~morkTable() /*i*/ // assert CloseTable() executed earlier
72 {
73 CloseMorkNode(mMorkEnv);
74 MORK_ASSERT(this->IsShutNode());
75 MORK_ASSERT(mTable_Store == 0);
76 MORK_ASSERT(mTable_RowSpace == 0);
77 }
78
79 /*public non-poly*/
morkTable(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioHeap,morkStore * ioStore,nsIMdbHeap * ioSlotHeap,morkRowSpace * ioRowSpace,const mdbOid * inOptionalMetaRowOid,mork_tid inTid,mork_kind inKind,mork_bool inMustBeUnique)80 morkTable::morkTable(
81 morkEnv* ev, /*i*/
82 const morkUsage& inUsage, nsIMdbHeap* ioHeap, morkStore* ioStore,
83 nsIMdbHeap* ioSlotHeap, morkRowSpace* ioRowSpace,
84 const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
85 mork_tid inTid, mork_kind inKind, mork_bool inMustBeUnique)
86 : morkObject(ev, inUsage, ioHeap, (mork_color)inTid, (morkHandle*)0),
87 mTable_Store(0),
88 mTable_RowSpace(0),
89 mTable_MetaRow(0)
90
91 ,
92 mTable_RowMap(0)
93 // , mTable_RowMap(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap,
94 // morkTable_kStartRowMapSlotCount)
95 ,
96 mTable_RowArray(ev, morkUsage::kMember, (nsIMdbHeap*)0,
97 morkTable_kStartRowArraySize, ioSlotHeap)
98
99 ,
100 mTable_ChangeList(),
101 mTable_ChangesCount(0),
102 mTable_ChangesMax(3) // any very small number greater than zero
103
104 ,
105 mTable_Kind(inKind)
106
107 ,
108 mTable_Flags(0),
109 mTable_Priority(morkPriority_kLo) // NOT high priority
110 ,
111 mTable_GcUses(0),
112 mTable_Pad(0) {
113 this->mLink_Next = 0;
114 this->mLink_Prev = 0;
115
116 if (ev->Good()) {
117 if (ioStore && ioSlotHeap && ioRowSpace) {
118 if (inKind) {
119 if (inMustBeUnique) this->SetTableUnique();
120 mTable_Store = ioStore;
121 mTable_RowSpace = ioRowSpace;
122 if (inOptionalMetaRowOid)
123 mTable_MetaRowOid = *inOptionalMetaRowOid;
124 else {
125 mTable_MetaRowOid.mOid_Scope = 0;
126 mTable_MetaRowOid.mOid_Id = morkRow_kMinusOneRid;
127 }
128 if (ev->Good()) {
129 if (this->MaybeDirtySpaceStoreAndTable())
130 this->SetTableRewrite(); // everything is dirty
131
132 mNode_Derived = morkDerived_kTable;
133 }
134 this->MaybeDirtySpaceStoreAndTable(); // new table might dirty store
135 } else
136 ioRowSpace->ZeroKindError(ev);
137 } else
138 ev->NilPointerError();
139 }
140 }
141
NS_IMPL_ISUPPORTS_INHERITED(morkTable,morkObject,nsIMdbTable)142 NS_IMPL_ISUPPORTS_INHERITED(morkTable, morkObject, nsIMdbTable)
143
144 /*public non-poly*/ void morkTable::CloseTable(
145 morkEnv* ev) /*i*/ // called by CloseMorkNode();
146 {
147 if (this->IsNode()) {
148 morkRowMap::SlotStrongRowMap((morkRowMap*)0, ev, &mTable_RowMap);
149 // mTable_RowMap.CloseMorkNode(ev);
150 mTable_RowArray.CloseMorkNode(ev);
151 mTable_Store = 0;
152 mTable_RowSpace = 0;
153 this->MarkShut();
154 } else
155 this->NonNodeError(ev);
156 }
157
158 // } ===== end morkNode methods =====
159 // ````` ````` ````` ````` `````
160
161 // { ===== begin nsIMdbCollection methods =====
162
163 // { ----- begin attribute methods -----
164 NS_IMETHODIMP
GetSeed(nsIMdbEnv * mev,mdb_seed * outSeed)165 morkTable::GetSeed(nsIMdbEnv* mev,
166 mdb_seed* outSeed) // member change count
167 {
168 nsresult outErr = NS_OK;
169 morkEnv* ev = morkEnv::FromMdbEnv(mev);
170 if (ev) {
171 *outSeed = mTable_RowArray.mArray_Seed;
172 outErr = ev->AsErr();
173 }
174 return outErr;
175 }
176
177 NS_IMETHODIMP
GetCount(nsIMdbEnv * mev,mdb_count * outCount)178 morkTable::GetCount(nsIMdbEnv* mev,
179 mdb_count* outCount) // member count
180 {
181 NS_ENSURE_ARG_POINTER(outCount);
182 *outCount = mTable_RowArray.mArray_Fill;
183 return NS_OK;
184 }
185
186 NS_IMETHODIMP
GetPort(nsIMdbEnv * mev,nsIMdbPort ** acqPort)187 morkTable::GetPort(nsIMdbEnv* mev,
188 nsIMdbPort** acqPort) // collection container
189 {
190 (void)morkEnv::FromMdbEnv(mev);
191 NS_ENSURE_ARG_POINTER(acqPort);
192 *acqPort = mTable_Store;
193 return NS_OK;
194 }
195 // } ----- end attribute methods -----
196
197 // { ----- begin cursor methods -----
198 NS_IMETHODIMP
GetCursor(nsIMdbEnv * mev,mdb_pos inMemberPos,nsIMdbCursor ** acqCursor)199 morkTable::GetCursor( // make a cursor starting iter at inMemberPos
200 nsIMdbEnv* mev, // context
201 mdb_pos inMemberPos, // zero-based ordinal pos of member in collection
202 nsIMdbCursor** acqCursor) // acquire new cursor instance
203 {
204 return this->GetTableRowCursor(mev, inMemberPos,
205 (nsIMdbTableRowCursor**)acqCursor);
206 }
207 // } ----- end cursor methods -----
208
209 // { ----- begin ID methods -----
210 NS_IMETHODIMP
GetOid(nsIMdbEnv * mev,mdbOid * outOid)211 morkTable::GetOid(nsIMdbEnv* mev,
212 mdbOid* outOid) // read object identity
213 {
214 morkEnv* ev = morkEnv::FromMdbEnv(mev);
215 GetTableOid(ev, outOid);
216 return NS_OK;
217 }
218
219 NS_IMETHODIMP
BecomeContent(nsIMdbEnv * mev,const mdbOid * inOid)220 morkTable::BecomeContent(nsIMdbEnv* mev,
221 const mdbOid* inOid) // exchange content
222 {
223 NS_ASSERTION(false, "not implemented");
224 return NS_ERROR_NOT_IMPLEMENTED;
225 // remember table->MaybeDirtySpaceStoreAndTable();
226 }
227
228 // } ----- end ID methods -----
229
230 // { ----- begin activity dropping methods -----
231 NS_IMETHODIMP
DropActivity(nsIMdbEnv * mev)232 morkTable::DropActivity( // tell collection usage no longer expected
233 nsIMdbEnv* mev) {
234 NS_ASSERTION(false, "not implemented");
235 return NS_ERROR_NOT_IMPLEMENTED;
236 }
237
238 // } ----- end activity dropping methods -----
239
240 // } ===== end nsIMdbCollection methods =====
241
242 // { ===== begin nsIMdbTable methods =====
243
244 // { ----- begin attribute methods -----
245
246 NS_IMETHODIMP
SetTablePriority(nsIMdbEnv * mev,mdb_priority inPrio)247 morkTable::SetTablePriority(nsIMdbEnv* mev, mdb_priority inPrio) {
248 nsresult outErr = NS_OK;
249 morkEnv* ev = morkEnv::FromMdbEnv(mev);
250 if (ev) {
251 if (inPrio > morkPriority_kMax) inPrio = morkPriority_kMax;
252
253 mTable_Priority = inPrio;
254 outErr = ev->AsErr();
255 }
256 return outErr;
257 }
258
259 NS_IMETHODIMP
GetTablePriority(nsIMdbEnv * mev,mdb_priority * outPrio)260 morkTable::GetTablePriority(nsIMdbEnv* mev, mdb_priority* outPrio) {
261 nsresult outErr = NS_OK;
262 mork_priority prio = 0;
263 morkEnv* ev = morkEnv::FromMdbEnv(mev);
264 if (ev) {
265 prio = mTable_Priority;
266 if (prio > morkPriority_kMax) {
267 prio = morkPriority_kMax;
268 mTable_Priority = prio;
269 }
270 outErr = ev->AsErr();
271 }
272 if (outPrio) *outPrio = prio;
273 return outErr;
274 }
275
276 NS_IMETHODIMP
GetTableBeVerbose(nsIMdbEnv * mev,mdb_bool * outBeVerbose)277 morkTable::GetTableBeVerbose(nsIMdbEnv* mev, mdb_bool* outBeVerbose) {
278 NS_ENSURE_ARG_POINTER(outBeVerbose);
279 *outBeVerbose = IsTableVerbose();
280 return NS_OK;
281 }
282
283 NS_IMETHODIMP
SetTableBeVerbose(nsIMdbEnv * mev,mdb_bool inBeVerbose)284 morkTable::SetTableBeVerbose(nsIMdbEnv* mev, mdb_bool inBeVerbose) {
285 nsresult outErr = NS_OK;
286 morkEnv* ev = morkEnv::FromMdbEnv(mev);
287 if (ev) {
288 if (inBeVerbose)
289 SetTableVerbose();
290 else
291 ClearTableVerbose();
292
293 outErr = ev->AsErr();
294 }
295 return outErr;
296 }
297
298 NS_IMETHODIMP
GetTableIsUnique(nsIMdbEnv * mev,mdb_bool * outIsUnique)299 morkTable::GetTableIsUnique(nsIMdbEnv* mev, mdb_bool* outIsUnique) {
300 NS_ENSURE_ARG_POINTER(outIsUnique);
301 *outIsUnique = IsTableUnique();
302 return NS_OK;
303 }
304
305 NS_IMETHODIMP
GetTableKind(nsIMdbEnv * mev,mdb_kind * outTableKind)306 morkTable::GetTableKind(nsIMdbEnv* mev, mdb_kind* outTableKind) {
307 NS_ENSURE_ARG_POINTER(outTableKind);
308 *outTableKind = mTable_Kind;
309 return NS_OK;
310 }
311
312 NS_IMETHODIMP
GetRowScope(nsIMdbEnv * mev,mdb_scope * outRowScope)313 morkTable::GetRowScope(nsIMdbEnv* mev, mdb_scope* outRowScope) {
314 nsresult outErr = NS_OK;
315 mdb_scope rowScope = 0;
316 morkEnv* ev = morkEnv::FromMdbEnv(mev);
317 if (ev) {
318 if (mTable_RowSpace)
319 rowScope = mTable_RowSpace->SpaceScope();
320 else
321 NilRowSpaceError(ev);
322
323 outErr = ev->AsErr();
324 }
325 if (outRowScope) *outRowScope = rowScope;
326 return outErr;
327 }
328
329 NS_IMETHODIMP
GetMetaRow(nsIMdbEnv * mev,const mdbOid * inOptionalMetaRowOid,mdbOid * outOid,nsIMdbRow ** acqRow)330 morkTable::GetMetaRow(
331 nsIMdbEnv* mev,
332 const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
333 mdbOid* outOid, // output meta row oid, can be nil to suppress output
334 nsIMdbRow** acqRow) // acquire table's unique singleton meta row
335 // The purpose of a meta row is to support the persistent recording of
336 // meta info about a table as cells put into the distinguished meta row.
337 // Each table has exactly one meta row, which is not considered a member
338 // of the collection of rows inside the table. The only way to tell
339 // whether a row is a meta row is by the fact that it is returned by this
340 // GetMetaRow() method from some table. Otherwise nothing distinguishes
341 // a meta row from any other row. A meta row can be used anyplace that
342 // any other row can be used, and can even be put into other tables (or
343 // the same table) as a table member, if this is useful for some reason.
344 // The first attempt to access a table's meta row using GetMetaRow() will
345 // cause the meta row to be created if it did not already exist. When the
346 // meta row is created, it will have the row oid that was previously
347 // requested for this table's meta row; or if no oid was ever explicitly
348 // specified for this meta row, then a unique oid will be generated in
349 // the row scope named "metaScope" (so obviously MDB clients should not
350 // manually allocate any row IDs from that special meta scope namespace).
351 // The meta row oid can be specified either when the table is created, or
352 // else the first time that GetMetaRow() is called, by passing a non-nil
353 // pointer to an oid for parameter inOptionalMetaRowOid. The meta row's
354 // actual oid is returned in outOid (if this is a non-nil pointer), and
355 // it will be different from inOptionalMetaRowOid when the meta row was
356 // already given a different oid earlier.
357 {
358 nsresult outErr = NS_OK;
359 nsIMdbRow* outRow = 0;
360 morkEnv* ev = morkEnv::FromMdbEnv(mev);
361 if (ev) {
362 morkRow* row = GetMetaRow(ev, inOptionalMetaRowOid);
363 if (row && ev->Good()) {
364 if (outOid) *outOid = row->mRow_Oid;
365
366 outRow = row->AcquireRowHandle(ev, mTable_Store);
367 }
368 outErr = ev->AsErr();
369 }
370 if (acqRow) *acqRow = outRow;
371
372 if (ev->Bad() && outOid) {
373 outOid->mOid_Scope = 0;
374 outOid->mOid_Id = morkRow_kMinusOneRid;
375 }
376 return outErr;
377 }
378
379 // } ----- end attribute methods -----
380
381 // { ----- begin cursor methods -----
382 NS_IMETHODIMP
GetTableRowCursor(nsIMdbEnv * mev,mdb_pos inRowPos,nsIMdbTableRowCursor ** acqCursor)383 morkTable::GetTableRowCursor( // make a cursor, starting iteration at inRowPos
384 nsIMdbEnv* mev, // context
385 mdb_pos inRowPos, // zero-based ordinal position of row in table
386 nsIMdbTableRowCursor** acqCursor) // acquire new cursor instance
387 {
388 nsresult outErr = NS_OK;
389 nsIMdbTableRowCursor* outCursor = 0;
390 morkEnv* ev = morkEnv::FromMdbEnv(mev);
391 if (ev) {
392 morkTableRowCursor* cursor = NewTableRowCursor(ev, inRowPos);
393 if (cursor) {
394 if (ev->Good()) {
395 // cursor->mCursor_Seed = (mork_seed) inRowPos;
396 outCursor = cursor;
397 outCursor->AddRef();
398 }
399 }
400
401 outErr = ev->AsErr();
402 }
403 if (acqCursor) *acqCursor = outCursor;
404 return outErr;
405 }
406 // } ----- end row position methods -----
407
408 // { ----- begin row position methods -----
409 NS_IMETHODIMP
PosToOid(nsIMdbEnv * mev,mdb_pos inRowPos,mdbOid * outOid)410 morkTable::PosToOid( // get row member for a table position
411 nsIMdbEnv* mev, // context
412 mdb_pos inRowPos, // zero-based ordinal position of row in table
413 mdbOid* outOid) // row oid at the specified position
414 {
415 nsresult outErr = NS_OK;
416 mdbOid roid;
417 roid.mOid_Scope = 0;
418 roid.mOid_Id = (mork_id)-1;
419
420 morkEnv* ev = morkEnv::FromMdbEnv(mev);
421 if (ev) {
422 morkRow* row = SafeRowAt(ev, inRowPos);
423 if (row) roid = row->mRow_Oid;
424
425 outErr = ev->AsErr();
426 }
427 if (outOid) *outOid = roid;
428 return outErr;
429 }
430
431 NS_IMETHODIMP
OidToPos(nsIMdbEnv * mev,const mdbOid * inOid,mdb_pos * outPos)432 morkTable::OidToPos( // test for the table position of a row member
433 nsIMdbEnv* mev, // context
434 const mdbOid* inOid, // row to find in table
435 mdb_pos* outPos) // zero-based ordinal position of row in table
436 {
437 nsresult outErr = NS_OK;
438 morkEnv* ev = morkEnv::FromMdbEnv(mev);
439 if (ev) {
440 mork_pos pos = ArrayHasOid(ev, inOid);
441 if (outPos) *outPos = pos;
442 outErr = ev->AsErr();
443 }
444 return outErr;
445 }
446
447 NS_IMETHODIMP
PosToRow(nsIMdbEnv * mev,mdb_pos inRowPos,nsIMdbRow ** acqRow)448 morkTable::PosToRow( // get row member for a table position
449 nsIMdbEnv* mev, // context
450 mdb_pos inRowPos, // zero-based ordinal position of row in table
451 nsIMdbRow** acqRow) // acquire row at table position inRowPos
452 {
453 nsresult outErr = NS_OK;
454 nsIMdbRow* outRow = 0;
455 morkEnv* ev = morkEnv::FromMdbEnv(mev);
456 if (ev) {
457 morkRow* row = SafeRowAt(ev, inRowPos);
458 if (row && mTable_Store) outRow = row->AcquireRowHandle(ev, mTable_Store);
459
460 outErr = ev->AsErr();
461 }
462 if (acqRow) *acqRow = outRow;
463 return outErr;
464 }
465
466 NS_IMETHODIMP
RowToPos(nsIMdbEnv * mev,nsIMdbRow * ioRow,mdb_pos * outPos)467 morkTable::RowToPos( // test for the table position of a row member
468 nsIMdbEnv* mev, // context
469 nsIMdbRow* ioRow, // row to find in table
470 mdb_pos* outPos) // zero-based ordinal position of row in table
471 {
472 nsresult outErr = NS_OK;
473 mork_pos pos = -1;
474 morkEnv* ev = morkEnv::FromMdbEnv(mev);
475 if (ev) {
476 morkRowObject* row = (morkRowObject*)ioRow;
477 pos = ArrayHasOid(ev, &row->mRowObject_Row->mRow_Oid);
478 outErr = ev->AsErr();
479 }
480 if (outPos) *outPos = pos;
481 return outErr;
482 }
483
484 // Note that HasRow() performs the inverse oid->pos mapping
485 // } ----- end row position methods -----
486
487 // { ----- begin oid set methods -----
488 NS_IMETHODIMP
AddOid(nsIMdbEnv * mev,const mdbOid * inOid)489 morkTable::AddOid( // make sure the row with inOid is a table member
490 nsIMdbEnv* mev, // context
491 const mdbOid* inOid) // row to ensure membership in table
492 {
493 NS_ASSERTION(false, "not implemented");
494 return NS_ERROR_NOT_IMPLEMENTED;
495 }
496
497 NS_IMETHODIMP
HasOid(nsIMdbEnv * mev,const mdbOid * inOid,mdb_bool * outHasOid)498 morkTable::HasOid( // test for the table position of a row member
499 nsIMdbEnv* mev, // context
500 const mdbOid* inOid, // row to find in table
501 mdb_bool* outHasOid) // whether inOid is a member row
502 {
503 nsresult outErr = NS_OK;
504 morkEnv* ev = morkEnv::FromMdbEnv(mev);
505 if (ev) {
506 if (outHasOid) *outHasOid = MapHasOid(ev, inOid);
507 outErr = ev->AsErr();
508 }
509 return outErr;
510 }
511
512 NS_IMETHODIMP
CutOid(nsIMdbEnv * mev,const mdbOid * inOid)513 morkTable::CutOid( // make sure the row with inOid is not a member
514 nsIMdbEnv* mev, // context
515 const mdbOid* inOid) // row to remove from table
516 {
517 nsresult outErr = NS_OK;
518 morkEnv* ev = morkEnv::FromMdbEnv(mev);
519 if (ev) {
520 if (inOid && mTable_Store) {
521 morkRow* row = mTable_Store->GetRow(ev, inOid);
522 if (row) CutRow(ev, row);
523 } else
524 ev->NilPointerError();
525
526 outErr = ev->AsErr();
527 }
528 return outErr;
529 }
530 // } ----- end oid set methods -----
531
532 // { ----- begin row set methods -----
533 NS_IMETHODIMP
NewRow(nsIMdbEnv * mev,mdbOid * ioOid,nsIMdbRow ** acqRow)534 morkTable::NewRow( // create a new row instance in table
535 nsIMdbEnv* mev, // context
536 mdbOid* ioOid, // please use zero (unbound) rowId for db-assigned IDs
537 nsIMdbRow** acqRow) // create new row
538 {
539 nsresult outErr = NS_OK;
540 nsIMdbRow* outRow = 0;
541 morkEnv* ev = morkEnv::FromMdbEnv(mev);
542 if (ev) {
543 if (ioOid && mTable_Store) {
544 morkRow* row = 0;
545 if (ioOid->mOid_Id == morkRow_kMinusOneRid)
546 row = mTable_Store->NewRow(ev, ioOid->mOid_Scope);
547 else
548 row = mTable_Store->NewRowWithOid(ev, ioOid);
549
550 if (row && AddRow(ev, row))
551 outRow = row->AcquireRowHandle(ev, mTable_Store);
552 } else
553 ev->NilPointerError();
554
555 outErr = ev->AsErr();
556 }
557 if (acqRow) *acqRow = outRow;
558 return outErr;
559 }
560
561 NS_IMETHODIMP
AddRow(nsIMdbEnv * mev,nsIMdbRow * ioRow)562 morkTable::AddRow( // make sure the row with inOid is a table member
563 nsIMdbEnv* mev, // context
564 nsIMdbRow* ioRow) // row to ensure membership in table
565 {
566 nsresult outErr = NS_OK;
567 morkEnv* ev = morkEnv::FromMdbEnv(mev);
568 if (ev) {
569 morkRowObject* rowObj = (morkRowObject*)ioRow;
570 morkRow* row = rowObj->mRowObject_Row;
571 AddRow(ev, row);
572 outErr = ev->AsErr();
573 }
574 return outErr;
575 }
576
577 NS_IMETHODIMP
HasRow(nsIMdbEnv * mev,nsIMdbRow * ioRow,mdb_bool * outBool)578 morkTable::HasRow( // test for the table position of a row member
579 nsIMdbEnv* mev, // context
580 nsIMdbRow* ioRow, // row to find in table
581 mdb_bool* outBool) // zero-based ordinal position of row in table
582 {
583 nsresult outErr = NS_OK;
584 morkEnv* ev = morkEnv::FromMdbEnv(mev);
585 if (ev) {
586 morkRowObject* rowObj = (morkRowObject*)ioRow;
587 morkRow* row = rowObj->mRowObject_Row;
588 if (outBool) *outBool = MapHasOid(ev, &row->mRow_Oid);
589 outErr = ev->AsErr();
590 }
591 return outErr;
592 }
593
594 NS_IMETHODIMP
CutRow(nsIMdbEnv * mev,nsIMdbRow * ioRow)595 morkTable::CutRow( // make sure the row with inOid is not a member
596 nsIMdbEnv* mev, // context
597 nsIMdbRow* ioRow) // row to remove from table
598 {
599 nsresult outErr = NS_OK;
600 morkEnv* ev = morkEnv::FromMdbEnv(mev);
601 if (ev) {
602 morkRowObject* rowObj = (morkRowObject*)ioRow;
603 morkRow* row = rowObj->mRowObject_Row;
604 CutRow(ev, row);
605 outErr = ev->AsErr();
606 }
607 return outErr;
608 }
609
610 NS_IMETHODIMP
CutAllRows(nsIMdbEnv * mev)611 morkTable::CutAllRows( // remove all rows from the table
612 nsIMdbEnv* mev) // context
613 {
614 nsresult outErr = NS_OK;
615 morkEnv* ev = morkEnv::FromMdbEnv(mev);
616 if (ev) {
617 CutAllRows(ev);
618 outErr = ev->AsErr();
619 }
620 return outErr;
621 }
622 // } ----- end row set methods -----
623
624 // { ----- begin searching methods -----
625 NS_IMETHODIMP
FindRowMatches(nsIMdbEnv * mev,const mdbYarn * inPrefix,nsIMdbTableRowCursor ** acqCursor)626 morkTable::FindRowMatches( // search variable number of sorted cols
627 nsIMdbEnv* mev, // context
628 const mdbYarn* inPrefix, // content to find as prefix in row's column cell
629 nsIMdbTableRowCursor** acqCursor) // set of matching rows
630 {
631 NS_ASSERTION(false, "not implemented");
632 return NS_ERROR_NOT_IMPLEMENTED;
633 }
634
635 NS_IMETHODIMP
GetSearchColumns(nsIMdbEnv * mev,mdb_count * outCount,mdbColumnSet * outColSet)636 morkTable::GetSearchColumns( // query columns used by FindRowMatches()
637 nsIMdbEnv* mev, // context
638 mdb_count* outCount, // context
639 mdbColumnSet* outColSet) // caller supplied space to put columns
640 // GetSearchColumns() returns the columns actually searched when the
641 // FindRowMatches() method is called. No more than mColumnSet_Count
642 // slots of mColumnSet_Columns will be written, since mColumnSet_Count
643 // indicates how many slots are present in the column array. The
644 // actual number of search column used by the table is returned in
645 // the outCount parameter; if this number exceeds mColumnSet_Count,
646 // then a caller needs a bigger array to read the entire column set.
647 // The minimum of mColumnSet_Count and outCount is the number slots
648 // in mColumnSet_Columns that were actually written by this method.
649 //
650 // Callers are expected to change this set of columns by calls to
651 // nsIMdbTable::SearchColumnsHint() or SetSearchSorting(), or both.
652 {
653 NS_ASSERTION(false, "not implemented");
654 return NS_ERROR_NOT_IMPLEMENTED;
655 }
656 // } ----- end searching methods -----
657
658 // { ----- begin hinting methods -----
659 NS_IMETHODIMP
SearchColumnsHint(nsIMdbEnv * mev,const mdbColumnSet * inColumnSet)660 morkTable::SearchColumnsHint( // advise re future expected search cols
661 nsIMdbEnv* mev, // context
662 const mdbColumnSet* inColumnSet) // columns likely to be searched
663 {
664 NS_ASSERTION(false, "not implemented");
665 return NS_ERROR_NOT_IMPLEMENTED;
666 }
667
668 NS_IMETHODIMP
SortColumnsHint(nsIMdbEnv * mev,const mdbColumnSet * inColumnSet)669 morkTable::SortColumnsHint( // advise re future expected sort columns
670 nsIMdbEnv* mev, // context
671 const mdbColumnSet* inColumnSet) // columns for likely sort requests
672 {
673 NS_ASSERTION(false, "not implemented");
674 return NS_ERROR_NOT_IMPLEMENTED;
675 }
676
677 NS_IMETHODIMP
StartBatchChangeHint(nsIMdbEnv * mev,const void * inLabel)678 morkTable::StartBatchChangeHint( // advise before many adds and cuts
679 nsIMdbEnv* mev, // context
680 const void* inLabel) // intend unique address to match end call
681 // If batch starts nest by virtue of nesting calls in the stack, then
682 // the address of a local variable makes a good batch start label that
683 // can be used at batch end time, and such addresses remain unique.
684 {
685 // we don't do anything here.
686 return NS_OK;
687 }
688
689 NS_IMETHODIMP
EndBatchChangeHint(nsIMdbEnv * mev,const void * inLabel)690 morkTable::EndBatchChangeHint( // advise before many adds and cuts
691 nsIMdbEnv* mev, // context
692 const void* inLabel) // label matching start label
693 // Suppose a table is maintaining one or many sort orders for a table,
694 // so that every row added to the table must be inserted in each sort,
695 // and every row cut must be removed from each sort. If a db client
696 // intends to make many such changes before needing any information
697 // about the order or positions of rows inside a table, then a client
698 // might tell the table to start batch changes in order to disable
699 // sorting of rows for the interim. Presumably a table will then do
700 // a full sort of all rows at need when the batch changes end, or when
701 // a surprise request occurs for row position during batch changes.
702 {
703 // we don't do anything here.
704 return NS_OK;
705 }
706 // } ----- end hinting methods -----
707
708 // { ----- begin sorting methods -----
709 // sorting: note all rows are assumed sorted by row ID as a secondary
710 // sort following the primary column sort, when table rows are sorted.
711
712 NS_IMETHODIMP
CanSortColumn(nsIMdbEnv * mev,mdb_column inColumn,mdb_bool * outCanSort)713 morkTable::CanSortColumn( // query which column is currently used for sorting
714 nsIMdbEnv* mev, // context
715 mdb_column inColumn, // column to query sorting potential
716 mdb_bool* outCanSort) // whether the column can be sorted
717 {
718 NS_ASSERTION(false, "not implemented");
719 return NS_ERROR_NOT_IMPLEMENTED;
720 }
721
722 NS_IMETHODIMP
GetSorting(nsIMdbEnv * mev,mdb_column inColumn,nsIMdbSorting ** acqSorting)723 morkTable::GetSorting( // view same table in particular sorting
724 nsIMdbEnv* mev, // context
725 mdb_column inColumn, // requested new column for sorting table
726 nsIMdbSorting** acqSorting) // acquire sorting for column
727 {
728 NS_ASSERTION(false, "not implemented");
729 return NS_ERROR_NOT_IMPLEMENTED;
730 }
731
732 NS_IMETHODIMP
SetSearchSorting(nsIMdbEnv * mev,mdb_column inColumn,nsIMdbSorting * ioSorting)733 morkTable::SetSearchSorting( // use this sorting in FindRowMatches()
734 nsIMdbEnv* mev, // context
735 mdb_column inColumn, // often same as nsIMdbSorting::GetSortColumn()
736 nsIMdbSorting* ioSorting) // requested sorting for some column
737 // SetSearchSorting() attempts to inform the table that ioSorting
738 // should be used during calls to FindRowMatches() for searching
739 // the column which is actually sorted by ioSorting. This method
740 // is most useful in conjunction with nsIMdbSorting::SetCompare(),
741 // because otherwise a caller would not be able to override the
742 // comparison ordering method used during searches. Note that some
743 // database implementations might be unable to use an arbitrarily
744 // specified sort order, either due to schema or runtime interface
745 // constraints, in which case ioSorting might not actually be used.
746 // Presumably ioSorting is an instance that was returned from some
747 // earlier call to nsIMdbTable::GetSorting(). A caller can also
748 // use nsIMdbTable::SearchColumnsHint() to specify desired change
749 // in which columns are sorted and searched by FindRowMatches().
750 //
751 // A caller can pass a nil pointer for ioSorting to request that
752 // column inColumn no longer be used at all by FindRowMatches().
753 // But when ioSorting is non-nil, then inColumn should match the
754 // column actually sorted by ioSorting; when these do not agree,
755 // implementations are instructed to give precedence to the column
756 // specified by ioSorting (so this means callers might just pass
757 // zero for inColumn when ioSorting is also provided, since then
758 // inColumn is both redundant and ignored).
759 {
760 NS_ASSERTION(false, "not implemented");
761 return NS_ERROR_NOT_IMPLEMENTED;
762 }
763
764 // } ----- end sorting methods -----
765
766 // { ----- begin moving methods -----
767 // moving a row does nothing unless a table is currently unsorted
768
769 NS_IMETHODIMP
MoveOid(nsIMdbEnv * mev,const mdbOid * inOid,mdb_pos inHintFromPos,mdb_pos inToPos,mdb_pos * outActualPos)770 morkTable::MoveOid( // change position of row in unsorted table
771 nsIMdbEnv* mev, // context
772 const mdbOid* inOid, // row oid to find in table
773 mdb_pos inHintFromPos, // suggested hint regarding start position
774 mdb_pos inToPos, // desired new position for row inOid
775 mdb_pos* outActualPos) // actual new position of row in table
776 {
777 nsresult outErr = NS_OK;
778 mdb_pos actualPos = -1; // meaning it was never found in table
779 morkEnv* ev = morkEnv::FromMdbEnv(mev);
780 if (ev) {
781 if (inOid && mTable_Store) {
782 morkRow* row = mTable_Store->GetRow(ev, inOid);
783 if (row) actualPos = MoveRow(ev, row, inHintFromPos, inToPos);
784 } else
785 ev->NilPointerError();
786
787 outErr = ev->AsErr();
788 }
789 if (outActualPos) *outActualPos = actualPos;
790 return outErr;
791 }
792
793 NS_IMETHODIMP
MoveRow(nsIMdbEnv * mev,nsIMdbRow * ioRow,mdb_pos inHintFromPos,mdb_pos inToPos,mdb_pos * outActualPos)794 morkTable::MoveRow( // change position of row in unsorted table
795 nsIMdbEnv* mev, // context
796 nsIMdbRow* ioRow, // row oid to find in table
797 mdb_pos inHintFromPos, // suggested hint regarding start position
798 mdb_pos inToPos, // desired new position for row ioRow
799 mdb_pos* outActualPos) // actual new position of row in table
800 {
801 mdb_pos actualPos = -1; // meaning it was never found in table
802 nsresult outErr = NS_OK;
803 morkEnv* ev = morkEnv::FromMdbEnv(mev);
804 if (ev) {
805 morkRowObject* rowObj = (morkRowObject*)ioRow;
806 morkRow* row = rowObj->mRowObject_Row;
807 actualPos = MoveRow(ev, row, inHintFromPos, inToPos);
808 outErr = ev->AsErr();
809 }
810 if (outActualPos) *outActualPos = actualPos;
811 return outErr;
812 }
813 // } ----- end moving methods -----
814
815 // { ----- begin index methods -----
816 NS_IMETHODIMP
AddIndex(nsIMdbEnv * mev,mdb_column inColumn,nsIMdbThumb ** acqThumb)817 morkTable::AddIndex( // create a sorting index for column if possible
818 nsIMdbEnv* mev, // context
819 mdb_column inColumn, // the column to sort by index
820 nsIMdbThumb** acqThumb) // acquire thumb for incremental index building
821 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
822 // then the index addition will be finished.
823 {
824 NS_ASSERTION(false, "not implemented");
825 return NS_ERROR_NOT_IMPLEMENTED;
826 }
827
828 NS_IMETHODIMP
CutIndex(nsIMdbEnv * mev,mdb_column inColumn,nsIMdbThumb ** acqThumb)829 morkTable::CutIndex( // stop supporting a specific column index
830 nsIMdbEnv* mev, // context
831 mdb_column inColumn, // the column with index to be removed
832 nsIMdbThumb** acqThumb) // acquire thumb for incremental index destroy
833 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
834 // then the index removal will be finished.
835 {
836 NS_ASSERTION(false, "not implemented");
837 return NS_ERROR_NOT_IMPLEMENTED;
838 }
839
840 NS_IMETHODIMP
HasIndex(nsIMdbEnv * mev,mdb_column inColumn,mdb_bool * outHasIndex)841 morkTable::HasIndex( // query for current presence of a column index
842 nsIMdbEnv* mev, // context
843 mdb_column inColumn, // the column to investigate
844 mdb_bool* outHasIndex) // whether column has index for this column
845 {
846 NS_ASSERTION(false, "not implemented");
847 return NS_ERROR_NOT_IMPLEMENTED;
848 }
849
850 NS_IMETHODIMP
EnableIndexOnSort(nsIMdbEnv * mev,mdb_column inColumn)851 morkTable::EnableIndexOnSort( // create an index for col on first sort
852 nsIMdbEnv* mev, // context
853 mdb_column inColumn) // the column to index if ever sorted
854 {
855 NS_ASSERTION(false, "not implemented");
856 return NS_ERROR_NOT_IMPLEMENTED;
857 }
858
859 NS_IMETHODIMP
QueryIndexOnSort(nsIMdbEnv * mev,mdb_column inColumn,mdb_bool * outIndexOnSort)860 morkTable::QueryIndexOnSort( // check whether index on sort is enabled
861 nsIMdbEnv* mev, // context
862 mdb_column inColumn, // the column to investigate
863 mdb_bool* outIndexOnSort) // whether column has index-on-sort enabled
864 {
865 NS_ASSERTION(false, "not implemented");
866 return NS_ERROR_NOT_IMPLEMENTED;
867 }
868
869 NS_IMETHODIMP
DisableIndexOnSort(nsIMdbEnv * mev,mdb_column inColumn)870 morkTable::DisableIndexOnSort( // prevent future index creation on sort
871 nsIMdbEnv* mev, // context
872 mdb_column inColumn) // the column to index if ever sorted
873 {
874 NS_ASSERTION(false, "not implemented");
875 return NS_ERROR_NOT_IMPLEMENTED;
876 }
877 // } ----- end index methods -----
878
879 // } ===== end nsIMdbTable methods =====
880
881 // we override these so that we'll use the xpcom add and release ref.
882 #ifndef _MSC_VER
AddStrongRef(nsIMdbEnv * ev)883 mork_refs morkTable::AddStrongRef(nsIMdbEnv* ev) { return (mork_refs)AddRef(); }
884 #endif
885
AddStrongRef(morkEnv * ev)886 mork_refs morkTable::AddStrongRef(morkEnv* ev) { return (mork_refs)AddRef(); }
887
888 #ifndef _MSC_VER
CutStrongRef(nsIMdbEnv * ev)889 nsresult morkTable::CutStrongRef(nsIMdbEnv* ev) { return (nsresult)Release(); }
890 #endif
891
CutStrongRef(morkEnv * ev)892 mork_refs morkTable::CutStrongRef(morkEnv* ev) { return (mork_refs)Release(); }
893
AddTableGcUse(morkEnv * ev)894 mork_u2 morkTable::AddTableGcUse(morkEnv* ev) {
895 MORK_USED_1(ev);
896 if (mTable_GcUses < morkTable_kMaxTableGcUses) // not already maxed out?
897 ++mTable_GcUses;
898
899 return mTable_GcUses;
900 }
901
CutTableGcUse(morkEnv * ev)902 mork_u2 morkTable::CutTableGcUse(morkEnv* ev) {
903 if (mTable_GcUses) // any outstanding uses to cut?
904 {
905 if (mTable_GcUses < morkTable_kMaxTableGcUses) // not frozen at max?
906 --mTable_GcUses;
907 } else
908 this->TableGcUsesUnderflowWarning(ev);
909
910 return mTable_GcUses;
911 }
912
913 // table dirty handling more complex than morkNode::SetNodeDirty() etc.
914
SetTableClean(morkEnv * ev)915 void morkTable::SetTableClean(morkEnv* ev) {
916 if (mTable_ChangeList.HasListMembers()) {
917 nsIMdbHeap* heap = mTable_Store->mPort_Heap;
918 mTable_ChangeList.CutAndZapAllListMembers(ev, heap); // forget changes
919 }
920 mTable_ChangesCount = 0;
921
922 mTable_Flags = 0;
923 this->SetNodeClean();
924 }
925
926 // notifications regarding table changes:
927
NoteTableMoveRow(morkEnv * ev,morkRow * ioRow,mork_pos inPos)928 void morkTable::NoteTableMoveRow(morkEnv* ev, morkRow* ioRow, mork_pos inPos) {
929 nsIMdbHeap* heap = mTable_Store->mPort_Heap;
930 if (this->IsTableRewrite() || this->HasChangeOverflow())
931 this->NoteTableSetAll(ev);
932 else {
933 morkTableChange* tableChange =
934 new (*heap, ev) morkTableChange(ev, ioRow, inPos);
935 if (tableChange) {
936 if (ev->Good()) {
937 mTable_ChangeList.PushTail(tableChange);
938 ++mTable_ChangesCount;
939 } else {
940 tableChange->ZapOldNext(ev, heap);
941 this->SetTableRewrite(); // just plan to write all table rows
942 }
943 }
944 }
945 }
946
note_row_move(morkEnv * ev,morkRow * ioRow,mork_pos inNewPos)947 void morkTable::note_row_move(morkEnv* ev, morkRow* ioRow, mork_pos inNewPos) {
948 if (this->IsTableRewrite() || this->HasChangeOverflow())
949 this->NoteTableSetAll(ev);
950 else {
951 nsIMdbHeap* heap = mTable_Store->mPort_Heap;
952 morkTableChange* tableChange =
953 new (*heap, ev) morkTableChange(ev, ioRow, inNewPos);
954 if (tableChange) {
955 if (ev->Good()) {
956 mTable_ChangeList.PushTail(tableChange);
957 ++mTable_ChangesCount;
958 } else {
959 tableChange->ZapOldNext(ev, heap);
960 this->NoteTableSetAll(ev);
961 }
962 }
963 }
964 }
965
note_row_change(morkEnv * ev,mork_change inChange,morkRow * ioRow)966 void morkTable::note_row_change(morkEnv* ev, mork_change inChange,
967 morkRow* ioRow) {
968 if (this->IsTableRewrite() || this->HasChangeOverflow())
969 this->NoteTableSetAll(ev);
970 else {
971 nsIMdbHeap* heap = mTable_Store->mPort_Heap;
972 morkTableChange* tableChange =
973 new (*heap, ev) morkTableChange(ev, inChange, ioRow);
974 if (tableChange) {
975 if (ev->Good()) {
976 mTable_ChangeList.PushTail(tableChange);
977 ++mTable_ChangesCount;
978 } else {
979 tableChange->ZapOldNext(ev, heap);
980 this->NoteTableSetAll(ev);
981 }
982 }
983 }
984 }
985
NoteTableSetAll(morkEnv * ev)986 void morkTable::NoteTableSetAll(morkEnv* ev) {
987 if (mTable_ChangeList.HasListMembers()) {
988 nsIMdbHeap* heap = mTable_Store->mPort_Heap;
989 mTable_ChangeList.CutAndZapAllListMembers(ev, heap); // forget changes
990 }
991 mTable_ChangesCount = 0;
992 this->SetTableRewrite();
993 }
994
TableGcUsesUnderflowWarning(morkEnv * ev)995 /*static*/ void morkTable::TableGcUsesUnderflowWarning(morkEnv* ev) {
996 ev->NewWarning("mTable_GcUses underflow");
997 }
998
NonTableTypeError(morkEnv * ev)999 /*static*/ void morkTable::NonTableTypeError(morkEnv* ev) {
1000 ev->NewError("non morkTable");
1001 }
1002
NonTableTypeWarning(morkEnv * ev)1003 /*static*/ void morkTable::NonTableTypeWarning(morkEnv* ev) {
1004 ev->NewWarning("non morkTable");
1005 }
1006
NilRowSpaceError(morkEnv * ev)1007 /*static*/ void morkTable::NilRowSpaceError(morkEnv* ev) {
1008 ev->NewError("nil mTable_RowSpace");
1009 }
1010
MaybeDirtySpaceStoreAndTable()1011 mork_bool morkTable::MaybeDirtySpaceStoreAndTable() {
1012 morkRowSpace* rowSpace = mTable_RowSpace;
1013 if (rowSpace) {
1014 morkStore* store = rowSpace->mSpace_Store;
1015 if (store && store->mStore_CanDirty) {
1016 store->SetStoreDirty();
1017 rowSpace->mSpace_CanDirty = morkBool_kTrue;
1018 }
1019
1020 if (rowSpace->mSpace_CanDirty) // first time being dirtied?
1021 {
1022 if (this->IsTableClean()) {
1023 mork_count rowCount = this->GetRowCount();
1024 mork_count oneThird = rowCount / 4; // one third of rows
1025 if (oneThird > 0x07FFF) // more than half max u2?
1026 oneThird = 0x07FFF;
1027
1028 mTable_ChangesMax = (mork_u2)oneThird;
1029 }
1030 this->SetTableDirty();
1031 rowSpace->SetRowSpaceDirty();
1032
1033 return morkBool_kTrue;
1034 }
1035 }
1036 return morkBool_kFalse;
1037 }
1038
GetMetaRow(morkEnv * ev,const mdbOid * inOptionalMetaRowOid)1039 morkRow* morkTable::GetMetaRow(morkEnv* ev,
1040 const mdbOid* inOptionalMetaRowOid) {
1041 morkRow* outRow = mTable_MetaRow;
1042 if (!outRow) {
1043 morkStore* store = mTable_Store;
1044 mdbOid* oid = &mTable_MetaRowOid;
1045 if (inOptionalMetaRowOid && !oid->mOid_Scope) *oid = *inOptionalMetaRowOid;
1046
1047 if (oid->mOid_Scope) // oid already recorded in table?
1048 outRow = store->OidToRow(ev, oid);
1049 else {
1050 outRow = store->NewRow(ev, morkStore_kMetaScope);
1051 if (outRow) // need to record new oid in table?
1052 *oid = outRow->mRow_Oid;
1053 }
1054 mTable_MetaRow = outRow;
1055 if (outRow) // need to note another use of this row?
1056 {
1057 outRow->AddRowGcUse(ev);
1058
1059 this->SetTableNewMeta();
1060 if (this->IsTableClean()) // catch dirty status of meta row?
1061 this->MaybeDirtySpaceStoreAndTable();
1062 }
1063 }
1064
1065 return outRow;
1066 }
1067
GetTableOid(morkEnv * ev,mdbOid * outOid)1068 void morkTable::GetTableOid(morkEnv* ev, mdbOid* outOid) {
1069 morkRowSpace* space = mTable_RowSpace;
1070 if (space) {
1071 outOid->mOid_Scope = space->SpaceScope();
1072 outOid->mOid_Id = this->TableId();
1073 } else
1074 this->NilRowSpaceError(ev);
1075 }
1076
AcquireTableHandle(morkEnv * ev)1077 nsIMdbTable* morkTable::AcquireTableHandle(morkEnv* ev) {
1078 AddRef();
1079 return this;
1080 }
1081
ArrayHasOid(morkEnv * ev,const mdbOid * inOid)1082 mork_pos morkTable::ArrayHasOid(morkEnv* ev, const mdbOid* inOid) {
1083 MORK_USED_1(ev);
1084 mork_count count = mTable_RowArray.mArray_Fill;
1085 mork_pos pos = -1;
1086 while (++pos < (mork_pos)count) {
1087 morkRow* row = (morkRow*)mTable_RowArray.At(pos);
1088 MORK_ASSERT(row);
1089 if (row && row->EqualOid(inOid)) {
1090 return pos;
1091 }
1092 }
1093 return -1;
1094 }
1095
MapHasOid(morkEnv * ev,const mdbOid * inOid)1096 mork_bool morkTable::MapHasOid(morkEnv* ev, const mdbOid* inOid) {
1097 if (mTable_RowMap)
1098 return (mTable_RowMap->GetOid(ev, inOid) != 0);
1099 else
1100 return (ArrayHasOid(ev, inOid) >= 0);
1101 }
1102
build_row_map(morkEnv * ev)1103 void morkTable::build_row_map(morkEnv* ev) {
1104 morkRowMap* map = mTable_RowMap;
1105 if (!map) {
1106 mork_count count = mTable_RowArray.mArray_Fill + 3;
1107 nsIMdbHeap* heap = mTable_Store->mPort_Heap;
1108 map = new (*heap, ev) morkRowMap(ev, morkUsage::kHeap, heap, heap, count);
1109 if (map) {
1110 if (ev->Good()) {
1111 mTable_RowMap = map; // put strong ref here
1112 count = mTable_RowArray.mArray_Fill;
1113 mork_pos pos = -1;
1114 while (++pos < (mork_pos)count) {
1115 morkRow* row = (morkRow*)mTable_RowArray.At(pos);
1116 if (row && row->IsRow())
1117 map->AddRow(ev, row);
1118 else
1119 row->NonRowTypeError(ev);
1120 }
1121 } else
1122 map->CutStrongRef(ev);
1123 }
1124 }
1125 }
1126
find_member_row(morkEnv * ev,morkRow * ioRow)1127 morkRow* morkTable::find_member_row(morkEnv* ev, morkRow* ioRow) {
1128 if (mTable_RowMap)
1129 return mTable_RowMap->GetRow(ev, ioRow);
1130 else {
1131 mork_count count = mTable_RowArray.mArray_Fill;
1132 mork_pos pos = -1;
1133 while (++pos < (mork_pos)count) {
1134 morkRow* row = (morkRow*)mTable_RowArray.At(pos);
1135 if (row == ioRow) return row;
1136 }
1137 }
1138 return (morkRow*)0;
1139 }
1140
MoveRow(morkEnv * ev,morkRow * ioRow,mork_pos inHintFromPos,mork_pos inToPos)1141 mork_pos morkTable::MoveRow(
1142 morkEnv* ev, morkRow* ioRow, // change row position
1143 mork_pos inHintFromPos, // suggested hint regarding start position
1144 mork_pos inToPos) // desired new position for row ioRow
1145 // MoveRow() returns the actual position of ioRow afterwards; this
1146 // position is -1 if and only if ioRow was not found as a member.
1147 {
1148 mork_pos outPos = -1; // means ioRow was not a table member
1149 mork_bool canDirty = (this->IsTableClean())
1150 ? this->MaybeDirtySpaceStoreAndTable()
1151 : morkBool_kTrue;
1152
1153 morkRow** rows = (morkRow**)mTable_RowArray.mArray_Slots;
1154 mork_count count = mTable_RowArray.mArray_Fill;
1155 if (count && rows && ev->Good()) // any members at all? no errors?
1156 {
1157 mork_pos lastPos = count - 1; // index of last row slot
1158
1159 if (inToPos > lastPos) // beyond last used array slot?
1160 inToPos = lastPos; // put row into last available slot
1161 else if (inToPos < 0) // before first usable slot?
1162 inToPos = 0; // put row in very first slow
1163
1164 if (inHintFromPos > lastPos) // beyond last used array slot?
1165 inHintFromPos = lastPos; // seek row in last available slot
1166 else if (inHintFromPos < 0) // before first usable slot?
1167 inHintFromPos = 0; // seek row in very first slow
1168
1169 morkRow** fromSlot = 0; // becomes nonzero of ioRow is ever found
1170 morkRow** rowsEnd = rows + count; // one past last used array slot
1171
1172 if (inHintFromPos <= 0) // start of table? just scan for row?
1173 {
1174 morkRow** cursor = rows - 1; // before first array slot
1175 while (++cursor < rowsEnd) {
1176 if (*cursor == ioRow) {
1177 fromSlot = cursor;
1178 break; // end while loop
1179 }
1180 }
1181 } else // search near the start position and work outwards
1182 {
1183 morkRow** lo = rows + inHintFromPos; // lowest search point
1184 morkRow** hi = lo; // highest search point starts at lowest point
1185
1186 // Seek ioRow in spiral widening search below and above inHintFromPos.
1187 // This is faster when inHintFromPos is at all accurate, but is slower
1188 // than a straightforward scan when inHintFromPos is nearly random.
1189
1190 while (lo >= rows || hi < rowsEnd) // keep searching?
1191 {
1192 if (lo >= rows) // low direction search still feasible?
1193 {
1194 if (*lo == ioRow) // actually found the row?
1195 {
1196 fromSlot = lo;
1197 break; // end while loop
1198 }
1199 --lo; // advance further lower
1200 }
1201 if (hi < rowsEnd) // high direction search still feasible?
1202 {
1203 if (*hi == ioRow) // actually found the row?
1204 {
1205 fromSlot = hi;
1206 break; // end while loop
1207 }
1208 ++hi; // advance further higher
1209 }
1210 }
1211 }
1212
1213 if (fromSlot) // ioRow was found as a table member?
1214 {
1215 outPos = fromSlot - rows; // actual position where row was found
1216 if (outPos != inToPos) // actually need to move this row?
1217 {
1218 morkRow** toSlot = rows + inToPos; // slot where row must go
1219
1220 ++mTable_RowArray.mArray_Seed; // we modify the array now:
1221
1222 if (fromSlot < toSlot) // row is moving upwards?
1223 {
1224 morkRow** up = fromSlot; // leading pointer going upward
1225 while (++up <= toSlot) // have not gone above destination?
1226 {
1227 *fromSlot = *up; // shift down one
1228 fromSlot = up; // shift trailing pointer up
1229 }
1230 } else // ( fromSlot > toSlot ) // row is moving downwards
1231 {
1232 morkRow** down = fromSlot; // leading pointer going downward
1233 while (--down >= toSlot) // have not gone below destination?
1234 {
1235 *fromSlot = *down; // shift up one
1236 fromSlot = down; // shift trailing pointer
1237 }
1238 }
1239 *toSlot = ioRow;
1240 outPos = inToPos; // okay, we actually moved the row here
1241
1242 if (canDirty) this->note_row_move(ev, ioRow, inToPos);
1243 }
1244 }
1245 }
1246 return outPos;
1247 }
1248
AddRow(morkEnv * ev,morkRow * ioRow)1249 mork_bool morkTable::AddRow(morkEnv* ev, morkRow* ioRow) {
1250 morkRow* row = this->find_member_row(ev, ioRow);
1251 if (!row && ev->Good()) {
1252 mork_bool canDirty = (this->IsTableClean())
1253 ? this->MaybeDirtySpaceStoreAndTable()
1254 : morkBool_kTrue;
1255
1256 mork_pos pos = mTable_RowArray.AppendSlot(ev, ioRow);
1257 if (ev->Good() && pos >= 0) {
1258 ioRow->AddRowGcUse(ev);
1259 if (mTable_RowMap) {
1260 if (mTable_RowMap->AddRow(ev, ioRow)) {
1261 // okay, anything else?
1262 } else
1263 mTable_RowArray.CutSlot(ev, pos);
1264 } else if (mTable_RowArray.mArray_Fill >= morkTable_kMakeRowMapThreshold)
1265 this->build_row_map(ev);
1266
1267 if (canDirty && ev->Good()) this->NoteTableAddRow(ev, ioRow);
1268 }
1269 }
1270 return ev->Good();
1271 }
1272
CutRow(morkEnv * ev,morkRow * ioRow)1273 mork_bool morkTable::CutRow(morkEnv* ev, morkRow* ioRow) {
1274 morkRow* row = this->find_member_row(ev, ioRow);
1275 if (row) {
1276 mork_bool canDirty = (this->IsTableClean())
1277 ? this->MaybeDirtySpaceStoreAndTable()
1278 : morkBool_kTrue;
1279
1280 mork_count count = mTable_RowArray.mArray_Fill;
1281 morkRow** rowSlots = (morkRow**)mTable_RowArray.mArray_Slots;
1282 if (rowSlots) // array has vector as expected?
1283 {
1284 mork_pos pos = -1;
1285 morkRow** end = rowSlots + count;
1286 morkRow** slot = rowSlots - 1; // prepare for preincrement:
1287 while (++slot < end) // another slot to check?
1288 {
1289 if (*slot == row) // found the slot containing row?
1290 {
1291 pos = slot - rowSlots; // record absolute position
1292 break; // end while loop
1293 }
1294 }
1295 if (pos >= 0) // need to cut if from the array?
1296 mTable_RowArray.CutSlot(ev, pos);
1297 else
1298 ev->NewWarning("row not found in array");
1299 } else
1300 mTable_RowArray.NilSlotsAddressError(ev);
1301
1302 if (mTable_RowMap) mTable_RowMap->CutRow(ev, ioRow);
1303
1304 if (canDirty) this->NoteTableCutRow(ev, ioRow);
1305
1306 if (ioRow->CutRowGcUse(ev) == 0) ioRow->OnZeroRowGcUse(ev);
1307 }
1308 return ev->Good();
1309 }
1310
CutAllRows(morkEnv * ev)1311 mork_bool morkTable::CutAllRows(morkEnv* ev) {
1312 if (this->MaybeDirtySpaceStoreAndTable()) {
1313 this->SetTableRewrite(); // everything is dirty
1314 this->NoteTableSetAll(ev);
1315 }
1316
1317 if (ev->Good()) {
1318 mTable_RowArray.CutAllSlots(ev);
1319 if (mTable_RowMap) {
1320 morkRowMapIter i(ev, mTable_RowMap);
1321 mork_change* c = 0;
1322 morkRow* r = 0;
1323
1324 for (c = i.FirstRow(ev, &r); c; c = i.NextRow(ev, &r)) {
1325 if (r) {
1326 if (r->CutRowGcUse(ev) == 0) r->OnZeroRowGcUse(ev);
1327
1328 i.CutHereRow(ev, (morkRow**)0);
1329 } else
1330 ev->NewWarning("nil row in table map");
1331 }
1332 }
1333 }
1334 return ev->Good();
1335 }
1336
NewTableRowCursor(morkEnv * ev,mork_pos inRowPos)1337 morkTableRowCursor* morkTable::NewTableRowCursor(morkEnv* ev,
1338 mork_pos inRowPos) {
1339 morkTableRowCursor* outCursor = 0;
1340 if (ev->Good()) {
1341 nsIMdbHeap* heap = mTable_Store->mPort_Heap;
1342 morkTableRowCursor* cursor = new (*heap, ev)
1343 morkTableRowCursor(ev, morkUsage::kHeap, heap, this, inRowPos);
1344 if (cursor) {
1345 if (ev->Good())
1346 outCursor = cursor;
1347 else
1348 cursor->CutStrongRef((nsIMdbEnv*)ev);
1349 }
1350 }
1351 return outCursor;
1352 }
1353
1354 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
1355
morkTableChange(morkEnv * ev,mork_change inChange,morkRow * ioRow)1356 morkTableChange::morkTableChange(morkEnv* ev, mork_change inChange,
1357 morkRow* ioRow)
1358 // use this constructor for inChange == morkChange_kAdd or morkChange_kCut
1359 : morkNext(),
1360 mTableChange_Row(ioRow),
1361 mTableChange_Pos(morkTableChange_kNone) {
1362 if (ioRow) {
1363 if (ioRow->IsRow()) {
1364 if (inChange == morkChange_kAdd)
1365 mTableChange_Pos = morkTableChange_kAdd;
1366 else if (inChange == morkChange_kCut)
1367 mTableChange_Pos = morkTableChange_kCut;
1368 else
1369 this->UnknownChangeError(ev);
1370 } else
1371 ioRow->NonRowTypeError(ev);
1372 } else
1373 ev->NilPointerError();
1374 }
1375
morkTableChange(morkEnv * ev,morkRow * ioRow,mork_pos inPos)1376 morkTableChange::morkTableChange(morkEnv* ev, morkRow* ioRow, mork_pos inPos)
1377 // use this constructor when the row is moved
1378 : morkNext(), mTableChange_Row(ioRow), mTableChange_Pos(inPos) {
1379 if (ioRow) {
1380 if (ioRow->IsRow()) {
1381 if (inPos < 0) this->NegativeMovePosError(ev);
1382 } else
1383 ioRow->NonRowTypeError(ev);
1384 } else
1385 ev->NilPointerError();
1386 }
1387
UnknownChangeError(morkEnv * ev) const1388 void morkTableChange::UnknownChangeError(morkEnv* ev) const
1389 // morkChange_kAdd or morkChange_kCut
1390 {
1391 ev->NewError("mTableChange_Pos neither kAdd nor kCut");
1392 }
1393
NegativeMovePosError(morkEnv * ev) const1394 void morkTableChange::NegativeMovePosError(morkEnv* ev) const
1395 // move must be non-neg position
1396 {
1397 ev->NewError("negative mTableChange_Pos for row move");
1398 }
1399
1400 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
1401
~morkTableMap()1402 morkTableMap::~morkTableMap() {}
1403
morkTableMap(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioHeap,nsIMdbHeap * ioSlotHeap)1404 morkTableMap::morkTableMap(morkEnv* ev, const morkUsage& inUsage,
1405 nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
1406 #ifdef MORK_BEAD_OVER_NODE_MAPS
1407 : morkBeadMap(ev, inUsage, ioHeap, ioSlotHeap)
1408 #else /*MORK_BEAD_OVER_NODE_MAPS*/
1409 : morkNodeMap(ev, inUsage, ioHeap, ioSlotHeap)
1410 #endif /*MORK_BEAD_OVER_NODE_MAPS*/
1411 {
1412 if (ev->Good()) mNode_Derived = morkDerived_kTableMap;
1413 }
1414
1415 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
1416