1/************* BlkFil C++ Program Source Code File (.CPP) **************/
2/* PROGRAM NAME: BLKFIL */
3/* ------------- */
4/* Version 2.6 */
5/* */
6/* COPYRIGHT: */
7/* ---------- */
8/* (C) Copyright to the author Olivier BERTRAND 2004-2017 */
9/* */
10/* WHAT THIS PROGRAM DOES: */
11/* ----------------------- */
12/* This program is the implementation of block indexing classes. */
13/* */
14/***********************************************************************/
15
16/***********************************************************************/
17/* Include relevant MariaDB header file. */
18/***********************************************************************/
19#include "my_global.h"
20#include "sql_class.h"
21//#include "sql_time.h"
22
23#if defined(__WIN__)
24//#include <windows.h>
25#else // !__WIN__
26#include <string.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#endif // !__WIN__
30
31/***********************************************************************/
32/* Include application header files: */
33/***********************************************************************/
34#include "global.h" // global declarations
35#include "plgdbsem.h" // DB application declarations
36#include "xindex.h" // Key Index class declarations
37#include "filamtxt.h" // File access method dcls
38#include "tabdos.h" // TDBDOS and DOSCOL class dcls
39#include "array.h" // ARRAY classes dcls
40#include "blkfil.h" // Block Filter classes dcls
41
42/* ------------------------ Class BLOCKFILTER ------------------------ */
43
44/***********************************************************************/
45/* BLOCKFILTER constructor. */
46/***********************************************************************/
47BLOCKFILTER::BLOCKFILTER(PTDBDOS tdbp, int op)
48 {
49 Tdbp = tdbp;
50 Correl = FALSE;
51 Opc = op;
52 Opm = 0;
53 Result = 0;
54 } // end of BLOCKFILTER constructor
55
56/***********************************************************************/
57/* Make file output of BLOCKFILTER contents. */
58/***********************************************************************/
59void BLOCKFILTER::Printf(PGLOBAL, FILE *f, uint n)
60 {
61 char m[64];
62
63 memset(m, ' ', n); // Make margin string
64 m[n] = '\0';
65
66 fprintf(f, "%sBLOCKFILTER: at %p opc=%d opm=%d result=%d\n",
67 m, this, Opc, Opm, Result);
68 } // end of Printf
69
70/***********************************************************************/
71/* Make string output of BLOCKFILTER contents. */
72/***********************************************************************/
73void BLOCKFILTER::Prints(PGLOBAL, char *ps, uint z)
74 {
75 strncat(ps, "BlockFilter(s)", z);
76 } // end of Prints
77
78
79/* ---------------------- Class BLKFILLOG ---------------------------- */
80
81/***********************************************************************/
82/* BLKFILLOG constructor. */
83/***********************************************************************/
84BLKFILLOG::BLKFILLOG(PTDBDOS tdbp, int op, PBF *bfp, int n)
85 : BLOCKFILTER(tdbp, op)
86 {
87 N = n;
88 Fil = bfp;
89
90 for (int i = 0; i < N; i++)
91 if (Fil[i])
92 Correl |= Fil[i]->Correl;
93
94 } // end of BLKFILLOG constructor
95
96/***********************************************************************/
97/* Reset: this function is used only to check the existence of a */
98/* BLKFILIN block and have it reset its Bot value for sorted columns. */
99/***********************************************************************/
100void BLKFILLOG::Reset(PGLOBAL g)
101 {
102 for (int i = 0; i < N; i++)
103 if (Fil[i])
104 Fil[i]->Reset(g);
105
106 } // end of Reset
107
108/***********************************************************************/
109/* This function is used for block filter evaluation. We use here a */
110/* fuzzy logic between the values returned by evaluation blocks: */
111/* -2: the condition will be always false for the rest of the file. */
112/* -1: the condition will be false for the whole group. */
113/* 0: the condition may be true for some of the group values. */
114/* 1: the condition will be true for the whole group. */
115/* 2: the condition will be always true for the rest of the file. */
116/***********************************************************************/
117int BLKFILLOG::BlockEval(PGLOBAL g)
118 {
119 int i, rc;
120
121 for (i = 0; i < N; i++) {
122 // 0: Means some block filter value may be True
123 rc = (Fil[i]) ? Fil[i]->BlockEval(g) : 0;
124
125 if (!i)
126 Result = (Opc == OP_NOT) ? -rc : rc;
127 else switch (Opc) {
128 case OP_AND:
129 Result = MY_MIN(Result, rc);
130 break;
131 case OP_OR:
132 Result = MY_MAX(Result, rc);
133 break;
134 default:
135 // Should never happen
136 Result = 0;
137 return Result;
138 } // endswitch Opc
139
140 } // endfor i
141
142 return Result;
143 } // end of BlockEval
144
145/* ---------------------- Class BLKFILARI----------------------------- */
146
147/***********************************************************************/
148/* BLKFILARI constructor. */
149/***********************************************************************/
150BLKFILARI::BLKFILARI(PGLOBAL g, PTDBDOS tdbp, int op, PXOB *xp)
151 : BLOCKFILTER(tdbp, op)
152 {
153 Colp = (PDOSCOL)xp[0];
154
155 if (xp[1]->GetType() == TYPE_COLBLK) {
156 Cpx = (PCOL)xp[1]; // Subquery pseudo constant column
157 Correl = TRUE;
158 } else
159 Cpx = NULL;
160
161 Sorted = Colp->IsSorted() > 0;
162
163 // Don't remember why this was changed. Anyway it is no good for
164 // correlated subqueries because the Value must reflect changes
165 if (Cpx)
166 Valp = xp[1]->GetValue();
167 else
168 Valp = AllocateValue(g, xp[1]->GetValue());
169
170 } // end of BLKFILARI constructor
171
172/***********************************************************************/
173/* Reset: re-eval the constant value in the case of pseudo constant */
174/* column use in a correlated subquery. */
175/***********************************************************************/
176void BLKFILARI::Reset(PGLOBAL g)
177 {
178 if (Cpx) {
179 Cpx->Reset();
180 Cpx->Eval(g);
181 MakeValueBitmap(); // Does nothing for class BLKFILARI
182 } // endif Cpx
183
184 } // end of Reset
185
186/***********************************************************************/
187/* Evaluate block filter for arithmetic operators. */
188/***********************************************************************/
189int BLKFILARI::BlockEval(PGLOBAL)
190 {
191 int mincmp, maxcmp, n;
192
193#if defined(_DEBUG)
194 assert (Colp->IsClustered());
195#endif
196
197 n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
198 mincmp = Colp->GetMin()->CompVal(Valp, n);
199 maxcmp = Colp->GetMax()->CompVal(Valp, n);
200
201 switch (Opc) {
202 case OP_EQ:
203 case OP_NE:
204 if (mincmp < 0) // Means minval > Val
205 Result = (Sorted) ? -2 : -1;
206 else if (maxcmp > 0) // Means maxval < Val
207 Result = -1;
208 else if (!mincmp && !maxcmp) // minval = maxval = val
209 Result = 1;
210 else
211 Result = 0;
212
213 break;
214 case OP_GT:
215 case OP_LE:
216 if (mincmp < 0) // minval > Val
217 Result = (Sorted) ? 2 : 1;
218 else if (maxcmp < 0) // maxval > Val
219 Result = 0;
220 else // maxval <= Val
221 Result = -1;
222
223 break;
224 case OP_GE:
225 case OP_LT:
226 if (mincmp <= 0) // minval >= Val
227 Result = (Sorted) ? 2 : 1;
228 else if (maxcmp <= 0) // Maxval >= Val
229 Result = 0;
230 else // Maxval < Val
231 Result = -1;
232
233 break;
234 } // endswitch Opc
235
236 switch (Opc) {
237 case OP_NE:
238 case OP_LE:
239 case OP_LT:
240 Result = -Result;
241 break;
242 } // endswitch Opc
243
244 if (trace(1))
245 htrc("BlockEval: op=%d n=%d rc=%d\n", Opc, n, Result);
246
247 return Result;
248 } // end of BlockEval
249
250/* ---------------------- Class BLKFILAR2----------------------------- */
251
252/***********************************************************************/
253/* BLKFILAR2 constructor. */
254/***********************************************************************/
255BLKFILAR2::BLKFILAR2(PGLOBAL g, PTDBDOS tdbp, int op, PXOB *xp)
256 : BLKFILARI(g, tdbp, op, xp)
257 {
258 MakeValueBitmap();
259 } // end of BLKFILAR2 constructor
260
261/***********************************************************************/
262/* MakeValueBitmap: Set the constant value bit map. It can be void */
263/* if the constant value is not in the column distinct values list. */
264/***********************************************************************/
265void BLKFILAR2::MakeValueBitmap(void)
266 {
267 int i; // ndv = Colp->GetNdv();
268 bool found = FALSE;
269 PVBLK dval = Colp->GetDval();
270
271 assert(dval);
272
273 /*********************************************************************/
274 /* Here we cannot use Find because we must get the index */
275 /* of where to put the value if it is not found in the array. */
276 /* This is needed by operators other than OP_EQ or OP_NE. */
277 /*********************************************************************/
278 found = dval->Locate(Valp, i);
279
280 /*********************************************************************/
281 /* Set the constant value bitmap. The bitmaps are really matching */
282 /* the OP_EQ, OP_LE, and OP_LT operator but are also used for the */
283 /* other operators for which the Result will be inverted. */
284 /* The reason the bitmaps are not directly complemented for them is */
285 /* to be able to test easily the cases of sorted columns with Bxp, */
286 /* and the case of a void bitmap, which happens if the constant */
287 /* value is not in the column distinct values list. */
288 /*********************************************************************/
289 if (found) {
290 Bmp = 1 << i; // Bit of the found value
291 Bxp = Bmp - 1; // All smaller values
292
293 if (Opc != OP_LT && Opc != OP_GE)
294 Bxp |= Bmp; // Found value must be included
295
296 } else {
297 Bmp = 0;
298 Bxp = (1 << i) - 1;
299 } // endif found
300
301 if (!(Opc == OP_EQ || Opc == OP_NE))
302 Bmp = Bxp;
303
304 } // end of MakeValueBitmap
305
306/***********************************************************************/
307/* Evaluate XDB2 block filter for arithmetic operators. */
308/***********************************************************************/
309int BLKFILAR2::BlockEval(PGLOBAL)
310 {
311#if defined(_DEBUG)
312 assert (Colp->IsClustered());
313#endif
314
315 int n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
316 uint bkmp = *(uint*)Colp->GetBmap()->GetValPtr(n);
317 uint bres = Bmp & bkmp;
318
319 // Set result as if Opc were OP_EQ, OP_LT, or OP_LE
320 if (!bres) {
321 if (!Bmp)
322 Result = -2; // No good block in the table file
323 else if (!Sorted)
324 Result = -1; // No good values in this block
325 else // Sorted column, test for no more good blocks in file
326 Result = (Bxp & bkmp) ? -1 : -2;
327
328 } else
329 // Test whether all block values are good or only some ones
330 Result = (bres == bkmp) ? 1 : 0;
331
332 // For OP_NE, OP_GE, and OP_GT the result must be inverted.
333 switch (Opc) {
334 case OP_NE:
335 case OP_GE:
336 case OP_GT:
337 Result = -Result;
338 break;
339 } // endswitch Opc
340
341 if (trace(1))
342 htrc("BlockEval2: op=%d n=%d rc=%d\n", Opc, n, Result);
343
344 return Result;
345 } // end of BlockEval
346
347/* ---------------------- Class BLKFILMR2----------------------------- */
348
349/***********************************************************************/
350/* BLKFILMR2 constructor. */
351/***********************************************************************/
352BLKFILMR2::BLKFILMR2(PGLOBAL g, PTDBDOS tdbp, int op, PXOB *xp)
353 : BLKFILARI(g, tdbp, op, xp)
354 {
355 Nbm = Colp->GetNbm();
356 Bmp = (uint*)PlugSubAlloc(g, NULL, Nbm * sizeof(uint));
357 Bxp = (uint*)PlugSubAlloc(g, NULL, Nbm * sizeof(uint));
358 MakeValueBitmap();
359 } // end of BLKFILMR2 constructor
360
361/***********************************************************************/
362/* MakeValueBitmap: Set the constant value bit map. It can be void */
363/* if the constant value is not in the column distinct values list. */
364/***********************************************************************/
365void BLKFILMR2::MakeValueBitmap(void)
366 {
367 int i; // ndv = Colp->GetNdv();
368 bool found = FALSE, noteq = !(Opc == OP_EQ || Opc == OP_NE);
369 PVBLK dval = Colp->GetDval();
370
371 assert(dval);
372
373 for (i = 0; i < Nbm; i++)
374 Bmp[i] = Bxp[i] = 0;
375
376 /*********************************************************************/
377 /* Here we cannot use Find because we must get the index */
378 /* of where to put the value if it is not found in the array. */
379 /* This is needed by operators other than OP_EQ or OP_NE. */
380 /*********************************************************************/
381 found = dval->Locate(Valp, i);
382
383 /*********************************************************************/
384 /* For bitmaps larger than a ULONG, we must know where Bmp and Bxp */
385 /* are positioned in the ULONG bit map block array. */
386 /*********************************************************************/
387 N = i / MAXBMP;
388 i %= MAXBMP;
389
390 /*********************************************************************/
391 /* Set the constant value bitmaps. The bitmaps are really matching */
392 /* the OP_EQ, OP_LE, and OP_LT operator but are also used for the */
393 /* other operators for which the Result will be inverted. */
394 /* The reason the bitmaps are not directly complemented for them is */
395 /* to be able to easily test the cases of sorted columns with Bxp, */
396 /* and the case of a void bitmap, which happens if the constant */
397 /* value is not in the column distinct values list. */
398 /*********************************************************************/
399 if (found) {
400 Bmp[N] = 1 << i;
401 Bxp[N] = Bmp[N] - 1;
402
403 if (Opc != OP_LT && Opc != OP_GE)
404 Bxp[N] |= Bmp[N]; // Found value must be included
405
406 } else
407 Bxp[N] = (1 << i) - 1;
408
409 if (noteq)
410 Bmp[N] = Bxp[N];
411
412 Void = !Bmp[N]; // There are no good values in the file
413
414 for (i = 0; i < N; i++) {
415 Bxp[i] = ~0;
416
417 if (noteq)
418 Bmp[i] = Bxp[i];
419
420 Void = Void && !Bmp[i];
421 } // endfor i
422
423 if (!Bmp[N] && !Bxp[N])
424 N--;
425
426 } // end of MakeValueBitmap
427
428/***********************************************************************/
429/* Evaluate XDB2 block filter for arithmetic operators. */
430/***********************************************************************/
431int BLKFILMR2::BlockEval(PGLOBAL)
432 {
433#if defined(_DEBUG)
434 assert (Colp->IsClustered());
435#endif
436
437 int i, n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
438 bool fnd = FALSE, all = TRUE, gt = TRUE;
439 uint bres;
440 uint *bkmp = (uint*)Colp->GetBmap()->GetValPtr(n * Nbm);
441
442 // Set result as if Opc were OP_EQ, OP_LT, or OP_LE
443 for (i = 0; i < Nbm; i++)
444 if (i <= N) {
445 if ((bres = Bmp[i] & bkmp[i]))
446 fnd = TRUE; // Some good value(s) found in the block
447
448 if (bres != bkmp[i])
449 all = FALSE; // Not all block values are good
450
451 if (Bxp[i] & bkmp[i])
452 gt = FALSE; // Not all block values are > good value(s)
453
454 } else if (bkmp[i]) {
455 all = FALSE;
456 break;
457 } // endif's
458
459 if (!fnd) {
460 if (Void || (gt && Sorted))
461 Result = -2; // No (more) good block in file
462 else
463 Result = -1; // No good values in this block
464
465 } else
466 Result = (all) ? 1 : 0; // All block values are good
467
468 // For OP_NE, OP_GE, and OP_GT the result must be inverted.
469 switch (Opc) {
470 case OP_NE:
471 case OP_GE:
472 case OP_GT:
473 Result = -Result;
474 break;
475 } // endswitch Opc
476
477 if (trace(1))
478 htrc("BlockEval2: op=%d n=%d rc=%d\n", Opc, n, Result);
479
480 return Result;
481 } // end of BlockEval
482
483/***********************************************************************/
484/* BLKSPCARI constructor. */
485/***********************************************************************/
486BLKSPCARI::BLKSPCARI(PTDBDOS tdbp, int op, PXOB *xp, int bsize)
487 : BLOCKFILTER(tdbp, op)
488 {
489 if (xp[1]->GetType() == TYPE_COLBLK) {
490 Cpx = (PCOL)xp[1]; // Subquery pseudo constant column
491 Correl = TRUE;
492 } else
493 Cpx = NULL;
494
495 Valp = xp[1]->GetValue();
496 Val = (int)xp[1]->GetValue()->GetIntValue();
497 Bsize = bsize;
498 } // end of BLKFILARI constructor
499
500/***********************************************************************/
501/* Reset: re-eval the constant value in the case of pseudo constant */
502/* column use in a correlated subquery. */
503/***********************************************************************/
504void BLKSPCARI::Reset(PGLOBAL g)
505 {
506 if (Cpx) {
507 Cpx->Reset();
508 Cpx->Eval(g);
509 Val = (int)Valp->GetIntValue();
510 } // endif Cpx
511
512 } // end of Reset
513
514/***********************************************************************/
515/* Evaluate block filter for arithmetic operators (ROWID) */
516/***********************************************************************/
517int BLKSPCARI::BlockEval(PGLOBAL)
518 {
519 int mincmp, maxcmp, n, m;
520
521 n = Tdbp->GetCurBlk();
522 m = n * Bsize + 1; // Minimum Rowid value for this block
523 mincmp = (Val > m) ? 1 : (Val < m) ? (-1) : 0;
524 m = (n + 1) * Bsize; // Maximum Rowid value for this block
525 maxcmp = (Val > m) ? 1 : (Val < m) ? (-1) : 0;
526
527 switch (Opc) {
528 case OP_EQ:
529 case OP_NE:
530 if (mincmp < 0) // Means minval > Val
531 Result = -2; // Always sorted
532 else if (maxcmp > 0) // Means maxval < Val
533 Result = -1;
534 else if (!mincmp && !maxcmp) // minval = maxval = val
535 Result = 1;
536 else
537 Result = 0;
538
539 break;
540 case OP_GT:
541 case OP_LE:
542 if (mincmp < 0) // minval > Val
543 Result = 2; // Always sorted
544 else if (maxcmp < 0) // maxval > Val
545 Result = 0;
546 else // maxval <= Val
547 Result = -1;
548
549 break;
550 case OP_GE:
551 case OP_LT:
552 if (mincmp <= 0) // minval >= Val
553 Result = 2; // Always sorted
554 else if (maxcmp <= 0) // Maxval >= Val
555 Result = 0;
556 else // Maxval < Val
557 Result = -1;
558
559 break;
560 } // endswitch Opc
561
562 switch (Opc) {
563 case OP_NE:
564 case OP_LE:
565 case OP_LT:
566 Result = -Result;
567 break;
568 } // endswitch Opc
569
570 if (trace(1))
571 htrc("BlockEval: op=%d n=%d rc=%d\n", Opc, n, Result);
572
573 return Result;
574 } // end of BlockEval
575
576/* ------------------------ Class BLKFILIN --------------------------- */
577
578/***********************************************************************/
579/* BLKFILIN constructor. */
580/***********************************************************************/
581BLKFILIN::BLKFILIN(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp)
582 : BLOCKFILTER(tdbp, op)
583 {
584 if (op == OP_IN) {
585 Opc = OP_EQ;
586 Opm = 1;
587 } else {
588 Opc = op;
589 Opm = opm;
590 } // endif op
591
592 Colp = (PDOSCOL)xp[0];
593 Arap = (PARRAY)xp[1];
594 Type = Arap->GetResultType();
595
596 if (Colp->GetResultType() != Type) {
597 sprintf(g->Message, "BLKFILIN: %s", MSG(VALTYPE_NOMATCH));
598 throw g->Message;
599 } else if (Colp->GetValue()->IsCi())
600 Arap->SetPrecision(g, 1); // Case insensitive
601
602 Sorted = Colp->IsSorted() > 0;
603 } // end of BLKFILIN constructor
604
605/***********************************************************************/
606/* Reset: have the sorted array reset its Bot value to -1 (bottom). */
607/***********************************************************************/
608void BLKFILIN::Reset(PGLOBAL)
609 {
610 Arap->Reset();
611// MakeValueBitmap(); // Does nothing for class BLKFILIN
612 } // end of Reset
613
614/***********************************************************************/
615/* Evaluate block filter for a IN operator on a constant array. */
616/* Note: here we need to use the GetValPtrEx function to get a zero */
617/* ended string in case of string argument. This is because the ARRAY */
618/* can have a different width than the char column. */
619/***********************************************************************/
620int BLKFILIN::BlockEval(PGLOBAL g)
621 {
622 int n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
623 void *minp = Colp->GetMin()->GetValPtrEx(n);
624 void *maxp = Colp->GetMax()->GetValPtrEx(n);
625
626 Result = Arap->BlockTest(g, Opc, Opm, minp, maxp, Sorted);
627 return Result;
628 } // end of BlockEval
629
630/* ------------------------ Class BLKFILIN2 -------------------------- */
631
632/***********************************************************************/
633/* BLKFILIN2 constructor. */
634/* New version that takes care of all operators and modificators. */
635/* It is also ready to handle the case of correlated sub-selects. */
636/***********************************************************************/
637BLKFILIN2::BLKFILIN2(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp)
638 : BLKFILIN(g, tdbp, op, opm, xp)
639 {
640 Nbm = Colp->GetNbm();
641 Valp = AllocateValue(g, Colp->GetValue());
642 Invert = (Opc == OP_NE || Opc == OP_GE || Opc ==OP_GT);
643 Bmp = (uint*)PlugSubAlloc(g, NULL, Nbm * sizeof(uint));
644 Bxp = (uint*)PlugSubAlloc(g, NULL, Nbm * sizeof(uint));
645 MakeValueBitmap();
646 } // end of BLKFILIN2 constructor
647
648/***********************************************************************/
649/* MakeValueBitmap: Set the constant values bit map. It can be void */
650/* if the constant values are not in the column distinct values list. */
651/* The bitmaps are prepared for the EQ, LE, and LT operators and */
652/* takes care of the ALL and ANY modificators. If the operators are */
653/* NE, GE, or GT the modificator is inverted and the result will be. */
654/***********************************************************************/
655void BLKFILIN2::MakeValueBitmap(void)
656 {
657 int i, k, n, ndv = Colp->GetNdv();
658 bool found, noteq = !(Opc == OP_EQ || Opc == OP_NE);
659 bool all = (!Invert) ? (Opm == 2) : (Opm != 2);
660 uint btp;
661 PVBLK dval = Colp->GetDval();
662
663 N = -1;
664
665 // Take care of special cases
666 if (!(n = Arap->GetNval())) {
667 // Return TRUE for ALL because it means that there are no item that
668 // does not verify the condition, which is true indeed.
669 // Return FALSE for ANY because TRUE means that there is at least
670 // one item that verifies the condition, which is false.
671 Result = (Opm == 2) ? 2 : -2;
672 return;
673 } else if (!noteq && all && n > 1) {
674 // An item cannot be equal to all different values
675 // or an item is always unequal to any different values
676 Result = (Opc == OP_EQ) ? -2 : 2;
677 return;
678 } // endif's
679
680 for (i = 0; i < Nbm; i++)
681 Bmp[i] = Bxp[i] = 0;
682
683 for (k = 0; k < n; k++) {
684 Arap->GetNthValue(Valp, k);
685 found = dval->Locate(Valp, i);
686 N = i / MAXBMP;
687 btp = 1 << (i % MAXBMP);
688
689 if (found)
690 Bmp[N] |= btp;
691
692 // For LT and LE if ALL the condition applies to the smallest item
693 // if ANY it applies to the largest item. In the case of EQ we come
694 // here only if ANY or if n == 1, so it does applies to the largest.
695 if ((!k && all) || (k == n - 1 && !all)) {
696 Bxp[N] = btp - 1;
697
698 if (found && Opc != OP_LT && Opc != OP_GE)
699 Bxp[N] |= btp; // Found value must be included
700
701 } // endif k, opm
702
703 } // endfor k
704
705 if (noteq)
706 Bmp[N] = Bxp[N];
707
708 Void = !Bmp[N]; // There are no good values in the file
709
710 for (i = 0; i < N; i++) {
711 Bxp[i] = ~0;
712
713 if (noteq) {
714 Bmp[i] = Bxp[i];
715 Void = FALSE;
716 } // endif noteq
717
718 } // endfor i
719
720 if (!Bmp[N] && !Bxp[N]) {
721 if (--N < 0)
722 // All array values are smaller than block values
723 Result = (Invert) ? 2 : -2;
724
725 } else if (N == Nbm - 1 && (signed)Bmp[N] == (1 << (ndv % MAXBMP)) - 1) {
726 // Condition will be always TRUE or FALSE for the whole file
727 Result = (Invert) ? -2 : 2;
728 N = -1;
729 } // endif's
730
731 } // end of MakeValueBitmap
732
733/***********************************************************************/
734/* Evaluate block filter for set operators on a constant array. */
735/* Note: here we need to use the GetValPtrEx function to get a zero */
736/* ended string in case of string argument. This is because the ARRAY */
737/* can have a different width than the char column. */
738/***********************************************************************/
739int BLKFILIN2::BlockEval(PGLOBAL)
740 {
741 if (N < 0)
742 return Result; // Was set in MakeValueBitmap
743
744 int i, n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
745 bool fnd = FALSE, all = TRUE, gt = TRUE;
746 uint bres;
747 uint *bkmp = (uint*)Colp->GetBmap()->GetValPtr(n * Nbm);
748
749 // Set result as if Opc were OP_EQ, OP_LT, or OP_LE
750 // The difference between ALL or ANY was handled in MakeValueBitmap
751 for (i = 0; i < Nbm; i++)
752 if (i <= N) {
753 if ((bres = Bmp[i] & bkmp[i]))
754 fnd = TRUE;
755
756 if (bres != bkmp[i])
757 all = FALSE;
758
759 if (Bxp[i] & bkmp[i])
760 gt = FALSE;
761
762 } else if (bkmp[i]) {
763 all = FALSE;
764 break;
765 } // endif's
766
767 if (!fnd) {
768 if (Void || (Sorted && gt))
769 Result = -2; // No more good block in file
770 else
771 Result = -1; // No good values in this block
772
773 } else if (all)
774 Result = 1; // All block values are good
775 else
776 Result = 0; // Block contains some good values
777
778 // For OP_NE, OP_GE, and OP_GT the result must be inverted.
779 switch (Opc) {
780 case OP_NE:
781 case OP_GE:
782 case OP_GT:
783 Result = -Result;
784 break;
785 } // endswitch Opc
786
787 return Result;
788 } // end of BlockEval
789
790#if 0
791/***********************************************************************/
792/* BLKFILIN2 constructor. */
793/***********************************************************************/
794BLKFILIN2::BLKFILIN2(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp)
795 : BLKFILIN(g, tdbp, op, opm, xp)
796 {
797 // Currently, bitmap matching is only implemented for the IN operator
798 if (!(Bitmap = (op == OP_IN || (op == OP_EQ && opm != 2)))) {
799 Nbm = Colp->GetNbm();
800 N = 0;
801 return; // Revert to standard minmax method
802 } // endif minmax
803
804 int i, n;
805 ULONG btp;
806 PVAL valp = AllocateValue(g, Colp->GetValue());
807 PVBLK dval = Colp->GetDval();
808
809 Nbm = Colp->GetNbm();
810 N = -1;
811 Bmp = (PULONG)PlugSubAlloc(g, NULL, Nbm * sizeof(ULONG));
812 Bxp = (PULONG)PlugSubAlloc(g, NULL, Nbm * sizeof(ULONG));
813
814 for (i = 0; i < Nbm; i++)
815 Bmp[i] = Bxp[i] = 0;
816
817 for (n = 0; n < Arap->GetNval(); n++) {
818 Arap->GetNthValue(valp, n);
819
820 if ((i = dval->Find(valp)) >= 0)
821 Bmp[i / MAXBMP] |= 1 << (i % MAXBMP);
822
823 } // endfor n
824
825 for (i = Nbm - 1; i >= 0; i--)
826 if (Bmp[i]) {
827 for (btp = Bmp[i]; btp; btp >>= 1)
828 Bxp[i] |= btp;
829
830 for (N = i--; i >= 0; i--)
831 Bxp[i] = ~0;
832
833 break;
834 } // endif Bmp
835
836 } // end of BLKFILIN2 constructor
837
838/***********************************************************************/
839/* Evaluate block filter for a IN operator on a constant array. */
840/* Note: here we need to use the GetValPtrEx function to get a zero */
841/* ended string in case of string argument. This is because the ARRAY */
842/* can have a different width than the char column. */
843/***********************************************************************/
844int BLKFILIN2::BlockEval(PGLOBAL g)
845 {
846 if (N < 0)
847 return -2; // IN list contains no good values
848
849 int i, n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
850 bool fnd = FALSE, all = TRUE, gt = TRUE;
851 ULONG bres;
852 PULONG bkmp = (PULONG)Colp->GetBmap()->GetValPtr(n * Nbm);
853
854 if (Bitmap) {
855 // For IN operator use the bitmap method
856 for (i = 0; i < Nbm; i++)
857 if (i <= N) {
858 if ((bres = Bmp[i] & bkmp[i]))
859 fnd = TRUE;
860
861 if (bres != bkmp[i])
862 all = FALSE;
863
864 if (Bxp[i] & bkmp[i])
865 gt = FALSE;
866
867 } else if (bkmp[i]) {
868 all = FALSE;
869 break;
870 } // endif's
871
872 if (!fnd) {
873 if (Sorted && gt)
874 Result = -2; // No more good block in file
875 else
876 Result = -1; // No good values in this block
877
878 } else if (all)
879 Result = 1; // All block values are good
880 else
881 Result = 0; // Block contains some good values
882
883 } else {
884 // For other than IN operators, revert to standard minmax method
885 int n = 0, ndv = Colp->GetNdv();
886 void *minp = NULL;
887 void *maxp = NULL;
888 ULONG btp;
889 PVBLK dval = Colp->GetDval();
890
891 for (i = 0; i < Nbm; i++)
892 for (btp = 1; btp && n < ndv; btp <<= 1, n++)
893 if (btp & bkmp[i]) {
894 if (!minp)
895 minp = dval->GetValPtrEx(n);
896
897 maxp = dval->GetValPtrEx(n);
898 } // endif btp
899
900 Result = Arap->BlockTest(g, Opc, Opm, minp, maxp, Colp->IsSorted());
901 } // endif Bitmap
902
903 return Result;
904 } // end of BlockEval
905#endif // 0
906
907/* ------------------------ Class BLKSPCIN --------------------------- */
908
909/***********************************************************************/
910/* BLKSPCIN constructor. */
911/***********************************************************************/
912BLKSPCIN::BLKSPCIN(PGLOBAL, PTDBDOS tdbp, int op, int opm,
913 PXOB *xp, int bsize)
914 : BLOCKFILTER(tdbp, op)
915 {
916 if (op == OP_IN) {
917 Opc = OP_EQ;
918 Opm = 1;
919 } else
920 Opm = opm;
921
922 Arap = (PARRAY)xp[1];
923#if defined(_DEBUG)
924 assert (Opm);
925 assert (Arap->GetResultType() == TYPE_INT);
926#endif
927 Bsize = bsize;
928 } // end of BLKSPCIN constructor
929
930/***********************************************************************/
931/* Reset: have the sorted array reset its Bot value to -1 (bottom). */
932/***********************************************************************/
933void BLKSPCIN::Reset(PGLOBAL)
934 {
935 Arap->Reset();
936 } // end of Reset
937
938/***********************************************************************/
939/* Evaluate block filter for a IN operator on a constant array. */
940/***********************************************************************/
941int BLKSPCIN::BlockEval(PGLOBAL g)
942 {
943 int n = Tdbp->GetCurBlk();
944 int minrow = n * Bsize + 1; // Minimum Rowid value for this block
945 int maxrow = (n + 1) * Bsize; // Maximum Rowid value for this block
946
947 Result = Arap->BlockTest(g, Opc, Opm, &minrow, &maxrow, TRUE);
948 return Result;
949 } // end of BlockEval
950
951/* ------------------------------------------------------------------- */
952
953#if 0
954/***********************************************************************/
955/* Implementation of the BLOCKINDEX class. */
956/***********************************************************************/
957BLOCKINDEX::BLOCKINDEX(PBX nx, PDOSCOL cp, PKXBASE kp)
958 {
959 Next = nx;
960 Tdbp = (cp) ? (PTDBDOS)cp->GetTo_Tdb() : NULL;
961 Colp = cp;
962 Kxp = kp;
963 Type = (cp) ? cp->GetResultType() : TYPE_ERROR;
964 Sorted = (cp) ? cp->IsSorted() > 0 : FALSE;
965 Result = 0;
966 } // end of BLOCKINDEX constructor
967
968/***********************************************************************/
969/* Reset Bot and Top values of optimized Kindex blocks. */
970/***********************************************************************/
971void BLOCKINDEX::Reset(void)
972 {
973 if (Next)
974 Next->Reset();
975
976 Kxp->Reset();
977 } // end of Reset
978
979/***********************************************************************/
980/* Evaluate block indexing test. */
981/***********************************************************************/
982int BLOCKINDEX::BlockEval(PGLOBAL g)
983 {
984#if defined(_DEBUG)
985 assert (Tdbp && Colp);
986#endif
987 int n = Tdbp->GetCurBlk();
988 void *minp = Colp->GetMin()->GetValPtr(n);
989 void *maxp = Colp->GetMax()->GetValPtr(n);
990
991 Result = Kxp->BlockTest(g, minp, maxp, Type, Sorted);
992 return Result;
993 } // end of BlockEval
994
995/***********************************************************************/
996/* Make file output of BLOCKINDEX contents. */
997/***********************************************************************/
998void BLOCKINDEX::Printf(PGLOBAL g, FILE *f, UINT n)
999 {
1000 char m[64];
1001
1002 memset(m, ' ', n); // Make margin string
1003 m[n] = '\0';
1004
1005 fprintf(f, "%sBLOCKINDEX: at %p next=%p col=%s kxp=%p result=%d\n",
1006 m, this, Next, (Colp) ? Colp->GetName() : "Rowid", Kxp, Result);
1007
1008 if (Next)
1009 Next->Printf(g, f, n);
1010
1011 } // end of Printf
1012
1013/***********************************************************************/
1014/* Make string output of BLOCKINDEX contents. */
1015/***********************************************************************/
1016void BLOCKINDEX::Prints(PGLOBAL g, char *ps, UINT z)
1017 {
1018 strncat(ps, "BlockIndex(es)", z);
1019 } // end of Prints
1020
1021/* ------------------------------------------------------------------- */
1022
1023/***********************************************************************/
1024/* Implementation of the BLOCKINDX2 class. */
1025/***********************************************************************/
1026BLOCKINDX2::BLOCKINDX2(PBX nx, PDOSCOL cp, PKXBASE kp)
1027 : BLOCKINDEX(nx, cp, kp)
1028 {
1029 Nbm = Colp->GetNbm();
1030 Dval = Colp->GetDval();
1031 Bmap = Colp->GetBmap();
1032#if defined(_DEBUG)
1033 assert(Dval && Bmap);
1034#endif
1035 } // end of BLOCKINDX2 constructor
1036
1037/***********************************************************************/
1038/* Evaluate block indexing test. */
1039/***********************************************************************/
1040int BLOCKINDX2::BlockEval(PGLOBAL g)
1041 {
1042 int n = Tdbp->GetCurBlk();
1043 PUINT bmp = (PUINT)Bmap->GetValPtr(n * Nbm);
1044
1045 Result = Kxp->BlockTst2(g, Dval, bmp, Nbm, Type, Sorted);
1046 return Result;
1047 } // end of BlockEval
1048
1049/* ------------------------------------------------------------------- */
1050
1051/***********************************************************************/
1052/* Implementation of the BLKSPCINDX class. */
1053/***********************************************************************/
1054BLKSPCINDX::BLKSPCINDX(PBX nx, PTDBDOS tp, PKXBASE kp, int bsize)
1055 : BLOCKINDEX(nx, NULL, kp)
1056 {
1057 Tdbp = tp;
1058 Bsize = bsize;
1059 Type = TYPE_INT;
1060 Sorted = TRUE;
1061 } // end of BLKSPCINDX constructor
1062
1063/***********************************************************************/
1064/* Evaluate block indexing test. */
1065/***********************************************************************/
1066int BLKSPCINDX::BlockEval(PGLOBAL g)
1067 {
1068 int n = Tdbp->GetCurBlk();
1069 int minrow = n * Bsize + 1; // Minimum Rowid value for this block
1070 int maxrow = (n + 1) * Bsize; // Maximum Rowid value for this block
1071
1072 Result = Kxp->BlockTest(g, &minrow, &maxrow, TYPE_INT, TRUE);
1073 return Result;
1074 } // end of BlockEval
1075#endif // 0
1076