OOFILE  1.9
oofrec3.cpp
Go to the documentation of this file.
1 // OOFILE record-oriented abstract backend implementation
2 //
3 // COPYRIGHT 1994 A.D. Software, All rights reserved
4 
5 
6 #include "oofpch_c.h" // for precompilation of core files
7 
8 #ifndef H_OOFIOS
9  #include "oofios.h"
10 #endif
11 #ifndef H_OOFRECS
12  #include "oofrecs.h"
13 #endif
14 #ifndef H_OOFWORDS
15  #include "oofwords.h"
16 #endif
17 #include <ctype.h>
18 
19 #ifdef OOF_MEM_DEBUG_LAST_INCLUDE
20  #include OOF_MEM_DEBUG_LAST_INCLUDE
21 #endif
22 
23 #ifndef OOF_NO_STDLIB
24  #ifndef std
25  using namespace std;
26  #endif
27 #endif
28 
29 
30 #ifdef OOF_INVARIANT_DUMP_NAME
31  #ifndef _Macintosh
32  // optional statics
33  oofDirectory OOF_simpleRecordBackend::sInvariantDumpDir;
34  ofstream OOF_simpleRecordBackend::sInvariantDump;
35  #endif
36 #endif
37 
38 // -------------------------------------------------------
39 // O O F I L E _ s i m p l e R e c o r d B a c k e n d
40 // see also oofrec1.cpp & oofrec2.cpp
41 // -------------------------------------------------------
42 bool
44 {
45  assert( Invariant("simpleB::search-entry") );
46 
47  dbTable *fieldTableNotUs, *fieldRelatedTable;
48  qClause->getSearchTables(mTable, fieldTableNotUs, fieldRelatedTable);
49  if (fieldTableNotUs) {
50  if (fieldRelatedTable) {
51  if (fieldTableNotUs->search(qClause)) {
52  const bool ret = fieldTableNotUs->relateSelectionFrom(mTable);
53  assert( Invariant("simpleB::search-exit relSelFrom") );
54  return ret;
55  }
56  else {
57  selectNone(); // traversal finds nothing
58  assert( Invariant("simpleB::search-exit found none") );
59  return false; // related search found nothing, no point in traversing
60  }
61  }
62  else {
63  return false; // quick hack - safe failure of bad spec
64  }
65  } // clause not directly only this table
66 
67  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
69  #endif
70 
71  bool ret = false;
72  if (qClause->queryClauseType()==dbQueryClause::builtQuery) // get the actual query
73  qClause = ((dbQuery*) qClause)->query(); // safe downcast
74 
75  switch (qClause->queryClauseType()) {
77  ret = SearchTrinaryFieldToLiterals( (dbQueryTrinary*) qClause); // safe downcast
78  break;
79 
81  ret = SearchBinaryFieldToLiteral( (dbQueryBinary*) qClause); // safe downcast
82  break;
83 
85  dbQueryBinaryCombo* comboClause = (dbQueryBinaryCombo*) qClause; // safe downcast
86  ret = SearchCombineSubclauses(comboClause, false);
87  }
88  break;
89 
90 
92  dbConnect::raise("Table keyword searches are only supported in the ctree backend", false);
93  selectNone();
94  break;
95 
96  default:
97  ret = false;
98  }
99  gotoBOF(); // clear mCurrLoadedRecOffset which may have been set by iterators above
100  unloadRecord(); // Make sure the selection context is logical before returning.
101  // don't want to start() in case triggers sort, as we shouldn't
102  // presume they need the results of the search sorted (eg: may just count)
103 
104  assert( Invariant("simpleB::search-exit") );
105  return ret;
106 }
107 
108 
109 bool
111 {
112  return false; // default for non-indexed backends
113 }
114 
115 
116 bool
118 {
119  assert( Invariant("simpleB::searchSelection-entry") );
120 
121  dbTable *fieldTableNotUs, *fieldRelatedTable;
122  qClause->getSearchTables(mTable, fieldTableNotUs, fieldRelatedTable);
123  if (fieldTableNotUs) {
124  if (fieldRelatedTable) {
125  if (fieldTableNotUs->search(qClause)) {
126  dbSelection narrowingSel = &mSelection;
127  if (fieldTableNotUs->relateSelectionFrom(mTable)) {
128  mSelection.intersection_with(narrowingSel.internalSelection());
129  assert( Invariant("simpleB::searchSelection-exit relSearch") );
130  return mSelection.isEmpty();
131  }
132  else {
133  selectNone(); // traversal finds nothing
134  assert( Invariant("simpleB::searchSelection-exit noneRelated") );
135  return false; // nothing as a search selection is like AND - empty result
136  }
137  }
138  else {
139  selectNone(); // related search found nothing, no point in traversing
140  assert( Invariant("simpleB::searchSelection-exit none found in rel field") );
141  return false; // nothing as a search selection is like AND - empty result
142  }
143  }
144  else {
145  return false; // quick hack - safe failure of bad spec
146  }
147  } // clause not directly only this table
148 
149 
150  bool ret = false;
151  switch (qClause->queryClauseType()) {
153  ret = SearchSelectionTrinaryFieldToLiterals( (dbQueryTrinary*) qClause); // safe downcast
154  break;
155 
157  ret = SearchSelectionBinaryFieldToLiteral( (dbQueryBinary*) qClause); // safe downcast
158  break;
159 
161  ret = SearchCombineSubclauses((dbQueryBinaryCombo*) qClause, true); // safe downcast
162  break;
163  }
164  default:
165  ret = false;
166 
167  }
168  gotoBOF(); // clear mCurrLoadedRecOffset which may have been set by iterators above
169  unloadRecord(); // Make sure the selection context is logical before returning.
170  assert( Invariant("simpleB::searchSelection-exit") );
171  return ret;
172 }
173 
174 
175 bool
176 OOF_simpleRecordBackend::searchEqual(const dbField* schField, const void* schAddress)
177 {
178  assert( Invariant("simpleB::searchEqual(bin)-entry") );
179 
180  selectAll();
181  return SearchEqualNonIndexed(schField, schAddress);
182 }
183 
184 
185 bool
186 OOF_simpleRecordBackend::searchEqual(const dbField* schField, const char* schStr, bool matchEntireKey)
187 {
188  assert( Invariant("simpleB::searchEqual(string)-entry") );
189 
190  selectAll();
191  return SearchEqualNonIndexed(schField, schStr, matchEntireKey);
192 }
193 
194 
195 bool
196 OOF_simpleRecordBackend::SearchEqualNonIndexed(const dbField* schField, const char* schStr, bool matchEntireKey)
197 {
198  assert( Invariant("simpleB::SearchEqualNonIndexed(string)-entry") );
199 
200  if (mSelection.isEmpty()) {
201  assert( Invariant("simpleB::SearchEqualNonIndexed(string)-exit emptySel") );
202  return false;
203  }
204 
206  return SearchEqualNonIndexedWildcard(schField,schStr,matchEntireKey);
207 
208  // Make a new selection into which we can put the result - NOTE: This could be made a lot
209  // more efficient if we made a reasonable stab at the initial size and the chunk size
210  OOF_recordSelection newSelection(mTable->prototype());
211 
212  unloadRecord();
213  if(matchEntireKey) { // True searchequals
214  for(start();more();next()) { // Vertical Iteration through the selection
215  if(OOF_stricmp(schField->asChars(), schStr)==0)
216  newSelection.append(mCurrLoadedRecOffset);
217  unloadRecord();
218  }
219  }
220  else { // Only check if it starts with the key !
221  unsigned int schLen=strlen(schStr);
222  for(start();more();next()) { // Vertical Iteration through the selection
223  if(OOF_strnicmp(schField->asChars(), schStr, schLen)==0)
224  newSelection.append(mCurrLoadedRecOffset);
225  unloadRecord();
226  }
227  }
228 
229  mSelection = newSelection;
230 
231  assert( Invariant("simpleB::SearchEqualNonIndexed(string)-exit") );
232  return !mSelection.isEmpty();
233 }
234 
235 
236 bool
237 OOF_simpleRecordBackend::SearchWordNonIndexed(const dbField* schField, const char* schStr, bool startsWith)
238 {
239  assert( Invariant("simpleB::SearchWordNonIndexed-entry") );
240 
241  if (mSelection.isEmpty())
242  return false;
243 
244 /* if (dbQueryClause::wildcardsInString(schStr))
245  return SearchEqualNonIndexedWildcard(schField,schStr,matchEntireKey);
246 NOT YET IMPLEMENTED - cope with wildcards in keywords
247 */
248  oofWordParser* wp = schField->words();
249  assert(wp); // should NOT be able to specify this kind of search on a field which can't then
250  // provide us with a word parser!!!
251 
252  // Make a new selection into which we can put the result - NOTE: This could be made a lot
253  // more efficient if we made a reasonable stab at the initial size and the chunk size
254  OOF_recordSelection newSelection( mTable->prototype() );
255 
256  unloadRecord();
257  if (startsWith) {
258  unsigned int matchLen = strlen(schStr);
259  for (start();more();next()) { // Vertical Iteration through the selection
260  for (wp->start(schField->asChars()); wp->more(); wp->next()) { // Horizontal Iteration through the field's words
261  if (OOF_strnicmp(wp->word(), schStr, matchLen)==0) {
262  newSelection.append(mCurrLoadedRecOffset);
263  break;
264  }
265  } // word loop
266  unloadRecord();
267  } // record loop
268  } // match starts of words
269  else {
270  for (start();more();next()) { // Vertical Iteration through the selection
271  for (wp->start(schField->asChars()); wp->more(); wp->next()) { // Horizontal Iteration through the field's words
272  if (OOF_stricmp(wp->word(), schStr)==0) {
273  newSelection.append(mCurrLoadedRecOffset);
274  break;
275  }
276  } // word loop
277  unloadRecord();
278  } // record loop
279  } // match full words
280 
281  mSelection = newSelection;
282  assert( Invariant("simpleB::SearchWordNonIndexed-exit") );
283  return !mSelection.isEmpty();
284 }
285 
286 
287 bool
288 OOF_simpleRecordBackend::SearchNotEqualNonIndexed(const dbField* schField, const char* schStr, bool matchEntireKey)
289 {
290  assert( Invariant("simpleB::SearchNotEqualNonIndexed(string)-entry") );
291 
292  if (mSelection.isEmpty()){
293  assert( Invariant("simpleB::SearchNotEqualNonIndexed(string)-exit emptySel") );
294  return false;
295  }
297  return SearchNotEqualNonIndexedWildcard(schField,schStr,matchEntireKey);
298  }
299  // Make a new selection into which we can put the result - NOTE: This could be made a lot
300  // more efficient if we made a reasonable stab at the initial size and the chunk size
301  OOF_recordSelection newSelection( mTable->prototype() );
302 
303  unloadRecord();
304  if(matchEntireKey) // True searchequals
305  for(start();more();next()) { // Vertical Iteration through the selection
306  if(OOF_stricmp(schField->asChars(), schStr)!=0)
307  newSelection.append(mCurrLoadedRecOffset);
308  unloadRecord();
309  }
310  else { // Only check if it doesn't start with the key !
311  unsigned int schLen=strlen(schStr);
312  for(start();more();next()) { // Vertical Iteration through the selection
313  if(OOF_strnicmp(schField->asChars(), schStr, schLen)!=0)
314  newSelection.append(mCurrLoadedRecOffset);
315  unloadRecord();
316  }
317  }
318 
319  mSelection = newSelection;
320 
321  assert( Invariant("simpleB::SearchNotEqualNonIndexed(string)-exit") );
322  return !mSelection.isEmpty();
323 }
324 
325 bool
326 OOF_simpleRecordBackend::SearchEqualNonIndexedWildcard(const dbField* schField, const char* schStr, bool matchEntireKey)
327 {
328  assert( Invariant("simpleB::SearchEqualNonIndexedWildcard-entry") );
329 
330  if (mSelection.isEmpty()){
331  assert( Invariant("simpleB::SearchEqualNonIndexedWildcard-exit emptySel") );
332  return false;
333  }
334  unsigned short numwcs=0;
335  WC wc[100]; // Yes - redo this without the static storage !
336 
337  char *thestr=new char[strlen(schStr)+1];
338  strcpy(thestr,schStr);
339 
340  // Parse the wildcard string
341  wc[0].thewc=prefix;
342  wc[0].thechars=thestr;
343  for(char *s=thestr;*s;s++)
345  numwcs++;
346  wc[numwcs].thewc=multiple;
347  wc[numwcs].thechars=s+1;
348  *s='\0';
349  // Special cases (*sigh*)
350  //
351  // Are we prefixed by another of ourself,
352  // in which case we are meaningless !
353  if((numwcs>1)&&(*(wc[numwcs-1].thechars)=='\0')&&(wc[numwcs-1].thewc==multiple)){
354  numwcs--;
355  wc[numwcs].thechars=s+1;
356  }
357  // Are we the last character ?
358  if(*(s+1)=='\0') {
359  wc[numwcs].thewc=multiplefinal;
360  }
361  }
362  else if (*s == dbQueryClause::sWildcardSingle) {
363  numwcs++;
364  wc[numwcs].thewc=single;
365  wc[numwcs].thechars=s+1;
366  *s='\0';
367  // Special cases (*sigh*)
368  //
369  // Are we prefixed by a multiple ('*'),
370  // in which case we should go first !
371  if((numwcs>1)&&(*(wc[numwcs-1].thechars)=='\0')&&(wc[numwcs-1].thewc==multiple)){
372  wc[numwcs].thewc=multiple;
373  wc[numwcs-1].thewc=single;
374  }
375  // Are we the last character ?
376  if(*(s+1)=='\0') {
377  if(wc[numwcs].thewc==multiple)
378  wc[numwcs].thewc=multiplefinal;
379  else
380  wc[numwcs].thewc=singlefinal;
381  }
382  }
383 
384  if(!matchEntireKey) // We got called as a startsWith !
385  if(!(wc[numwcs].thewc==multiplefinal)) { // if we already have a '*' on the end of the string - do nothing
386  if(wc[numwcs].thewc==singlefinal) // If we had a trailing '*', it's no longer trailing
387  wc[numwcs].thewc=single;
388  numwcs++;
389  wc[numwcs].thewc=multiplefinal; // Make a new final string
390  wc[numwcs].thechars=&thestr[strlen(thestr)]; // point the trailer at a null !
391  }
392 
393  int startingWC;
394 
395  // OK - Lets do the thing - I have a couple of performance heuristics that go here...
396  if(*(wc[0].thechars)=='\0')
397  startingWC=1;
398  else {
399  startingWC=0;
400  if (CanUseIndex(schField))
401  searchEqual(schField, wc[0].thechars, false); // 1) Do an indexed startsWith search - this will cut down our non-indexed iteration
402  }
403 
404  if((numwcs==1)&&(wc[1].thewc==multiplefinal)){
405  // We have a case where there is simply a prefix string (or maybe even not) and just a '*'
406  if(startingWC==0) // We have a non-empty prefix string
407  if (!CanUseIndex(schField)){
408  // We have already doe a searchequal for the indexed case - now we just do the non-indexed verison
409  SearchEqualNonIndexed(schField, wc[0].thechars, false);
410  }
411  // OK - we're done !
412  delete[] thestr;
413  assert( Invariant("simpleB::SearchEqualNonIndexedWildcard-exit trailingWC") );
414  return !mSelection.isEmpty();
415  } // optimal case - trailing wildcard
416 
417  OOF_recordSelection newSelection( mTable->prototype() );
418 
419  unloadRecord();
420  for(start();more();next()){ // Vertical Iteration through the selection
421 
422  int curwc=startingWC;
423  int curchar=0;
424  int curskipped=0;
425 
426  const oofString fldContents=schField->copyString(); //Retrieve the current field contents
427  const char *s=fldContents;
428 
429  while(*s){
430  if(wc[curwc].thewc==single) {
431  if(!curskipped) {
432  s++;
433  curskipped++;
434  } else if(*(wc[curwc].thechars)=='\0'){
435  // singular folowed by a null literal is a match always
436  // BUT we don't advance the pointer in this case !
437  curwc++;
438  curskipped=0;
439  } else if (toupper(*s)==toupper(wc[curwc].thechars[curchar])) {
440  // singular followed by a real literal is a match !
441  s++;
442  curchar++;
443  if(!wc[curwc].thechars[curchar]) { // End of matched literal
444  curwc++;
445  if(curwc>numwcs) // We have run out of literals
446  break;
447  curchar=0;
448  curskipped=0;
449  }
450  } else { // filed to match
451  curskipped++;
452  if(curskipped>1) // failed to match more than once !
453  break;
454  }
455  } else if(wc[curwc].thewc==singlefinal) {
456  // We have a trailing '?'
457  s++;
458  curwc++;
459  break; // We skipped the '?', so we can leave the rest to the final test
460  } else if(wc[curwc].thewc==multiplefinal) {
461  // We have a trailing '*' so we match from here automatically
462  curwc++;
463  s = ""; // point to local null so loop termination works below, which is all that the above achieved
464  break;
465  } else if(toupper(*s)==toupper(wc[curwc].thechars[curchar])) { // Matched character
466  s++;
467  curchar++;
468  curskipped=0;
469  if(!wc[curwc].thechars[curchar]) { // End of matched literal
470  curwc++;
471  if(curwc>numwcs) // We have run out of literals
472  break;
473  curchar=0;
474  }
475  } else { // Character didn't match
476  if(curchar>0) { // are we currently matching a literal ?
477  s-=(curchar-1);
478  curchar=0;
479  } else {
480  s++;
481  curskipped++;
482  }
483  }
484  }
485 
486  if((curwc>numwcs)&&!(*s))
487  newSelection.append(mCurrLoadedRecOffset);
488 
489  unloadRecord();
490  }
491 
492  delete[] thestr;
493 
494  mSelection = newSelection;
495  assert( Invariant("simpleB::SearchEqualNonIndexedWildcard-exit") );
496  return !mSelection.isEmpty();
497 }
498 
499 bool
500 OOF_simpleRecordBackend::SearchNotEqualNonIndexedWildcard(const dbField* schField, const char* schStr, bool matchEntireKey)
501 {
502  assert( Invariant("simpleB::SearchNotEqualNonIndexedWildcard-entry") );
503 
504  if (mSelection.isEmpty()){
505  assert( Invariant("simpleB::SearchNotEqualNonIndexedWildcard-exit emptySel") );
506  return false;
507  }
508  unsigned short numwcs=0;
509  WC wc[100]; // Yes - redo this without the static storage !
510 
511  char *thestr=new char[strlen(schStr)+1];
512  strcpy(thestr,schStr);
513 
514  // Parse the wildcard string
515  wc[0].thewc=prefix;
516  wc[0].thechars=thestr;
517  for(char *s=thestr;*s;s++)
519  numwcs++;
520  wc[numwcs].thewc=multiple;
521  wc[numwcs].thechars=s+1;
522  *s='\0';
523  // Special cases (*sigh*)
524  //
525  // Are we prefixed by another of ourself,
526  // in which case we are meaningless !
527  if((numwcs>1)&&(*(wc[numwcs-1].thechars)=='\0')&&(wc[numwcs-1].thewc==multiple)){
528  numwcs--;
529  wc[numwcs].thechars=s+1;
530  }
531  // Are we the last character ?
532  if(*(s+1)=='\0') {
533  wc[numwcs].thewc=multiplefinal;
534  }
535  }
536  else if (*s == dbQueryClause::sWildcardSingle) {
537  numwcs++;
538  wc[numwcs].thewc=single;
539  wc[numwcs].thechars=s+1;
540  *s='\0';
541  // Special cases (*sigh*)
542  //
543  // Are we prefixed by a multiple ('*'),
544  // in which case we should go first !
545  if((numwcs>1)&&(*(wc[numwcs-1].thechars)=='\0')&&(wc[numwcs-1].thewc==multiple)){
546  wc[numwcs].thewc=multiple;
547  wc[numwcs-1].thewc=single;
548  }
549  // Are we the last character ?
550  if(*(s+1)=='\0') {
551  if(wc[numwcs].thewc==multiple)
552  wc[numwcs].thewc=multiplefinal;
553  else
554  wc[numwcs].thewc=singlefinal;
555  }
556  }
557 
558  if(!matchEntireKey) // We got called as a startsWith !
559  if(!(wc[numwcs].thewc==multiplefinal)) { // if we already have a '*' on the end of the string - do nothing
560  if(wc[numwcs].thewc==singlefinal) // If we had a trailing '*', it's no longer trailing
561  wc[numwcs].thewc=single;
562  numwcs++;
563  wc[numwcs].thewc=multiplefinal; // Make a new final string
564  wc[numwcs].thechars=&thestr[strlen(thestr)]; // point the trailer at a null !
565  }
566 
567  int startingWC;
568  if(*(wc[0].thechars)=='\0')
569  startingWC=1;
570  else
571  startingWC=0;
572 
573  if((numwcs==1)&&(wc[1].thewc==multiplefinal)){
574  // We have a case where there is simply a prefix string (or maybe even not) and justa '*'
575  if(startingWC==0) // We have a non-empty prefix string
576  SearchNotEqualNonIndexed(schField, wc[0].thechars, 0);
577  // OK - we're done !
578  delete[] thestr;
579  assert( Invariant("simpleB::SearchNotEqualNonIndexedWildcard-exit trailingWC") );
580  return !mSelection.isEmpty();
581  }
582 
583  OOF_recordSelection newSelection( mTable->prototype() );
584 
585  unloadRecord();
586  for(start();more();next()){ // Vertical Iteration through the selection
587 
588  int curwc=startingWC;
589  int curchar=0;
590  int curskipped=0;
591 
592  const oofString fldContents=schField->copyString(); //Retrieve the current field contents
593  const char *s=fldContents;
594 
595  while(*s){
596  if(wc[curwc].thewc==single) {
597  if(!curskipped) {
598  s++;
599  curskipped++;
600  } else if(*(wc[curwc].thechars)=='\0'){
601  // singular folowed by a null literal is a match always
602  // BUT we don't advance the pointer in this case !
603  curwc++;
604  curskipped=0;
605  } else if (toupper(*s)==toupper(wc[curwc].thechars[curchar])) {
606  // singular followed by a real literal is a match !
607  s++;
608  curchar++;
609  if(!wc[curwc].thechars[curchar]) { // End of matched literal
610  curwc++;
611  if(curwc>numwcs) // We have run out of literals
612  break;
613  curchar=0;
614  curskipped=0;
615  }
616  } else { // filed to match
617  curskipped++;
618  if(curskipped>1) // failed to match more than once !
619  break;
620  }
621  } else if(wc[curwc].thewc==singlefinal) {
622  // We have a trailing '?'
623  s++;
624  curwc++;
625  break; // We skipped the '?', so we can leave the rest to the final test
626  } else if(wc[curwc].thewc==multiplefinal) {
627  // We have a trailing '*' so we match from here automatically
628  curwc++;
629  s = ""; // point at static null string to terminate loop
630  break;
631  } else if(toupper(*s)==toupper(wc[curwc].thechars[curchar])) { // Matched character
632  s++;
633  curchar++;
634  curskipped=0;
635  if(!wc[curwc].thechars[curchar]) { // End of matched literal
636  curwc++;
637  if(curwc>numwcs) // We have run out of literals
638  break;
639  curchar=0;
640  }
641  } else { // Character didn't match
642  if(curchar>0) { // are we currently matching a literal ?
643  s-=(curchar-1);
644  curchar=0;
645  } else {
646  s++;
647  curskipped++;
648  }
649  }
650  }
651 
652  if(!((curwc>numwcs)&&!(*s)))
653  newSelection.append(mCurrLoadedRecOffset);
654 
655  unloadRecord();
656  }
657 
658  delete[] thestr;
659 
660  mSelection = newSelection;
661 
662  assert( Invariant("simpleB::SearchNotEqualNonIndexedWildcard-exit") );
663  return !mSelection.isEmpty();
664 }
665 
666 
667 bool
668 OOF_simpleRecordBackend::SearchEqualNonIndexed(const dbField* schField, const void* schAddress)
669 {
670  assert( Invariant("simpleB::SearchEqualNonIndexed(bin)-entry") );
671 
672  if (mSelection.isEmpty()){
673  assert( Invariant("simpleB::SearchEqualNonIndexed(bin)-exit emptySel") );
674  return false;
675  }
676  // Make a new selection into which we can put the result - NOTE: This could be made a lot
677  // more efficient if we made a reasonable stab at the initial size and the chunk size
678  OOF_recordSelection newSelection( mTable->prototype() );
679 
680  switch(schField->fieldStorageLen()){
681  case 2: {
682  unsigned short theValue;
683  memcpy(&theValue,schAddress,2);
684  for(start();more();next()) { // Vertical Iteration through the selection
685  if((unsigned short)(*(dbUshort*)schField)==theValue)
686  newSelection.append(mCurrLoadedRecOffset);
687  }
688  break;
689  }
690 
691  case 4: {
692  unsigned long theValue;
693  memcpy(&theValue,schAddress,4);
694  for(start();more();next()) { // Vertical Iteration through the selection
695  if((unsigned long)(*(dbUlong*)schField)==theValue)
696  newSelection.append(mCurrLoadedRecOffset);
697  }
698  break;
699  }
700 
701  case 8: {
702  double theValue;
703  memcpy(&theValue,schAddress,8);
704  for(start();more();next()) { // Vertical Iteration through the selection
705  if((double)(*(dbReal*)schField)==theValue)
706  newSelection.append(mCurrLoadedRecOffset);
707  }
708  break;
709  }
710 
711  default: {
712 #ifdef OOF_DEBUG
713  dbConnect::raise("Search not yet implemented for non-indexed multi-byte binary field");
714 #endif
715  ; // NOT YET IMPLEMENTED - scan a non-indexed multi-byte binary field
716  }
717  }
718 
719  mSelection = newSelection;
720 
721  assert( Invariant("simpleB::SearchEqualNonIndexed(bin)-exit") );
722  return !mSelection.isEmpty();
723 }
724 
725 
726 bool
727 OOF_simpleRecordBackend::SearchNotEqualNonIndexed(const dbField* schField, const void* schAddress)
728 {
729  assert( Invariant("simpleB::SearchNotEqualNonIndexed(bin)-entry") );
730 
731  if (mSelection.isEmpty()){
732  assert( Invariant("simpleB::SearchNotEqualNonIndexed(bin)-exit") );
733  return false;
734  }
735  // Make a new selection into which we can put the result - NOTE: This could be made a lot
736  // more efficient if we made a reasonable stab at the initial size and the chunk size
737  OOF_recordSelection newSelection( mTable->prototype() );
738 
739  switch(schField->fieldStorageLen()){
740  case 2: {
741  unsigned short theValue;
742  memcpy(&theValue,schAddress,2);
743  for(start();more();next()) // Vertical Iteration through the selection
744  if((unsigned short)(*(dbUshort*)schField)!=theValue)
745  newSelection.append(mCurrLoadedRecOffset);
746  break;
747  }
748 
749  case 4: {
750  unsigned long theValue;
751  memcpy(&theValue,schAddress,4);
752  for(start();more();next()) // Vertical Iteration through the selection
753  if((unsigned long)(*(dbUlong*)schField)!=theValue)
754  newSelection.append(mCurrLoadedRecOffset);
755  break;
756  }
757 
758  case 8: {
759  double theValue;
760  memcpy(&theValue,schAddress,8);
761  for(start();more();next()) // Vertical Iteration through the selection
762  if((double)(*(dbReal*)schField)!=theValue)
763  newSelection.append(mCurrLoadedRecOffset);
764  break;
765  }
766 
767  default: {
768 #ifdef OOF_DEBUG
769  dbConnect::raise("Search not yet implemented for non-indexed multi-byte binary field");
770 #endif
771  ; // NOT YET IMPLEMENTED - scan a non-indexed multi-byte binary field
772  }
773  }
774 
775  mSelection = newSelection;
776 
777  assert( Invariant("simpleB::SearchNotEqualNonIndexed(bin)-exit") );
778  return !mSelection.isEmpty();
779 }
780 
781 
782 bool
783 OOF_simpleRecordBackend::SearchBetweenNonIndexed(const dbField* schField, const char* strFrom, const char* strTo)
784 {
785  assert( Invariant("simpleB::SearchBetweenNonIndexed(string)-entry") );
786 
787  if (mSelection.isEmpty()){
788  assert( Invariant("simpleB::SearchBetweenNonIndexed(string)-exit emptySel") );
789  return false;
790  }
791  // If the database was ordered by this field, we would only need to perform one test
792  // on each record instead of two - perhpas we could optimise somehow ?
793 
794  // Make a new selection into which we can put the result - NOTE: This could be made a lot
795  // more efficient if we made a reasonable stab at the initial size and the chunk size
796  OOF_recordSelection newSelection( mTable->prototype() );
797 
798  unloadRecord();
799  for(start();more();next()){
800  const char *theFld = schField->asChars();
801  if((OOF_stricmp(theFld, strFrom)>=0)&&(OOF_stricmp(theFld, strTo)<=0))
802  newSelection.append(mCurrLoadedRecOffset);
803  unloadRecord();
804  }
805 
806  mSelection = newSelection;
807  assert( Invariant("simpleB::SearchBetweenNonIndexed(string)-exit") );
808  return !mSelection.isEmpty();
809 }
810 
811 
812 bool
813 OOF_simpleRecordBackend::SearchOutsideNonIndexed(const dbField* schField, const char* strFrom, const char* strTo)
814 {
815  assert( Invariant("simpleB::SearchOutsideNonIndexed(string)-entry") );
816 
817  if (mSelection.isEmpty()){
818  assert( Invariant("simpleB::SearchOutsideNonIndexed(string)-exit emptySel") );
819  return false;
820  }
821  // If the database was ordered by this field, we would only need to perform one test
822  // on each record instead of two - perhpas we could optimise somehow ?
823 
824  // NOTE: This method is used on indexed fields as well - we could heavily optimise
825  // by using a combinatorial indexed search !
826 
827  // Make a new selection into which we can put the result - NOTE: This could be made a lot
828  // more efficient if we made a reasonable stab at the initial size and the chunk size
829  OOF_recordSelection newSelection( mTable->prototype() );
830 
831  unloadRecord();
832  for(start();more();next()){
833  const char *theFld = schField->asChars();
834  if((OOF_stricmp(theFld, strFrom)<0)||(OOF_stricmp(theFld, strTo)>0))
835  newSelection.append(mCurrLoadedRecOffset);
836  unloadRecord();
837  }
838 
839  mSelection = newSelection;
840 
841  assert( Invariant("simpleB::SearchOutsideNonIndexed(string)-exit") );
842  return !mSelection.isEmpty();
843 }
844 
845 
846 bool
847 OOF_simpleRecordBackend::SearchBetweenNonIndexed(const dbField* schField, const void* addressFrom, const void* addressTo)
848 {
849  assert( Invariant("simpleB::SearchBetweenNonIndexed(bin)-entry") );
850  if (mSelection.isEmpty()){
851  assert( Invariant("simpleB::SearchBetweenNonIndexed(bin)-exit emptySel") );
852  return false;
853  }
854  // If the database was ordered by this field, we would only need to perform one test
855  // on each record instead of two - perhpas we could optimise somehow ?
856 
857  // Make a new selection into which we can put the result - NOTE: This could be made a lot
858  // more efficient if we made a reasonable stab at the initial size and the chunk size
859  OOF_recordSelection newSelection( mTable->prototype() );
860 
861  switch(schField->nativeType()){
862  case uShortField: {
863  unsigned short From, To;
864  memcpy(&From,addressFrom,sizeof(unsigned short));
865  memcpy(&To,addressTo,sizeof(unsigned short));
866  for(start();more();next()){
867  const unsigned short theFld = (unsigned short)(*(dbUshort*)schField);
868  if((theFld>=From)&&(theFld<=To))
869  newSelection.append(mCurrLoadedRecOffset);
870  }
871  break;
872  }
873 
874  case shortField: {
875  short From, To;
876  memcpy(&From,addressFrom,sizeof(short));
877  memcpy(&To,addressTo,sizeof(short));
878  for(start();more();next()){
879  const short theFld = (short)(*(dbShort*)schField);
880  if((theFld>=From)&&(theFld<=To))
881  newSelection.append(mCurrLoadedRecOffset);
882  }
883  break;
884  }
885 
886  case uLongField: {
887  unsigned long From, To;
888  memcpy(&From,addressFrom,sizeof(unsigned long));
889  memcpy(&To,addressTo,sizeof(unsigned long));
890  for(start();more();next()){
891  const unsigned long theFld = (unsigned long)(*(dbUlong*)schField);
892  if((theFld>=From)&&(theFld<=To))
893  newSelection.append(mCurrLoadedRecOffset);
894  }
895  break;
896  }
897 
898  case longField: {
899  long From, To;
900  memcpy(&From,addressFrom,sizeof(long));
901  memcpy(&To,addressTo,sizeof(long));
902  for(start();more();next()){
903  const long theFld = (long)(*(dbLong*)schField);
904  if((theFld>=From)&&(theFld<=To))
905  newSelection.append(mCurrLoadedRecOffset);
906  }
907  break;
908  }
909 
910  case realField: {
911  double From, To;
912  memcpy(&From,addressFrom,sizeof(double));
913  memcpy(&To,addressTo,sizeof(double));
914  for(start();more();next()){
915  const double theFld = (double)(*(dbReal*)schField);
916  if((theFld>=From)&&(theFld<=To))
917  newSelection.append(mCurrLoadedRecOffset);
918  }
919  break;
920  }
921 
922  default: {
923 #ifdef OOF_DEBUG
924  dbConnect::raise("SearchBetween not yet implemented for non-indexed multi-byte binary field");
925 #endif
926  ; // NOT YET IMPLEMENTED - scan a non-indexed multi-byte binary field
927  }
928  }
929 
930  mSelection = newSelection;
931  assert( Invariant("simpleB::SearchBetweenNonIndexed(bin)-exit") );
932  return !mSelection.isEmpty();
933 }
934 
935 
936 bool
937 OOF_simpleRecordBackend::SearchOutsideNonIndexed(const dbField* schField, const void* addressFrom, const void* addressTo)
938 {
939  assert( Invariant("simpleB::SearchOutsideNonIndexed(bin)-entry") );
940 
941  if (mSelection.isEmpty()){
942  assert( Invariant("simpleB::SearchOutsideNonIndexed(bin)-exit emptySel") );
943  return false;
944  }
945  // If the database was ordered by this field, we would only need to perform one test
946  // on each record instead of two - perhpas we could optimise somehow ?
947 
948  // NOTE: This method is used on indexed fields as well - we could heavily optimise
949  // by using a combinatorial indexed search !
950 
951  // Make a new selection into which we can put the result - NOTE: This could be made a lot
952  // more efficient if we made a reasonable stab at the initial size and the chunk size
953  OOF_recordSelection newSelection( mTable->prototype() );
954 
955  switch(schField->nativeType()){
956  case uShortField: {
957  unsigned short From, To;
958  memcpy(&From,addressFrom,sizeof(unsigned short));
959  memcpy(&To,addressTo,sizeof(unsigned short));
960  for(start();more();next()){
961  const unsigned short theFld = (unsigned short)(*(dbUshort*)schField);
962  if((theFld<From)||(theFld>To))
963  newSelection.append(mCurrLoadedRecOffset);
964  }
965  break;
966  }
967 
968  case shortField: {
969  short From, To;
970  memcpy(&From,addressFrom,sizeof(short));
971  memcpy(&To,addressTo,sizeof(short));
972  for(start();more();next()){
973  const short theFld = (short)(*(dbShort*)schField);
974  if((theFld<From)||(theFld>To))
975  newSelection.append(mCurrLoadedRecOffset);
976  }
977  break;
978  }
979 
980  case uLongField:{
981  unsigned long From, To;
982  memcpy(&From,addressFrom,sizeof(unsigned long));
983  memcpy(&To,addressTo,sizeof(unsigned long));
984  for(start();more();next()){
985  const unsigned long theFld = (unsigned long)(*(dbUlong*)schField);
986  if((theFld<From)||(theFld>To))
987  newSelection.append(mCurrLoadedRecOffset);
988  }
989  break;
990  }
991 
992  case longField: {
993  long From, To;
994  memcpy(&From,addressFrom,sizeof(long));
995  memcpy(&To,addressTo,sizeof(long));
996  for(start();more();next()){
997  const long theFld = (long)(*(dbLong*)schField);
998  if((theFld<From)||(theFld>To))
999  newSelection.append(mCurrLoadedRecOffset);
1000  }
1001  break;
1002  }
1003 
1004  case realField: {
1005  double From, To;
1006  memcpy(&From,addressFrom,sizeof(double));
1007  memcpy(&To,addressTo,sizeof(double));
1008  for(start();more();next()){
1009  const double theFld = (double)(*(dbReal*)schField);
1010  if((theFld<From)||(theFld>To))
1011  newSelection.append(mCurrLoadedRecOffset);
1012  }
1013  break;
1014  }
1015 
1016  default: {
1017 #ifdef OOF_DEBUG
1018  dbConnect::raise("SearchBetween not yet implemented for non-indexed multi-byte binary field");
1019 #endif
1020  ; // NOT YET IMPLEMENTED - scan a non-indexed multi-byte binary field
1021  }
1022  }
1023 
1024  mSelection = newSelection;
1025 
1026  assert( Invariant("simpleB::SearchOutsideNonIndexed(bin)-exit") );
1027  return !mSelection.isEmpty();
1028 }
1029 
1030 
1031 bool
1033 
1034 {
1035  assert( Invariant("simpleB::SearchComparativeNonIndexed(string)-entry") );
1036 
1037  if (mSelection.isEmpty()){
1038  assert( Invariant("simpleB::SearchComparativeNonIndexed(string)-exit emptySel") );
1039  return false;
1040 
1041  }
1042  OOF_recordSelection newSelection( mTable->prototype() );
1043  unloadRecord();
1044 
1045  switch(theOp) { // We only have to test comparative searches here, the others have already
1046  // been weeded out
1047  case (dbQueryClause::lessThan) :
1048  for(start();more();next()){
1049  if(OOF_stricmp(schField->asChars(), schStr)<0)
1050  newSelection.append(mCurrLoadedRecOffset);
1051  unloadRecord();
1052  }
1053  break;
1054 
1056  for(start();more();next()){
1057  if(OOF_stricmp(schField->asChars(), schStr)<=0)
1058  newSelection.append(mCurrLoadedRecOffset);
1059  unloadRecord();
1060  }
1061  break;
1062 
1064  for(start();more();next()){
1065  if(OOF_stricmp(schField->asChars(), schStr)>0)
1066  newSelection.append(mCurrLoadedRecOffset);
1067  unloadRecord();
1068  }
1069  break;
1070 
1072  for(start();more();next()){
1073  if(OOF_stricmp(schField->asChars(), schStr)>=0)
1074  newSelection.append(mCurrLoadedRecOffset);
1075  unloadRecord();
1076  }
1077  break;
1078 
1079  default:
1080  break;
1081  }
1082 
1083  mSelection = newSelection;
1084  assert( Invariant("simpleB::SearchComparativeNonIndexed(string)-exit") );
1085  return !mSelection.isEmpty();
1086 }
1087 
1088 
1089 bool
1091 {
1092  assert( Invariant("simpleB::SearchComparativeNonIndexed(bin)-entry") );
1093 
1094  if (mSelection.isEmpty()){
1095  assert( Invariant("simpleB::SearchComparativeNonIndexed(bin)-exit emptySel") );
1096  return false;
1097  }
1098  OOF_recordSelection newSelection( mTable->prototype() );
1099 
1100  switch(schField->nativeType()){
1101  case uShortField: {
1102  unsigned short Value;
1103  memcpy(&Value,schAddress,sizeof(unsigned short));
1104  switch(theOp) { // We only have to test comparative searches here, the others have already
1105  // been weeded out
1106  case (dbQueryClause::lessThan) :
1107  for(start();more();next()){
1108  if((unsigned short)(*(dbUshort*)schField)<Value)
1109  newSelection.append(mCurrLoadedRecOffset);
1110  }
1111  break;
1112 
1114  for(start();more();next()){
1115  if((unsigned short)(*(dbUshort*)schField)<=Value)
1116  newSelection.append(mCurrLoadedRecOffset);
1117  }
1118  break;
1119 
1121  for(start();more();next()){
1122  if((unsigned short)(*(dbUshort*)schField)>Value)
1123  newSelection.append(mCurrLoadedRecOffset);
1124  }
1125  break;
1126 
1128  for(start();more();next()){
1129  if((unsigned short)(*(dbUshort*)schField)>=Value)
1130  newSelection.append(mCurrLoadedRecOffset);
1131  }
1132  break;
1133 
1134  default:
1135  break;
1136 
1137  }
1138  break;
1139  }
1140 
1141  case shortField: {
1142  short Value;
1143  memcpy(&Value,schAddress,sizeof(short));
1144  switch(theOp) { // We only have to test comparative searches here, the others have already
1145  // been weeded out
1146  case (dbQueryClause::lessThan) :
1147  for(start();more();next()){
1148  if((short)(*(dbShort*)schField)<Value)
1149  newSelection.append(mCurrLoadedRecOffset);
1150  }
1151  break;
1152 
1154  for(start();more();next()){
1155  if((short)(*(dbShort*)schField)<=Value)
1156  newSelection.append(mCurrLoadedRecOffset);
1157  }
1158  break;
1159 
1161  for(start();more();next()){
1162  if((short)(*(dbShort*)schField)>Value)
1163  newSelection.append(mCurrLoadedRecOffset);
1164  }
1165  break;
1166 
1168  for(start();more();next()){
1169  if((short)(*(dbShort*)schField)>=Value)
1170  newSelection.append(mCurrLoadedRecOffset);
1171  }
1172  break;
1173 
1174  default:
1175  break;
1176 
1177  }
1178  break;
1179  }
1180 
1181  case uLongField:{
1182  unsigned long Value;
1183  memcpy(&Value,schAddress,sizeof(unsigned long));
1184  switch(theOp) { // We only have to test comparative searches here, the others have already
1185  // been weeded out
1186  case (dbQueryClause::lessThan) :
1187  for(start();more();next()){
1188  if((unsigned long)(*(dbUlong*)schField)<Value)
1189  newSelection.append(mCurrLoadedRecOffset);
1190  }
1191  break;
1192 
1194  for(start();more();next()){
1195  if((unsigned long)(*(dbUlong*)schField)<=Value)
1196  newSelection.append(mCurrLoadedRecOffset);
1197  }
1198  break;
1199 
1201  for(start();more();next()){
1202  if((unsigned long)(*(dbUlong*)schField)>Value)
1203  newSelection.append(mCurrLoadedRecOffset);
1204  }
1205  break;
1206 
1208  for(start();more();next()){
1209  if((unsigned long)(*(dbUlong*)schField)>=Value)
1210  newSelection.append(mCurrLoadedRecOffset);
1211  }
1212  break;
1213 
1214  default:
1215  break;
1216 
1217  }
1218  break;
1219  }
1220 
1221  case longField: {
1222  long Value;
1223  memcpy(&Value,schAddress,sizeof(long));
1224  switch(theOp) { // We only have to test comparative searches here, the others have already
1225  // been weeded out
1226  case (dbQueryClause::lessThan) :
1227  for(start();more();next()){
1228  if((long)(*(dbLong*)schField)<Value)
1229  newSelection.append(mCurrLoadedRecOffset);
1230  }
1231  break;
1232 
1234  for(start();more();next()){
1235  if((long)(*(dbLong*)schField)<=Value)
1236  newSelection.append(mCurrLoadedRecOffset);
1237  }
1238  break;
1239 
1241  for(start();more();next()){
1242  if((long)(*(dbLong*)schField)>Value)
1243  newSelection.append(mCurrLoadedRecOffset);
1244  }
1245  break;
1246 
1248  for(start();more();next()){
1249  if((long)(*(dbLong*)schField)>=Value)
1250  newSelection.append(mCurrLoadedRecOffset);
1251  }
1252  break;
1253 
1254  default:
1255  break;
1256 
1257  }
1258  break;
1259  }
1260 
1261  case realField: {
1262  double Value;
1263  memcpy(&Value,schAddress,sizeof(double));
1264  switch(theOp) { // We only have to test comparative searches here, the others have already
1265  // been weeded out
1266  case (dbQueryClause::lessThan) :
1267  for(start();more();next()){
1268  if((double)(*(dbReal*)schField)<Value)
1269  newSelection.append(mCurrLoadedRecOffset);
1270  }
1271  break;
1272 
1274  for(start();more();next()){
1275  if((double)(*(dbReal*)schField)<=Value)
1276  newSelection.append(mCurrLoadedRecOffset);
1277  }
1278  break;
1279 
1281  for(start();more();next()){
1282  if((double)(*(dbReal*)schField)>Value)
1283  newSelection.append(mCurrLoadedRecOffset);
1284  }
1285  break;
1286 
1288  for(start();more();next()){
1289  if((double)(*(dbReal*)schField)>=Value)
1290  newSelection.append(mCurrLoadedRecOffset);
1291  }
1292  break;
1293 
1294  default:
1295  break;
1296 
1297  }
1298  break;
1299  }
1300 
1301  default: {
1302 #ifdef OOF_DEBUG
1303  dbConnect::raise("SearchBetween not yet implemented for non-indexed multi-byte binary field");
1304 #endif
1305  ; // NOT YET IMPLEMENTED - scan a non-indexed multi-byte binary field
1306  }
1307  }
1308 
1309  mSelection = newSelection;
1310 
1311  assert( Invariant("simpleB::SearchComparativeNonIndexed-schAddress-exit") );
1312  return !mSelection.isEmpty();
1313 }
1314 
1315 
1316 bool
1317 OOF_simpleRecordBackend::searchSelContainsAnyOf(const dbField* schField, const char **schStrs, unsigned long count)
1318 {
1319  assert( Invariant("simpleB::searchSelContainsAnyOf-entry") );
1320 
1321  // Make a new selection into which we can put the result - NOTE: This could be made a lot
1322  // more efficient if we made a reasonable stab at the initial size and the chunk size
1323  OOF_recordSelection newSelection( mTable->prototype() );
1324 
1325  unloadRecord();
1326  for(start();more();next()){ // Vertical Iteration through the selection
1327  const oofString fldContents=schField->copyString();
1328  bool matched=false;
1329  for(unsigned long i=0;(i<count)&&!matched;i++) {
1330  unsigned long keyLen=strlen(schStrs[i]);
1331  for(const char *s=fldContents;*s;s++)
1332  if(OOF_strnicmp(s, schStrs[i], keyLen)==0) {
1333  matched=true;
1334  break;
1335  }
1336  } // string loop
1337  if(matched)
1338  newSelection.append(mCurrLoadedRecOffset);
1339  unloadRecord();
1340  } // record loop
1341 
1342  mSelection = newSelection;
1343 
1344  assert( Invariant("simpleB::searchSelContainsAnyOf-exit") );
1345  return !mSelection.isEmpty();
1346 }
1347 
1348 
1349 bool
1350 OOF_simpleRecordBackend::searchSelContainsAnyDelimited(const dbField* schField, const char *schStr, char delim)
1351 {
1352  assert( Invariant("simpleB::searchSelContainsAnyDelimited-entry") );
1353 
1354  char *myStr=new char[strlen(schStr)+1];
1355  strcpy(myStr,schStr);
1356 
1357  unsigned long numStrs=1;
1358  if(myStr[0]==delim)
1359  myStr++;
1360  for(unsigned long i=0;myStr[i];i++){
1361  if(myStr[i]==delim){
1362  if(myStr[i+1])
1363  numStrs++;
1364  else
1365  myStr[i]='\0';
1366  }
1367  }
1368 
1369  char **myStrArray=new char*[numStrs]; // can't declare as const char** as vc1.52 complains on delete[]
1370 // char **myStrArray=new char*[numStrs]; causes g++ to complain when passed into searchContainsAnyOf
1371  myStrArray[0]=myStr;
1372  numStrs=1;
1373  for(unsigned long j=0;myStr[j];j++){
1374  if(myStr[j]==delim){
1375  myStrArray[numStrs++]=&myStr[j+1];
1376  myStr[j]='\0';
1377  }
1378  }
1379 
1380  bool retval=searchSelContainsAnyOf(schField, (const char**)myStrArray, numStrs);
1381 
1382  delete [] myStr;
1383  delete [] myStrArray;
1384  assert( Invariant("simpleB::searchSelContainsAnyDelimited-exit") );
1385  return retval;
1386 }
1387 
1388 
1389 bool
1390 OOF_simpleRecordBackend::searchSelContainsAllOf(const dbField* schField, const char **schStrs, unsigned long count)
1391 {
1392  assert( Invariant("simpleB::searchSelContainsAllOf-entry") );
1393  // Make a new selection into which we can put the result - NOTE: This could be made a lot
1394  // more efficient if we made a reasonable stab at the initial size and the chunk size
1395  OOF_recordSelection newSelection( mTable->prototype() );
1396 
1397  unloadRecord();
1398  for(start();more();next()){ // Vertical Iteration through the selection
1399  const oofString fldContents=schField->copyString();
1400  bool matched=true;
1401  for(unsigned long i=0;(i<count)&&matched;i++) {
1402  unsigned long keyLen=strlen(schStrs[i]);
1403  matched=false;
1404  for(const char* s=fldContents;*s;s++)
1405  if(OOF_strnicmp(s, schStrs[i], keyLen)==0) {
1406  matched=true;
1407  break;
1408  }
1409  }
1410  if(matched)
1411  newSelection.append(mCurrLoadedRecOffset);
1412  unloadRecord();
1413  } // record loop
1414 
1415  mSelection = newSelection;
1416  assert( Invariant("simpleB::searchSelContainsAllOf-exit") );
1417  return !mSelection.isEmpty();
1418 }
1419 
1420 
1421 bool
1422 OOF_simpleRecordBackend::searchSelContainsAllDelimited(const dbField* schField, const char *schStr, char delim)
1423 {
1424  assert( Invariant("simpleB::searchSelContainsAllDelimited-entry") );
1425 
1426  char *myStr=new char[strlen(schStr)+1];
1427  strcpy(myStr,schStr);
1428 
1429  unsigned long numStrs=1;
1430  if(myStr[0]==delim)
1431  myStr++;
1432  for(unsigned long i=0;myStr[i];i++){
1433  if(myStr[i]==delim){
1434  if(myStr[i+1])
1435  numStrs++;
1436  else
1437  myStr[i]='\0';
1438  }
1439  }
1440 
1441  char **myStrArray=new char*[numStrs]; // can't declare as const char** as vc1.52 complains on delete[]
1442  myStrArray[0]=myStr;
1443  numStrs=1;
1444  for(unsigned long j=0;myStr[j];j++){
1445  if(myStr[j]==delim){
1446  myStrArray[numStrs++]=&myStr[j+1];
1447  myStr[j]='\0';
1448  }
1449  }
1450 
1451  bool retval=searchSelContainsAllOf(schField, (const char**)myStrArray, numStrs); // cast for g++
1452 
1453  delete [] myStr;
1454  delete [] myStrArray;
1455 
1456  assert( Invariant("simpleB::searchSelContainsAllDelimited-exit") );
1457  return retval;
1458 }
1459 
1460 
1469 bool
1471 {
1472  assert( Invariant("simpleB::loadRelatedContextJoiningFromTo-entry") );
1473 
1474  OOF_recordCache* savedCache=0;
1475 
1476  if (mDirtyRecordCache) {
1477  const unsigned long numOcc = mDirtyRecordCache->countOccupied() ; // minor optim. - this is a fast call!
1478  if (numOcc>0 && (numOcc==mDirtyRecordCache->count()) ) { // all new records!
1479  savedCache = mDirtyRecordCache; // KIDNAP THE CACHE!
1480  mDirtyRecordCache=0;
1481  assert( Invariant("simpleB::loadRelatedContextJoiningFromTo-savedCache") );
1482  // *** MAY NEED TO EXPLICITLY REMOVE THE NEW ONES FROM THE SELECTION?????
1483 
1484  } // has cache of all new recs
1485  } // has cache
1486 
1487  if (isNew() && !mDirtyRecordCache) { // kidnapped cache or never was one
1488  // current record is also (only?) new so save
1490  assert(ctx);
1491  DonateBlobBodiesTo(ctx);
1492  if (!savedCache)
1493  savedCache = new OOF_recordCache(ctx);
1494  else
1495  savedCache->append(ctx);
1496  } // save current new record to special cache
1497 
1498  bool ret = false;
1499  switch (fldTo->fieldType()) {
1500  case charField : {
1501  ret = searchEqual(fldTo, ((dbChar*)fldFrom)->operator const char*()); // safe downcast
1502  break;
1503  }
1504 
1505  case textField : {
1506  ret = searchEqual(fldTo, ((dbText*)fldFrom)->operator const char*()); // safe downcast
1507  break;
1508  }
1509 
1510  default : { // binary single fields
1511  dbQueryLiteral* fldLiteral = (dbQueryLiteral*)fldFrom->valueAsQueryLiteral(); // safe downcast
1512  assert(fldLiteral);
1513  ret = searchEqual(fldTo, fldLiteral->binaryContents());
1514  delete fldLiteral;
1515  }
1516  }
1517 
1518 // maybe restore cache
1519  if (savedCache) {
1520  assert(!mDirtyRecordCache); // because only kidnapped it if all new recs in there
1521  mDirtyRecordCache=savedCache;
1522  unsigned long numCached = savedCache->count();
1523  for (unsigned long i=0; i<numCached; i++) {
1524  const OOF_recordBufferedContext* ctx = (const OOF_recordBufferedContext*) (savedCache->item(i)); // safe downcast
1525  assert(ctx);
1526  if (ctx->isNew()) { // only copy the new ones, modified records in the cache will have their oids appended already
1527  const unsigned long theOID = ctx->currentOffset();
1528  mSelection.append(theOID);
1529  } // NOTE you may have items in the cache which are not in the current
1530  // selection - that is perfectly legal for a bufferForever mode
1531  // you should regard the cache as an alternate data source
1532  }
1533  }
1534 
1535  start();
1536  assert( Invariant("simpleB::loadRelatedContextJoiningFromTo-exit") );
1537  return ret;
1538 }
1539 
1540 
1541 bool
1543 {
1544  assert( Invariant("simpleB::SearchSelectionBinaryFieldToLiteral-entry") );
1545 
1546  const dbQueryLiteralStr* strRHS = qClause->literalStrClause();
1547  dbQueryClause::BinaryQueryOps theOp = qClause->binaryOperator();
1548  bool ret = false;
1549  if (strRHS) {
1550  switch(theOp) {
1551  case (dbQueryClause::startsWith) :
1552  ret = SearchEqualNonIndexed(qClause->lhsField(), strRHS->str(), false);
1553  break;
1554 
1555  case (dbQueryClause::hasWord) :
1556  ret = SearchWordNonIndexed(qClause->lhsField(), strRHS->str());
1557  break;
1558 
1560  ret = SearchWordNonIndexed(qClause->lhsField(), strRHS->str(), true);
1561  break;
1562 
1563  case (dbQueryClause::equals) :
1564  ret = SearchEqualNonIndexed(qClause->lhsField(), strRHS->str());
1565  break;
1566 
1567  case (dbQueryClause::notEquals) :
1568  ret = SearchNotEqualNonIndexed(qClause->lhsField(), strRHS->str());
1569  break;
1570 
1571  default:
1572  ret = SearchComparativeNonIndexed(qClause->lhsField(), strRHS->str(), theOp);
1573  }
1574  }
1575  else {
1576  if (qClause->literalMultiStrClause())
1577  dbConnect::raise("multiple string searches only allowed on keyword indexed fields", false);
1578  else {
1579  const dbQueryLiteral* rhs = qClause->literalClause();
1580  assert(rhs);
1581  switch(theOp) {
1582  case (dbQueryClause::equals) :
1583  ret = SearchEqualNonIndexed(qClause->lhsField(), rhs->binaryContents());
1584  break;
1585 
1586  case (dbQueryClause::notEquals) :
1587  ret = SearchNotEqualNonIndexed(qClause->lhsField(), rhs->binaryContents());
1588  break;
1589 
1590  default:
1591  ret = SearchComparativeNonIndexed(qClause->lhsField(), rhs->binaryContents(), theOp);
1592  }
1593  } // binary literal
1594  } // not string literal
1595 
1596  assert( Invariant("simpleB::SearchSelectionBinaryFieldToLiteral-exit") );
1597  return ret;
1598 }
1599 
1600 
1601 bool
1603 {
1604  assert( Invariant("simpleB::SearchSelectionTrinaryFieldToLiterals-entry") );
1605 
1606  // Currently we just call the non-indexed searches, which will do their own exit Invariants
1607  //
1608  // The non-indexed versions always work on a current selection, so this will have
1609  // the effect of refining the selection
1610  //
1611  // This could be optimised for indexed fields - We need to develop some heuristics for this
1612  //
1613  const dbQueryLiteralStr* strFrom = qClause->literalStrFromClause();
1615  if (strFrom) {
1616  const dbQueryLiteralStr* strTo = qClause->literalStrToClause();
1617  assert(strTo); // must be both strings or both binary literals
1618 
1619  switch(theOp) {
1620  case (dbQueryClause::between) :
1621  return SearchBetweenNonIndexed(qClause->lhsField(), strFrom->str(), strTo->str());
1622 
1623  case (dbQueryClause::outside) :
1624  return SearchOutsideNonIndexed(qClause->lhsField(), strFrom->str(), strTo->str());
1625  }
1626  }
1627 
1628  else {
1629  const dbQueryLiteral* numFrom = qClause->literalFromClause();
1630  const dbQueryLiteral* numTo = qClause->literalToClause();
1631  switch(theOp) {
1632  case (dbQueryClause::between) :
1633  return SearchBetweenNonIndexed(qClause->lhsField(), numFrom->binaryContents(), numTo->binaryContents());
1634 
1635  case (dbQueryClause::outside) :
1636  return SearchOutsideNonIndexed(qClause->lhsField(), numFrom->binaryContents(), numTo->binaryContents());
1637  }
1638  }
1639  assert( Invariant("simpleB::SearchSelectionTrinaryFieldToLiterals-exit unhandled") );
1640  return false;
1641 }
1642 
1643 
1644 bool
1646 {
1647  assert( Invariant("simpleB::SearchBinaryFieldToLiteral-entry") );
1648 
1649  dbQueryLiteralStr* strRHS = qClause->literalStrClause();
1650  dbQueryClause::BinaryQueryOps theOp = qClause->binaryOperator();
1651  bool ret = false;
1652  selectAll();
1653  #ifdef OOF_MEM_DEBUG_FORCE_POOL_CHECK
1655  #endif
1656 
1657  if (strRHS) {
1658  switch(theOp) {
1659  case (dbQueryClause::startsWith) :
1660  ret = SearchEqualNonIndexed(qClause->lhsField(), strRHS->str(), false);
1661  break;
1662 
1663  case (dbQueryClause::hasWord) :
1664  ret = SearchWordNonIndexed(qClause->lhsField(), strRHS->str());
1665  break;
1666 
1668  ret = SearchWordNonIndexed(qClause->lhsField(), strRHS->str(), true);
1669  break;
1670 
1671  case (dbQueryClause::equals) :
1672  ret = SearchEqualNonIndexed(qClause->lhsField(), strRHS->str());
1673  break;
1674 
1675  case (dbQueryClause::notEquals) :
1676  ret = SearchNotEqualNonIndexed(qClause->lhsField(), strRHS->str());
1677  break;
1678 
1679  default:
1680  ret = SearchComparativeNonIndexed(qClause->lhsField(), strRHS->str(), theOp);
1681  }
1682  }
1683  else {
1684  if (qClause->literalMultiStrClause())
1685  dbConnect::raise("multiple string searches only allowed on keyword indexed fields", false);
1686  else {
1687  const dbQueryLiteral* rhs = qClause->literalClause();
1688  assert(rhs);
1689  switch(theOp) {
1690  case (dbQueryClause::equals) :
1691  ret = SearchEqualNonIndexed(qClause->lhsField(), rhs->binaryContents());
1692  break;
1693 
1694  case (dbQueryClause::notEquals) :
1695  ret = SearchNotEqualNonIndexed(qClause->lhsField(), rhs->binaryContents());
1696  break;
1697 
1698  default:
1699  return SearchComparativeNonIndexed(qClause->lhsField(), rhs->binaryContents(), theOp);
1700  }
1701  } // binary rhs
1702  } // not string rhs
1703  assert( Invariant("simpleB::SearchBinaryFieldToLiteral-exit") );
1704  return ret;
1705 }
1706 
1707 
1708 bool
1710 {
1711  assert( Invariant("simpleB::SearchCombineSubclauses-entry") );
1712 
1713  bool lhsResults = false;
1714  OOF_recordSelection saveOriginalSelection( mTable->prototype() );
1715 
1716  if (searchSel) {
1717  saveOriginalSelection = mSelection; // not adopted
1718  lhsResults = searchSelection(qClause->item(0));
1719  }
1720  else
1721  lhsResults = search(qClause->item(0));
1722 
1723  if (qClause->binaryOperator()==dbQueryClause::oofAND) {
1724  if (!lhsResults){ // try LHS, it may find nothing!
1725  assert( Invariant("simpleB::SearchCombineSubclauses-exit AND rhs fail") );
1726  return false;
1727  }
1728  const bool ret = searchSelection(qClause->item(1));
1729  assert( Invariant("simpleB::SearchCombineSubclauses-exit AND") );
1730  return ret;
1731  } // AND search
1732 
1733  else { // must be an OR
1734 // NOTE unlike above, even in searchSelection we combine results
1735  OOF_recordSelection saveLhsSelection( mTable->prototype());
1736  saveLhsSelection.adopt(mSelection);
1737  if (searchSel) {
1738  mSelection.adopt(saveOriginalSelection);
1739  searchSelection(qClause->item(1)); // don't care if it works
1740  }
1741  else
1742  search(qClause->item(1)); // don't care if it works
1743  if (lhsResults) // have something to combine with the search we just did
1744  mSelection.union_with(saveLhsSelection);
1745 
1746  assert( Invariant("simpleB::SearchCombineSubclauses-exit OR") );
1747  return !mSelection.isEmpty();
1748  } // OR search
1749 }
1750 
1751 
1752 bool
1754 {
1755  assert( Invariant("simpleB::SearchTrinaryFieldToLiterals-entry") );
1756 
1757  const dbQueryLiteralStr* strFrom = qClause->literalStrFromClause();
1759 
1760  if (strFrom) {
1761  const dbQueryLiteralStr* strTo = qClause->literalStrToClause();
1762  assert(strTo); // must be both strings or both binary literals
1763 
1764  switch(theOp) {
1765  case (dbQueryClause::between) :
1766  selectAll();
1767  return SearchBetweenNonIndexed(qClause->lhsField(), strFrom->str(), strTo->str());
1768 
1769  case (dbQueryClause::outside) :
1770  selectAll();
1771  return SearchOutsideNonIndexed(qClause->lhsField(), strFrom->str(), strTo->str());
1772  }
1773  }
1774 
1775  else {
1776  const dbQueryLiteral* numFrom = qClause->literalFromClause();
1777  const dbQueryLiteral* numTo = qClause->literalToClause();
1778  switch(theOp) {
1779  case (dbQueryClause::between) :
1780  selectAll();
1781  return SearchBetweenNonIndexed(qClause->lhsField(), numFrom->binaryContents(), numTo->binaryContents());
1782 
1783  case (dbQueryClause::outside) :
1784  selectAll();
1785  return SearchOutsideNonIndexed(qClause->lhsField(), numFrom->binaryContents(), numTo->binaryContents());
1786  }
1787  }
1788 
1789  assert( Invariant("simpleB::SearchTrinaryFieldToLiterals-exit unhandled") );
1790  return false;
1791 }
1792 
1793 
1794 void
1796 {
1797  // null method for backends that lack locking
1798 }
1799 
1800 
1801 void
1803 {
1804  // null method for backends that lack locking
1805 }
1806 
1807 void
1809 {
1810  // null method for backends that do not have transactions
1811 }
1812 
1813 
1814 void
1816 {
1817  // null method for backends that do not have transactions
1818 }
1819 
1820 
1821 void
1823 {
1824  // null method for backends that do not have transactions
1825 }
1826 
1827 
1836 bool
1837 OOF_simpleRecordBackend::Invariant(const char* optionalComment) const
1838 {
1839 #ifndef _Macintosh
1840  return true; // Andy 991224 hack for other platforms
1841 #endif
1842 
1843 // Note if an this code returns false
1844 // please add a temporay if(state == XXXX)
1845 // ret = true
1846 // and contact AD software with a description of the state and the calling circumstances?????
1847 // mailto:dent@oofile.com.au
1848 
1849 #ifdef OOF_INVARIANT_DUMP_NAME
1850  InvariantDump(optionalComment);
1851 #else
1852  #ifdef __MWERKS__
1853  #pragma unused (optionalComment)
1854  #endif
1855 #endif
1856 
1857  bool ret = false;
1858  unsigned long curState = state();
1859  unsigned long noSelection = curState & 0xffffff00;
1860 
1861 
1862  dbSorter* theSorter = mSelection.sorter();
1863  // handle closed table
1864  if(((curState & '\0\xff\0\0')=='\0C\0\0')&& ((curState ^ 'UCNA') )) // Mask out all but table valid field and look for 'C'
1865  return false;
1866 
1867  //check sorter state
1868  if(theSorter){
1869  unsigned long sortState = theSorter->state();
1870  if(((sortState & '\0\xff\xff\0')=='\0NS\0')||((sortState & '\0\0\xff\xff')=='\0\0SX')
1871  ||((sortState & '\0\0\xff\0')=='\0\0S\0') && ((curState & '\0\xff\0\0') == '\0I\0\0') // sorting on invalid table
1872  || (((sortState & '\0\0\xff\0')=='\0\0S\0') &&((noSelection) & '\0\xff\0\0'== '\0I\0\0'))) // sorting on an invalid table
1873  return false; // its bad so we do not care about other states
1874  }
1875 
1876  // Check validating state
1877  // 991221 we can end up in nested invalidates (I think) because we reset the current "object" (ie: record)
1878  // when traversing a relationship on non-indexed fields doing the search
1879  /*
1880  if(mTable->validatingDepth() > 1)
1881  return false;
1882  */
1883 
1884 // loaded valid table with empty selection
1885 // the folowing has temporally removed as it occurs as a transient in ,this will be reinstated when further
1886 //investigations devleop a clean save method of handling transient state
1887 // typically the transient transition is LVNX (where X is O, S or all) -> LVNE -> UVNE
1888  //if((curState & '\xff\xff\0\xff')=='LV\0E') // check for LVNE r LVDE
1889 
1890  if(curState =='LVDE') // check for LVNE r LVDE
1891  return false;
1892 
1893  // legal states
1894  ret = (!(noSelection ^ 'LID\0')) || (!(noSelection ^ 'LIN\0' )) || (!(noSelection ^ 'UVN\0' ))
1895  || (!(noSelection ^ 'UIN\0' )) || (!(curState ^ 'NINE')) || (!(noSelection ^ 'LVN\0')
1896  || !(noSelection ^ 'LVD\0')||(!(curState ^ 'UCNA')) ||!(noSelection ^ 'NVN\0' )||!(noSelection ^ 'NVD\0' ));
1897 
1898 
1899  return ret;
1900 }
1901 
1902 
1903 unsigned long
1905 {
1906 
1907 
1908  unsigned long ret = 0;
1909  switch(mRecordState) {
1910  case (eNew) :
1911  ret |= 'N\0\0\0' ;
1912  break;
1913 
1914  case (eLoaded) :
1915  ret |= 'L\0\0\0';
1916  break;
1917 
1918  case (eUnloaded) :
1919  ret |= 'U\0\0\0';
1920  break;
1921 
1922  default:
1923  assert(!"unknown state"); //lint !e506 constant Boolean
1924  }
1925  //unsigned long aState = mTable->mTableValid;
1926  if(mTable){
1927  switch(mTable->validStatus()) {
1928 
1929  case (dbTable::eInvalid) :
1930  ret|= '\0\x49\0\0';
1931  break;
1932 
1933  case (dbTable::eValid) :
1934  ret|= '\0V\0\0';
1935  break;
1936 
1937  case (dbTable::eClosed) :
1938  ret|= '\0C\0\0';
1939  break;
1940 
1941  default:
1942  assert(!"unknown state"); //lint !e506 constant Boolean
1943  }
1944  }
1945 
1946  if (mDirty)
1947  ret|= '\0\0D\0';
1948  else
1949  ret|= '\0\0N\0';
1950 
1951  switch(mSelection.state()) {
1953  ret |= '\0\0\0\x45';
1954  break;
1955 
1957  ret |= '\0\0\0O';
1958  break;
1959 
1961  ret |= '\0\0\0S';
1962  break;
1963 
1965  ret |= '\0\0\0\x41';
1966  break;
1967 
1968  default:
1969  assert(!"unknown state"); //lint !e506 constant Boolean
1970  }
1971 
1972  return ret;
1973 }
1974 
1975 #ifdef OOF_INVARIANT_DUMP_NAME
1976 
1977 void
1978 OOF_simpleRecordBackend::InvariantDump(const char* optionalComment) const
1979 {
1980  oofString stateString(optionalComment,"\t", InvariantDescription() );
1981 
1982  #ifdef _Macintosh
1983  // needs programmer to enter MacsBug and start logging to file, eg:
1984  // log ooftest
1985  //::DebugStr("\p;LOG OOFLOG ; SC;; printf \"David was here\";log G; \n ");
1986 
1987  oofString makeDump = ";log stLOg;sc;printf \" stlog: ";
1988  // time stamp in mac ticks 16.66ms aslo a uniqui ID i hope
1989  unsigned long aTime = ::TickCount();
1990  makeDump.convertNumber(aTime, "%.8X\t", true /* append */);
1991  //::TickCount()
1992  makeDump += stateString;
1993 
1994  makeDump += "\" ;g; \n";
1995  assert(makeDump.length() <= 255);
1996  Str255 pString;
1997  makeDump.getStr255(pString);
1998  ::DebugStr(pString);
1999 
2000  //::DebugStr("\pSC ;g");
2001 
2002  #else
2003  // always reopen the file
2004  stSaveDirectory preserveUserDir;
2005 
2006  sInvariantDumpDir.gotoDirectory(); // wherever we were when app started
2007  sInvariantDump.open(OOF_INVARIANT_DUMP_NAME, ios::app | ios::out); // now will always open in same place!
2008  assert(sInvariantDump.good());
2009 
2010  sInvariantDump << stateString;
2011  if (optionalComment)
2012  sInvariantDump << '\t' << optionalComment;
2013  sInvariantDump << endl;
2014 
2015  // close with flushing to force it to be written even if we crash
2016  sInvariantDump.flush();
2017  sInvariantDump.close();
2018  #endif // _Macintosh
2019 }
2020 
2021 #endif // OOF_INVARIANT_DUMP_NAME
2022 
2023 
2024 void
2026 {
2027  const oofString stateString = InvariantDescription();
2028  os << " Current database state: " << endl
2029  << stateString << endl;
2030 }
2031 
2032 
2033 oofString
2035 {
2036  oofString stateString;
2037 
2038  stateString.convertNumber(mTable->validatingDepth(),"%u",true);
2039  stateString += "\t";
2040 
2041 
2042  switch(mRecordState) {
2043  case (eNew) :
2044  stateString += "N\t";
2045  break;
2046 
2047  case (eLoaded) :
2048  stateString += "L\t";
2049  break;
2050 
2051  case (eUnloaded) :
2052  stateString += "U\t";
2053  break;
2054 
2055  default:
2056  assert(!"unknown state"); //lint !e506 constant Boolean
2057  }
2058 
2059  switch(mTable->validStatus()) {
2060  case (dbTable::eInvalid) :
2061  stateString += "I\t";
2062  break;
2063 
2064  case (dbTable::eValid) :
2065  stateString += "V\t";
2066  break;
2067 
2068  case (dbTable::eClosed) :
2069  stateString += "C\t";
2070  break;
2071 
2072  default:
2073  assert(!"unknown state"); //lint !e506 constant Boolean
2074  }
2075 
2076  if(mDirty)
2077  stateString += "D\t";
2078  else
2079  stateString += "N\t";
2080  //add the address of this
2081  stateString.convertNumber((unsigned long) this, "%.8X\t", true /* append */);
2082  stateString.convertNumber(mCurrLoadedRecOffset, "%.8X\t", true /* append */);
2083  //selection state
2084  stateString.convertNumber(mSelection.oneRecOffset(), "%.8X\t", true /* append */);
2085  stateString.convertNumber(mSelection.iter(), "%.8X\t", true /* append */);
2086 
2087  //stateString.convertNumber(mSelection.mRep->mCurrSingleRecOffset, "%X\t", true /* append */);
2088  //stateString.convertNumber(mSelection.mRep->iter(), "%X\t", true /* append */);
2089 
2090  switch(mSelection.state()) {
2092  stateString += "E\t";
2093  break;
2094 
2096  stateString += "O\t";
2097  break;
2098 
2100  stateString += "S\t";
2101  break;
2102 
2104  stateString += "A\t";
2105  break;
2106 
2107  default:
2108  assert(!"unknown state"); //lint !e506 constant Boolean
2109  }
2110 
2111 
2112  // sorter state
2113  dbSorter* theSorter = mSelection.sorter();
2114  if(theSorter){
2115  union {
2116  char theString[4];
2117  unsigned long currentState;
2118  } stateValue;
2119  stateValue.currentState = theSorter->state();
2120 
2121  stateString.append(stateValue.theString ,4); // may have endian problems
2122 
2123  //stateString+= "\t";
2124  }
2125  else{
2126  stateString += "NONE";
2127 
2128  }
2129  return stateString;
2130 }
2131 
Persistent field used to store a double.
Definition: oof4.h:521
int OOF_strnicmp(const char *, const char *, const unsigned int)
Compare strings ignoring case, with length limit.
Definition: oofstr.cpp:69
const dbField * lhsField() const
Definition: oofquery.h:620
dbQueryLiteralStrMultiValue * literalMultiStrClause() const
Definition: oofquery.cpp:286
static void raise(std::ostream &, bool terminateAfterMsg=true)
unsigned long countOccupied() const
Definition: oofrecs.h:801
virtual const char * word() const
returns the current word.
Definition: oofwords.cpp:228
bool SearchWordNonIndexed(const dbField *, const char *, bool startsWith=false)
Definition: oofrec3.cpp:237
void adopt(OOF_recordSelection &)
Definition: oofrec4.cpp:836
void intersection_with(const dbSelection &)
Definition: oof2.cpp:635
precompilation header.
Binary query combining two sub-queries.
Definition: oofquery.h:203
Tries to hide the different platforms and version issues with standard IO.
virtual bool searchSelContainsAnyDelimited(const dbField *schField, const char *schStr, char delim)
Definition: oofrec3.cpp:1350
virtual bool SearchTrinaryFieldToLiterals(const dbQueryTrinary *)
Definition: oofrec3.cpp:1753
virtual void beginTransaction(short tMode)
Definition: oofrec3.cpp:1808
bool SearchEqualNonIndexed(const dbField *, const char *, bool matchEntireKey=true)
Definition: oofrec3.cpp:196
Base class for user-replaceable word parser.
Definition: oofwords.h:40
void append(OOF_recordBufferedContext *adoptingContext)
Definition: oofrec4.cpp:135
Simplest internal representation of a record's contents and context in dbTable.
Definition: oofrecs.h:130
Highest level used to assemble queries.
Definition: oofquery.h:46
dbQueryClause::QueryCombinatorialOps binaryOperator() const
Definition: oofquery.h:630
bool SearchBetweenNonIndexed(const dbField *, const char *, const char *)
Definition: oofrec3.cpp:783
virtual bool checkDuplicate(const dbQueryClause *)
Definition: oofrec3.cpp:110
Envelope class to contain an abstract selection apart from its dbTable.
Definition: oof1.h:316
dbQueryLiteralStr * literalStrToClause() const
Definition: oofquery.cpp:769
virtual bool searchSelContainsAllOf(const dbField *schField, const char **schStrs, unsigned long count)
Definition: oofrec3.cpp:1390
OOF_recordBufferedContext * item(unsigned long)
Definition: oofrec4.cpp:203
dbQueryClause::BinaryQueryOps binaryOperator() const
Definition: oofquery.h:610
void append(const char *, unsigned long appendLen)
Definition: oofstr.cpp:843
virtual unsigned long fieldStorageLen() const =0
Definition: oof3.h:26
dbQueryLiteral * literalToClause() const
Definition: oofquery.cpp:788
Common trinary query for field, eg: People.Salary.between(50000, 90000); Very similar to dbQueryBinar...
Definition: oofquery.h:263
int OOF_stricmp(const char *, const char *)
Compare strings ignoring case.
Definition: oofstr.cpp:59
virtual void getSearchTables(const dbTable *inSchTable, dbTable *&outDiffFieldTable, dbTable *&outRelatedTable) const
Definition: oofquery.cpp:41
virtual bool loadRelatedContextJoiningFromTo(const dbField *, const dbField *)
Implements relationships via searching.
Definition: oofrec3.cpp:1470
virtual bool SearchSelectionBinaryFieldToLiteral(const dbQueryBinary *)
Definition: oofrec3.cpp:1542
unsigned long currentOffset() const
Definition: oofrecs.h:718
virtual void commitTransaction(short rMode)
Definition: oofrec3.cpp:1815
virtual bool SearchCombineSubclauses(const dbQueryBinaryCombo *, bool searchSel)
Definition: oofrec3.cpp:1709
bool search(const dbQueryClause &query)
Definition: oof1.cpp:2348
virtual OOF_fieldTypes nativeType() const
Definition: oof3.cpp:301
Persistent field used to store an unsigned short.
Definition: oof4.h:317
static bool wildcardsInString(const char *)
Definition: oofquery.cpp:55
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
void describeInvariant(std::ostream &) const
debugging
Definition: oofrec3.cpp:2025
Common binary query for field, eg: People.Salary > 90000.
Definition: oofquery.h:165
bool SearchComparativeNonIndexed(const dbField *, const char *, dbQueryClause::BinaryQueryOps)
Definition: oofrec3.cpp:1032
virtual bool search(const dbQueryClause *qClause)
Definition: oofrec3.cpp:43
void convertNumber(int, const char *printfMask=0, bool appendIt=false)
Definition: oofstr.cpp:882
void getStr255(Str255 s) const
Definition: oofstr.cpp:414
Definition: oof3.h:26
bool SearchSelectionTrinaryFieldToLiterals(const dbQueryTrinary *)
Definition: oofrec3.cpp:1602
unsigned long count() const
Definition: oofrecs.h:794
oofString InvariantDescription() const
Definition: oofrec3.cpp:2034
dbQueryLiteralStr * literalStrClause() const
Definition: oofquery.cpp:276
dbQueryLiteral * literalFromClause() const
Definition: oofquery.cpp:779
Wildcard type for parsing string literals when querying database.
Definition: oofrecs.h:305
virtual const void * binaryContents() const
Definition: oofquery.cpp:898
Selection of records in context of a single dbTable instance.
Definition: oofrecs.h:173
static char sWildcardMultiple
Definition: oofquery.h:86
unsigned long length() const
Primary test: oofStringTest::emptyStringByNullInitIsLenZero()
Definition: oofstr.h:447
class for building queries of arbitrary complexity with application logic.
Definition: oofquery.h:101
bool SearchNotEqualNonIndexedWildcard(const dbField *schField, const char *schStr, bool matchEntireKey=true)
Definition: oofrec3.cpp:500
Store RAM-resident cache of records, eg: OOF_simpleRecordBackend::mDirtyRecordCache.
Definition: oofrecs.h:76
virtual void unlockRecord()
Definition: oofrec3.cpp:1802
virtual dbQueryClause * valueAsQueryLiteral() const
Definition: oof3.cpp:184
virtual bool searchSelection(const dbQueryClause *)
Definition: oofrec3.cpp:117
Persistent field used to store a fixed-length string.
Definition: oof3.h:255
Specify sort order by one more fields.
Definition: oof1.h:1277
bool SearchOutsideNonIndexed(const dbField *, const char *, const char *)
Definition: oofrec3.cpp:813
virtual bool searchSelContainsAnyOf(const dbField *schField, const char **schStrs, unsigned long count)
Definition: oofrec3.cpp:1317
virtual bool SearchBinaryFieldToLiteral(const dbQueryBinary *)
Definition: oofrec3.cpp:1645
Base class for persistent tables.
Definition: oof1.h:452
dbQueryLiteral * literalClause() const
Definition: oofquery.cpp:296
dbQueryClause::TrinaryQueryOps trinaryOperator() const
Definition: oofquery.h:640
Definition: oof3.h:26
Portable highly capable string class.
Definition: oofstr.h:101
Definition: oof3.h:26
bool relateSelectionFrom(dbTable *)
Definition: oof1.cpp:1900
Save the current directory and restore when we leave scope.
Definition: ooffiles.h:362
virtual bool searchSelContainsAllDelimited(const dbField *schField, const char *schStr, char delim)
Definition: oofrec3.cpp:1422
const dbField * lhsField() const
Definition: oofquery.h:646
Persistent field used to store a short.
Definition: oof4.h:272
dbQueryLiteralStr * literalStrFromClause() const
Definition: oofquery.cpp:759
virtual void lockRecord()
Definition: oofrec3.cpp:1795
#define OOF_MEM_DEBUG_FORCE_POOL_CHECK
Definition: doxyoof.h:408
bool SearchEqualNonIndexedWildcard(const dbField *schField, const char *schStr, bool matchEntireKey=true)
Definition: oofrec3.cpp:326
static char sWildcardSingle
Definition: oofquery.h:87
Provides cross-platform directory specification and iteration.
Definition: ooffiles.h:235
virtual void abortTransaction(short rMode)
Definition: oofrec3.cpp:1822
Persistent field used to store a variable length string.
Definition: oof3.h:459
RHS String argument to queries on fields like dbChar.
Definition: oofquery.h:324
virtual oofString copyString() const
Definition: oof3.cpp:472
const char * str() const
Definition: oofquery.h:666
virtual bool searchEqual(const dbField *, const char *, bool matchEntireKey=true)
Definition: oofrec3.cpp:186
virtual OOF_fieldTypes fieldType() const =0
virtual bool more() const
return true if any words left.
Definition: oofwords.cpp:217
bool isNew() const
Definition: oofrecs.h:697
bool Invariant(const char *optionalComment=0) const
Check combination of member variables defining Invariant state.
Definition: oofrec3.cpp:1837
virtual oofWordParser * words() const
Definition: oof3.cpp:251
virtual unsigned long state() const
Definition: oof1.cpp:3055
virtual void next(void)
Find the next word, updating the mWord pointer returned by word();.
Definition: oofwords.cpp:135
Persistent field used to store an unsigned long.
Definition: oof4.h:475
unsigned long state() const
Definition: oofrec3.cpp:1904
#define OOF_INVARIANT_DUMP_NAME
Define this as a valid filename to cause detailed logging.
const dbQueryClause * item(unsigned int) const
Definition: oofquery.cpp:498
Base for the RHS arguments to combinatorial queries dbQueryBinary, dbQueryTrinary.
Definition: oofquery.h:307
Base class for persistent fields in dbTable's.
Definition: oof3.h:63
bool SearchNotEqualNonIndexed(const dbField *, const char *, bool matchEntireKey=true)
Definition: oofrec3.cpp:288
virtual const char * asChars() const
Definition: oof3.cpp:243
virtual dbQueryClause::QueryClauseTypes queryClauseType() const =0
Persistent field used to store a long.
Definition: oof4.h:433