OOFILE  1.9
oofctre1.cpp
Go to the documentation of this file.
1 // OOFILE c-tree Plus backend implementation
2 //
3 // COPYRIGHT 1994 A.D. Software, All rights reserved
4 
5 #include "oofpch_c.h" // for precompilation of core files
6 
7 #ifndef H_OOFIOS
8  #include "oofios.h"
9 #endif
10 #ifndef H_OOFctreeX
11  #include "oofctrex.h"
12 #endif
13 #ifndef H_OOFWORDS
14  #include "oofwords.h"
15 #endif
16 #ifndef H_OOFFILES
17  #include "ooffiles.h"
18 #endif
19 #ifdef _Macintosh
20  #ifdef _Macintosh_Carbon
21  #include <carbon/carbon.h>
22  #else
23  #include <Events.h>
24  #endif
25 #endif
26 #ifndef H_OOFEXCEP
27  #include "oofexcep.h"
28 #endif
29 
30 #ifdef OOF_MEM_DEBUG_LAST_INCLUDE
31  #include OOF_MEM_DEBUG_LAST_INCLUDE
32 #endif
33 
34 #ifndef OOF_NO_STDLIB
35  #ifndef std
36  using namespace std;
37  #endif
38 #endif
39 
40 // -------------------------------------------------------
41 // O O F _ c t r e e I n d e x S e g L i s t
42 // -------------------------------------------------------
43 OOF_ctreeIndexSegList::OOF_ctreeIndexSegList(COUNT indexFileNo, const dbCompoundField* indexField) :
44  mIndexFileNo(indexFileNo),
45  mIndexField(indexField)
46 {
47  mSegmentFieldNos = new fieldNumT[2]; // guarantee at least two indexes!
48  assert(mSegmentFieldNos);
49  mSegmentFieldNos[0] = USHRT_MAX;
50  mSegmentFieldNos[1] = USHRT_MAX;
51 }
52 
53 
55 {
56  delete[] mSegmentFieldNos;
57 }
58 
59 
60 void
62 {
63  unsigned int numSlots = sizeof(mSegmentFieldNos)/sizeof(unsigned short);
64  for (unsigned int i=0; i<numSlots; i++) {
65  if (mSegmentFieldNos[i]==USHRT_MAX) { // can't use 0 as it is a valid field No
66  mSegmentFieldNos[i]=fieldNo;
67  return; // exit without expanding
68  }
69  }
70 // if get here have to expand the array
71 
72  fieldNumT* newArray = new fieldNumT[numSlots+1]; // not many indices so don't chunk
73  assert(newArray);
74  for (unsigned int j=0; j<numSlots; j++) {
75  newArray[j] = mSegmentFieldNos[j];
76  }
77  newArray[numSlots]=fieldNo;
78  delete[] mSegmentFieldNos;
79  mSegmentFieldNos = newArray;
80 }
81 
82 
83 bool
84 OOF_ctreeIndexSegList::startsWith(unsigned long pairOfFieldNos) const
85 {
86  unsigned long firstPair = (mSegmentFieldNos[0]<<16)+mSegmentFieldNos[1];
87  return (firstPair==pairOfFieldNos);
88 }
89 
90 
91 
92 // -------------------------------------------------------
93 // O O F _ c t r e e I n d e x D i c t i o n a r y
94 // -------------------------------------------------------
95 OOF_ctreeIndexDictionary::OOF_ctreeIndexDictionary()
96 {
97  ownsContents(); // unlike many other dictionaries
98 }
99 
100 
101 COUNT
102 OOF_ctreeIndexDictionary::indexStartingWithField(fieldNumT fldNo, bool wantReverse, const dbField* &compoundField) const
103 {
104  unsigned int numSlots = count();
105  for (unsigned int i=0; i<numSlots; i++) {
106  const OOF_ctreeIndexSegList* segs = (const OOF_ctreeIndexSegList*) value(i); // safe downcast
107  if (segs->startsWith(fldNo)) // starts with field
108  if (segs->indexField()->segment(0)->isReversed()==wantReverse) { // in correct order
109  compoundField = segs->indexField();
110  return segs->indexFileNo();
111  }
112  }
113  return 0; // failure
114 }
115 
116 
117 const dbCompoundField*
118 OOF_ctreeIndexDictionary::fieldMatchingPair(unsigned long combinedFldNo) const
119 {
120  unsigned int numSlots = count();
121  for (unsigned int i=0; i<numSlots; i++) {
122  const OOF_ctreeIndexSegList* segs = (const OOF_ctreeIndexSegList*) value(i); // safe downcast
123  if (segs->startsWith(combinedFldNo))
124  return segs->indexField();
125  }
126  return 0; // failure
127 }
128 
129 
130 // -------------------------------------------------------
131 // O O F _ c t r e e K e y w o r d I n d e x
132 // -------------------------------------------------------
133 
135  mTable(0)
136 {
137 }
138 
139 
141 {
142  delete mTable;
143 }
144 
145 
146 void
148 {
149  mFieldNos.append(n);
150 }
151 
152 
153 void
155 {
156  mTable = new OOF_ctreeKeywordTable(parentTable->tableName()+"Words");
157 }
158 
159 
160 bool
162 {
163  bool ret = mFieldNos.contains(inFieldNum);
164  return ret;
165 }
166 
167 
168 void
169 OOF_ctreeKeywordIndex::FinishSearch(dbTable* schTable) const
170 {
171  if (mTable->isEmpty())
172  schTable->selectNone();
173  else {
174  // optimisation of relateSelection - build selection directly from our OIDs
175  OOF_recordSelection result( schTable->prototype() );
176  unsigned long numRecs = mTable->count();
177  mTable->start();
178  for (unsigned long i=0; i<numRecs; i++) {
179  unsigned long oid = mTable->OID;
180  if (!result.contains(oid))
181  result.append(oid);
182  mTable->next();
183  } // loop maybe adding recs
184  schTable->setSelection(&result);
185  }
186 }
187 
188 
189 void
190 OOF_ctreeKeywordIndex::FinishSearchAny(dbTable* schTable, OOF_recordSelection& newSelection) const
191 {
192 // use the result combined selection
193  mTable->setSelection(&newSelection);
194  if (mTable->isEmpty())
195  schTable->selectNone();
196  else {
197  // optimisation of relateSelection - build selection directly from our OIDs
198  OOF_recordSelection result( schTable->prototype() );
199  unsigned long numRecs = mTable->count();
200  mTable->start();
201  for (unsigned long i=0; i<numRecs; i++) {
202  unsigned long oid = mTable->OID;
203  if (!result.contains(oid))
204  result.append(oid);
205  mTable->next();
206  } // loop maybe adding recs
207  schTable->setSelection(&result);
208  }
209 }
210 
211 
212 void
213 OOF_ctreeKeywordIndex::searchField(dbTable* schTable, fieldNumT inFieldNum, const char* schWord, bool startsWith) const
214 {
215  assert(indexesField(inFieldNum)); // just in case
216  if (startsWith)
217  mTable->search( mTable->mainIndex.startsWith(schWord) && mTable->FieldNo == (unsigned short)inFieldNum);
218  else
219  mTable->search( mTable->Word == schWord && mTable->FieldNo == (unsigned short)inFieldNum);
220 
221  FinishSearch(schTable);
222 }
223 
224 
225 void
226 OOF_ctreeKeywordIndex::searchFieldAllWords(dbTable* schTable, fieldNumT inFieldNum, dbQueryLiteralStrMultiValue* schWords, bool startsWith) const
227 {
228 
229  assert(indexesField(inFieldNum)); // just in case
230 
231  // Make a new selection which becomes the intersection of records
232  // found by each keyword in turn
233 
234  // so first word creates initial selection
235  // and user can optimise by having least likely words first, so if
236  // get empty result, don't bother with rest of searches
237  schWords->start();
238  const char* schWord = schWords->current();
239  searchField(schTable, inFieldNum, schWord, startsWith);
240  dbSelection firstSel = schTable->currentSelection(); // avoid problems with temporary
241  OOF_recordSelection* firstRecs = (OOF_recordSelection*) firstSel.internalSelection(); // DANGEROUS downcast - may break if every have other than OOF_RecordSelection
242  OOF_recordSelection newSelection = *firstRecs;
243 
244 
245  for(schWords->next(); schWords->more() && !newSelection.isEmpty(); schWords->next()){ // for all other words
246  const char* schWord = schWords->current();
247  searchField(schTable, inFieldNum, schWord, startsWith);
248  dbSelection nextSel = schTable->currentSelection();
249  newSelection.intersection_with(nextSel.internalSelection());
250  }
251 
252  schTable->setSelection(&newSelection);
253 }
254 
255 
256 void
257 OOF_ctreeKeywordIndex::searchFieldAnyWords(dbTable* schTable, fieldNumT inFieldNum, dbQueryLiteralStrMultiValue* schWords, bool startsWith) const
258 {
259  assert(indexesField(inFieldNum)); // just in case
260 
261  // Make a new selection which grows to contain all the keywords found
262  OOF_recordSelection newSelection( mTable->prototype() );
263 
264  for(schWords->start(); schWords->more(); schWords->next()){ // for all words
265  const char* schWord = schWords->current();
266  if (startsWith)
267  mTable->search( mTable->mainIndex.startsWith(schWord) && mTable->FieldNo == (unsigned short)inFieldNum);
268  else
269  mTable->search( mTable->Word == schWord && mTable->FieldNo == (unsigned short)inFieldNum);
270  newSelection.union_with(mTable->currentSelection().internalSelection());
271  }
272  FinishSearchAny(schTable, newSelection);
273 }
274 
275 
276 
277 
278 void
279 OOF_ctreeKeywordIndex::searchTable(dbTable* schTable, const char* schWord, bool startsWith) const
280 {
281  if (startsWith)
282  mTable->search( mTable->mainIndex.startsWith(schWord));
283  else
284  mTable->search( mTable->Word == schWord);
285  FinishSearch(schTable);
286 }
287 
288 
289 void
291 {
292  // Make a new selection which becomes the intersection of records
293  // found by each keyword in turn
294 
295  // so first word creates initial selection
296  // and user can optimise by having least likely words first, so if
297  // get empty result, don't bother with rest of searches
298  schWords->start();
299  const char* schWord = schWords->current();
300  searchTable(schTable, schWord, startsWith);
301  dbSelection firstSel = schTable->currentSelection(); // avoid problems with temporary
302  OOF_recordSelection* firstRecs = (OOF_recordSelection*) firstSel.internalSelection(); // DANGEROUS downcast - may break if every have other than OOF_RecordSelection
303  OOF_recordSelection newSelection = *firstRecs;
304 
305 
306  for(schWords->next(); schWords->more() && !newSelection.isEmpty(); schWords->next()){ // for all other words
307  const char* schWord = schWords->current();
308  searchTable(schTable, schWord, startsWith);
309  dbSelection nextSel = schTable->currentSelection();
310  newSelection.intersection_with(nextSel.internalSelection());
311  }
312 
313  schTable->setSelection(&newSelection);
314 }
315 
316 
317 void
319 {
320  // Make a new selection which grows to contain all the keywords found
321  OOF_recordSelection newSelection( mTable->prototype() );
322 
323  for(schWords->start(); schWords->more(); schWords->next()){ // for all words
324  const char* schWord = schWords->current();
325  if (startsWith)
326  mTable->search( mTable->mainIndex.startsWith(schWord));
327  else
328  mTable->search( mTable->Word == schWord);
329  newSelection.union_with(mTable->currentSelection().internalSelection());
330  }
331  FinishSearchAny(schTable, newSelection);
332 }
333 
334 
335 void
337 {
338  mTable->search( mTable->OID == currOID && mTable->FieldNo == (unsigned short)fldNo);
339  mTable->deleteSelection();
340 }
341 
342 
343 void
345 {
346  mTable->search( mTable->OID == currOID);
347  mTable->deleteSelection();
348 }
349 
350 
351 void
352 OOF_ctreeKeywordIndex::updateWords(dbTable* inTable, bool isNew, const OOF_dirtyFieldMap& dirtyMap)
353 {
354  oidT currOID = inTable->currentOID();
355  for (mFieldNos.start();mFieldNos.more();mFieldNos.next()) { // Iteration through the fields
356  fieldNumT fldNo = mFieldNos();
357  if (dirtyMap.isDirty(fldNo)) {
358  if (!isNew)
359  deleteWords(currOID, fldNo);
360  dbField* theField = inTable->field(fldNo);
361  if (!theField->isEmpty()) {
362  oofWordParser* wp = theField->words();
363  OOF_WordList wordsToIndex;
364  for (wp->start(theField->asChars()); wp->more(); wp->next()) { // Iteration through the field's words
365  const char* theWord = wp->word();
366  if (theWord && *theWord && !wordsToIndex.contains(theWord)) { // check if null string
367  wordsToIndex.append(theWord);
368  addRecordForOID(theWord, fldNo, currOID);
369  }
370  } // word loop
371  } // non-empty field
372  } // dirty field
373  } // record loop
374 }
375 
376 
377 void
378 OOF_ctreeKeywordIndex::addRecordForOID(const char* theWord, fieldNumT fldNum, oidT currOID)
379 {
380  mTable->newRecord();
381  mTable->Word = theWord;
382  mTable->FieldNo = fldNum;
383  mTable->OID = currOID;
384  mTable->saveRecord();
385 }
386 
387 
388 void
390 {
391  mTable->rebuild();
392 }
393 
394 
395 void
397 {
398  mTable->suppressIndices();
399 }
400 
401 
402 void
404 {
405  mTable->close();
406 }
407 
408 
409 void
411 {
412  mTable->deleteStorage();
413 }
414 
415 // -------------------------------------------------------
416 // O O F _ c t r e e B a c k e n d
417 // see also oofctre2.cpp & oofctre3.cpp
418 // -------------------------------------------------------
419 
420 OOF_ctreeBackend::OOF_ctreeBackend(dbTable* theTable, dbConnect_ctree* connection):
421  OOF_simpleRecordBackend(theTable),
422  mConnection(connection),
423  mFieldCtreeMap(0),
424  mFieldCtreeMapRefCount(0),
425  mIndicesSuppressed(false),
426 /*
427  mDataExt(".dat"),
428  mIndexExt(".idx")
429 */
430  mKeywordIndex(0),
431  mUniqueFieldNums(0)
432 {
433  mIFIL.ix = 0;
434 };
435 
436 
437 OOF_ctreeBackend::OOF_ctreeBackend(const OOF_ctreeBackend& rhs, dbTable::selSharingT selSharing, dbTable* theTable) :
438  OOF_simpleRecordBackend(rhs, selSharing, theTable),
439  mConnection(rhs.mConnection),
440  mFieldCtreeMap(rhs.mFieldCtreeMap),
441  mFieldCtreeMapRefCount(rhs.mFieldCtreeMapRefCount),
442  mBlobFilNo(rhs.mBlobFilNo),
443  mISAMdatno(rhs.mISAMdatno),
444  mIFIL(rhs.mIFIL),
445  mIndicesSuppressed(rhs.mIndicesSuppressed),
446  mFileName(rhs.mFileName),
447  mDataExt(rhs.mDataExt),
448  mIndexExt(rhs.mIndexExt),
449  mKeywordIndex(rhs.mKeywordIndex),
450  mUniqueFieldNums(rhs.mUniqueFieldNums)
451 {
452  *mFieldCtreeMapRefCount +=1;
453  if (mKeywordIndex)
454  mKeywordIndex->incRefs();
455  if (mUniqueFieldNums)
456  mUniqueFieldNums->incRefs();
457 }
458 
459 
461 {
462  DeleteIIDX(); // call this before the mFieldCtreeMapRefCount decrement!
463  if (mFieldCtreeMapRefCount) { // in case never created database!
464  if (*mFieldCtreeMapRefCount <= 1) {
465  delete[] mFieldCtreeMap;
466  delete mFieldCtreeMapRefCount;
467  }
468  else
469  *mFieldCtreeMapRefCount -= 1;
470  }
471  if (mKeywordIndex)
472  mKeywordIndex->decRefs();
473  if (mUniqueFieldNums)
474  mUniqueFieldNums->decRefs();
475 }
476 
477 
478 void
479 OOF_ctreeBackend::LockCollisionWait() const
480 {
481 #ifdef _Macintosh
482  long attemptedWaitTicks = rand()%120; // up to 2 seconds
483  EventRecord ignoredEvent;
484 
485  ::WaitNextEvent(0, &ignoredEvent, attemptedWaitTicks, 0);
486 #else
487  #ifdef _MSDOS
488  #ifdef __WIN32__
489  sleep(2); // only missing in Win 16
490  #endif
491  #else
492  sleep(2); // standard unix
493  #endif
494 #endif
495 // NOT YET IMPLEMENTED later make more sophisticated in picking interval
496 }
497 
498 
499 
500 
501 
503 {
504  assert( Invariant("ctB::newRecord-entry") );
505 
506  #ifdef OOF_DEBUG
507  if (mConnection->isReadLocked())
508  dbConnect::raise("Attempt to create a newRecord while database read-locked");
509  #endif
511 
512  assert( Invariant("ctB::newRecord-exit") );
513 }
514 
515 
516 void
518 {
519  assert( Invariant("ctB::saveRecord-entry") );
520 
523 
524  assert( Invariant("ctB::saveRecord-exit") );
525 }
526 
527 
528 void
530 {
531  assert( Invariant("ctB::unloadRecord-entry") );
532 
534 // mConnection->resetLocks();
535 
536  assert( Invariant("ctB::unloadRecord-exit") );
537 }
538 
539 
540 void
541 OOF_ctreeBackend::setFileExtensions(const char* dataExt, const char* indexExt)
542 {
543  mDataExt = dataExt;
544  mIndexExt = indexExt;
545 }
546 
547 
548 void
549 OOF_ctreeBackend::SetISAMtoContext(const OOF_recordBufferedContext* ctx) {
550  unsigned long filePos = ::CurrentFileOffset(mISAMdatno);
551 // COUNT err = SetRecord(mISAMdatno, ctx->mCurrLoadedRecOffset, ctx->mBuffer, 0);
552  if (ctx->currentOffset() != filePos) {
553  COUNT err = ::SetRecord(mISAMdatno, ctx->currentOffset(), 0, 0); // just reset pointer
554  if (err!=NO_ERROR) {
556  "SetRecord", "OOF_ctreeBackend::SetISAMtoContext");
557  RAISE_EXCEPTION(excp);
558  }
559  }
560  char* oldImageBuffer = new char[mRecBufLen];
561  COUNT err = ::ReReadRecord(mISAMdatno, oldImageBuffer); // reset ISAM internal buffers
562  if (err!=NO_ERROR) {
564  "ReReadRecord", "OOF_ctreeBackend::SetISAMtoContext");
565  RAISE_EXCEPTION(excp);
566  }
567  delete[] oldImageBuffer;
568 }
569 
570 
571 bool
572 OOF_ctreeBackend::SaveBlob(fieldNumT fldNum)
573 {
574  COUNT err;
575  dbBLOB* fld = (dbBLOB *) mFields[fldNum]; // safe downcast
576  if (!fld->isDirty())
577  return false;
578 
579  mDirtyMap.markDirty(fldNum); // we are now dirty as far as the main record is concerned!
580  VRLEN bLen = BlobLenFromBuffer(fld, mBuffer);
581  LONG recNo = BlobPosFromBuffer(fld, mBuffer);
582  if (recNo) {
583  void* bodyAt = fld->bodyAddress();
584  if (bLen) {
585  err = ::WriteVData(mBlobFilNo, recNo, bodyAt, bLen);
586  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
588  #endif
589  if (err==VLEN_ERR) { // doesn't fit at that loc'n
590  err = ::ReleaseVData(mBlobFilNo, recNo);
591  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
593  #endif
594  if (err != NO_ERROR) {
596  excp(mTable, fldNum, err, "save blob record", "OOF_ctreeBackend::SaveBlob");
597  RAISE_EXCEPTION(excp);
598  }
599  recNo = ::NewVData(mBlobFilNo, bLen);
600  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
602  #endif
603  if (recNo == 0) {
605  excp(mTable, fldNum, mConnection->uerr_cod(), "save blob record", "OOF_ctreeBackend::SaveBlob");
606  RAISE_EXCEPTION(excp);
607  }
608  err = ::WriteVData(mBlobFilNo, recNo, bodyAt, bLen);
609  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
611  #endif
612  if (err != NO_ERROR) {
614  excp(mTable, fldNum, err, "save blob record", "OOF_ctreeBackend::SaveBlob");
615  RAISE_EXCEPTION(excp);
616  }
617  err = ::LockCtData(mBlobFilNo, FREE, recNo); // release lock created by NewVData
618  }
619  }
620  else { // blob len has dropped to zero - probably empty dbText
621  err = ::ReleaseVData(mBlobFilNo, recNo);
622  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
624  #endif
625  if (err != NO_ERROR) {
627  excp(mTable, fldNum, err, "save blob record", "OOF_ctreeBackend::SaveBlob");
628  RAISE_EXCEPTION(excp);
629  }
630  recNo = 0; // so we know there's no blob out there!
631  }
632  } // blob existed so rewrite it
633  else // blob doesn't exist - maybe new rec or never written
634  if (bLen) { // BUT only create it if we now have an entry - may still be null
635  recNo = ::NewVData(mBlobFilNo, bLen);
636  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
638  #endif
639  if (recNo == 0) {
641  excp(mTable, fldNum, mConnection->uerr_cod(), "save blob record", "OOF_ctreeBackend::SaveBlob");
642  RAISE_EXCEPTION(excp);
643  }
644  // NOT YET IMPLEMENTED - failed to write data
645 
646  err = ::WriteVData(mBlobFilNo, recNo, ((dbBLOB *)fld)->bodyAddress(), bLen);
647  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
649  #endif
650  if (err != NO_ERROR) {
652  excp(mTable, fldNum, err, "save blob record", "OOF_ctreeBackend::SaveBlob");
653  RAISE_EXCEPTION(excp);
654  }
655  err = ::LockCtData(mBlobFilNo, FREE, recNo); // release lock created by NewVData
656  }
657  SetBlobPosInBuffer(fldNum, recNo, mBuffer);
658  SetBlobLenInBuffer(fldNum, bLen, mBuffer);
659  return true; // if get here without exception!
660 }
661 
662 
663 void
664 OOF_ctreeBackend::SaveContext()
665 {
666  COUNT err;
667 
668 // mConnection->enterWriteLocking();
669 
670  assert( Invariant("ctB::SaveContext-entry") );
671 
672  bool savedMainOK = true;
673  bool savingNew = (mRecordState==eNew);
674 // do we have any blobs
675  bool saveBlobsLast = (mBlobFieldNums &&
676  ( (savingNew && HasUniqueIndices()) ||
677  HasDirtyUniqueIndices()
678  )
679  );
680 
681  if (!saveBlobsLast)
682  SaveBlobs(); // save first so we get new disk addresses
683 
684 // now write the parent record
685  if (savingNew) {
686  err = ::AddRecord(mISAMdatno, mBuffer);
687  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
689  #endif
690  if (err==KDUP_ERR) {
691  if (IgnoringDuplicateRecords()) {
692  savedMainOK = false;
693  mRecordState = eLoaded; // cancel a state of eNew so don't loop trying to add
694  }
695  else {
696  oofE_DuplicateRecord excp(mTable, mISAMdatno, "AddRecord", "OOF_ctreeBackend::SaveContext");
697  RAISE_EXCEPTION(excp);
698  }
699  }
700  else {
701  if (err != NO_ERROR) {
702  oofE_CtreeISAMError excp(mTable, mISAMdatno, err, "AddRecord", "OOF_ctreeBackend::SaveContext");
703  RAISE_EXCEPTION(excp);
704  }
705  }
706 
707  if (savedMainOK) {
708  mCurrLoadedRecOffset = CurrentFileOffset(mISAMdatno);
709  if (!mTable->lockedCurrentRecord()) { // if not meant to be locked, unlock the auto-lock immediately
710  COUNT unlockErr = LockCtData(mISAMdatno, FREE, mCurrLoadedRecOffset);
711  if (unlockErr && unlockErr != UDLK_ERR) { // ignore "can't unlock" errors
713  "free lock on file", "OOF_ctreeBackend::SaveContext");
714  RAISE_EXCEPTION(excp);
715  }
716  }
718  mSelection.gotoRecord(ULONG_MAX); // invalid!
719  else {
722  else
724  }
726  } // saved main
727  } // saved new
728  else { // EXISTING RECORD
729  SetISAMtoContext(this);
730  SaveExistingMainRecord();
731  } // save existing
732 
733  if (savedMainOK) {
734  // save any dirty blobs
735  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
737  #endif
738  if (saveBlobsLast) {
739  bool savedAnyBlobs = SaveBlobs();
740  if (savedAnyBlobs) // need to rewrite main record
741  SaveExistingMainRecord();
742  } // save blobs
743 
744  if (mKeywordIndex)
745  mKeywordIndex->updateWords(mTable, savingNew, mDirtyMap);
746  }
747 // mConnection->exitLocking();
748 
749  assert( Invariant("ctB::SaveContext-exit") );
750 }
751 
752 
753 bool
754 OOF_ctreeBackend::SaveBlobs()
755 {
756  assert( Invariant("ctB::SaveBlobs-entry") );
757 
758  bool savedAny = false;
759  if (mBlobFieldNums) {
760  unsigned int numBlobs = mBlobFieldNums->count();
761  for (unsigned int i=0; i<numBlobs; i++)
762  if (SaveBlob(mBlobFieldNums->item(i)))
763  savedAny = true;
764  }
765  assert( Invariant("ctB::SaveBlobs-exit") );
766  return savedAny;
767 }
768 
769 
770 void
771 OOF_ctreeBackend::SaveExistingMainRecord()
772 {
773  // assumes in correct position already
774  COUNT err = ::ReWriteRecord(mISAMdatno, mBuffer);
775  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
777  #endif
778  if (err != NO_ERROR)
779  if (err == KDUP_ERR) {
780  // ES - cannot ignore duplicate records here, I think...
781  oofE_DuplicateRecord excp(mTable, mISAMdatno, "ReWriteRecord", "OOF_ctreeBackend::SaveExistingMainRecord");
782  RAISE_EXCEPTION(excp);
783  }
784  else {
785  oofE_CtreeISAMError excp(mTable, mISAMdatno, err, "ReWriteRecord", "OOF_ctreeBackend::SaveExistingMainRecord");
786  RAISE_EXCEPTION(excp);
787  }
788 }
789 
790 
791 bool
792 OOF_ctreeBackend::HasDirtyUniqueIndices() const
793 {
794  if (mUniqueFieldNums==0)
795  return false;
796 
797  assert( Invariant("ctB::HasDirtyUniqueIndices-entry") );
798 
799 // loop through the unique fields, to see if at least one marked dirty
800  const unsigned short numUnique = mUniqueFieldNums->count();
801  for (unsigned short i=0; i<numUnique; i++) {
802  unsigned long fieldNum = mUniqueFieldNums->value(i);
803  if (mDirtyMap.isDirty(fieldNum)) {
804  assert( Invariant("ctB::HasDirtyUniqueIndices-exit dirty field") );
805  return true;
806  }
807  }
808  assert( Invariant("ctB::HasDirtyUniqueIndices-exit clean") );
809  return false;
810 }
811 
812 
813 void
815 {
816  assert( Invariant("ctB::deleteRecord-entry") );
817 
818  if (CommonSimpleDelete())
819  return;
820 
822 
823  COUNT err;
824  EnsureOurContextMatchesISAM();
825 // first delete the main ISAM record
826  err = ::DeleteRecord(mISAMdatno);
827  if (err != NO_ERROR) {
829  "delete record", "OOF_ctreeBackend::deleteRecord");
830  RAISE_EXCEPTION(excp);
831  }
832  else {
833  // delete any blobs
834  if (mBlobFieldNums) {
835  unsigned int numBlobs = mBlobFieldNums->count();
836  for (unsigned int i=0; i<numBlobs; i++) {
837  fieldNumT fldNum = mBlobFieldNums->item(i);
838  LONG recNo = BlobPosFromBuffer(fldNum, mBuffer);
839  if (recNo) {
840  err = ::ReleaseVData(mBlobFilNo, recNo);
841  if (err != NO_ERROR) {
843  excp(mTable, fldNum, err, "delete blob record", "OOF_ctreeBackend::deleteRecord");
844  RAISE_EXCEPTION(excp);
845  }
846  }
847  } // deleting BLOBs
848  if (mKeywordIndex)
849  mKeywordIndex->deleteWords(mCurrLoadedRecOffset); // NOT YET IMPLEMENTED - cope with true OIDs
850 
851  } // deleted OK
852  unloadRecord(); // gets rid of in-mem
853 
854  switch (mSelection.state()) {
855 
857 #ifdef OOF_DEBUG
858  dbConnect::raise(stringstream() << flush << "deleteRecord() called on empty selection in table: " << mTable->tableName(), false);
859 #endif
860  break;
861  }
862 
864  selectNone();
865  break;
866  }
867 
869  mSelection.deleteCurrent(); // takes care of position if delete last
870  LoadRecordAtOffset(mSelection());
871  break;
872  }
873 
875  COUNT err;
876  COUNT filno = SortIndexNo();
878  err = ::NextRecord(filno, mBuffer);
879  END_LOCK_WAIT(err)
880  if (err == INOT_ERR) { // just deleted last record
882  err = ::FirstRecord(filno, mBuffer);
883  END_LOCK_WAIT(err)
884  if (err == INOT_ERR)
885  selectNone(); // and last record was ONLY record
886  else
887  mSelection.start();
888  }
889  CompleteMoveToRecForAllRecs(err, "deleteRecord() allRecs:");
890  }
891  }
892  } // error deleting main ISAM
893 
894  assert( Invariant("ctB::deleteRecord-exit") );
895 }
896 
897 
898 
899 
900 
903 {
904  return new OOF_ctreeBackend(*this, selSharing, theTable);
905 }
906 
907 
908 bool
909 OOF_ctreeBackend::validFileMode(long fileMode)
910 {
911  bool res = true;
912  long temp = (EXCLUSIVE|SHARED|READFIL)&fileMode;
913 
914 
915  if(!( (temp == EXCLUSIVE)||(temp == SHARED)||(temp == READFIL)) )
916  res = false;
917  return res;
918 }
919 
920 
921 void
922 OOF_ctreeBackend::BuildIFIL()
923 {
924  assert( Invariant("ctB::BuildIFIL-entry") );
925 
926  assert(!mIFIL.ix); // DeleteIFIL should have been called prior delete[] mIFIL.ix; // eg: after suppressIndices, called from rebuild
927  IIDX *indexes = 0;
928  if (mNumIndexes) {
929 //***** build index structures from indexed fields *****
930  indexes = new IIDX[mNumIndexes];
931  assert(indexes);
932  unsigned int indexRelNum = 0;
933  unsigned int numFields = mFields.count();
934  for (unsigned int fieldNum=0; fieldNum<numFields; fieldNum++)
935  if (mFieldCtreeMap[fieldNum].mIndexNo) {
936  dbField *indexField = (dbField *) mFields[fieldNum]; // safe downcast
937  if (indexField->fieldIsUniqueIndexed()) {
938  if (!mUniqueFieldNums)
939  mUniqueFieldNums = new OOF_SharedArray;
940  mUniqueFieldNums->append(fieldNum);
941  }
942  CompleteIIDX(indexField, indexes[indexRelNum]);
943  indexRelNum++;
944  }
945 // now see if we can use compound indices for any non-indexed fields
946 /*
947 
948 97/08/25 removed this feature
949 Realise that the way we construct keys in the various search methods assumes that a non-unique key
950 only has 4 extra bytes. If we use a compound Key again for another field we have to assume that it is
951 non-unique but we have N extra bytes. ie: field A is 10 chars, field B is 6 chars and the compound is unique,
952 the key construction algorithm must allow for 6 chars padding on the end of the key, not the standard 4.
953 
954 Later need to store something like total key len vs active len.
955 
956  if (mCompoundIndexDict.count()) { // we have at least one compound index
957  for (unsigned int j=0; j<numFields; j++)
958  if (!mFieldCtreeMap[j].mIndexNo) { // NOT an indexed field
959  const dbField* compoundField;
960  COUNT possibleIndexNo = mCompoundIndexDict.indexStartingWithField(j, false, compoundField); // assume ascending
961  if (possibleIndexNo) {
962  assert(compoundField);
963  mFieldCtreeMap[j].mIndexNo = possibleIndexNo;
964  unsigned short compoundKeyLen = compoundField->fieldStorageLen();
965  if (!compoundField->fieldIsUniqueIndexed())
966  compoundKeyLen += kCtreeKeySeqenceAddonLength;
967  mFieldCtreeMap[j].mKeyLength = compoundKeyLen;
968  dbField *indexField = (dbField *) mFields[j]; // safe downcast
969  indexField->index(compoundField->fieldIndexOptions()); // field is now indexed & as far as anyone else needs to know this is true
970  }
971  }
972  }
973 */
974  }
975 
976  assert(validFileMode(sFileMode));
977 // ***** now fill in our IFIL member *****
978  mIFIL.pfilnam = 0; // defer setting table name until creating the actual connection
979  // there may be some differences depending on whether we use superfiles or not
980  // and remember that the table name now includes the superfile name and so
981  // cannot be determined until the time that the actual database file name is
982  // known - ie: after the physical database has been opened or created.
983 // ----------- mIFIL.dfilno = -1; // auto assign
984  mIFIL.dfilno = mISAMdatno; // auto-assign via negative not working?
985  mIFIL.dreclen = mRecBufLen;
986  mIFIL.dxtdsiz = kDataExtendSize;
987  mIFIL.dfilmod = sFileMode | ctFIXED;
988  mIFIL.dnumidx = mNumIndexes;
989  mIFIL.ixtdsiz = kIndexExtendSize;
990  mIFIL.ifilmod = sFileMode;
991  mIFIL.ix = indexes;
992  mIFIL.rfstfld = 0;
993  mIFIL.rlstfld = 0;
994 
995  assert((mUniqueFieldNums==0) || mUniqueFieldNums->count());
996 
997  assert( Invariant("ctB::BuildIFIL-exit") );
998 }
999 
1000 
1001 bool
1002 OOF_ctreeBackend::FieldHasStorage(dbField* theField) const
1003 {
1004  assert( Invariant("ctB::FieldHasStorage-entry") );
1005 
1006 // WARNING if this logic changes, check around the fieldIsVirtual test
1007 // in OOF_ctreeBackend::BuildBackendtables as it is closely related
1008  const bool ret =
1009  !theField->fieldIsVirtual() || (
1010  theField->fieldIsIndexed() &&
1011  theField->fieldType()!=compoundField && // compound indexing handled by c-tree
1012  theField->fieldKeyLen()>0 // allow key lengths to be set to zero to suppress storage
1013  ); // as backward-compatability in case people accidentally declared calc fields indexed
1014 
1015  assert( Invariant("ctB::FieldHasStorage-exit") );
1016  return ret;
1017 }
1018 
1019 
1020 void
1021 OOF_ctreeBackend::addIndices(const char* newIDXname)
1022 {
1023  mIndicesSuppressed = false;
1024  COUNT firstNewIndexNo = RebuildIndexMap(newIDXname);
1025  BuildIFIL();
1026  mIFIL.tfilno = firstNewIndexNo;
1027 
1028  assert(!(dbConnect_ctree::sFileMode & EXCLUSIVE));
1029  COUNT err = ::PermIIndex(&mIFIL);
1030  if (err != NO_ERROR) {
1031  oofE_CtreeISAMError excp(mTable, mISAMdatno, err, "create index", "OOF_ctreeBackend::addIndices");
1032  RAISE_EXCEPTION(excp);
1033  }
1034 }
1035 
1036 
1041 void
1042 OOF_ctreeBackend::DeleteIIDX()
1043 {
1044  if (mFieldCtreeMapRefCount) { // this instance
1045  if ((*mFieldCtreeMapRefCount <= 1) && mIFIL.ix) {
1046  for (unsigned short indexes=0; indexes < mNumIndexes; indexes++) {
1047  delete[] mIFIL.ix[indexes].seg;
1048  }
1049  delete[] mIFIL.ix;
1050  mIFIL.ix = 0;
1051  }
1052  else
1053  mIFIL.ix = 0; // unlink to shared mIFIL so safe to rebuild
1054  }
1055  else {
1056  assert(!mIFIL.ix);
1057  }
1058 }
1059 
1060 void
1062 {
1063  stSaveDirectory preserveUserDir;
1064  mConnection->gotoDatabaseDir(); // change default so the following doesn't care where it is
1065 
1066  mIndicesSuppressed = true;
1067 // now tell the file the indexes are suppressed
1068 // so it fails to update them!
1069  mIFIL.dnumidx = 0;
1070  DeleteIIDX();
1071 
1072  close();
1073  COUNT err = ::PutIFileXtd(&mIFIL, mDataExt.charsForOldInterfacesNotWriting(), mIndexExt.charsForOldInterfacesNotWriting(), 0);
1074  if (err != NO_ERROR) {
1075  oofE_CtreeISAMError excp(mTable, mISAMdatno, err, "put IFIL structure", "OOF_ctreeBackend::suppressIndices");
1076  RAISE_EXCEPTION(excp);
1077  }
1078  open();
1079 
1080  if (mKeywordIndex)
1081  mKeywordIndex->suppressIndices();
1082 }
1083 
1084 
1085 void
1087 {
1088  assert( Invariant("ctB::rebuild-entry") );
1089 
1091  close();
1092 // then we can play with the IFIL
1093 
1094  stSaveDirectory preserveUserDir;
1095  mConnection->gotoDatabaseDir(); // change default so the following doesn't care where it is
1096 
1097  mIndicesSuppressed = false;
1098  RebuildIndexMap(0);
1099  BuildIFIL();
1100  mIFIL.pfilnam = mFileName.charsForOldInterfacesNotWriting();
1101  mIFIL.tfilno = updateIFIL; //forces modified IFIL to be written
1102 
1103  COUNT err = ::RebuildIFileXtd(&mIFIL, mDataExt.charsForOldInterfacesNotWriting(), mIndexExt.charsForOldInterfacesNotWriting(), 0, 0, 0);
1104  if (err != NO_ERROR) {
1105  oofE_CtreeISAMError excp(mTable, mISAMdatno, err, "rebuild file", "OOF_ctreeBackend::rebuild");
1106  RAISE_EXCEPTION(excp);
1107  }
1108  open();
1109 
1110  if (mKeywordIndex)
1111  mKeywordIndex->rebuild();
1112 
1113  assert( Invariant("ctB::rebuild-exit") );
1114 }
1115 
1116 
1117 void
1119 {
1120  assert( Invariant("ctB::buildSchema-entry") );
1121 
1122  assert(!rebuilding); // NOT YET IMPLEMENTED
1123  mNumFiles = 1; // start with at least one file for the basic data
1124  mNumIndexes = 0;
1125 
1126  mBlobFieldNums = 0;
1128 
1129  mISAMdatno = sNextFileNo;
1130  BuildBackendtables(rebuilding);
1131  selectAll();
1132 
1133  BuildIFIL();
1134  sNextFileNo += mNumIndexes+mNumFiles;
1135  if (mKeywordIndex) {
1136  mKeywordIndex->buildSchema(mTable);
1137  }
1138  AllocBuffer();
1139  memset(mBuffer, 0, mRecBufLen);
1140 
1141  if (mBlobFieldNums) // noticed some in BuildBackendtables
1143 
1144  assert( Invariant("ctB::buildSchema-exit") );
1145 } // OOF_ctreeBackend::buildSchema
1146 
1147 
1148 void
1150 {
1151  assert( Invariant("ctB::createTableInConnection-entry") );
1152 
1153  const dbConnect_ctree* theDB = (dbConnect_ctree*) theDB_; // safe downcast
1154  mFileName = theDB->makeTableName(mTable->tableName());
1155  mIFIL.pfilnam = mFileName.charsForOldInterfacesNotWriting();
1156  UCOUNT numDODAfields;
1157  DATOBJ* theDODA = BuildDODA(numDODAfields);
1158  COUNT err = ::CreateIFileXtd(&mIFIL, mDataExt.charsForOldInterfacesNotWriting(), mIndexExt.charsForOldInterfacesNotWriting(), 0, 0, 0); // no security
1159  if (err != NO_ERROR) {
1160  oofE_CtreeISAMError excp(mTable, mISAMdatno, err, "CreateIFile", "OOF_ctreeBackend::createTableInConnection");
1161  RAISE_EXCEPTION(excp);
1162  }
1163  err = ::PutDODA(mISAMdatno, theDODA, numDODAfields);
1164  if (err != NO_ERROR) {
1165  oofE_CtreeISAMError excp(mTable, mISAMdatno, err, "PutDODA", "OOF_ctreeBackend::createTableInConnection");
1166  RAISE_EXCEPTION(excp);
1167  }
1168  delete[] theDODA;
1169  assert( Invariant("ctB::createTableInConnection-exit") );
1170 }
1171 
1172 
1177 bool
1178 OOF_ctreeBackend::openTableInConnection(const dbConnect* theDB_, const bool createIfMissing)
1179 {
1180  bool ret = true;// default value for createIfMissing = false
1181 
1182  assert( Invariant("ctB::openTableInConnection-entry") );
1183  const dbConnect_ctree* theDB = (dbConnect_ctree*) theDB_; // safe downcast
1184  mFileName = theDB->makeTableName(mTable->tableName());
1185  mIFIL.pfilnam = mFileName.charsForOldInterfacesNotWriting();
1186 
1187  if(!createIfMissing) {
1188  open(); // will throw oofE_CtreeISAMError if fails
1189  }
1190  else {// open or create
1191  COUNT err = ::OpenIFileXtd(&mIFIL, mDataExt.charsForOldInterfacesNotWriting(), mIndexExt.charsForOldInterfacesNotWriting(), 0); // no security word
1192  switch (err){// did we suceed
1193  case NO_ERROR:// it exists
1194  ret = true;
1195  break;
1196 
1197  case FNOP_ERR: // Could not open file(s) assume it's not there
1198  createTableInConnection(theDB_);
1199  ret = false;
1200  break;
1201 
1202  default:
1203  assert(0); // problem with file add eception later
1204  //must add better handiling of errors maybe exceptions
1205  }
1206 
1207 
1208  }
1209 
1210  assert( Invariant("ctB::openTableInConnection-exit") );
1211  return ret;
1212 }
1213 
1214 
1215 void
1217 {
1218  COUNT err = ::OpenIFileXtd(&mIFIL, mDataExt.charsForOldInterfacesNotWriting(), mIndexExt.charsForOldInterfacesNotWriting(), 0); // no security word
1219  if (err != NO_ERROR) {
1220  oofE_CtreeISAMError excp(mTable, mISAMdatno, err, "OpenIFile", "OOF_ctreeBackend::open");
1221  RAISE_EXCEPTION(excp);
1222  }
1223 #ifdef TESTING_DODA_INTERFACE
1224  DATOBJ* thingy;//
1225  thingy = BuildConectionSchemFromFile();
1226  DODAInterface testthiny(mISAMdatno);
1227  testthiny.describe(cout);
1228 
1229  delete [] thingy;
1230 #endif //TESTING_DODA_INTERFACE
1231 /*
1232 // BIT OF DEBUGGING CODE
1233 // used to walk through the DODA in a file to diagnose errors
1234 // 95/09/28 used to find that PC was putting 2 byte lengths on Blob components
1235  unsigned int numDODAfields = mFieldBufMap[mFields.count()-1].mDODAfieldNo+2; // allow for extra
1236  DATOBJ* ret = new DATOBJ[numDODAfields];
1237  assert(ret);
1238  VRLEN dodaErr = GETDODA(mISAMdatno, 300, ret, SCHEMA_DODA);
1239 */
1240 }
1241 
1242 
1243 void
1245 {
1246  assert( Invariant("ctB::close-entry") );
1247 
1248  COUNT err = ::CloseIFile(&mIFIL);
1249  if (err != NO_ERROR) {
1250  oofE_CtreeISAMError excp(mTable, mISAMdatno, err, "CloseIFile", "OOF_ctreeBackend::close");
1251  RAISE_EXCEPTION(excp);
1252  }
1253 
1254  assert( Invariant("ctB::close-exit") );
1255 }
1256 
1257 
1258 void
1260 {
1261  assert( Invariant("ctB::deleteStorage-entry") );
1262 
1263  assert(mConnection);
1265  // note that we don't use the c-tree function DeleteIFile because
1266  // that requires the file still to be opened and we can't guarantee
1267  // from our various calling contexts
1268 
1269  // delete the files created in createTableInConnection
1270  // NOT YET IMPLEMENTED - more than one index file
1271 
1272  oofString dataExt = mDataExt;
1273  if (dataExt.isEmpty())
1274  dataExt = ".dat";
1275 
1277  const oofString dataName (mTable->tableName(), dataExt);
1278  oofFileRef dataFile(*dbDir, dataName);
1279  dataFile.deleteFile();
1280 
1281  if (mNumIndexes > 0) {
1282  oofString indexExt = mIndexExt;
1283  if (indexExt.isEmpty())
1284  indexExt = ".idx";
1285 
1286  const oofString indexName (mTable->tableName(), indexExt);
1287  oofFileRef indexFile(*dbDir, indexName);
1288  indexFile.deleteFile();
1289  }
1290 
1291  if (mKeywordIndex)
1292  mKeywordIndex->deleteStorage();
1293  }
1294  else {
1295  // NOT YET IMPLEMENTED - cope with removal from a superfile!
1296  // which is only a problem when trying to delete a file in isolation
1297  // if we are deleting an entire database storage then we don't need to remove
1298  // files from the superfile
1299  }
1300 
1301  assert( Invariant("ctB::deleteStorage-exit") );
1302 }
1303 
1304 
1305 
1306 
1307 void
1308 OOF_ctreeBackend::CompleteIIDX(const dbField * fld, IIDX& ix)
1309 {
1310  assert( Invariant("ctB::CompleteIIDX-entry") );
1311 
1312  ix.ikeytyp = 0; // alphanumeric scanned left-right
1313  if (fld->fieldIndexIsCompressLeading())
1314  ix.ikeytyp += 4;
1315  if (fld->fieldIndexIsCompressPadding())
1316  ix.ikeytyp += 8;
1317 
1318  if (fld->fieldIndexIgnoresNulls()) {
1319  #ifdef NO_IDXENT
1320  dbConnect::raise(stringstream() << flush << "c-tree setting NO_IDXENT in ctoptn.h means you can't use an index without nulls on field:" << fld->fieldName());
1321  #endif
1322  ix.inulkey = 1; // ignore totally blank (null) keys - won't index them
1323  }
1324  else
1325  ix.inulkey = 0; // include zero values! USUALLY WANT NULL KEYS AS WE ITERATE THRU INDEXES
1326  ix.iempchr = 0; // empty character is null
1327  ix.ridxnam = 0; // no symbolic name (yet) NOT YET IMPLEMENTED
1328  ix.altseq = 0; // no alternate collating sequence
1329  ix.pvbyte = 0; // no special pad byte
1330 
1331  fieldNumT fieldNum = fld->fieldNumber();
1332 // cast away const
1333  char* alternateIndexName = (char*) (mFieldCtreeMap[fieldNum].mAlternateIndexName);
1334  ix.aidxnam = alternateIndexName; // defaults 0, only used if add indices
1335 
1336  if (fld->fieldType() != compoundField) {
1337  ix.inumseg = 1;
1338  ix.seg = new ISEG[1];
1339  assert(ix.seg);
1340  ix.seg[0].soffset = mFieldCtreeMap[fieldNum].mDODAfieldNo;
1341  ix.seg[0].slength = fld->fieldKeyLen();
1342  ix.ikeylen = ix.seg[0].slength;
1343  ix.seg[0].segmode = MapFieldTypeToCtreeKeyType(fld->nativeType(), fld->caseSensitive());
1344  }
1345  else { // must be compound field
1346  ix.ikeylen = 0;
1347  OOF_ctreeIndexSegList* indexFiles = new OOF_ctreeIndexSegList(mFieldCtreeMap[fieldNum].mIndexNo, (dbCompoundField*) fld); // safe downcast
1348  dbCompoundField* compFld = (dbCompoundField*) fld; // safe downcast
1349  ix.inumseg = compFld->countSegments();
1350  ix.seg = new ISEG[ix.inumseg];
1351  assert(ix.seg);
1352  unsigned short numSeg = (unsigned short) ix.inumseg; // cast to avoid warnings
1353  for (unsigned short i=0; i<numSeg; i++) {
1354  const dbField* segFld = compFld->field(i);
1355  unsigned int segFldNum = segFld->fieldNumber();
1356  ix.seg[i].soffset = mFieldCtreeMap[segFldNum].mDODAfieldNo;
1357  ix.seg[i].slength = segFld->fieldStorageLen(); // NOT segment length in record, don't want trailing nulls
1358  ix.ikeylen += ix.seg[i].slength;
1359  ix.seg[i].segmode = MapFieldTypeToCtreeKeyType(segFld->fieldType(), segFld->caseSensitive());
1360  if (compFld->segment(i)->isReversed())
1361  ix.seg[i].segmode |= DSCSEG;
1362  indexFiles->appendFieldNo(segFldNum);
1363  }
1364  mCompoundIndexDict.append(indexFiles);
1365  }
1366  if (!fld->fieldIsUniqueIndexed()) {
1367  ix.ikeylen += kCtreeKeySeqenceAddonLength;
1368  ix.ikeydup = 1;
1369  }
1370  else
1371  ix.ikeydup = 0;
1372  mFieldCtreeMap[fieldNum].mKeyLength = ix.ikeylen;
1373 
1374  assert( Invariant("ctB::CompleteIIDX-exit") );
1375 }
1376 
1377 
1378 COUNT
1379 OOF_ctreeBackend::MapFieldTypeToCtreeKeyType(const OOF_fieldTypes t, bool caseSensitive) const
1380 {
1381  switch (t) {
1382  case charField :
1383  return caseSensitive ? SCHSEG : USCHSEG;
1384 
1385  default :
1386  return SCHSEG;
1387  }
1388 }
1389 
1390 
1391 COUNT
1392 OOF_ctreeBackend::MapFieldTypeToCtreeDODAType(const OOF_fieldTypes t) const
1393 {
1394  switch (t) {
1395  case charField :
1396  return CT_FSTRING;
1397 
1398  case shortField :
1399  return CT_INT2;
1400 
1401  case uShortField :
1402  return CT_INT2U;
1403 
1404  case timeField :
1405  case longField :
1406  return CT_INT4;
1407 
1408  case dateField :
1409  case dateTimeField :
1410  case uLongField :
1411  return CT_INT4U;
1412 
1413  case realField :
1414  return CT_DFLOAT;
1415 
1416  default :
1417  return CT_ARRAY;
1418  }
1419 }
1420 
1421 
1422 
1425 {
1426  switch (t) {
1427  case CT_FSTRING :
1428  return charField;
1429 
1430  case CT_INT2 :
1431  return shortField;
1432 
1433  case CT_INT2U :
1434  return uShortField ;
1435 
1436  case CT_INT4:
1437  //case timeField :
1438  //case longField :
1439  return longField;
1440 
1441  case CT_INT4U:
1442  return uLongField;
1443  //case dateTimeField :
1444  //case dateField
1445 
1446  case CT_DFLOAT:
1447  return realField ;
1448 
1449  default: //CT_ARRAY:
1450  //return blob?;
1451  textField; // David debug 000731 look into this as i think it is wrong
1452  }
1453  return textField;//david debug 20000817
1454 }
1455 
1456 
1457 
1458 DATOBJ*
1459 OOF_ctreeBackend::BuildConnectionSchemFromFile()
1460 {
1461 /*
1462 work in progress, commented out for this release
1463  //UCOUNT numDODAfields;
1464  ConvMap schemaMap;
1465  // bufSize =sizeof(ConvMap);// m
1466  VRLEN result;
1467  VRLEN mapLength;
1468  DATOBJ* buf;
1469  //unsigned long tableIndex;
1470  //unsigned long fieldIndex;
1471  //COUNT result;
1472  // It look like the error handling iswrong
1473  //result = ::GetDODA( mISAMdatno,sizeof(schemaMap),&schemaMap,SCHEMA_MAP);
1474  //if(result != sizeof(schemaMap)){
1475  //if(mConnection->uerr_cod() != NO_ERROR){
1476  //if (mConnection->uerr_cod() == RBUF_ERR){
1477  // int a = 2;
1478  // ConvMap *
1479  //buf = new DATOBJ[result]
1480  //result = ::GetDODA( mISAMdatno,res,buf,SCHEMA_DODA);
1481 
1482  // }
1483  //else {
1484  // oofE_CtreeISAMError excp(mTable, mISAMdatno, mConnection->uerr_cod(), "Readmap", "OOF_ctreeBackend::BuildConectionSchemFromFile");
1485  // RAISE_EXCEPTION(excp);
1486  //}//
1487  //}
1488 
1489  mapLength = schemaMap.maplen;
1490  const long numFieldsThisTable =schemaMap.nbrflds;
1491  DATOBJ scrap;
1492  //buf = new DATOBJ;
1493  result = ::GetDODA( mISAMdatno,sizeof(DATOBJ),&scrap,SCHEMA_DODA);
1494  //if (mConnection->uerr_cod() == RBUF_ERR){
1495  if(result != sizeof(DATOBJ)){
1496  // unsigned long spod = result/sizeof(DATOBJ);
1497  //buf = new DATOBJ[result/sizeof(DATOBJ)];
1498  buf = (DATOBJ*)new char[result];
1499 
1500  result = ::GetDODA( mISAMdatno,result,buf,SCHEMA_DODA);
1501  }
1502  else {
1503  oofE_CtreeISAMError excp(mTable, mISAMdatno, mConnection->uerr_cod(), "Readmap", "OOF_ctreeBackend::BuildConectionSchemFromFile");
1504  RAISE_EXCEPTION(excp);
1505  }
1506 
1507  //ok we have the stuff we need
1508  //delete buf;
1509  return buf;
1510 */
1511  return 0; // HACK
1512 }
1513 
1514 
1515 DATOBJ*
1516 OOF_ctreeBackend::BuildDODA(UCOUNT& numDODAfields)
1517 {
1518  unsigned int numFields = mFields.count();
1519  numDODAfields = mFieldCtreeMap[numFields-1].mDODAfieldNo+1;
1520  DATOBJ* ret = new DATOBJ[numDODAfields];
1521  assert(ret);
1522 
1523  OOF_DummyString dummyNames; // statically stored self-incrementing const char*'s
1524  unsigned long expectNextFieldAt = kOverheadLeadingBytes;
1525  // fake entry for filler to avoid clashes with delete flag
1526  ret[0].fsymb = dummyNames.nextDummy().charsForOldInterfacesNotWriting();
1527  ret[0].fadr = 0;
1528  ret[0].ftype = CT_FSTRING; // was CT_ARRAY but that breaks ODBC
1529  ret[0].flen = kOverheadLeadingBytes;
1530 
1531  unsigned int iDODA, lastDODA = 0; // skip leading dummy
1532  for (unsigned int i = 0; i < numFields; i++) {
1533  dbField *fld = (dbField *) mFields[i]; // safe downcast
1534  if (FieldHasStorage(fld)) {
1535  iDODA = mFieldCtreeMap[i].mDODAfieldNo;
1536  ret[iDODA].fsymb = fld->fieldName().charsForOldInterfacesNotWriting(); // ultimately points to constant OOF_String embedded to field
1537  ret[iDODA].fadr = 0;
1538 
1539  if (fld->fieldIsBlob()) { // second of pair of cells
1540  ret[iDODA].ftype = CT_INT4;
1541  ret[iDODA].flen = 4;
1542  ret[iDODA-1].fsymb = dummyNames.nextDummy().charsForOldInterfacesNotWriting();
1543  ret[iDODA-1].fadr = 0;
1544  ret[iDODA-1].ftype = CT_INT4;
1545  ret[iDODA-1].flen = 4;
1546  // check for fillers, before our preceding field
1547  // ie: the iDODA just jumped 3, not 2
1548  if ( iDODA > 2 && lastDODA<(iDODA-2)) { // there's a dummy in front
1549  ret[iDODA-2].fsymb = dummyNames.nextDummy().charsForOldInterfacesNotWriting();
1550  ret[iDODA-2].fadr = 0;
1551  ret[iDODA-2].ftype = CT_FSTRING;
1552  ret[iDODA-2].flen = mFieldBufMap[i].mOffset - expectNextFieldAt;
1553  }
1554  }
1555  else {
1556  ret[iDODA].ftype = MapFieldTypeToCtreeDODAType(fld->nativeType());
1557  ret[iDODA].flen = mFieldBufMap[i].mLength;
1558  // check for fillers
1559  if (lastDODA<(iDODA-1)) { // there's a dummy in front
1560  ret[iDODA-1].fsymb = dummyNames.nextDummy().charsForOldInterfacesNotWriting();
1561  ret[iDODA-1].fadr = 0;
1562  ret[iDODA-1].ftype = CT_FSTRING;
1563  ret[iDODA-1].flen = mFieldBufMap[i].mOffset - expectNextFieldAt;
1564  }
1565  if (fld->storesCalculatedValues())
1566  fieldHasStoredCalculator(fld); // record so we know in future
1567  } // not a blob
1568  expectNextFieldAt = mFieldBufMap[i].mOffset + mFieldBufMap[i].mLength;
1569  lastDODA = iDODA;
1570  } // non-virtual
1571  } // loop through fields
1572  return ret;
1573 }
1574 
1575 
1576 
1577 void
1579 {
1580  assert( Invariant("ctB::BuildBackendtables-entry") );
1581 
1582  assert(!mFieldBufMap);
1583  assert(!rebuilding); // NOT YET IMPLEMENTED
1584  unsigned int numfields = mFields.count();
1585  mDirtyMap.finishMap(numfields);
1586  COUNT indexFileNo = mISAMdatno+1;
1587 
1588  mFieldBufMap = new OOF_recordFieldEntry[numfields];
1589  assert(mFieldBufMap);
1590  mFieldBufMapRefCount = new unsigned int(1);
1591  assert(mFieldBufMapRefCount);
1592 
1593  mFieldCtreeMap = new OOF_ctreeFieldExtra[numfields];
1594  assert(mFieldCtreeMap);
1595  mFieldCtreeMapRefCount = new unsigned int(1);
1596  assert(mFieldCtreeMapRefCount);
1597 
1598  mRecBufLen = kOverheadLeadingBytes;
1599  unsigned int mapDODAfieldNum = 1; // allow for leading filler
1600  for (unsigned int i = 0; i < numfields; i++) {
1601  dbField *fld = (dbField *) mFields[i]; // safe downcast
1602 
1603 #ifdef OOF_DEBUG
1604  if (mRecBufLen%2==1)
1605  dbConnect::raise(stringstream() << flush << "OOF_ctreeBackend::BuildBackendtables odd buffer size at field:" << fld->fieldName());
1606 #endif
1607  unsigned long len;
1608  const bool thisFieldHasStorage = FieldHasStorage(fld);
1609  if (!thisFieldHasStorage) {
1610  mFieldBufMap[i].mOffset = 0;
1611  len = 0;
1612  mapDODAfieldNum--; // so keep the same number as prev cell
1613  }
1614  else {
1615 // work out if need to pad field alignment, by inserting dummy field
1616  unsigned int alignTo = FieldAlignsTo(fld);
1617  if (alignTo>2) {
1618  unsigned int alignRemainder = mRecBufLen%alignTo;
1619  if (alignRemainder) {
1620  mapDODAfieldNum++; // skip a num as insert dummy field
1621  mRecBufLen += (alignTo - alignRemainder);
1622  }
1623  }
1624 
1625  if (fld->fieldIsBlob()) {
1626  mapDODAfieldNum++; // skip a num as map to two DODA fields
1627  if (!mBlobFieldNums)
1628  mBlobFieldNums = new OOF_ExpandableLongArray(0,2,2); // 0 def value, alloc 2 slots & grow by same
1629  mBlobFieldNums->append(i);
1630  }
1631 
1633  len = PadFieldWidthForAlignment(fld);
1634  mRecBufLen += len; // watch the order here - inc AFTER copy to mOffset
1635  }
1636 
1637  mFieldCtreeMap[i].mDODAfieldNo = mapDODAfieldNum;
1638  mFieldCtreeMap[i].mAlternateIndexName = 0;
1639  mFieldBufMap[i].mLength = len;
1640  mapDODAfieldNum++;
1641 
1642  if (!mIndicesSuppressed && fld->fieldNumIndexes()) {
1643  mFieldCtreeMap[i].mIndexNo = indexFileNo;
1644  indexFileNo++;
1645  mNumIndexes++;
1646  // WARNING if the rules change in OOF_ctreeBackend::FieldHasStorage change may
1647  // be needed below as this is closely allied logic
1648  if (fld->fieldIsVirtual() && fld->fieldType()!=compoundField && fld->fieldKeyLen()>0) { // but also indexed, to get here
1649 // NOTE at any time until this point, field's indexed status or calculator could be removed
1650  fld->storeCalculatedValues(); // now it's safe to make this decision
1652  }
1653  }
1654  else
1655  mFieldCtreeMap[i].mIndexNo = 0;
1656 
1657  if (fld->fieldIsKeywordIndexed()) {
1658  if (!mKeywordIndex)
1659  mKeywordIndex = new OOF_ctreeKeywordIndex;
1660  mKeywordIndex->appendFieldNo(i);
1661  }
1662  } // loop through fields
1663 
1664  assert( Invariant("ctB::BuildBackendtables-exit") );
1665 }
1666 
1667 
1668 COUNT
1669 OOF_ctreeBackend::RebuildIndexMap(const char* newIDXname)
1670 {
1671  assert( Invariant("ctB::RebuildIndexMap-entry") );
1672 
1673  assert(mFieldBufMap);
1674  assert(mFieldBufMapRefCount);
1675  unsigned int numfields = mFields.count();
1676  COUNT indexFileNo = sNextFileNo;
1677  COUNT startingNewIndexNo = indexFileNo;
1678  for (unsigned int i = 0; i < numfields; i++) {
1679  dbField *fld = (dbField *) mFields[i]; // safe downcast
1680 // only interested if never had index before
1681  if ((mFieldCtreeMap[i].mIndexNo==0) && (fld->fieldNumIndexes())) {
1682  mFieldCtreeMap[i].mIndexNo = indexFileNo;
1683  mFieldCtreeMap[i].mAlternateIndexName = newIDXname;
1684  indexFileNo++;
1685  mNumIndexes++;
1686  sNextFileNo++;
1687  }
1688  }
1689 
1690  assert( Invariant("ctB::RebuildIndexMap-exit") );
1691  return startingNewIndexNo;
1692 }
1693 
1694 
1695 void
1697 {
1698  assert( Invariant("ctB::loadBlob-entry") );
1699 
1701  LONG blobPos = BlobPosFromBuffer(blob, mBuffer);
1702  if (blobPos==0) {
1703  blob->reset();
1704  assert( Invariant("ctB::loadBlob-exit no blob") );
1705  return; // EXIT FOR NO BLOB
1706  }
1707 
1708  VRLEN len = BlobLenFromBuffer(blob, mBuffer);
1709  if (len==0) {
1710  blob->reset();
1711  assert( Invariant("ctB::loadBlob-exit no blob") );
1712  return; // EXIT FOR NO BLOB (was a blob and shrunk to nothing)
1713  }
1714 
1715  VRLEN fileLen = ::VDataLength(mBlobFilNo, blobPos);
1716  if (fileLen>0) {
1717  if (fileLen!=len) {
1718  oofE_TableError err(mTable, stringstream() << flush
1719  << "Error in loadBlob len from file differs from parent's len"
1720  << "file length: " << fileLen << " parent saved length: " << len
1721  << " record offset: " << blobPos
1722  << endl);
1723  RAISE_EXCEPTION(err);
1724  }
1725 
1726  void *body = blob->allocRoomFor(len);
1727  COUNT err = ::ReadVData(mBlobFilNo, blobPos, body, len);
1728  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
1730  #endif
1731  if (err != NO_ERROR) {
1732  oofE_CtreeBlobError excp(mTable, blob->fieldNumber(), err, blobPos, len,
1733  "ReadVData from blob file", "OOF_ctreeBackend::loadBlob");
1734  RAISE_EXCEPTION(excp);
1735  }
1736  }
1737  else { // ALWAYS an error - we don't bother storing 0-length blobs
1738  if (mConnection->uerr_cod()!=NO_ERROR) {
1740  blobPos, -1, "get VDataLength from blob file", "OOF_ctreeBackend::loadBlob");
1741  RAISE_EXCEPTION(excp);
1742  }
1743  else {
1744  oofE_TableError excp(mTable, stringstream() << flush
1745  << "c-tree error in loadBlob, length of 0 returned for offset "
1746  << blobPos << endl);
1747  RAISE_EXCEPTION(excp);
1748  }
1749  }
1750  assert( Invariant("ctB::loadBlob-exit") );
1751 }
1752 
1753 
1754 void
1755 OOF_ctreeBackend::BuildKey(COUNT keyIndexNo, char* target, const char* keyStr, COUNT keyStrLen, VRLEN keyLen) const
1756 {
1757  memset(target, 0, keyLen);
1758  if (keyLen < keyStrLen)
1759  keyStrLen = keyLen; // truncate search string to max width of key!
1760  memcpy(target, keyStr, keyStrLen);
1761  pTEXT keyPtr = ::TransformKey(keyIndexNo, target);
1762  assert(keyPtr);
1763  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
1765  #endif
1766 }
1767 
1768 
1769 void
1770 OOF_ctreeBackend::BuildKey(COUNT keyIndexNo, char* target, const char* keyStr, COUNT keyStrLen, VRLEN keyLen, LONG suffix) const
1771 {
1772  memset(target, 0, keyLen);
1773  if (keyLen < keyStrLen)
1774  keyStrLen = keyLen; // truncate search string to max width of key!
1775  memcpy(target, keyStr, keyStrLen);
1776  pTEXT keyPtr = ::TransformKey(keyIndexNo, target);
1777  assert(keyPtr);
1778  memcpy(target+keyLen, &suffix, sizeof(LONG));
1779 // *((LONG*) (target+keyLen)) = suffix; // after the duplicate suffix has been set to zero
1780  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
1782  #endif
1783 }
1784 
1785 
1786 void
1787 OOF_ctreeBackend::BuildKey(COUNT keyIndexNo, char* target, const VOID* binKey, VRLEN keyLen) const
1788 {
1789  memcpy(target, binKey, keyLen);
1790  pTEXT keyPtr = ::TransformKey(keyIndexNo, target);
1791  assert(keyPtr);
1792  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
1794  #endif
1795 }
1796 
1797 
1798 void
1799 OOF_ctreeBackend::BuildKey(COUNT keyIndexNo, char* target, const VOID* binKey, VRLEN keyLen, LONG suffix) const
1800 {
1801  memcpy(target, binKey, keyLen);
1802  pTEXT keyPtr = ::TransformKey(keyIndexNo, target);
1803  assert(keyPtr);
1804  memcpy(target+keyLen, &suffix, sizeof(LONG));
1805 // *((LONG*) (target+keyLen)) = suffix; // after the duplicate suffix has been set to zero
1806  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
1808  #endif
1809 }
1810 
1811 
1812 void
1813 OOF_ctreeBackend::LoadRecordAtOffset(unsigned long offset)
1814 {
1815  assert( Invariant("ctB::LoadRecordAtOffset-entry") );
1816 
1817  if(mDirty)
1819 
1820  if (!MaybeLoadRecordFromCache(offset)) {
1821  COUNT err ;
1822  err = ::SetRecord(mISAMdatno, offset, 0, 0);
1823  if (err!=NO_ERROR) {
1824  oofE_CtreeISAMErrorAtOffset excp(mTable, mISAMdatno, offset, err, "SetRecord",
1825  "OOF_ctreeBackend::LoadRecordAtOffset");
1826  RAISE_EXCEPTION(excp);
1827  }
1829  err = ::ReReadRecord(mISAMdatno, mBuffer);
1830  END_LOCK_WAIT(err)
1831  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
1833  #endif
1834  if (err==ITIM_ERR)
1835  memset(mBuffer, 0, mRecBufLen); // HORRIBLE HACK FOR NOW, RETURN EMPTY RECORD
1836  else {
1837  if (err!=NO_ERROR) {
1838  oofE_CtreeISAMErrorAtOffset excp(mTable, mISAMdatno, offset, err, "ReReadRecord",
1839  "OOF_ctreeBackend::LoadRecordAtOffset");
1840  RAISE_EXCEPTION(excp);
1841  }
1842  }
1843  CompleteLoadFromOffset(offset);
1844  }
1845 #ifdef OOF_DebugDumpBlobState
1846  describeBlobs();
1847 #endif
1848  assert( Invariant("ctB::LoadRecordAtOffset-exit") );
1849 }
1850 
1851 
1852 void
1853 OOF_ctreeBackend::CompleteLoadFromOffset(LONG offset)
1854 {
1855  assert( Invariant("ctB::CompleteLoadFromOffset-entry") );
1856 
1857  mCurrLoadedRecOffset = offset;
1859  mDirty = false;
1860 
1861  assert( Invariant("ctB::CompleteLoadFromOffset-exit") );
1862 }
1863 
1864 
1865 unsigned long
1867 {
1869  unsigned long serialNbr = ::GetSerialNbr(mISAMdatno);
1870 // DESPITE comment on page F-121 of the Function Reference, the above may return 0
1871 // if you have never added records to the file.
1872  return serialNbr;
1873 }
1874 
1875 
1876 void
1878 {
1879  if (mRecordState!=eLoaded)
1880  return; //*** EARLY exit - unloaded or new record, so nothing on disk to lock
1881 
1882  assert(mCurrLoadedRecOffset);
1883  COUNT err = LockCtData(mISAMdatno, ENABLE, mCurrLoadedRecOffset);
1884  if (err==DLOK_ERR) {
1885  oofE_RecordLocked excp(mTable); // MS VC4 & earlier bug with throwing singl-param local objects
1886  RAISE_EXCEPTION(excp);
1887  }
1888  else
1889  if (err) {
1891  "OOF_ctreeBackend::lockRecord");
1892  RAISE_EXCEPTION(excp);
1893  }
1894 }
1895 
1896 
1897 void
1899 {
1900  if ((mRecordState==eNew) || (mCurrLoadedRecOffset==0))
1901  return; //*** EARLY exit - unloaded or new record, so nothing on disk to lock
1902 
1903 // we may have unloaded a record but still have mCurrLoadedRecOffset and probably still have a lock!
1904  COUNT err = LockCtData(mISAMdatno, FREE, mCurrLoadedRecOffset);
1905  if (err && err!=UDLK_ERR) { // not an error if no lock present
1907  "unlock record", "OOF_ctreeBackend::unlockRecord");
1908  RAISE_EXCEPTION(excp);
1909  }
1910 }
1911 
1912 // ---------------
1913 // transaction code
1914 //------------------
1915 
1916 
1917 void
1919 {
1920 #ifdef TRANPROC
1921  COUNT res;
1922 
1923  if(tMode)
1924  res = ::Begin(tMode);
1925  else
1926  res = ::Begin(sTransMode);// full recovery no auto locks
1927  if (!res) {
1928  long bug = mConnection->uerr_cod();
1930  "OOF_ctreeBackend::beginTransaction");
1931  RAISE_EXCEPTION(excp);
1932  }
1933 #else
1934  #ifdef __MWERKS__
1935  #pragma unused(tMode)
1936  #endif
1937 #endif
1938 }
1939 
1940 
1941 void
1943 {
1944 #ifdef TRANPROC
1945  COUNT err;
1946  if(rMode)
1947  err = ::Commit(rMode);
1948  else
1949  err = ::Commit(sTransReleaseMode);
1950  if (err) {
1951  oofE_CtreeISAMErrorAtOffset excp(mTable, mISAMdatno, mCurrLoadedRecOffset, err, "Commit transaction",
1952  "OOF_ctreeBackend::commitTransaction");
1953  RAISE_EXCEPTION(excp);
1954  }
1955 #else
1956  #ifdef __MWERKS__
1957  #pragma unused(rMode)
1958  #endif
1959 #endif
1960 }
1961 
1962 
1963 void
1965 {
1966 #ifdef TRANPROC
1967  int recpos = CurrentFileOffset(mISAMdatno);
1968 
1969  COUNT err;
1970 
1971  if(rMode)
1972  err = ::AbortXtd (rMode);
1973  else
1974  err = ::AbortXtd (sTransReleaseMode);
1975 
1976  recpos = ::CurrentFileOffset(mISAMdatno);
1977 
1978  if (err) {
1979  oofE_CtreeISAMErrorAtOffset excp(mTable, mISAMdatno, mCurrLoadedRecOffset, err, "Abort transaction",
1980  "OOF_ctreeBackend::abortTransaction");
1981  RAISE_EXCEPTION(excp);
1982  }
1983 #else
1984  #ifdef __MWERKS__
1985  #pragma unused(rMode)
1986  #endif
1987 #endif
1988 }
1989 
1990 
1991 // -------------------------------------------------------
1992 // D O D A I n t e r f a c e
1993 // -------------------------------------------------------
1994 
1995 
1997 mDODA(0),
1998 mCurrentObj(0),
1999 mBufferLength(0)
2000 {
2001 
2002 
2003 }
2004 
2006 mDODA(0),
2007 mCurrentObj(0),
2008 mBufferLength(0)
2009 {
2010  loadDODA(datno);
2011 
2012 }
2013 
2014 
2016 mDODA(0),
2017 mCurrentObj(0),
2018 mBufferLength(0)
2019 {
2020  loadDODA(fileName , ext, iExt);
2021 
2022 }
2023 
2025 {
2026  if(mDODA)
2027  delete [] mDODA;
2028 }
2029 
2030 
2034 void
2036 {
2037 
2038  mIFIL.pfilnam = inFile.charsForOldInterfacesNotWriting();
2039  mIFIL.dfilno = 1; // i think this will do
2040  COUNT err = ::OpenIFileXtd(&mIFIL, ext.charsForOldInterfacesNotWriting(), iExt.charsForOldInterfacesNotWriting(), 0); // no security word
2041  loadDODA(1);
2042  if (CloseIFile(&mIFIL))
2043  {
2044  }
2045 }
2046 
2047 
2048 void
2049 DODAInterface::loadDODA(oofString &inFile, oofString &connectionName, oofString& ext, oofString& iExt)
2050 {
2051 
2052  TEXT tempName[32] = "buildingschema";
2053  stSaveDirectory willReturnToCurrentDir;
2054  oofDirectory *databaseDir = new oofDirectory(connectionName, "", true /* create dirs if necessary */);
2055  databaseDir->gotoDirectory();
2056 
2057  #ifndef MULTITRD
2058  #ifdef ctNOGLOBALS
2059  COUNT regErr = ::RegisterCtree(tempName);
2060  //if (regErr!=NO_ERROR) {
2061  // oofE_CtreeConnectionError excp(this, regErr, "register c-tree", "SetupConnection");
2062  // RAISE_EXCEPTION(excp);
2063  //}
2064  //#ifdef _Windows
2065  //mCtreeVars = ::GetCtreePointer(mCtreeInstanceName); // was GetCtreeGV();
2066  //#else
2067  //mCtreeVars = ctWNGV; // the global is used elsewhere (does this stuff Mac XCMDS???)
2068  #endif
2069  #else
2070  if (sConnectionsOpened>1) {
2071  oofE_CtreeConnectionError err(this,
2072  "You must build the c-tree libraries with ctNOGLOBALS to open multiple databases simultaneously.");
2073  RAISE_EXCEPTION(err);
2074  }
2075  #endif // ctNOGLOBALS
2076  //COUNT initerr = ::InitISAMXtd(3, 1, 1, 8, 0, 0, 0, 0);
2077  COUNT err = ::InitISAMXtd(6, 8, 8, 8, 0, 0, 0, 0);
2078 
2079  mIFIL.pfilnam = inFile.charsForOldInterfacesNotWriting();
2080  // there may be some differences depending on whether we use superfiles or not
2081  // and remember that the table name now includes the superfile name and so
2082  // cannot be determined until the time that the actual database file name is
2083  // known - ie: after the physical database has been opened or created.
2084 // ----------- mIFIL.dfilno = -1; // auto assign
2085  mIFIL.dfilno = 50; // auto-assign via negative not working?
2086  mIFIL.dreclen = 2;
2087  mIFIL.dxtdsiz = 0;//kDataExtendSize;
2088  mIFIL.dfilmod = OOF_ctreeBackend::sFileMode | ctFIXED;
2089  mIFIL.dnumidx = 0; // try and read withou the indexes
2090  mIFIL.ixtdsiz = 0;
2091  mIFIL.ifilmod = 0;
2092  mIFIL.ix = 0;
2093  mIFIL.rfstfld = 0;
2094  mIFIL.rlstfld = 0;
2095  err = ::OpenIFileXtd(&mIFIL, ext.charsForOldInterfacesNotWriting(), iExt.charsForOldInterfacesNotWriting(), 0); // no security word
2096  loadDODA(50);
2097 
2098 
2099 
2100  if (::CloseIFile(&mIFIL)){
2101  oofE_General err("Unable to close file after loading a DODA");
2102  RAISE_EXCEPTION(err);
2103  }
2104  err = CloseISAM();
2105  ::UNRCTREE(tempName);
2106  delete databaseDir;
2107 
2108 
2109 }
2110 
2111  void
2113  {
2114  VRLEN result;
2115  DATOBJ scrap;// just so we can read the doda to se how big it is
2116  if(mDODA){// do we already have a buffer
2117  result = ::GetDODA( datno,sizeof(DATOBJ),mDODA,SCHEMA_DODA); // try and use it
2118  if(result != mBufferLength){
2119  delete [] mDODA;// old bugffer to smal so get another one
2120  mDODA = (DATOBJ*)new char[result];
2121  mBufferLength = result;
2122  result = ::GetDODA( datno,sizeof(DATOBJ),mDODA,SCHEMA_DODA); // try and use it
2123  if(!result){
2124  //oofE_CtreeISAMError excp(mTable, datno, mConnection->uerr_cod(), "loading doda", "DODAInterface::loadDODA");
2125  //RAISE_EXCEPTION(excp);
2126  }
2127 
2128  }
2129  }else{
2130  result = ::GetDODA( datno,sizeof(DATOBJ),&scrap,SCHEMA_DODA);
2131  if(result){
2132  // unsigned long spod = result/sizeof(DATOBJ);
2133  //buf = new DATOBJ[result/sizeof(DATOBJ)];
2134  //assert(mDODA !=0);
2135  mDODA = (DATOBJ*)new char[result];
2136  mBufferLength = result;
2137  result = ::GetDODA( datno,result,mDODA,SCHEMA_DODA);
2138  if(!result){
2139  //oofE_CtreeISAMError excp(mTable, datno, mConnection->uerr_cod(), "loading doda", "DODAInterface::loadDODA");
2140  //RAISE_EXCEPTION(excp);
2141  }
2142  }
2143  else {
2144  //oofE_CtreeISAMError excp(mTable, datno, mConnection->uerr_cod(), "loading DODA to get buffer size", "DODAInterface::loadDODA");
2145  //RAISE_EXCEPTION(excp);
2146  }
2147 
2148 
2149 
2150  }
2151 }
2152 
2153 dbField *
2154 DODAInterface::makeField(OOF_fieldTypes theField,unsigned long theFieldWidth, const char* theFieldName)
2155 {
2156 
2157  dbField *res;
2158  switch (theField) { // see oofXMLDBWriter::fieldtype2Attributes
2159  case charField:
2160  res = new dbChar(theFieldWidth, theFieldName);
2161  break;
2162 
2163  case textField:
2164  res = new dbText(theFieldName);
2165  break;
2166 
2167  case shortField:
2168  res = new dbShort(theFieldName);
2169  break;
2170 
2171  case uShortField:
2172  res = new dbUshort(theFieldName);
2173  break;
2174 
2175  case longField:
2176  res = new dbLong(theFieldName);
2177  break;
2178 
2179  case uLongField:
2180  res = new dbUlong(theFieldName);
2181  break;
2182 
2183  case realField:
2184  res = new dbReal(theFieldName);
2185  break;
2186 
2187  case dateField:
2188  res = new dbDate(theFieldName);
2189  break;
2190 
2191  case dateTimeField:
2192  res = new dbDateTime(theFieldName);
2193  break;
2194 
2195  case timeField:
2196  res = new dbTime(theFieldName);
2197  break;
2198 
2199  default:
2200  {
2201  oofE_General excp(stringstream() << flush
2202  << "Can't yet handle field type"
2203  << theField
2204  );
2205  RAISE_EXCEPTION(excp);
2206  // NOT YET IMPLEMENTED
2207  }
2208  }
2209  return res;
2210 
2211 }
2212 
2213 
2218 void
2220 {
2221  dbField* theField;
2222  bool nextFieldIsBlob = false;
2223  OOF_fieldTypes theType;
2224  //UCOUNT ctType;
2225 
2226  dbTableOwningFields* buildingTable = new dbTableOwningFields((const char*)mIFIL.pfilnam); // append to connection we are building, before newConnection called
2227  oofString defaultExt = "";
2228  for(start();more();next()){
2229  if(strncmp("dummy",fieldName(),5)==0){
2230  if(fieldType() == CT_INT4){
2231  nextFieldIsBlob = true;
2232  }else{
2233  assert(fieldType() == CT_FSTRING);
2234 
2235  }
2236  }else{ // It's not a dummy
2237  //theFieldName = schemaMap.fieldName();
2238 
2240  //fieldLength = fieldLength();
2241  if(nextFieldIsBlob){
2242  nextFieldIsBlob = false;
2243  assert(fieldType() == CT_INT4);
2244  //theType = blobField;
2245  theType = textField;
2246  }else{
2248  }
2249  theField = makeField(theType,fieldLength(),fieldName());
2250  buildingTable->adoptField(theField); // apphend field
2251 
2252  }
2253 
2254  }
2255 }
2256 
2257 
2258 
2259 void
2261 {
2262  for(start();more();next()){
2263  os << "DATOBJ[" << mCurrentObj<<"] " << endl
2264  <<" fieldName: "<< fieldName()<< endl
2265  <<" fieldAddress: "<< fieldAddress()<< endl
2266  <<" fieldType: "<< fieldType()<< endl
2267  <<" fieldLength: "<< fieldLength()<< endl << endl;
2268 
2269  }
2270 
2271 }
unsigned int * mFieldBufMapRefCount
Definition: oofrecs.h:562
dbQueryBinary startsWith(const char *str) const
Definition: oof3.cpp:2463
fieldNumT fieldNo(unsigned short segmentNo) const
Definition: oofctrex.h:499
virtual void selectAll()
Definition: oofrec1.cpp:1353
OOF_ExpandableLongArray * mBlobFieldNums
Definition: oofrecs.h:566
void finishMap(unsigned short numFields)
Definition: oofrec1.cpp:1498
Persistent field used to store a double.
Definition: oof4.h:521
Exception for database connection to c-tree Plus backend.
Definition: oofexcep.h:72
virtual void BuildBackendtables(bool rebuilding)
backend construction
Definition: oofctre1.cpp:1578
virtual void saveRecord()
Save current main record and any cached dirty records.
Definition: oofctre1.cpp:517
unsigned short mNumFiles
Definition: oofrecs.h:563
virtual bool usesSeparateStorageFiles() const
Definition: oofctre4.cpp:625
unsigned long mLength
Definition: oofrecs.h:42
static void raise(std::ostream &, bool terminateAfterMsg=true)
unsigned long count()
Count records in current selection.
Definition: oof1.h:2017
virtual const char * word() const
returns the current word.
Definition: oofwords.cpp:228
void appendFieldNo(fieldNumT)
Definition: oofctre1.cpp:147
void deleteWords(oidT, fieldNumT) const
Definition: oofctre1.cpp:336
fieldNumT fieldNumber() const
Definition: oof3.h:754
virtual void addIndices(const char *newIDXname)
Definition: oofctre1.cpp:1021
static long sFileMode
Definition: oofctrex.h:445
typedef LONG(ctDECL *ctComparativeKeySearch)(COUNT
virtual const oofString & fieldName() const
Definition: oof3.h:769
precompilation header.
long allocBlobFilNo()
Definition: oofctre4.cpp:271
static long sTransReleaseMode
Definition: oofctrex.h:447
Tries to hide the different platforms and version issues with standard IO.
Exception where we get a c-tree error number and know the record address.
Definition: oofexcep.h:380
bool more()
Definition: oofctrex.h:575
Base class for user-replaceable word parser.
Definition: oofwords.h:40
virtual bool fieldIsUniqueIndexed() const
Definition: oof3.cpp:422
virtual void abortTransaction(COUNT rMode=0)
Definition: oofctre1.cpp:1964
virtual unsigned short countSegments() const
Definition: oof1.h:2577
bool fieldIndexIgnoresNulls() const
Definition: oof3.h:699
#define WITH_LOCK_WAIT
Definition: oofctrex.h:92
Simplest internal representation of a record's contents and context in dbTable.
Definition: oofrecs.h:130
virtual void loadBlob(const dbBLOB *)
Definition: oofctre1.cpp:1696
unsigned long mOffset
Definition: oofrecs.h:42
OOF_dirtyFieldMap mDirtyMap
Definition: oofrecs.h:158
bool isDirty() const
Definition: oof3.h:857
bool isDirty(unsigned short) const
Definition: oofrecs.h:782
Envelope class to contain an abstract selection apart from its dbTable.
Definition: oof1.h:316
virtual void unloadRecord()
Definition: oofctre1.cpp:529
virtual void beginTransaction(COUNT tMode=0)
Definition: oofctre1.cpp:1918
bool indexesField(fieldNumT) const
Definition: oofctre1.cpp:161
const dbField * field(unsigned int) const
Definition: oof3.cpp:2413
virtual bool fieldIsIndexed() const
Definition: oof3.cpp:408
virtual bool isEmpty() const
Definition: oof3.cpp:170
#define END_LOCK_WAIT(filErr)
Definition: oofctrex.h:99
void start()
Definition: oofctrex.h:569
Exception for database table operation resulting in duplicate record error.
Definition: oofexcep.h:167
unsigned short fieldKeyLen() const
Definition: oof3.cpp:430
void start()
Definition: oof1.cpp:2057
Abstract base for string fragment queries like OOF_mixKeywordableField::hasAnyWordsOf.
Definition: oofquery.h:355
char * allocRoomFor(unsigned long) const
Definition: oof3.h:885
virtual unsigned long fieldStorageLen() const =0
Definition: oof3.h:26
unsigned long BlobPosFromBuffer(const dbField *fld, const char *theirBuffer) const
Definition: oofrecs.h:749
virtual void rebuild()
Definition: oofctre1.cpp:1086
COUNT mBlobFilNo
Definition: oofctrex.h:442
OOF_recordSelection mSelection
Definition: oofrecs.h:560
void searchField(dbTable *, fieldNumT, const char *, bool startsWith=false) const
Definition: oofctre1.cpp:213
unsigned long count() const
Definition: oofarray.h:126
bool caseSensitive() const
Definition: oof3.h:747
void CacheDirtyCurrentRecord()
Definition: oofrec1.cpp:935
void append(oidT)
Definition: oofrecs.h:1020
virtual void newRecord()
Definition: oof1.cpp:2090
void append(OOF_bitPointer)
Definition: oof1.h:1551
void reset() const
Definition: oof3.h:878
unsigned short mNumIndexes
Definition: oofrecs.h:563
dbTable * prototype() const
Definition: oof1.h:2477
bool MaybeLoadRecordFromCache(unsigned long offset)
Definition: oofrec1.cpp:1014
void next()
Definition: oofctrex.h:584
virtual void deleteRecord()
Definition: oofctre1.cpp:814
unsigned long PadFieldWidthForAlignment(const dbField *fld) const
Definition: oofrec1.cpp:101
char * charsForOldInterfacesNotWriting() const
Definition: oofstr.h:396
unsigned long currentOffset() const
Definition: oofrecs.h:718
virtual void setFileExtensions(const char *dataExt, const char *indexExt)
Definition: oofctre1.cpp:541
COUNT indexFileNo() const
Definition: oofctrex.h:507
OOF_bitPointer value(unsigned int index) const
Definition: oof1.h:1594
bool isReversed() const
Definition: oof3.h:958
bool search(const dbQueryClause &query)
Definition: oof1.cpp:2348
virtual OOF_fieldTypes nativeType() const
Definition: oof3.cpp:301
virtual void open()
Definition: oofctre1.cpp:1216
Persistent field used to store an unsigned short.
Definition: oof4.h:317
static long sFileMode
Definition: oofctree.h:123
virtual void start()
sets the oofWordParser to the start of the string.
Definition: oofwords.cpp:196
const OOF_Selection * internalSelection() const
Definition: oof2.h:317
unsigned short fieldNumIndexes() const
Definition: oof3.h:723
bool isEmpty()
Definition: oof1.cpp:2107
unsigned int FieldAlignsTo(const dbField *) const
Definition: oofrec1.cpp:123
virtual void saveRecord()
Save current main record and any cached dirty records.
Definition: oofrec1.cpp:788
void loadDODA(COUNT)
Definition: oofctre1.cpp:2112
Main implementation parent for backends following the record-oriented model.
Definition: oofrecs.h:295
Describe c-tree index as list of fields.
Definition: oofctrex.h:147
virtual ~OOF_ctreeIndexSegList()
Definition: oofctre1.cpp:54
Wrap reading and writing elements of a c-tree Plus DODA which describes fields in a record...
Definition: oofctrex.h:535
void blobsHaveBeenFound()
Definition: oofctre4.cpp:264
bool IgnoringDuplicateRecords() const
Definition: oofrecs.h:763
Manage keyword indexing for a dbTable which has indexed fields.
Definition: oofctrex.h:235
virtual bool openTableInConnection(const dbConnect *, const bool createIfMissing=false)
Definition: oofctre1.cpp:1178
bool contains(unsigned long value) const
Definition: oofarray.cpp:174
void searchTable(dbTable *, const char *, bool startsWith=false) const
Definition: oofctre1.cpp:279
virtual bool fieldIsKeywordIndexed() const
Definition: oof3.cpp:415
Exception where we get a c-tree error number for an operation on a variable-length BLOB...
Definition: oofexcep.h:417
bool contains(const char *) const
Definition: oofwords.cpp:318
bool lockedCurrentRecord() const
Definition: oof1.h:2470
unsigned long & item(unsigned long index)
Definition: oofarray.h:168
void updateWords(dbTable *inTable, bool isNew, const OOF_dirtyFieldMap &)
Definition: oofctre1.cpp:352
bool isReadLocked() const
Definition: oofctree.h:133
Definition: oof3.h:26
virtual void newRecord()
Sets up a new record ready to enter data On exit the state is: Selection state is aboutToDirty Select...
Definition: oofctre1.cpp:502
Exception where we get a c-tree error number back for diagnosis.
Definition: oofexcep.h:363
virtual void commitTransaction(COUNT rMode=0)
Definition: oofctre1.cpp:1942
Implement the backend for Faircom's c-tree Plus ISAM engine including locking and indexed searches...
Definition: oofctrex.h:288
void addRecordForOID(const char *theWord, fieldNumT, oidT)
Definition: oofctre1.cpp:378
void rebuild()
Definition: oof1.cpp:1173
void deleteSelection()
Definition: oof1.cpp:1765
virtual const char * current()=0
Selection of records in context of a single dbTable instance.
Definition: oofrecs.h:173
const dbCompoundField * indexField() const
Definition: oofctrex.h:514
Definition: oof3.h:26
bool isEmpty() const
Test based on either length or null pointer.
Definition: oofstr.h:413
void gotoDatabaseDir() const
Definition: oof1.cpp:675
unsigned long oidT
type we pass around pretending we have a real OID.
Definition: oof1.h:229
OOF_String makeTableName(const char *) const
Definition: oofctre4.cpp:593
Abstract interface to database backend.
Definition: oof1.h:1047
void selectNone()
Change the current selection to no records.
Definition: oof1.h:2321
short uerr_cod() const
Definition: oofctre4.cpp:764
virtual bool isEmpty() const
Definition: oofrecs.h:910
bool fieldIndexIsCompressLeading() const
Definition: oof3.h:707
void SetBlobLenInBuffer(fieldNumT, unsigned long len, const char *theirBuffer) const
Definition: oofrec1.cpp:254
statically stored self-incrementing const char*'s
Definition: oof2.h:85
OOFILE table to be used for keywords.
Definition: oofctrex.h:205
Persistent field used to store a date and time.
Definition: oof4.h:929
OOF_recordFieldEntry * mFieldBufMap
Definition: oofrecs.h:561
unsigned long BlobLenFromBuffer(const dbField *, const char *theirBuffer) const
Definition: oofrecs.h:742
virtual void union_with(const OOF_Selection *)
Definition: oofrec2.cpp:2181
const oofString & tableName() const
Definition: oof1.h:2369
Persistent field used to store a fixed-length string.
Definition: oof3.h:255
dbSelection currentSelection()
Definition: oof1.cpp:2674
dbField * makeField(OOF_fieldTypes theField, unsigned long fieldWidth, const char *fieldName)
Definition: oofctre1.cpp:2154
void setSelection(const dbSelection &)
Definition: oof1.cpp:2725
Array of longs which expands automatically with refcount so easily shared.
Definition: oof2.h:48
COUNT mISAMdatno
Definition: oofctrex.h:442
Exception for database table operation failure due to locking conflict.
Definition: oofexcep.h:186
OOF_fieldTypes
Definition: oof3.h:26
Portable way to refer to files.
Definition: ooffiles.h:66
Exception for unclassified use when nothing else is better.
Definition: oofexcep.h:325
void searchFieldAnyWords(dbTable *, fieldNumT, dbQueryLiteralStrMultiValue *, bool startsWith=false) const
Definition: oofctre1.cpp:257
bool tableCachesDirtyRecords() const
Definition: oof1.h:2518
Array of longs which expands automatically as you write to cells.
Definition: oofarray.h:21
#define RAISE_EXCEPTION(E)
Macro to allow us to either throw an exception or call dbConnect::raise.
Definition: oofexcep.h:31
OOF_Segment * segment(unsigned int) const
Definition: oof1.h:2592
const char * fieldName() const
Definition: oofctrex.h:591
dbField * field(fieldNumT) const
Definition: oof1.h:2355
Describe entries in schema like OOF_simpleRecordBackend::mFieldBufMap.
Definition: oofrecs.h:38
virtual void createTableInConnection(const dbConnect *)
Definition: oofctre1.cpp:1149
Persistent field used to store a set of segments referring to other fields.
Definition: oof3.h:575
ERecordState mRecordState
Definition: oofrecs.h:153
dbConnect_ctree * mConnection
Definition: oofctrex.h:443
virtual void lockRecord()
Definition: oofctre1.cpp:1877
unsigned int count() const
Definition: oof1.h:1498
unsigned short fieldNumT
Definition: oof1.h:276
Base class for persistent tables.
Definition: oof1.h:452
virtual void close()
Definition: oofctre1.cpp:1244
Definition: oof3.h:26
Persistent field used to store a date.
Definition: oof4.h:577
void next()
Next record in the selection becomes current.
Definition: oof1.h:1970
Definition: oof3.h:26
Portable highly capable string class.
Definition: oofstr.h:101
Definition: oof3.h:26
void deleteStorage()
Definition: oof1.cpp:1198
Connection that manufactures OOF_ctreeBackend backends.
Definition: oofctree.h:39
Describe a subset of fields in a table which are dirty.
Definition: oofrecs.h:51
unsigned long mRecBufLen
Definition: oofrecs.h:155
virtual void unloadRecord()
Definition: oofrec1.cpp:828
Save the current directory and restore when we leave scope.
Definition: ooffiles.h:362
void appendFieldNo(fieldNumT)
Definition: oofctre1.cpp:61
void append(unsigned long)
Definition: oofarray.cpp:131
void storeCalculatedValues()
Definition: oof3.h:813
Persistent field used to store a short.
Definition: oof4.h:272
void searchTableAnyWords(dbTable *, dbQueryLiteralStrMultiValue *, bool startsWith=false) const
Definition: oofctre1.cpp:318
virtual void buildSchema(bool rebuilding=false)
Definition: oofctre1.cpp:1118
oofDirectory * databaseDirectory() const
Definition: oof1.h:1683
virtual bool fieldIsVirtual() const
Definition: oof3.cpp:400
void fieldHasStoredCalculator(dbField *)
Definition: oof1.h:1747
virtual void saveRecord()
Definition: oof1.cpp:1689
Persistent field used to store a time without date.
Definition: oof4.h:751
void suppressIndices()
Definition: oof1.cpp:1208
bool fieldIndexIsCompressPadding() const
Definition: oof3.h:715
virtual void intersection_with(const OOF_Selection *)
Definition: oofrec2.cpp:2038
#define OOF_MEM_DEBUG_FORCE_POOL_CHECK
Definition: doxyoof.h:408
unsigned long mCurrLoadedRecOffset
Definition: oofrecs.h:154
Provides cross-platform directory specification and iteration.
Definition: ooffiles.h:235
Persistent field used to store a variable length string.
Definition: oof3.h:459
virtual void newRecord()
Sets up a new record ready to enter data On exit the state is: Selection state is aboutToDirty Select...
Definition: oofrec1.cpp:965
Store extra field info for OOF_ctreeBackend beyond normal OOFILE schema details.
Definition: oofctrex.h:128
bool more() const
Definition: oofarray.h:147
void describe(std::ostream &)
Definition: oofctre1.cpp:2260
virtual OOF_fieldTypes fieldType() const =0
virtual bool more() const
return true if any words left.
Definition: oofwords.cpp:217
Contain a list of words parsed from an input string or field being word-indexed.
Definition: oofwords.h:107
const OOF_String & nextDummy()
Definition: oof2.cpp:41
void decRefs()
Definition: oof1.cpp:3212
void makeTable()
Grotty DavidG code.
Definition: oofctre1.cpp:2219
bool startsWith(fieldNumT) const
Definition: oofctrex.h:521
Persistent field used to store an arbitrary binary object.
Definition: oof3.h:387
selSharingT
Definition: oof1.h:463
Base exception for table operations that can report more details.
Definition: oofexcep.h:442
void buildSchema(dbTable *parentTable)
Definition: oofctre1.cpp:154
void gotoRecord(unsigned long)
Definition: oofrecs.h:982
dbTable * mTable
Definition: oof1.h:1234
bool Invariant(const char *optionalComment=0) const
Check combination of member variables defining Invariant state.
Definition: oofrec3.cpp:1837
virtual void suppressIndices()
Definition: oofctre1.cpp:1061
void adoptField(dbField *adoptedField)
Definition: oof1.cpp:2832
virtual oofWordParser * words() const
Definition: oof3.cpp:251
EselectionState state() const
Definition: oofrecs.h:846
virtual void deleteStorage()
Definition: oofctre1.cpp:1259
virtual ~OOF_ctreeBackend()
Definition: oofctre1.cpp:460
void updateCurrent(unsigned long)
Definition: oofrec4.cpp:935
void ownsContents(bool ownsFlag=true)
Definition: oof1.h:2557
virtual unsigned long sequenceNumber() const
Definition: oofctre1.cpp:1866
void activateConnection()
Definition: oofctre4.cpp:801
OOF_Dictionary mFields
Definition: oof1.h:1233
oidT currentOID()
Absolute record address of current record.
Definition: oof1.h:1938
virtual void next(void)
Find the next word, updating the mWord pointer returned by word();.
Definition: oofwords.cpp:135
void searchFieldAllWords(dbTable *, fieldNumT, dbQueryLiteralStrMultiValue *, bool startsWith=false) const
Definition: oofctre1.cpp:226
Table used when don't declare with class structure but dynamically create.
Definition: oof2.h:144
void markDirty(unsigned short)
Definition: oofrecs.h:774
bool storesCalculatedValues() const
Definition: oof3.h:806
Persistent field used to store an unsigned long.
Definition: oof4.h:475
virtual void unlockRecord()
Definition: oofctre1.cpp:1898
char * bodyAddress() const
Definition: oof3.cpp:2197
void append(const char *)
Definition: oofwords.cpp:331
UCOUNT fieldType()
Definition: oofctrex.h:604
virtual OOF_tableBackend * clone(dbTable::selSharingT, dbTable *) const
Definition: oofctre1.cpp:902
virtual ~OOF_ctreeKeywordIndex()
Definition: oofctre1.cpp:140
Base class for persistent fields in dbTable's.
Definition: oof3.h:63
void searchTableAllWords(dbTable *, dbQueryLiteralStrMultiValue *, bool startsWith=false) const
Definition: oofctre1.cpp:290
const char * fieldAddress() const
Definition: oofctrex.h:597
void SetBlobPosInBuffer(fieldNumT, unsigned long pos, const char *theirBuffer) const
Definition: oofrec1.cpp:261
virtual void selectNone()
Definition: oofrec1.cpp:1367
unsigned long value(unsigned long index) const
Definition: oofarray.cpp:243
UCOUNT fieldLength()
Definition: oofctrex.h:611
virtual const char * asChars() const
Definition: oof3.cpp:243
static long sTransMode
Definition: oofctrex.h:446
void gotoDirectory() const
Change current dir to this oofDirectory.
static OOF_fieldTypes MapCtreeDODATypeToFieldType(const COUNT t)
Definition: oofctre1.cpp:1424
Abstract interface for database.
Definition: oof1.h:920
void close()
Definition: oof1.cpp:1180
Persistent field used to store a long.
Definition: oof4.h:433
virtual bool fieldIsBlob() const
Definition: oof3.cpp:386