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 _MORKBLOB_
19 #  include "morkBlob.h"
20 #endif
21 
22 #ifndef _MORKMAP_
23 #  include "morkMap.h"
24 #endif
25 
26 #ifndef _MORKENV_
27 #  include "morkEnv.h"
28 #endif
29 
30 #ifndef _MORKSTORE_
31 #  include "morkStore.h"
32 #endif
33 
34 #ifndef _MORKFACTORY_
35 #  include "morkFactory.h"
36 #endif
37 
38 #ifndef _MORKNODEMAP_
39 #  include "morkNodeMap.h"
40 #endif
41 
42 #ifndef _MORKROW_
43 #  include "morkRow.h"
44 #endif
45 
46 #ifndef _MORKTHUMB_
47 #  include "morkThumb.h"
48 #endif
49 // #ifndef _MORKFILE_
50 // #include "morkFile.h"
51 // #endif
52 
53 #ifndef _MORKBUILDER_
54 #  include "morkBuilder.h"
55 #endif
56 
57 #ifndef _MORKATOMSPACE_
58 #  include "morkAtomSpace.h"
59 #endif
60 
61 #ifndef _MORKSTREAM_
62 #  include "morkStream.h"
63 #endif
64 
65 #ifndef _MORKATOMSPACE_
66 #  include "morkAtomSpace.h"
67 #endif
68 
69 #ifndef _MORKROWSPACE_
70 #  include "morkRowSpace.h"
71 #endif
72 
73 #ifndef _MORKPORTTABLECURSOR_
74 #  include "morkPortTableCursor.h"
75 #endif
76 
77 #ifndef _MORKTABLE_
78 #  include "morkTable.h"
79 #endif
80 
81 #ifndef _MORKROWMAP_
82 #  include "morkRowMap.h"
83 #endif
84 
85 #ifndef _MORKPARSER_
86 #  include "morkParser.h"
87 #endif
88 
89 #include "nsCOMPtr.h"
90 
91 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
92 
93 // ````` ````` ````` ````` `````
94 // { ===== begin morkNode interface =====
95 
96 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
97 
98 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
99 
100 // ````` ````` ````` ````` `````
101 // { ===== begin morkNode interface =====
102 
CloseMorkNode(morkEnv * ev)103 /*public virtual*/ void morkStore::CloseMorkNode(
104     morkEnv* ev)  // ClosePort() only if open
105 {
106   if (this->IsOpenNode()) {
107     this->MarkClosing();
108     this->CloseStore(ev);
109     this->MarkShut();
110   }
111 }
112 
ClosePort(morkEnv * ev)113 /*public non-poly*/ void morkStore::ClosePort(
114     morkEnv* ev)  // called by CloseMorkNode();
115 {
116   if (this->IsNode()) {
117     morkFactory::SlotWeakFactory((morkFactory*)0, ev, &mPort_Factory);
118     nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*)0, ev, &mPort_Heap);
119     this->CloseObject(ev);
120     this->MarkShut();
121   } else
122     this->NonNodeError(ev);
123 }
124 
125 /*public virtual*/
~morkStore()126 morkStore::~morkStore()  // assert CloseStore() executed earlier
127 {
128   if (IsOpenNode()) CloseMorkNode(mMorkEnv);
129   MORK_ASSERT(this->IsShutNode());
130   MORK_ASSERT(mStore_File == 0);
131   MORK_ASSERT(mStore_InStream == 0);
132   MORK_ASSERT(mStore_OutStream == 0);
133   MORK_ASSERT(mStore_Builder == 0);
134   MORK_ASSERT(mStore_OidAtomSpace == 0);
135   MORK_ASSERT(mStore_GroundAtomSpace == 0);
136   MORK_ASSERT(mStore_GroundColumnSpace == 0);
137   MORK_ASSERT(mStore_RowSpaces.IsShutNode());
138   MORK_ASSERT(mStore_AtomSpaces.IsShutNode());
139   MORK_ASSERT(mStore_Pool.IsShutNode());
140 }
141 
142 /*public non-poly*/
morkStore(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioNodeHeap,morkFactory * inFactory,nsIMdbHeap * ioPortHeap)143 morkStore::morkStore(
144     morkEnv* ev, const morkUsage& inUsage,
145     nsIMdbHeap* ioNodeHeap,  // the heap (if any) for this node instance
146     morkFactory* inFactory,  // the factory for this
147     nsIMdbHeap* ioPortHeap   // the heap to hold all content in the port
148     )
149     : morkObject(ev, inUsage, ioNodeHeap, morkColor_kNone, (morkHandle*)0),
150       mPort_Env(ev),
151       mPort_Factory(0),
152       mPort_Heap(0),
153       mStore_OidAtomSpace(0),
154       mStore_GroundAtomSpace(0),
155       mStore_GroundColumnSpace(0)
156 
157       ,
158       mStore_File(0),
159       mStore_InStream(0),
160       mStore_Builder(0),
161       mStore_OutStream(0)
162 
163       ,
164       mStore_RowSpaces(ev, morkUsage::kMember, (nsIMdbHeap*)0, ioPortHeap),
165       mStore_AtomSpaces(ev, morkUsage::kMember, (nsIMdbHeap*)0, ioPortHeap),
166       mStore_Zone(ev, morkUsage::kMember, (nsIMdbHeap*)0, ioPortHeap),
167       mStore_Pool(ev, morkUsage::kMember, (nsIMdbHeap*)0, ioPortHeap)
168 
169       ,
170       mStore_CommitGroupIdentity(0)
171 
172       ,
173       mStore_FirstCommitGroupPos(0),
174       mStore_SecondCommitGroupPos(0)
175 
176       // disable auto-assignment of atom IDs until someone knows it is okay:
177       ,
178       mStore_CanAutoAssignAtomIdentity(morkBool_kFalse),
179       mStore_CanDirty(morkBool_kFalse)  // not until the store is open
180       ,
181       mStore_CanWriteIncremental(morkBool_kTrue)  // always with few exceptions
182 {
183   if (ev->Good()) {
184     if (inFactory && ioPortHeap) {
185       morkFactory::SlotWeakFactory(inFactory, ev, &mPort_Factory);
186       nsIMdbHeap_SlotStrongHeap(ioPortHeap, ev, &mPort_Heap);
187       if (ev->Good()) mNode_Derived = morkDerived_kPort;
188     } else
189       ev->NilPointerError();
190   }
191   if (ev->Good()) {
192     mNode_Derived = morkDerived_kStore;
193   }
194 }
195 
NS_IMPL_ISUPPORTS_INHERITED(morkStore,morkObject,nsIMdbStore)196 NS_IMPL_ISUPPORTS_INHERITED(morkStore, morkObject, nsIMdbStore)
197 
198 /*public non-poly*/ void morkStore::CloseStore(
199     morkEnv* ev)  // called by CloseMorkNode();
200 {
201   if (this->IsNode()) {
202     nsIMdbFile* file = mStore_File;
203     file->AddRef();
204 
205     morkFactory::SlotWeakFactory((morkFactory*)0, ev, &mPort_Factory);
206     nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*)0, ev, &mPort_Heap);
207     morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*)0, ev,
208                                        &mStore_OidAtomSpace);
209     morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*)0, ev,
210                                        &mStore_GroundAtomSpace);
211     morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*)0, ev,
212                                        &mStore_GroundColumnSpace);
213     mStore_RowSpaces.CloseMorkNode(ev);
214     mStore_AtomSpaces.CloseMorkNode(ev);
215     morkBuilder::SlotStrongBuilder((morkBuilder*)0, ev, &mStore_Builder);
216 
217     nsIMdbFile_SlotStrongFile((nsIMdbFile*)0, ev, &mStore_File);
218 
219     file->Release();
220 
221     morkStream::SlotStrongStream((morkStream*)0, ev, &mStore_InStream);
222     morkStream::SlotStrongStream((morkStream*)0, ev, &mStore_OutStream);
223 
224     mStore_Pool.CloseMorkNode(ev);
225     mStore_Zone.CloseMorkNode(ev);
226     this->ClosePort(ev);
227     this->MarkShut();
228   } else
229     this->NonNodeError(ev);
230 }
231 
232 // } ===== end morkNode methods =====
233 // ````` ````` ````` ````` `````
234 
DoPreferLargeOverCompressCommit(morkEnv * ev)235 mork_bool morkStore::DoPreferLargeOverCompressCommit(morkEnv* ev)
236 // true when mStore_CanWriteIncremental && store has file large enough
237 {
238   nsIMdbFile* file = mStore_File;
239   if (file && mStore_CanWriteIncremental) {
240     mdb_pos fileEof = 0;
241     file->Eof(ev->AsMdbEnv(), &fileEof);
242     if (ev->Good() && fileEof > 128) return morkBool_kTrue;
243   }
244   return morkBool_kFalse;
245 }
246 
PercentOfStoreWasted(morkEnv * ev)247 mork_percent morkStore::PercentOfStoreWasted(morkEnv* ev) {
248   mork_percent outPercent = 0;
249   nsIMdbFile* file = mStore_File;
250 
251   if (file) {
252     mork_pos firstPos = mStore_FirstCommitGroupPos;
253     mork_pos secondPos = mStore_SecondCommitGroupPos;
254     if (firstPos || secondPos) {
255       if (firstPos < 512 && secondPos > firstPos)
256         firstPos = secondPos;  // better approximation of first commit
257 
258       mork_pos fileLength = 0;
259       file->Eof(ev->AsMdbEnv(), &fileLength);  // end of file
260       if (ev->Good() && fileLength > firstPos) {
261         mork_size groupContent = fileLength - firstPos;
262         outPercent = (groupContent * 100) / fileLength;
263       }
264     }
265   } else
266     this->NilStoreFileError(ev);
267 
268   return outPercent;
269 }
270 
SetStoreAndAllSpacesCanDirty(morkEnv * ev,mork_bool inCanDirty)271 void morkStore::SetStoreAndAllSpacesCanDirty(morkEnv* ev,
272                                              mork_bool inCanDirty) {
273   mStore_CanDirty = inCanDirty;
274 
275   mork_change* c = 0;
276   mork_scope* key = 0;  // ignore keys in maps
277 
278   if (ev->Good()) {
279     morkAtomSpaceMapIter asi(ev, &mStore_AtomSpaces);
280 
281     morkAtomSpace* atomSpace = 0;  // old val node in the map
282 
283     for (c = asi.FirstAtomSpace(ev, key, &atomSpace); c && ev->Good();
284          c = asi.NextAtomSpace(ev, key, &atomSpace)) {
285       if (atomSpace) {
286         if (atomSpace->IsAtomSpace())
287           atomSpace->mSpace_CanDirty = inCanDirty;
288         else
289           atomSpace->NonAtomSpaceTypeError(ev);
290       } else
291         ev->NilPointerError();
292     }
293   }
294 
295   if (ev->Good()) {
296     morkRowSpaceMapIter rsi(ev, &mStore_RowSpaces);
297     morkRowSpace* rowSpace = 0;  // old val node in the map
298 
299     for (c = rsi.FirstRowSpace(ev, key, &rowSpace); c && ev->Good();
300          c = rsi.NextRowSpace(ev, key, &rowSpace)) {
301       if (rowSpace) {
302         if (rowSpace->IsRowSpace())
303           rowSpace->mSpace_CanDirty = inCanDirty;
304         else
305           rowSpace->NonRowSpaceTypeError(ev);
306       }
307     }
308   }
309 }
310 
RenumberAllCollectableContent(morkEnv * ev)311 void morkStore::RenumberAllCollectableContent(morkEnv* ev) {
312   MORK_USED_1(ev);
313   // do nothing currently
314 }
315 
AcquireStoreHandle(morkEnv * ev)316 nsIMdbStore* morkStore::AcquireStoreHandle(morkEnv* ev) { return this; }
317 
StageAliasAsFarBookAtom(morkEnv * ev,const morkMid * inMid,morkAtomSpace * ioSpace,mork_cscode inForm)318 morkFarBookAtom* morkStore::StageAliasAsFarBookAtom(morkEnv* ev,
319                                                     const morkMid* inMid,
320                                                     morkAtomSpace* ioSpace,
321                                                     mork_cscode inForm) {
322   if (inMid && inMid->mMid_Buf) {
323     const morkBuf* buf = inMid->mMid_Buf;
324     mork_size length = buf->mBuf_Fill;
325     if (length <= morkBookAtom_kMaxBodySize) {
326       mork_aid dummyAid = 1;
327       // mStore_BookAtom.InitMaxBookAtom(ev, *buf,
328       //  inForm, ioSpace, dummyAid);
329 
330       mStore_FarBookAtom.InitFarBookAtom(ev, *buf, inForm, ioSpace, dummyAid);
331       return &mStore_FarBookAtom;
332     }
333   } else
334     ev->NilPointerError();
335 
336   return (morkFarBookAtom*)0;
337 }
338 
StageYarnAsFarBookAtom(morkEnv * ev,const mdbYarn * inYarn,morkAtomSpace * ioSpace)339 morkFarBookAtom* morkStore::StageYarnAsFarBookAtom(morkEnv* ev,
340                                                    const mdbYarn* inYarn,
341                                                    morkAtomSpace* ioSpace) {
342   if (inYarn && inYarn->mYarn_Buf) {
343     mork_size length = inYarn->mYarn_Fill;
344     if (length <= morkBookAtom_kMaxBodySize) {
345       morkBuf buf(inYarn->mYarn_Buf, length);
346       mork_aid dummyAid = 1;
347       // mStore_BookAtom.InitMaxBookAtom(ev, buf,
348       //  inYarn->mYarn_Form, ioSpace, dummyAid);
349       mStore_FarBookAtom.InitFarBookAtom(ev, buf, inYarn->mYarn_Form, ioSpace,
350                                          dummyAid);
351       return &mStore_FarBookAtom;
352     }
353   } else
354     ev->NilPointerError();
355 
356   return (morkFarBookAtom*)0;
357 }
358 
StageStringAsFarBookAtom(morkEnv * ev,const char * inString,mork_cscode inForm,morkAtomSpace * ioSpace)359 morkFarBookAtom* morkStore::StageStringAsFarBookAtom(morkEnv* ev,
360                                                      const char* inString,
361                                                      mork_cscode inForm,
362                                                      morkAtomSpace* ioSpace) {
363   if (inString) {
364     mork_size length = strlen(inString);
365     if (length <= morkBookAtom_kMaxBodySize) {
366       morkBuf buf(inString, length);
367       mork_aid dummyAid = 1;
368       // mStore_BookAtom.InitMaxBookAtom(ev, buf, inForm, ioSpace, dummyAid);
369       mStore_FarBookAtom.InitFarBookAtom(ev, buf, inForm, ioSpace, dummyAid);
370       return &mStore_FarBookAtom;
371     }
372   } else
373     ev->NilPointerError();
374 
375   return (morkFarBookAtom*)0;
376 }
377 
LazyGetOidAtomSpace(morkEnv * ev)378 morkAtomSpace* morkStore::LazyGetOidAtomSpace(morkEnv* ev) {
379   MORK_USED_1(ev);
380   if (!mStore_OidAtomSpace) {
381   }
382   return mStore_OidAtomSpace;
383 }
384 
LazyGetGroundAtomSpace(morkEnv * ev)385 morkAtomSpace* morkStore::LazyGetGroundAtomSpace(morkEnv* ev) {
386   if (!mStore_GroundAtomSpace) {
387     mork_scope atomScope = morkStore_kValueSpaceScope;
388     nsIMdbHeap* heap = mPort_Heap;
389     morkAtomSpace* space = new (*heap, ev)
390         morkAtomSpace(ev, morkUsage::kHeap, atomScope, this, heap, heap);
391 
392     if (space)  // successful space creation?
393     {
394       this->MaybeDirtyStore();
395 
396       mStore_GroundAtomSpace = space;  // transfer strong ref to this slot
397       mStore_AtomSpaces.AddAtomSpace(ev, space);
398     }
399   }
400   return mStore_GroundAtomSpace;
401 }
402 
LazyGetGroundColumnSpace(morkEnv * ev)403 morkAtomSpace* morkStore::LazyGetGroundColumnSpace(morkEnv* ev) {
404   if (!mStore_GroundColumnSpace) {
405     mork_scope atomScope = morkStore_kGroundColumnSpace;
406     nsIMdbHeap* heap = mPort_Heap;
407     morkAtomSpace* space = new (*heap, ev)
408         morkAtomSpace(ev, morkUsage::kHeap, atomScope, this, heap, heap);
409 
410     if (space)  // successful space creation?
411     {
412       this->MaybeDirtyStore();
413 
414       mStore_GroundColumnSpace = space;  // transfer strong ref to this slot
415       mStore_AtomSpaces.AddAtomSpace(ev, space);
416     }
417   }
418   return mStore_GroundColumnSpace;
419 }
420 
LazyGetInStream(morkEnv * ev)421 morkStream* morkStore::LazyGetInStream(morkEnv* ev) {
422   if (!mStore_InStream) {
423     nsIMdbFile* file = mStore_File;
424     if (file) {
425       morkStream* stream = new (*mPort_Heap, ev)
426           morkStream(ev, morkUsage::kHeap, mPort_Heap, file,
427                      morkStore_kStreamBufSize, /*frozen*/ morkBool_kTrue);
428       if (stream) {
429         this->MaybeDirtyStore();
430         mStore_InStream = stream;  // transfer strong ref to this slot
431       }
432     } else
433       this->NilStoreFileError(ev);
434   }
435   return mStore_InStream;
436 }
437 
LazyGetOutStream(morkEnv * ev)438 morkStream* morkStore::LazyGetOutStream(morkEnv* ev) {
439   if (!mStore_OutStream) {
440     nsIMdbFile* file = mStore_File;
441     if (file) {
442       morkStream* stream = new (*mPort_Heap, ev)
443           morkStream(ev, morkUsage::kHeap, mPort_Heap, file,
444                      morkStore_kStreamBufSize, /*frozen*/ morkBool_kFalse);
445       if (stream) {
446         this->MaybeDirtyStore();
447         mStore_InStream = stream;  // transfer strong ref to this slot
448       }
449     } else
450       this->NilStoreFileError(ev);
451   }
452   return mStore_OutStream;
453 }
454 
ForgetBuilder(morkEnv * ev)455 void morkStore::ForgetBuilder(morkEnv* ev) {
456   if (mStore_Builder)
457     morkBuilder::SlotStrongBuilder((morkBuilder*)0, ev, &mStore_Builder);
458   if (mStore_InStream)
459     morkStream::SlotStrongStream((morkStream*)0, ev, &mStore_InStream);
460 }
461 
LazyGetBuilder(morkEnv * ev)462 morkBuilder* morkStore::LazyGetBuilder(morkEnv* ev) {
463   if (!mStore_Builder) {
464     morkStream* stream = this->LazyGetInStream(ev);
465     if (stream) {
466       nsIMdbHeap* heap = mPort_Heap;
467       morkBuilder* builder = new (*heap, ev)
468           morkBuilder(ev, morkUsage::kHeap, heap, stream,
469                       morkBuilder_kDefaultBytesPerParseSegment, heap, this);
470       if (builder) {
471         mStore_Builder = builder;  // transfer strong ref to this slot
472       }
473     }
474   }
475   return mStore_Builder;
476 }
477 
LazyGetRowSpace(morkEnv * ev,mdb_scope inRowScope)478 morkRowSpace* morkStore::LazyGetRowSpace(morkEnv* ev, mdb_scope inRowScope) {
479   morkRowSpace* outSpace = mStore_RowSpaces.GetRowSpace(ev, inRowScope);
480   if (!outSpace && ev->Good())  // try to make new space?
481   {
482     nsIMdbHeap* heap = mPort_Heap;
483     outSpace = new (*heap, ev)
484         morkRowSpace(ev, morkUsage::kHeap, inRowScope, this, heap, heap);
485 
486     if (outSpace)  // successful space creation?
487     {
488       this->MaybeDirtyStore();
489 
490       // note adding to node map creates its own strong ref...
491       if (mStore_RowSpaces.AddRowSpace(ev, outSpace))
492         outSpace->CutStrongRef(ev);  // ...so we can drop our strong ref
493     }
494   }
495   return outSpace;
496 }
497 
LazyGetAtomSpace(morkEnv * ev,mdb_scope inAtomScope)498 morkAtomSpace* morkStore::LazyGetAtomSpace(morkEnv* ev, mdb_scope inAtomScope) {
499   morkAtomSpace* outSpace = mStore_AtomSpaces.GetAtomSpace(ev, inAtomScope);
500   if (!outSpace && ev->Good())  // try to make new space?
501   {
502     if (inAtomScope == morkStore_kValueSpaceScope)
503       outSpace = this->LazyGetGroundAtomSpace(ev);
504 
505     else if (inAtomScope == morkStore_kGroundColumnSpace)
506       outSpace = this->LazyGetGroundColumnSpace(ev);
507     else {
508       nsIMdbHeap* heap = mPort_Heap;
509       outSpace = new (*heap, ev)
510           morkAtomSpace(ev, morkUsage::kHeap, inAtomScope, this, heap, heap);
511 
512       if (outSpace)  // successful space creation?
513       {
514         this->MaybeDirtyStore();
515 
516         // note adding to node map creates its own strong ref...
517         if (mStore_AtomSpaces.AddAtomSpace(ev, outSpace))
518           outSpace->CutStrongRef(ev);  // ...so we can drop our strong ref
519       }
520     }
521   }
522   return outSpace;
523 }
524 
NonStoreTypeError(morkEnv * ev)525 /*static*/ void morkStore::NonStoreTypeError(morkEnv* ev) {
526   ev->NewError("non morkStore");
527 }
528 
NilStoreFileError(morkEnv * ev)529 /*static*/ void morkStore::NilStoreFileError(morkEnv* ev) {
530   ev->NewError("nil mStore_File");
531 }
532 
CannotAutoAssignAtomIdentityError(morkEnv * ev)533 /*static*/ void morkStore::CannotAutoAssignAtomIdentityError(morkEnv* ev) {
534   ev->NewError("false mStore_CanAutoAssignAtomIdentity");
535 }
536 
OpenStoreFile(morkEnv * ev,mork_bool inFrozen,nsIMdbFile * ioFile,const mdbOpenPolicy * inOpenPolicy)537 mork_bool morkStore::OpenStoreFile(
538     morkEnv* ev, mork_bool inFrozen,
539     // const char* inFilePath,
540     nsIMdbFile* ioFile,  // db abstract file interface
541     const mdbOpenPolicy* inOpenPolicy) {
542   MORK_USED_2(inOpenPolicy, inFrozen);
543   nsIMdbFile_SlotStrongFile(ioFile, ev, &mStore_File);
544 
545   // if ( ev->Good() )
546   // {
547   //   morkFile* file = morkFile::OpenOldFile(ev, mPort_Heap,
548   //     inFilePath, inFrozen);
549   //   if ( ioFile )
550   //   {
551   //     if ( ev->Good() )
552   //       morkFile::SlotStrongFile(file, ev, &mStore_File);
553   //     else
554   //       file->CutStrongRef(ev);
555   //
556   //   }
557   // }
558   return ev->Good();
559 }
560 
CreateStoreFile(morkEnv * ev,nsIMdbFile * ioFile,const mdbOpenPolicy * inOpenPolicy)561 mork_bool morkStore::CreateStoreFile(
562     morkEnv* ev,
563     // const char* inFilePath,
564     nsIMdbFile* ioFile,  // db abstract file interface
565     const mdbOpenPolicy* inOpenPolicy) {
566   MORK_USED_1(inOpenPolicy);
567   nsIMdbFile_SlotStrongFile(ioFile, ev, &mStore_File);
568 
569   return ev->Good();
570 }
571 
CopyAtom(morkEnv * ev,const morkAtom * inAtom)572 morkAtom* morkStore::CopyAtom(morkEnv* ev, const morkAtom* inAtom)
573 // copy inAtom (from some other store) over to this store
574 {
575   morkAtom* outAtom = 0;
576   if (inAtom) {
577     mdbYarn yarn;
578     if (morkAtom::AliasYarn(inAtom, &yarn))
579       outAtom = this->YarnToAtom(ev, &yarn, true /* create */);
580   }
581   return outAtom;
582 }
583 
YarnToAtom(morkEnv * ev,const mdbYarn * inYarn,bool createIfMissing)584 morkAtom* morkStore::YarnToAtom(morkEnv* ev, const mdbYarn* inYarn,
585                                 bool createIfMissing /* = true */) {
586   morkAtom* outAtom = 0;
587   if (ev->Good()) {
588     morkAtomSpace* groundSpace = this->LazyGetGroundAtomSpace(ev);
589     if (groundSpace) {
590       morkFarBookAtom* keyAtom =
591           this->StageYarnAsFarBookAtom(ev, inYarn, groundSpace);
592 
593       if (keyAtom) {
594         morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
595         outAtom = map->GetAtom(ev, keyAtom);
596         if (!outAtom && createIfMissing) {
597           this->MaybeDirtyStore();
598           outAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
599         }
600       } else if (ev->Good()) {
601         morkBuf b(inYarn->mYarn_Buf, inYarn->mYarn_Fill);
602         morkZone* z = &mStore_Zone;
603         outAtom = mStore_Pool.NewAnonAtom(ev, b, inYarn->mYarn_Form, z);
604       }
605     }
606   }
607   return outAtom;
608 }
609 
MidToOid(morkEnv * ev,const morkMid & inMid,mdbOid * outOid)610 mork_bool morkStore::MidToOid(morkEnv* ev, const morkMid& inMid,
611                               mdbOid* outOid) {
612   *outOid = inMid.mMid_Oid;
613   const morkBuf* buf = inMid.mMid_Buf;
614   if (buf && !outOid->mOid_Scope) {
615     if (buf->mBuf_Fill <= morkBookAtom_kMaxBodySize) {
616       if (buf->mBuf_Fill == 1) {
617         mork_u1* name = (mork_u1*)buf->mBuf_Body;
618         if (name) {
619           outOid->mOid_Scope = (mork_scope)*name;
620           return ev->Good();
621         }
622       }
623       morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev);
624       if (groundSpace) {
625         mork_cscode form = 0;  // default
626         mork_aid aid = 1;      // dummy
627         mStore_FarBookAtom.InitFarBookAtom(ev, *buf, form, groundSpace, aid);
628         morkFarBookAtom* keyAtom = &mStore_FarBookAtom;
629         morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
630         morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom);
631         if (bookAtom)
632           outOid->mOid_Scope = bookAtom->mBookAtom_Id;
633         else {
634           this->MaybeDirtyStore();
635           bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
636           if (bookAtom) {
637             outOid->mOid_Scope = bookAtom->mBookAtom_Id;
638             bookAtom->MakeCellUseForever(ev);
639           }
640         }
641       }
642     }
643   }
644   return ev->Good();
645 }
646 
MidToRow(morkEnv * ev,const morkMid & inMid)647 morkRow* morkStore::MidToRow(morkEnv* ev, const morkMid& inMid) {
648   mdbOid tempOid;
649   this->MidToOid(ev, inMid, &tempOid);
650   return this->OidToRow(ev, &tempOid);
651 }
652 
MidToTable(morkEnv * ev,const morkMid & inMid)653 morkTable* morkStore::MidToTable(morkEnv* ev, const morkMid& inMid) {
654   mdbOid tempOid;
655   this->MidToOid(ev, inMid, &tempOid);
656   return this->OidToTable(ev, &tempOid, /*metarow*/ (mdbOid*)0);
657 }
658 
MidToYarn(morkEnv * ev,const morkMid & inMid,mdbYarn * outYarn)659 mork_bool morkStore::MidToYarn(morkEnv* ev, const morkMid& inMid,
660                                mdbYarn* outYarn) {
661   mdbOid tempOid;
662   this->MidToOid(ev, inMid, &tempOid);
663   return this->OidToYarn(ev, tempOid, outYarn);
664 }
665 
OidToYarn(morkEnv * ev,const mdbOid & inOid,mdbYarn * outYarn)666 mork_bool morkStore::OidToYarn(morkEnv* ev, const mdbOid& inOid,
667                                mdbYarn* outYarn) {
668   morkBookAtom* atom = 0;
669 
670   morkAtomSpace* atomSpace =
671       mStore_AtomSpaces.GetAtomSpace(ev, inOid.mOid_Scope);
672   if (atomSpace) {
673     morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids;
674     atom = map->GetAid(ev, (mork_aid)inOid.mOid_Id);
675   }
676   morkAtom::GetYarn(atom, outYarn);
677 
678   return ev->Good();
679 }
680 
MidToAtom(morkEnv * ev,const morkMid & inMid)681 morkBookAtom* morkStore::MidToAtom(morkEnv* ev, const morkMid& inMid) {
682   morkBookAtom* outAtom = 0;
683   mdbOid oid;
684   if (this->MidToOid(ev, inMid, &oid)) {
685     morkAtomSpace* atomSpace =
686         mStore_AtomSpaces.GetAtomSpace(ev, oid.mOid_Scope);
687     if (atomSpace) {
688       morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids;
689       outAtom = map->GetAid(ev, (mork_aid)oid.mOid_Id);
690     }
691   }
692   return outAtom;
693 }
694 
SmallTokenToOneByteYarn(morkEnv * ev,mdb_token inToken,mdbYarn * outYarn)695 /*static*/ void morkStore::SmallTokenToOneByteYarn(morkEnv* ev,
696                                                    mdb_token inToken,
697                                                    mdbYarn* outYarn) {
698   MORK_USED_1(ev);
699   if (outYarn->mYarn_Buf && outYarn->mYarn_Size)  // any space in yarn at all?
700   {
701     mork_u1* buf = (mork_u1*)outYarn->mYarn_Buf;  // for byte arithmetic
702     buf[0] = (mork_u1)inToken;                    // write the single byte
703     outYarn->mYarn_Fill = 1;
704     outYarn->mYarn_More = 0;
705   } else  // just record we could not write the single byte
706   {
707     outYarn->mYarn_More = 1;
708     outYarn->mYarn_Fill = 0;
709   }
710 }
711 
TokenToString(morkEnv * ev,mdb_token inToken,mdbYarn * outTokenName)712 void morkStore::TokenToString(morkEnv* ev, mdb_token inToken,
713                               mdbYarn* outTokenName) {
714   if (inToken > morkAtomSpace_kMaxSevenBitAid) {
715     morkBookAtom* atom = 0;
716     morkAtomSpace* space = mStore_GroundColumnSpace;
717     if (space) atom = space->mAtomSpace_AtomAids.GetAid(ev, (mork_aid)inToken);
718 
719     morkAtom::GetYarn(atom, outTokenName);
720   } else  // token is an "immediate" single byte string representation?
721     this->SmallTokenToOneByteYarn(ev, inToken, outTokenName);
722 }
723 
724 // void
725 // morkStore::SyncTokenIdChange(morkEnv* ev, const morkBookAtom* inAtom,
726 //   const mdbOid* inOid)
727 // {
728 // mork_token   mStore_MorkNoneToken;    // token for "mork:none"   // fill=9
729 // mork_column  mStore_CharsetToken;     // token for "charset"     // fill=7
730 // mork_column  mStore_AtomScopeToken;   // token for "atomScope"   // fill=9
731 // mork_column  mStore_RowScopeToken;    // token for "rowScope"    // fill=8
732 // mork_column  mStore_TableScopeToken;  // token for "tableScope"  // fill=10
733 // mork_column  mStore_ColumnScopeToken; // token for "columnScope" // fill=11
734 // mork_kind    mStore_TableKindToken;   // token for "tableKind"   // fill=9
735 // ---------------------ruler-for-token-length-above---123456789012
736 //
737 //   if ( inOid->mOid_Scope == morkStore_kColumnSpaceScope &&
738 //   inAtom->IsWeeBook() )
739 //   {
740 //     const mork_u1* body = ((const morkWeeBookAtom*)
741 //     inAtom)->mWeeBookAtom_Body; mork_size size = inAtom->mAtom_Size;
742 //
743 //     if ( size >= 7 && size <= 11 )
744 //     {
745 //       if ( size == 9 )
746 //       {
747 //         if ( *body == 'm' )
748 //         {
749 //           if ( MORK_MEMCMP(body, "mork:none", 9) == 0 )
750 //             mStore_MorkNoneToken = inAtom->mBookAtom_Id;
751 //         }
752 //         else if ( *body == 'a' )
753 //         {
754 //           if ( MORK_MEMCMP(body, "atomScope", 9) == 0 )
755 //             mStore_AtomScopeToken = inAtom->mBookAtom_Id;
756 //         }
757 //         else if ( *body == 't' )
758 //         {
759 //           if ( MORK_MEMCMP(body, "tableKind", 9) == 0 )
760 //             mStore_TableKindToken = inAtom->mBookAtom_Id;
761 //         }
762 //       }
763 //       else if ( size == 7 && *body == 'c' )
764 //       {
765 //         if ( MORK_MEMCMP(body, "charset", 7) == 0 )
766 //           mStore_CharsetToken = inAtom->mBookAtom_Id;
767 //       }
768 //       else if ( size == 8 && *body == 'r' )
769 //       {
770 //         if ( MORK_MEMCMP(body, "rowScope", 8) == 0 )
771 //           mStore_RowScopeToken = inAtom->mBookAtom_Id;
772 //       }
773 //       else if ( size == 10 && *body == 't' )
774 //       {
775 //         if ( MORK_MEMCMP(body, "tableScope", 10) == 0 )
776 //           mStore_TableScopeToken = inAtom->mBookAtom_Id;
777 //       }
778 //       else if ( size == 11 && *body == 'c' )
779 //       {
780 //         if ( MORK_MEMCMP(body, "columnScope", 11) == 0 )
781 //           mStore_ColumnScopeToken = inAtom->mBookAtom_Id;
782 //       }
783 //     }
784 //   }
785 // }
786 
AddAlias(morkEnv * ev,const morkMid & inMid,mork_cscode inForm)787 morkAtom* morkStore::AddAlias(morkEnv* ev, const morkMid& inMid,
788                               mork_cscode inForm) {
789   morkBookAtom* outAtom = 0;
790   if (ev->Good()) {
791     const mdbOid* oid = &inMid.mMid_Oid;
792     morkAtomSpace* atomSpace = this->LazyGetAtomSpace(ev, oid->mOid_Scope);
793     if (atomSpace) {
794       morkFarBookAtom* keyAtom =
795           this->StageAliasAsFarBookAtom(ev, &inMid, atomSpace, inForm);
796       if (keyAtom) {
797         morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids;
798         outAtom = map->GetAid(ev, (mork_aid)oid->mOid_Id);
799         if (outAtom) {
800           if (!outAtom->EqualFormAndBody(ev, keyAtom))
801             ev->NewError("duplicate alias ID");
802         } else {
803           this->MaybeDirtyStore();
804           keyAtom->mBookAtom_Id = oid->mOid_Id;
805           outAtom = atomSpace->MakeBookAtomCopyWithAid(ev, *keyAtom,
806                                                        (mork_aid)oid->mOid_Id);
807 
808           // if ( outAtom && outAtom->IsWeeBook() )
809           // {
810           //   if ( oid->mOid_Scope == morkStore_kColumnSpaceScope )
811           //   {
812           //    mork_size size = outAtom->mAtom_Size;
813           //     if ( size >= 7 && size <= 11 )
814           //       this->SyncTokenIdChange(ev, outAtom, oid);
815           //   }
816           // }
817         }
818       }
819     }
820   }
821   return outAtom;
822 }
823 
824 #define morkStore_kMaxCopyTokenSize 512 /* if larger, cannot be copied */
825 
CopyToken(morkEnv * ev,mdb_token inToken,morkStore * inStore)826 mork_token morkStore::CopyToken(morkEnv* ev, mdb_token inToken,
827                                 morkStore* inStore)
828 // copy inToken from inStore over to this store
829 {
830   mork_token outToken = 0;
831   if (inStore == this)   // same store?
832     outToken = inToken;  // just return token unchanged
833   else {
834     char yarnBuf[morkStore_kMaxCopyTokenSize];
835     mdbYarn yarn;
836     yarn.mYarn_Buf = yarnBuf;
837     yarn.mYarn_Fill = 0;
838     yarn.mYarn_Size = morkStore_kMaxCopyTokenSize;
839     yarn.mYarn_More = 0;
840     yarn.mYarn_Form = 0;
841     yarn.mYarn_Grow = 0;
842 
843     inStore->TokenToString(ev, inToken, &yarn);
844     if (ev->Good()) {
845       morkBuf buf(yarn.mYarn_Buf, yarn.mYarn_Fill);
846       outToken = this->BufToToken(ev, &buf);
847     }
848   }
849   return outToken;
850 }
851 
BufToToken(morkEnv * ev,const morkBuf * inBuf)852 mork_token morkStore::BufToToken(morkEnv* ev, const morkBuf* inBuf) {
853   mork_token outToken = 0;
854   if (ev->Good()) {
855     const mork_u1* s = (const mork_u1*)inBuf->mBuf_Body;
856     mork_bool nonAscii = (*s > 0x7F);
857     mork_size length = inBuf->mBuf_Fill;
858     if (nonAscii || length > 1)  // more than one byte?
859     {
860       mork_cscode form = 0;  // default charset
861       morkAtomSpace* space = this->LazyGetGroundColumnSpace(ev);
862       if (space) {
863         morkFarBookAtom* keyAtom = 0;
864         if (length <= morkBookAtom_kMaxBodySize) {
865           mork_aid aid = 1;  // dummy
866           // mStore_BookAtom.InitMaxBookAtom(ev, *inBuf, form, space, aid);
867           mStore_FarBookAtom.InitFarBookAtom(ev, *inBuf, form, space, aid);
868           keyAtom = &mStore_FarBookAtom;
869         }
870         if (keyAtom) {
871           morkAtomBodyMap* map = &space->mAtomSpace_AtomBodies;
872           morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom);
873           if (bookAtom)
874             outToken = bookAtom->mBookAtom_Id;
875           else {
876             this->MaybeDirtyStore();
877             bookAtom = space->MakeBookAtomCopy(ev, *keyAtom);
878             if (bookAtom) {
879               outToken = bookAtom->mBookAtom_Id;
880               bookAtom->MakeCellUseForever(ev);
881             }
882           }
883         }
884       }
885     } else  // only a single byte in inTokenName string:
886       outToken = *s;
887   }
888 
889   return outToken;
890 }
891 
StringToToken(morkEnv * ev,const char * inTokenName)892 mork_token morkStore::StringToToken(morkEnv* ev, const char* inTokenName) {
893   mork_token outToken = 0;
894   if (ev->Good()) {
895     const mork_u1* s = (const mork_u1*)inTokenName;
896     mork_bool nonAscii = (*s > 0x7F);
897     if (nonAscii || (*s && s[1]))  // more than one byte?
898     {
899       mork_cscode form = 0;  // default charset
900       morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev);
901       if (groundSpace) {
902         morkFarBookAtom* keyAtom =
903             this->StageStringAsFarBookAtom(ev, inTokenName, form, groundSpace);
904         if (keyAtom) {
905           morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
906           morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom);
907           if (bookAtom)
908             outToken = bookAtom->mBookAtom_Id;
909           else {
910             this->MaybeDirtyStore();
911             bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
912             if (bookAtom) {
913               outToken = bookAtom->mBookAtom_Id;
914               bookAtom->MakeCellUseForever(ev);
915             }
916           }
917         }
918       }
919     } else  // only a single byte in inTokenName string:
920       outToken = *s;
921   }
922 
923   return outToken;
924 }
925 
QueryToken(morkEnv * ev,const char * inTokenName)926 mork_token morkStore::QueryToken(morkEnv* ev, const char* inTokenName) {
927   mork_token outToken = 0;
928   if (ev->Good()) {
929     const mork_u1* s = (const mork_u1*)inTokenName;
930     mork_bool nonAscii = (*s > 0x7F);
931     if (nonAscii || (*s && s[1]))  // more than one byte?
932     {
933       mork_cscode form = 0;  // default charset
934       morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev);
935       if (groundSpace) {
936         morkFarBookAtom* keyAtom =
937             this->StageStringAsFarBookAtom(ev, inTokenName, form, groundSpace);
938         if (keyAtom) {
939           morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
940           morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom);
941           if (bookAtom) {
942             outToken = bookAtom->mBookAtom_Id;
943             bookAtom->MakeCellUseForever(ev);
944           }
945         }
946       }
947     } else  // only a single byte in inTokenName string:
948       outToken = *s;
949   }
950 
951   return outToken;
952 }
953 
HasTableKind(morkEnv * ev,mdb_scope inRowScope,mdb_kind inTableKind,mdb_count * outTableCount)954 mork_bool morkStore::HasTableKind(morkEnv* ev, mdb_scope inRowScope,
955                                   mdb_kind inTableKind,
956                                   mdb_count* outTableCount) {
957   MORK_USED_2(inRowScope, inTableKind);
958   mork_bool outBool = morkBool_kFalse;
959   mdb_count tableCount = 0;
960 
961   ev->StubMethodOnlyError();
962 
963   if (outTableCount) *outTableCount = tableCount;
964   return outBool;
965 }
966 
GetTableKind(morkEnv * ev,mdb_scope inRowScope,mdb_kind inTableKind,mdb_count * outTableCount,mdb_bool * outMustBeUnique)967 morkTable* morkStore::GetTableKind(morkEnv* ev, mdb_scope inRowScope,
968                                    mdb_kind inTableKind,
969                                    mdb_count* outTableCount,
970                                    mdb_bool* outMustBeUnique) {
971   morkTable* outTable = 0;
972   if (ev->Good()) {
973     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope);
974     if (rowSpace) {
975       outTable = rowSpace->FindTableByKind(ev, inTableKind);
976       if (outTable) {
977         if (outTableCount) *outTableCount = outTable->GetRowCount();
978         if (outMustBeUnique) *outMustBeUnique = outTable->IsTableUnique();
979       }
980     }
981   }
982   return outTable;
983 }
984 
FindRow(morkEnv * ev,mdb_scope inScope,mdb_column inColumn,const mdbYarn * inYarn)985 morkRow* morkStore::FindRow(morkEnv* ev, mdb_scope inScope, mdb_column inColumn,
986                             const mdbYarn* inYarn) {
987   morkRow* outRow = 0;
988   if (ev->Good()) {
989     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inScope);
990     if (rowSpace) {
991       outRow = rowSpace->FindRow(ev, inColumn, inYarn);
992     }
993   }
994   return outRow;
995 }
996 
GetRow(morkEnv * ev,const mdbOid * inOid)997 morkRow* morkStore::GetRow(morkEnv* ev, const mdbOid* inOid) {
998   morkRow* outRow = 0;
999   if (ev->Good()) {
1000     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
1001     if (rowSpace) {
1002       outRow = rowSpace->mRowSpace_Rows.GetOid(ev, inOid);
1003     }
1004   }
1005   return outRow;
1006 }
1007 
GetTable(morkEnv * ev,const mdbOid * inOid)1008 morkTable* morkStore::GetTable(morkEnv* ev, const mdbOid* inOid) {
1009   morkTable* outTable = 0;
1010   if (ev->Good()) {
1011     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
1012     if (rowSpace) {
1013       outTable = rowSpace->FindTableByTid(ev, inOid->mOid_Id);
1014     }
1015   }
1016   return outTable;
1017 }
1018 
NewTable(morkEnv * ev,mdb_scope inRowScope,mdb_kind inTableKind,mdb_bool inMustBeUnique,const mdbOid * inOptionalMetaRowOid)1019 morkTable* morkStore::NewTable(
1020     morkEnv* ev, mdb_scope inRowScope, mdb_kind inTableKind,
1021     mdb_bool inMustBeUnique,
1022     const mdbOid* inOptionalMetaRowOid)  // can be nil to avoid specifying
1023 {
1024   morkTable* outTable = 0;
1025   if (ev->Good()) {
1026     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope);
1027     if (rowSpace)
1028       outTable = rowSpace->NewTable(ev, inTableKind, inMustBeUnique,
1029                                     inOptionalMetaRowOid);
1030   }
1031   return outTable;
1032 }
1033 
GetPortTableCursor(morkEnv * ev,mdb_scope inRowScope,mdb_kind inTableKind)1034 morkPortTableCursor* morkStore::GetPortTableCursor(morkEnv* ev,
1035                                                    mdb_scope inRowScope,
1036                                                    mdb_kind inTableKind) {
1037   morkPortTableCursor* outCursor = 0;
1038   if (ev->Good()) {
1039     nsIMdbHeap* heap = mPort_Heap;
1040     outCursor = new (*heap, ev) morkPortTableCursor(
1041         ev, morkUsage::kHeap, heap, this, inRowScope, inTableKind, heap);
1042   }
1043   NS_IF_ADDREF(outCursor);
1044   return outCursor;
1045 }
1046 
NewRow(morkEnv * ev,mdb_scope inRowScope)1047 morkRow* morkStore::NewRow(morkEnv* ev, mdb_scope inRowScope) {
1048   morkRow* outRow = 0;
1049   if (ev->Good()) {
1050     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope);
1051     if (rowSpace) outRow = rowSpace->NewRow(ev);
1052   }
1053   return outRow;
1054 }
1055 
NewRowWithOid(morkEnv * ev,const mdbOid * inOid)1056 morkRow* morkStore::NewRowWithOid(morkEnv* ev, const mdbOid* inOid) {
1057   morkRow* outRow = 0;
1058   if (ev->Good()) {
1059     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
1060     if (rowSpace) outRow = rowSpace->NewRowWithOid(ev, inOid);
1061   }
1062   return outRow;
1063 }
1064 
OidToRow(morkEnv * ev,const mdbOid * inOid)1065 morkRow* morkStore::OidToRow(morkEnv* ev, const mdbOid* inOid)
1066 // OidToRow() finds old row with oid, or makes new one if not found.
1067 {
1068   morkRow* outRow = 0;
1069   if (ev->Good()) {
1070     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
1071     if (rowSpace) {
1072       outRow = rowSpace->mRowSpace_Rows.GetOid(ev, inOid);
1073       if (!outRow && ev->Good()) outRow = rowSpace->NewRowWithOid(ev, inOid);
1074     }
1075   }
1076   return outRow;
1077 }
1078 
OidToTable(morkEnv * ev,const mdbOid * inOid,const mdbOid * inOptionalMetaRowOid)1079 morkTable* morkStore::OidToTable(
1080     morkEnv* ev, const mdbOid* inOid,
1081     const mdbOid* inOptionalMetaRowOid)  // can be nil to avoid specifying
1082 // OidToTable() finds old table with oid, or makes new one if not found.
1083 {
1084   morkTable* outTable = 0;
1085   if (ev->Good()) {
1086     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
1087     if (rowSpace) {
1088       outTable = rowSpace->mRowSpace_Tables.GetTable(ev, inOid->mOid_Id);
1089       if (!outTable && ev->Good()) {
1090         mork_kind tableKind = morkStore_kNoneToken;
1091         outTable = rowSpace->NewTableWithTid(ev, inOid->mOid_Id, tableKind,
1092                                              inOptionalMetaRowOid);
1093       }
1094     }
1095   }
1096   return outTable;
1097 }
1098 
1099 // { ===== begin nsIMdbObject methods =====
1100 
1101 // { ----- begin ref counting for well-behaved cyclic graphs -----
1102 NS_IMETHODIMP
GetWeakRefCount(nsIMdbEnv * mev,mdb_count * outCount)1103 morkStore::GetWeakRefCount(nsIMdbEnv* mev,  // weak refs
1104                            mdb_count* outCount) {
1105   *outCount = WeakRefsOnly();
1106   return NS_OK;
1107 }
1108 NS_IMETHODIMP
GetStrongRefCount(nsIMdbEnv * mev,mdb_count * outCount)1109 morkStore::GetStrongRefCount(nsIMdbEnv* mev,  // strong refs
1110                              mdb_count* outCount) {
1111   *outCount = StrongRefsOnly();
1112   return NS_OK;
1113 }
1114 // ### TODO - clean up this cast, if required
1115 NS_IMETHODIMP
AddWeakRef(nsIMdbEnv * mev)1116 morkStore::AddWeakRef(nsIMdbEnv* mev) {
1117   morkEnv* ev = morkEnv::FromMdbEnv(mev);
1118   // XXX Casting mork_refs to nsresult
1119   return static_cast<nsresult>(morkNode::AddWeakRef(ev));
1120 }
1121 #ifndef _MSC_VER
NS_IMETHODIMP_(mork_uses)1122 NS_IMETHODIMP_(mork_uses)
1123 morkStore::AddStrongRef(morkEnv* mev) { return AddRef(); }
1124 #endif
NS_IMETHODIMP_(mork_uses)1125 NS_IMETHODIMP_(mork_uses)
1126 morkStore::AddStrongRef(nsIMdbEnv* mev) { return AddRef(); }
1127 NS_IMETHODIMP
CutWeakRef(nsIMdbEnv * mev)1128 morkStore::CutWeakRef(nsIMdbEnv* mev) {
1129   morkEnv* ev = morkEnv::FromMdbEnv(mev);
1130   // XXX Casting mork_refs to nsresult
1131   return static_cast<nsresult>(morkNode::CutWeakRef(ev));
1132 }
1133 #ifndef _MSC_VER
NS_IMETHODIMP_(mork_uses)1134 NS_IMETHODIMP_(mork_uses)
1135 morkStore::CutStrongRef(morkEnv* mev) { return Release(); }
1136 #endif
1137 NS_IMETHODIMP
CutStrongRef(nsIMdbEnv * mev)1138 morkStore::CutStrongRef(nsIMdbEnv* mev) {
1139   // XXX Casting nsrefcnt to nsresult
1140   return static_cast<nsresult>(Release());
1141 }
1142 
1143 NS_IMETHODIMP
CloseMdbObject(nsIMdbEnv * mev)1144 morkStore::CloseMdbObject(nsIMdbEnv* mev) {
1145   morkEnv* ev = morkEnv::FromMdbEnv(mev);
1146   CloseMorkNode(ev);
1147   Release();
1148   return NS_OK;
1149 }
1150 
1151 NS_IMETHODIMP
IsOpenMdbObject(nsIMdbEnv * mev,mdb_bool * outOpen)1152 morkStore::IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen) {
1153   *outOpen = IsOpenNode();
1154   return NS_OK;
1155 }
1156 // } ----- end ref counting -----
1157 
1158 // } ===== end nsIMdbObject methods =====
1159 
1160 // { ===== begin nsIMdbPort methods =====
1161 
1162 // { ----- begin attribute methods -----
1163 NS_IMETHODIMP
GetIsPortReadonly(nsIMdbEnv * mev,mdb_bool * outBool)1164 morkStore::GetIsPortReadonly(nsIMdbEnv* mev, mdb_bool* outBool) {
1165   nsresult outErr = NS_OK;
1166   mdb_bool isReadOnly = morkBool_kFalse;
1167   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1168   if (ev) {
1169     ev->StubMethodOnlyError();
1170     outErr = ev->AsErr();
1171   }
1172   if (outBool) *outBool = isReadOnly;
1173   return outErr;
1174 }
1175 
CanUseStore(nsIMdbEnv * mev,mork_bool inMutable,nsresult * outErr) const1176 morkEnv* morkStore::CanUseStore(nsIMdbEnv* mev, mork_bool inMutable,
1177                                 nsresult* outErr) const {
1178   morkEnv* outEnv = 0;
1179   morkEnv* ev = morkEnv::FromMdbEnv(mev);
1180   if (ev) {
1181     if (IsStore())
1182       outEnv = ev;
1183     else
1184       NonStoreTypeError(ev);
1185     *outErr = ev->AsErr();
1186   }
1187   MORK_ASSERT(outEnv);
1188   return outEnv;
1189 }
1190 
1191 NS_IMETHODIMP
GetIsStore(nsIMdbEnv * mev,mdb_bool * outBool)1192 morkStore::GetIsStore(nsIMdbEnv* mev, mdb_bool* outBool) {
1193   MORK_USED_1(mev);
1194   if (outBool) *outBool = morkBool_kTrue;
1195   return NS_OK;
1196 }
1197 
1198 NS_IMETHODIMP
GetIsStoreAndDirty(nsIMdbEnv * mev,mdb_bool * outBool)1199 morkStore::GetIsStoreAndDirty(nsIMdbEnv* mev, mdb_bool* outBool) {
1200   nsresult outErr = NS_OK;
1201   mdb_bool isStoreAndDirty = morkBool_kFalse;
1202   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1203   if (ev) {
1204     ev->StubMethodOnlyError();
1205     outErr = ev->AsErr();
1206   }
1207   if (outBool) *outBool = isStoreAndDirty;
1208   return outErr;
1209 }
1210 
1211 NS_IMETHODIMP
GetUsagePolicy(nsIMdbEnv * mev,mdbUsagePolicy * ioUsagePolicy)1212 morkStore::GetUsagePolicy(nsIMdbEnv* mev, mdbUsagePolicy* ioUsagePolicy) {
1213   MORK_USED_1(ioUsagePolicy);
1214   nsresult outErr = NS_OK;
1215   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1216   if (ev) {
1217     ev->StubMethodOnlyError();
1218     outErr = ev->AsErr();
1219   }
1220   return outErr;
1221 }
1222 
1223 NS_IMETHODIMP
SetUsagePolicy(nsIMdbEnv * mev,const mdbUsagePolicy * inUsagePolicy)1224 morkStore::SetUsagePolicy(nsIMdbEnv* mev, const mdbUsagePolicy* inUsagePolicy) {
1225   MORK_USED_1(inUsagePolicy);
1226   nsresult outErr = NS_OK;
1227   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1228   if (ev) {
1229     // ev->StubMethodOnlyError(); // okay to do nothing?
1230     outErr = ev->AsErr();
1231   }
1232   return outErr;
1233 }
1234 // } ----- end attribute methods -----
1235 
1236 // { ----- begin memory policy methods -----
1237 NS_IMETHODIMP
IdleMemoryPurge(nsIMdbEnv * mev,mdb_size * outEstimatedBytesFreed)1238 morkStore::IdleMemoryPurge(            // do memory management already scheduled
1239     nsIMdbEnv* mev,                    // context
1240     mdb_size* outEstimatedBytesFreed)  // approximate bytes actually freed
1241 {
1242   nsresult outErr = NS_OK;
1243   mdb_size estimatedBytesFreed = 0;
1244   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1245   if (ev) {
1246     // ev->StubMethodOnlyError(); // okay to do nothing?
1247     outErr = ev->AsErr();
1248   }
1249   if (outEstimatedBytesFreed) *outEstimatedBytesFreed = estimatedBytesFreed;
1250   return outErr;
1251 }
1252 
1253 NS_IMETHODIMP
SessionMemoryPurge(nsIMdbEnv * mev,mdb_size inDesiredBytesFreed,mdb_size * outEstimatedBytesFreed)1254 morkStore::SessionMemoryPurge(         // request specific footprint decrease
1255     nsIMdbEnv* mev,                    // context
1256     mdb_size inDesiredBytesFreed,      // approximate number of bytes wanted
1257     mdb_size* outEstimatedBytesFreed)  // approximate bytes actually freed
1258 {
1259   MORK_USED_1(inDesiredBytesFreed);
1260   nsresult outErr = NS_OK;
1261   mdb_size estimate = 0;
1262   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1263   if (ev) {
1264     // ev->StubMethodOnlyError(); // okay to do nothing?
1265     outErr = ev->AsErr();
1266   }
1267   if (outEstimatedBytesFreed) *outEstimatedBytesFreed = estimate;
1268   return outErr;
1269 }
1270 
1271 NS_IMETHODIMP
PanicMemoryPurge(nsIMdbEnv * mev,mdb_size * outEstimatedBytesFreed)1272 morkStore::PanicMemoryPurge(           // desperately free all possible memory
1273     nsIMdbEnv* mev,                    // context
1274     mdb_size* outEstimatedBytesFreed)  // approximate bytes actually freed
1275 {
1276   nsresult outErr = NS_OK;
1277   mdb_size estimate = 0;
1278   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1279   if (ev) {
1280     // ev->StubMethodOnlyError(); // okay to do nothing?
1281     outErr = ev->AsErr();
1282   }
1283   if (outEstimatedBytesFreed) *outEstimatedBytesFreed = estimate;
1284   return outErr;
1285 }
1286 // } ----- end memory policy methods -----
1287 
1288 // { ----- begin filepath methods -----
1289 NS_IMETHODIMP
GetPortFilePath(nsIMdbEnv * mev,mdbYarn * outFilePath,mdbYarn * outFormatVersion)1290 morkStore::GetPortFilePath(
1291     nsIMdbEnv* mev,             // context
1292     mdbYarn* outFilePath,       // name of file holding port content
1293     mdbYarn* outFormatVersion)  // file format description
1294 {
1295   nsresult outErr = NS_OK;
1296   if (outFormatVersion) outFormatVersion->mYarn_Fill = 0;
1297   if (outFilePath) outFilePath->mYarn_Fill = 0;
1298   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1299   if (ev) {
1300     if (mStore_File)
1301       mStore_File->Path(mev, outFilePath);
1302     else
1303       NilStoreFileError(ev);
1304 
1305     outErr = ev->AsErr();
1306   }
1307   return outErr;
1308 }
1309 
1310 NS_IMETHODIMP
GetPortFile(nsIMdbEnv * mev,nsIMdbFile ** acqFile)1311 morkStore::GetPortFile(
1312     nsIMdbEnv* mev,        // context
1313     nsIMdbFile** acqFile)  // acquire file used by port or store
1314 {
1315   nsresult outErr = NS_OK;
1316   if (acqFile) *acqFile = 0;
1317 
1318   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1319   if (ev) {
1320     if (mStore_File) {
1321       if (acqFile) {
1322         mStore_File->AddRef();
1323         if (ev->Good()) *acqFile = mStore_File;
1324       }
1325     } else
1326       NilStoreFileError(ev);
1327 
1328     outErr = ev->AsErr();
1329   }
1330   return outErr;
1331 }
1332 // } ----- end filepath methods -----
1333 
1334 // { ----- begin export methods -----
1335 NS_IMETHODIMP
BestExportFormat(nsIMdbEnv * mev,mdbYarn * outFormatVersion)1336 morkStore::BestExportFormat(    // determine preferred export format
1337     nsIMdbEnv* mev,             // context
1338     mdbYarn* outFormatVersion)  // file format description
1339 {
1340   nsresult outErr = NS_OK;
1341   if (outFormatVersion) outFormatVersion->mYarn_Fill = 0;
1342   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1343   if (ev) {
1344     ev->StubMethodOnlyError();
1345     outErr = ev->AsErr();
1346   }
1347   return outErr;
1348 }
1349 
1350 NS_IMETHODIMP
CanExportToFormat(nsIMdbEnv * mev,const char * inFormatVersion,mdb_bool * outCanExport)1351 morkStore::CanExportToFormat(  // can export content in given specific format?
1352     nsIMdbEnv* mev,            // context
1353     const char* inFormatVersion,  // file format description
1354     mdb_bool* outCanExport)       // whether ExportSource() might succeed
1355 {
1356   MORK_USED_1(inFormatVersion);
1357   mdb_bool canExport = morkBool_kFalse;
1358   nsresult outErr = NS_OK;
1359   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1360   if (ev) {
1361     ev->StubMethodOnlyError();
1362     outErr = ev->AsErr();
1363   }
1364   if (outCanExport) *outCanExport = canExport;
1365   return outErr;
1366 }
1367 
1368 NS_IMETHODIMP
ExportToFormat(nsIMdbEnv * mev,nsIMdbFile * ioFile,const char * inFormatVersion,nsIMdbThumb ** acqThumb)1369 morkStore::ExportToFormat(  // export content in given specific format
1370     nsIMdbEnv* mev,         // context
1371     // const char* inFilePath, // the file to receive exported content
1372     nsIMdbFile* ioFile,           // destination abstract file interface
1373     const char* inFormatVersion,  // file format description
1374     nsIMdbThumb** acqThumb)       // acquire thumb for incremental export
1375 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1376 // then the export will be finished.
1377 {
1378   nsresult outErr = NS_OK;
1379   nsIMdbThumb* outThumb = 0;
1380   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1381   if (ev) {
1382     if (ioFile && inFormatVersion && acqThumb) {
1383       ev->StubMethodOnlyError();
1384     } else
1385       ev->NilPointerError();
1386 
1387     outErr = ev->AsErr();
1388   }
1389   if (acqThumb) *acqThumb = outThumb;
1390   return outErr;
1391 }
1392 
1393 // } ----- end export methods -----
1394 
1395 // { ----- begin token methods -----
1396 NS_IMETHODIMP
TokenToString(nsIMdbEnv * mev,mdb_token inToken,mdbYarn * outTokenName)1397 morkStore::TokenToString(   // return a string name for an integer token
1398     nsIMdbEnv* mev,         // context
1399     mdb_token inToken,      // token for inTokenName inside this port
1400     mdbYarn* outTokenName)  // the type of table to access
1401 {
1402   nsresult outErr = NS_OK;
1403   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1404   if (ev) {
1405     TokenToString(ev, inToken, outTokenName);
1406     outErr = ev->AsErr();
1407   }
1408   return outErr;
1409 }
1410 
1411 NS_IMETHODIMP
StringToToken(nsIMdbEnv * mev,const char * inTokenName,mdb_token * outToken)1412 morkStore::StringToToken(     // return an integer token for scope name
1413     nsIMdbEnv* mev,           // context
1414     const char* inTokenName,  // Latin1 string to tokenize if possible
1415     mdb_token* outToken)      // token for inTokenName inside this port
1416 // String token zero is never used and never supported. If the port
1417 // is a mutable store, then StringToToken() to create a new
1418 // association of inTokenName with a new integer token if possible.
1419 // But a readonly port will return zero for an unknown scope name.
1420 {
1421   nsresult outErr = NS_OK;
1422   mdb_token token = 0;
1423   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1424   if (ev) {
1425     token = StringToToken(ev, inTokenName);
1426     outErr = ev->AsErr();
1427   }
1428   if (outToken) *outToken = token;
1429   return outErr;
1430 }
1431 
1432 NS_IMETHODIMP
QueryToken(nsIMdbEnv * mev,const char * inTokenName,mdb_token * outToken)1433 morkStore::QueryToken(        // like StringToToken(), but without adding
1434     nsIMdbEnv* mev,           // context
1435     const char* inTokenName,  // Latin1 string to tokenize if possible
1436     mdb_token* outToken)      // token for inTokenName inside this port
1437 // QueryToken() will return a string token if one already exists,
1438 // but unlike StringToToken(), will not assign a new token if not
1439 // already in use.
1440 {
1441   nsresult outErr = NS_OK;
1442   mdb_token token = 0;
1443   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1444   if (ev) {
1445     token = QueryToken(ev, inTokenName);
1446     outErr = ev->AsErr();
1447   }
1448   if (outToken) *outToken = token;
1449   return outErr;
1450 }
1451 
1452 // } ----- end token methods -----
1453 
1454 // { ----- begin row methods -----
1455 NS_IMETHODIMP
HasRow(nsIMdbEnv * mev,const mdbOid * inOid,mdb_bool * outHasRow)1456 morkStore::HasRow(        // contains a row with the specified oid?
1457     nsIMdbEnv* mev,       // context
1458     const mdbOid* inOid,  // hypothetical row oid
1459     mdb_bool* outHasRow)  // whether GetRow() might succeed
1460 {
1461   nsresult outErr = NS_OK;
1462   mdb_bool hasRow = morkBool_kFalse;
1463   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1464   if (ev) {
1465     morkRow* row = GetRow(ev, inOid);
1466     if (row) hasRow = morkBool_kTrue;
1467 
1468     outErr = ev->AsErr();
1469   }
1470   if (outHasRow) *outHasRow = hasRow;
1471   return outErr;
1472 }
1473 
1474 NS_IMETHODIMP
GetRow(nsIMdbEnv * mev,const mdbOid * inOid,nsIMdbRow ** acqRow)1475 morkStore::GetRow(        // access one row with specific oid
1476     nsIMdbEnv* mev,       // context
1477     const mdbOid* inOid,  // hypothetical row oid
1478     nsIMdbRow** acqRow)   // acquire specific row (or null)
1479 {
1480   nsresult outErr = NS_OK;
1481   nsIMdbRow* outRow = 0;
1482   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1483   if (ev) {
1484     morkRow* row = GetRow(ev, inOid);
1485     if (row && ev->Good()) outRow = row->AcquireRowHandle(ev, this);
1486 
1487     outErr = ev->AsErr();
1488   }
1489   if (acqRow) *acqRow = outRow;
1490   return outErr;
1491 }
1492 
1493 NS_IMETHODIMP
GetRowRefCount(nsIMdbEnv * mev,const mdbOid * inOid,mdb_count * outRefCount)1494 morkStore::GetRowRefCount(   // get number of tables that contain a row
1495     nsIMdbEnv* mev,          // context
1496     const mdbOid* inOid,     // hypothetical row oid
1497     mdb_count* outRefCount)  // number of tables containing inRowKey
1498 {
1499   nsresult outErr = NS_OK;
1500   mdb_count count = 0;
1501   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1502   if (ev) {
1503     morkRow* row = GetRow(ev, inOid);
1504     if (row && ev->Good()) count = row->mRow_GcUses;
1505 
1506     outErr = ev->AsErr();
1507   }
1508   if (outRefCount) *outRefCount = count;
1509   return outErr;
1510 }
1511 
1512 NS_IMETHODIMP
FindRow(nsIMdbEnv * mev,mdb_scope inRowScope,mdb_column inColumn,const mdbYarn * inTargetCellValue,mdbOid * outRowOid,nsIMdbRow ** acqRow)1513 morkStore::FindRow(
1514     nsIMdbEnv* mev,        // search for row with matching cell
1515     mdb_scope inRowScope,  // row scope for row ids
1516     mdb_column inColumn,   // the column to search (and maintain an index)
1517     const mdbYarn* inTargetCellValue,  // cell value for which to search
1518     mdbOid* outRowOid,   // out row oid on match (or {0,-1} for no match)
1519     nsIMdbRow** acqRow)  // acquire matching row (or nil for no match)
1520 // FindRow() searches for one row that has a cell in column inColumn with
1521 // a contained value with the same form (i.e. charset) and is byte-wise
1522 // identical to the blob described by yarn inTargetCellValue.  Both content
1523 // and form of the yarn must be an exact match to find a matching row.
1524 //
1525 // (In other words, both a yarn's blob bytes and form are significant.  The
1526 // form is not expected to vary in columns used for identity anyway.  This
1527 // is intended to make the cost of FindRow() cheaper for MDB implementors,
1528 // since any cell value atomization performed internally must necessarily
1529 // make yarn form significant in order to avoid data loss in atomization.)
1530 //
1531 // FindRow() can lazily create an index on attribute inColumn for all rows
1532 // with that attribute in row space scope inRowScope, so that subsequent
1533 // calls to FindRow() will perform faster.  Such an index might or might
1534 // not be persistent (but this seems desirable if it is cheap to do so).
1535 // Note that lazy index creation in readonly DBs is not very feasible.
1536 //
1537 // This FindRow() interface assumes that attribute inColumn is effectively
1538 // an alternative means of unique identification for a row in a rowspace,
1539 // so correct behavior is only guaranteed when no duplicates for this col
1540 // appear in the given set of rows.  (If more than one row has the same cell
1541 // value in this column, no more than one will be found; and cutting one of
1542 // two duplicate rows can cause the index to assume no other such row lives
1543 // in the row space, so future calls return nil for negative search results
1544 // even though some duplicate row might still live within the rowspace.)
1545 //
1546 // In other words, the FindRow() implementation is allowed to assume simple
1547 // hash tables mapping unique column keys to associated row values will be
1548 // sufficient, where any duplication is not recorded because only one copy
1549 // of a given key need be remembered.  Implementors are not required to sort
1550 // all rows by the specified column.
1551 {
1552   nsresult outErr = NS_OK;
1553   nsIMdbRow* outRow = 0;
1554   mdbOid rowOid;
1555   rowOid.mOid_Scope = 0;
1556   rowOid.mOid_Id = (mdb_id)-1;
1557 
1558   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1559   if (ev) {
1560     morkRow* row = FindRow(ev, inRowScope, inColumn, inTargetCellValue);
1561     if (row && ev->Good()) {
1562       rowOid = row->mRow_Oid;
1563       if (acqRow) outRow = row->AcquireRowHandle(ev, this);
1564     }
1565     outErr = ev->AsErr();
1566   }
1567   if (acqRow) *acqRow = outRow;
1568   if (outRowOid) *outRowOid = rowOid;
1569 
1570   return outErr;
1571 }
1572 
1573 // } ----- end row methods -----
1574 
1575 // { ----- begin table methods -----
1576 NS_IMETHODIMP
HasTable(nsIMdbEnv * mev,const mdbOid * inOid,mdb_bool * outHasTable)1577 morkStore::HasTable(        // supports a table with the specified oid?
1578     nsIMdbEnv* mev,         // context
1579     const mdbOid* inOid,    // hypothetical table oid
1580     mdb_bool* outHasTable)  // whether GetTable() might succeed
1581 {
1582   nsresult outErr = NS_OK;
1583   mork_bool hasTable = morkBool_kFalse;
1584   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1585   if (ev) {
1586     morkTable* table = GetTable(ev, inOid);
1587     if (table) hasTable = morkBool_kTrue;
1588 
1589     outErr = ev->AsErr();
1590   }
1591   if (outHasTable) *outHasTable = hasTable;
1592   return outErr;
1593 }
1594 
1595 NS_IMETHODIMP
GetTable(nsIMdbEnv * mev,const mdbOid * inOid,nsIMdbTable ** acqTable)1596 morkStore::GetTable(         // access one table with specific oid
1597     nsIMdbEnv* mev,          // context
1598     const mdbOid* inOid,     // hypothetical table oid
1599     nsIMdbTable** acqTable)  // acquire specific table (or null)
1600 {
1601   nsresult outErr = NS_OK;
1602   nsIMdbTable* outTable = 0;
1603   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1604   if (ev) {
1605     morkTable* table = GetTable(ev, inOid);
1606     if (table && ev->Good()) outTable = table->AcquireTableHandle(ev);
1607     outErr = ev->AsErr();
1608   }
1609   if (acqTable) *acqTable = outTable;
1610   return outErr;
1611 }
1612 
1613 NS_IMETHODIMP
HasTableKind(nsIMdbEnv * mev,mdb_scope inRowScope,mdb_kind inTableKind,mdb_count * outTableCount,mdb_bool * outSupportsTable)1614 morkStore::HasTableKind(         // supports a table of the specified type?
1615     nsIMdbEnv* mev,              // context
1616     mdb_scope inRowScope,        // rid scope for row ids
1617     mdb_kind inTableKind,        // the type of table to access
1618     mdb_count* outTableCount,    // current number of such tables
1619     mdb_bool* outSupportsTable)  // whether GetTableKind() might succeed
1620 {
1621   nsresult outErr = NS_OK;
1622   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1623   if (ev) {
1624     *outSupportsTable =
1625         HasTableKind(ev, inRowScope, inTableKind, outTableCount);
1626     outErr = ev->AsErr();
1627   }
1628   return outErr;
1629 }
1630 
1631 NS_IMETHODIMP
GetTableKind(nsIMdbEnv * mev,mdb_scope inRowScope,mdb_kind inTableKind,mdb_count * outTableCount,mdb_bool * outMustBeUnique,nsIMdbTable ** acqTable)1632 morkStore::GetTableKind(        // access one (random) table of specific type
1633     nsIMdbEnv* mev,             // context
1634     mdb_scope inRowScope,       // row scope for row ids
1635     mdb_kind inTableKind,       // the type of table to access
1636     mdb_count* outTableCount,   // current number of such tables
1637     mdb_bool* outMustBeUnique,  // whether port can hold only one of these
1638     nsIMdbTable** acqTable)     // acquire scoped collection of rows
1639 {
1640   nsresult outErr = NS_OK;
1641   nsIMdbTable* outTable = 0;
1642   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1643   if (ev) {
1644     morkTable* table = GetTableKind(ev, inRowScope, inTableKind, outTableCount,
1645                                     outMustBeUnique);
1646     if (table && ev->Good()) outTable = table->AcquireTableHandle(ev);
1647     outErr = ev->AsErr();
1648   }
1649   if (acqTable) *acqTable = outTable;
1650   return outErr;
1651 }
1652 
1653 NS_IMETHODIMP
GetPortTableCursor(nsIMdbEnv * mev,mdb_scope inRowScope,mdb_kind inTableKind,nsIMdbPortTableCursor ** acqCursor)1654 morkStore::GetPortTableCursor(  // get cursor for all tables of specific type
1655     nsIMdbEnv* mev,             // context
1656     mdb_scope inRowScope,       // row scope for row ids
1657     mdb_kind inTableKind,       // the type of table to access
1658     nsIMdbPortTableCursor** acqCursor)  // all such tables in the port
1659 {
1660   nsresult outErr = NS_OK;
1661   nsIMdbPortTableCursor* outCursor = 0;
1662   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1663   if (ev) {
1664     morkPortTableCursor* cursor =
1665         GetPortTableCursor(ev, inRowScope, inTableKind);
1666     if (cursor && ev->Good()) outCursor = cursor;
1667 
1668     outErr = ev->AsErr();
1669   }
1670   if (acqCursor) *acqCursor = outCursor;
1671   return outErr;
1672 }
1673 // } ----- end table methods -----
1674 
1675 // { ----- begin commit methods -----
1676 
1677 NS_IMETHODIMP
ShouldCompress(nsIMdbEnv * mev,mdb_percent inPercentWaste,mdb_percent * outActualWaste,mdb_bool * outShould)1678 morkStore::ShouldCompress(        // store wastes at least inPercentWaste?
1679     nsIMdbEnv* mev,               // context
1680     mdb_percent inPercentWaste,   // 0..100 percent file size waste threshold
1681     mdb_percent* outActualWaste,  // 0..100 percent of file actually wasted
1682     mdb_bool* outShould)          // true when about inPercentWaste% is wasted
1683 {
1684   mdb_percent actualWaste = 0;
1685   mdb_bool shouldCompress = morkBool_kFalse;
1686   nsresult outErr = NS_OK;
1687   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1688   if (ev) {
1689     actualWaste = PercentOfStoreWasted(ev);
1690     if (inPercentWaste > 100) inPercentWaste = 100;
1691     shouldCompress = (actualWaste >= inPercentWaste);
1692     outErr = ev->AsErr();
1693   }
1694   if (outActualWaste) *outActualWaste = actualWaste;
1695   if (outShould) *outShould = shouldCompress;
1696   return outErr;
1697 }
1698 
1699 // } ===== end nsIMdbPort methods =====
1700 
1701 NS_IMETHODIMP
NewTable(nsIMdbEnv * mev,mdb_scope inRowScope,mdb_kind inTableKind,mdb_bool inMustBeUnique,const mdbOid * inOptionalMetaRowOid,nsIMdbTable ** acqTable)1702 morkStore::NewTable(          // make one new table of specific type
1703     nsIMdbEnv* mev,           // context
1704     mdb_scope inRowScope,     // row scope for row ids
1705     mdb_kind inTableKind,     // the type of table to access
1706     mdb_bool inMustBeUnique,  // whether store can hold only one of these
1707     const mdbOid* inOptionalMetaRowOid,  // can be nil to avoid specifying
1708     nsIMdbTable** acqTable)              // acquire scoped collection of rows
1709 {
1710   nsresult outErr = NS_OK;
1711   nsIMdbTable* outTable = 0;
1712   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1713   if (ev) {
1714     morkTable* table = NewTable(ev, inRowScope, inTableKind, inMustBeUnique,
1715                                 inOptionalMetaRowOid);
1716     if (table && ev->Good()) outTable = table->AcquireTableHandle(ev);
1717     outErr = ev->AsErr();
1718   }
1719   if (acqTable) *acqTable = outTable;
1720   return outErr;
1721 }
1722 
1723 NS_IMETHODIMP
NewTableWithOid(nsIMdbEnv * mev,const mdbOid * inOid,mdb_kind inTableKind,mdb_bool inMustBeUnique,const mdbOid * inOptionalMetaRowOid,nsIMdbTable ** acqTable)1724 morkStore::NewTableWithOid(   // make one new table of specific type
1725     nsIMdbEnv* mev,           // context
1726     const mdbOid* inOid,      // caller assigned oid
1727     mdb_kind inTableKind,     // the type of table to access
1728     mdb_bool inMustBeUnique,  // whether store can hold only one of these
1729     const mdbOid* inOptionalMetaRowOid,  // can be nil to avoid specifying
1730     nsIMdbTable** acqTable)              // acquire scoped collection of rows
1731 {
1732   nsresult outErr = NS_OK;
1733   nsIMdbTable* outTable = 0;
1734   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1735   if (ev) {
1736     morkTable* table = OidToTable(ev, inOid, inOptionalMetaRowOid);
1737     if (table && ev->Good()) {
1738       table->mTable_Kind = inTableKind;
1739       if (inMustBeUnique) table->SetTableUnique();
1740       outTable = table->AcquireTableHandle(ev);
1741     }
1742     outErr = ev->AsErr();
1743   }
1744   if (acqTable) *acqTable = outTable;
1745   return outErr;
1746 }
1747 // } ----- end table methods -----
1748 
1749 // { ----- begin row scope methods -----
1750 NS_IMETHODIMP
RowScopeHasAssignedIds(nsIMdbEnv * mev,mdb_scope inRowScope,mdb_bool * outCallerAssigned,mdb_bool * outStoreAssigned)1751 morkStore::RowScopeHasAssignedIds(
1752     nsIMdbEnv* mev,
1753     mdb_scope inRowScope,         // row scope for row ids
1754     mdb_bool* outCallerAssigned,  // nonzero if caller assigned specified
1755     mdb_bool* outStoreAssigned)   // nonzero if store db assigned specified
1756 {
1757   NS_ASSERTION(false, " not implemented");
1758   return NS_ERROR_NOT_IMPLEMENTED;
1759 }
1760 
1761 NS_IMETHODIMP
SetCallerAssignedIds(nsIMdbEnv * mev,mdb_scope inRowScope,mdb_bool * outCallerAssigned,mdb_bool * outStoreAssigned)1762 morkStore::SetCallerAssignedIds(
1763     nsIMdbEnv* mev,
1764     mdb_scope inRowScope,         // row scope for row ids
1765     mdb_bool* outCallerAssigned,  // nonzero if caller assigned specified
1766     mdb_bool* outStoreAssigned)   // nonzero if store db assigned specified
1767 {
1768   NS_ASSERTION(false, " not implemented");
1769   return NS_ERROR_NOT_IMPLEMENTED;
1770 }
1771 
1772 NS_IMETHODIMP
SetStoreAssignedIds(nsIMdbEnv * mev,mdb_scope inRowScope,mdb_bool * outCallerAssigned,mdb_bool * outStoreAssigned)1773 morkStore::SetStoreAssignedIds(
1774     nsIMdbEnv* mev,
1775     mdb_scope inRowScope,         // row scope for row ids
1776     mdb_bool* outCallerAssigned,  // nonzero if caller assigned specified
1777     mdb_bool* outStoreAssigned)   // nonzero if store db assigned specified
1778 {
1779   NS_ASSERTION(false, " not implemented");
1780   return NS_ERROR_NOT_IMPLEMENTED;
1781 }
1782 // } ----- end row scope methods -----
1783 
1784 // { ----- begin row methods -----
1785 NS_IMETHODIMP
NewRowWithOid(nsIMdbEnv * mev,const mdbOid * inOid,nsIMdbRow ** acqRow)1786 morkStore::NewRowWithOid(nsIMdbEnv* mev,       // new row w/ caller assigned oid
1787                          const mdbOid* inOid,  // caller assigned oid
1788                          nsIMdbRow** acqRow)   // create new row
1789 {
1790   nsresult outErr = NS_OK;
1791   nsIMdbRow* outRow = 0;
1792   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1793   if (ev) {
1794     morkRow* row = NewRowWithOid(ev, inOid);
1795     if (row && ev->Good()) outRow = row->AcquireRowHandle(ev, this);
1796 
1797     outErr = ev->AsErr();
1798   }
1799   if (acqRow) *acqRow = outRow;
1800   return outErr;
1801 }
1802 
1803 NS_IMETHODIMP
NewRow(nsIMdbEnv * mev,mdb_scope inRowScope,nsIMdbRow ** acqRow)1804 morkStore::NewRow(nsIMdbEnv* mev,        // new row with db assigned oid
1805                   mdb_scope inRowScope,  // row scope for row ids
1806                   nsIMdbRow** acqRow)    // create new row
1807 // Note this row must be added to some table or cell child before the
1808 // store is closed in order to make this row persist across sessions.
1809 {
1810   nsresult outErr = NS_OK;
1811   nsIMdbRow* outRow = 0;
1812   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1813   if (ev) {
1814     morkRow* row = NewRow(ev, inRowScope);
1815     if (row && ev->Good()) outRow = row->AcquireRowHandle(ev, this);
1816 
1817     outErr = ev->AsErr();
1818   }
1819   if (acqRow) *acqRow = outRow;
1820   return outErr;
1821 }
1822 // } ----- end row methods -----
1823 
1824 // { ----- begin import/export methods -----
1825 NS_IMETHODIMP
ImportContent(nsIMdbEnv * mev,mdb_scope inRowScope,nsIMdbPort * ioPort,nsIMdbThumb ** acqThumb)1826 morkStore::ImportContent(    // import content from port
1827     nsIMdbEnv* mev,          // context
1828     mdb_scope inRowScope,    // scope for rows (or zero for all?)
1829     nsIMdbPort* ioPort,      // the port with content to add to store
1830     nsIMdbThumb** acqThumb)  // acquire thumb for incremental import
1831 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1832 // then the import will be finished.
1833 {
1834   NS_ASSERTION(false, " not implemented");
1835   return NS_ERROR_NOT_IMPLEMENTED;
1836 }
1837 
1838 NS_IMETHODIMP
ImportFile(nsIMdbEnv * mev,nsIMdbFile * ioFile,nsIMdbThumb ** acqThumb)1839 morkStore::ImportFile(       // import content from port
1840     nsIMdbEnv* mev,          // context
1841     nsIMdbFile* ioFile,      // the file with content to add to store
1842     nsIMdbThumb** acqThumb)  // acquire thumb for incremental import
1843 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1844 // then the import will be finished.
1845 {
1846   NS_ASSERTION(false, " not implemented");
1847   return NS_ERROR_NOT_IMPLEMENTED;
1848 }
1849 // } ----- end import/export methods -----
1850 
1851 // { ----- begin hinting methods -----
1852 NS_IMETHODIMP
ShareAtomColumnsHint(nsIMdbEnv * mev,mdb_scope inScopeHint,const mdbColumnSet * inColumnSet)1853 morkStore::ShareAtomColumnsHint(      // advise re shared col content atomizing
1854     nsIMdbEnv* mev,                   // context
1855     mdb_scope inScopeHint,            // zero, or suggested shared namespace
1856     const mdbColumnSet* inColumnSet)  // cols desired tokenized together
1857 {
1858   MORK_USED_2(inColumnSet, inScopeHint);
1859   nsresult outErr = NS_OK;
1860   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1861   if (ev) {
1862     // ev->StubMethodOnlyError(); // okay to do nothing for a hint method
1863     outErr = ev->AsErr();
1864   }
1865   return outErr;
1866 }
1867 
1868 NS_IMETHODIMP
AvoidAtomColumnsHint(nsIMdbEnv * mev,const mdbColumnSet * inColumnSet)1869 morkStore::AvoidAtomColumnsHint(      // advise col w/ poor atomizing prospects
1870     nsIMdbEnv* mev,                   // context
1871     const mdbColumnSet* inColumnSet)  // cols with poor atomizing prospects
1872 {
1873   MORK_USED_1(inColumnSet);
1874   nsresult outErr = NS_OK;
1875   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1876   if (ev) {
1877     // ev->StubMethodOnlyError(); // okay to do nothing for a hint method
1878     outErr = ev->AsErr();
1879   }
1880   return outErr;
1881 }
1882 // } ----- end hinting methods -----
1883 
1884 // { ----- begin commit methods -----
1885 NS_IMETHODIMP
LargeCommit(nsIMdbEnv * mev,nsIMdbThumb ** acqThumb)1886 morkStore::LargeCommit(      // save important changes if at all possible
1887     nsIMdbEnv* mev,          // context
1888     nsIMdbThumb** acqThumb)  // acquire thumb for incremental commit
1889 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1890 // then the commit will be finished.  Note the store is effectively write
1891 // locked until commit is finished or canceled through the thumb instance.
1892 // Until the commit is done, the store will report it has readonly status.
1893 {
1894   nsresult outErr = NS_OK;
1895   nsIMdbThumb* outThumb = 0;
1896   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1897   if (ev) {
1898     morkThumb* thumb = 0;
1899     // morkFile* file = store->mStore_File;
1900     if (DoPreferLargeOverCompressCommit(ev)) {
1901       thumb = morkThumb::Make_LargeCommit(ev, mPort_Heap, this);
1902     } else {
1903       mork_bool doCollect = morkBool_kFalse;
1904       thumb = morkThumb::Make_CompressCommit(ev, mPort_Heap, this, doCollect);
1905     }
1906 
1907     if (thumb) {
1908       outThumb = thumb;
1909       thumb->AddRef();
1910     }
1911 
1912     outErr = ev->AsErr();
1913   }
1914   if (acqThumb) *acqThumb = outThumb;
1915   return outErr;
1916 }
1917 
1918 NS_IMETHODIMP
SessionCommit(nsIMdbEnv * mev,nsIMdbThumb ** acqThumb)1919 morkStore::SessionCommit(    // save all changes if large commits delayed
1920     nsIMdbEnv* mev,          // context
1921     nsIMdbThumb** acqThumb)  // acquire thumb for incremental commit
1922 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1923 // then the commit will be finished.  Note the store is effectively write
1924 // locked until commit is finished or canceled through the thumb instance.
1925 // Until the commit is done, the store will report it has readonly status.
1926 {
1927   nsresult outErr = NS_OK;
1928   nsIMdbThumb* outThumb = 0;
1929   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1930   if (ev) {
1931     morkThumb* thumb = 0;
1932     if (DoPreferLargeOverCompressCommit(ev)) {
1933       thumb = morkThumb::Make_LargeCommit(ev, mPort_Heap, this);
1934     } else {
1935       mork_bool doCollect = morkBool_kFalse;
1936       thumb = morkThumb::Make_CompressCommit(ev, mPort_Heap, this, doCollect);
1937     }
1938 
1939     if (thumb) {
1940       outThumb = thumb;
1941       thumb->AddRef();
1942     }
1943     outErr = ev->AsErr();
1944   }
1945   if (acqThumb) *acqThumb = outThumb;
1946   return outErr;
1947 }
1948 
1949 NS_IMETHODIMP
CompressCommit(nsIMdbEnv * mev,nsIMdbThumb ** acqThumb)1950 morkStore::CompressCommit(   // commit and make db smaller if possible
1951     nsIMdbEnv* mev,          // context
1952     nsIMdbThumb** acqThumb)  // acquire thumb for incremental commit
1953 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1954 // then the commit will be finished.  Note the store is effectively write
1955 // locked until commit is finished or canceled through the thumb instance.
1956 // Until the commit is done, the store will report it has readonly status.
1957 {
1958   nsresult outErr = NS_OK;
1959   nsIMdbThumb* outThumb = 0;
1960   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
1961   if (ev) {
1962     mork_bool doCollect = morkBool_kFalse;
1963     morkThumb* thumb =
1964         morkThumb::Make_CompressCommit(ev, mPort_Heap, this, doCollect);
1965     if (thumb) {
1966       outThumb = thumb;
1967       thumb->AddRef();
1968       mStore_CanWriteIncremental = morkBool_kTrue;
1969     }
1970 
1971     outErr = ev->AsErr();
1972   }
1973   if (acqThumb) *acqThumb = outThumb;
1974   return outErr;
1975 }
1976 
1977 // } ----- end commit methods -----
1978 
1979 // } ===== end nsIMdbStore methods =====
1980 
1981 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
1982