1 //-< CURSOR.CPP >----------------------------------------------------*--------*
2 // GigaBASE Version 1.0 (c) 1999 GARRET * ? *
3 // (Post Relational Database Management System) * /\| *
4 // * / \ *
5 // Created: 20-Nov-98 K.A. Knizhnik * / [] \ *
6 // Last update: 21-Dec-98 K.A. Knizhnik * GARRET *
7 //-------------------------------------------------------------------*--------*
8 // Table cursor
9 //-------------------------------------------------------------------*--------*
10
11 #define INSIDE_GIGABASE
12
13 #include "gigabase.h"
14 #include "compiler.h"
15 #include "btree.h"
16
17 BEGIN_GIGABASE_NAMESPACE
18
19 size_t dbSelection::buildSelectionBitmapThreshold = 100;
20
next()21 oid_t dbTableIterator::next()
22 {
23 if (curr != 0) {
24 dbRecord rec;
25 oid_t oid = curr;
26 while (true) {
27 cursor->db->getHeader(rec, oid);
28 oid = rec.next;
29 if (oid != 0) {
30 if (filter == NULL
31 || cursor->db->evaluateBoolean(filter, oid, cursor->table, cursor))
32 {
33 return curr = oid;
34 }
35 } else {
36 break;
37 }
38 }
39 }
40 return 0;
41 }
42
prev()43 oid_t dbTableIterator::prev()
44 {
45 if (curr != 0) {
46 dbRecord rec;
47 oid_t oid = curr;
48 while (true) {
49 cursor->db->getHeader(rec, oid);
50 oid = rec.prev;
51 if (oid != 0) {
52 if (filter == NULL
53 || cursor->db->evaluateBoolean(filter, oid, cursor->table, cursor))
54 {
55 return curr = oid;
56 }
57 } else {
58 break;
59 }
60 }
61 }
62 return 0;
63 }
64
first()65 oid_t dbTableIterator::first()
66 {
67 oid_t oid = cursor->table->firstRow;
68 while (oid != 0
69 && filter != NULL
70 && !cursor->db->evaluateBoolean(filter, oid, cursor->table, cursor))
71 {
72 dbRecord rec;
73 cursor->db->getHeader(rec, oid);
74 oid = rec.next;
75 }
76 return curr = oid;
77 }
78
79
last()80 oid_t dbTableIterator::last()
81 {
82 oid_t oid = cursor->table->lastRow;
83 while (oid != 0
84 && filter != NULL
85 && !cursor->db->evaluateBoolean(filter, oid, cursor->table, cursor))
86 {
87 dbRecord rec;
88 cursor->db->getHeader(rec, oid);
89 oid = rec.prev;
90 }
91 return curr = oid;
92 }
93
94
reset()95 void dbSelection::reset()
96 {
97 while (first.next != &first) {
98 delete first.next;
99 }
100 first.nRows = 0;
101 curr = &first;
102 nRows = 0;
103 pos = 0;
104 }
105
reverse()106 void dbSelection::reverse()
107 {
108 segment* seg = &first;
109 do {
110 segment* next = seg->next;
111 seg->next = seg->prev;
112 seg->prev = next;
113 for (int l = 0, r = (int)seg->nRows-1; l < r; l++, r--) {
114 oid_t oid = seg->rows[l];
115 seg->rows[l] = seg->rows[r];
116 seg->rows[r] = oid;
117 }
118 seg = next;
119 } while (seg != &first);
120 }
121
truncate(cardinality_t from,cardinality_t length)122 void dbSelection::truncate(cardinality_t from, cardinality_t length)
123 {
124 if (from == 0 && length >= nRows) {
125 // do nothing
126 return;
127 }
128 segment* src = &first;
129 bool empty = true;
130 if (from < nRows) {
131 do {
132 if (from < src->nRows) {
133 empty = false;
134 break;
135 }
136 from -= src->nRows;
137 } while ((src = src->next) != &first);
138 }
139 if (from + length > nRows) {
140 length = nRows - from;
141 }
142 nRows = 0;
143 segment* dst = &first;
144 size_t pos = 0;
145 if (!empty) {
146 while (length != 0) {
147 size_t n = src->nRows - from;
148 if (n > length) {
149 n = length;
150 }
151 if (dst->nRows == pos) {
152 dst = dst->next;
153 pos = 0;
154 }
155 if (n > dst->nRows - pos) {
156 n = dst->nRows - pos;
157 }
158 memcpy(dst->rows + pos, src->rows + from, n*sizeof(oid_t));
159 pos += n;
160 length -= n;
161 nRows += n;
162 if ((from += n) == src->nRows) {
163 if ((src = src->next) == &first) {
164 break;
165 }
166 from = 0;
167 }
168 }
169 }
170 dst->nRows = pos;
171 dst = dst->next;
172 while (dst != &first) {
173 segment* next = dst->next;
174 delete dst;
175 dst = next;
176 }
177 }
178
compare(oid_t o1,dbRecord * a,oid_t o2,dbRecord * b,dbOrderByNode * order)179 int dbSelection::compare(oid_t o1, dbRecord* a, oid_t o2, dbRecord* b, dbOrderByNode* order)
180 {
181 byte* p = (byte*)a;
182 byte* q = (byte*)b;
183 int diff = 0;
184 do {
185 if (order->expr != NULL) {
186 dbDatabase* db = order->table->db;
187 dbInheritedAttribute iattr1;
188 dbInheritedAttribute iattr2;
189 dbSynthesizedAttribute sattr1;
190 dbSynthesizedAttribute sattr2;
191 iattr1.db = iattr2.db = db;
192 iattr1.table = iattr2.table = order->table;
193 iattr1.record = sattr1.base = p;
194 iattr1.oid = o1;
195 iattr2.record = sattr2.base = q;
196 iattr2.oid = o2;
197 db->execute(order->expr, iattr1, sattr1);
198 db->execute(order->expr, iattr2, sattr2);
199 switch (order->expr->type) {
200 case tpInteger:
201 diff = sattr1.ivalue < sattr2.ivalue ? -1 : sattr1.ivalue == sattr2.ivalue ? 0 : 1;
202 break;
203 case tpReal:
204 diff = sattr1.fvalue < sattr2.fvalue ? -1 : sattr1.fvalue == sattr2.fvalue ? 0 : 1;
205 break;
206 case tpBoolean:
207 diff = sattr1.bvalue != 0 ? sattr2.bvalue != 0 ? 0 : 1 : sattr2.bvalue != 0 ? -1 : 0;
208 break;
209 case tpString:
210 #ifdef USE_LOCALE_SETTINGS
211 diff = STRCOLL((char_t*)sattr1.array.base, (char_t*)sattr2.array.base);
212 #else
213 diff = STRCMP((char_t*)sattr1.array.base, (char_t*)sattr2.array.base);
214 #endif
215 break;
216 case tpReference:
217 diff = sattr1.oid < sattr2.oid ? -1 : sattr1.oid == sattr2.oid ? 0 : 1;
218 break;
219 default:
220 assert(false);
221 }
222 iattr1.free(sattr1);
223 iattr2.free(sattr2);
224 } else {
225 int offs = order->field->dbsOffs;
226 switch (order->field->type) {
227 case dbField::tpBool:
228 diff = *(bool*)(p + offs) - *(bool*)(q + offs);
229 break;
230 case dbField::tpInt1:
231 diff = *(int1*)(p + offs) - *(int1*)(q + offs);
232 break;
233 case dbField::tpInt2:
234 diff = *(int2*)(p + offs) - *(int2*)(q + offs);
235 break;
236 case dbField::tpInt4:
237 case dbField::tpArray: // compre arrays length
238 diff = *(int4*)(p + offs) < *(int4*)(q + offs) ? -1 :
239 *(int4*)(p + offs) == *(int4*)(q + offs) ? 0 : 1;
240 break;
241 case dbField::tpInt8:
242 diff = *(db_int8*)(p + offs) < *(db_int8*)(q + offs) ? -1 :
243 *(db_int8*)(p + offs) == *(db_int8*)(q + offs) ? 0 : 1;
244 break;
245 case dbField::tpReference:
246 diff = *(oid_t*)(p + offs) < *(oid_t*)(q + offs) ? -1 :
247 *(oid_t*)(p + offs) == *(oid_t*)(q + offs) ? 0 : 1;
248 break;
249 case dbField::tpReal4:
250 diff = *(real4*)(p + offs) < *(real4*)(q + offs) ? -1 :
251 *(real4*)(p + offs) == *(real4*)(q + offs) ? 0 : 1;
252 break;
253 case dbField::tpReal8:
254 diff = *(real8*)(p + offs) < *(real8*)(q + offs) ? -1 :
255 *(real8*)(p + offs) == *(real8*)(q + offs) ? 0 : 1;
256 break;
257 case dbField::tpString:
258 #ifdef USE_LOCALE_SETTINGS
259 diff = STRCOLL((char_t*)(p + ((dbVarying*)(p + offs))->offs),
260 (char_t*)(q + ((dbVarying*)(q + offs))->offs));
261 #else
262 diff = STRCMP((char_t*)(p + ((dbVarying*)(p + offs))->offs),
263 (char_t*)(q + ((dbVarying*)(q + offs))->offs));
264 #endif
265 break;
266 case dbField::tpRawBinary:
267 diff = order->field->comparator(p + offs, q + offs, order->field->dbsSize);
268 break;
269 default:
270 assert(false);
271 }
272 }
273 if (!order->ascent) {
274 diff = -diff;
275 }
276 } while (diff == 0 && (order = order->next) != NULL);
277
278 return diff;
279 }
280
281 struct dbSortContext {
282 dbDatabase* db;
283 dbOrderByNode* order;
284 };
285
packStrKey(byte * p,bool caseInsensitive)286 inline db_int8 packStrKey(byte* p, bool caseInsensitive)
287 {
288 char_t cnvBuf[8/sizeof(char_t) + 1];
289 if (caseInsensitive) {
290 size_t i;
291 for (i = 0; i < 8/sizeof(char_t) && *((char_t*)p + i) != 0; i++) {
292 cnvBuf[i] = TOLOWER(*((char_t*)p + i));
293 }
294 cnvBuf[i] = 0;
295 p = (byte*)cnvBuf;
296 }
297 #ifdef USE_LOCALE_SETTINGS
298 char_t buf[8/sizeof(char_t)];
299 STRXFRM(buf, (char_t*)p, itemsof(buf));
300 p = (byte*)buf;
301 #endif
302 db_int8 pkey = 0;
303 for (size_t i = 0; i < 8/sizeof(char_t) && *((char_t*)p + i) != 0; i++) {
304 char_t ch = *((char_t*)p + i);
305 pkey |= ((db_int8)ch & ((1 << sizeof(char_t)*8)-1))
306 << ((8/sizeof(char_t)-1-i)*8*sizeof(char_t));
307 }
308 // As far as signed comparison is used for packed key,
309 // and strcmp compares characters as unsign, we should make this
310 // correction
311 return pkey - ((db_int8)-1 << 63);
312 }
313
cmpStrKey(void const * a,void const * b)314 static int __cdecl cmpStrKey(void const* a, void const* b)
315 {
316 #ifdef USE_LOCALE_SETTINGS
317 return STRCOLL(((dbSortRecord*)a)->u.strKey, ((dbSortRecord*)b)->u.strKey);
318 #else
319 return STRCMP(((dbSortRecord*)a)->u.strKey, ((dbSortRecord*)b)->u.strKey);
320 #endif
321 }
322
cmpIntKey(void const * a,void const * b)323 static int __cdecl cmpIntKey(void const* a, void const* b)
324 {
325 return ((dbSortRecord*)a)->u.intKey < ((dbSortRecord*)b)->u.intKey ? -1
326 : ((dbSortRecord*)a)->u.intKey == ((dbSortRecord*)b)->u.intKey ? 0 : 1;
327 }
328
cmpLongKey(void const * a,void const * b)329 static int __cdecl cmpLongKey(void const* a, void const* b)
330 {
331 return ((dbSortRecord*)a)->u.longKey < ((dbSortRecord*)b)->u.longKey ? -1
332 : ((dbSortRecord*)a)->u.longKey == ((dbSortRecord*)b)->u.longKey ? 0 : 1;
333 }
334
cmpRealKey(void const * a,void const * b)335 static int __cdecl cmpRealKey(void const* a, void const* b)
336 {
337 return ((dbSortRecord*)a)->u.realKey < ((dbSortRecord*)b)->u.realKey ? -1
338 : ((dbSortRecord*)a)->u.realKey == ((dbSortRecord*)b)->u.realKey ? 0 : 1;
339 }
340
cmpStrKeyDesc(void const * a,void const * b)341 static int __cdecl cmpStrKeyDesc(void const* a, void const* b)
342 {
343 #ifdef USE_LOCALE_SETTINGS
344 return -STRCOLL(((dbSortRecord*)a)->u.strKey, ((dbSortRecord*)b)->u.strKey);
345 #else
346 return -STRCMP(((dbSortRecord*)a)->u.strKey, ((dbSortRecord*)b)->u.strKey);
347 #endif
348 }
349
cmpIntKeyDesc(void const * a,void const * b)350 static int __cdecl cmpIntKeyDesc(void const* a, void const* b)
351 {
352 return ((dbSortRecord*)a)->u.intKey > ((dbSortRecord*)b)->u.intKey ? -1
353 : ((dbSortRecord*)a)->u.intKey == ((dbSortRecord*)b)->u.intKey ? 0 : 1;
354 }
355
cmpLongKeyDesc(void const * a,void const * b)356 static int __cdecl cmpLongKeyDesc(void const* a, void const* b)
357 {
358 return ((dbSortRecord*)a)->u.longKey > ((dbSortRecord*)b)->u.longKey ? -1
359 : ((dbSortRecord*)a)->u.longKey == ((dbSortRecord*)b)->u.longKey ? 0 : 1;
360 }
361
cmpRealKeyDesc(void const * a,void const * b)362 static int __cdecl cmpRealKeyDesc(void const* a, void const* b)
363 {
364 return ((dbSortRecord*)a)->u.realKey > ((dbSortRecord*)b)->u.realKey ? -1
365 : ((dbSortRecord*)a)->u.realKey == ((dbSortRecord*)b)->u.realKey ? 0 : 1;
366 }
367
368
369 static dbThreadContext<dbSortContext> sortThreadContext;
370
371
exactKeyCmp(void const * a,void const * b)372 int __cdecl dbSelection::exactKeyCmp(void const* a, void const* b)
373 {
374 dbGetTie ta, tb;
375 dbSortContext* ctx = sortThreadContext.get();
376 return compare(((dbSortRecord*)a)->oid, ctx->db->getRow(ta, ((dbSortRecord*)a)->oid),
377 ((dbSortRecord*)b)->oid, ctx->db->getRow(tb, ((dbSortRecord*)b)->oid),
378 ctx->order);
379 }
380
udtComparator(void const * a,void const * b)381 int __cdecl dbSelection::udtComparator(void const* a, void const* b)
382 {
383 dbSortContext* ctx = sortThreadContext.get();
384 int rc = ctx->order->field->comparator(((dbSortRecord*)a)->u.rawKey, ((dbSortRecord*)b)->u.rawKey,
385 ctx->order->field->dbsSize);
386 return ctx->order->ascent ? rc : -rc;
387 }
388
toArray(oid_t * oids) const389 void dbSelection::toArray(oid_t* oids) const
390 {
391 segment const* seg = &first;
392 do {
393 for (int i = 0, n = (int)seg->nRows; i < n; i++) {
394 *oids++ = seg->rows[i];
395 }
396 } while ((seg = seg->next) != &first);
397 }
398
compareOids(void const * a,void const * b)399 static int __cdecl compareOids(void const* a, void const* b)
400 {
401 return *(oid_t*)a < *(oid_t*)b ? -1 : *(oid_t*)a == *(oid_t*)b ? 0 : 1;
402 }
403
404
allocateBitmap(dbDatabase * db)405 void dbSelection::allocateBitmap(dbDatabase* db)
406 {
407 size_t size = (size_t)((db->currIndexSize + 31) / 32);
408 if (size > bitmapSize) {
409 delete[] bitmap;
410 bitmap = new int4[size];
411 bitmapSize = size;
412 }
413 memset(bitmap, 0, size*4);
414 }
415
deallocateBitmap()416 void dbSelection::deallocateBitmap()
417 {
418 if (bitmap != NULL) {
419 delete[] bitmap;
420 bitmap = NULL;
421 bitmapSize = 0;
422 }
423 }
424
merge(dbDatabase * db,dbSelection & selection)425 void dbSelection::merge(dbDatabase* db, dbSelection& selection)
426 {
427 size_t n1 = nRows, n2 = selection.nRows;
428 TRACE_MSG((STRLITERAL("Performing indexed merge of %d and %d rows\n"), n1, n2));
429 segment* dst = &first;
430 size_t n = 0, j = 0;
431
432 if (n1 > buildSelectionBitmapThreshold || n2 > buildSelectionBitmapThreshold) {
433 allocateBitmap(db);
434 int4* bm = bitmap;
435 segment const* seg = &selection.first;
436 do {
437 for (size_t i = 0, sn = seg->nRows; i < sn; i++) {
438 oid_t o = seg->rows[i];
439 bm[(size_t)o >> 5] |= 1 << ((int)o & 31);
440 }
441 } while ((seg = seg->next) != &selection.first);
442
443 seg = &first;
444 do {
445 for (size_t i = 0, sn = seg->nRows; i < sn; i++) {
446 oid_t o = seg->rows[i];
447 if (bm[(size_t)o >> 5] & (1 << ((int)o & 31))) {
448 if (j == dst->nRows) {
449 dst = dst->next;
450 j = 0;
451 }
452 dst->rows[j++] = o;
453 n += 1;
454 }
455 }
456 } while ((seg = seg->next) != &first);
457 } else {
458 dbSmallBuffer<oid_t> buf2(n2);
459 dbSmallBuffer<oid_t> buf1(n1);
460 oid_t* refs1 = buf1.base();
461 oid_t* refs2 = buf2.base();
462 toArray(refs1);
463 selection.toArray(refs2);
464 qsort(refs1, nRows, sizeof(oid_t), &compareOids);
465 qsort(refs2, selection.nRows, sizeof(oid_t), &compareOids);
466 size_t i1 = 0, i2 = 0;
467
468 while (true) {
469 if (i1 == n1 || i2 == n2) {
470 break;
471 }
472 if (refs1[i1] > refs2[i2]) {
473 i2 += 1;
474 } else if (refs1[i1] < refs2[i2]) {
475 i1 += 1;
476 } else {
477 if (j == dst->nRows) {
478 dst = dst->next;
479 j = 0;
480 }
481 n += 1;
482 dst->rows[j++] = refs1[i1];
483 i1 += 1;
484 i2 += 1;
485 }
486 }
487 }
488 dst->nRows = j;
489 nRows = n;
490 segment* next = dst->next;
491 first.prev = dst;
492 dst->next = &first;
493 while (next != &first) {
494 dst = next;
495 next = dst->next;
496 delete dst;
497 }
498 }
499
500
sort(dbDatabase * db,dbOrderByNode * order,bool caseInsensitive,dbSortResult * sortResult)501 void dbSelection::sort(dbDatabase* db, dbOrderByNode* order, bool caseInsensitive, dbSortResult* sortResult)
502 {
503 int i = 0, j, k, n = (int)nRows;
504 dbSortRecord* keys = new dbSortRecord[n];
505 char* rawKeys = NULL;
506 segment* seg = &first;
507 bool partialOrder = false;
508
509 TRACE_MSG((STRLITERAL("Sort %d records\n"), n));
510
511 if (order->expr != NULL) {
512 dbSynthesizedAttribute result;
513 switch (order->expr->type) {
514 case tpReal:
515 do {
516 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
517 db->evaluate(order->expr, seg->rows[j], order->table, result);
518 keys[i].u.realKey = result.fvalue;
519 keys[i].oid = seg->rows[j];
520 }
521 } while ((seg = seg->next) != &first);
522 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpRealKey : cmpRealKeyDesc);
523 break;
524 case tpInteger:
525 do {
526 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
527 db->evaluate(order->expr, seg->rows[j], order->table, result);
528 keys[i].u.longKey = result.ivalue;
529 keys[i].oid = seg->rows[j];
530 }
531 } while ((seg = seg->next) != &first);
532 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpIntKey : cmpIntKeyDesc);
533 break;
534 case tpBoolean:
535 do {
536 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
537 db->evaluate(order->expr, seg->rows[j], order->table, result);
538 keys[i].u.intKey = result.bvalue;
539 keys[i].oid = seg->rows[j];
540 }
541 } while ((seg = seg->next) != &first);
542 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpIntKey : cmpIntKeyDesc);
543 break;
544 case tpReference:
545 do {
546 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
547 db->evaluate(order->expr, seg->rows[j], order->table, result);
548 keys[i].u.longKey = result.oid;
549 keys[i].oid = seg->rows[j];
550 }
551 } while ((seg = seg->next) != &first);
552 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpLongKey : cmpLongKeyDesc);
553 break;
554 case tpString:
555 if (sortResult != NULL) {
556 do {
557 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
558 char_t buf[dbBtreePage::dbMaxKeyLen];
559 int len = (int)db->evaluateString(order->expr, seg->rows[j], order->table, buf, itemsof(buf));
560 assert(len <= dbBtreePage::dbMaxKeyLen);
561 keys[i].u.strKey = sortResult->strBuf.put(buf, len);
562 if (caseInsensitive) {
563 strlower(keys[i].u.strKey, keys[i].u.strKey);
564 }
565 keys[i].oid = seg->rows[j];
566 }
567 } while ((seg = seg->next) != &first);
568 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpStrKey : cmpStrKeyDesc);
569 } else {
570 do {
571 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
572 char_t buf[8/sizeof(char_t)];
573 db->evaluateString(order->expr, seg->rows[j], order->table, buf, itemsof(buf));
574 keys[i].u.longKey = packStrKey((byte*)buf, caseInsensitive);
575 keys[i].oid = seg->rows[j];
576 }
577 } while ((seg = seg->next) != &first);
578 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpLongKey : cmpLongKeyDesc);
579 partialOrder = true;
580 }
581 break;
582 default:
583 assert(false);
584 }
585 } else {
586 int offs = order->field->dbsOffs;
587 dbGetTie tie;
588 byte* p;
589
590 memset(keys, 0, n*sizeof(dbSortRecord));
591
592 switch (order->field->type) {
593 case dbField::tpBool:
594 case dbField::tpInt1:
595 do {
596 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
597 p = (byte*)db->getRow(tie, seg->rows[j]);
598 keys[i].u.intKey = *(int1*)(p + offs);
599 keys[i].oid = seg->rows[j];
600 }
601 } while ((seg = seg->next) != &first);
602 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpIntKey : cmpIntKeyDesc);
603 break;
604 case dbField::tpInt2:
605 do {
606 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
607 p = (byte*)db->getRow(tie, seg->rows[j]);
608 keys[i].u.intKey = *(int2*)(p + offs);
609 keys[i].oid = seg->rows[j];
610 }
611 } while ((seg = seg->next) != &first);
612 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpIntKey : cmpIntKeyDesc);
613 break;
614 case dbField::tpReal4:
615 do {
616 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
617 p = (byte*)db->getRow(tie, seg->rows[j]);
618 keys[i].u.realKey = *(float*)(p + offs);
619 keys[i].oid = seg->rows[j];
620 }
621 } while ((seg = seg->next) != &first);
622 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpRealKey : cmpRealKeyDesc);
623 break;
624 case dbField::tpInt4:
625 case dbField::tpArray:
626 do {
627 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
628 p = (byte*)db->getRow(tie, seg->rows[j]);
629 keys[i].u.intKey = *(int4*)(p + offs);
630 keys[i].oid = seg->rows[j];
631 }
632 } while ((seg = seg->next) != &first);
633 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpIntKey : cmpIntKeyDesc);
634 break;
635 case dbField::tpInt8:
636 do {
637 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
638 p = (byte*)db->getRow(tie, seg->rows[j]);
639 keys[i].u.longKey = *(db_int8*)(p + offs);
640 keys[i].oid = seg->rows[j];
641 }
642 } while ((seg = seg->next) != &first);
643 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpLongKey : cmpLongKeyDesc);
644 break;
645 case dbField::tpReference:
646 do {
647 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
648 p = (byte*)db->getRow(tie, seg->rows[j]);
649 keys[i].u.longKey = *(oid_t*)(p + offs);
650 keys[i].oid = seg->rows[j];
651 }
652 } while ((seg = seg->next) != &first);
653 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpLongKey : cmpLongKeyDesc);
654 break;
655 case dbField::tpReal8:
656 do {
657 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
658 p = (byte*)db->getRow(tie, seg->rows[j]);
659 keys[i].u.realKey = *(real8*)(p + offs);
660 keys[i].oid = seg->rows[j];
661 }
662 } while ((seg = seg->next) != &first);
663 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpRealKey : cmpRealKeyDesc);
664 break;
665 case dbField::tpString:
666 if (sortResult != NULL) {
667 do {
668 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
669 byte* p = (byte*)db->getRow(tie, seg->rows[j]);
670 keys[i].u.strKey = sortResult->strBuf.put((char_t*)(p + ((dbVarying*)(p + offs))->offs),
671 ((dbVarying*)(p + offs))->size-1);
672 if (caseInsensitive) {
673 strlower(keys[i].u.strKey, keys[i].u.strKey);
674 }
675 keys[i].oid = seg->rows[j];
676 }
677 } while ((seg = seg->next) != &first);
678 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpStrKey : cmpStrKeyDesc);
679 } else {
680 do {
681 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
682 byte* p = (byte*)db->getRow(tie, seg->rows[j]);
683 keys[i].u.longKey = packStrKey(p + ((dbVarying*)(p + offs))->offs, caseInsensitive);
684 keys[i].oid = seg->rows[j];
685 }
686 } while ((seg = seg->next) != &first);
687 qsort(keys, n, sizeof(dbSortRecord), order->ascent ? cmpLongKey : cmpLongKeyDesc);
688 partialOrder = true;
689 }
690 break;
691 case dbField::tpRawBinary:
692 {
693 int rawSize = (int)order->field->dbsSize;
694 rawKeys = new char[n*rawSize];
695 dbSortContext ctx;
696 ctx.db = db;
697 ctx.order = order;
698 sortThreadContext.set(&ctx);
699 do {
700 for (j = 0, k = (int)seg->nRows; j < k; j++, i++) {
701 p = (byte*)db->getRow(tie, seg->rows[j]);
702 keys[i].oid = seg->rows[j];
703 keys[i].u.rawKey = rawKeys + i*rawSize;
704 memcpy(keys[i].u.rawKey, p + offs, rawSize);
705 }
706 } while ((seg = seg->next) != &first);
707 qsort(keys, n, sizeof(dbSortRecord), udtComparator);
708 break;
709 }
710 default:
711 assert(false);
712 }
713 }
714 if (order->next != NULL || partialOrder) {
715 dbSortContext ctx;
716 ctx.db = db;
717 ctx.order = partialOrder ? order : order->next;
718 sortThreadContext.set(&ctx);
719 if (rawKeys != NULL) {
720 for (i = 0, k = 0; i < n; i = j) {
721 for (j = i+1; j < n && order->field->comparator(keys[j].u.rawKey,
722 keys[i].u.rawKey,
723 order->field->dbsSize) == 0; j++);
724 if (j > i + 1) {
725 qsort(keys + i, j - i, sizeof(dbSortRecord), exactKeyCmp);
726 }
727 }
728 } else {
729 for (i = 0, k = 0; i < n; i = j) {
730 for (j = i+1; j < n && keys[j].u.longKey == keys[i].u.longKey; j++);
731 if (j > i + 1) {
732 qsort(keys + i, j - i, sizeof(dbSortRecord), exactKeyCmp);
733 }
734 }
735 }
736 }
737 if (sortResult != NULL) {
738 sortResult->keys = keys;
739 sortResult->rawKeys = rawKeys;
740 } else {
741 if (n != 0) {
742 for (i = 0, j = 0, seg = &first, k = (int)seg->nRows; i < n; i++, j++) {
743 if (j == k) {
744 seg = seg->next;
745 k = (int)seg->nRows;
746 j = 0;
747 }
748 seg->rows[j] = keys[i].oid;
749 }
750 }
751 delete[] keys;
752 delete[] rawKeys;
753 }
754 }
755
dbAnyCursor(dbTableDescriptor & aTable,dbCursorType aType,byte * rec)756 dbAnyCursor::dbAnyCursor(dbTableDescriptor& aTable, dbCursorType aType, byte* rec)
757 : table(&aTable),type(aType),defaultType(aType),
758 allRecords(false),currId(0),record(rec)
759 {
760 limit = dbDefaultSelectionLimit;
761 prefetch = rec != NULL;
762 removed = false;
763 eliminateDuplicates = false;
764 checkForDuplicatedIsEnabled = true;
765 db = aTable.db;
766 paramBase = NULL;
767 stmtLimitLen = dbDefaultSelectionLimit;
768 stmtLimitStart = 0;
769 nSkipped = 0;
770 iterator = NULL;
771 }
772
dbAnyCursor(dbCursorType aType)773 dbAnyCursor::dbAnyCursor(dbCursorType aType)
774 : table(NULL),type(aType),defaultType(aType),
775 allRecords(false),currId(0),record(NULL)
776 {
777 limit = dbDefaultSelectionLimit;
778 prefetch = false;
779 removed = false;
780 eliminateDuplicates = false;
781 checkForDuplicatedIsEnabled = true;
782 db = NULL;
783 paramBase = NULL;
784 stmtLimitLen = dbDefaultSelectionLimit;
785 stmtLimitStart = 0;
786 nSkipped = 0;
787 iterator = NULL;
788 }
789
select(dbQuery & query,dbCursorType aType,void * paramStruct)790 cardinality_t dbAnyCursor::select(dbQuery& query, dbCursorType aType, void* paramStruct)
791 {
792 paramBase = paramStruct;
793 type = aType;
794 reset();
795 db->select(this, query);
796 paramBase = NULL;
797 if (gotoFirst() && prefetch) {
798 fetch();
799 }
800 if (aType == dbCursorDetached) {
801 unlink();
802 db->commit();
803 }
804 return selection.nRows;
805 }
806
toArrayOfOid(oid_t * arr) const807 oid_t* dbAnyCursor::toArrayOfOid(oid_t* arr) const
808 {
809 assert(iterator == NULL); // do not use incremental cursor if you need to get array of OIDs
810 if (arr == NULL) {
811 arr = new oid_t[selection.nRows];
812 }
813 if (allRecords) {
814 dbRecord rec;
815 oid_t* oids = arr;
816 for (oid_t oid = firstId; oid != 0; oid = rec.next) {
817 db->getHeader(rec, oid);
818 *oids++ = oid;
819 }
820 } else {
821 selection.toArray(arr);
822 }
823 return arr;
824 }
setCurrent(dbAnyReference const & ref)825 void dbAnyCursor::setCurrent(dbAnyReference const& ref)
826 {
827 removed = false;
828 assert(ref.oid != 0);
829 reset();
830 db->beginTransaction(type == dbCursorForUpdate ? dbUpdateLock : dbSharedLock);
831 db->threadContext.get()->cursors.link(this);
832 currId = ref.oid;
833 selection.first.nRows = 1;
834 selection.first.rows[0] = currId;
835 selection.nRows = 1;
836 if (prefetch) {
837 fetch();
838 }
839 }
840
selectByKey(char_t const * key,void const * value)841 cardinality_t dbAnyCursor::selectByKey(char_t const* key, void const* value)
842 {
843 dbFieldDescriptor* field = table->find(key);
844 assert(field != NULL);
845 return selectByKey(field, value);
846 }
847
selectByKey(dbFieldDescriptor * field,void const * value)848 cardinality_t dbAnyCursor::selectByKey(dbFieldDescriptor* field, void const* value)
849 {
850 assert(field->hashTable != 0 || field->bTree != 0);
851 reset();
852 db->beginTransaction(type == dbCursorForUpdate ? dbUpdateLock : dbSharedLock);
853 db->threadContext.get()->cursors.link(this);
854 dbSearchContext sc;
855 sc.db = db;
856 sc.probes = 0;
857 sc.ascent = true;
858 sc.offs = field->dbsOffs;
859 sc.cursor = this;
860 sc.tmpKeys = false;
861 sc.condition = NULL;
862 sc.prefixLength = 0;
863 sc.spatialSearch = false;
864 sc.arraySearch = false;
865 sc.firstKey = sc.lastKey = (char_t*)value;
866 sc.firstKeyInclusion = sc.lastKeyInclusion = true;
867 if (type == dbCursorIncremental) {
868 btreeIterator.init(db, field->bTree, sc, field->comparator);
869 iterator = &btreeIterator;
870 } else {
871 dbBtree::find(db, field->bTree, sc, field->comparator);
872 }
873 if (gotoFirst() && prefetch) {
874 fetch();
875 }
876 return selection.nRows;
877 }
878
seek(oid_t oid)879 int dbAnyCursor::seek(oid_t oid)
880 {
881 int pos = 0;
882 if (gotoFirst()) {
883 do {
884 if (currId == oid) {
885 if (prefetch) {
886 fetch();
887 }
888 return pos;
889 }
890 pos += 1;
891 } while (gotoNext());
892 }
893 return -1;
894 }
895
skip(int n)896 bool dbAnyCursor::skip(int n) {
897 while (n > 0) {
898 if (!gotoNext()) {
899 return false;
900 }
901 n -= 1;
902 }
903 while (n < 0) {
904 if (!gotoPrev()) {
905 return false;
906 }
907 n += 1;
908 }
909 if (prefetch) {
910 fetch();
911 }
912 return true;
913 }
914
selectByKeyRange(char_t const * key,void const * minValue,void const * maxValue,bool ascent)915 cardinality_t dbAnyCursor::selectByKeyRange(char_t const* key, void const* minValue,
916 void const* maxValue, bool ascent)
917 {
918 dbFieldDescriptor* field = table->find(key);
919 assert(field != NULL);
920 return selectByKeyRange(field, minValue, maxValue, ascent);
921 }
922
selectByKeyRange(dbFieldDescriptor * field,void const * minValue,void const * maxValue,bool ascent)923 cardinality_t dbAnyCursor::selectByKeyRange(dbFieldDescriptor* field, void const* minValue,
924 void const* maxValue, bool ascent)
925 {
926 assert(field->bTree != 0);
927 reset();
928 db->beginTransaction(type == dbCursorForUpdate ? dbUpdateLock : dbSharedLock);
929 db->threadContext.get()->cursors.link(this);
930 dbSearchContext sc;
931 sc.db = db;
932 sc.probes = 0;
933 sc.offs = field->dbsOffs;
934 sc.cursor = this;
935 sc.tmpKeys = false;
936 sc.ascent = ascent;
937 sc.condition = NULL;
938 sc.prefixLength = 0;
939 sc.firstKey = (char_t*)minValue;
940 sc.lastKey = (char_t*)maxValue;
941 sc.firstKeyInclusion = sc.lastKeyInclusion = true;
942 sc.spatialSearch = false;
943 sc.arraySearch = false;
944 if (type == dbCursorIncremental) {
945 btreeIterator.init(db, field->bTree, sc, field->comparator);
946 iterator = &btreeIterator;
947 } else {
948 dbBtree::find(db, field->bTree, sc, field->comparator);
949 }
950 if (gotoFirst() && prefetch) {
951 fetch();
952 }
953 return selection.nRows;
954 }
955
remove()956 void dbAnyCursor::remove()
957 {
958 oid_t removedId = currId;
959 lastRecordWasDeleted = false;
960 if (type != dbCursorForUpdate) {
961 db->handleError(dbDatabase::CursorError, "Readonly cursor");
962 }
963 if (removedId == 0) {
964 db->handleError(dbDatabase::CursorError, "No current record");
965 }
966 if (allRecords) {
967 dbRecord rec;
968 db->getHeader(rec, removedId);
969 if (rec.next != 0) {
970 if (removedId == firstId) {
971 firstId = currId = rec.next;
972 } else {
973 currId = rec.next;
974 }
975 } else {
976 lastRecordWasDeleted = true;
977 if (removedId == firstId) {
978 firstId = lastId = currId = 0;
979 } else {
980 lastId = currId = rec.prev;
981 }
982 }
983 } else {
984 if (selection.curr != NULL) {
985 if (--selection.curr->nRows == 0 || selection.pos == selection.curr->nRows) {
986 dbSelection::segment* s = selection.curr, *next= s->next;;
987 if (selection.curr->nRows == 0 && s != &selection.first) {
988 delete s;
989 }
990 if (next != &selection.first) {
991 selection.curr = next;
992 selection.pos = 0;
993 } else {
994 lastRecordWasDeleted = true;
995 selection.curr = next->prev;
996 selection.pos = selection.curr->nRows-1;
997 }
998 if (selection.curr->nRows != 0) {
999 currId = selection.curr->rows[selection.pos];
1000 } else {
1001 currId = 0;
1002 }
1003 } else {
1004 memcpy(selection.curr->rows + selection.pos,
1005 selection.curr->rows + selection.pos + 1,
1006 (selection.curr->nRows - selection.pos)
1007 *sizeof(oid_t));
1008 currId = selection.curr->rows[selection.pos];
1009 }
1010 } else {
1011 currId = 0;
1012 }
1013 }
1014 byte* saveRecord = record;
1015 record = NULL;
1016 db->remove(table, removedId);
1017 record = saveRecord;
1018 removed = true;
1019 if (currId != 0 && prefetch) {
1020 fetch();
1021 }
1022 }
1023
1024
removeAllSelected()1025 void dbAnyCursor::removeAllSelected()
1026 {
1027 if (type != dbCursorForUpdate) {
1028 db->handleError(dbDatabase::CursorError, "Readonly cursor");
1029 }
1030 byte* saveRecord = record;
1031 record = NULL;
1032 if (allRecords) {
1033 removeAll();
1034 } else if (selection.nRows != 0) {
1035 dbSelection::segment* curr = &selection.first;
1036 currId = 0;
1037 do {
1038 for (int i = 0, n = (int)curr->nRows; i < n; i++) {
1039 db->remove(table, curr->rows[i]);
1040 }
1041 } while ((curr = curr->next) != &selection.first);
1042 reset();
1043 } else if (currId != 0) {
1044 db->remove(table, currId);
1045 currId = 0;
1046 }
1047 record = saveRecord;
1048 }
1049
isLast() const1050 bool dbAnyCursor::isLast() const
1051 {
1052 if (iterator != NULL) {
1053 if (currId != 0) {
1054 if (!iterator->next()) {
1055 return true;
1056 }
1057 iterator->prev();
1058 }
1059 } else if (allRecords) {
1060 if (currId != 0) {
1061 dbRecord rec;
1062 db->getHeader(rec, currId);
1063 return rec.next == 0;
1064 }
1065 } else if (selection.curr != NULL) {
1066 return selection.pos+1 == selection.curr->nRows
1067 && selection.curr->next == &selection.first;
1068 }
1069 return false;
1070 }
1071
1072
isFirst() const1073 bool dbAnyCursor::isFirst() const
1074 {
1075 if (iterator != NULL) {
1076 if (currId != 0) {
1077 if (!iterator->prev()) {
1078 return true;
1079 }
1080 iterator->next();
1081 }
1082 } else if (allRecords) {
1083 if (currId != 0) {
1084 dbRecord rec;
1085 db->getHeader(rec, currId);
1086 return rec.prev == 0;
1087 }
1088 } else if (selection.curr != NULL) {
1089 return selection.pos == 0 && selection.curr == &selection.first;
1090 }
1091 return false;
1092 }
1093
1094
hasNext() const1095 bool dbAnyCursor::hasNext() const
1096 {
1097 if (iterator != NULL) {
1098 if (currId != 0 && iterator->next()) {
1099 iterator->prev();
1100 return true;
1101 }
1102 } else if (allRecords) {
1103 if (currId != 0) {
1104 dbRecord rec;
1105 db->getHeader(rec, currId);
1106 return rec.next != 0;
1107 }
1108 } else if (selection.curr != NULL
1109 && (selection.pos+1 < selection.curr->nRows || selection.curr->next != &selection.first))
1110 {
1111 return true;
1112 }
1113 return false;
1114 }
1115
fetchNext()1116 byte* dbAnyCursor::fetchNext()
1117 {
1118 byte* result = NULL;
1119 if (type == dbCursorDetached) {
1120 db->beginTransaction(dbSharedLock);
1121 db->threadContext.get()->cursors.link(this);
1122 assert(!removed);
1123 while (gotoNext()) {
1124 if (db->isValidOid(currId)) {
1125 fetch();
1126 result = record;
1127 break;
1128 }
1129 }
1130 unlink();
1131 db->commit();
1132 } else {
1133 if (!removed) {
1134 if (gotoNext()) {
1135 fetch();
1136 result = record;
1137 }
1138 } else {
1139 removed = false;
1140 if (currId != 0 && !lastRecordWasDeleted) {
1141 if (!prefetch) {
1142 fetch();
1143 }
1144 result = record;
1145 }
1146 }
1147 }
1148 return result;
1149 }
1150
fetchPrev()1151 byte* dbAnyCursor::fetchPrev()
1152 {
1153 if (type == dbCursorDetached) {
1154 db->beginTransaction(dbSharedLock);
1155 db->threadContext.get()->cursors.link(this);
1156 assert(!removed);
1157 byte* result = NULL;
1158 while (gotoPrev()) {
1159 if (db->isValidOid(currId)) {
1160 fetch();
1161 result = record;
1162 break;
1163 }
1164 }
1165 unlink();
1166 db->commit();
1167 return result;
1168 } else {
1169 if (removed) {
1170 removed = false;
1171 if (lastRecordWasDeleted) {
1172 if (currId != 0) {
1173 if (!prefetch) {
1174 fetch();
1175 }
1176 return record;
1177 }
1178 return NULL;
1179 }
1180 }
1181 if (gotoPrev()) {
1182 fetch();
1183 return record;
1184 }
1185 return NULL;
1186 }
1187 }
1188
fetchFirst()1189 byte* dbAnyCursor::fetchFirst()
1190 {
1191 byte* result = NULL;
1192
1193 if (type == dbCursorDetached) {
1194 db->beginTransaction(dbSharedLock);
1195 db->threadContext.get()->cursors.link(this);
1196
1197 if (gotoFirst()) {
1198 do {
1199 if (db->isValidOid(currId)) {
1200 fetch();
1201 result = record;
1202 break;
1203 }
1204 } while (gotoNext());
1205 }
1206 unlink();
1207 db->commit();
1208 } else {
1209 if (gotoFirst()) {
1210 fetch();
1211 result = record;
1212 }
1213 }
1214 return result;
1215 }
1216
fetchLast()1217 byte* dbAnyCursor::fetchLast()
1218 {
1219 byte* result = NULL;
1220
1221 if (type == dbCursorDetached) {
1222 db->beginTransaction(dbSharedLock);
1223 db->threadContext.get()->cursors.link(this);
1224
1225 if (gotoLast()) {
1226 do {
1227 if (db->isValidOid(currId)) {
1228 fetch();
1229 result = record;
1230 break;
1231 }
1232 } while (gotoPrev());
1233 }
1234 unlink();
1235 db->commit();
1236 } else {
1237 if (gotoLast()) {
1238 fetch();
1239 result = record;
1240 }
1241 }
1242 return result;
1243 }
1244
1245
gotoNext()1246 bool dbAnyCursor::gotoNext()
1247 {
1248 if (iterator != NULL) {
1249 oid_t next = iterator->next();
1250 if (next != 0) {
1251 currId = next;
1252 return true;
1253 }
1254 return false;
1255 }
1256 removed = false;
1257 if (allRecords) {
1258 if (currId != 0) {
1259 dbRecord rec;
1260 db->getHeader(rec, currId);
1261 if (rec.next != 0) {
1262 currId = rec.next;
1263 return true;
1264 }
1265 }
1266 } else if (selection.curr != NULL) {
1267 if (++selection.pos == selection.curr->nRows) {
1268 if (selection.curr->next == &selection.first) {
1269 selection.pos -= 1;
1270 return false;
1271 }
1272 selection.pos = 0;
1273 selection.curr = selection.curr->next;
1274 }
1275 currId = selection.curr->rows[selection.pos];
1276 return true;
1277 }
1278 return false;
1279 }
1280
gotoPrev()1281 bool dbAnyCursor::gotoPrev()
1282 {
1283 if (iterator != NULL) {
1284 oid_t prev = iterator->prev();
1285 if (prev != 0) {
1286 currId = prev;
1287 return true;
1288 }
1289 return false;
1290 }
1291 removed = false;
1292 if (allRecords) {
1293 if (currId != 0) {
1294 dbRecord rec;
1295 db->getHeader(rec, currId);
1296 if (rec.prev != 0) {
1297 currId = rec.prev;
1298 return true;
1299 }
1300 }
1301 } else if (selection.curr != NULL) {
1302 if (selection.pos == 0) {
1303 if (selection.curr == &selection.first || selection.curr->prev->nRows == 0) {
1304 return false;
1305 }
1306 selection.curr = selection.curr->prev;
1307 selection.pos = selection.curr->nRows;
1308 }
1309 currId = selection.curr->rows[--selection.pos];
1310 return true;
1311 }
1312 return false;
1313 }
1314
1315
moveNext()1316 bool dbAnyCursor::moveNext()
1317 {
1318 if (!removed) {
1319 return gotoNext();
1320 } else {
1321 removed = false;
1322 return !lastRecordWasDeleted;
1323 }
1324 }
1325
movePrev()1326 bool dbAnyCursor::movePrev()
1327 {
1328 if (!removed) {
1329 return gotoPrev();
1330 } else {
1331 removed = false;
1332 return lastRecordWasDeleted ? (currId != 0) : gotoPrev();
1333 }
1334 }
1335
gotoFirst()1336 bool dbAnyCursor::gotoFirst()
1337 {
1338 if (iterator != NULL) {
1339 if ((currId = iterator->first()) != 0) {
1340 selection.nRows = 1;
1341 return true;
1342 }
1343 return false;
1344 }
1345 removed = false;
1346 if (allRecords) {
1347 currId = firstId;
1348 return (currId != 0);
1349 } else {
1350 selection.curr = selection.first.nRows == 0 ? selection.first.next : &selection.first;
1351 selection.pos = 0;
1352 if (selection.curr->nRows == 0) {
1353 return (currId != 0);
1354 } else {
1355 currId = selection.curr->rows[0];
1356 return true;
1357 }
1358 }
1359 }
1360
gotoLast()1361 bool dbAnyCursor::gotoLast()
1362 {
1363 if (iterator != NULL) {
1364 return (currId = iterator->last()) != 0;
1365 }
1366 removed = false;
1367 if (allRecords) {
1368 currId = lastId;
1369 return (currId != 0);
1370 } else {
1371 selection.curr = selection.first.prev;
1372 if (selection.curr->nRows == 0) {
1373 return (currId != 0);
1374 } else {
1375 selection.pos = selection.curr->nRows-1;
1376 currId = selection.curr->rows[selection.pos];
1377 return true;
1378 }
1379 }
1380 }
1381
isInSelection(oid_t oid)1382 bool dbAnyCursor::isInSelection(oid_t oid)
1383 {
1384 assert(iterator == NULL);
1385 if (eliminateDuplicates) {
1386 return isMarked(oid);
1387 } else if (selection.nRows > dbSelection::buildSelectionBitmapThreshold) {
1388 checkForDuplicates();
1389 dbSelection::segment* curr = &selection.first;
1390 do {
1391 for (int i = 0, n = (int)curr->nRows; i < n; i++) {
1392 oid_t o = curr->rows[i];
1393 selection.bitmap[(size_t)o >> 5] |= 1 << ((int)o & 31);
1394 }
1395 } while ((curr = curr->next) != &selection.first);
1396 return isMarked(oid);
1397 } else {
1398 dbSelection::segment* curr = &selection.first;
1399 do {
1400 for (int i = 0, n = (int)curr->nRows; i < n; i++) {
1401 if (curr->rows[i] == oid) {
1402 return true;
1403 }
1404 }
1405 } while ((curr = curr->next) != &selection.first);
1406 return false;
1407 }
1408 }
1409
reset()1410 void dbAnyCursor::reset()
1411 {
1412 if (db == NULL) {
1413 db = table->db;
1414 assert(((void)"cursor associated with online database table",
1415 table->tableId != 0));
1416 } else if (table->db != db) {
1417 table = db->lookupTable(table);
1418 }
1419 unlink();
1420 selection.reset();
1421 eliminateDuplicates = false;
1422 allRecords = false;
1423 removed = false;
1424 currId = 0;
1425 tie.reset();
1426 stmtLimitLen = dbDefaultSelectionLimit;
1427 stmtLimitStart = 0;
1428 nSkipped = 0;
1429 iterator = NULL;
1430 }
1431
freeze()1432 void dbAnyCursor::freeze()
1433 {
1434 assert(type != dbCursorIncremental && type != dbCursorDetached);
1435 unlink();
1436 tie.reset();
1437 }
1438
unfreeze()1439 void dbAnyCursor::unfreeze()
1440 {
1441 db->beginTransaction(type == dbCursorForUpdate ? dbUpdateLock : dbSharedLock);
1442 db->threadContext.get()->cursors.link(this);
1443 if (currId != 0 && prefetch) {
1444 fetch();
1445 }
1446 }
1447
~dbAnyCursor()1448 dbAnyCursor::~dbAnyCursor()
1449 {
1450 selection.reset();
1451 }
1452
search(int i)1453 void dbParallelQueryContext::search(int i)
1454 {
1455 int nThreads = db->parThreads;
1456 oid_t oid = firstRow;
1457 dbRecord rec;
1458 int j;
1459 for (j = i; --j >= 0;) {
1460 db->getHeader(rec, oid);
1461 oid = rec.next;
1462 }
1463 while (oid != 0) {
1464 if (db->evaluateBoolean(query->tree, oid, table, cursor)) {
1465 selection[i].add(oid);
1466 }
1467 db->getHeader(rec, oid);
1468 oid = rec.next;
1469 for (j = nThreads; --j > 0 && oid != 0;) {
1470 db->getHeader(rec, oid);
1471 oid = rec.next;
1472 }
1473 }
1474 if (query->order != NULL) {
1475 selection[i].sort(db, query->order);
1476 }
1477 }
1478
1479 END_GIGABASE_NAMESPACE
1480
1481
1482
1483
1484
1485
1486
1487