OOFILE  1.9
oofrec2.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 #include "oofpch_c.h" // for precompilation of core files
6 
7 #ifndef H_OOFIOS
8  #include "oofios.h"
9 #endif
10 #ifndef H_OOFRECS
11  #include "oofrecs.h"
12 #endif
13 #ifndef H_OOFLIST
14  #include "ooflist.h"
15 #endif
16 #ifndef H_OOFWORDS
17  #include "oofwords.h"
18 #endif
19 #ifndef OOF_EXCEP
20  #include "oofexcep.h"
21 #endif
22 #include <ctype.h>
23 
24 #ifdef OOF_MEM_DEBUG_LAST_INCLUDE
25  #include OOF_MEM_DEBUG_LAST_INCLUDE
26 #endif
27 
28 #ifndef OOF_NO_STDLIB
29  #ifndef std
30  using namespace std;
31  #endif
32 #endif
33 
34 
35 // Prototype for function used in these sorts only
36 void OOF_copyFirstFour(unsigned long *dest,const char *input);
37 
38 
39 // --------------------------------------------------------------------------------------------------
40 // U T I L I T I E S
41 // --------------------------------------------------------------------------------------------------
42 
51 void
52 OOF_copyFirstFour(unsigned long* dest,const char* input)
53 {
54  char* destch=(char*)dest;
55 
56 #if OOF_INTEL_BYTE_ORDER
57 // we are treating strings as an unsigned long
58 // so must swap the order of the bytes to keep numeric order
59 // ascending same as string sort order
60  for(unsigned i=0;i<4;i++){
61  destch[3-i]=toupper(input[i]);
62  }
63 #else
64  for(unsigned i=0;i<4;i++){
65  destch[i]=toupper(input[i]);
66  }
67 #endif
68 }
69 
70 
71 // -------------------------------------------------------
72 // 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
73 // see also oofrec1.cpp & oofrec3.cpp
74 // -------------------------------------------------------
75 
92 void
94 {
95 #ifdef OOF_DEBUG
96  if(!theSorter->countSegments())
97  dbConnect::raise("dbSorter has no segments - What am I meant to be sorting on ?");
98 #endif
99 
100 // mSelection.aboutToDirtySelection(); NOT NEEDED UNLESS SORTS CHANGE TO BE IN-PLACE
101 
102  const fieldNumT sortFieldNum = theSorter->fieldNumberOfSegment(0);
103  const dbField *theField=field(sortFieldNum);
104  OOF_recordSelection newSelection( mTable->prototype() );
105 
106  switch(theField->fieldType()) {
107  case uLongField:
108  {
109  OOF_ULPSorter lhs;
110 
111  if(!theSorter->segment(0)->isReversed()) {
112  for(start();more();next()) {
113  lhs.sortedInsert(*(dbUlong*)theField, mCurrLoadedRecOffset);
114  }
115  }
116  else {
117  for(start();more();next()) {
118  lhs.sortedInsertReverse(*(dbUlong*)theField, mCurrLoadedRecOffset);
119  }
120  }
121 
122  // OK - we have a sorted and partitioned lhs - now copy it back
123  // and subsort the partitions
124  if(theSorter->countSegments()==1) { // If we have no subsorts - don't bother
125  while(!lhs.isEmpty())
126  newSelection.append(lhs.remove());
127  }
128  else {
129  while(!lhs.isEmpty()) {
130  if(lhs.theFirst()->mPart) { // we found a partition
131  unsigned long count=lhs.theFirst()->mPart+1;
132  while(lhs.theFirst()->mPart) {
133  newSelection.append(lhs.remove());
134  }
135  newSelection.append(lhs.remove()); // Append the zeroth item in the partition
136  SubSort(theSorter, 1, &newSelection[(newSelection.count()-count)], count);
137  }
138  else
139  newSelection.append(lhs.remove());
140  }
141  }
142  }
143  break;
144 
145  case dateField:
146  {
147  OOF_ULPSorter lhs;
148 
149  if(!theSorter->segment(0)->isReversed()) {
150  for(start();more();next()) {
151  lhs.sortedInsert(*(dbDate*)theField, mCurrLoadedRecOffset);
152  }
153  }
154  else {
155  for(start();more();next()) {
156  lhs.sortedInsertReverse(*(dbDate*)theField, mCurrLoadedRecOffset);
157  }
158  }
159 
160  // OK - we have a sorted and partitioned lhs - now copy it back
161  // and subsort the partitions
162  if(theSorter->countSegments()==1) {// If we have no subsorts - don't bother
163  while(!lhs.isEmpty())
164  newSelection.append(lhs.remove());
165  }
166  else {
167  while(!lhs.isEmpty()) {
168  if(lhs.theFirst()->mPart) { // we found a partition
169  unsigned long count=lhs.theFirst()->mPart+1;
170  while(lhs.theFirst()->mPart) {
171  newSelection.append(lhs.remove());
172  }
173  newSelection.append(lhs.remove()); // Append the zeroth item in the partition
174  SubSort(theSorter, 1, &newSelection[(newSelection.count()-count)], count);
175  }
176  else
177  newSelection.append(lhs.remove());
178  }
179  }
180  }
181  break;
182 
183  case dateTimeField:
184  {
185  OOF_ULPSorter lhs;
186 
187  if(!theSorter->segment(0)->isReversed()) {
188  for(start();more();next()) {
189  lhs.sortedInsert(*(dbDateTime*)theField, mCurrLoadedRecOffset);
190  }
191  }
192  else {
193  for(start();more();next()) {
194  lhs.sortedInsertReverse(*(dbDateTime*)theField, mCurrLoadedRecOffset);
195  }
196  }
197 
198  // OK - we have a sorted and partitioned lhs - now copy it back
199  // and subsort the partitions
200  if(theSorter->countSegments()==1) { // If we have no subsorts - don't bother
201  while(!lhs.isEmpty())
202  newSelection.append(lhs.remove());
203  }
204  else {
205  while(!lhs.isEmpty()) {
206  if(lhs.theFirst()->mPart) { // we found a partition
207  unsigned long count=lhs.theFirst()->mPart+1;
208  while(lhs.theFirst()->mPart) {
209  newSelection.append(lhs.remove());
210  }
211  newSelection.append(lhs.remove()); // Append the zeroth item in the partition
212  SubSort(theSorter, 1, &newSelection[(newSelection.count()-count)], count);
213  }
214  else
215  newSelection.append(lhs.remove());
216  }
217  }
218  }
219  break;
220 
221  case timeField:
222  {
223  OOF_ULPSorter lhs;
224 
225  if(!theSorter->segment(0)->isReversed()) {
226  for(start();more();next()) {
227  lhs.sortedInsert(*(dbTime*)theField, mCurrLoadedRecOffset);
228  }
229  }
230  else {
231  for(start();more();next()) {
232  lhs.sortedInsertReverse(*(dbTime*)theField, mCurrLoadedRecOffset);
233  }
234  }
235 
236  // OK - we have a sorted and partitioned lhs - now copy it back
237  // and subsort the partitions
238  if(theSorter->countSegments()==1) { // If we have no subsorts - don't bother
239  while(!lhs.isEmpty())
240  newSelection.append(lhs.remove());
241  }
242  else {
243  while(!lhs.isEmpty()) {
244  if(lhs.theFirst()->mPart) { // we found a partition
245  unsigned long count=lhs.theFirst()->mPart+1;
246  while(lhs.theFirst()->mPart) {
247  newSelection.append(lhs.remove());
248  }
249  newSelection.append(lhs.remove()); // Append the zeroth item in the partition
250  SubSort(theSorter, 1, &newSelection[(newSelection.count()-count)], count);
251  }
252  else
253  newSelection.append(lhs.remove());
254  }
255  }
256  }
257  break;
258 
259  case uShortField:
260  {
261  OOF_ULPSorter lhs;
262 
263  if(!theSorter->segment(0)->isReversed()) {
264  for(start();more();next()) {
265  lhs.sortedInsert(*(dbUshort*)theField, mCurrLoadedRecOffset);
266  }
267  }
268  else {
269  for(start();more();next()) {
270  lhs.sortedInsertReverse(*(dbUshort*)theField, mCurrLoadedRecOffset);
271  }
272  }
273 
274  // OK - we have a sorted and partitioned lhs - now copy it back
275  // and subsort the partitions
276  if(theSorter->countSegments()==1) {// If we have no subsorts - don't bother
277  while(!lhs.isEmpty())
278  newSelection.append(lhs.remove());
279  }
280  else {
281  while(!lhs.isEmpty()) {
282  if(lhs.theFirst()->mPart) { // we found a partition
283  unsigned long count=lhs.theFirst()->mPart+1;
284  while(lhs.theFirst()->mPart) {
285  newSelection.append(lhs.remove());
286  }
287  newSelection.append(lhs.remove()); // Append the zeroth item in the partition
288  SubSort(theSorter, 1, &newSelection[(newSelection.count()-count)], count);
289  }
290  else
291  newSelection.append(lhs.remove());
292  }
293  }
294  }
295  break;
296 
297  case longField:
298  {
299  OOF_LPSorter lhs;
300 
301  if(!theSorter->segment(0)->isReversed()) {
302  for(start();more();next()) {
303  lhs.sortedInsert(*(dbLong*)theField, mCurrLoadedRecOffset);
304  }
305  }
306  else {
307  for(start();more();next()) {
308  lhs.sortedInsertReverse(*(dbLong*)theField, mCurrLoadedRecOffset);
309  }
310  }
311  // OK - we have a sorted and partitioned lhs - now copy it back
312  // and subsort the partitions
313  if(theSorter->countSegments()==1) { // If we have no subsorts - don't bother
314  while(!lhs.isEmpty())
315  newSelection.append(lhs.remove());
316  }
317  else {
318  while(!lhs.isEmpty()) {
319  if(lhs.theFirst()->mPart) { // we found a partition
320  unsigned long count=lhs.theFirst()->mPart+1;
321  while(lhs.theFirst()->mPart) {
322  newSelection.append(lhs.remove());
323  }
324  newSelection.append(lhs.remove()); // Append the zeroth item in the partition
325  SubSort(theSorter, 1, &newSelection[(newSelection.count()-count)], count);
326  }
327  else
328  newSelection.append(lhs.remove());
329  }
330  }
331  }
332  break;
333 
334  case shortField:
335  {
336  OOF_LPSorter lhs;
337 
338  if(!theSorter->segment(0)->isReversed()) {
339  for(start();more();next()) {
340  lhs.sortedInsert(*(dbShort*)theField, mCurrLoadedRecOffset);
341  }
342  }
343  else {
344  for(start();more();next()) {
345  lhs.sortedInsertReverse(*(dbShort*)theField, mCurrLoadedRecOffset);
346  }
347  }
348  // OK - we have a sorted and partitioned lhs - now copy it back
349  // and subsort the partitions
350  if(theSorter->countSegments()==1) {// If we have no subsorts - don't bother
351  while(!lhs.isEmpty())
352  newSelection.append(lhs.remove());
353  }
354  else {
355  while(!lhs.isEmpty()) {
356  if(lhs.theFirst()->mPart) { // we found a partition
357  unsigned long count=lhs.theFirst()->mPart+1;
358  while(lhs.theFirst()->mPart) {
359  newSelection.append(lhs.remove());
360  }
361  newSelection.append(lhs.remove()); // Append the zeroth item in the partition
362  SubSort(theSorter, 1, &newSelection[(newSelection.count()-count)], count);
363  }
364  else
365  newSelection.append(lhs.remove());
366  }
367  }
368  }
369  break;
370 
371  case realField:
372  {
373  OOF_DPSorter lhs;
374 
375  if(!theSorter->segment(0)->isReversed()) {
376  for(start();more();next()) {
377  lhs.sortedInsert(*(dbReal*)theField, mCurrLoadedRecOffset);
378  }
379  }
380  else {
381  for(start();more();next()) {
382  lhs.sortedInsertReverse(*(dbReal*)theField, mCurrLoadedRecOffset);
383  }
384  }
385  // OK - we have a sorted and partitioned lhs - now copy it back
386  // and subsort the partitions
387  if(theSorter->countSegments()==1) {// If we have no subsorts - don't bother
388  while(!lhs.isEmpty())
389  newSelection.append(lhs.remove());
390  }
391  else {
392  while(!lhs.isEmpty()) {
393  if(lhs.theFirst()->mPart) { // we found a partition
394  unsigned long count=lhs.theFirst()->mPart+1;
395  while(lhs.theFirst()->mPart) {
396  newSelection.append(lhs.remove());
397  }
398  newSelection.append(lhs.remove()); // Append the zeroth item in the partition
399  SubSort(theSorter, 1, &newSelection[(newSelection.count()-count)], count);
400  }
401  else
402  newSelection.append(lhs.remove());
403  }
404  }
405  }
406  break;
407 
408  case charField:
409  {
410  OOF_ULPSorter lhs;
411  dbTable* compareTable = theField->fieldTable()->cloneTableWithoutSelection();
412  dbChar* compareField = (dbChar *)compareTable->field(theField->fieldNumber());
413 
414  if(!theSorter->segment(0)->isReversed()) {
415  for(start();more();next()) {
416  unsigned long FirstFour = 0;
417  OOF_copyFirstFour(&FirstFour,*(dbChar *)theField);
418  lhs.sortedInsert(FirstFour, mCurrLoadedRecOffset);
419  while(lhs.lastEqual()) {
420  // Load the matching record into compareField
421  compareTable->selectJustOID(lhs.theEqual()->mNext->mData);
422  int diff=OOF_stricmp(*(dbChar *)theField,*compareField);
423  if(!diff){
424  lhs.theEqual()->mPart=lhs.theEqual()->mNext->mPart+1;
425  break;
426  }
427  else if(diff>0) {
428  lhs.theEqual()->mPart=0; // This is not part of a partition
429  lhs.exchange(lhs.theEqual());
430  }
431  else {
432  lhs.theEqual()->mPart=0; // This is not part of a partition
433  break;
434  }
435  }
436  }
437  }
438  else {
439  for(start();more();next()) {
440  unsigned long FirstFour = 0;
441  OOF_copyFirstFour(&FirstFour,*(dbChar *)theField);
442  lhs.sortedInsertReverse(FirstFour, mCurrLoadedRecOffset);
443  while(lhs.lastEqual()) {
444  // Load the matching record into compareField
445  compareTable->selectJustOID(lhs.theEqual()->mNext->mData);
446  int diff=OOF_stricmp(*(dbChar *)theField,*compareField);
447  if(!diff){
448  lhs.theEqual()->mPart=lhs.theEqual()->mNext->mPart+1;
449  break;
450  }
451  else if(diff<0) {
452  lhs.theEqual()->mPart=0; // This is not part of a partition
453  lhs.exchange(lhs.theEqual());
454  }
455  else {
456  lhs.theEqual()->mPart=0; // This is not part of a partition
457  break;
458  }
459  }
460  }
461  }
462 
463  // OK - we have a sorted and partitioned lhs - now copy it back
464  // and subsort the partitions
465  if(theSorter->countSegments()==1) { // If we have no subsorts - don't bother
466  while(!lhs.isEmpty())
467  newSelection.append(lhs.remove());
468  }
469  else {
470  while(!lhs.isEmpty()) {
471  if(lhs.theFirst()->mPart) { // we found a partition
472  unsigned long count=lhs.theFirst()->mPart+1;
473  while(lhs.theFirst()->mPart) {
474  newSelection.append(lhs.remove());
475  }
476  newSelection.append(lhs.remove()); // Append the zeroth item in the partition
477  SubSort(theSorter, 1, &newSelection[(newSelection.count()-count)], count);
478  }
479  else
480  newSelection.append(lhs.remove());
481  }
482  }
483  delete compareTable;
484  }
485  break;
486 
487  case textField:
488  {
489  OOF_ULPSorter lhs;
490  dbTable* compareTable = theField->fieldTable()->cloneTableWithoutSelection();
491  dbText* compareField = (dbText *)compareTable->field(theField->fieldNumber());
492 
493  if(!theSorter->segment(0)->isReversed()) {
494  for(start();more();next())
495  {
496  unsigned long FirstFour = 0;
497  OOF_copyFirstFour(&FirstFour,*(dbText *)theField);
498  lhs.sortedInsert(FirstFour, mCurrLoadedRecOffset);
499  while(lhs.lastEqual()) {
500  // Load the matching record into compareField
501  compareTable->selectJustOID(lhs.theEqual()->mNext->mData);
502  int diff=OOF_stricmp(*(dbText *)theField,*compareField);
503  if(!diff){
504  lhs.theEqual()->mPart=lhs.theEqual()->mNext->mPart+1;
505  break;
506  } else if(diff>0) {
507  lhs.theEqual()->mPart=0; // This is not part of a partition
508  lhs.exchange(lhs.theEqual());
509  } else {
510  lhs.theEqual()->mPart=0; // This is not part of a partition
511  break;
512  }
513  }
514  }
515  }
516  else
517  for(start();more();next())
518  {
519  unsigned long FirstFour = 0;
520  OOF_copyFirstFour(&FirstFour,*(dbText *)theField);
521  lhs.sortedInsertReverse(FirstFour, mCurrLoadedRecOffset);
522  while(lhs.lastEqual()) {
523  // Load the matching record into compareField
524  compareTable->selectJustOID(lhs.theEqual()->mNext->mData);
525  int diff=OOF_stricmp(*(dbText *)theField,*compareField);
526  if(!diff){
527  lhs.theEqual()->mPart=lhs.theEqual()->mNext->mPart+1;
528  break;
529  }
530  else if(diff<0) {
531  lhs.theEqual()->mPart=0; // This is not part of a partition
532  lhs.exchange(lhs.theEqual());
533  }
534  else {
535  lhs.theEqual()->mPart=0; // This is not part of a partition
536  break;
537  }
538  }
539  }
540 
541  // OK - we have a sorted and partitioned lhs - now copy it back
542  // and subsort the partitions
543  if(theSorter->countSegments()==1) {// If we have no subsorts - don't bother
544  while(!lhs.isEmpty())
545  newSelection.append(lhs.remove());
546  }
547  else {
548  while(!lhs.isEmpty()) {
549  if(lhs.theFirst()->mPart) { // we found a partition
550  unsigned long count=lhs.theFirst()->mPart+1;
551  while(lhs.theFirst()->mPart) {
552  newSelection.append(lhs.remove());
553  }
554  newSelection.append(lhs.remove()); // Append the zeroth item in the partition
555  SubSort(theSorter, 1, &newSelection[(newSelection.count()-count)], count);
556  }
557  else
558  newSelection.append(lhs.remove());
559  }
560  }
561  delete compareTable;
562  }
563  break;
564 
565  case compoundField:
566  {
567  dbCompoundField* sortingBy = (dbCompoundField*)theField; // safe downcast
568  dbSorter temp(*sortingBy); // both descend from OOF_FieldSegOwner so can copy construct
569  sortSelectionNow(&temp);
570  return; // EARLY EXIT - recursive call has already done the following
571  }
572  break;
573 
574  default:
575  {
576  oofE_General excp(stringstream() << flush
577  << "SortSelectionNow is not defined on field type"
578  << theField->fieldType() << " for other than indexed selections of all records");
579  RAISE_EXCEPTION(excp);
580  // NOT YET IMPLEMENTED
581  }
582  }
583 
584  mSelection=newSelection;
585  start(); // Make sure the selection context is logical before returning.
586 }
587 
588 
601 void
602 OOF_simpleRecordBackend::SubSort(const dbSorter *theSorter, const unsigned long level, unsigned long *theData, const unsigned long count)
603 {
604  assert( Invariant("simpleB::SubSort-entry") );
605  const fieldNumT sortFieldNum = theSorter->fieldNumberOfSegment(level);
606  const dbField *theField=field(sortFieldNum);
607  switch(theField->fieldType()) {
608  case uLongField: {
609  OOF_ULPSorter lhs;
610 
611  if(!theSorter->segment(level)->isReversed()) {
612  for(unsigned int i=0;i<count;i++){
613  LoadRecordAtOffset(theData[i]);
614  lhs.sortedInsert(*(dbUlong*)theField, theData[i]);
615  }
616  } else {
617  for(unsigned int i=0;i<count;i++){
618  LoadRecordAtOffset(theData[i]);
619  lhs.sortedInsertReverse(*(dbUlong*)theField, theData[i]);
620  }
621  }
622 
623  // OK - we have a sorted and partitioned lhs - now copy it back
624  // and subsort the partitions
625  if(theSorter->countSegments()==(level+1)) { // If we have no further subsorts - don't bother
626  for(unsigned int i=0;i<count;i++)
627  theData[i]=lhs.remove();
628  } else {
629  unsigned int i=0;
630  while(i<count) {
631  if(lhs.theFirst()->mPart) { // we found a partition
632  unsigned long thisCount=lhs.theFirst()->mPart+1;
633  while(lhs.theFirst()->mPart) {
634  theData[i++]=lhs.remove();
635  }
636  theData[i++]=lhs.remove(); // Append the zeroth item in the partition
637  SubSort(theSorter, level+1, &theData[(i-thisCount)], thisCount);
638  } else
639  theData[i++]=lhs.remove();
640  }
641  }
642  }
643  break;
644  case uShortField: {
645  OOF_ULPSorter lhs;
646 
647  if(!theSorter->segment(level)->isReversed()) {
648  for(unsigned int i=0;i<count;i++){
649  LoadRecordAtOffset(theData[i]);
650  lhs.sortedInsert(*(dbUshort*)theField, theData[i]);
651  }
652  } else {
653  for(unsigned int i=0;i<count;i++){
654  LoadRecordAtOffset(theData[i]);
655  lhs.sortedInsertReverse(*(dbUshort*)theField, theData[i]);
656  }
657  }
658 
659  // OK - we have a sorted and partitioned lhs - now copy it back
660  // and subsort the partitions
661  if(theSorter->countSegments()==(level+1)) { // If we have no further subsorts - don't bother
662  for(unsigned int i=0;i<count;i++)
663  theData[i]=lhs.remove();
664  } else {
665  unsigned int i=0;
666  while(i<count) {
667  if(lhs.theFirst()->mPart) { // we found a partition
668  unsigned long thisCount=lhs.theFirst()->mPart+1;
669  while(lhs.theFirst()->mPart) {
670  theData[i++]=lhs.remove();
671  }
672  theData[i++]=lhs.remove(); // Append the zeroth item in the partition
673  SubSort(theSorter, level+1, &theData[(i-thisCount)], thisCount);
674  } else
675  theData[i++]=lhs.remove();
676  }
677  }
678  }
679  break;
680  case dateField: {
681  OOF_ULPSorter lhs;
682 
683  if(!theSorter->segment(level)->isReversed()) {
684  for(unsigned int i=0;i<count;i++){
685  LoadRecordAtOffset(theData[i]);
686  lhs.sortedInsert(*(dbDate*)theField, theData[i]);
687  }
688  } else {
689  for(unsigned int i=0;i<count;i++){
690  LoadRecordAtOffset(theData[i]);
691  lhs.sortedInsertReverse(*(dbDate*)theField, theData[i]);
692  }
693  }
694 
695  // OK - we have a sorted and partitioned lhs - now copy it back
696  // and subsort the partitions
697  if(theSorter->countSegments()==(level+1)) { // If we have no further subsorts - don't bother
698  for(unsigned int i=0;i<count;i++)
699  theData[i]=lhs.remove();
700  } else {
701  unsigned int i=0;
702  while(i<count) {
703  if(lhs.theFirst()->mPart) { // we found a partition
704  unsigned long thisCount=lhs.theFirst()->mPart+1;
705  while(lhs.theFirst()->mPart) {
706  theData[i++]=lhs.remove();
707  }
708  theData[i++]=lhs.remove(); // Append the zeroth item in the partition
709  SubSort(theSorter, level+1, &theData[(i-thisCount)], thisCount);
710  } else
711  theData[i++]=lhs.remove();
712  }
713  }
714  }
715  break;
716  case dateTimeField: {
717  OOF_ULPSorter lhs;
718 
719  if(!theSorter->segment(level)->isReversed()) {
720  for(unsigned int i=0;i<count;i++){
721  LoadRecordAtOffset(theData[i]);
722  lhs.sortedInsert(*(dbDateTime*)theField, theData[i]);
723  }
724  } else {
725  for(unsigned int i=0;i<count;i++){
726  LoadRecordAtOffset(theData[i]);
727  lhs.sortedInsertReverse(*(dbDateTime*)theField, theData[i]);
728  }
729  }
730 
731  // OK - we have a sorted and partitioned lhs - now copy it back
732  // and subsort the partitions
733  if(theSorter->countSegments()==(level+1)) { // If we have no further subsorts - don't bother
734  for(unsigned int i=0;i<count;i++)
735  theData[i]=lhs.remove();
736  } else {
737  unsigned int i=0;
738  while(i<count) {
739  if(lhs.theFirst()->mPart) { // we found a partition
740  unsigned long thisCount=lhs.theFirst()->mPart+1;
741  while(lhs.theFirst()->mPart) {
742  theData[i++]=lhs.remove();
743  }
744  theData[i++]=lhs.remove(); // Append the zeroth item in the partition
745  SubSort(theSorter, level+1, &theData[(i-thisCount)], thisCount);
746  } else
747  theData[i++]=lhs.remove();
748  }
749  }
750  }
751  break;
752  case timeField: {
753  OOF_ULPSorter lhs;
754 
755  if(!theSorter->segment(level)->isReversed()) {
756  for(unsigned int i=0;i<count;i++){
757  LoadRecordAtOffset(theData[i]);
758  lhs.sortedInsert(*(dbTime*)theField, theData[i]);
759  }
760  } else {
761  for(unsigned int i=0;i<count;i++){
762  LoadRecordAtOffset(theData[i]);
763  lhs.sortedInsertReverse(*(dbTime*)theField, theData[i]);
764  }
765  }
766 
767  // OK - we have a sorted and partitioned lhs - now copy it back
768  // and subsort the partitions
769  if(theSorter->countSegments()==(level+1)) { // If we have no further subsorts - don't bother
770  for(unsigned int i=0;i<count;i++)
771  theData[i]=lhs.remove();
772  } else {
773  unsigned int i=0;
774  while(i<count) {
775  if(lhs.theFirst()->mPart) { // we found a partition
776  unsigned long thisCount=lhs.theFirst()->mPart+1;
777  while(lhs.theFirst()->mPart) {
778  theData[i++]=lhs.remove();
779  }
780  theData[i++]=lhs.remove(); // Append the zeroth item in the partition
781  SubSort(theSorter, level+1, &theData[(i-thisCount)], thisCount);
782  } else
783  theData[i++]=lhs.remove();
784  }
785  }
786  }
787  break;
788  case longField: {
789  OOF_LPSorter lhs;
790 
791  if(!theSorter->segment(level)->isReversed()) {
792  for(unsigned int i=0;i<count;i++){
793  LoadRecordAtOffset(theData[i]);
794  lhs.sortedInsert(*(dbLong*)theField, theData[i]);
795  }
796  } else {
797  for(unsigned int i=0;i<count;i++){
798  LoadRecordAtOffset(theData[i]);
799  lhs.sortedInsertReverse(*(dbLong*)theField, theData[i]);
800  }
801  }
802 
803  // OK - we have a sorted and partitioned lhs - now copy it back
804  // and subsort the partitions
805  if(theSorter->countSegments()==(level+1)) { // If we have no further subsorts - don't bother
806  for(unsigned int i=0;i<count;i++)
807  theData[i]=lhs.remove();
808  } else {
809  unsigned int i=0;
810  while(i<count) {
811  if(lhs.theFirst()->mPart) { // we found a partition
812  unsigned long thisCount=lhs.theFirst()->mPart+1;
813  while(lhs.theFirst()->mPart) {
814  theData[i++]=lhs.remove();
815  }
816  theData[i++]=lhs.remove(); // Append the zeroth item in the partition
817  SubSort(theSorter, level+1, &theData[(i-thisCount)], thisCount);
818  } else
819  theData[i++]=lhs.remove();
820  }
821  }
822  }
823  break;
824  case shortField: {
825  OOF_LPSorter lhs;
826 
827  if(!theSorter->segment(level)->isReversed()) {
828  for(unsigned int i=0;i<count;i++){
829  LoadRecordAtOffset(theData[i]);
830  lhs.sortedInsert(*(dbShort*)theField, theData[i]);
831  }
832  } else {
833  for(unsigned int i=0;i<count;i++){
834  LoadRecordAtOffset(theData[i]);
835  lhs.sortedInsertReverse(*(dbShort*)theField, theData[i]);
836  }
837  }
838 
839  // OK - we have a sorted and partitioned lhs - now copy it back
840  // and subsort the partitions
841  if(theSorter->countSegments()==(level+1)) { // If we have no further subsorts - don't bother
842  for(unsigned int i=0;i<count;i++)
843  theData[i]=lhs.remove();
844  } else {
845  unsigned int i=0;
846  while(i<count) {
847  if(lhs.theFirst()->mPart) { // we found a partition
848  unsigned long thisCount=lhs.theFirst()->mPart+1;
849  while(lhs.theFirst()->mPart) {
850  theData[i++]=lhs.remove();
851  }
852  theData[i++]=lhs.remove(); // Append the zeroth item in the partition
853  SubSort(theSorter, level+1, &theData[(i-thisCount)], thisCount);
854  } else
855  theData[i++]=lhs.remove();
856  }
857  }
858  }
859  break;
860  case realField: {
861  OOF_DPSorter lhs;
862 
863  if(!theSorter->segment(level)->isReversed()) {
864  for(unsigned int i=0;i<count;i++){
865  LoadRecordAtOffset(theData[i]);
866  lhs.sortedInsert(*(dbReal*)theField, theData[i]);
867  }
868  } else {
869  for(unsigned int i=0;i<count;i++){
870  LoadRecordAtOffset(theData[i]);
871  lhs.sortedInsertReverse(*(dbReal*)theField, theData[i]);
872  }
873  }
874 
875  // OK - we have a sorted and partitioned lhs - now copy it back
876  // and subsort the partitions
877  if(theSorter->countSegments()==(level+1)) { // If we have no further subsorts - don't bother
878  for(unsigned int i=0;i<count;i++)
879  theData[i]=lhs.remove();
880  } else {
881  unsigned int i=0;
882  while(i<count) {
883  if(lhs.theFirst()->mPart) { // we found a partition
884  unsigned long thisCount=lhs.theFirst()->mPart+1;
885  while(lhs.theFirst()->mPart) {
886  theData[i++]=lhs.remove();
887  }
888  theData[i++]=lhs.remove(); // Append the zeroth item in the partition
889  SubSort(theSorter, level+1, &theData[(i-thisCount)], thisCount);
890  } else
891  theData[i++]=lhs.remove();
892  }
893  }
894  }
895  break;
896  case charField: {
897  OOF_ULPSorter lhs;
898 
899  if(!theSorter->segment(level)->isReversed()) {
900  for(unsigned int i=0;i<count;i++)
901  {
902  LoadRecordAtOffset(theData[i]);
903  unsigned long FirstFour = 0;
904  OOF_copyFirstFour(&FirstFour,*(dbChar *)theField);
905  lhs.sortedInsert(FirstFour, mCurrLoadedRecOffset);
906  if(lhs.lastEqual()) {
907  const oofString compareField=theField->copyString();
908  while(lhs.lastEqual()) {
909  // Load the matching record into a string
910  LoadRecordAtOffset(lhs.theEqual()->mNext->mData);
911  const int diff=OOF_stricmp(compareField,*(dbChar *)theField); // safe downcast
912  if(!diff){
913  lhs.theEqual()->mPart=lhs.theEqual()->mNext->mPart+1;
914  break;
915  } else if(diff>0) {
916  lhs.theEqual()->mPart=0; // This is not part of a partition
917  lhs.exchange(lhs.theEqual());
918  } else {
919  lhs.theEqual()->mPart=0; // This is not part of a partition
920  break;
921  }
922  }
923  }
924  }
925  }
926  else {
927  for(unsigned int i=0;i<count;i++)
928  {
929  LoadRecordAtOffset(theData[i]);
930  unsigned long FirstFour = 0;
931  OOF_copyFirstFour(&FirstFour,*(dbChar *)theField);
932  lhs.sortedInsertReverse(FirstFour, mCurrLoadedRecOffset);
933  if(lhs.lastEqual()) {
934  const oofString compareField=theField->copyString();
935  while(lhs.lastEqual()) {
936  // Load the matching record into a string
937  LoadRecordAtOffset(lhs.theEqual()->mNext->mData);
938  const int diff=OOF_stricmp(compareField,*(dbChar *)theField);
939  if(!diff){
940  lhs.theEqual()->mPart=lhs.theEqual()->mNext->mPart+1;
941  break;
942  } else if(diff<0) {
943  lhs.theEqual()->mPart=0; // This is not part of a partition
944  lhs.exchange(lhs.theEqual());
945  } else {
946  lhs.theEqual()->mPart=0; // This is not part of a partition
947  break;
948  }
949  }
950  }
951  }
952  }
953 
954  // OK - we have a sorted and partitioned lhs - now copy it back
955  // and subsort the partitions
956  if(theSorter->countSegments()==(level+1)) { // If we have no further subsorts - don't bother
957  for(unsigned int i=0;i<count;i++)
958  theData[i]=lhs.remove();
959  } else {
960  unsigned int i=0;
961  while(i<count) {
962  if(lhs.theFirst()->mPart) { // we found a partition
963  unsigned long thisCount=lhs.theFirst()->mPart+1;
964  while(lhs.theFirst()->mPart) {
965  theData[i++]=lhs.remove();
966  }
967  theData[i++]=lhs.remove(); // Append the zeroth item in the partition
968  SubSort(theSorter, level+1, &theData[(i-thisCount)], thisCount);
969  } else
970  theData[i++]=lhs.remove();
971  }
972  }
973  }
974  break;
975  case textField: {
976  OOF_ULPSorter lhs;
977 
978  if(!theSorter->segment(level)->isReversed()) {
979  for(unsigned int i=0;i<count;i++)
980  {
981  ((dbText *)theField)->reset();
982  LoadRecordAtOffset(theData[i]);
983  unsigned long FirstFour = 0;
984  OOF_copyFirstFour(&FirstFour,*(dbText *)theField);
985  lhs.sortedInsert(FirstFour, mCurrLoadedRecOffset);
986  if(lhs.lastEqual()) {
987  const oofString compareField=theField->copyString();
988  while(lhs.lastEqual()) {
989  // Load the matching record into a string
990  LoadRecordAtOffset(lhs.theEqual()->mNext->mData);
991  const int diff=OOF_stricmp(compareField,*(dbText *)theField);
992  if(!diff){
993  lhs.theEqual()->mPart=lhs.theEqual()->mNext->mPart+1;
994  break;
995  } else if(diff>0) {
996  lhs.theEqual()->mPart=0; // This is not part of a partition
997  lhs.exchange(lhs.theEqual());
998  } else {
999  lhs.theEqual()->mPart=0; // This is not part of a partition
1000  break;
1001  }
1002  }
1003  }
1004  }
1005  }
1006  else {
1007  for(unsigned int i=0;i<count;i++)
1008  {
1009  LoadRecordAtOffset(theData[i]);
1010  unsigned long FirstFour = 0;
1011  OOF_copyFirstFour(&FirstFour,*(dbChar *)theField);
1012  lhs.sortedInsertReverse(FirstFour, mCurrLoadedRecOffset);
1013  if(lhs.lastEqual()) {
1014  const oofString compareField=theField->copyString();
1015  while(lhs.lastEqual()) {
1016  // Load the matching record into a string
1017  LoadRecordAtOffset(lhs.theEqual()->mNext->mData);
1018  const int diff=OOF_stricmp(compareField,*(dbText *)theField);
1019  if(!diff){
1020  lhs.theEqual()->mPart=lhs.theEqual()->mNext->mPart+1;
1021  break;
1022  } else if(diff<0) {
1023  lhs.theEqual()->mPart=0; // This is not part of a partition
1024  lhs.exchange(lhs.theEqual());
1025  } else {
1026  lhs.theEqual()->mPart=0; // This is not part of a partition
1027  break;
1028  }
1029  }
1030  }
1031  }
1032  }
1033 
1034  // OK - we have a sorted and partitioned lhs - now copy it back
1035  // and subsort the partitions
1036  if(theSorter->countSegments()==(level+1)) { // If we have no further subsorts - don't bother
1037  for(unsigned int i=0;i<count;i++)
1038  theData[i]=lhs.remove();
1039  }
1040  else {
1041  unsigned int i=0;
1042  while(i<count) {
1043  if(lhs.theFirst()->mPart) { // we found a partition
1044  unsigned long thisCount=lhs.theFirst()->mPart+1;
1045  while(lhs.theFirst()->mPart) {
1046  theData[i++]=lhs.remove();
1047  }
1048  theData[i++]=lhs.remove(); // Append the zeroth item in the partition
1049  SubSort(theSorter, level+1, &theData[(i-thisCount)], thisCount);
1050  } else
1051  theData[i++]=lhs.remove();
1052  }
1053  }
1054  }
1055  break;
1056  default:
1057 #ifdef OOF_DEBUG
1058  dbConnect::raise(stringstream() << flush << "SubSort is not defined on field type"
1059  << theField->fieldType() << " for other than indexed selections of all records");
1060 #endif
1061  // NOT YET IMPLEMENTED - any field types left unimplemented, or is this a catchall for future?
1062  ;
1063  }
1064  assert( Invariant("simpleB::SubSort-exit") );
1065 }
1066 
1067 
1068 void
1070 {
1071  if ( (mSelection.state() == OOF_recordSelection::empty) ||
1072  (mSelection.state() == OOF_recordSelection::oneRec) )
1073  return;
1074 
1075  dbField* theFld = (dbField*) mFields.value(sortFieldNo); // safe downcast
1076 
1077  if ( CanUseIndex(theFld) && (mSelection.state() == OOF_recordSelection::allRecs) ) {
1078  return;
1079  }
1080 // mSelection.aboutToDirtySelection(); NOT NEEDED UNLESS SORTS CHANGE TO BE IN-PLACE
1081 
1082  switch(theFld->fieldType()){
1083  case uShortField: SortSelectionNow((dbUshort*)theFld); break;
1084  case shortField: SortSelectionNow((dbShort*)theFld); break;
1085  case uLongField: SortSelectionNow((dbUlong*)theFld); break;
1086  case longField: SortSelectionNow((dbLong*)theFld); break;
1087  case dateField: SortSelectionNow((dbUlong*)theFld); break;
1088  case dateTimeField: SortSelectionNow((dbUlong*)theFld); break;
1089  case timeField: SortSelectionNow((dbLong*)theFld); break;
1090  case realField: SortSelectionNow((dbReal*)theFld); break;
1091  case charField: SortSelectionNow((dbChar*)theFld); break;
1092  case textField: SortSelectionNow((dbText*)theFld); break;
1093  case compoundField:
1094  {
1095  dbCompoundField* sortingBy = (dbCompoundField*)theFld; // safe downcast
1096  dbSorter temp(*sortingBy); // both descend from OOF_FieldSegOwner so can copy construct
1097  sortSelectionNow(&temp);
1098  return; // EARLY EXIT - recursive call has already done the following
1099  }
1100  break;
1101 
1102  case fixedBinaryField: {
1103  unsigned long fixedLength = theFld->fieldStorageLen();
1104  // NOT YET IMPLEMENTED - cope with 4-byte fields as special case
1105  if (fixedLength>3)
1106  SortSelectionNow(theFld, fixedLength);
1107  else { // NOT YET IMPLEMENTED - cope with 2-byte fields with uShort sorter
1108  dbConnect::raise(stringstream() << flush
1109  << "Unable to Sort by field" << theFld->fieldName()
1110  << " SortSelectionNow is not defined on fields of type"
1111  << theFld->fieldType() << " < 4 bytes long",
1112  false /* don't terminate */
1113  );
1114  }
1115  }
1116  break;
1117  default:
1118  dbConnect::raise(stringstream() << flush
1119  << "Unable to Sort by field" << theFld->fieldName()
1120  << " SortSelectionNow is not defined on fields of type"
1121  << theFld->fieldType() << " for other than indexed selections of all records",
1122  false /* don't terminate */
1123  );
1124  // NOT YET IMPLEMENTED
1125  ;
1126  }
1127 }
1128 
1129 
1130 void
1132 {
1133  assert( Invariant("simpleB::sortSelectionInverseNow-entry") );
1134 
1135 // non-indexed sort, likely called on a subset of records
1136 
1137  if ( (mSelection.state() == OOF_recordSelection::empty) ||
1138  (mSelection.state() == OOF_recordSelection::oneRec)
1139  ) {
1140  assert( Invariant("simpleB::sortSelectionInverseNow-exit emptyOrOneRec") );
1141  return;
1142  }
1143 
1144 // mSelection.aboutToDirtySelection(); NOT NEEDED UNLESS SORTS CHANGE TO BE IN-PLACE
1145 
1146  dbField* theFld = (dbField*) mFields.value(sortFieldNo); // safe downcast
1147  switch(theFld->fieldType()){
1148  case uShortField: SortSelectionInverseNow((dbUshort*)theFld); break;
1149  case shortField: SortSelectionInverseNow((dbShort*)theFld); break;
1150  case uLongField: SortSelectionInverseNow((dbUlong*)theFld); break;
1151  case longField: SortSelectionInverseNow((dbLong*)theFld); break;
1152  case dateTimeField: SortSelectionInverseNow((dbUlong*)theFld); break;
1153  case dateField: SortSelectionInverseNow((dbUlong*)theFld); break;
1154  case timeField: SortSelectionInverseNow((dbLong*)theFld); break;
1155  case realField: SortSelectionInverseNow((dbReal*)theFld); break;
1156  case charField: SortSelectionInverseNow((dbChar*)theFld); break;
1157  case textField: SortSelectionInverseNow((dbText*)theFld); break;
1158 
1159  case compoundField:
1160  {
1161  dbCompoundField* sortingBy = (dbCompoundField*)theFld; // safe downcast
1162  dbSorter temp(*sortingBy); // both descend from OOF_FieldSegOwner so can copy construct
1164  sortSelectionNow(&temp);
1165  return; // EARLY EXIT - recursive call has already done the following
1166  }
1167  break;
1168 
1169  case fixedBinaryField: {
1170  unsigned long fixedLength = theFld->fieldStorageLen();
1171  // NOT YET IMPLEMENTED - cope with 4-byte fields as special case
1172  if (fixedLength>3)
1173  SortSelectionInverseNow(theFld, fixedLength);
1174  else { // NOT YET IMPLEMENTED - cope with 2-byte fields with uShort sorter
1175  dbConnect::raise(stringstream() << flush
1176  << "Unable to Sort by field" << theFld->fieldName()
1177  << " SortSelectionInverseNow is not defined on fields of type"
1178  << theFld->fieldType() << " < 4 bytes long",
1179  false /* don't terminate */
1180  );
1181  }
1182  }
1183  break;
1184 
1185  default:
1186  dbConnect::raise(stringstream() << flush
1187  << "Unable to Sort by field" << theFld->fieldName()
1188  << " SortSelectionInverseNow is not defined on fields of type"
1189  << theFld->fieldType(),
1190  false /* don't terminate */
1191  );
1192  // NOT YET IMPLEMENTED
1193  ;
1194  }
1195 
1196  assert( Invariant("simpleB::sortSelectionInverseNow-exit") );
1197 }
1198 
1199 void
1201 {
1202  OOF_ULSorter lhs;
1203 
1204  for(start();more();next())
1205  {
1206  lhs.sortedInsert(*theFld, mCurrLoadedRecOffset);
1207  }
1208 
1209  OOF_recordSelection newSelection( mTable->prototype() );
1210  while(!lhs.isEmpty())
1211  newSelection.append(lhs.remove());
1212 
1213  mSelection=newSelection;
1214  start(); // Make sure the selection context is logical before returning.
1215 }
1216 
1217 
1218 void
1220 {
1221  OOF_LSorter lhs;
1222 
1223  for(start();more();next())
1224  {
1225  lhs.sortedInsert(*theFld, mCurrLoadedRecOffset);
1226  }
1227 
1228  OOF_recordSelection newSelection( mTable->prototype() );
1229  while(!lhs.isEmpty())
1230  newSelection.append(lhs.remove());
1231 
1232  mSelection=newSelection;
1233  start(); // Make sure the selection context is logical before returning.
1234 }
1235 
1236 
1238 {
1239 
1240  OOF_ULSorter lhs;
1241 
1242  for(start();more();next())
1243  {
1244  lhs.sortedInsert(*theFld, mCurrLoadedRecOffset);
1245  }
1246 
1247  OOF_recordSelection newSelection( mTable->prototype() );
1248  while(!lhs.isEmpty())
1249  newSelection.append(lhs.remove());
1250 
1251  mSelection=newSelection;
1252  start(); // Make sure the selection context is logical before returning.
1253 }
1254 
1255 
1256 void
1258 {
1259  OOF_LSorter lhs;
1260 
1261  for(start();more();next())
1262  {
1263  lhs.sortedInsert(*theFld, mCurrLoadedRecOffset);
1264  }
1265 
1266  OOF_recordSelection newSelection( mTable->prototype() );
1267  while(!lhs.isEmpty())
1268  newSelection.append(lhs.remove());
1269 
1270  mSelection=newSelection;
1271  start(); // Make sure the selection context is logical before returning.
1272 }
1273 
1274 
1275 void
1277 {
1278  OOF_DSorter lhs;
1279 
1280  for(start();more();next())
1281  {
1282  lhs.sortedInsert(*theFld, mCurrLoadedRecOffset);
1283  }
1284 
1285  OOF_recordSelection newSelection( mTable->prototype() );
1286  while(!lhs.isEmpty())
1287  newSelection.append(lhs.remove());
1288 
1289  mSelection=newSelection;
1290  start(); // Make sure the selection context is logical before returning.
1291 }
1292 
1293 
1297 void
1299 {
1300  OOF_ULSorter lhs;
1301  unsigned long FirstFour;
1302 
1303  if (mDirtyRecordCache && mDirtyRecordCache->count()>0) {
1304  if (mSelection.state() == OOF_recordSelection::allRecs) {
1305  // case one: all records selected with bufferforever and dirty record cache
1306 
1307  unsigned long currentIterator = 0;
1308  oofString compareField;
1309 
1310  for(start();more();next()){
1311  OOF_copyFirstFour(&FirstFour,*theFld);
1312  lhs.sortedInsert(FirstFour, mCurrLoadedRecOffset);
1313  bool doneFirstSwap = false;
1314  while(lhs.lastEqual()) {
1315  if(!doneFirstSwap){
1316  compareField = theFld->asChars(); // save before we lose selection!
1317  doneFirstSwap = true;
1318  currentIterator = mSelection.iter();// thats all the context we need as we know we are in select all
1319  }
1320  selectJustOID(lhs.theEqual()->mNext->mData); // have corrupteed selection to selectone
1321  if(OOF_stricmp(compareField,*theFld )>0)
1322  lhs.exchange(lhs.theEqual());
1323  else
1324  break;
1325  } // loop looking for differences beyond first four bytes
1326  if(doneFirstSwap){
1327  selectAll();
1328  gotoRecord(currentIterator); // but id does indicate we have been throught the loop at least once
1329  }
1330  }// sort loop
1331  }
1332  else{ // NOT allRecs but still dirty cache
1333 
1334  // Case two: some records selected with bufferforever and dirty record cache
1335 
1336  OOF_recordSelection snapshot(mSelection); // declare this temp outside the loop!
1337  const long numRecords = snapshot.count();
1338  oofString compareField;
1339 
1340  for(long i=0; i<numRecords; i++){
1341  selectJustOID(snapshot.value(i));
1342  OOF_copyFirstFour(&FirstFour,*theFld);
1343  lhs.sortedInsert(FirstFour, mCurrLoadedRecOffset);
1344  compareField = theFld->asChars(); // save before we lose selection!//david debug 000309
1345  while(lhs.lastEqual()) {
1346  selectJustOID(lhs.theEqual()->mNext->mData);
1347  if(OOF_stricmp(compareField,*theFld )>0)
1348  lhs.exchange(lhs.theEqual());
1349  else
1350  break;
1351  } // loop looking for differences beyond first four bytes
1352  } // sort loop
1353  }
1354  } // all vs some records
1355  else { // original - use if no dirty records
1356  // NOT YET IMPLEMENTED - probably faster to use case 2 above even if no
1357  // dirty records - preserving original here to isolate impact of change
1358  // but later review performance
1359  dbTable* compareTable = theFld->fieldTable()->cloneTableWithoutSelection();
1360  dbChar* compareField = (dbChar*)compareTable->field(theFld->fieldNumber());
1361 
1362  for(start();more();next()) {
1363  FirstFour = 0;
1364  OOF_copyFirstFour(&FirstFour,*theFld);
1365  lhs.sortedInsert(FirstFour, mCurrLoadedRecOffset);
1366  while(lhs.lastEqual()) {
1367  // Load the matching record into compareField
1368  compareTable->selectJustOID(lhs.theEqual()->mNext->mData);
1369  if(OOF_stricmp(*theFld,*compareField)>0)
1370  lhs.exchange(lhs.theEqual());
1371  else
1372  break;
1373  }
1374  } // sort loop
1375  delete compareTable;
1376  } // has dirty cache
1377 
1378  OOF_recordSelection newSelection( mTable->prototype() );
1379  while(!lhs.isEmpty())
1380  newSelection.append(lhs.remove());
1381 
1382  mSelection=newSelection;
1383  start(); // Make sure the selection context is logical before returning.
1384 }
1385 
1386 
1387 void
1389 {
1390  OOF_ULSorter lhs;
1391  dbTable* compareTable = theFld->fieldTable()->cloneTableWithoutSelection();
1392  dbText* compareField = (dbText *)compareTable->field(theFld->fieldNumber());
1393 
1394  for(start();more();next())
1395  {
1396  theFld->reset();
1397  unsigned long FirstFour = 0;
1398  OOF_copyFirstFour(&FirstFour,*theFld);
1399  lhs.sortedInsert(FirstFour, mCurrLoadedRecOffset);
1400  while(lhs.lastEqual()) {
1401  // Load the matching record into compareField
1402  compareTable->selectJustOID(lhs.theEqual()->mNext->mData);
1403  if(OOF_stricmp(*theFld,*compareField)>0)
1404  lhs.exchange(lhs.theEqual());
1405  else
1406  break;
1407  }
1408  }
1409 
1410  OOF_recordSelection newSelection( mTable->prototype() );
1411  while(!lhs.isEmpty())
1412  newSelection.append(lhs.remove());
1413 
1414  delete compareTable;
1415  mSelection=newSelection;
1416  start(); // Make sure the selection context is logical before returning.
1417 }
1418 
1419 
1427 void
1428 OOF_simpleRecordBackend::SortSelectionNow(const dbField* theFld, unsigned long fixedBinaryLength)
1429 {
1430  assert("not yet reimplemented");
1431 #if 0
1432 // sort any arbitrary binary data of given length
1433  assert(fixedBinaryLength>3);
1434 
1435  OOF_ULSorter lhs;
1436  dbTable* compareTable = theFld->fieldTable()->cloneTableWithoutSelection();
1437  dbField* compareField = compareTable->field(theFld->fieldNumber());
1438 
1439  for(start();more();next())
1440  {
1441  unsigned long FirstFour = 0;
1442  const char* s1 = (const char*) theFld->binaryContents();
1443  OOF_copyFirstFour(&FirstFour,s1);
1444  lhs.sortedInsert(FirstFour, mCurrLoadedRecOffset);
1445  while(lhs.lastEqual()) {
1446  // Load the matching record into compareField
1447  compareTable->selectJustOID(lhs.theEqual()->mNext->mData);
1448 
1449  // direct binary compare
1450  const char* s2 = (const char*) compareField->binaryContents();
1451  unsigned long i;
1452  for (i=0; (i<fixedBinaryLength) && (s1[i]==s2[i]); ++i)
1453  ;
1454  if(s1[i]>s2[i])
1455  lhs.exchange(lhs.theEqual());
1456  else
1457  break;
1458  }
1459  }
1460 
1461  OOF_recordSelection newSelection( mTable->prototype() );
1462  while(!lhs.isEmpty())
1463  newSelection.append(lhs.remove());
1464 
1465  delete compareTable;
1466  mSelection=newSelection;
1467  start(); // Make sure the selection context is logical before returning.
1468 #endif
1469 }
1470 
1471 
1472 void
1474 {
1475  OOF_ULSorter lhs;
1476 
1477  for(start();more();next())
1478  {
1479  lhs.sortedInsertReverse(*theFld, mCurrLoadedRecOffset);
1480  }
1481 
1482  OOF_recordSelection newSelection( mTable->prototype() );
1483  while(!lhs.isEmpty())
1484  newSelection.append(lhs.remove());
1485 
1486  mSelection=newSelection;
1487  start(); // Make sure the selection context is logical before returning.
1488 }
1489 
1490 
1491 void
1493 {
1494  OOF_LSorter lhs;
1495 
1496  for(start();more();next())
1497  {
1498  lhs.sortedInsertReverse(*theFld, mCurrLoadedRecOffset);
1499  }
1500 
1501  OOF_recordSelection newSelection( mTable->prototype() );
1502  while(!lhs.isEmpty())
1503  newSelection.append(lhs.remove());
1504 
1505  mSelection=newSelection;
1506  start(); // Make sure the selection context is logical before returning.
1507 }
1508 
1509 
1511 {
1512  OOF_ULSorter lhs;
1513 
1514  for(start();more();next())
1515  {
1516  lhs.sortedInsertReverse(*theFld, mCurrLoadedRecOffset);
1517  }
1518 
1519  OOF_recordSelection newSelection( mTable->prototype() );
1520  while(!lhs.isEmpty())
1521  newSelection.append(lhs.remove());
1522 
1523  mSelection=newSelection;
1524  start(); // Make sure the selection context is logical before returning.
1525 }
1526 
1527 
1528 void
1530 {
1531  OOF_LSorter lhs;
1532 
1533  for(start();more();next())
1534  {
1535  lhs.sortedInsertReverse(*theFld, mCurrLoadedRecOffset);
1536  }
1537 
1538  OOF_recordSelection newSelection( mTable->prototype() );
1539  while(!lhs.isEmpty())
1540  newSelection.append(lhs.remove());
1541 
1542  mSelection=newSelection;
1543  start(); // Make sure the selection context is logical before returning.
1544 }
1545 
1546 
1547 void
1549 {
1550  OOF_DSorter lhs;
1551 
1552  for(start();more();next())
1553  {
1554  lhs.sortedInsertReverse(*theFld, mCurrLoadedRecOffset);
1555  }
1556 
1557  OOF_recordSelection newSelection( mTable->prototype() );
1558  while(!lhs.isEmpty())
1559  newSelection.append(lhs.remove());
1560 
1561  mSelection=newSelection;
1562  start(); // Make sure the selection context is logical before returning.
1563 }
1564 
1565 
1569 void
1571 {
1572  OOF_ULSorter lhs;
1573  unsigned long FirstFour;
1574 
1575  if (mDirtyRecordCache && mDirtyRecordCache->count()>0) {
1576  if(mSelection.state() == OOF_recordSelection::allRecs ){
1577 
1578  unsigned long currentIterator = 0;
1579  oofString compareField;
1580 
1581  for(start();more();next()){
1582  OOF_copyFirstFour(&FirstFour,*theFld);
1583  lhs.sortedInsertReverse(FirstFour, mCurrLoadedRecOffset);
1584  bool doneFirstSwap = false;
1585  while(lhs.lastEqual()) {
1586  if(!doneFirstSwap){
1587  compareField = theFld->asChars(); // save before we lose selection!
1588  doneFirstSwap = true;
1589  currentIterator = mSelection.iter();// that's all the context we need as we know we are in select all
1590  }
1591  selectJustOID(lhs.theEqual()->mNext->mData); // have corrupted selection to selectone
1592  if(OOF_stricmp(compareField,*theFld )<0)
1593  lhs.exchange(lhs.theEqual());
1594  else
1595  break;
1596  } // loop looking for differences beyond first four bytes
1597  if(doneFirstSwap) {
1598  selectAll();
1599  gotoRecord(currentIterator); // but it does indicate we have been through the loop at least once
1600  }
1601  }// sort loop
1602  }
1603  else{
1604  OOF_recordSelection snapshot(mSelection); // declare this temp outside the loop!
1605  const long numRecords = snapshot.count();
1606  oofString compareField;
1607 
1608  for(long i=0; i<numRecords; i++){
1609  selectJustOID(snapshot.value(i)); // replaces start/more/next
1610  OOF_copyFirstFour(&FirstFour,*theFld);
1611  lhs.sortedInsertReverse(FirstFour, mCurrLoadedRecOffset);
1612  bool doneFirstSwap = false;
1613  while(lhs.lastEqual()) {
1614  if(!doneFirstSwap){
1615  compareField = theFld->asChars(); // save before we lose selection!
1616  doneFirstSwap = true;
1617  }
1618  selectJustOID(lhs.theEqual()->mNext->mData);
1619  if(OOF_stricmp(compareField,*theFld )<0) // compareField not deref'd
1620  lhs.exchange(lhs.theEqual());
1621  else
1622  break;
1623  } // loop looking for differences beyond first four bytes
1624  } // sort loop
1625  }
1626  }
1627  else{ // original code if no dirty records
1628  dbTable* compareTable = theFld->fieldTable()->cloneTableWithoutSelection();
1629  dbChar* compareField = (dbChar *)compareTable->field(theFld->fieldNumber());
1630 
1631  for(start();more();next())
1632  {
1633  FirstFour = 0;
1634  OOF_copyFirstFour(&FirstFour,*theFld);
1635  lhs.sortedInsertReverse(FirstFour, mCurrLoadedRecOffset);
1636  while(lhs.lastEqual()) {
1637  // Load the matching record into compareField
1638  compareTable->selectJustOID(lhs.theEqual()->mNext->mData);
1639  if(OOF_stricmp(*theFld,*compareField)<0)
1640  lhs.exchange(lhs.theEqual());
1641  else
1642  break;
1643  }
1644  }
1645  delete compareTable;
1646  }
1647  OOF_recordSelection newSelection( mTable->prototype() );
1648  while(!lhs.isEmpty())
1649  newSelection.append(lhs.remove());
1650 
1651  mSelection=newSelection;
1652  start(); // Make sure the selection context is logical before returning.
1653 }
1654 
1655 
1656 void
1658 {
1659  OOF_ULSorter lhs;
1660  dbTable* compareTable = theFld->fieldTable()->cloneTableWithoutSelection();
1661  dbText* compareField = (dbText *)compareTable->field(theFld->fieldNumber());
1662 
1663  for(start();more();next())
1664  {
1665  theFld->reset();
1666  unsigned long FirstFour = 0;
1667  OOF_copyFirstFour(&FirstFour,*theFld);
1668  lhs.sortedInsertReverse(FirstFour, mCurrLoadedRecOffset);
1669  while(lhs.lastEqual()) {
1670  // Load the matching record into compareField
1671  compareTable->selectJustOID(lhs.theEqual()->mNext->mData);
1672  if(OOF_stricmp(*theFld,*compareField)<0)
1673  lhs.exchange(lhs.theEqual());
1674  else
1675  break;
1676  }
1677  }
1678 
1679  OOF_recordSelection newSelection( mTable->prototype() );
1680  while(!lhs.isEmpty())
1681  newSelection.append(lhs.remove());
1682 
1683  delete compareTable;
1684  mSelection=newSelection;
1685  start(); // Make sure the selection context is logical before returning.
1686 }
1687 
1688 
1694 void
1695 OOF_simpleRecordBackend::SortSelectionInverseNow(const dbField* theFld, unsigned long fixedBinaryLength)
1696 {
1697  assert("not yet reimplemented");
1698 #if 0
1699 // sort any arbitrary binary data of given length
1700  assert(fixedBinaryLength>3);
1701 
1702  OOF_ULSorter lhs;
1703  dbTable* compareTable = theFld->fieldTable()->cloneTableWithoutSelection();
1704  dbField* compareField = compareTable->field(theFld->fieldNumber());
1705 
1706  for(start();more();next())
1707  {
1708  unsigned long FirstFour = 0;
1709  const char* s1 = (const char*) theFld->binaryContents();
1710  OOF_copyFirstFour(&FirstFour,s1);
1711  lhs.sortedInsertReverse(FirstFour, mCurrLoadedRecOffset);
1712  while(lhs.lastEqual()) {
1713  // Load the matching record into compareField
1714  compareTable->selectJustOID(lhs.theEqual()->mNext->mData);
1715 
1716  // direct binary compare
1717  const char* s2 = (const char*) compareField->binaryContents();
1718  unsigned long i;
1719  for (i=0; (i<fixedBinaryLength) && (s1[i]==s2[i]); ++i)
1720  ;
1721  if(s1[i]<s2[i])
1722  lhs.exchange(lhs.theEqual());
1723  else
1724  break;
1725  }
1726  }
1727 
1728  OOF_recordSelection newSelection( mTable->prototype() );
1729  while(!lhs.isEmpty())
1730  newSelection.append(lhs.remove());
1731 
1732  delete compareTable;
1733  mSelection=newSelection;
1734  start(); // Make sure the selection context is logical before returning.
1735 #endif // 0
1736 }
1737 
1738 
1739 void
1741 {
1742  assert( Invariant("simpleB::difference_with-backend-entry") );
1743 
1744  OOF_simpleRecordBackend* theRHS = (OOF_simpleRecordBackend*) rhs; // DANGEROUS downcast - may break if every have other than OOF_simpleRecordBackend as direct subclass of OOF_tableBackend
1745  mSelection.difference_with(theRHS->mSelection); // calls back our invert() in some cases
1746  unloadRecord();
1747 
1748  assert( Invariant("simpleB::difference_with-backend-exit") );
1749 }
1750 
1751 
1752 void
1754 {
1755  assert( Invariant("simpleB::difference_with-entry") );
1756 
1757  mSelection.difference_with( rhs.internalSelection() );
1758  unloadRecord();
1759 
1760  assert( Invariant("simpleB::difference_with-exit") );
1761 }
1762 
1763 
1764 void
1766 {
1767  assert( Invariant("simpleB::intersection_with-tableBackend-entry") );
1768 
1769  OOF_simpleRecordBackend* theRHS = (OOF_simpleRecordBackend*) rhs; // DANGEROUS downcast - may break if every have other than OOF_simpleRecordBackend as direct subclass of OOF_tableBackend
1770  mSelection.intersection_with(theRHS->mSelection);
1771  unloadRecord();
1772 
1773  assert( Invariant("simpleB::intersection_with-tableBackend-exit") );
1774 }
1775 
1776 
1777 
1778 void
1780 {
1781  assert( Invariant("simpleB::intersection_with-dbSelection-entry") );
1782 
1783  mSelection.intersection_with( rhs.internalSelection() );
1784  unloadRecord();
1785 
1786  assert( Invariant("simpleB::intersection_with-dbSelection-exit") );
1787 }
1788 
1789 
1790 void
1792 {
1793  assert( Invariant("simpleB::union_with-tableBackend-entry") );
1794 
1795  OOF_simpleRecordBackend* theRHS = (OOF_simpleRecordBackend*) rhs; // DANGEROUS downcast - may break if every have other than OOF_simpleRecordBackend as direct subclass of OOF_tableBackend
1796  mSelection.union_with(theRHS->mSelection);
1797  unloadRecord();
1798 
1799  assert( Invariant("simpleB::union_with-tableBackend-exit") );
1800 }
1801 
1802 
1803 void
1805 {
1806  assert( Invariant("simpleB::union_with-dbSelection-entry") );
1807 
1808  mSelection.union_with( rhs.internalSelection() );
1809  unloadRecord();
1810 
1811  assert( Invariant("simpleB::union_with-dbSelection-exit") );
1812 }
1813 
1814 
1815 void
1817 {
1818  assert( Invariant("simpleB::union_with_no_overlap-tableBackend-entry") );
1819 
1820  OOF_simpleRecordBackend* theRHS = (OOF_simpleRecordBackend*) rhs; // DANGEROUS downcast - may break if every have other than OOF_simpleRecordBackend as direct subclass of OOF_tableBackend
1821  mSelection.union_with_no_overlap(theRHS->mSelection);
1822  unloadRecord();
1823 
1824  assert( Invariant("simpleB::union_with_no_overlap-tableBackend-exit") );
1825 }
1826 
1827 
1828 void
1830 {
1831  assert( Invariant("simpleB::union_with_no_overlap-dbSelection-entry") );
1832 
1833  mSelection.union_with_no_overlap( rhs.internalSelection() );
1834  unloadRecord();
1835 
1836  assert( Invariant("simpleB::union_with_no_overlap-dbSelection-exit") );
1837 }
1838 
1839 
1840 void
1842 {
1843  assert( Invariant("simpleB::invert-entry") );
1844 
1845  switch(mSelection.state())
1846  {
1848  mSelection.selectAll();
1849  break;
1850 
1852  mSelection.selectNone();
1853  break;
1854 
1857 // This is necessarily iterative and yucky...
1858 // Loading the selection into a tree and doing member checks on that would
1859 // be much faster..
1860 
1861 // This also leaves the record pointer in an undefined state WRT the current selection
1862 
1863  OOF_List* theInversion = new OOF_List();
1864  // Save our current selection
1865  OOF_recordSelection savedSelection = mSelection;
1866  // Turn off sorting
1867  dbSorter* currentSorter = sorter();
1868  if (currentSorter)
1869  currentSorter->suspendSorting();
1870  selectAll();
1871 
1872  for(start();more();next())
1873  if(!savedSelection.contains(mCurrLoadedRecOffset))
1874  theInversion->append(mCurrLoadedRecOffset);
1875 
1876  switch(theInversion->count()) // Copy the tree back into a Selection
1877  {
1878  case 0:
1879  mSelection.selectNone();
1880  break;
1881  case 1:
1882  mSelection.selectOneRec(theInversion->remove());
1883  break;
1884  default: {
1885  OOF_recordSelection newSelection(OOF_recordSelection::someRecs, theInversion->count(), mTable->prototype());
1886  while (!theInversion->isEmpty())
1887  newSelection.append(theInversion->remove());
1888  mSelection = newSelection;
1889  break;
1890  }
1891  }
1892  delete theInversion;
1893 
1894  if (currentSorter)
1895  currentSorter->resumeSorting();
1896  break;
1897  }
1898 
1899  assert( Invariant("simpleB::invert - end, prior unloadRecord") );
1900  unloadRecord();
1901 
1902  assert( Invariant("simpleB::invert-exit") );
1903 }
1904 
1905 
1906 // -------------------------------------------------------
1907 // O O F _ S e l e c t i o n
1908 // see also oofctre5.cpp
1909 // -------------------------------------------------------
1910 void
1912 {
1913  // This one would especially benefit from a tree because of many calls to member
1914 
1915  switch(rhs.state()) // Branch on RHS State
1916  {
1917  case empty:
1918  break;
1919 
1920  case oneRec:
1921  switch(state()) // What we do depends on LHS as well
1922  {
1923  case empty:
1924  break;
1925 
1926  case oneRec:
1927  if(contains(rhs.oneRecOffset()))
1928  selectNone();
1929  break;
1930 
1931  case someRecs: {
1932  unsigned long numLHS = count();
1933  OOF_List* theDifference = new OOF_List();
1934  // Copy the ones in the lhs that don't match the rhs item
1935  for (unsigned long i=0; i<numLHS; i++) {
1936  unsigned long current = value(i);
1937  if(!rhs.contains(current))
1938  theDifference->append(current);
1939  }
1940  switch(theDifference->count()) // Copy the tree back into a Selection
1941  {
1942  case 0:
1943  selectNone();
1944  break;
1945  case 1:
1946  selectOneRec(theDifference->remove());
1947  break;
1948  default: {
1949  OOF_recordSelection newSelection(someRecs, theDifference->count(), mPrototypicalTable);
1950  while (!theDifference->isEmpty())
1951  newSelection.append(theDifference->remove());
1952  *this = newSelection;
1953  }
1954  }
1955  delete theDifference;
1956  break;
1957  }
1958 
1959  case allRecs:
1960  selectOneRec(rhs.oneRecOffset());
1961  invert(); // Copy the RHS to the LHS and invert
1962  break;
1963  }
1964  break;
1965 
1966  case someRecs:
1967  switch(state()) // What we do depends on A as well
1968  {
1969  case empty:
1970  break;
1971 
1972  case oneRec:
1973  if(rhs.contains(oneRecOffset()))
1974  selectNone();
1975  break;
1976 
1977  case someRecs: {
1978  OOF_List* theDifference = new OOF_List();
1979  unsigned long numLHS = count();
1980 
1981 // This commented chunk will be better when the list class is not just a LL...
1982 
1983 /* OOF_List* theRHSlist = new OOF_List();
1984  rhs.start(); // Put the rhs into a list
1985  while (mSelection.more()) {
1986  theRHSlist->append(rhs()); // Don't sort - just bung 'em in
1987  next();
1988  }
1989 */
1990  // Copy the ones in the lhs that aren't in the rhs
1991  for (unsigned long i=0; i<numLHS; i++) {
1992  unsigned long current = value(i);
1993  if(!rhs.contains(current))
1994  theDifference->append(current);
1995  }
1996 
1997  switch(theDifference->count()) // Copy the tree back into a Selection
1998  {
1999  case 0:
2000  selectNone();
2001  break;
2002  case 1:
2003  selectOneRec(theDifference->remove());
2004  break;
2005  default: {
2006  OOF_recordSelection newSelection(someRecs, theDifference->count(), mPrototypicalTable);
2007  while (!theDifference->isEmpty())
2008  newSelection.append(theDifference->remove());
2009  *this = newSelection;
2010  }
2011  }
2012  delete theDifference;
2013 /* delete therhsList; */ // See Above
2014  break;
2015  }
2016 
2017  case allRecs: { // Copy the RHS to the LHS and invert
2018  unsigned long numRHS = rhs.count();
2019  OOF_recordSelection newSelection(someRecs, numRHS, mPrototypicalTable);
2020  for (unsigned long i=0; i<numRHS; i++)
2021  newSelection.append(rhs.value(i));
2022  *this = newSelection;
2023  invert();
2024  break;
2025  }
2026  }
2027  break;
2028 
2029  case allRecs:
2030  selectNone();
2031  break;
2032  }
2033 }
2034 
2035 
2036 
2037 void
2039 {
2040  intersection_with(*(OOF_recordSelection*)rhs); // DANGEROUS downcast - may break if every have other than OOF_RecordSelection
2041 }
2042 
2043 
2044 void
2046 {
2047  difference_with(*(OOF_recordSelection*)rhs); // DANGEROUS downcast - may break if every have other than OOF_simpleRecordBackend as direct subclass of OOF_tableBackend
2048 }
2049 
2050 
2051 void
2053 {
2054  switch(state()) // What we do depends on LHS as well
2055  {
2056  case empty:
2057  break;
2058 
2059  case oneRec:
2060  if(!contains(rhsOffset))
2061  selectNone();
2062  break;
2063 
2064  case someRecs:
2065  if(!contains(rhsOffset)) {
2066  selectNone();
2067  }
2068  else {
2069  selectOneRec(rhsOffset);
2070  }
2071  break;
2072 
2073  case allRecs:
2074  selectOneRec(rhsOffset);
2075  break;
2076  }
2077 }
2078 
2079 
2080 void
2082 {
2083  // This one would especially benefit from a tree because of many calls to member
2084  switch(rhs.state()) // Branch on RHS State
2085  {
2086  case empty:
2087  selectNone();
2088  break;
2089 
2090  case oneRec:
2091  switch(state()) // What we do depends on LHS as well
2092  {
2093  case empty:
2094  break;
2095 
2096  case oneRec:
2097  if(!contains(rhs.oneRecOffset()))
2098  selectNone();
2099  break;
2100 
2101  case someRecs:
2102  if(!contains(rhs.oneRecOffset())) {
2103  selectNone();
2104  }
2105  else {
2106  selectOneRec(rhs.oneRecOffset());
2107  }
2108  break;
2109 
2110  case allRecs:
2111  copyContents(rhs);
2112  break;
2113  }
2114  break;
2115 
2116  case someRecs: // rhs
2117  switch(state()) // What we do depends on A as well
2118  {
2119  case empty:
2120  break;
2121 
2122  case oneRec:
2123  if(!rhs.contains(oneRecOffset()))
2124  selectNone();
2125  break;
2126 
2127  case someRecs: {
2128  OOF_List* theIntersection = new OOF_List();
2129  unsigned long numRHS = rhs.count();
2130 
2131 // This commented chunk will be better when the list class is not just a LL...
2132 
2133 /* OOF_List* thelhs = new OOF_List();
2134  mSelection.start(); // Put the lhs into a list
2135  while (mSelection.more()) {
2136  thelhs->append(mSelection()); // Don't sort - just bung 'em in
2137  mSelection.next();
2138  }
2139 */
2140  // Copy the ones that are in both to a new list
2141  for (unsigned long i=0; i<numRHS; i++) {
2142 /* if(thelhs->member(theRhs->mSelection()))*/ // See above
2143  unsigned long rhsCurrent = rhs.value(i);
2144  if (contains(rhsCurrent))
2145  theIntersection->append(rhsCurrent);
2146  }
2147  switch(theIntersection->count()) // Copy the tree back into a Selection
2148  {
2149  case 0:
2150  selectNone();
2151  break;
2152  case 1:
2153  selectOneRec(theIntersection->remove());
2154  break;
2155  default: {
2156  OOF_recordSelection newSelection(someRecs, theIntersection->count(), mPrototypicalTable);
2157  while (!theIntersection->isEmpty())
2158  newSelection.append(theIntersection->remove());
2159  *this = newSelection;
2160  }
2161  }
2162  delete theIntersection;
2163 /* delete thelhs;*/ // See above
2164  break;
2165  }
2166 
2167  case allRecs: {
2168  copyContents(rhs);
2169  break;
2170  }
2171  }
2172  break;
2173 
2174  case allRecs: // rhs
2175  break;
2176  }
2177 }
2178 
2179 
2180 void
2182 {
2183  union_with(*(OOF_recordSelection*)rhs); // DANGEROUS downcast - may break if every have other than OOF_RecordSelection
2184 }
2185 
2186 
2190 void
2192 {
2193  if(!contains(rhsOffset))
2194  {
2195  switch(state()) // What we do depends on LHS as well
2196  {
2197  case empty:
2198  selectOneRec(rhsOffset);
2199  break;
2200 
2201  case oneRec: {
2202  OOF_recordSelection newSelection(someRecs, 2, mPrototypicalTable);
2203  newSelection.append(oneRecOffset());
2204  newSelection.append(rhsOffset);
2205 
2206  *this = newSelection;
2207  break;
2208  }
2209 
2210  case someRecs:
2211  append(rhsOffset);
2212  break;
2213 
2214  case allRecs:
2215  break;
2216  }
2217  }
2218 }
2219 
2220 
2225 void
2227 {
2228  switch(rhs.state()) // Branch on RHS State
2229  {
2230  case empty:
2231 
2232  break; // If B is empty then A = A + B returns A !
2233 
2234  case oneRec:
2235  if(!contains(rhs.oneRecOffset()))
2236  {
2237  switch(state()) // What we do depends on LHS as well
2238  {
2239  case empty:
2240  selectOneRec(rhs.oneRecOffset());
2241  break;
2242 
2243  case oneRec: {
2244  OOF_recordSelection newSelection(someRecs, 2, mPrototypicalTable);
2245  newSelection.append(rhs.oneRecOffset());
2246  newSelection.append(oneRecOffset());
2247 
2248  *this = newSelection; // getting the someRecs state created above
2249  break;
2250  }
2251 
2252  case someRecs:
2253  append(rhs.oneRecOffset());
2254  break;
2255 
2256  case allRecs:
2257  break;
2258  }
2259  }
2260  break;
2261 
2262  case someRecs: {
2263  unsigned long numRHS = rhs.count();
2264  switch(state()) // What we do depends on A as well
2265  {
2266  case empty: {
2267  OOF_recordSelection newSelection(someRecs, numRHS, mPrototypicalTable);
2268  for (unsigned long i=0; i<numRHS; i++)
2269  newSelection.append(rhs.value(i));
2270  *this = newSelection;
2271  break;
2272  }
2273 
2274  case oneRec: {
2275  bool Copied = false;
2276  OOF_recordSelection newSelection(someRecs, numRHS, mPrototypicalTable);
2277  for (unsigned long i=0; i<numRHS; i++) {
2278  newSelection.append(rhs.value(i));
2279  Copied = (Copied || (rhs.value(i) == oneRecOffset()) );
2280  }
2281  if(!Copied)
2282  newSelection.append(oneRecOffset());
2283 /* NOT YET IMPLEMENTED
2284  if (newSelection.count()==NbrOfRecords(mISAMdatno)) {
2285  selectAll();
2286  } else {
2287  mSelection = newSelection;
2288  }
2289 */
2290  *this = newSelection;
2291  break;
2292  }
2293 
2294  case someRecs: {
2295  unsigned long numLHS = count();
2296  OOF_List* theUnion = new OOF_List();
2297  // Sort the LHS
2298  {
2299  for (unsigned long i=0; i<numLHS; i++)
2300  theUnion->sortedInsert(value(i));
2301  }
2302  {
2303  for (unsigned long j=0; j<numRHS; j++)// Insert the RHS ignoring duplicates
2304  theUnion->sortedInsertNoDups(rhs.value(j));
2305  }
2306  OOF_recordSelection newSelection(someRecs, numRHS, mPrototypicalTable);
2307  while (!theUnion->isEmpty())
2308  newSelection.append(theUnion->remove()); // Copy the tree back into a Selection
2309  delete theUnion;
2310 // NOT YET IMPLEMENTED - work out if we have now produced a selection of all recs
2311 // and change state accordingly (was in original OOF_ctreeBackend version as below)
2312 /*
2313  if (newSelection.count()==NbrOfRecords(mISAMdatno)) {
2314  selectAll();
2315  } else {
2316  mSelection = newSelection;
2317  }
2318 */
2319  *this = newSelection;
2320  break;
2321  }
2322 
2323  case allRecs:
2324  break;
2325  }
2326  break;
2327  }
2328 
2329  case allRecs: // in rhs
2330  selectAll();
2331  break;
2332  }
2333 }
2334 
2335 
2336 void
2338 {
2339  union_with_no_overlap(*(OOF_recordSelection*)rhs); // DANGEROUS downcast - may break if every have other than OOF_RecordSelection
2340 }
2341 
2342 
2350 void
2352 {
2353  switch(rhs.state()) // Branch on RHS State
2354  {
2355  case empty:
2356 
2357  break; // If B is empty then A = A + B returns A !
2358 
2359  case oneRec:
2360  {
2361  switch(state()) // What we do depends on LHS as well
2362  {
2363  case empty:
2364  selectOneRec(rhs.oneRecOffset());
2365  break;
2366 
2367  case oneRec: {
2368  OOF_recordSelection newSelection(someRecs, 2, mPrototypicalTable);
2369  newSelection.append(rhs.oneRecOffset());
2370  newSelection.append(oneRecOffset());
2371 
2372  *this = newSelection; // getting the someRecs state created above
2373  break;
2374  }
2375 
2376  case someRecs:
2377  append(rhs.oneRecOffset());
2378  break;
2379 
2380  case allRecs:
2381  break;
2382  }
2383  }
2384  break;
2385 
2386  case someRecs: {
2387  unsigned long numRHS = rhs.count();
2388  switch(state()) // What we do depends on A as well
2389  {
2390  case empty: {
2391  OOF_recordSelection newSelection(someRecs, numRHS, mPrototypicalTable);
2392  for (unsigned long i=0; i<numRHS; i++)
2393  newSelection.append(rhs.value(i));
2394  *this = newSelection;
2395  break;
2396  }
2397 
2398  case oneRec: {
2399  bool Copied = false;
2400  OOF_recordSelection newSelection(someRecs, numRHS+1, mPrototypicalTable);
2401  for (unsigned long i=0; i<numRHS; i++) {
2402  newSelection.append(rhs.value(i));
2403  }
2404  newSelection.append(oneRecOffset()); // append our single after blind copy loop
2405  *this = newSelection;
2406  break;
2407  }
2408 
2409  case someRecs: {
2410  unsigned long numLHS = count();
2411  expandToInclude(numRHS+numLHS);
2412  for (unsigned long i=0; i<numRHS; i++) {
2413  append(rhs.value(i));
2414  }
2415  break;
2416  }
2417 
2418  case allRecs:
2419  break;
2420  }
2421  break;
2422  }
2423 
2424  case allRecs: // in rhs
2425  selectAll();
2426  break;
2427  }
2428 }
2429 
2430 
2431 void
2433 {
2434  assert(mPrototypicalTable); // no business calling this on uninitialised selection!
2435  dbTable* tempTable = mPrototypicalTable->cloneTableWithoutSelection();
2436  tempTable->setSelection(this);
2437  tempTable->invert();
2438  OOF_recordSelection* newSel = (OOF_recordSelection*) tempTable->currentSelection().internalSelection(); // DANGEROUS downcast if ever other sel types
2439  // but still reasonably safe - we've just created the bloody thing anyway and it's our prototypical table, so should
2440  // be compatible with me!
2441 
2442  *this = *newSel;
2443  delete tempTable;
2444 }
2445 
virtual void union_with_no_overlap(const OOF_tableBackend *)=0
void SubSort(const dbSorter *theSorter, const unsigned long level, unsigned long *theData, const unsigned long count)
Now we're sorting at the recursive level of partitioning in a nested sort !
Definition: oofrec2.cpp:602
unsigned long mData
Definition: ooflist.h:118
Persistent field used to store a double.
Definition: oof4.h:521
void sortedInsert(double theItem, unsigned long theData)
Definition: ooflist.cpp:509
virtual unsigned long remove()
Definition: ooflist.cpp:585
Sortable list of doubles.
Definition: ooflist.h:230
static void raise(std::ostream &, bool terminateAfterMsg=true)
void sortedInsertReverse(unsigned long theItem, unsigned long theData)
Put item into list sorted.
Definition: ooflist.cpp:318
void sortedInsertReverse(long theItem, unsigned long theData)
Definition: ooflist.cpp:818
fieldNumT fieldNumber() const
Definition: oof3.h:754
virtual const oofString & fieldName() const
Definition: oof3.h:769
precompilation header.
virtual unsigned long remove()
Take item off the front of the list.
Definition: ooflist.cpp:231
virtual void invert()
Definition: oofrec2.cpp:1841
virtual bool contains(oidT) const
Definition: oofrecs.h:860
Tries to hide the different platforms and version issues with standard IO.
virtual unsigned short countSegments() const
Definition: oof1.h:2577
bool isEmpty()
Definition: ooflist.h:44
void sortedInsert(unsigned long theItem, unsigned long theData)
Definition: ooflist.cpp:263
Envelope class to contain an abstract selection apart from its dbTable.
Definition: oof1.h:316
fieldNumT fieldNumberOfSegment(unsigned int) const
Definition: oof1.cpp:2854
virtual void intersection_with(const OOF_tableBackend *)
Definition: oofrec2.cpp:1765
virtual void union_with_no_overlap(const OOF_tableBackend *)
Definition: oofrec2.cpp:1816
void sortedInsertReverse(unsigned long theItem, unsigned long theData)
Definition: ooflist.cpp:674
abstract base for public interface to selections.
Definition: oof2.h:107
Default list.
Definition: ooflist.h:77
unsigned long mData
Definition: ooflist.h:271
virtual unsigned long fieldStorageLen() const =0
OOF_LPSorterElement * theFirst()
Definition: ooflist.h:352
Definition: oof3.h:26
OOF_recordSelection mSelection
Definition: oofrecs.h:560
void append(oidT)
Definition: oofrecs.h:1020
Sortable list of doubles with partitioning for nested sorts.
Definition: ooflist.h:393
int OOF_stricmp(const char *, const char *)
Compare strings ignoring case.
Definition: oofstr.cpp:59
void reset() const
Definition: oof3.h:878
void SortSelectionInverseNow(const dbUlong *theFld)
Definition: oofrec2.cpp:1473
bool lastEqual()
Definition: ooflist.h:145
virtual void sortSelectionInverseNow(fieldNumT)
Definition: oofrec2.cpp:1131
unsigned long oneRecOffset() const
Definition: oofrecs.h:924
virtual void union_with(const OOF_tableBackend *)
Definition: oofrec2.cpp:1791
bool isReversed() const
Definition: oof3.h:958
Persistent field used to store an unsigned short.
Definition: oof4.h:317
unsigned short mPart
Definition: ooflist.h:333
const OOF_Selection * internalSelection() const
Definition: oof2.h:317
virtual void union_with_no_overlap(const OOF_Selection *)
Definition: oofrec2.cpp:2337
Main implementation parent for backends following the record-oriented model.
Definition: oofrecs.h:295
bool lastEqual()
Definition: ooflist.h:299
void append(unsigned long theItem)
Put item at the end of the list.
Definition: ooflist.cpp:42
void toggleSegmentReversedFlags()
Definition: oof1.cpp:2877
void sortedInsert(long theItem, unsigned long theData)
Definition: ooflist.cpp:415
virtual void difference_with(const OOF_tableBackend *)=0
void sortedInsert(unsigned long theItem, unsigned long theData)
Definition: ooflist.cpp:617
Definition: oof3.h:26
OOF_ULSorterElement * mNext
Definition: ooflist.h:113
virtual void union_with(const OOF_tableBackend *)=0
virtual unsigned long count() const
Definition: oofrecs.h:853
void exchange(OOF_ULPSorterElement *theItem)
Definition: ooflist.cpp:720
virtual const char * asChars() const
Definition: oof3.cpp:944
Selection of records in context of a single dbTable instance.
Definition: oofrecs.h:173
Definition: oof3.h:26
unsigned long oidT
type we pass around pretending we have a real OID.
Definition: oof1.h:229
Abstract interface to database backend.
Definition: oof1.h:1047
virtual void difference_with(const OOF_Selection *)
Definition: oofrec2.cpp:2045
Sortable list of unsigned longs with partitioning for nested sorts.
Definition: ooflist.h:280
OOF_ULSorterElement * theEqual()
Definition: ooflist.h:146
void OOF_copyFirstFour(unsigned long *dest, const char *input)
OOF_simpleRecordBackend
Definition: oofrec2.cpp:52
Persistent field used to store a date and time.
Definition: oof4.h:929
virtual void union_with(const OOF_Selection *)
Definition: oofrec2.cpp:2181
Persistent field used to store a fixed-length string.
Definition: oof3.h:255
dbSelection currentSelection()
Definition: oof1.cpp:2674
Specify sort order by one more fields.
Definition: oof1.h:1277
void setSelection(const dbSelection &)
Definition: oof1.cpp:2725
virtual unsigned long remove()
Definition: ooflist.cpp:861
void resumeSorting()
Definition: oof1.cpp:3031
Exception for unclassified use when nothing else is better.
Definition: oofexcep.h:325
unsigned short mPart
Definition: ooflist.h:385
#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
OOF_DPSorterElement * theFirst()
Definition: ooflist.h:404
dbField * field(fieldNumT) const
Definition: oof1.h:2355
OOF_ULPSorterElement * theFirst()
Definition: ooflist.h:301
Persistent field used to store a set of segments referring to other fields.
Definition: oof3.h:575
virtual dbTable * cloneTableWithoutSelection() const
Definition: oof1.cpp:1423
unsigned short fieldNumT
Definition: oof1.h:276
void sortedInsert(long theItem, unsigned long theData)
Definition: ooflist.cpp:776
virtual unsigned long remove()
Definition: ooflist.cpp:751
unsigned short mPart
Definition: ooflist.h:272
Base class for persistent tables.
Definition: oof1.h:452
void SortSelectionNow(const dbUlong *theFld)
Definition: oofrec2.cpp:1200
Definition: oof3.h:26
dbTable * fieldTable() const
Definition: oof3.cpp:308
Persistent field used to store a date.
Definition: oof4.h:577
Definition: oof3.h:26
Portable highly capable string class.
Definition: oofstr.h:101
Definition: oof3.h:26
Sortable list of longs.
Definition: ooflist.h:184
Sortable list of longs with partitioning for nested sorts.
Definition: ooflist.h:341
void sortedInsertNoDups(unsigned long theItem)
Put item into list sorted only if not already there.
Definition: ooflist.cpp:179
Persistent field used to store a short.
Definition: oof4.h:272
Persistent field used to store a time without date.
Definition: oof4.h:751
virtual void intersection_with(const OOF_Selection *)
Definition: oofrec2.cpp:2038
OOF_ULPSorterElement * theEqual()
Definition: ooflist.h:300
void invert()
Definition: oof1.cpp:2595
Persistent field used to store a variable length string.
Definition: oof3.h:459
virtual unsigned long remove()
Take item off the front of the list.
Definition: ooflist.cpp:90
void sortedInsert(unsigned long theItem)
Put item into list sorted.
Definition: ooflist.cpp:139
virtual void difference_with(const OOF_tableBackend *)
Definition: oofrec2.cpp:1740
virtual oofString copyString() const
Definition: oof3.cpp:472
OOF_ULPSorterElement * mNext
Definition: ooflist.h:266
virtual OOF_fieldTypes fieldType() const =0
Sortable list of unsigned longs.
Definition: ooflist.h:126
bool selectJustOID(oidT)
Try to change the current selection to just the matching record.
Definition: oof1.cpp:2705
virtual unsigned long remove()
Definition: ooflist.cpp:390
virtual void sortSelectionNow(fieldNumT)
Definition: oofrec2.cpp:1069
unsigned long value(unsigned long) const
Definition: oofrecs.h:967
Defines varying list types because we run on older compilers instead of templating lists...
void suspendSorting()
Definition: oof1.cpp:3024
EselectionState state() const
Definition: oofrecs.h:846
void exchange(OOF_ULSorterElement *theItem)
Definition: ooflist.cpp:362
virtual void invert()
Definition: oofrec2.cpp:2432
Persistent field used to store an unsigned long.
Definition: oof4.h:475
unsigned long count()
Definition: ooflist.h:46
void sortedInsertReverse(double theItem, unsigned long theData)
Definition: ooflist.cpp:543
virtual void intersection_with(const OOF_tableBackend *)=0
Base class for persistent fields in dbTable's.
Definition: oof3.h:63
void sortedInsertReverse(long theItem, unsigned long theData)
Definition: ooflist.cpp:449
void sortedInsert(double theItem, unsigned long theData)
Definition: ooflist.cpp:886
virtual unsigned long remove()
Definition: ooflist.cpp:484
void sortedInsertReverse(double theItem, unsigned long theData)
Definition: ooflist.cpp:928
Persistent field used to store a long.
Definition: oof4.h:433