1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-  */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is mozilla.org code.
16  *
17  * The Initial Developer of the Original Code is
18  * Netscape Communications Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 1999
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *   Blake Ross (blake@blakeross.com)
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either of the GNU General Public License Version 2 or later (the "GPL"),
27  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  *
37  * ***** END LICENSE BLOCK ***** */
38 
39 #ifndef _MDB_
40 #define _MDB_ 1
41 
42 #include "mozilla/Path.h"
43 #include "nscore.h"
44 #include "nsISupports.h"
45 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
46 
47 // { %%%%% begin scalar typedefs %%%%%
48 typedef unsigned char mdb_u1;   // make sure this is one byte
49 typedef unsigned short mdb_u2;  // make sure this is two bytes
50 typedef short mdb_i2;           // make sure this is two bytes
51 typedef uint32_t mdb_u4;        // make sure this is four bytes
52 typedef int32_t mdb_i4;         // make sure this is four bytes
53 typedef PRWord mdb_ip;          // make sure sizeof(mdb_ip) == sizeof(void*)
54 
55 typedef mdb_u1 mdb_bool;  // unsigned byte with zero=false, nonzero=true
56 
57 /* canonical boolean constants provided only for code clarity: */
58 #define mdbBool_kTrue ((mdb_bool)1)  /* actually any nonzero means true */
59 #define mdbBool_kFalse ((mdb_bool)0) /* only zero means false */
60 
61 typedef mdb_u4 mdb_id;         // unsigned object identity in a scope
62 typedef mdb_id mdb_rid;        // unsigned row identity inside scope
63 typedef mdb_id mdb_tid;        // unsigned table identity inside scope
64 typedef mdb_u4 mdb_token;      // unsigned token for atomized string
65 typedef mdb_token mdb_scope;   // token used to id scope for rows
66 typedef mdb_token mdb_kind;    // token used to id kind for tables
67 typedef mdb_token mdb_column;  // token used to id columns for rows
68 typedef mdb_token mdb_cscode;  // token used to id charset names
69 typedef mdb_u4 mdb_seed;       // unsigned collection change counter
70 typedef mdb_u4 mdb_count;      // unsigned collection member count
71 typedef mdb_u4 mdb_size;       // unsigned physical media size
72 typedef mdb_u4 mdb_fill;       // unsigned logical content size
73 typedef mdb_u4 mdb_more;       // more available bytes for larger buffer
74 
75 typedef mdb_u2 mork_uses;  // 2-byte strong uses count
76 typedef mdb_u2 mork_refs;  // 2-byte actual reference count
77 
78 #define mdbId_kNone ((mdb_id)-1) /* never a valid Mork object ID */
79 
80 typedef mdb_u4 mdb_percent;  // 0..100, with values >100 same as 100
81 
82 typedef mdb_u1 mdb_priority;  // 0..9, for a total of ten different values
83 
84 // sequence position is signed; negative is useful to mean "before first":
85 typedef mdb_i4 mdb_pos;  // signed zero-based ordinal collection position
86 
87 #define mdbPos_kBeforeFirst ((mdb_pos)-1) /* any negative is before zero */
88 
89 // order is also signed, so we can use three states for comparison order:
90 typedef mdb_i4 mdb_order;  // neg:lessthan, zero:equalto, pos:greaterthan
91 
92 typedef mdb_order (*mdbAny_Order)(const void* inA, const void* inB,
93                                   const void* inClosure);
94 
95 // } %%%%% end scalar typedefs %%%%%
96 
97 // { %%%%% begin C structs %%%%%
98 
99 #ifndef mdbScopeStringSet_typedef
100 typedef struct mdbScopeStringSet mdbScopeStringSet;
101 #  define mdbScopeStringSet_typedef 1
102 #endif
103 
104 /*| mdbScopeStringSet: a set of null-terminated C strings that enumerate some
105 **| names of row scopes, so that row scopes intended for use by an application
106 **| can be declared by an app when trying to open or create a database file.
107 **| (We use strings and not tokens because we cannot know the tokens for any
108 **| particular db without having first opened the db.)  The goal is to inform
109 **| a db runtime that scopes not appearing in this list can be given relatively
110 **| short shrift in runtime representation, with the expectation that other
111 **| scopes will not actually be used.  However, a db should still be prepared
112 **| to handle accessing row scopes not in this list, rather than raising errors.
113 **| But it could be quite expensive to access a row scope not on the list.
114 **| Note a zero count for the string set means no such string set is being
115 **| specified, and that a db should handle all row scopes efficiently.
116 **| (It does NOT mean an app plans to use no content whatsoever.)
117 |*/
118 #ifndef mdbScopeStringSet_struct
119 #  define mdbScopeStringSet_struct 1
120 struct mdbScopeStringSet {  // vector of scopes for use in db opening policy
121   // when mScopeStringSet_Count is zero, this means no scope constraints
122   mdb_count mScopeStringSet_Count;       // number of strings in vector below
123   const char** mScopeStringSet_Strings;  // null-ended ascii scope strings
124 };
125 #endif /*mdbScopeStringSet_struct*/
126 
127 #ifndef mdbOpenPolicy_typedef
128 typedef struct mdbOpenPolicy mdbOpenPolicy;
129 #  define mdbOpenPolicy_typedef 1
130 #endif
131 
132 #ifndef mdbOpenPolicy_struct
133 #  define mdbOpenPolicy_struct 1
134 struct mdbOpenPolicy {  // policies affecting db usage for ports and stores
135   mdbScopeStringSet mOpenPolicy_ScopePlan;  // predeclare scope usage plan
136   mdb_bool mOpenPolicy_MaxLazy;             // nonzero: do least work
137   mdb_bool mOpenPolicy_MinMemory;           // nonzero: use least memory
138 };
139 #endif /*mdbOpenPolicy_struct*/
140 
141 #ifndef mdbTokenSet_typedef
142 typedef struct mdbTokenSet mdbTokenSet;
143 #  define mdbTokenSet_typedef 1
144 #endif
145 
146 #ifndef mdbTokenSet_struct
147 #  define mdbTokenSet_struct 1
148 struct mdbTokenSet {  // array for a set of tokens, and actual slots used
149   mdb_count mTokenSet_Count;    // number of token slots in the array
150   mdb_fill mTokenSet_Fill;      // the subset of count slots actually used
151   mdb_more mTokenSet_More;      // more tokens available for bigger array
152   mdb_token* mTokenSet_Tokens;  // array of count mdb_token instances
153 };
154 #endif /*mdbTokenSet_struct*/
155 
156 #ifndef mdbUsagePolicy_typedef
157 typedef struct mdbUsagePolicy mdbUsagePolicy;
158 #  define mdbUsagePolicy_typedef 1
159 #endif
160 
161 /*| mdbUsagePolicy: another version of mdbOpenPolicy which uses tokens instead
162 **| of scope strings, because usage policies can be constructed for use with a
163 **| db that is already open, while an open policy must be constructed before a
164 **| db has yet been opened.
165 |*/
166 #ifndef mdbUsagePolicy_struct
167 #  define mdbUsagePolicy_struct 1
168 struct mdbUsagePolicy {  // policies affecting db usage for ports and stores
169   mdbTokenSet mUsagePolicy_ScopePlan;  // current scope usage plan
170   mdb_bool mUsagePolicy_MaxLazy;       // nonzero: do least work
171   mdb_bool mUsagePolicy_MinMemory;     // nonzero: use least memory
172 };
173 #endif /*mdbUsagePolicy_struct*/
174 
175 #ifndef mdbOid_typedef
176 typedef struct mdbOid mdbOid;
177 #  define mdbOid_typedef 1
178 #endif
179 
180 #ifndef mdbOid_struct
181 #  define mdbOid_struct 1
182 struct mdbOid {          // identity of some row or table inside a database
183   mdb_scope mOid_Scope;  // scope token for an id's namespace
184   mdb_id mOid_Id;        // identity of object inside scope namespace
185 };
186 #endif /*mdbOid_struct*/
187 
188 #ifndef mdbRange_typedef
189 typedef struct mdbRange mdbRange;
190 #  define mdbRange_typedef 1
191 #endif
192 
193 #ifndef mdbRange_struct
194 #  define mdbRange_struct 1
195 struct mdbRange {           // range of row positions in a table
196   mdb_pos mRange_FirstPos;  // position of first row
197   mdb_pos mRange_LastPos;   // position of last row
198 };
199 #endif /*mdbRange_struct*/
200 
201 #ifndef mdbColumnSet_typedef
202 typedef struct mdbColumnSet mdbColumnSet;
203 #  define mdbColumnSet_typedef 1
204 #endif
205 
206 #ifndef mdbColumnSet_struct
207 #  define mdbColumnSet_struct 1
208 struct mdbColumnSet {  // array of column tokens (just the same as mdbTokenSet)
209   mdb_count mColumnSet_Count;      // number of columns
210   mdb_column* mColumnSet_Columns;  // count mdb_column instances
211 };
212 #endif /*mdbColumnSet_struct*/
213 
214 #ifndef mdbYarn_typedef
215 typedef struct mdbYarn mdbYarn;
216 #  define mdbYarn_typedef 1
217 #endif
218 
219 #ifdef MDB_BEGIN_C_LINKAGE_define
220 #  define MDB_BEGIN_C_LINKAGE_define 1
221 #  define MDB_BEGIN_C_LINKAGE extern "C" {
222 #  define MDB_END_C_LINKAGE }
223 #endif /*MDB_BEGIN_C_LINKAGE_define*/
224 
225 /*| mdbYarn_mGrow: an abstract API for growing the size of a mdbYarn
226 **| instance.  With respect to a specific API that requires a caller
227 **| to supply a string (mdbYarn) that a callee fills with content
228 **| that might exceed the specified size, mdbYarn_mGrow is a caller-
229 **| supplied means of letting a callee attempt to increase the string
230 **| size to become large enough to receive all content available.
231 **|
232 **|| Grow(): a method for requesting that a yarn instance be made
233 **| larger in size.  Note that such requests need not be honored, and
234 **| need not be honored in full if only partial size growth is desired.
235 **| (Note that no nsIMdbEnv instance is passed as argument, although one
236 **| might be needed in some circumstances.  So if an nsIMdbEnv is needed,
237 **| a reference to one might be held inside a mdbYarn member slot.)
238 **|
239 **|| self: a yarn instance to be grown.  Presumably this yarn is
240 **| the instance which holds the mYarn_Grow method pointer.  Yarn
241 **| instancesshould only be passed to grow methods which they were
242 **| specifically designed to fit, as indicated by the mYarn_Grow slot.
243 **|
244 **|| inNewSize: the new desired value for slot mYarn_Size in self.
245 **| If mYarn_Size is already this big, then nothing should be done.
246 **| If inNewSize is larger than seems feasible or desirable to honor,
247 **| then any size restriction policy can be used to grow to some size
248 **| greater than mYarn_Size.  (Grow() might even grow to a size
249 **| greater than inNewSize in order to make the increase in size seem
250 **| worthwhile, rather than growing in many smaller steps over time.)
251 |*/
252 typedef void (*mdbYarn_mGrow)(mdbYarn* self, mdb_size inNewSize);
253 // mdbYarn_mGrow methods must be declared with C linkage in C++
254 
255 /*| mdbYarn: a variable length "string" of arbitrary binary bytes,
256 **| whose length is mYarn_Fill, inside a buffer mYarn_Buf that has
257 **| at most mYarn_Size byte of physical space.
258 **|
259 **|| mYarn_Buf: a pointer to space containing content.  This slot
260 **| might never be nil when mYarn_Size is nonzero, but checks for nil
261 **| are recommended anyway.
262 **| (Implementations of mdbYarn_mGrow methods should take care to
263 **| ensure the existence of a replacement before dropping old Bufs.)
264 **| Content in Buf can be anything in any format, but the mYarn_Form
265 **| implies the actual format by some caller-to-callee convention.
266 **| mYarn_Form==0 implies US-ASCII iso-8859-1 Latin1 string content.
267 **|
268 **|| mYarn_Size: the physical size of Buf in bytes.  Note that if one
269 **| intends to terminate a string with a null byte, that it must not
270 **| be written at or after mYarn_Buf[mYarn_Size] because this is after
271 **| the last byte in the physical buffer space.  Size can be zero,
272 **| which means the string has no content whatsoever; note that when
273 **| Size is zero, this is a suitable reason for Buf==nil as well.
274 **|
275 **|| mYarn_Fill: the logical content in Buf in bytes, where Fill must
276 **| never exceed mYarn_Size.  Note that yarn strings might not have a
277 **| terminating null byte (since they might not even be C strings), but
278 **| when they do, such terminating nulls are considered part of content
279 **| and therefore Fill will count such null bytes.  So an "empty" C
280 **| string will have Fill==1, because content includes one null byte.
281 **| Fill does not mean "length" when applied to C strings for this
282 **| reason.  However, clients using yarns to hold C strings can infer
283 **| that length is equal to Fill-1 (but should take care to handle the
284 **| case where Fill==0).  To be paranoid, one can always copy to a
285 **| destination with size exceeding Fill, and place a redundant null
286 **| byte in the Fill position when this simplifies matters.
287 **|
288 **|| mYarn_Form: a designation of content format within mYarn_Buf.
289 **| The semantics of this slot are the least well defined, since the
290 **| actual meaning is context dependent, to the extent that callers
291 **| and callees must agree on format encoding conventions when such
292 **| are not standardized in many computing contexts.  However, in the
293 **| context of a specific mdb database, mYarn_Form is a token for an
294 **| atomized string in that database that typically names a preferred
295 **| mime type charset designation.  If and when mdbYarn is used for
296 **| other purposes away from the mdb interface, folks can use another
297 **| convention system for encoding content formats.  However, in all
298 **| contexts is it useful to maintain the convention that Form==0
299 **| implies Buf contains US-ASCII iso-8859-1 Latin1 string content.
300 **|
301 **|| mYarn_Grow: either a mdbYarn_mGrow method, or else nil.  When
302 **| a mdbYarn_mGrow method is provided, this method can be used to
303 **| request a yarn buf size increase.  A caller who constructs the
304 **| original mdbYarn instance decides whether a grow method is necessary
305 **| or desirable, and uses only grow methods suitable for the buffering
306 **| nature of a specific mdbYarn instance.  (For example, Buf might be a
307 **| statically allocated string space which switches to something heap-based
308 **| when grown, and subsequent calls to grow the yarn must distinguish the
309 **| original static string from heap allocated space, etc.) Note that the
310 **| method stored in mYarn_Grow can change, and this might be a common way
311 **| to track memory managent changes in policy for mYarn_Buf.
312 |*/
313 #ifndef mdbYarn_struct
314 #  define mdbYarn_struct 1
315 struct mdbYarn {             // buffer with caller space allocation semantics
316   void* mYarn_Buf;           // space for holding any binary content
317   mdb_fill mYarn_Fill;       // logical content in Buf in bytes
318   mdb_size mYarn_Size;       // physical size of Buf in bytes
319   mdb_more mYarn_More;       // more available bytes if Buf is bigger
320   mdb_cscode mYarn_Form;     // charset format encoding
321   mdbYarn_mGrow mYarn_Grow;  // optional method to grow mYarn_Buf
322 
323   // Subclasses might add further slots after mYarn_Grow in order to
324   // maintain bookkeeping needs, such as state info about mYarn_Buf.
325 };
326 #endif /*mdbYarn_struct*/
327 
328 // } %%%%% end C structs %%%%%
329 
330 // { %%%%% begin class forward defines %%%%%
331 class nsIMdbEnv;
332 class nsIMdbObject;
333 class nsIMdbErrorHook;
334 class nsIMdbThumb;
335 class nsIMdbFactory;
336 class nsIMdbFile;
337 class nsIMdbPort;
338 class nsIMdbStore;
339 class nsIMdbCursor;
340 class nsIMdbPortTableCursor;
341 class nsIMdbCollection;
342 class nsIMdbTable;
343 class nsIMdbTableRowCursor;
344 class nsIMdbRow;
345 class nsIMdbRowCellCursor;
346 class nsIMdbBlob;
347 class nsIMdbCell;
348 class nsIMdbSorting;
349 // } %%%%% end class forward defines %%%%%
350 
351 // { %%%%% begin C++ abstract class interfaces %%%%%
352 
353 /*| nsIMdbObject: base class for all message db class interfaces
354 **|
355 **|| factory: all nsIMdbObjects from the same code suite have the same factory
356 **|
357 **|| refcounting: both strong and weak references, to ensure strong refs are
358 **| acyclic, while weak refs can cause cycles.  CloseMdbObject() is
359 **| called when (strong) use counts hit zero, but clients can call this close
360 **| method early for some reason, if absolutely necessary even though it will
361 **| thwart the other uses of the same object.  Note that implementations must
362 **| cope with close methods being called arbitrary numbers of times.  The COM
363 **| calls to AddRef() and release ref map directly to strong use ref calls,
364 **| but the total ref count for COM objects is the sum of weak & strong refs.
365 |*/
366 
367 #define NS_IMDBOBJECT_IID_STR "5533ea4b-14c3-4bef-ac60-22f9e9a49084"
368 
369 #define NS_IMDBOBJECT_IID                            \
370   {                                                  \
371     0x5533ea4b, 0x14c3, 0x4bef, {                    \
372       0xac, 0x60, 0x22, 0xf9, 0xe9, 0xa4, 0x90, 0x84 \
373     }                                                \
374   }
375 
376 class nsIMdbObject : public nsISupports {  // msg db base class
377  public:
378   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBOBJECT_IID)
379   // { ===== begin nsIMdbObject methods =====
380 
381   // { ----- begin attribute methods -----
382   NS_IMETHOD IsFrozenMdbObject(nsIMdbEnv* ev, mdb_bool* outIsReadonly) = 0;
383   // same as nsIMdbPort::GetIsPortReadonly() when this object is inside a port.
384   // } ----- end attribute methods -----
385 
386   // { ----- begin factory methods -----
387   NS_IMETHOD GetMdbFactory(nsIMdbEnv* ev, nsIMdbFactory** acqFactory) = 0;
388   // } ----- end factory methods -----
389 
390   // { ----- begin ref counting for well-behaved cyclic graphs -----
391   NS_IMETHOD GetWeakRefCount(nsIMdbEnv* ev,  // weak refs
392                              mdb_count* outCount) = 0;
393   NS_IMETHOD GetStrongRefCount(nsIMdbEnv* ev,  // strong refs
394                                mdb_count* outCount) = 0;
395 
396   NS_IMETHOD AddWeakRef(nsIMdbEnv* ev) = 0;
397   NS_IMETHOD_(mork_uses) AddStrongRef(nsIMdbEnv* ev) = 0;
398 
399   NS_IMETHOD CutWeakRef(nsIMdbEnv* ev) = 0;
400   NS_IMETHOD CutStrongRef(nsIMdbEnv* ev) = 0;
401 
402   NS_IMETHOD CloseMdbObject(nsIMdbEnv* ev) = 0;  // called at strong refs zero
403   NS_IMETHOD IsOpenMdbObject(nsIMdbEnv* ev, mdb_bool* outOpen) = 0;
404   // } ----- end ref counting -----
405 
406   // } ===== end nsIMdbObject methods =====
407 };
408 
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbObject,NS_IMDBOBJECT_IID)409 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbObject, NS_IMDBOBJECT_IID)
410 
411 /*| nsIMdbErrorHook: a base class for clients of this API to subclass, in order
412 **| to provide a callback installable in nsIMdbEnv for error notifications. If
413 **| apps that subclass nsIMdbErrorHook wish to maintain a reference to the env
414 **| that contains the hook, then this should be a weak ref to avoid cycles.
415 **|
416 **|| OnError: when nsIMdbEnv has an error condition that causes the total count
417 **| of errors to increase, then nsIMdbEnv should call OnError() to report the
418 **| error in some fashion when an instance of nsIMdbErrorHook is installed.  The
419 **| variety of string flavors is currently due to the uncertainty here in the
420 **| nsIMdbBlob and nsIMdbCell interfaces.  (Note that overloading by using the
421 **| same method name is not necessary here, and potentially less clear.)
422 |*/
423 class nsIMdbErrorHook
424     : public nsISupports {  // env callback handler to report errors
425  public:
426   // { ===== begin error methods =====
427   NS_IMETHOD OnErrorString(nsIMdbEnv* ev, const char* inAscii) = 0;
428   NS_IMETHOD OnErrorYarn(nsIMdbEnv* ev, const mdbYarn* inYarn) = 0;
429   // } ===== end error methods =====
430 
431   // { ===== begin warning methods =====
432   NS_IMETHOD OnWarningString(nsIMdbEnv* ev, const char* inAscii) = 0;
433   NS_IMETHOD OnWarningYarn(nsIMdbEnv* ev, const mdbYarn* inYarn) = 0;
434   // } ===== end warning methods =====
435 
436   // { ===== begin abort hint methods =====
437   NS_IMETHOD OnAbortHintString(nsIMdbEnv* ev, const char* inAscii) = 0;
438   NS_IMETHOD OnAbortHintYarn(nsIMdbEnv* ev, const mdbYarn* inYarn) = 0;
439   // } ===== end abort hint methods =====
440 };
441 
442 /*| nsIMdbHeap: abstract memory allocation interface.
443 **|
444 **|| Alloc: return a block at least inSize bytes in size with alignment
445 **| suitable for any native type (such as long integers).  When no such
446 **| block can be allocated, failure is indicated by a null address in
447 **| addition to reporting an error in the environment.
448 **|
449 **|| Free: deallocate a block allocated or resized earlier by the same
450 **| heap instance.  If the inBlock parameter is nil, the heap should do
451 **| nothing (and crashing is strongly discouraged).
452 |*/
453 class nsIMdbHeap {  // caller-supplied memory management interface
454  public:
455   // { ===== begin nsIMdbHeap methods =====
456   NS_IMETHOD Alloc(nsIMdbEnv* ev,    // allocate a piece of memory
457                    mdb_size inSize,  // requested byte size of new memory block
458                    void** outBlock) =
459       0;  // memory block of inSize bytes, or nil
460 
461   NS_IMETHOD Free(nsIMdbEnv* ev,       // free block from Alloc or Resize()
462                   void* ioBlock) = 0;  // block to be destroyed/deallocated
463 
464   virtual size_t GetUsedSize() = 0;
465 
~nsIMdbHeap()466   virtual ~nsIMdbHeap(){};
467   // } ===== end nsIMdbHeap methods =====
468 };
469 
470 /*| nsIMdbCPlusHeap: Alloc() with global ::new(), Free() with global ::delete().
471 **| Resize() is done by ::new() followed by ::delete().
472 |*/
473 class nsIMdbCPlusHeap {  // caller-supplied memory management interface
474  public:
475   // { ===== begin nsIMdbHeap methods =====
476   NS_IMETHOD Alloc(nsIMdbEnv* ev,     // allocate a piece of memory
477                    mdb_size inSize,   // requested size of new memory block
478                    void** outBlock);  // memory block of inSize bytes, or nil
479 
480   NS_IMETHOD Free(nsIMdbEnv* ev,  // free block allocated earlier by Alloc()
481                   void* inBlock);
482 
483   NS_IMETHOD HeapAddStrongRef(nsIMdbEnv* ev);
484   NS_IMETHOD HeapCutStrongRef(nsIMdbEnv* ev);
485   // } ===== end nsIMdbHeap methods =====
486 };
487 
488 /*| nsIMdbThumb:
489 |*/
490 
491 #define NS_IMDBTHUMB_IID_STR "6d3ad7c1-a809-4e74-8577-49fa9a4562fa"
492 
493 #define NS_IMDBTHUMB_IID                             \
494   {                                                  \
495     0x6d3ad7c1, 0xa809, 0x4e74, {                    \
496       0x85, 0x77, 0x49, 0xfa, 0x9a, 0x45, 0x62, 0xfa \
497     }                                                \
498   }
499 
500 class nsIMdbThumb
501     : public nsISupports {  // closure for repeating incremental method
502  public:
503   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBTHUMB_IID)
504 
505   // { ===== begin nsIMdbThumb methods =====
506   NS_IMETHOD GetProgress(
507       nsIMdbEnv* ev,
508       mdb_count* outTotal,    // total somethings to do in operation
509       mdb_count* outCurrent,  // subportion of total completed so far
510       mdb_bool* outDone,      // is operation finished?
511       mdb_bool* outBroken     // is operation irreparably dead and broken?
512       ) = 0;
513 
514   NS_IMETHOD DoMore(
515       nsIMdbEnv* ev,
516       mdb_count* outTotal,    // total somethings to do in operation
517       mdb_count* outCurrent,  // subportion of total completed so far
518       mdb_bool* outDone,      // is operation finished?
519       mdb_bool* outBroken     // is operation irreparably dead and broken?
520       ) = 0;
521 
522   NS_IMETHOD CancelAndBreakThumb(  // cancel pending operation
523       nsIMdbEnv* ev) = 0;
524   // } ===== end nsIMdbThumb methods =====
525 };
526 
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbThumb,NS_IMDBTHUMB_IID)527 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbThumb, NS_IMDBTHUMB_IID)
528 
529 /*| nsIMdbEnv: a context parameter used when calling most abstract db methods.
530 **| The main purpose of such an object is to permit a database implementation
531 **| to avoid the use of globals to share information between various parts of
532 **| the implementation behind the abstract db interface.  An environment acts
533 **| like a session object for a given calling thread, and callers should use
534 **| at least one different nsIMdbEnv instance for each thread calling the API.
535 **| While the database implementation might not be threaded, it is highly
536 **| desirable that the db be thread-safe if calling threads use distinct
537 **| instances of nsIMdbEnv.  Callers can stop at one nsIMdbEnv per thread, or
538 they
539 **| might decide to make on nsIMdbEnv instance for every nsIMdbPort opened, so
540 that
541 **| error information is segregated by database instance.  Callers create
542 **| instances of nsIMdbEnv by calling the MakeEnv() method in nsIMdbFactory.
543 **|
544 **|| tracing: an environment might support some kind of tracing, and this
545 **| boolean attribute permits such activity to be enabled or disabled.
546 **|
547 **|| errors: when a call to the abstract db interface returns, a caller might
548 **| check the number of outstanding errors to see whether the operation did
549 **| actually succeed. Each nsIMdbEnv should have all its errors cleared by a
550 **| call to ClearErrors() before making each call to the abstract db API,
551 **| because outstanding errors might disable further database actions.  (This
552 **| is not done inside the db interface, because the db cannot in general know
553 **| when a call originates from inside or outside -- only the app knows this.)
554 **|
555 **|| error hook: callers can install an instance of nsIMdbErrorHook to receive
556 **| error notifications whenever the error count increases.  The hook can
557 **| be uninstalled by passing a null pointer.
558 **|
559 |*/
560 
561 #define NS_IMDBENV_IID_STR "a765e46b-efb6-41e6-b75b-c5d6bd710594"
562 
563 #define NS_IMDBENV_IID                               \
564   {                                                  \
565     0xa765e46b, 0xefb6, 0x41e6, {                    \
566       0xb7, 0x5b, 0xc5, 0xd6, 0xbd, 0x71, 0x05, 0x94 \
567     }                                                \
568   }
569 
570 class nsIMdbEnv : public nsISupports {  // db specific context parameter
571  public:
572   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBENV_IID)
573   // { ===== begin nsIMdbEnv methods =====
574 
575   // { ----- begin attribute methods -----
576   NS_IMETHOD GetErrorCount(mdb_count* outCount, mdb_bool* outShouldAbort) = 0;
577   NS_IMETHOD GetWarningCount(mdb_count* outCount, mdb_bool* outShouldAbort) = 0;
578 
579   NS_IMETHOD GetEnvBeVerbose(mdb_bool* outBeVerbose) = 0;
580   NS_IMETHOD SetEnvBeVerbose(mdb_bool inBeVerbose) = 0;
581 
582   NS_IMETHOD GetDoTrace(mdb_bool* outDoTrace) = 0;
583   NS_IMETHOD SetDoTrace(mdb_bool inDoTrace) = 0;
584 
585   NS_IMETHOD GetAutoClear(mdb_bool* outAutoClear) = 0;
586   NS_IMETHOD SetAutoClear(mdb_bool inAutoClear) = 0;
587 
588   NS_IMETHOD GetErrorHook(nsIMdbErrorHook** acqErrorHook) = 0;
589   NS_IMETHOD SetErrorHook(nsIMdbErrorHook* ioErrorHook) =
590       0;  // becomes referenced
591 
592   NS_IMETHOD GetHeap(nsIMdbHeap** acqHeap) = 0;
593   NS_IMETHOD SetHeap(nsIMdbHeap* ioHeap) = 0;  // becomes referenced
594   // } ----- end attribute methods -----
595 
596   NS_IMETHOD ClearErrors() = 0;    // clear errors beore re-entering db API
597   NS_IMETHOD ClearWarnings() = 0;  // clear warnings
598   NS_IMETHOD ClearErrorsAndWarnings() = 0;  // clear both errors & warnings
599   // } ===== end nsIMdbEnv methods =====
600 };
601 
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbEnv,NS_IMDBENV_IID)602 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbEnv, NS_IMDBENV_IID)
603 
604 /*| nsIMdbFactory: the main entry points to the abstract db interface.  A DLL
605 **| that supports this mdb interface need only have a single exported method
606 **| that will return an instance of nsIMdbFactory, so that further methods in
607 **| the suite can be accessed from objects returned by nsIMdbFactory methods.
608 **|
609 **|| mdbYarn: note all nsIMdbFactory subclasses must guarantee null
610 **| termination of all strings written into mdbYarn instances, as long as
611 **| mYarn_Size and mYarn_Buf are nonzero.  Even truncated string values must
612 **| be null terminated.  This is more strict behavior than mdbYarn requires,
613 **| but it is part of the nsIMdbFactory interface.
614 **|
615 **|| envs: an environment instance is required as per-thread context for
616 **| most of the db method calls, so nsIMdbFactory creates such instances.
617 **|
618 **|| rows: callers must be able to create row instances that are independent
619 **| of storage space that is part of the db content graph.  Many interfaces
620 **| for data exchange have strictly copy semantics, so that a row instance
621 **| has no specific identity inside the db content model, and the text in
622 **| cells are an independenty copy of unexposed content inside the db model.
623 **| Callers are expected to maintain one or more row instances as a buffer
624 **| for staging cell content copied into or out of a table inside the db.
625 **| Callers are urged to use an instance of nsIMdbRow created by the
626 nsIMdbFactory
627 **| code suite, because reading and writing might be much more efficient than
628 **| when using a hand-rolled nsIMdbRow subclass with no relation to the suite.
629 **|
630 **|| ports: a port is a readonly interface to a specific database file. Most
631 **| of the methods to access a db file are suitable for a readonly interface,
632 **| so a port is the basic minimum for accessing content.  This makes it
633 **| possible to read other external formats for import purposes, without
634 **| needing the code or competence necessary to write every such format.  So
635 **| we can write generic import code just once, as long as every format can
636 **| show a face based on nsIMdbPort. (However, same suite import can be faster.)
637 **| Given a file name and the first 512 bytes of a file, a factory can say if
638 **| a port can be opened by this factory.  Presumably an app maintains chains
639 **| of factories for different suites, and asks each in turn about opening a
640 **| a prospective file for reading (as a port) or writing (as a store).  I'm
641 **| not ready to tackle issues of format fidelity and factory chain ordering.
642 **|
643 **|| stores: a store is a mutable interface to a specific database file, and
644 **| includes the port interface plus any methods particular to writing, which
645 **| are few in number.  Presumably the set of files that can be opened as
646 **| stores is a subset of the set of files that can be opened as ports.  A
647 **| new store can be created with CreateNewFileStore() by supplying a new
648 **| file name which does not yet exist (callers are always responsible for
649 **| destroying any existing files before calling this method).
650 |*/
651 
652 #define NS_IMDBFACTORY_IID_STR "2b80395c-b91e-4990-b1a7-023e99ab14e9"
653 
654 #define NS_IMDBFACTORY_IID                           \
655   {                                                  \
656     0xf04aa4ab, 0x1fe, 0x4115, {                     \
657       0xa4, 0xa5, 0x68, 0x19, 0xdf, 0xf1, 0x10, 0x3d \
658     }                                                \
659   }
660 
661 class nsIMdbFactory : public nsISupports {  // suite entry points
662   using PathChar = mozilla::filesystem::Path::value_type;
663 
664  public:
665   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBFACTORY_IID)
666   // { ===== begin nsIMdbFactory methods =====
667 
668   // { ----- begin file methods -----
669   NS_IMETHOD OpenOldFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
670                          const PathChar* inFilePath, mdb_bool inFrozen,
671                          nsIMdbFile** acqFile) = 0;
672   // Choose some subclass of nsIMdbFile to instantiate, in order to read
673   // (and write if not frozen) the file known by inFilePath.  The file
674   // returned should be open and ready for use, and presumably positioned
675   // at the first byte position of the file.  The exact manner in which
676   // files must be opened is considered a subclass specific detail, and
677   // other portions or Mork source code don't want to know how it's done.
678 
679   NS_IMETHOD CreateNewFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
680                            const PathChar* inFilePath,
681                            nsIMdbFile** acqFile) = 0;
682   // Choose some subclass of nsIMdbFile to instantiate, in order to read
683   // (and write if not frozen) the file known by inFilePath.  The file
684   // returned should be created and ready for use, and presumably positioned
685   // at the first byte position of the file.  The exact manner in which
686   // files must be opened is considered a subclass specific detail, and
687   // other portions or Mork source code don't want to know how it's done.
688   // } ----- end file methods -----
689 
690   // { ----- begin env methods -----
691   NS_IMETHOD MakeEnv(nsIMdbHeap* ioHeap,
692                      nsIMdbEnv** acqEnv) = 0;  // acquire new env
693   // ioHeap can be nil, causing a MakeHeap() style heap instance to be used
694   // } ----- end env methods -----
695 
696   // { ----- begin heap methods -----
697   NS_IMETHOD MakeHeap(nsIMdbEnv* ev,
698                       nsIMdbHeap** acqHeap) = 0;  // acquire new heap
699   // } ----- end heap methods -----
700 
701   // { ----- begin row methods -----
702   NS_IMETHOD MakeRow(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
703                      nsIMdbRow** acqRow) = 0;  // new row
704   // ioHeap can be nil, causing the heap associated with ev to be used
705   // } ----- end row methods -----
706 
707   // { ----- begin port methods -----
708   NS_IMETHOD CanOpenFilePort(
709       nsIMdbEnv* ev,  // context
710       // const char* inFilePath, // the file to investigate
711       // const mdbYarn* inFirst512Bytes,
712       nsIMdbFile* ioFile,              // db abstract file interface
713       mdb_bool* outCanOpen,            // whether OpenFilePort() might succeed
714       mdbYarn* outFormatVersion) = 0;  // informal file format description
715 
716   NS_IMETHOD OpenFilePort(
717       nsIMdbEnv* ev,       // context
718       nsIMdbHeap* ioHeap,  // can be nil to cause ev's heap attribute to be used
719       // const char* inFilePath, // the file to open for readonly import
720       nsIMdbFile* ioFile,                 // db abstract file interface
721       const mdbOpenPolicy* inOpenPolicy,  // runtime policies for using db
722       nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental port open
723   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
724   // then call nsIMdbFactory::ThumbToOpenPort() to get the port instance.
725 
726   NS_IMETHOD
727   ThumbToOpenPort(           // redeeming a completed thumb from OpenFilePort()
728       nsIMdbEnv* ev,         // context
729       nsIMdbThumb* ioThumb,  // thumb from OpenFilePort() with done status
730       nsIMdbPort** acqPort) = 0;  // acquire new port object
731   // } ----- end port methods -----
732 
733   // { ----- begin store methods -----
734   NS_IMETHOD CanOpenFileStore(
735       nsIMdbEnv* ev,  // context
736       // const char* inFilePath, // the file to investigate
737       // const mdbYarn* inFirst512Bytes,
738       nsIMdbFile* ioFile,              // db abstract file interface
739       mdb_bool* outCanOpenAsStore,     // whether OpenFileStore() might succeed
740       mdb_bool* outCanOpenAsPort,      // whether OpenFilePort() might succeed
741       mdbYarn* outFormatVersion) = 0;  // informal file format description
742 
743   NS_IMETHOD OpenFileStore(  // open an existing database
744       nsIMdbEnv* ev,         // context
745       nsIMdbHeap* ioHeap,  // can be nil to cause ev's heap attribute to be used
746       // const char* inFilePath, // the file to open for general db usage
747       nsIMdbFile* ioFile,                 // db abstract file interface
748       const mdbOpenPolicy* inOpenPolicy,  // runtime policies for using db
749       nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental store open
750   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
751   // then call nsIMdbFactory::ThumbToOpenStore() to get the store instance.
752 
753   NS_IMETHOD
754   ThumbToOpenStore(          // redeem completed thumb from OpenFileStore()
755       nsIMdbEnv* ev,         // context
756       nsIMdbThumb* ioThumb,  // thumb from OpenFileStore() with done status
757       nsIMdbStore** acqStore) = 0;  // acquire new db store object
758 
759   NS_IMETHOD CreateNewFileStore(  // create a new db with minimal content
760       nsIMdbEnv* ev,              // context
761       nsIMdbHeap* ioHeap,  // can be nil to cause ev's heap attribute to be used
762       // const char* inFilePath, // name of file which should not yet exist
763       nsIMdbFile* ioFile,                 // db abstract file interface
764       const mdbOpenPolicy* inOpenPolicy,  // runtime policies for using db
765       nsIMdbStore** acqStore) = 0;        // acquire new db store object
766   // } ----- end store methods -----
767 
768   // } ===== end nsIMdbFactory methods =====
769 };
770 
771 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbFactory, NS_IMDBFACTORY_IID)
772 
773 extern "C" nsIMdbFactory* MakeMdbFactory();
774 
775 /*| nsIMdbFile: abstract file interface resembling the original morkFile
776 **| abstract interface (which was in turn modeled on the file interface
777 **| from public domain IronDoc).  The design of this file interface is
778 **| complicated by the fact that some DB's will not find this interface
779 **| adequate for all runtime requirements (even though this file API is
780 **| enough to implement text-based DB's like Mork).  For this reason,
781 **| more methods have been added to let a DB library force the file to
782 **| become closed so the DB can reopen the file in some other manner.
783 **| Folks are encouraged to suggest ways to tune this interface to suit
784 **| DB's that cannot manage to pull their maneuvers even given this API.
785 **|
786 **|| Tell: get the current i/o position in file
787 **|
788 **|| Seek: change the current i/o position in file
789 **|
790 **|| Eof: return file's total length in bytes
791 **|
792 **|| Read: input inSize bytes into outBuf, returning actual transfer size
793 **|
794 **|| Get: read starting at specific file offset (e.g. Seek(); Read();)
795 **|
796 **|| Write: output inSize bytes from inBuf, returning actual transfer size
797 **|
798 **|| Put: write starting at specific file offset (e.g. Seek(); Write();)
799 **|
800 **|| Flush: if written bytes are buffered, push them to final destination
801 **|
802 **|| Path: get file path in some string representation.  This is intended
803 **| either to support the display of file name in a user presentation, or
804 **| to support the closing and reopening of the file when the DB needs more
805 **| exotic file access than is presented by the nsIMdbFile interface.
806 **|
807 **|| Steal: tell this file to close any associated i/o stream in the file
808 **| system, because the file ioThief intends to reopen the file in order
809 **| to provide the MDB implementation with more exotic file access than is
810 **| offered by the nsIMdbFile alone.  Presumably the thief knows enough
811 **| from Path() in order to know which file to reopen.  If Steal() is
812 **| successful, this file should probably delegate all future calls to
813 **| the nsIMdbFile interface down to the thief files, so that even after
814 **| the file has been stolen, it can still be read, written, or forcibly
815 **| closed (by a call to CloseMdbObject()).
816 **|
817 **|| Thief: acquire and return thief passed to an earlier call to Steal().
818 |*/
819 
820 #define NS_IMDBFILE_IID_STR "f04aa4ab-1fe7-4115-a4a5-6819dff1103d"
821 
822 #define NS_IMDBFILE_IID                              \
823   {                                                  \
824     0xf04aa4ab, 0x1fe, 0x4115, {                     \
825       0xa4, 0xa5, 0x68, 0x19, 0xdf, 0xf1, 0x10, 0x3d \
826     }                                                \
827   }
828 
829 class nsIMdbFile : public nsISupports {  // minimal file interface
830  public:
831   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBFILE_IID)
832   // { ===== begin nsIMdbFile methods =====
833 
834   // { ----- begin pos methods -----
835   NS_IMETHOD Tell(nsIMdbEnv* ev, mdb_pos* outPos) const = 0;
836   NS_IMETHOD Seek(nsIMdbEnv* ev, mdb_pos inPos, mdb_pos* outPos) = 0;
837   NS_IMETHOD Eof(nsIMdbEnv* ev, mdb_pos* outPos) = 0;
838   // } ----- end pos methods -----
839 
840   // { ----- begin read methods -----
841   NS_IMETHOD Read(nsIMdbEnv* ev, void* outBuf, mdb_size inSize,
842                   mdb_size* outActualSize) = 0;
843   NS_IMETHOD Get(nsIMdbEnv* ev, void* outBuf, mdb_size inSize, mdb_pos inPos,
844                  mdb_size* outActualSize) = 0;
845   // } ----- end read methods -----
846 
847   // { ----- begin write methods -----
848   NS_IMETHOD Write(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
849                    mdb_size* outActualSize) = 0;
850   NS_IMETHOD Put(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
851                  mdb_pos inPos, mdb_size* outActualSize) = 0;
852   NS_IMETHOD Flush(nsIMdbEnv* ev) = 0;
853   // } ----- end attribute methods -----
854 
855   // { ----- begin path methods -----
856   NS_IMETHOD Path(nsIMdbEnv* ev, mdbYarn* outFilePath) = 0;
857   // } ----- end path methods -----
858 
859   // { ----- begin replacement methods -----
860   NS_IMETHOD Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief) = 0;
861   NS_IMETHOD Thief(nsIMdbEnv* ev, nsIMdbFile** acqThief) = 0;
862   // } ----- end replacement methods -----
863 
864   // { ----- begin versioning methods -----
865   NS_IMETHOD BecomeTrunk(nsIMdbEnv* ev) = 0;
866   // If this file is a file version branch created by calling AcquireBud(),
867   // BecomeTrunk() causes this file's content to replace the original
868   // file's content, typically by assuming the original file's identity.
869   // This default implementation of BecomeTrunk() does nothing, and this
870   // is appropriate behavior for files which are not branches, and is
871   // also the right behavior for files returned from AcquireBud() which are
872   // in fact the original file that has been truncated down to zero length.
873 
874   NS_IMETHOD AcquireBud(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
875                         nsIMdbFile** acqBud) =
876       0;  // acquired file for new version of content
877   // AcquireBud() starts a new "branch" version of the file, empty of content,
878   // so that a new version of the file can be written.  This new file
879   // can later be told to BecomeTrunk() the original file, so the branch
880   // created by budding the file will replace the original file.  Some
881   // file subclasses might initially take the unsafe but expedient
882   // approach of simply truncating this file down to zero length, and
883   // then returning the same morkFile pointer as this, with an extra
884   // reference count increment.  Note that the caller of AcquireBud() is
885   // expected to eventually call CutStrongRef() on the returned file
886   // in order to release the strong reference.  High quality versions
887   // of morkFile subclasses will create entirely new files which later
888   // are renamed to become the old file, so that better transactional
889   // behavior is exhibited by the file, so crashes protect old files.
890   // Note that AcquireBud() is an illegal operation on readonly files.
891   // } ----- end versioning methods -----
892 
893   // } ===== end nsIMdbFile methods =====
894 };
895 
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbFile,NS_IMDBFILE_IID)896 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbFile, NS_IMDBFILE_IID)
897 
898 /*| nsIMdbPort: a readonly interface to a specific database file. The mutable
899 **| nsIMdbStore interface is a subclass that includes writing behavior, but
900 **| most of the needed db methods appear in the readonly nsIMdbPort interface.
901 **|
902 **|| mdbYarn: note all nsIMdbPort and nsIMdbStore subclasses must guarantee null
903 **| termination of all strings written into mdbYarn instances, as long as
904 **| mYarn_Size and mYarn_Buf are nonzero.  Even truncated string values must
905 **| be null terminated.  This is more strict behavior than mdbYarn requires,
906 **| but it is part of the nsIMdbPort and nsIMdbStore interface.
907 **|
908 **|| attributes: methods are provided to distinguish a readonly port from a
909 **| mutable store, and whether a mutable store actually has any dirty content.
910 **|
911 **|| filepath: the file path used to open the port from the nsIMdbFactory can be
912 **| queried and discovered by GetPortFilePath(), which includes format info.
913 **|
914 **|| export: a port can write itself in other formats, with perhaps a typical
915 **| emphasis on text interchange formats used by other systems.  A port can be
916 **| queried to determine its preferred export interchange format, and a port
917 **| can be queried to see whether a specific export format is supported.  And
918 **| actually exporting a port requires a new destination file name and format.
919 **|
920 **|| tokens: a port supports queries about atomized strings to map tokens to
921 **| strings or strings to token integers.  (All atomized strings must be in
922 **| US-ASCII iso-8859-1 Latin1 charset encoding.)  When a port is actually a
923 **| mutable store and a string has not yet been atomized, then StringToToken()
924 **| will actually do so and modify the store.  The QueryToken() method will not
925 **| atomize a string if it has not already been atomized yet, even in stores.
926 **|
927 **|| tables: other than string tokens, all port content is presented through
928 **| tables, which are ordered collections of rows.  Tables are identified by
929 **| row scope and table kind, which might or might not be unique in a port,
930 **| depending on app convention.  When tables are effectively unique, then
931 **| queries for specific scope and kind pairs will find those tables.  To see
932 **| all tables that match specific row scope and table kind patterns, even in
933 **| the presence of duplicates, every port supports a GetPortTableCursor()
934 **| method that returns an iterator over all matching tables.  Table kind is
935 **| considered scoped inside row scope, so passing a zero for table kind will
936 **| find all table kinds for some nonzero row scope.  Passing a zero for row
937 **| scope will iterate over all tables in the port, in some undefined order.
938 **| (A new table can be added to a port using nsIMdbStore::NewTable(), even when
939 **| the requested scope and kind combination is already used by other tables.)
940 **|
941 **|| memory: callers can request that a database use less memory footprint in
942 **| several flavors, from an inconsequential idle flavor to a rather drastic
943 **| panic flavor. Callers might perform an idle purge very frequently if desired
944 **| with very little cost, since only normally scheduled memory management will
945 **| be conducted, such as freeing resources for objects scheduled to be dropped.
946 **| Callers should perform session memory purges infrequently because they might
947 **| involve costly scanning of data structures to removed cached content, and
948 **| session purges are recommended only when a caller experiences memory crunch.
949 **| Callers should only rarely perform a panic purge, in response to dire memory
950 **| straits, since this is likely to make db operations much more expensive
951 **| than they would be otherwise.  A panic purge asks a database to free as much
952 **| memory as possible while staying effective and operational, because a caller
953 **| thinks application failure might otherwise occur.  (Apps might better close
954 **| an open db, so panic purges only make sense when a db is urgently needed.)
955 |*/
956 class nsIMdbPort : public nsISupports {
957  public:
958   // { ===== begin nsIMdbPort methods =====
959 
960   // { ----- begin attribute methods -----
961   NS_IMETHOD GetIsPortReadonly(nsIMdbEnv* ev, mdb_bool* outBool) = 0;
962   NS_IMETHOD GetIsStore(nsIMdbEnv* ev, mdb_bool* outBool) = 0;
963   NS_IMETHOD GetIsStoreAndDirty(nsIMdbEnv* ev, mdb_bool* outBool) = 0;
964 
965   NS_IMETHOD GetUsagePolicy(nsIMdbEnv* ev, mdbUsagePolicy* ioUsagePolicy) = 0;
966 
967   NS_IMETHOD SetUsagePolicy(nsIMdbEnv* ev,
968                             const mdbUsagePolicy* inUsagePolicy) = 0;
969   // } ----- end attribute methods -----
970 
971   // { ----- begin memory policy methods -----
972   NS_IMETHOD IdleMemoryPurge(  // do memory management already scheduled
973       nsIMdbEnv* ev,           // context
974       mdb_size* outEstimatedBytesFreed) =
975       0;  // approximate bytes actually freed
976 
977   NS_IMETHOD SessionMemoryPurge(     // request specific footprint decrease
978       nsIMdbEnv* ev,                 // context
979       mdb_size inDesiredBytesFreed,  // approximate number of bytes wanted
980       mdb_size* outEstimatedBytesFreed) =
981       0;  // approximate bytes actually freed
982 
983   NS_IMETHOD PanicMemoryPurge(  // desperately free all possible memory
984       nsIMdbEnv* ev,            // context
985       mdb_size* outEstimatedBytesFreed) =
986       0;  // approximate bytes actually freed
987   // } ----- end memory policy methods -----
988 
989   // { ----- begin filepath methods -----
990   NS_IMETHOD GetPortFilePath(
991       nsIMdbEnv* ev,                   // context
992       mdbYarn* outFilePath,            // name of file holding port content
993       mdbYarn* outFormatVersion) = 0;  // file format description
994 
995   NS_IMETHOD GetPortFile(nsIMdbEnv* ev,  // context
996                          nsIMdbFile** acqFile) =
997       0;  // acquire file used by port or store
998   // } ----- end filepath methods -----
999 
1000   // { ----- begin export methods -----
1001   NS_IMETHOD BestExportFormat(         // determine preferred export format
1002       nsIMdbEnv* ev,                   // context
1003       mdbYarn* outFormatVersion) = 0;  // file format description
1004 
1005   // some tentative suggested import/export formats
1006   // "ns:msg:db:port:format:ldif:ns4.0:passthrough" // necessary
1007   // "ns:msg:db:port:format:ldif:ns4.5:utf8"        // necessary
1008   // "ns:msg:db:port:format:ldif:ns4.5:tabbed"
1009   // "ns:msg:db:port:format:ldif:ns4.5:binary"      // necessary
1010   // "ns:msg:db:port:format:html:ns3.0:addressbook" // necessary
1011   // "ns:msg:db:port:format:html:display:verbose"
1012   // "ns:msg:db:port:format:html:display:concise"
1013   // "ns:msg:db:port:format:mork:zany:verbose"      // necessary
1014   // "ns:msg:db:port:format:mork:zany:atomized"     // necessary
1015   // "ns:msg:db:port:format:rdf:xml"
1016   // "ns:msg:db:port:format:xml:mork"
1017   // "ns:msg:db:port:format:xml:display:verbose"
1018   // "ns:msg:db:port:format:xml:display:concise"
1019   // "ns:msg:db:port:format:xml:print:verbose"      // recommended
1020   // "ns:msg:db:port:format:xml:print:concise"
1021 
1022   NS_IMETHOD
1023   CanExportToFormat(  // can export content in given specific format?
1024       nsIMdbEnv* ev,  // context
1025       const char* inFormatVersion,  // file format description
1026       mdb_bool* outCanExport) = 0;  // whether ExportSource() might succeed
1027 
1028   NS_IMETHOD ExportToFormat(  // export content in given specific format
1029       nsIMdbEnv* ev,          // context
1030       // const char* inFilePath, // the file to receive exported content
1031       nsIMdbFile* ioFile,           // destination abstract file interface
1032       const char* inFormatVersion,  // file format description
1033       nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental export
1034   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1035   // then the export will be finished.
1036 
1037   // } ----- end export methods -----
1038 
1039   // { ----- begin token methods -----
1040   NS_IMETHOD TokenToString(        // return a string name for an integer token
1041       nsIMdbEnv* ev,               // context
1042       mdb_token inToken,           // token for inTokenName inside this port
1043       mdbYarn* outTokenName) = 0;  // the type of table to access
1044 
1045   NS_IMETHOD StringToToken(      // return an integer token for scope name
1046       nsIMdbEnv* ev,             // context
1047       const char* inTokenName,   // Latin1 string to tokenize if possible
1048       mdb_token* outToken) = 0;  // token for inTokenName inside this port
1049 
1050   // String token zero is never used and never supported. If the port
1051   // is a mutable store, then StringToToken() to create a new
1052   // association of inTokenName with a new integer token if possible.
1053   // But a readonly port will return zero for an unknown scope name.
1054 
1055   NS_IMETHOD QueryToken(         // like StringToToken(), but without adding
1056       nsIMdbEnv* ev,             // context
1057       const char* inTokenName,   // Latin1 string to tokenize if possible
1058       mdb_token* outToken) = 0;  // token for inTokenName inside this port
1059 
1060   // QueryToken() will return a string token if one already exists,
1061   // but unlike StringToToken(), will not assign a new token if not
1062   // already in use.
1063 
1064   // } ----- end token methods -----
1065 
1066   // { ----- begin row methods -----
1067   NS_IMETHOD HasRow(             // contains a row with the specified oid?
1068       nsIMdbEnv* ev,             // context
1069       const mdbOid* inOid,       // hypothetical row oid
1070       mdb_bool* outHasRow) = 0;  // whether GetRow() might succeed
1071 
1072   NS_IMETHOD GetRowRefCount(        // get number of tables that contain a row
1073       nsIMdbEnv* ev,                // context
1074       const mdbOid* inOid,          // hypothetical row oid
1075       mdb_count* outRefCount) = 0;  // number of tables containing inRowKey
1076 
1077   NS_IMETHOD GetRow(            // access one row with specific oid
1078       nsIMdbEnv* ev,            // context
1079       const mdbOid* inOid,      // hypothetical row oid
1080       nsIMdbRow** acqRow) = 0;  // acquire specific row (or null)
1081 
1082   // NS_IMETHOD
1083   // GetPortRowCursor( // get cursor for all rows in specific scope
1084   //   nsIMdbEnv* ev, // context
1085   //   mdb_scope inRowScope, // row scope for row ids
1086   //   nsIMdbPortRowCursor** acqCursor) = 0; // all such rows in the port
1087 
1088   NS_IMETHOD FindRow(
1089       nsIMdbEnv* ev,         // search for row with matching cell
1090       mdb_scope inRowScope,  // row scope for row ids
1091       mdb_column inColumn,   // the column to search (and maintain an index)
1092       const mdbYarn* inTargetCellValue,  // cell value for which to search
1093       mdbOid* outRowOid,        // out row oid on match (or {0,-1} for no match)
1094       nsIMdbRow** acqRow) = 0;  // acquire matching row (or nil for no match)
1095                                 // can be null if you only want the oid
1096   // FindRow() searches for one row that has a cell in column inColumn with
1097   // a contained value with the same form (i.e. charset) and is byte-wise
1098   // identical to the blob described by yarn inTargetCellValue.  Both content
1099   // and form of the yarn must be an exact match to find a matching row.
1100   //
1101   // (In other words, both a yarn's blob bytes and form are significant.  The
1102   // form is not expected to vary in columns used for identity anyway.  This
1103   // is intended to make the cost of FindRow() cheaper for MDB implementors,
1104   // since any cell value atomization performed internally must necessarily
1105   // make yarn form significant in order to avoid data loss in atomization.)
1106   //
1107   // FindRow() can lazily create an index on attribute inColumn for all rows
1108   // with that attribute in row space scope inRowScope, so that subsequent
1109   // calls to FindRow() will perform faster.  Such an index might or might
1110   // not be persistent (but this seems desirable if it is cheap to do so).
1111   // Note that lazy index creation in readonly DBs is not very feasible.
1112   //
1113   // This FindRow() interface assumes that attribute inColumn is effectively
1114   // an alternative means of unique identification for a row in a rowspace,
1115   // so correct behavior is only guaranteed when no duplicates for this col
1116   // appear in the given set of rows.  (If more than one row has the same cell
1117   // value in this column, no more than one will be found; and cutting one of
1118   // two duplicate rows can cause the index to assume no other such row lives
1119   // in the row space, so future calls return nil for negative search results
1120   // even though some duplicate row might still live within the rowspace.)
1121   //
1122   // In other words, the FindRow() implementation is allowed to assume simple
1123   // hash tables mapping unique column keys to associated row values will be
1124   // sufficient, where any duplication is not recorded because only one copy
1125   // of a given key need be remembered.  Implementors are not required to sort
1126   // all rows by the specified column.
1127   // } ----- end row methods -----
1128 
1129   // { ----- begin table methods -----
1130   NS_IMETHOD HasTable(             // supports a table with the specified oid?
1131       nsIMdbEnv* ev,               // context
1132       const mdbOid* inOid,         // hypothetical table oid
1133       mdb_bool* outHasTable) = 0;  // whether GetTable() might succeed
1134 
1135   NS_IMETHOD GetTable(              // access one table with specific oid
1136       nsIMdbEnv* ev,                // context
1137       const mdbOid* inOid,          // hypothetical table oid
1138       nsIMdbTable** acqTable) = 0;  // acquire specific table (or null)
1139 
1140   NS_IMETHOD HasTableKind(       // supports a table of the specified type?
1141       nsIMdbEnv* ev,             // context
1142       mdb_scope inRowScope,      // rid scope for row ids
1143       mdb_kind inTableKind,      // the type of table to access
1144       mdb_count* outTableCount,  // current number of such tables
1145       mdb_bool* outSupportsTable) = 0;  // whether GetTableKind() might succeed
1146 
1147   // row scopes to be supported include the following suggestions:
1148   // "ns:msg:db:row:scope:address:cards:all"
1149   // "ns:msg:db:row:scope:mail:messages:all"
1150   // "ns:msg:db:row:scope:news:articles:all"
1151 
1152   // table kinds to be supported include the following suggestions:
1153   // "ns:msg:db:table:kind:address:cards:main"
1154   // "ns:msg:db:table:kind:address:lists:all"
1155   // "ns:msg:db:table:kind:address:list"
1156   // "ns:msg:db:table:kind:news:threads:all"
1157   // "ns:msg:db:table:kind:news:thread"
1158   // "ns:msg:db:table:kind:mail:threads:all"
1159   // "ns:msg:db:table:kind:mail:thread"
1160 
1161   NS_IMETHOD GetTableKind(        // access one (random) table of specific type
1162       nsIMdbEnv* ev,              // context
1163       mdb_scope inRowScope,       // row scope for row ids
1164       mdb_kind inTableKind,       // the type of table to access
1165       mdb_count* outTableCount,   // current number of such tables
1166       mdb_bool* outMustBeUnique,  // whether port can hold only one of these
1167       nsIMdbTable** acqTable) = 0;  // acquire scoped collection of rows
1168 
1169   NS_IMETHOD
1170   GetPortTableCursor(        // get cursor for all tables of specific type
1171       nsIMdbEnv* ev,         // context
1172       mdb_scope inRowScope,  // row scope for row ids
1173       mdb_kind inTableKind,  // the type of table to access
1174       nsIMdbPortTableCursor** acqCursor) = 0;  // all such tables in the port
1175   // } ----- end table methods -----
1176 
1177   // { ----- begin commit methods -----
1178 
1179   NS_IMETHOD ShouldCompress(        // store wastes at least inPercentWaste?
1180       nsIMdbEnv* ev,                // context
1181       mdb_percent inPercentWaste,   // 0..100 percent file size waste threshold
1182       mdb_percent* outActualWaste,  // 0..100 percent of file actually wasted
1183       mdb_bool* outShould) = 0;     // true when about inPercentWaste% is wasted
1184   // ShouldCompress() returns true if the store can determine that the file
1185   // will shrink by an estimated percentage of inPercentWaste% (or more) if
1186   // CompressCommit() is called, because that percentage of the file seems
1187   // to be recoverable free space.  The granularity is only in terms of
1188   // percentage points, and any value over 100 is considered equal to 100.
1189   //
1190   // If a store only has an approximate idea how much space might be saved
1191   // during a compress, then a best guess should be made.  For example, the
1192   // Mork implementation might keep track of how much file space began with
1193   // text content before the first updating transaction, and then consider
1194   // all content following the start of the first transaction as potentially
1195   // wasted space if it is all updates and not just new content.  (This is
1196   // a safe assumption in the sense that behavior will stabilize on a low
1197   // estimate of wastage after a commit removes all transaction updates.)
1198   //
1199   // Some db formats might attempt to keep a very accurate reckoning of free
1200   // space size, so a very accurate determination can be made.  But other db
1201   // formats might have difficulty determining size of free space, and might
1202   // require some lengthy calculation to answer.  This is the reason for
1203   // passing in the percentage threshold of interest, so that such lengthy
1204   // computations can terminate early as soon as at least inPercentWaste is
1205   // found, so that the entire file need not be groveled when unnecessary.
1206   // However, we hope implementations will always favor fast but imprecise
1207   // heuristic answers instead of extremely slow but very precise answers.
1208   //
1209   // If the outActualWaste parameter is non-nil, it will be used to return
1210   // the actual estimated space wasted as a percentage of file size.  (This
1211   // parameter is provided so callers need not call repeatedly with altered
1212   // inPercentWaste values to isolate the actual wastage figure.)  Note the
1213   // actual wastage figure returned can exactly equal inPercentWaste even
1214   // when this grossly underestimates the real figure involved, if the db
1215   // finds it very expensive to determine the extent of wastage after it is
1216   // known to at least exceed inPercentWaste.  Note we expect that whenever
1217   // outShould returns true, that outActualWaste returns >= inPercentWaste.
1218   //
1219   // The effect of different inPercentWaste values is not very uniform over
1220   // the permitted range.  For example, 50 represents 50% wastage, or a file
1221   // that is about double what it should be ideally.  But 99 represents 99%
1222   // wastage, or a file that is about ninety-nine times as big as it should
1223   // be ideally.  In the smaller direction, 25 represents 25% wastage, or
1224   // a file that is only 33% larger than it should be ideally.
1225   //
1226   // Callers can determine what policy they want to use for considering when
1227   // a file holds too much wasted space, and express this as a percentage
1228   // of total file size to pass as in the inPercentWaste parameter.  A zero
1229   // likely returns always trivially true, and 100 always trivially false.
1230   // The great majority of callers are expected to use values from 25 to 75,
1231   // since most plausible thresholds for compressing might fall between the
1232   // extremes of 133% of ideal size and 400% of ideal size.  (Presumably the
1233   // larger a file gets, the more important the percentage waste involved, so
1234   // a sliding scale for compress thresholds might use smaller numbers for
1235   // much bigger file sizes.)
1236 
1237   // } ----- end commit methods -----
1238 
1239   // } ===== end nsIMdbPort methods =====
1240 };
1241 
1242 /*| nsIMdbStore: a mutable interface to a specific database file.
1243 **|
1244 **|| tables: one can force a new table to exist in a store with NewTable()
1245 **| and nonzero values for both row scope and table kind.  (If one wishes only
1246 **| one table of a certain kind, then one might look for it first using the
1247 **| GetTableKind() method).  One can pass inMustBeUnique to force future
1248 **| users of this store to be unable to create other tables with the same pair
1249 **| of scope and kind attributes.  When inMustBeUnique is true, and the table
1250 **| with the given scope and kind pair already exists, then the existing one
1251 **| is returned instead of making a new table.  Similarly, if one passes false
1252 **| for inMustBeUnique, but the table kind has already been marked unique by a
1253 **| previous user of the store, then the existing unique table is returned.
1254 **|
1255 **|| import: all or some of another port's content can be imported by calling
1256 **| AddPortContent() with a row scope identifying the extent of content to
1257 **| be imported.  A zero row scope will import everything.  A nonzero row
1258 **| scope will only import tables with a matching row scope.  Note that one
1259 **| must somehow find a way to negotiate possible conflicts between existing
1260 **| row content and imported row content, and this involves a specific kind of
1261 **| definition for row identity involving either row IDs or unique attributes,
1262 **| or some combination of these two.  At the moment I am just going to wave
1263 **| my hands, and say the default behavior is to assign all new row identities
1264 **| to all imported content, which will result in no merging of content; this
1265 **| must change later because it is unacceptable in some contexts.
1266 **|
1267 **|| commits: to manage modifications in a mutable store, very few methods are
1268 **| really needed to indicate global policy choices that are independent of
1269 **| the actual modifications that happen in objects at the level of tables,
1270 **| rows, and cells, etc.  The most important policy to specify is which sets
1271 **| of changes are considered associated in a manner such that they should be
1272 **| applied together atomically to a given store.  We call each such group of
1273 **| changes a transaction.  We handle three different grades of transaction,
1274 **| but they differ only in semantic significance to the application, and are
1275 **| not intended to nest.  (If small transactions were nested inside large
1276 **| transactions, that would imply that a single large transaction must be
1277 **| atomic over all the contained small transactions; but actually we intend
1278 **| smalls transaction never be undone once committed due to, say, aborting a
1279 **| transaction of greater significance.)  The small, large, and session level
1280 **| commits have equal granularity, and differ only in risk of loss from the
1281 **| perspective of an application.  Small commits characterize changes that
1282 **| can be lost with relatively small risk, so small transactions can delay
1283 **| until later if they are expensive or impractical to commit.  Large commits
1284 **| involve changes that would probably inconvenience users if lost, so the
1285 **| need to pay costs of writing is rather greater than with small commits.
1286 **| Session commits are last ditch attempts to save outstanding changes before
1287 **| stopping the use of a particular database, so there will be no later point
1288 **| in time to save changes that have been delayed due to possible high cost.
1289 **| If large commits are never delayed, then a session commit has about the
1290 **| same performance effect as another large commit; but if small and large
1291 **| commits are always delayed, then a session commit is likely to be rather
1292 **| expensive as a runtime cost compared to any earlier database usage.
1293 **|
1294 **|| aborts: the only way to abort changes to a store is by closing the store.
1295 **| So there is no specific method for causing any abort.  Stores must discard
1296 **| all changes made that are uncommitted when a store is closed.  This design
1297 **| choice makes the implementations of tables, rows, and cells much less
1298 **| complex because they need not maintain a record of undobable changes.  When
1299 **| a store is closed, presumably this precipitates the closure of all tables,
1300 **| rows, and cells in the store as well.   So an application can revert the
1301 **| state of a store in the user interface by quietly closing and reopening a
1302 **| store, because this will discard uncommitted changes and show old content.
1303 **| This implies an app that closes a store will need to send a "scramble"
1304 **| event notification to any views that depend on old discarded content.
1305 |*/
1306 
1307 #define NS_IMDBSTORE_IID_STR "74d6218d-44b0-43b5-9ebe-69a17dfb562c"
1308 #define NS_IMDBSTORE_IID                             \
1309   {                                                  \
1310     0x74d6218d, 0x44b0, 0x43b5, {                    \
1311       0x9e, 0xbe, 0x69, 0xa1, 0x7d, 0xfb, 0x56, 0x2c \
1312     }                                                \
1313   }
1314 
1315 class nsIMdbStore : public nsIMdbPort {
1316  public:
1317   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBSTORE_IID)
1318 
1319   // { ===== begin nsIMdbStore methods =====
1320 
1321   // { ----- begin table methods -----
1322   NS_IMETHOD NewTable(          // make one new table of specific type
1323       nsIMdbEnv* ev,            // context
1324       mdb_scope inRowScope,     // row scope for row ids
1325       mdb_kind inTableKind,     // the type of table to access
1326       mdb_bool inMustBeUnique,  // whether store can hold only one of these
1327       const mdbOid* inOptionalMetaRowOid,  // can be nil to avoid specifying
1328       nsIMdbTable** acqTable) = 0;         // acquire scoped collection of rows
1329 
1330   NS_IMETHOD NewTableWithOid(   // make one new table of specific type
1331       nsIMdbEnv* ev,            // context
1332       const mdbOid* inOid,      // caller assigned oid
1333       mdb_kind inTableKind,     // the type of table to access
1334       mdb_bool inMustBeUnique,  // whether store can hold only one of these
1335       const mdbOid* inOptionalMetaRowOid,  // can be nil to avoid specifying
1336       nsIMdbTable** acqTable) = 0;         // acquire scoped collection of rows
1337   // } ----- end table methods -----
1338 
1339   // { ----- begin row scope methods -----
1340   NS_IMETHOD RowScopeHasAssignedIds(
1341       nsIMdbEnv* ev,
1342       mdb_scope inRowScope,         // row scope for row ids
1343       mdb_bool* outCallerAssigned,  // nonzero if caller assigned specified
1344       mdb_bool* outStoreAssigned) =
1345       0;  // nonzero if store db assigned specified
1346 
1347   NS_IMETHOD SetCallerAssignedIds(
1348       nsIMdbEnv* ev,
1349       mdb_scope inRowScope,         // row scope for row ids
1350       mdb_bool* outCallerAssigned,  // nonzero if caller assigned specified
1351       mdb_bool* outStoreAssigned) =
1352       0;  // nonzero if store db assigned specified
1353 
1354   NS_IMETHOD SetStoreAssignedIds(
1355       nsIMdbEnv* ev,
1356       mdb_scope inRowScope,         // row scope for row ids
1357       mdb_bool* outCallerAssigned,  // nonzero if caller assigned specified
1358       mdb_bool* outStoreAssigned) =
1359       0;  // nonzero if store db assigned specified
1360   // } ----- end row scope methods -----
1361 
1362   // { ----- begin row methods -----
1363   NS_IMETHOD NewRowWithOid(nsIMdbEnv* ev,  // new row w/ caller assigned oid
1364                            const mdbOid* inOid,      // caller assigned oid
1365                            nsIMdbRow** acqRow) = 0;  // create new row
1366 
1367   NS_IMETHOD NewRow(nsIMdbEnv* ev,            // new row with db assigned oid
1368                     mdb_scope inRowScope,     // row scope for row ids
1369                     nsIMdbRow** acqRow) = 0;  // create new row
1370   // Note this row must be added to some table or cell child before the
1371   // store is closed in order to make this row persist across sessions.
1372 
1373   // } ----- end row methods -----
1374 
1375   // { ----- begin import/export methods -----
1376   NS_IMETHOD ImportContent(         // import content from port
1377       nsIMdbEnv* ev,                // context
1378       mdb_scope inRowScope,         // scope for rows (or zero for all?)
1379       nsIMdbPort* ioPort,           // the port with content to add to store
1380       nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental import
1381   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1382   // then the import will be finished.
1383 
1384   NS_IMETHOD ImportFile(            // import content from port
1385       nsIMdbEnv* ev,                // context
1386       nsIMdbFile* ioFile,           // the file with content to add to store
1387       nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental import
1388   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1389   // then the import will be finished.
1390   // } ----- end import/export methods -----
1391 
1392   // { ----- begin hinting methods -----
1393   NS_IMETHOD
1394   ShareAtomColumnsHint(       // advise re shared column content atomizing
1395       nsIMdbEnv* ev,          // context
1396       mdb_scope inScopeHint,  // zero, or suggested shared namespace
1397       const mdbColumnSet* inColumnSet) = 0;  // cols desired tokenized together
1398 
1399   NS_IMETHOD
1400   AvoidAtomColumnsHint(  // advise column with poor atomizing prospects
1401       nsIMdbEnv* ev,     // context
1402       const mdbColumnSet* inColumnSet) =
1403       0;  // cols with poor atomizing prospects
1404   // } ----- end hinting methods -----
1405 
1406   // { ----- begin commit methods -----
1407   NS_IMETHOD LargeCommit(           // save important changes if at all possible
1408       nsIMdbEnv* ev,                // context
1409       nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental commit
1410   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1411   // then the commit will be finished.  Note the store is effectively write
1412   // locked until commit is finished or canceled through the thumb instance.
1413   // Until the commit is done, the store will report it has readonly status.
1414 
1415   NS_IMETHOD SessionCommit(         // save all changes if large commits delayed
1416       nsIMdbEnv* ev,                // context
1417       nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental commit
1418   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1419   // then the commit will be finished.  Note the store is effectively write
1420   // locked until commit is finished or canceled through the thumb instance.
1421   // Until the commit is done, the store will report it has readonly status.
1422 
1423   NS_IMETHOD
1424   CompressCommit(     // commit and make db physically smaller if possible
1425       nsIMdbEnv* ev,  // context
1426       nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental commit
1427   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1428   // then the commit will be finished.  Note the store is effectively write
1429   // locked until commit is finished or canceled through the thumb instance.
1430   // Until the commit is done, the store will report it has readonly status.
1431 
1432   // } ----- end commit methods -----
1433 
1434   // } ===== end nsIMdbStore methods =====
1435 };
1436 
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbStore,NS_IMDBSTORE_IID)1437 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbStore, NS_IMDBSTORE_IID)
1438 
1439 /*| nsIMdbCursor: base cursor class for iterating row cells and table rows
1440 **|
1441 **|| count: the number of elements in the collection (table or row)
1442 **|
1443 **|| seed: the change count in the underlying collection, which is synced
1444 **| with the collection when the iteration position is set, and henceforth
1445 **| acts to show whether the iter has lost collection synchronization, in
1446 **| case it matters to clients whether any change happens during iteration.
1447 **|
1448 **|| pos: the position of the current element in the collection.  Negative
1449 **| means a position logically before the first element.  A positive value
1450 **| equal to count (or larger) implies a position after the last element.
1451 **| To iterate over all elements, set the position to negative, so subsequent
1452 **| calls to any 'next' method will access the first collection element.
1453 **|
1454 **|| doFailOnSeedOutOfSync: whether a cursor should return an error if the
1455 **| cursor's snapshot of a table's seed becomes stale with respect the table's
1456 **| current seed value (which implies the iteration is less than total) in
1457 **| between to cursor calls that actually access collection content.  By
1458 **| default, a cursor should assume this attribute is false until specified,
1459 **| so that iterations quietly try to re-sync when they lose coherence.
1460 |*/
1461 
1462 #define NS_IMDBCURSOR_IID_STR "a0c37337-6ebc-474c-90db-e65ea0b850aa"
1463 
1464 #define NS_IMDBCURSOR_IID                            \
1465   {                                                  \
1466     0xa0c37337, 0x6ebc, 0x474c, {                    \
1467       0x90, 0xdb, 0xe6, 0x5e, 0xa0, 0xb8, 0x50, 0xaa \
1468     }                                                \
1469   }
1470 
1471 class nsIMdbCursor : public nsISupports {  // collection iterator
1472  public:
1473   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBCURSOR_IID)
1474   // { ===== begin nsIMdbCursor methods =====
1475 
1476   // { ----- begin attribute methods -----
1477   NS_IMETHOD GetCount(nsIMdbEnv* ev, mdb_count* outCount) = 0;  // readonly
1478   NS_IMETHOD GetSeed(nsIMdbEnv* ev, mdb_seed* outSeed) = 0;     // readonly
1479 
1480   NS_IMETHOD SetPos(nsIMdbEnv* ev, mdb_pos inPos) = 0;  // mutable
1481   NS_IMETHOD GetPos(nsIMdbEnv* ev, mdb_pos* outPos) = 0;
1482 
1483   NS_IMETHOD SetDoFailOnSeedOutOfSync(nsIMdbEnv* ev, mdb_bool inFail) = 0;
1484   NS_IMETHOD GetDoFailOnSeedOutOfSync(nsIMdbEnv* ev, mdb_bool* outFail) = 0;
1485   // } ----- end attribute methods -----
1486 
1487   // } ===== end nsIMdbCursor methods =====
1488 };
1489 
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbCursor,NS_IMDBCURSOR_IID)1490 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbCursor, NS_IMDBCURSOR_IID)
1491 
1492 #define NS_IMDBPORTTABLECURSOR_IID_STR = "f181a41e-933d-49b3-af93-20d3634b8b78"
1493 
1494 #define NS_IMDBPORTTABLECURSOR_IID                   \
1495   {                                                  \
1496     0xf181a41e, 0x933d, 0x49b3, {                    \
1497       0xaf, 0x93, 0x20, 0xd3, 0x63, 0x4b, 0x8b, 0x78 \
1498     }                                                \
1499   }
1500 
1501 /*| nsIMdbPortTableCursor: cursor class for iterating port tables
1502 **|
1503 **|| port: the cursor is associated with a specific port, which can be
1504 **| set to a different port (which resets the position to -1 so the
1505 **| next table acquired is the first in the port.
1506 **|
1507 |*/
1508 class nsIMdbPortTableCursor : public nsISupports {  // table collection iterator
1509  public:
1510   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBPORTTABLECURSOR_IID)
1511   // { ===== begin nsIMdbPortTableCursor methods =====
1512 
1513   // { ----- begin attribute methods -----
1514   NS_IMETHOD SetPort(nsIMdbEnv* ev, nsIMdbPort* ioPort) = 0;  // sets pos to -1
1515   NS_IMETHOD GetPort(nsIMdbEnv* ev, nsIMdbPort** acqPort) = 0;
1516 
1517   NS_IMETHOD SetRowScope(nsIMdbEnv* ev,  // sets pos to -1
1518                          mdb_scope inRowScope) = 0;
1519   NS_IMETHOD GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope) = 0;
1520   // setting row scope to zero iterates over all row scopes in port
1521 
1522   NS_IMETHOD SetTableKind(nsIMdbEnv* ev,  // sets pos to -1
1523                           mdb_kind inTableKind) = 0;
1524   NS_IMETHOD GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind) = 0;
1525   // setting table kind to zero iterates over all table kinds in row scope
1526   // } ----- end attribute methods -----
1527 
1528   // { ----- begin table iteration methods -----
1529   NS_IMETHOD NextTable(             // get table at next position in the db
1530       nsIMdbEnv* ev,                // context
1531       nsIMdbTable** acqTable) = 0;  // the next table in the iteration
1532   // } ----- end table iteration methods -----
1533 
1534   // } ===== end nsIMdbPortTableCursor methods =====
1535 };
1536 
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbPortTableCursor,NS_IMDBPORTTABLECURSOR_IID)1537 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbPortTableCursor, NS_IMDBPORTTABLECURSOR_IID)
1538 
1539 /*| nsIMdbCollection: an object that collects a set of other objects as members.
1540 **| The main purpose of this base class is to unify the perceived semantics
1541 **| of tables and rows where their collection behavior is similar.  This helps
1542 **| isolate the mechanics of collection behavior from the other semantics that
1543 **| are more characteristic of rows and tables.
1544 **|
1545 **|| count: the number of objects in a collection is the member count. (Some
1546 **| collection interfaces call this attribute the 'size', but that can be a
1547 **| little ambiguous, and counting actual members is harder to confuse.)
1548 **|
1549 **|| seed: the seed of a collection is a counter for changes in membership in
1550 **| a specific collection.  This seed should change when members are added to
1551 **| or removed from a collection, but not when a member changes internal state.
1552 **| The seed should also change whenever the internal collection of members has
1553 **| a complex state change that reorders member positions (say by sorting) that
1554 **| would affect the nature of an iteration over that collection of members.
1555 **| The purpose of a seed is to inform any outstanding collection cursors that
1556 **| they might be stale, without incurring the cost of broadcasting an event
1557 **| notification to such cursors, which would need more data structure support.
1558 **| Presumably a cursor in a particular mdb code suite has much more direct
1559 **| access to a collection seed member slot that this abstract COM interface,
1560 **| so this information is intended more for clients outside mdb that want to
1561 **| make inferences similar to those made by the collection cursors.  The seed
1562 **| value as an integer magnitude is not very important, and callers should not
1563 **| assume meaningful information can be derived from an integer value beyond
1564 **| whether it is equal or different from a previous inspection.  A seed uses
1565 **| integers of many bits in order to make the odds of wrapping and becoming
1566 **| equal to an earlier seed value have probability that is vanishingly small.
1567 **|
1568 **|| port: every collection is associated with a specific database instance.
1569 **|
1570 **|| cursor: a subclass of nsIMdbCursor suitable for this specific collection
1571 **| subclass.  The ability to GetCursor() from the base nsIMdbCollection class
1572 **| is not really as useful as getting a more specifically typed cursor more
1573 **| directly from the base class without any casting involved.  So including
1574 **| this method here is more for conceptual illustration.
1575 **|
1576 **|| oid: every collection has an identity that persists from session to
1577 **| session. Implementations are probably able to distinguish row IDs from
1578 **| table IDs, but we don't specify anything official in this regard.  A
1579 **| collection has the same identity for the lifetime of the collection,
1580 **| unless identity is swapped with another collection by means of a call to
1581 **| BecomeContent(), which is considered a way to swap a new representation
1582 **| for an old well-known object.  (Even so, only content appears to change,
1583 **| while the identity seems to stay the same.)
1584 **|
1585 **|| become: developers can effectively cause two objects to swap identities,
1586 **| in order to effect a complete swap between what persistent content is
1587 **| represented by two oids.  The caller should consider this a content swap,
1588 **| and not identity wap, because identities will seem to stay the same while
1589 **| only content changes.  However, implementations will likely do this
1590 **| internally by swapping identities.  Callers must swap content only
1591 **| between objects of similar type, such as a row with another row, and a
1592 **| table with another table, because implementations need not support
1593 **| cross-object swapping because it might break object name spaces.
1594 **|
1595 **|| dropping: when a caller expects a row or table will no longer be used, the
1596 **| caller can tell the collection to 'drop activity', which means the runtime
1597 **| object can have its internal representation purged to save memory or any
1598 **| other resource that is being consumed by the collection's representation.
1599 **| This has no effect on the collection's persistent content or semantics,
1600 **| and is only considered a runtime effect.  After a collection drops
1601 **| activity, the object should still be as usable as before (because it has
1602 **| NOT been closed), but further usage can be expensive to re-instate because
1603 **| it might involve reallocating space and/or re-reading disk space.  But
1604 **| since this future usage is not expected, the caller does not expect to
1605 **| pay the extra expense.  An implementation can choose to implement
1606 **| 'dropping activity' in different ways, or even not at all if this
1607 **| operation is not really feasible.  Callers cannot ask objects whether they
1608 **| are 'dropped' or not, so this should be transparent. (Note that
1609 **| implementors might fear callers do not really know whether future
1610 **| usage will occur, and therefore might delay the act of dropping until
1611 **| the near future, until seeing whether the object is used again
1612 **| immediately elsewhere. Such use soon after the drop request might cause
1613 **| the drop to be cancelled.)
1614 |*/
1615 class nsIMdbCollection : public nsISupports {  // sequence of objects
1616  public:
1617   // { ===== begin nsIMdbCollection methods =====
1618 
1619   // { ----- begin attribute methods -----
1620   NS_IMETHOD GetSeed(nsIMdbEnv* ev,
1621                      mdb_seed* outSeed) = 0;  // member change count
1622   NS_IMETHOD GetCount(nsIMdbEnv* ev,
1623                       mdb_count* outCount) = 0;  // member count
1624 
1625   NS_IMETHOD GetPort(nsIMdbEnv* ev,
1626                      nsIMdbPort** acqPort) = 0;  // collection container
1627   // } ----- end attribute methods -----
1628 
1629   // { ----- begin cursor methods -----
1630   NS_IMETHOD GetCursor(     // make a cursor starting iter at inMemberPos
1631       nsIMdbEnv* ev,        // context
1632       mdb_pos inMemberPos,  // zero-based ordinal pos of member in collection
1633       nsIMdbCursor** acqCursor) = 0;  // acquire new cursor instance
1634   // } ----- end cursor methods -----
1635 
1636   // { ----- begin ID methods -----
1637   NS_IMETHOD GetOid(nsIMdbEnv* ev,
1638                     mdbOid* outOid) = 0;  // read object identity
1639   NS_IMETHOD BecomeContent(nsIMdbEnv* ev,
1640                            const mdbOid* inOid) = 0;  // exchange content
1641   // } ----- end ID methods -----
1642 
1643   // { ----- begin activity dropping methods -----
1644   NS_IMETHOD DropActivity(  // tell collection usage no longer expected
1645       nsIMdbEnv* ev) = 0;
1646   // } ----- end activity dropping methods -----
1647 
1648   // } ===== end nsIMdbCollection methods =====
1649 };
1650 
1651 /*| nsIMdbTable: an ordered collection of rows
1652 **|
1653 **|| row scope: an integer token for an atomized string in this database
1654 **| that names a space for row IDs.  This attribute of a table is intended
1655 **| as guidance metainformation that helps with searching a database for
1656 **| tables that operate on collections of rows of the specific type.  By
1657 **| convention, a table with a specific row scope is expected to focus on
1658 **| containing rows that belong to that scope, however exceptions are easily
1659 **| allowed because all rows in a table are known by both row ID and scope.
1660 **| (A table with zero row scope is never allowed because this would make it
1661 **| ambiguous to use a zero row scope when iterating over tables in a port to
1662 **| indicate that all row scopes should be seen by a cursor.)
1663 **|
1664 **|| table kind: an integer token for an atomized string in this database
1665 **| that names a kind of table as a subset of the associated row scope. This
1666 **| attribute is intended as guidance metainformation to clarify the role of
1667 **| this table with respect to other tables in the same row scope, and this
1668 **| also helps search for such tables in a database.  By convention, a table
1669 **| with a specific table kind has a consistent role for containing rows with
1670 **| respect to other collections of such rows in the same row scope.  Also by
1671 **| convention, at least one table in a row scope has a table kind purporting
1672 **| to contain ALL the rows that belong in that row scope, so that at least
1673 **| one table exists that allows all rows in a scope to be iterated over.
1674 **| (A table with zero table kind is never allowed because this would make it
1675 **| ambiguous to use a zero table kind when iterating over tables in a port to
1676 **| indicate that all table kinds in a row scope should be seen by a cursor.)
1677 **|
1678 **|| port: every table is considered part of some port that contains the
1679 **| table, so that closing the containing port will cause the table to be
1680 **| indirectly closed as well.  We make it easy to get the containing port for
1681 **| a table, because the port supports important semantic interfaces that will
1682 **| affect how content in table is presented; the most important port context
1683 **| that affects a table is specified by the set of token to string mappings
1684 **| that affect all tokens used throughout the database, and which drive the
1685 **| meanings of row scope, table kind, cell columns, etc.
1686 **|
1687 **|| cursor: a cursor that iterates over the rows in this table, where rows
1688 **| have zero-based index positions from zero to count-1.  Making a cursor
1689 **| with negative position will next iterate over the first row in the table.
1690 **|
1691 **|| position: given any position from zero to count-1, a table will return
1692 **| the row ID and row scope for the row at that position.  (One can use the
1693 **| GetRowAllCells() method to read that row, or else use a row cursor to both
1694 **| get the row at some position and read its content at the same time.)  The
1695 **| position depends on whether a table is sorted, and upon the actual sort.
1696 **| Note that moving a row's position is only possible in unsorted tables.
1697 **|
1698 **|| row set: every table contains a collection of rows, where a member row is
1699 **| referenced by the table using the row ID and row scope for the row.  No
1700 **| single table owns a given row instance, because rows are effectively ref-
1701 **| counted and destroyed only when the last table removes a reference to that
1702 **| particular row.  (But a row can be emptied of all content no matter how
1703 **| many refs exist, and this might be the next best thing to destruction.)
1704 **| Once a row exists in a least one table (after NewRow() is called), then it
1705 **| can be added to any other table by calling AddRow(), or removed from any
1706 **| table by calling CutRow(), or queried as a member by calling HasRow().  A
1707 **| row can only be added to a table once, and further additions do nothing and
1708 **| complain not at all.  Cutting a row from a table only does something when
1709 **| the row was actually a member, and otherwise does nothing silently.
1710 **|
1711 **|| row ref count: one can query the number of tables (and/or cells)
1712 **| containing a row as a member or a child.
1713 **|
1714 **|| row content: one can access or modify the cell content in a table's row
1715 **| by moving content to or from an instance of nsIMdbRow.  Note that nsIMdbRow
1716 **| never represents the actual row inside a table, and this is the reason
1717 **| why nsIMdbRow instances do not have row IDs or row scopes.  So an instance
1718 **| of nsIMdbRow always and only contains a snapshot of some or all content in
1719 **| past, present, or future persistent row inside a table.  This means that
1720 **| reading and writing rows in tables has strictly copy semantics, and we
1721 **| currently do not plan any exceptions for specific performance reasons.
1722 **|
1723 **|| sorting: note all rows are assumed sorted by row ID as a secondary
1724 **| sort following the primary column sort, when table rows are sorted.
1725 **|
1726 **|| indexes:
1727 |*/
1728 
1729 #define NS_IMDBTABLE_IID_STR = "fe11bc98-d02b-4128-9fac-87042fdf9639"
1730 
1731 #define NS_IMDBTABLE_IID                             \
1732   {                                                  \
1733     0xfe11bc98, 0xd02b, 0x4128, {                    \
1734       0x9f, 0xac, 0x87, 0x04, 0x2f, 0xdf, 0x96, 0x39 \
1735     }                                                \
1736   }
1737 
1738 class nsIMdbTable : public nsIMdbCollection {  // a collection of rows
1739  public:
1740   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBTABLE_IID)
1741   // { ===== begin nsIMdbTable methods =====
1742 
1743   // { ----- begin meta attribute methods -----
1744   NS_IMETHOD SetTablePriority(nsIMdbEnv* ev, mdb_priority inPrio) = 0;
1745   NS_IMETHOD GetTablePriority(nsIMdbEnv* ev, mdb_priority* outPrio) = 0;
1746 
1747   NS_IMETHOD GetTableBeVerbose(nsIMdbEnv* ev, mdb_bool* outBeVerbose) = 0;
1748   NS_IMETHOD SetTableBeVerbose(nsIMdbEnv* ev, mdb_bool inBeVerbose) = 0;
1749 
1750   NS_IMETHOD GetTableIsUnique(nsIMdbEnv* ev, mdb_bool* outIsUnique) = 0;
1751 
1752   NS_IMETHOD GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind) = 0;
1753   NS_IMETHOD GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope) = 0;
1754 
1755   NS_IMETHOD GetMetaRow(
1756       nsIMdbEnv* ev,                       // context
1757       const mdbOid* inOptionalMetaRowOid,  // can be nil to avoid specifying
1758       mdbOid* outOid,  // output meta row oid, can be nil to suppress output
1759       nsIMdbRow** acqRow) = 0;  // acquire table's unique singleton meta row
1760   // The purpose of a meta row is to support the persistent recording of
1761   // meta info about a table as cells put into the distinguished meta row.
1762   // Each table has exactly one meta row, which is not considered a member
1763   // of the collection of rows inside the table.  The only way to tell
1764   // whether a row is a meta row is by the fact that it is returned by this
1765   // GetMetaRow() method from some table. Otherwise nothing distinguishes
1766   // a meta row from any other row.  A meta row can be used anyplace that
1767   // any other row can be used, and can even be put into other tables (or
1768   // the same table) as a table member, if this is useful for some reason.
1769   // The first attempt to access a table's meta row using GetMetaRow() will
1770   // cause the meta row to be created if it did not already exist.  When the
1771   // meta row is created, it will have the row oid that was previously
1772   // requested for this table's meta row; or if no oid was ever explicitly
1773   // specified for this meta row, then a unique oid will be generated in
1774   // the row scope named "m" (so obviously MDB clients should not
1775   // manually allocate any row IDs from that special meta scope namespace).
1776   // The meta row oid can be specified either when the table is created, or
1777   // else the first time that GetMetaRow() is called, by passing a non-nil
1778   // pointer to an oid for parameter inOptionalMetaRowOid.  The meta row's
1779   // actual oid is returned in outOid (if this is a non-nil pointer), and
1780   // it will be different from inOptionalMetaRowOid when the meta row was
1781   // already given a different oid earlier.
1782   // } ----- end meta attribute methods -----
1783 
1784   // { ----- begin cursor methods -----
1785   NS_IMETHOD
1786   GetTableRowCursor(     // make a cursor, starting iteration at inRowPos
1787       nsIMdbEnv* ev,     // context
1788       mdb_pos inRowPos,  // zero-based ordinal position of row in table
1789       nsIMdbTableRowCursor** acqCursor) = 0;  // acquire new cursor instance
1790   // } ----- end row position methods -----
1791 
1792   // { ----- begin row position methods -----
1793   NS_IMETHOD PosToOid(      // get row member for a table position
1794       nsIMdbEnv* ev,        // context
1795       mdb_pos inRowPos,     // zero-based ordinal position of row in table
1796       mdbOid* outOid) = 0;  // row oid at the specified position
1797 
1798   NS_IMETHOD OidToPos(       // test for the table position of a row member
1799       nsIMdbEnv* ev,         // context
1800       const mdbOid* inOid,   // row to find in table
1801       mdb_pos* outPos) = 0;  // zero-based ordinal position of row in table
1802 
1803   NS_IMETHOD PosToRow(          // test for the table position of a row member
1804       nsIMdbEnv* ev,            // context
1805       mdb_pos inRowPos,         // zero-based ordinal position of row in table
1806       nsIMdbRow** acqRow) = 0;  // acquire row at table position inRowPos
1807 
1808   NS_IMETHOD RowToPos(       // test for the table position of a row member
1809       nsIMdbEnv* ev,         // context
1810       nsIMdbRow* ioRow,      // row to find in table
1811       mdb_pos* outPos) = 0;  // zero-based ordinal position of row in table
1812   // } ----- end row position methods -----
1813 
1814   // { ----- begin oid set methods -----
1815   NS_IMETHOD AddOid(  // make sure the row with inOid is a table member
1816       nsIMdbEnv* ev,  // context
1817       const mdbOid* inOid) = 0;  // row to ensure membership in table
1818 
1819   NS_IMETHOD HasOid(             // test for the table position of a row member
1820       nsIMdbEnv* ev,             // context
1821       const mdbOid* inOid,       // row to find in table
1822       mdb_bool* outHasOid) = 0;  // whether inOid is a member row
1823 
1824   NS_IMETHOD CutOid(             // make sure the row with inOid is not a member
1825       nsIMdbEnv* ev,             // context
1826       const mdbOid* inOid) = 0;  // row to remove from table
1827   // } ----- end oid set methods -----
1828 
1829   // { ----- begin row set methods -----
1830   NS_IMETHOD NewRow(  // create a new row instance in table
1831       nsIMdbEnv* ev,  // context
1832       mdbOid*
1833           ioOid,  // please use minus one (unbound) rowId for db-assigned IDs
1834       nsIMdbRow** acqRow) = 0;  // create new row
1835 
1836   NS_IMETHOD AddRow(          // make sure the row with inOid is a table member
1837       nsIMdbEnv* ev,          // context
1838       nsIMdbRow* ioRow) = 0;  // row to ensure membership in table
1839 
1840   NS_IMETHOD HasRow(             // test for the table position of a row member
1841       nsIMdbEnv* ev,             // context
1842       nsIMdbRow* ioRow,          // row to find in table
1843       mdb_bool* outHasRow) = 0;  // whether row is a table member
1844 
1845   NS_IMETHOD CutRow(          // make sure the row with inOid is not a member
1846       nsIMdbEnv* ev,          // context
1847       nsIMdbRow* ioRow) = 0;  // row to remove from table
1848 
1849   NS_IMETHOD CutAllRows(   // remove all rows from the table
1850       nsIMdbEnv* ev) = 0;  // context
1851   // } ----- end row set methods -----
1852 
1853   // { ----- begin hinting methods -----
1854   NS_IMETHOD SearchColumnsHint(  // advise re future expected search cols
1855       nsIMdbEnv* ev,             // context
1856       const mdbColumnSet* inColumnSet) = 0;  // columns likely to be searched
1857 
1858   NS_IMETHOD SortColumnsHint(  // advise re future expected sort columns
1859       nsIMdbEnv* ev,           // context
1860       const mdbColumnSet* inColumnSet) = 0;  // columns for likely sort requests
1861 
1862   NS_IMETHOD StartBatchChangeHint(  // advise before many adds and cuts
1863       nsIMdbEnv* ev,                // context
1864       const void* inLabel) = 0;     // intend unique address to match end call
1865   // If batch starts nest by virtue of nesting calls in the stack, then
1866   // the address of a local variable makes a good batch start label that
1867   // can be used at batch end time, and such addresses remain unique.
1868 
1869   NS_IMETHOD EndBatchChangeHint(  // advise before many adds and cuts
1870       nsIMdbEnv* ev,              // context
1871       const void* inLabel) = 0;   // label matching start label
1872   // Suppose a table is maintaining one or many sort orders for a table,
1873   // so that every row added to the table must be inserted in each sort,
1874   // and every row cut must be removed from each sort.  If a db client
1875   // intends to make many such changes before needing any information
1876   // about the order or positions of rows inside a table, then a client
1877   // might tell the table to start batch changes in order to disable
1878   // sorting of rows for the interim.  Presumably a table will then do
1879   // a full sort of all rows at need when the batch changes end, or when
1880   // a surprise request occurs for row position during batch changes.
1881   // } ----- end hinting methods -----
1882 
1883   // { ----- begin searching methods -----
1884   NS_IMETHOD FindRowMatches(  // search variable number of sorted cols
1885       nsIMdbEnv* ev,          // context
1886       const mdbYarn*
1887           inPrefix,  // content to find as prefix in row's column cell
1888       nsIMdbTableRowCursor** acqCursor) = 0;  // set of matching rows
1889 
1890   NS_IMETHOD GetSearchColumns(       // query columns used by FindRowMatches()
1891       nsIMdbEnv* ev,                 // context
1892       mdb_count* outCount,           // context
1893       mdbColumnSet* outColSet) = 0;  // caller supplied space to put columns
1894   // GetSearchColumns() returns the columns actually searched when the
1895   // FindRowMatches() method is called.  No more than mColumnSet_Count
1896   // slots of mColumnSet_Columns will be written, since mColumnSet_Count
1897   // indicates how many slots are present in the column array.  The
1898   // actual number of search column used by the table is returned in
1899   // the outCount parameter; if this number exceeds mColumnSet_Count,
1900   // then a caller needs a bigger array to read the entire column set.
1901   // The minimum of mColumnSet_Count and outCount is the number slots
1902   // in mColumnSet_Columns that were actually written by this method.
1903   //
1904   // Callers are expected to change this set of columns by calls to
1905   // nsIMdbTable::SearchColumnsHint() or SetSearchSorting(), or both.
1906   // } ----- end searching methods -----
1907 
1908   // { ----- begin sorting methods -----
1909   // sorting: note all rows are assumed sorted by row ID as a secondary
1910   // sort following the primary column sort, when table rows are sorted.
1911 
1912   NS_IMETHOD
1913   CanSortColumn(            // query which column is currently used for sorting
1914       nsIMdbEnv* ev,        // context
1915       mdb_column inColumn,  // column to query sorting potential
1916       mdb_bool* outCanSort) = 0;  // whether the column can be sorted
1917 
1918   NS_IMETHOD GetSorting(    // view same table in particular sorting
1919       nsIMdbEnv* ev,        // context
1920       mdb_column inColumn,  // requested new column for sorting table
1921       nsIMdbSorting** acqSorting) = 0;  // acquire sorting for column
1922 
1923   NS_IMETHOD SetSearchSorting(  // use this sorting in FindRowMatches()
1924       nsIMdbEnv* ev,            // context
1925       mdb_column inColumn,      // often same as nsIMdbSorting::GetSortColumn()
1926       nsIMdbSorting* ioSorting) = 0;  // requested sorting for some column
1927   // SetSearchSorting() attempts to inform the table that ioSorting
1928   // should be used during calls to FindRowMatches() for searching
1929   // the column which is actually sorted by ioSorting.  This method
1930   // is most useful in conjunction with nsIMdbSorting::SetCompare(),
1931   // because otherwise a caller would not be able to override the
1932   // comparison ordering method used during searches.  Note that some
1933   // database implementations might be unable to use an arbitrarily
1934   // specified sort order, either due to schema or runtime interface
1935   // constraints, in which case ioSorting might not actually be used.
1936   // Presumably ioSorting is an instance that was returned from some
1937   // earlier call to nsIMdbTable::GetSorting().  A caller can also
1938   // use nsIMdbTable::SearchColumnsHint() to specify desired change
1939   // in which columns are sorted and searched by FindRowMatches().
1940   //
1941   // A caller can pass a nil pointer for ioSorting to request that
1942   // column inColumn no longer be used at all by FindRowMatches().
1943   // But when ioSorting is non-nil, then inColumn should match the
1944   // column actually sorted by ioSorting; when these do not agree,
1945   // implementations are instructed to give precedence to the column
1946   // specified by ioSorting (so this means callers might just pass
1947   // zero for inColumn when ioSorting is also provided, since then
1948   // inColumn is both redundant and ignored).
1949   // } ----- end sorting methods -----
1950 
1951   // { ----- begin moving methods -----
1952   // moving a row does nothing unless a table is currently unsorted
1953 
1954   NS_IMETHOD MoveOid(              // change position of row in unsorted table
1955       nsIMdbEnv* ev,               // context
1956       const mdbOid* inOid,         // row oid to find in table
1957       mdb_pos inHintFromPos,       // suggested hint regarding start position
1958       mdb_pos inToPos,             // desired new position for row inRowId
1959       mdb_pos* outActualPos) = 0;  // actual new position of row in table
1960 
1961   NS_IMETHOD MoveRow(              // change position of row in unsorted table
1962       nsIMdbEnv* ev,               // context
1963       nsIMdbRow* ioRow,            // row oid to find in table
1964       mdb_pos inHintFromPos,       // suggested hint regarding start position
1965       mdb_pos inToPos,             // desired new position for row inRowId
1966       mdb_pos* outActualPos) = 0;  // actual new position of row in table
1967   // } ----- end moving methods -----
1968 
1969   // { ----- begin index methods -----
1970   NS_IMETHOD AddIndex(      // create a sorting index for column if possible
1971       nsIMdbEnv* ev,        // context
1972       mdb_column inColumn,  // the column to sort by index
1973       nsIMdbThumb** acqThumb) =
1974       0;  // acquire thumb for incremental index building
1975   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1976   // then the index addition will be finished.
1977 
1978   NS_IMETHOD CutIndex(      // stop supporting a specific column index
1979       nsIMdbEnv* ev,        // context
1980       mdb_column inColumn,  // the column with index to be removed
1981       nsIMdbThumb** acqThumb) =
1982       0;  // acquire thumb for incremental index destroy
1983   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
1984   // then the index removal will be finished.
1985 
1986   NS_IMETHOD HasIndex(      // query for current presence of a column index
1987       nsIMdbEnv* ev,        // context
1988       mdb_column inColumn,  // the column to investigate
1989       mdb_bool* outHasIndex) = 0;  // whether column has index for this column
1990 
1991   NS_IMETHOD EnableIndexOnSort(  // create an index for col on first sort
1992       nsIMdbEnv* ev,             // context
1993       mdb_column inColumn) = 0;  // the column to index if ever sorted
1994 
1995   NS_IMETHOD QueryIndexOnSort(  // check whether index on sort is enabled
1996       nsIMdbEnv* ev,            // context
1997       mdb_column inColumn,      // the column to investigate
1998       mdb_bool* outIndexOnSort) =
1999       0;  // whether column has index-on-sort enabled
2000 
2001   NS_IMETHOD DisableIndexOnSort(  // prevent future index creation on sort
2002       nsIMdbEnv* ev,              // context
2003       mdb_column inColumn) = 0;   // the column to index if ever sorted
2004   // } ----- end index methods -----
2005 
2006   // } ===== end nsIMdbTable methods =====
2007 };
2008 
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbTable,NS_IMDBTABLE_IID)2009 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbTable, NS_IMDBTABLE_IID)
2010 
2011 /*| nsIMdbSorting: a view of a table in some particular sort order.  This
2012 **| row order closely resembles a readonly array of rows with the same row
2013 **| membership as the underlying table, but in a different order than the
2014 **| table's explicit row order.  But the sorting's row membership changes
2015 **| whenever the table's membership changes (without any notification, so
2016 **| keep this in mind when modifying the table).
2017 **|
2018 **|| table: every sorting is associated with a particular table.  You
2019 **| cannot change which table is used by a sorting (just ask some new
2020 **| table for a suitable sorting instance instead).
2021 **|
2022 **|| compare: the ordering method used by a sorting, wrapped up in a
2023 **| abstract plug-in interface.  When this was never installed by an
2024 **| explicit call to SetNewCompare(), a compare object is still returned,
2025 **| and it might match the compare instance returned by the factory method
2026 **| nsIMdbFactory::MakeCompare(), which represents a default sort order
2027 **| (which we fervently hope is consistently ASCII byte ordering).
2028 **|
2029 **|| cursor: in case callers are more comfortable with a cursor style
2030 **| of accessing row members, each sorting will happily return a cursor
2031 **| instance with behavior very similar to a cursor returned from a call
2032 **| to nsIMdbTable::GetTableRowCursor(), but with different row order.
2033 **| A cursor should show exactly the same information as the pos methods.
2034 **|
2035 **|| pos: the PosToOid() and PosToRow() methods are just like the table
2036 **| methods of the same name, except they show rows in the sort order of
2037 **| the sorting, rather than that of the table.  These methods are like
2038 **| readonly array position accessor's, or like a C++ operator[].
2039 |*/
2040 class nsIMdbSorting : public nsIMdbObject {  // sorting of some table
2041  public:
2042   // { ===== begin nsIMdbSorting methods =====
2043 
2044   // { ----- begin attribute methods -----
2045   // sorting: note all rows are assumed sorted by row ID as a secondary
2046   // sort following the primary column sort, when table rows are sorted.
2047 
2048   NS_IMETHOD GetTable(nsIMdbEnv* ev, nsIMdbTable** acqTable) = 0;
2049   NS_IMETHOD GetSortColumn(        // query which col is currently sorted
2050       nsIMdbEnv* ev,               // context
2051       mdb_column* outColumn) = 0;  // col the table uses for sorting (or zero)
2052 
2053   // } ----- end attribute methods -----
2054 
2055   // { ----- begin cursor methods -----
2056   NS_IMETHOD GetSortingRowCursor(  // make a cursor, starting at inRowPos
2057       nsIMdbEnv* ev,               // context
2058       mdb_pos inRowPos,  // zero-based ordinal position of row in table
2059       nsIMdbTableRowCursor** acqCursor) = 0;  // acquire new cursor instance
2060   // A cursor interface turning same info as PosToOid() or PosToRow().
2061   // } ----- end row position methods -----
2062 
2063   // { ----- begin row position methods -----
2064   NS_IMETHOD PosToOid(      // get row member for a table position
2065       nsIMdbEnv* ev,        // context
2066       mdb_pos inRowPos,     // zero-based ordinal position of row in table
2067       mdbOid* outOid) = 0;  // row oid at the specified position
2068 
2069   NS_IMETHOD PosToRow(          // test for the table position of a row member
2070       nsIMdbEnv* ev,            // context
2071       mdb_pos inRowPos,         // zero-based ordinal position of row in table
2072       nsIMdbRow** acqRow) = 0;  // acquire row at table position inRowPos
2073   // } ----- end row position methods -----
2074 
2075   // } ===== end nsIMdbSorting methods =====
2076 };
2077 
2078 /*| nsIMdbTableRowCursor: cursor class for iterating table rows
2079 **|
2080 **|| table: the cursor is associated with a specific table, which can be
2081 **| set to a different table (which resets the position to -1 so the
2082 **| next row acquired is the first in the table.
2083 **|
2084 **|| NextRowId: the rows in the table can be iterated by identity alone,
2085 **| without actually reading the cells of any row with this method.
2086 **|
2087 **|| NextRowCells: read the next row in the table, but only read cells
2088 **| from the table which are already present in the row (so no new cells
2089 **| are added to the row, even if they are present in the table).  All the
2090 **| cells will have content specified, even it is the empty string.  No
2091 **| columns will be removed, even if missing from the row (because missing
2092 **| and empty are semantically equivalent).
2093 **|
2094 **|| NextRowAllCells: read the next row in the table, and access all the
2095 **| cells for this row in the table, adding any missing columns to the row
2096 **| as needed until all cells are represented.  All the
2097 **| cells will have content specified, even it is the empty string.  No
2098 **| columns will be removed, even if missing from the row (because missing
2099 **| and empty are semantically equivalent).
2100 **|
2101 |*/
2102 
2103 #define NS_IMDBTABLEROWCURSOR_IID_STR = "4f325dad-0385-4b62-a992-c914ab93587e"
2104 
2105 #define NS_IMDBTABLEROWCURSOR_IID                    \
2106   {                                                  \
2107     0x4f325dad, 0x0385, 0x4b62, {                    \
2108       0xa9, 0x92, 0xc9, 0x14, 0xab, 0x93, 0x58, 0x7e \
2109     }                                                \
2110   }
2111 
2112 class nsIMdbTableRowCursor : public nsISupports {  // table row iterator
2113  public:
2114   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBTABLEROWCURSOR_IID)
2115 
2116   // { ===== begin nsIMdbTableRowCursor methods =====
2117 
2118   // { ----- begin attribute methods -----
2119   // NS_IMETHOD SetTable(nsIMdbEnv* ev, nsIMdbTable* ioTable) = 0; // sets pos
2120   // to -1 Method SetTable() cut and made obsolete in keeping with new sorting
2121   // methods.
2122 
2123   NS_IMETHOD GetTable(nsIMdbEnv* ev, nsIMdbTable** acqTable) = 0;
2124   // } ----- end attribute methods -----
2125 
2126   // { ----- begin duplicate row removal methods -----
2127   NS_IMETHOD CanHaveDupRowMembers(nsIMdbEnv* ev,  // cursor might hold dups?
2128                                   mdb_bool* outCanHaveDups) = 0;
2129 
2130   NS_IMETHOD MakeUniqueCursor(  // clone cursor, removing duplicate rows
2131       nsIMdbEnv* ev,            // context
2132       nsIMdbTableRowCursor** acqCursor) = 0;  // acquire clone with no dups
2133   // Note that MakeUniqueCursor() is never necessary for a cursor which was
2134   // created by table method nsIMdbTable::GetTableRowCursor(), because a table
2135   // never contains the same row as a member more than once.  However, a cursor
2136   // created by table method nsIMdbTable::FindRowMatches() might contain the
2137   // same row more than once, because the same row can generate a hit by more
2138   // than one column with a matching string prefix.  Note this method can
2139   // return the very same cursor instance with just an incremented refcount,
2140   // when the original cursor could not contain any duplicate rows (calling
2141   // CanHaveDupRowMembers() shows this case on a false return).  Otherwise
2142   // this method returns a different cursor instance.  Callers should not use
2143   // this MakeUniqueCursor() method lightly, because it tends to defeat the
2144   // purpose of lazy programming techniques, since it can force creation of
2145   // an explicit row collection in a new cursor's representation, in order to
2146   // inspect the row membership and remove any duplicates; this can have big
2147   // impact if a collection holds tens of thousands of rows or more, when
2148   // the original cursor with dups simply referenced rows indirectly by row
2149   // position ranges, without using an explicit row set representation.
2150   // Callers are encouraged to use nsIMdbCursor::GetCount() to determine
2151   // whether the row collection is very large (tens of thousands), and to
2152   // delay calling MakeUniqueCursor() when possible, until a user interface
2153   // element actually demands the creation of an explicit set representation.
2154   // } ----- end duplicate row removal methods -----
2155 
2156   // { ----- begin oid iteration methods -----
2157   NS_IMETHOD NextRowOid(        // get row id of next row in the table
2158       nsIMdbEnv* ev,            // context
2159       mdbOid* outOid,           // out row oid
2160       mdb_pos* outRowPos) = 0;  // zero-based position of the row in table
2161   // } ----- end oid iteration methods -----
2162 
2163   // { ----- begin row iteration methods -----
2164   NS_IMETHOD NextRow(      // get row cells from table for cells already in row
2165       nsIMdbEnv* ev,       // context
2166       nsIMdbRow** acqRow,  // acquire next row in table
2167       mdb_pos* outRowPos) = 0;  // zero-based position of the row in table
2168 
2169   NS_IMETHOD PrevRowOid(        // get row id of previous row in the table
2170       nsIMdbEnv* ev,            // context
2171       mdbOid* outOid,           // out row oid
2172       mdb_pos* outRowPos) = 0;  // zero-based position of the row in table
2173   // } ----- end oid iteration methods -----
2174 
2175   // { ----- begin row iteration methods -----
2176   NS_IMETHOD PrevRow(      // get row cells from table for cells already in row
2177       nsIMdbEnv* ev,       // context
2178       nsIMdbRow** acqRow,  // acquire previous row in table
2179       mdb_pos* outRowPos) = 0;  // zero-based position of the row in table
2180 
2181   // } ----- end row iteration methods -----
2182 
2183   // { ----- begin copy iteration methods -----
2184   // NS_IMETHOD NextRowCopy( // put row cells into sink only when already in
2185   // sink
2186   //   nsIMdbEnv* ev, // context
2187   //   nsIMdbRow* ioSinkRow, // sink for row cells read from next row
2188   //   mdbOid* outOid, // out row oid
2189   //   mdb_pos* outRowPos) = 0;    // zero-based position of the row in table
2190   //
2191   // NS_IMETHOD NextRowCopyAll( // put all row cells into sink, adding to sink
2192   //   nsIMdbEnv* ev, // context
2193   //   nsIMdbRow* ioSinkRow, // sink for row cells read from next row
2194   //   mdbOid* outOid, // out row oid
2195   //   mdb_pos* outRowPos) = 0;    // zero-based position of the row in table
2196   // } ----- end copy iteration methods -----
2197 
2198   // } ===== end nsIMdbTableRowCursor methods =====
2199 };
2200 
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbTableRowCursor,NS_IMDBTABLEROWCURSOR_IID)2201 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbTableRowCursor, NS_IMDBTABLEROWCURSOR_IID)
2202 
2203 /*| nsIMdbRow: a collection of cells
2204 **|
2205 |*/
2206 
2207 #define NS_IMDBROW_IID_STR "271e8d6e-183a-40e3-9f18-36913b4c7853"
2208 
2209 #define NS_IMDBROW_IID                               \
2210   {                                                  \
2211     0x271e8d6e, 0x183a, 0x40e3, {                    \
2212       0x9f, 0x18, 0x36, 0x91, 0x3b, 0x4c, 0x78, 0x53 \
2213     }                                                \
2214   }
2215 
2216 class nsIMdbRow : public nsIMdbCollection {  // cell tuple
2217  public:
2218   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBROW_IID)
2219   // { ===== begin nsIMdbRow methods =====
2220 
2221   // { ----- begin cursor methods -----
2222   NS_IMETHOD GetRowCellCursor(  // make a cursor starting iteration at inCellPos
2223       nsIMdbEnv* ev,            // context
2224       mdb_pos inCellPos,        // zero-based ordinal position of cell in row
2225       nsIMdbRowCellCursor** acqCursor) = 0;  // acquire new cursor instance
2226   // } ----- end cursor methods -----
2227 
2228   // { ----- begin column methods -----
2229   NS_IMETHOD AddColumn(     // make sure a particular column is inside row
2230       nsIMdbEnv* ev,        // context
2231       mdb_column inColumn,  // column to add
2232       const mdbYarn* inYarn) = 0;  // cell value to install
2233 
2234   NS_IMETHOD CutColumn(          // make sure a column is absent from the row
2235       nsIMdbEnv* ev,             // context
2236       mdb_column inColumn) = 0;  // column to ensure absent from row
2237 
2238   NS_IMETHOD CutAllColumns(  // remove all columns from the row
2239       nsIMdbEnv* ev) = 0;    // context
2240   // } ----- end column methods -----
2241 
2242   // { ----- begin cell methods -----
2243   NS_IMETHOD NewCell(       // get cell for specified column, or add new one
2244       nsIMdbEnv* ev,        // context
2245       mdb_column inColumn,  // column to add
2246       nsIMdbCell** acqCell) = 0;  // cell column and value
2247 
2248   NS_IMETHOD AddCell(  // copy a cell from another row to this row
2249       nsIMdbEnv* ev,   // context
2250       const nsIMdbCell* inCell) = 0;  // cell column and value
2251 
2252   NS_IMETHOD GetCell(             // find a cell in this row
2253       nsIMdbEnv* ev,              // context
2254       mdb_column inColumn,        // column to find
2255       nsIMdbCell** acqCell) = 0;  // cell for specified column, or null
2256 
2257   NS_IMETHOD EmptyAllCells(  // make all cells in row empty of content
2258       nsIMdbEnv* ev) = 0;    // context
2259   // } ----- end cell methods -----
2260 
2261   // { ----- begin row methods -----
2262   NS_IMETHOD AddRow(                // add all cells in another row to this one
2263       nsIMdbEnv* ev,                // context
2264       nsIMdbRow* ioSourceRow) = 0;  // row to union with
2265 
2266   NS_IMETHOD SetRow(                // make exact duplicate of another row
2267       nsIMdbEnv* ev,                // context
2268       nsIMdbRow* ioSourceRow) = 0;  // row to duplicate
2269   // } ----- end row methods -----
2270 
2271   // { ----- begin blob methods -----
2272   NS_IMETHOD SetCellYarn(nsIMdbEnv* ev,               // synonym for AddColumn()
2273                          mdb_column inColumn,         // column to write
2274                          const mdbYarn* inYarn) = 0;  // reads from yarn slots
2275   // make this text object contain content from the yarn's buffer
2276 
2277   NS_IMETHOD GetCellYarn(nsIMdbEnv* ev,
2278                          mdb_column inColumn,    // column to read
2279                          mdbYarn* outYarn) = 0;  // writes some yarn slots
2280   // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
2281 
2282   NS_IMETHOD AliasCellYarn(nsIMdbEnv* ev,
2283                            mdb_column inColumn,    // column to alias
2284                            mdbYarn* outYarn) = 0;  // writes ALL yarn slots
2285 
2286   NS_IMETHOD NextCellYarn(nsIMdbEnv* ev,  // iterative version of GetCellYarn()
2287                           mdb_column* ioColumn,   // next column to read
2288                           mdbYarn* outYarn) = 0;  // writes some yarn slots
2289   // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
2290   //
2291   // The ioColumn argument is an inout parameter which initially contains the
2292   // last column accessed and returns the next column corresponding to the
2293   // content read into the yarn.  Callers should start with a zero column
2294   // value to say 'no previous column', which causes the first column to be
2295   // read.  Then the value returned in ioColumn is perfect for the next call
2296   // to NextCellYarn(), since it will then be the previous column accessed.
2297   // Callers need only examine the column token returned to see which cell
2298   // in the row is being read into the yarn.  When no more columns remain,
2299   // and the iteration has ended, ioColumn will return a zero token again.
2300   // So iterating over cells starts and ends with a zero column token.
2301 
2302   NS_IMETHOD SeekCellYarn(    // resembles nsIMdbRowCellCursor::SeekCell()
2303       nsIMdbEnv* ev,          // context
2304       mdb_pos inPos,          // position of cell in row sequence
2305       mdb_column* outColumn,  // column for this particular cell
2306       mdbYarn* outYarn) = 0;  // writes some yarn slots
2307   // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
2308   // Callers can pass nil for outYarn to indicate no interest in content, so
2309   // only the outColumn value is returned.  NOTE to subclasses: you must be
2310   // able to ignore outYarn when the pointer is nil; please do not crash.
2311 
2312   // } ----- end blob methods -----
2313 
2314   // } ===== end nsIMdbRow methods =====
2315 };
2316 
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbRow,NS_IMDBROW_IID)2317 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbRow, NS_IMDBROW_IID)
2318 
2319 /*| nsIMdbRowCellCursor: cursor class for iterating row cells
2320 **|
2321 **|| row: the cursor is associated with a specific row, which can be
2322 **| set to a different row (which resets the position to -1 so the
2323 **| next cell acquired is the first in the row.
2324 **|
2325 **|| NextCell: get the next cell in the row and return its position and
2326 **| a new instance of a nsIMdbCell to represent this next cell.
2327 |*/
2328 
2329 #define NS_IMDBROWCELLCURSOR_IID_STR "b33371a7-5d63-4d10-85a8-e44dffe75c28"
2330 
2331 #define NS_IMDBROWCELLCURSOR_IID                     \
2332   {                                                  \
2333     0x271e8d6e, 0x5d63, 0x4d10, {                    \
2334       0x85, 0xa8, 0xe4, 0x4d, 0xff, 0xe7, 0x5c, 0x28 \
2335     }                                                \
2336   }
2337 
2338 class nsIMdbRowCellCursor : public nsISupports {  // cell collection iterator
2339  public:
2340   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBROWCELLCURSOR_IID)
2341   // { ===== begin nsIMdbRowCellCursor methods =====
2342 
2343   // { ----- begin attribute methods -----
2344   NS_IMETHOD SetRow(nsIMdbEnv* ev, nsIMdbRow* ioRow) = 0;  // sets pos to -1
2345   NS_IMETHOD GetRow(nsIMdbEnv* ev, nsIMdbRow** acqRow) = 0;
2346   // } ----- end attribute methods -----
2347 
2348   // { ----- begin cell seeking methods -----
2349   NS_IMETHOD SeekCell(nsIMdbEnv* ev,  // context
2350                       mdb_pos inPos,  // position of cell in row sequence
2351                       mdb_column* outColumn,  // column for this particular cell
2352                       nsIMdbCell** acqCell) = 0;  // the cell at inPos
2353   // } ----- end cell seeking methods -----
2354 
2355   // { ----- begin cell iteration methods -----
2356   NS_IMETHOD NextCell(        // get next cell in the row
2357       nsIMdbEnv* ev,          // context
2358       nsIMdbCell** acqCell,   // changes to the next cell in the iteration
2359       mdb_column* outColumn,  // column for this particular cell
2360       mdb_pos* outPos) = 0;   // position of cell in row sequence
2361 
2362   NS_IMETHOD PickNextCell(  // get next cell in row within filter set
2363       nsIMdbEnv* ev,        // context
2364       nsIMdbCell* ioCell,   // changes to the next cell in the iteration
2365       const mdbColumnSet* inFilterSet,  // col set of actual caller interest
2366       mdb_column* outColumn,            // column for this particular cell
2367       mdb_pos* outPos) = 0;             // position of cell in row sequence
2368 
2369   // Note that inFilterSet should not have too many (many more than 10?)
2370   // cols, since this might imply a potential excessive consumption of time
2371   // over many cursor calls when looking for column and filter intersection.
2372   // } ----- end cell iteration methods -----
2373 
2374   // } ===== end nsIMdbRowCellCursor methods =====
2375 };
2376 
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbRowCellCursor,NS_IMDBROWCELLCURSOR_IID)2377 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbRowCellCursor, NS_IMDBROWCELLCURSOR_IID)
2378 
2379 /*| nsIMdbBlob: a base class for objects composed mainly of byte sequence state.
2380 **| (This provides a base class for nsIMdbCell, so that cells themselves can
2381 **| be used to set state in another cell, without extracting a buffer.)
2382 |*/
2383 class nsIMdbBlob : public nsISupports {  // a string with associated charset
2384  public:
2385   // { ===== begin nsIMdbBlob methods =====
2386 
2387   // { ----- begin attribute methods -----
2388   NS_IMETHOD SetBlob(nsIMdbEnv* ev,
2389                      nsIMdbBlob* ioBlob) = 0;  // reads inBlob slots
2390   // when inBlob is in the same suite, this might be fastest cell-to-cell
2391 
2392   NS_IMETHOD ClearBlob(  // make empty (so content has zero length)
2393       nsIMdbEnv* ev) = 0;
2394   // clearing a yarn is like SetYarn() with empty yarn instance content
2395 
2396   NS_IMETHOD GetBlobFill(nsIMdbEnv* ev,
2397                          mdb_fill* outFill) = 0;  // size of blob
2398   // Same value that would be put into mYarn_Fill, if one called GetYarn()
2399   // with a yarn instance that had mYarn_Buf==nil and mYarn_Size==0.
2400 
2401   NS_IMETHOD SetYarn(nsIMdbEnv* ev,
2402                      const mdbYarn* inYarn) = 0;  // reads from yarn slots
2403   // make this text object contain content from the yarn's buffer
2404 
2405   NS_IMETHOD GetYarn(nsIMdbEnv* ev,
2406                      mdbYarn* outYarn) = 0;  // writes some yarn slots
2407   // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
2408 
2409   NS_IMETHOD AliasYarn(nsIMdbEnv* ev,
2410                        mdbYarn* outYarn) = 0;  // writes ALL yarn slots
2411   // AliasYarn() reveals sensitive internal text buffer state to the caller
2412   // by setting mYarn_Buf to point into the guts of this text implementation.
2413   //
2414   // The caller must take great care to avoid writing on this space, and to
2415   // avoid calling any method that would cause the state of this text object
2416   // to change (say by directly or indirectly setting the text to hold more
2417   // content that might grow the size of the buffer and free the old buffer).
2418   // In particular, callers should scrupulously avoid making calls into the
2419   // mdb interface to write any content while using the buffer pointer found
2420   // in the returned yarn instance.  Best safe usage involves copying content
2421   // into some other kind of external content representation beyond mdb.
2422   //
2423   // (The original design of this method a week earlier included the concept
2424   // of very fast and efficient cooperative locking via a pointer to some lock
2425   // member slot.  But let's ignore that complexity in the current design.)
2426   //
2427   // AliasYarn() is specifically intended as the first step in transferring
2428   // content from nsIMdbBlob to a nsString representation, without forcing extra
2429   // allocations and/or memory copies. (A standard nsIMdbBlob_AsString() utility
2430   // will use AliasYarn() as the first step in setting a nsString instance.)
2431   //
2432   // This is an alternative to the GetYarn() method, which has copy semantics
2433   // only; AliasYarn() relaxes a robust safety principle only for performance
2434   // reasons, to accommodate the need for callers to transform text content to
2435   // some other canonical representation that would necessitate an additional
2436   // copy and transformation when such is incompatible with the mdbYarn format.
2437   //
2438   // The implementation of AliasYarn() should have extremely little overhead
2439   // besides the virtual dispatch to the method implementation, and the code
2440   // necessary to populate all the mdbYarn member slots with internal buffer
2441   // address and metainformation that describes the buffer content.  Note that
2442   // mYarn_Grow must always be set to nil to indicate no resizing is allowed.
2443 
2444   // } ----- end attribute methods -----
2445 
2446   // } ===== end nsIMdbBlob methods =====
2447 };
2448 
2449 /*| nsIMdbCell: the text in a single column of a row.  The base nsIMdbBlob
2450 **| class provides all the interface related to accessing cell text.
2451 **|
2452 **|| column: each cell in a row appears in a specific column, where this
2453 **| column is identified by the an integer mdb_scope value (generated by
2454 **| the StringToScopeToken() method in the containing nsIMdbPort instance).
2455 **| Because a row cannot have more than one cell with the same column,
2456 **| something must give if one calls SetColumn() with an existing column
2457 **| in the same row. When this happens, the other cell is replaced with
2458 **| this cell (and the old cell is closed if it has outstanding refs).
2459 **|
2460 **|| row: every cell instance is a part of some row, and every cell knows
2461 **| which row is the parent row.  (Note this should be represented by a
2462 **| weak backpointer, so that outstanding cell references cannot keep a
2463 **| row open that should be closed. Otherwise we'd have ref graph cycles.)
2464 **|
2465 **|| text: a cell can either be text, or it can have a child row or table,
2466 **| but not both at once.  If text is read from a cell with a child, the text
2467 **| content should be empty (for AliasYarn()) or a description of the type
2468 **| of child (perhaps "mdb:cell:child:row" or "mdb:cell:child:table").
2469 **|
2470 **|| child: a cell might reference another row or a table, rather than text.
2471 **| The interface for putting and getting children rows and tables was first
2472 **| defined in the nsIMdbTable interface, but then this was moved to this cell
2473 **| interface as more natural.
2474 |*/
2475 
2476 #define NS_IMDBCELL_IID                              \
2477   {                                                  \
2478     0xa3b62f71, 0xa181, 0x4a91, {                    \
2479       0xb6, 0x6b, 0x27, 0x10, 0x9b, 0x88, 0x98, 0x35 \
2480     }                                                \
2481   }
2482 
2483 #define NS_IMDBCELL_IID_STR = "a3b62f71-a181-4a91-b66b-27109b889835"
2484 
2485 class nsIMdbCell
2486     : public nsIMdbBlob {  // text attribute in row with column scope
2487  public:
2488   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBTABLEROWCURSOR_IID)
2489   // { ===== begin nsIMdbCell methods =====
2490 
2491   // { ----- begin attribute methods -----
2492   NS_IMETHOD SetColumn(nsIMdbEnv* ev, mdb_column inColumn) = 0;
2493   NS_IMETHOD GetColumn(nsIMdbEnv* ev, mdb_column* outColumn) = 0;
2494 
2495   NS_IMETHOD GetCellInfo(  // all cell metainfo except actual content
2496       nsIMdbEnv* ev,
2497       mdb_column* outColumn,         // the column in the containing row
2498       mdb_fill* outBlobFill,         // the size of text content in bytes
2499       mdbOid* outChildOid,           // oid of possible row or table child
2500       mdb_bool* outIsRowChild) = 0;  // nonzero if child, and a row child
2501 
2502   // Checking all cell metainfo is a good way to avoid forcing a large cell
2503   // in to memory when you don't actually want to use the content.
2504 
2505   NS_IMETHOD GetRow(nsIMdbEnv* ev,  // parent row for this cell
2506                     nsIMdbRow** acqRow) = 0;
2507   NS_IMETHOD GetPort(nsIMdbEnv* ev,  // port containing cell
2508                      nsIMdbPort** acqPort) = 0;
2509   // } ----- end attribute methods -----
2510 
2511   // { ----- begin children methods -----
2512   NS_IMETHOD HasAnyChild(  // does cell have a child instead of text?
2513       nsIMdbEnv* ev,
2514       mdbOid* outOid,  // out id of row or table (or unbound if no child)
2515       mdb_bool* outIsRow) =
2516       0;  // nonzero if child is a row (rather than a table)
2517 
2518   NS_IMETHOD GetAnyChild(           // access table of specific attribute
2519       nsIMdbEnv* ev,                // context
2520       nsIMdbRow** acqRow,           // child row (or null)
2521       nsIMdbTable** acqTable) = 0;  // child table (or null)
2522 
2523   NS_IMETHOD SetChildRow(     // access table of specific attribute
2524       nsIMdbEnv* ev,          // context
2525       nsIMdbRow* ioRow) = 0;  // inRow must be bound inside this same db port
2526 
2527   NS_IMETHOD GetChildRow(       // access row of specific attribute
2528       nsIMdbEnv* ev,            // context
2529       nsIMdbRow** acqRow) = 0;  // acquire child row (or nil if no child)
2530 
2531   NS_IMETHOD SetChildTable(  // access table of specific attribute
2532       nsIMdbEnv* ev,         // context
2533       nsIMdbTable* inTable) =
2534       0;  // table must be bound inside this same db port
2535 
2536   NS_IMETHOD GetChildTable(         // access table of specific attribute
2537       nsIMdbEnv* ev,                // context
2538       nsIMdbTable** acqTable) = 0;  // acquire child table (or nil if no child)
2539   // } ----- end children methods -----
2540 
2541   // } ===== end nsIMdbCell methods =====
2542 };
2543 
2544 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbCell, NS_IMDBTABLEROWCURSOR_IID)
2545 
2546 // } %%%%% end C++ abstract class interfaces %%%%%
2547 
2548 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
2549 
2550 #endif /* _MDB_ */
2551