mariadb/storage/connect/blkfil.cpp
Olivier Bertrand 56e2771321 1) Handling string memory allocation with a new STRING class. This is only
the beginning. Defining the STRING class and begining to use it (MYSQL)

2) Change the xtrace, use_tempfile and exact_info connect variables from
   GLOBAL to SESSION. Remaining GLOBAL variables have been made readonly.

3) Take care of LEX_STRING variables. The .str should not be regarded as
   allways being 0 terminated. This is handled by the Strz functions that
   make sure to return 0 terminated strings.

Bug fix:
- When inserting in MYSQL table with special column(s) a query such as:
insert into t2 values(0,4,'new04'),(0,5,'new05');
failed saying: column id (the special column) not found in t2.
It is now accepted but must be counted in values (these 0 are ignored)
- ROWID was returning row numbers based 0. Now it is from base 1.

modified:
  storage/connect/array.cpp
  storage/connect/blkfil.cpp
  storage/connect/colblk.cpp
  storage/connect/connect.cc
  storage/connect/filamap.cpp
  storage/connect/filamdbf.cpp
  storage/connect/filamfix.cpp
  storage/connect/filamtxt.cpp
  storage/connect/filamvct.cpp
  storage/connect/filamzip.cpp
  storage/connect/filamzip.h
  storage/connect/filter.cpp
  storage/connect/global.h
  storage/connect/ha_connect.cc
  storage/connect/ha_connect.h
  storage/connect/libdoc.cpp
  storage/connect/mycat.cc
  storage/connect/myconn.cpp
  storage/connect/odbconn.cpp
  storage/connect/plgdbutl.cpp
  storage/connect/plugutil.c
  storage/connect/reldef.cpp
  storage/connect/tabcol.cpp
  storage/connect/tabdos.cpp
  storage/connect/tabfix.cpp
  storage/connect/tabfmt.cpp
  storage/connect/table.cpp
  storage/connect/tabmul.cpp
  storage/connect/tabmysql.cpp
  storage/connect/tabmysql.h
  storage/connect/taboccur.cpp
  storage/connect/tabodbc.cpp
  storage/connect/tabpivot.cpp
  storage/connect/tabsys.cpp
  storage/connect/tabtbl.cpp
  storage/connect/tabutil.cpp
  storage/connect/tabvct.cpp
  storage/connect/tabwmi.cpp
  storage/connect/tabwmi.h
  storage/connect/tabxcl.cpp
  storage/connect/tabxml.cpp
  storage/connect/user_connect.cc
  storage/connect/valblk.cpp
  storage/connect/value.cpp
  storage/connect/value.h
  storage/connect/xindex.cpp
  storage/connect/xobject.cpp
  storage/connect/xobject.h
  storage/connect/xtable.h
2014-10-21 17:29:51 +02:00

1075 lines
35 KiB
C++

/************* BlkFil C++ Program Source Code File (.CPP) **************/
/* PROGRAM NAME: BLKFIL */
/* ------------- */
/* Version 2.5 */
/* */
/* COPYRIGHT: */
/* ---------- */
/* (C) Copyright to the author Olivier BERTRAND 2004-2014 */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
/* This program is the implementation of block indexing classes. */
/* */
/***********************************************************************/
/***********************************************************************/
/* Include relevant MariaDB header file. */
/***********************************************************************/
#include "my_global.h"
#include "sql_class.h"
//#include "sql_time.h"
#if defined(WIN32)
//#include <windows.h>
#else // !WIN32
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#endif // !WIN32
/***********************************************************************/
/* Include application header files: */
/***********************************************************************/
#include "global.h" // global declarations
#include "plgdbsem.h" // DB application declarations
#include "xindex.h" // Key Index class declarations
#include "filamtxt.h" // File access method dcls
#include "tabdos.h" // TDBDOS and DOSCOL class dcls
#include "array.h" // ARRAY classes dcls
#include "blkfil.h" // Block Filter classes dcls
/* ------------------------ Class BLOCKFILTER ------------------------ */
/***********************************************************************/
/* BLOCKFILTER constructor. */
/***********************************************************************/
BLOCKFILTER::BLOCKFILTER(PTDBDOS tdbp, int op)
{
Tdbp = tdbp;
Correl = FALSE;
Opc = op;
Opm = 0;
Result = 0;
} // end of BLOCKFILTER constructor
/***********************************************************************/
/* Make file output of BLOCKFILTER contents. */
/***********************************************************************/
void BLOCKFILTER::Print(PGLOBAL g, FILE *f, uint n)
{
char m[64];
memset(m, ' ', n); // Make margin string
m[n] = '\0';
fprintf(f, "%sBLOCKFILTER: at %p opc=%d opm=%d result=%d\n",
m, this, Opc, Opm, Result);
} // end of Print
/***********************************************************************/
/* Make string output of BLOCKFILTER contents. */
/***********************************************************************/
void BLOCKFILTER::Print(PGLOBAL g, char *ps, uint z)
{
strncat(ps, "BlockFilter(s)", z);
} // end of Print
/* ---------------------- Class BLKFILLOG ---------------------------- */
/***********************************************************************/
/* BLKFILLOG constructor. */
/***********************************************************************/
BLKFILLOG::BLKFILLOG(PTDBDOS tdbp, int op, PBF *bfp, int n)
: BLOCKFILTER(tdbp, op)
{
N = n;
Fil = bfp;
for (int i = 0; i < N; i++)
if (Fil[i])
Correl |= Fil[i]->Correl;
} // end of BLKFILLOG constructor
/***********************************************************************/
/* Reset: this function is used only to check the existence of a */
/* BLKFILIN block and have it reset its Bot value for sorted columns. */
/***********************************************************************/
void BLKFILLOG::Reset(PGLOBAL g)
{
for (int i = 0; i < N; i++)
if (Fil[i])
Fil[i]->Reset(g);
} // end of Reset
/***********************************************************************/
/* This function is used for block filter evaluation. We use here a */
/* fuzzy logic between the values returned by evaluation blocks: */
/* -2: the condition will be always false for the rest of the file. */
/* -1: the condition will be false for the whole group. */
/* 0: the condition may be true for some of the group values. */
/* 1: the condition will be true for the whole group. */
/* 2: the condition will be always true for the rest of the file. */
/***********************************************************************/
int BLKFILLOG::BlockEval(PGLOBAL g)
{
int i, rc;
for (i = 0; i < N; i++) {
// 0: Means some block filter value may be True
rc = (Fil[i]) ? Fil[i]->BlockEval(g) : 0;
if (!i)
Result = (Opc == OP_NOT) ? -rc : rc;
else switch (Opc) {
case OP_AND:
Result = MY_MIN(Result, rc);
break;
case OP_OR:
Result = MY_MAX(Result, rc);
break;
default:
// Should never happen
Result = 0;
return Result;
} // endswitch Opc
} // endfor i
return Result;
} // end of BlockEval
/* ---------------------- Class BLKFILARI----------------------------- */
/***********************************************************************/
/* BLKFILARI constructor. */
/***********************************************************************/
BLKFILARI::BLKFILARI(PGLOBAL g, PTDBDOS tdbp, int op, PXOB *xp)
: BLOCKFILTER(tdbp, op)
{
Colp = (PDOSCOL)xp[0];
if (xp[1]->GetType() == TYPE_COLBLK) {
Cpx = (PCOL)xp[1]; // Subquery pseudo constant column
Correl = TRUE;
} else
Cpx = NULL;
Sorted = Colp->IsSorted() > 0;
// Don't remember why this was changed. Anyway it is no good for
// correlated subqueries because the Value must reflect changes
if (Cpx)
Valp = xp[1]->GetValue();
else
Valp = AllocateValue(g, xp[1]->GetValue());
} // end of BLKFILARI constructor
/***********************************************************************/
/* Reset: re-eval the constant value in the case of pseudo constant */
/* column use in a correlated subquery. */
/***********************************************************************/
void BLKFILARI::Reset(PGLOBAL g)
{
if (Cpx) {
Cpx->Reset();
Cpx->Eval(g);
MakeValueBitmap(); // Does nothing for class BLKFILARI
} // endif Cpx
} // end of Reset
/***********************************************************************/
/* Evaluate block filter for arithmetic operators. */
/***********************************************************************/
int BLKFILARI::BlockEval(PGLOBAL g)
{
int mincmp, maxcmp, n;
#if defined(_DEBUG)
assert (Colp->IsClustered());
#endif
n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
mincmp = Colp->GetMin()->CompVal(Valp, n);
maxcmp = Colp->GetMax()->CompVal(Valp, n);
switch (Opc) {
case OP_EQ:
case OP_NE:
if (mincmp < 0) // Means minval > Val
Result = (Sorted) ? -2 : -1;
else if (maxcmp > 0) // Means maxval < Val
Result = -1;
else if (!mincmp && !maxcmp) // minval = maxval = val
Result = 1;
else
Result = 0;
break;
case OP_GT:
case OP_LE:
if (mincmp < 0) // minval > Val
Result = (Sorted) ? 2 : 1;
else if (maxcmp < 0) // maxval > Val
Result = 0;
else // maxval <= Val
Result = -1;
break;
case OP_GE:
case OP_LT:
if (mincmp <= 0) // minval >= Val
Result = (Sorted) ? 2 : 1;
else if (maxcmp <= 0) // Maxval >= Val
Result = 0;
else // Maxval < Val
Result = -1;
break;
} // endswitch Opc
switch (Opc) {
case OP_NE:
case OP_LE:
case OP_LT:
Result = -Result;
break;
} // endswitch Opc
if (trace)
htrc("BlockEval: op=%d n=%d rc=%d\n", Opc, n, Result);
return Result;
} // end of BlockEval
/* ---------------------- Class BLKFILAR2----------------------------- */
/***********************************************************************/
/* BLKFILAR2 constructor. */
/***********************************************************************/
BLKFILAR2::BLKFILAR2(PGLOBAL g, PTDBDOS tdbp, int op, PXOB *xp)
: BLKFILARI(g, tdbp, op, xp)
{
MakeValueBitmap();
} // end of BLKFILAR2 constructor
/***********************************************************************/
/* MakeValueBitmap: Set the constant value bit map. It can be void */
/* if the constant value is not in the column distinct values list. */
/***********************************************************************/
void BLKFILAR2::MakeValueBitmap(void)
{
int i; // ndv = Colp->GetNdv();
bool found = FALSE;
PVBLK dval = Colp->GetDval();
assert(dval);
/*********************************************************************/
/* Here we cannot use Find because we must get the index */
/* of where to put the value if it is not found in the array. */
/* This is needed by operators other than OP_EQ or OP_NE. */
/*********************************************************************/
found = dval->Locate(Valp, i);
/*********************************************************************/
/* Set the constant value bitmap. The bitmaps are really matching */
/* the OP_EQ, OP_LE, and OP_LT operator but are also used for the */
/* other operators for which the Result will be inverted. */
/* The reason the bitmaps are not directly complemented for them is */
/* to be able to test easily the cases of sorted columns with Bxp, */
/* and the case of a void bitmap, which happens if the constant */
/* value is not in the column distinct values list. */
/*********************************************************************/
if (found) {
Bmp = 1 << i; // Bit of the found value
Bxp = Bmp - 1; // All smaller values
if (Opc != OP_LT && Opc != OP_GE)
Bxp |= Bmp; // Found value must be included
} else {
Bmp = 0;
Bxp = (1 << i) - 1;
} // endif found
if (!(Opc == OP_EQ || Opc == OP_NE))
Bmp = Bxp;
} // end of MakeValueBitmap
/***********************************************************************/
/* Evaluate XDB2 block filter for arithmetic operators. */
/***********************************************************************/
int BLKFILAR2::BlockEval(PGLOBAL g)
{
#if defined(_DEBUG)
assert (Colp->IsClustered());
#endif
int n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
uint bkmp = *(uint*)Colp->GetBmap()->GetValPtr(n);
uint bres = Bmp & bkmp;
// Set result as if Opc were OP_EQ, OP_LT, or OP_LE
if (!bres) {
if (!Bmp)
Result = -2; // No good block in the table file
else if (!Sorted)
Result = -1; // No good values in this block
else // Sorted column, test for no more good blocks in file
Result = (Bxp & bkmp) ? -1 : -2;
} else
// Test whether all block values are good or only some ones
Result = (bres == bkmp) ? 1 : 0;
// For OP_NE, OP_GE, and OP_GT the result must be inverted.
switch (Opc) {
case OP_NE:
case OP_GE:
case OP_GT:
Result = -Result;
break;
} // endswitch Opc
if (trace)
htrc("BlockEval2: op=%d n=%d rc=%d\n", Opc, n, Result);
return Result;
} // end of BlockEval
/* ---------------------- Class BLKFILMR2----------------------------- */
/***********************************************************************/
/* BLKFILMR2 constructor. */
/***********************************************************************/
BLKFILMR2::BLKFILMR2(PGLOBAL g, PTDBDOS tdbp, int op, PXOB *xp)
: BLKFILARI(g, tdbp, op, xp)
{
Nbm = Colp->GetNbm();
Bmp = (uint*)PlugSubAlloc(g, NULL, Nbm * sizeof(uint));
Bxp = (uint*)PlugSubAlloc(g, NULL, Nbm * sizeof(uint));
MakeValueBitmap();
} // end of BLKFILMR2 constructor
/***********************************************************************/
/* MakeValueBitmap: Set the constant value bit map. It can be void */
/* if the constant value is not in the column distinct values list. */
/***********************************************************************/
void BLKFILMR2::MakeValueBitmap(void)
{
int i; // ndv = Colp->GetNdv();
bool found = FALSE, noteq = !(Opc == OP_EQ || Opc == OP_NE);
PVBLK dval = Colp->GetDval();
assert(dval);
for (i = 0; i < Nbm; i++)
Bmp[i] = Bxp[i] = 0;
/*********************************************************************/
/* Here we cannot use Find because we must get the index */
/* of where to put the value if it is not found in the array. */
/* This is needed by operators other than OP_EQ or OP_NE. */
/*********************************************************************/
found = dval->Locate(Valp, i);
/*********************************************************************/
/* For bitmaps larger than a ULONG, we must know where Bmp and Bxp */
/* are positioned in the ULONG bit map block array. */
/*********************************************************************/
N = i / MAXBMP;
i %= MAXBMP;
/*********************************************************************/
/* Set the constant value bitmaps. The bitmaps are really matching */
/* the OP_EQ, OP_LE, and OP_LT operator but are also used for the */
/* other operators for which the Result will be inverted. */
/* The reason the bitmaps are not directly complemented for them is */
/* to be able to easily test the cases of sorted columns with Bxp, */
/* and the case of a void bitmap, which happens if the constant */
/* value is not in the column distinct values list. */
/*********************************************************************/
if (found) {
Bmp[N] = 1 << i;
Bxp[N] = Bmp[N] - 1;
if (Opc != OP_LT && Opc != OP_GE)
Bxp[N] |= Bmp[N]; // Found value must be included
} else
Bxp[N] = (1 << i) - 1;
if (noteq)
Bmp[N] = Bxp[N];
Void = !Bmp[N]; // There are no good values in the file
for (i = 0; i < N; i++) {
Bxp[i] = ~0;
if (noteq)
Bmp[i] = Bxp[i];
Void = Void && !Bmp[i];
} // endfor i
if (!Bmp[N] && !Bxp[N])
N--;
} // end of MakeValueBitmap
/***********************************************************************/
/* Evaluate XDB2 block filter for arithmetic operators. */
/***********************************************************************/
int BLKFILMR2::BlockEval(PGLOBAL g)
{
#if defined(_DEBUG)
assert (Colp->IsClustered());
#endif
int i, n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
bool fnd = FALSE, all = TRUE, gt = TRUE;
uint bres;
uint *bkmp = (uint*)Colp->GetBmap()->GetValPtr(n * Nbm);
// Set result as if Opc were OP_EQ, OP_LT, or OP_LE
for (i = 0; i < Nbm; i++)
if (i <= N) {
if ((bres = Bmp[i] & bkmp[i]))
fnd = TRUE; // Some good value(s) found in the block
if (bres != bkmp[i])
all = FALSE; // Not all block values are good
if (Bxp[i] & bkmp[i])
gt = FALSE; // Not all block values are > good value(s)
} else if (bkmp[i]) {
all = FALSE;
break;
} // endif's
if (!fnd) {
if (Void || (gt && Sorted))
Result = -2; // No (more) good block in file
else
Result = -1; // No good values in this block
} else
Result = (all) ? 1 : 0; // All block values are good
// For OP_NE, OP_GE, and OP_GT the result must be inverted.
switch (Opc) {
case OP_NE:
case OP_GE:
case OP_GT:
Result = -Result;
break;
} // endswitch Opc
if (trace)
htrc("BlockEval2: op=%d n=%d rc=%d\n", Opc, n, Result);
return Result;
} // end of BlockEval
/***********************************************************************/
/* BLKSPCARI constructor. */
/***********************************************************************/
BLKSPCARI::BLKSPCARI(PTDBDOS tdbp, int op, PXOB *xp, int bsize)
: BLOCKFILTER(tdbp, op)
{
if (xp[1]->GetType() == TYPE_COLBLK) {
Cpx = (PCOL)xp[1]; // Subquery pseudo constant column
Correl = TRUE;
} else
Cpx = NULL;
Valp = xp[1]->GetValue();
Val = (int)xp[1]->GetValue()->GetIntValue();
Bsize = bsize;
} // end of BLKFILARI constructor
/***********************************************************************/
/* Reset: re-eval the constant value in the case of pseudo constant */
/* column use in a correlated subquery. */
/***********************************************************************/
void BLKSPCARI::Reset(PGLOBAL g)
{
if (Cpx) {
Cpx->Reset();
Cpx->Eval(g);
Val = (int)Valp->GetIntValue();
} // endif Cpx
} // end of Reset
/***********************************************************************/
/* Evaluate block filter for arithmetic operators (ROWID) */
/***********************************************************************/
int BLKSPCARI::BlockEval(PGLOBAL g)
{
int mincmp, maxcmp, n, m;
n = Tdbp->GetCurBlk();
m = n * Bsize + 1; // Minimum Rowid value for this block
mincmp = (Val > m) ? 1 : (Val < m) ? (-1) : 0;
m = (n + 1) * Bsize; // Maximum Rowid value for this block
maxcmp = (Val > m) ? 1 : (Val < m) ? (-1) : 0;
switch (Opc) {
case OP_EQ:
case OP_NE:
if (mincmp < 0) // Means minval > Val
Result = -2; // Always sorted
else if (maxcmp > 0) // Means maxval < Val
Result = -1;
else if (!mincmp && !maxcmp) // minval = maxval = val
Result = 1;
else
Result = 0;
break;
case OP_GT:
case OP_LE:
if (mincmp < 0) // minval > Val
Result = 2; // Always sorted
else if (maxcmp < 0) // maxval > Val
Result = 0;
else // maxval <= Val
Result = -1;
break;
case OP_GE:
case OP_LT:
if (mincmp <= 0) // minval >= Val
Result = 2; // Always sorted
else if (maxcmp <= 0) // Maxval >= Val
Result = 0;
else // Maxval < Val
Result = -1;
break;
} // endswitch Opc
switch (Opc) {
case OP_NE:
case OP_LE:
case OP_LT:
Result = -Result;
break;
} // endswitch Opc
if (trace)
htrc("BlockEval: op=%d n=%d rc=%d\n", Opc, n, Result);
return Result;
} // end of BlockEval
/* ------------------------ Class BLKFILIN --------------------------- */
/***********************************************************************/
/* BLKFILIN constructor. */
/***********************************************************************/
BLKFILIN::BLKFILIN(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp)
: BLOCKFILTER(tdbp, op)
{
if (op == OP_IN) {
Opc = OP_EQ;
Opm = 1;
} else {
Opc = op;
Opm = opm;
} // endif op
Colp = (PDOSCOL)xp[0];
Arap = (PARRAY)xp[1];
Type = Arap->GetResultType();
if (Colp->GetResultType() != Type) {
sprintf(g->Message, "BLKFILIN: %s", MSG(VALTYPE_NOMATCH));
longjmp(g->jumper[g->jump_level], 99);
} else if (Colp->GetValue()->IsCi())
Arap->SetPrecision(g, 1); // Case insensitive
Sorted = Colp->IsSorted() > 0;
} // end of BLKFILIN constructor
/***********************************************************************/
/* Reset: have the sorted array reset its Bot value to -1 (bottom). */
/***********************************************************************/
void BLKFILIN::Reset(PGLOBAL g)
{
Arap->Reset();
// MakeValueBitmap(); // Does nothing for class BLKFILIN
} // end of Reset
/***********************************************************************/
/* Evaluate block filter for a IN operator on a constant array. */
/* Note: here we need to use the GetValPtrEx function to get a zero */
/* ended string in case of string argument. This is because the ARRAY */
/* can have a different width than the char column. */
/***********************************************************************/
int BLKFILIN::BlockEval(PGLOBAL g)
{
int n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
void *minp = Colp->GetMin()->GetValPtrEx(n);
void *maxp = Colp->GetMax()->GetValPtrEx(n);
Result = Arap->BlockTest(g, Opc, Opm, minp, maxp, Sorted);
return Result;
} // end of BlockEval
/* ------------------------ Class BLKFILIN2 -------------------------- */
/***********************************************************************/
/* BLKFILIN2 constructor. */
/* New version that takes care of all operators and modificators. */
/* It is also ready to handle the case of correlated sub-selects. */
/***********************************************************************/
BLKFILIN2::BLKFILIN2(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp)
: BLKFILIN(g, tdbp, op, opm, xp)
{
Nbm = Colp->GetNbm();
Valp = AllocateValue(g, Colp->GetValue());
Invert = (Opc == OP_NE || Opc == OP_GE || Opc ==OP_GT);
Bmp = (uint*)PlugSubAlloc(g, NULL, Nbm * sizeof(uint));
Bxp = (uint*)PlugSubAlloc(g, NULL, Nbm * sizeof(uint));
MakeValueBitmap();
} // end of BLKFILIN2 constructor
/***********************************************************************/
/* MakeValueBitmap: Set the constant values bit map. It can be void */
/* if the constant values are not in the column distinct values list. */
/* The bitmaps are prepared for the EQ, LE, and LT operators and */
/* takes care of the ALL and ANY modificators. If the operators are */
/* NE, GE, or GT the modificator is inverted and the result will be. */
/***********************************************************************/
void BLKFILIN2::MakeValueBitmap(void)
{
int i, k, n, ndv = Colp->GetNdv();
bool found, noteq = !(Opc == OP_EQ || Opc == OP_NE);
bool all = (!Invert) ? (Opm == 2) : (Opm != 2);
uint btp;
PVBLK dval = Colp->GetDval();
N = -1;
// Take care of special cases
if (!(n = Arap->GetNval())) {
// Return TRUE for ALL because it means that there are no item that
// does not verify the condition, which is true indeed.
// Return FALSE for ANY because TRUE means that there is at least
// one item that verifies the condition, which is false.
Result = (Opm == 2) ? 2 : -2;
return;
} else if (!noteq && all && n > 1) {
// An item cannot be equal to all different values
// or an item is always unequal to any different values
Result = (Opc == OP_EQ) ? -2 : 2;
return;
} // endif's
for (i = 0; i < Nbm; i++)
Bmp[i] = Bxp[i] = 0;
for (k = 0; k < n; k++) {
Arap->GetNthValue(Valp, k);
found = dval->Locate(Valp, i);
N = i / MAXBMP;
btp = 1 << (i % MAXBMP);
if (found)
Bmp[N] |= btp;
// For LT and LE if ALL the condition applies to the smallest item
// if ANY it applies to the largest item. In the case of EQ we come
// here only if ANY or if n == 1, so it does applies to the largest.
if ((!k && all) || (k == n - 1 && !all)) {
Bxp[N] = btp - 1;
if (found && Opc != OP_LT && Opc != OP_GE)
Bxp[N] |= btp; // Found value must be included
} // endif k, opm
} // endfor k
if (noteq)
Bmp[N] = Bxp[N];
Void = !Bmp[N]; // There are no good values in the file
for (i = 0; i < N; i++) {
Bxp[i] = ~0;
if (noteq) {
Bmp[i] = Bxp[i];
Void = FALSE;
} // endif noteq
} // endfor i
if (!Bmp[N] && !Bxp[N]) {
if (--N < 0)
// All array values are smaller than block values
Result = (Invert) ? 2 : -2;
} else if (N == Nbm - 1 && (signed)Bmp[N] == (1 << (ndv % MAXBMP)) - 1) {
// Condition will be always TRUE or FALSE for the whole file
Result = (Invert) ? -2 : 2;
N = -1;
} // endif's
} // end of MakeValueBitmap
/***********************************************************************/
/* Evaluate block filter for set operators on a constant array. */
/* Note: here we need to use the GetValPtrEx function to get a zero */
/* ended string in case of string argument. This is because the ARRAY */
/* can have a different width than the char column. */
/***********************************************************************/
int BLKFILIN2::BlockEval(PGLOBAL g)
{
if (N < 0)
return Result; // Was set in MakeValueBitmap
int i, n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
bool fnd = FALSE, all = TRUE, gt = TRUE;
uint bres;
uint *bkmp = (uint*)Colp->GetBmap()->GetValPtr(n * Nbm);
// Set result as if Opc were OP_EQ, OP_LT, or OP_LE
// The difference between ALL or ANY was handled in MakeValueBitmap
for (i = 0; i < Nbm; i++)
if (i <= N) {
if ((bres = Bmp[i] & bkmp[i]))
fnd = TRUE;
if (bres != bkmp[i])
all = FALSE;
if (Bxp[i] & bkmp[i])
gt = FALSE;
} else if (bkmp[i]) {
all = FALSE;
break;
} // endif's
if (!fnd) {
if (Void || (Sorted && gt))
Result = -2; // No more good block in file
else
Result = -1; // No good values in this block
} else if (all)
Result = 1; // All block values are good
else
Result = 0; // Block contains some good values
// For OP_NE, OP_GE, and OP_GT the result must be inverted.
switch (Opc) {
case OP_NE:
case OP_GE:
case OP_GT:
Result = -Result;
break;
} // endswitch Opc
return Result;
} // end of BlockEval
#if 0
/***********************************************************************/
/* BLKFILIN2 constructor. */
/***********************************************************************/
BLKFILIN2::BLKFILIN2(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp)
: BLKFILIN(g, tdbp, op, opm, xp)
{
// Currently, bitmap matching is only implemented for the IN operator
if (!(Bitmap = (op == OP_IN || (op == OP_EQ && opm != 2)))) {
Nbm = Colp->GetNbm();
N = 0;
return; // Revert to standard minmax method
} // endif minmax
int i, n;
ULONG btp;
PVAL valp = AllocateValue(g, Colp->GetValue());
PVBLK dval = Colp->GetDval();
Nbm = Colp->GetNbm();
N = -1;
Bmp = (PULONG)PlugSubAlloc(g, NULL, Nbm * sizeof(ULONG));
Bxp = (PULONG)PlugSubAlloc(g, NULL, Nbm * sizeof(ULONG));
for (i = 0; i < Nbm; i++)
Bmp[i] = Bxp[i] = 0;
for (n = 0; n < Arap->GetNval(); n++) {
Arap->GetNthValue(valp, n);
if ((i = dval->Find(valp)) >= 0)
Bmp[i / MAXBMP] |= 1 << (i % MAXBMP);
} // endfor n
for (i = Nbm - 1; i >= 0; i--)
if (Bmp[i]) {
for (btp = Bmp[i]; btp; btp >>= 1)
Bxp[i] |= btp;
for (N = i--; i >= 0; i--)
Bxp[i] = ~0;
break;
} // endif Bmp
} // end of BLKFILIN2 constructor
/***********************************************************************/
/* Evaluate block filter for a IN operator on a constant array. */
/* Note: here we need to use the GetValPtrEx function to get a zero */
/* ended string in case of string argument. This is because the ARRAY */
/* can have a different width than the char column. */
/***********************************************************************/
int BLKFILIN2::BlockEval(PGLOBAL g)
{
if (N < 0)
return -2; // IN list contains no good values
int i, n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
bool fnd = FALSE, all = TRUE, gt = TRUE;
ULONG bres;
PULONG bkmp = (PULONG)Colp->GetBmap()->GetValPtr(n * Nbm);
if (Bitmap) {
// For IN operator use the bitmap method
for (i = 0; i < Nbm; i++)
if (i <= N) {
if ((bres = Bmp[i] & bkmp[i]))
fnd = TRUE;
if (bres != bkmp[i])
all = FALSE;
if (Bxp[i] & bkmp[i])
gt = FALSE;
} else if (bkmp[i]) {
all = FALSE;
break;
} // endif's
if (!fnd) {
if (Sorted && gt)
Result = -2; // No more good block in file
else
Result = -1; // No good values in this block
} else if (all)
Result = 1; // All block values are good
else
Result = 0; // Block contains some good values
} else {
// For other than IN operators, revert to standard minmax method
int n = 0, ndv = Colp->GetNdv();
void *minp = NULL;
void *maxp = NULL;
ULONG btp;
PVBLK dval = Colp->GetDval();
for (i = 0; i < Nbm; i++)
for (btp = 1; btp && n < ndv; btp <<= 1, n++)
if (btp & bkmp[i]) {
if (!minp)
minp = dval->GetValPtrEx(n);
maxp = dval->GetValPtrEx(n);
} // endif btp
Result = Arap->BlockTest(g, Opc, Opm, minp, maxp, Colp->IsSorted());
} // endif Bitmap
return Result;
} // end of BlockEval
#endif // 0
/* ------------------------ Class BLKSPCIN --------------------------- */
/***********************************************************************/
/* BLKSPCIN constructor. */
/***********************************************************************/
BLKSPCIN::BLKSPCIN(PGLOBAL g, PTDBDOS tdbp, int op, int opm,
PXOB *xp, int bsize)
: BLOCKFILTER(tdbp, op)
{
if (op == OP_IN) {
Opc = OP_EQ;
Opm = 1;
} else
Opm = opm;
Arap = (PARRAY)xp[1];
#if defined(_DEBUG)
assert (Opm);
assert (Arap->GetResultType() == TYPE_INT);
#endif
Bsize = bsize;
} // end of BLKSPCIN constructor
/***********************************************************************/
/* Reset: have the sorted array reset its Bot value to -1 (bottom). */
/***********************************************************************/
void BLKSPCIN::Reset(PGLOBAL g)
{
Arap->Reset();
} // end of Reset
/***********************************************************************/
/* Evaluate block filter for a IN operator on a constant array. */
/***********************************************************************/
int BLKSPCIN::BlockEval(PGLOBAL g)
{
int n = Tdbp->GetCurBlk();
int minrow = n * Bsize + 1; // Minimum Rowid value for this block
int maxrow = (n + 1) * Bsize; // Maximum Rowid value for this block
Result = Arap->BlockTest(g, Opc, Opm, &minrow, &maxrow, TRUE);
return Result;
} // end of BlockEval
/* ------------------------------------------------------------------- */
#if 0
/***********************************************************************/
/* Implementation of the BLOCKINDEX class. */
/***********************************************************************/
BLOCKINDEX::BLOCKINDEX(PBX nx, PDOSCOL cp, PKXBASE kp)
{
Next = nx;
Tdbp = (cp) ? (PTDBDOS)cp->GetTo_Tdb() : NULL;
Colp = cp;
Kxp = kp;
Type = (cp) ? cp->GetResultType() : TYPE_ERROR;
Sorted = (cp) ? cp->IsSorted() > 0 : FALSE;
Result = 0;
} // end of BLOCKINDEX constructor
/***********************************************************************/
/* Reset Bot and Top values of optimized Kindex blocks. */
/***********************************************************************/
void BLOCKINDEX::Reset(void)
{
if (Next)
Next->Reset();
Kxp->Reset();
} // end of Reset
/***********************************************************************/
/* Evaluate block indexing test. */
/***********************************************************************/
int BLOCKINDEX::BlockEval(PGLOBAL g)
{
#if defined(_DEBUG)
assert (Tdbp && Colp);
#endif
int n = Tdbp->GetCurBlk();
void *minp = Colp->GetMin()->GetValPtr(n);
void *maxp = Colp->GetMax()->GetValPtr(n);
Result = Kxp->BlockTest(g, minp, maxp, Type, Sorted);
return Result;
} // end of BlockEval
/***********************************************************************/
/* Make file output of BLOCKINDEX contents. */
/***********************************************************************/
void BLOCKINDEX::Print(PGLOBAL g, FILE *f, UINT n)
{
char m[64];
memset(m, ' ', n); // Make margin string
m[n] = '\0';
fprintf(f, "%sBLOCKINDEX: at %p next=%p col=%s kxp=%p result=%d\n",
m, this, Next, (Colp) ? Colp->GetName() : "Rowid", Kxp, Result);
if (Next)
Next->Print(g, f, n);
} // end of Print
/***********************************************************************/
/* Make string output of BLOCKINDEX contents. */
/***********************************************************************/
void BLOCKINDEX::Print(PGLOBAL g, char *ps, UINT z)
{
strncat(ps, "BlockIndex(es)", z);
} // end of Print
/* ------------------------------------------------------------------- */
/***********************************************************************/
/* Implementation of the BLOCKINDX2 class. */
/***********************************************************************/
BLOCKINDX2::BLOCKINDX2(PBX nx, PDOSCOL cp, PKXBASE kp)
: BLOCKINDEX(nx, cp, kp)
{
Nbm = Colp->GetNbm();
Dval = Colp->GetDval();
Bmap = Colp->GetBmap();
#if defined(_DEBUG)
assert(Dval && Bmap);
#endif
} // end of BLOCKINDX2 constructor
/***********************************************************************/
/* Evaluate block indexing test. */
/***********************************************************************/
int BLOCKINDX2::BlockEval(PGLOBAL g)
{
int n = Tdbp->GetCurBlk();
PUINT bmp = (PUINT)Bmap->GetValPtr(n * Nbm);
Result = Kxp->BlockTst2(g, Dval, bmp, Nbm, Type, Sorted);
return Result;
} // end of BlockEval
/* ------------------------------------------------------------------- */
/***********************************************************************/
/* Implementation of the BLKSPCINDX class. */
/***********************************************************************/
BLKSPCINDX::BLKSPCINDX(PBX nx, PTDBDOS tp, PKXBASE kp, int bsize)
: BLOCKINDEX(nx, NULL, kp)
{
Tdbp = tp;
Bsize = bsize;
Type = TYPE_INT;
Sorted = TRUE;
} // end of BLKSPCINDX constructor
/***********************************************************************/
/* Evaluate block indexing test. */
/***********************************************************************/
int BLKSPCINDX::BlockEval(PGLOBAL g)
{
int n = Tdbp->GetCurBlk();
int minrow = n * Bsize + 1; // Minimum Rowid value for this block
int maxrow = (n + 1) * Bsize; // Maximum Rowid value for this block
Result = Kxp->BlockTest(g, &minrow, &maxrow, TYPE_INT, TRUE);
return Result;
} // end of BlockEval
#endif // 0