diff options
Diffstat (limited to 'storage')
45 files changed, 3329 insertions, 390 deletions
diff --git a/storage/connect/catalog.h b/storage/connect/catalog.h index a61b1a53653..86d973e0036 100644 --- a/storage/connect/catalog.h +++ b/storage/connect/catalog.h @@ -44,6 +44,7 @@ typedef struct _colinfo { int Precision; int Scale; int Opt; + int Freq; char *Remark; char *Datefmt; char *Fieldfmt; diff --git a/storage/connect/colblk.cpp b/storage/connect/colblk.cpp index bce26e25387..364628bfca6 100644 --- a/storage/connect/colblk.cpp +++ b/storage/connect/colblk.cpp @@ -39,6 +39,7 @@ COLBLK::COLBLK(PCOLDEF cdp, PTDB tdbp, int i) Opt = cdp->Opt; Long = cdp->Long; Precision = cdp->Precision; + Freq = cdp->Freq; Buf_Type = cdp->Buf_Type; ColUse |= cdp->Flags; // Used by CONNECT Nullable = !!(cdp->Flags & U_NULLS); @@ -49,6 +50,7 @@ COLBLK::COLBLK(PCOLDEF cdp, PTDB tdbp, int i) Opt = 0; Long = 0; Precision = 0; + Freq = 0; Buf_Type = TYPE_ERROR; Nullable = false; Unsigned = false; diff --git a/storage/connect/colblk.h b/storage/connect/colblk.h index 7b84d237bd2..1204c4623f7 100644 --- a/storage/connect/colblk.h +++ b/storage/connect/colblk.h @@ -36,6 +36,10 @@ class DllExport COLBLK : public XOBJECT { virtual int GetAmType() {return TYPE_AM_ERROR;} virtual void SetOk(void) {Status |= BUF_EMPTY;} virtual PTDB GetTo_Tdb(void) {return To_Tdb;} +#if defined(BLK_INDX) + virtual int GetClustered(void) {return 0;} + virtual int IsClustered(void) {return FALSE;} +#endif // BLK_INDX PCOL GetNext(void) {return Next;} PSZ GetName(void) {return Name;} int GetIndex(void) {return Index;} @@ -76,7 +80,9 @@ class DllExport COLBLK : public XOBJECT { virtual void WriteColumn(PGLOBAL g); virtual void Print(PGLOBAL g, FILE *, uint); virtual void Print(PGLOBAL g, char *, uint); +#if defined(BLK_INDX) virtual bool VarSize(void) {return false;} +#endif // BLK_INDX virtual bool IsColInside(PCOL colp) {return this == colp;} bool InitValue(PGLOBAL g); @@ -94,6 +100,7 @@ class DllExport COLBLK : public XOBJECT { int Buf_Type; // Data type int Long; // Internal length in table int Precision; // Column length (as for ODBC) + int Freq; // Evaluated ceiling of distinct values FORMAT Format; // Output format ushort ColUse; // Column usage ushort Status; // Column read status diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index d111ff07044..f6d25b47ce7 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -433,7 +433,7 @@ RCODE EvalColumns(PGLOBAL g, PTDB tdbp, bool mrr) /***********************************************************************/ /* ReadNext: Read next record sequentially. */ /***********************************************************************/ -RCODE CntReadNext(PGLOBAL g, PTDB tdbp) +RCODE CntReadNext(PGLOBAL g, PTDB tdbp) { RCODE rc; @@ -449,8 +449,21 @@ RCODE CntReadNext(PGLOBAL g, PTDB tdbp) ((PTDBASE)tdbp)->SetKindex(NULL); } // endif index + // Save stack and allocation environment and prepare error return + if (g->jump_level == MAX_JUMP) { + strcpy(g->Message, MSG(TOO_MANY_JUMPS)); + return RC_FX; + } // endif jump_level + + if ((setjmp(g->jumper[++g->jump_level])) != 0) { + rc= RC_FX; + goto err; + } // endif rc + while ((rc= (RCODE)tdbp->ReadDB(g)) == RC_NF) ; - + + err: + g->jump_level--; return (rc != RC_OK) ? rc : EvalColumns(g, tdbp); } // end of CntReadNext @@ -578,7 +591,7 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp) tbxp= (TDBDOX*)tdbp; tbxp->SetKindex(NULL); tbxp->To_Key_Col= NULL; - rc= tbxp->ResetTableOpt(g, ((PTDBASE)tdbp)->GetDef()->Indexable()); + rc= tbxp->ResetTableOpt(g, false, ((PTDBASE)tdbp)->GetDef()->Indexable()); err: if (xtrace > 1) diff --git a/storage/connect/filamap.cpp b/storage/connect/filamap.cpp index 5a67c5d2dd2..64e9ed15f40 100644 --- a/storage/connect/filamap.cpp +++ b/storage/connect/filamap.cpp @@ -1,11 +1,11 @@ /*********** File AM Map C++ Program Source Code File (.CPP) ***********/ /* PROGRAM NAME: FILAMAP */ /* ------------- */ -/* Version 1.4 */ +/* Version 1.5 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -322,8 +322,30 @@ int MAPFAM::ReadBuffer(PGLOBAL g) /*******************************************************************/ /* Record file position in case of UPDATE or DELETE. */ /*******************************************************************/ - Fpos = Mempos; - CurBlk = (int)Rows++; +#if defined(BLK_INDX) + int rc; + + next: +#endif // BLK_INDX + Fpos = Mempos; + CurBlk = (int)Rows++; + +#if defined(BLK_INDX) + /*******************************************************************/ + /* Check whether optimization on ROWID */ + /* can be done, as well as for join as for local filtering. */ + /*******************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + // Skip this record + if ((rc = SkipRecord(g, FALSE)) != RC_OK) + return rc; + + goto next; + } // endswitch rc +#endif // BLK_INDX } else Placed = false; @@ -491,7 +513,11 @@ MBKFAM::MBKFAM(PDOSDEF tdp) : MAPFAM(tdp) Block = tdp->GetBlock(); Last = tdp->GetLast(); Nrec = tdp->GetElemt(); +#if defined(BLK_INDX) BlkPos = tdp->GetTo_Pos(); +#else // !BLK_INDX + BlkPos = NULL; +#endif // !BLK_INDX CurNum = Nrec; } // end of MBKFAM standard constructor @@ -537,6 +563,7 @@ int MBKFAM::GetRowID(void) /***********************************************************************/ int MBKFAM::ReadBuffer(PGLOBAL g) { +#if defined(BLK_INDX) int len; /*********************************************************************/ @@ -554,9 +581,21 @@ int MBKFAM::ReadBuffer(PGLOBAL g) /*******************************************************************/ CurNum = 0; + next: if (++CurBlk >= Block) return RC_EF; + /*******************************************************************/ + /* Before reading a new block, check whether block optimization */ + /* can be done, as well as for join as for local filtering. */ + /*******************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + goto next; + } // endswitch rc + Fpos = Mempos = Memory + BlkPos[CurBlk]; } // endif's @@ -568,6 +607,10 @@ int MBKFAM::ReadBuffer(PGLOBAL g) memcpy(Tdbp->GetLine(), Fpos, len); Tdbp->GetLine()[len] = '\0'; return RC_OK; +#else // !BLK_POS + strcpy(g->Message, "This AM cannot be used in this version"); + return RC_FX; +#endif // !BLK_POS } // end of ReadBuffer /***********************************************************************/ @@ -657,10 +700,26 @@ int MPXFAM::ReadBuffer(PGLOBAL g) /* New block. */ /*******************************************************************/ CurNum = 0; - + +#if defined(BLK_INDX) + next: +#endif // BLK_INDX if (++CurBlk >= Block) return RC_EF; +#if defined(BLK_INDX) + /*******************************************************************/ + /* Before reading a new block, check whether block optimization */ + /* can be done, as well as for join as for local filtering. */ + /*******************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + goto next; + } // endswitch rc +#endif // BLK_INDX + Fpos = Mempos = Headlen + Memory + CurBlk * Blksize; } // endif's diff --git a/storage/connect/filamfix.cpp b/storage/connect/filamfix.cpp index a92d9766933..295c281a478 100644 --- a/storage/connect/filamfix.cpp +++ b/storage/connect/filamfix.cpp @@ -1,11 +1,11 @@ /*********** File AM Fix C++ Program Source Code File (.CPP) ***********/ /* PROGRAM NAME: FILAMFIX */ /* ------------- */ -/* Version 1.4 */ +/* Version 1.5 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -168,9 +168,24 @@ int FIXFAM::ReadBuffer(PGLOBAL g) CurNum = 0; Tdbp->SetLine(To_Buf); +#if defined(BLK_INDX) + next: +#endif // BLK_INDX if (++CurBlk >= Block) return RC_EF; +#if defined(BLK_INDX) + /*****************************************************************/ + /* Before reading a new block, check whether block indexing */ + /* can be done, as well as for join as for local filtering. */ + /*****************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + goto next; + } // endswitch rc +#endif // BLK_INDX } // endif's if (OldBlk == CurBlk) { @@ -1028,9 +1043,24 @@ int BGXFAM::ReadBuffer(PGLOBAL g) CurNum = 0; Tdbp->SetLine(To_Buf); +#if defined(BLK_INDX) + next: +#endif // BLK_INDX if (++CurBlk >= Block) return RC_EF; +#if defined(BLK_INDX) + /*****************************************************************/ + /* Before reading a new block, check whether block optimization */ + /* can be done, as well as for join as for local filtering. */ + /*****************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + goto next; + } // endswitch rc +#endif // BLK_INDX } // endif's if (OldBlk == CurBlk) { diff --git a/storage/connect/filamfix.h b/storage/connect/filamfix.h index 758d891bf2c..b2c5019c635 100644 --- a/storage/connect/filamfix.h +++ b/storage/connect/filamfix.h @@ -33,16 +33,16 @@ class DllExport FIXFAM : public BLKFAM { virtual int Cardinality(PGLOBAL g) {return TXTFAM::Cardinality(g);} virtual int MaxBlkSize(PGLOBAL g, int s) {return TXTFAM::MaxBlkSize(g, s);} - virtual bool AllocateBuffer(PGLOBAL g); - virtual void ResetBuffer(PGLOBAL g); - virtual int ReadBuffer(PGLOBAL g); - virtual int WriteBuffer(PGLOBAL g); - virtual int DeleteRecords(PGLOBAL g, int irc); - virtual void CloseTableFile(PGLOBAL g); + virtual bool AllocateBuffer(PGLOBAL g); + virtual void ResetBuffer(PGLOBAL g); + virtual int ReadBuffer(PGLOBAL g); + virtual int WriteBuffer(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g); protected: - virtual bool CopyHeader(PGLOBAL g) {return false;} - virtual bool MoveIntermediateLines(PGLOBAL g, bool *b); + virtual bool CopyHeader(PGLOBAL g) {return false;} + virtual bool MoveIntermediateLines(PGLOBAL g, bool *b); // No additional members }; // end of class FIXFAM @@ -69,7 +69,7 @@ class BGXFAM : public FIXFAM { virtual bool OpenTableFile(PGLOBAL g); virtual int ReadBuffer(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); - virtual int DeleteRecords(PGLOBAL g, int irc); + virtual int DeleteRecords(PGLOBAL g, int irc); virtual void CloseTableFile(PGLOBAL g); virtual void Rewind(void); @@ -78,7 +78,7 @@ class BGXFAM : public FIXFAM { , int org = FILE_BEGIN); int BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req); bool BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req); - virtual bool OpenTempFile(PGLOBAL g); + virtual bool OpenTempFile(PGLOBAL g); virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL); // Members diff --git a/storage/connect/filamtxt.cpp b/storage/connect/filamtxt.cpp index 1d3f17e2228..d7310f34e6b 100644 --- a/storage/connect/filamtxt.cpp +++ b/storage/connect/filamtxt.cpp @@ -1,11 +1,11 @@ /*********** File AM Txt C++ Program Source Code File (.CPP) ***********/ /* PROGRAM NAME: FILAMTXT */ /* ------------- */ -/* Version 1.4 */ +/* Version 1.5 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -235,13 +235,20 @@ int TXTFAM::Cardinality(PGLOBAL g) /***********************************************************************/ int TXTFAM::MaxBlkSize(PGLOBAL g, int s) { - int savcur = CurBlk, blm1 = Block - 1; + int rc = RC_OK, savcur = CurBlk, blm1 = Block - 1; int size, last = s - blm1 * Nrec; // Roughly estimate the table size as the sum of blocks // that can contain good rows for (size = 0, CurBlk = 0; CurBlk < Block; CurBlk++) +#if defined(BLK_INDX) + if ((rc = Tdbp->TestBlock(g)) == RC_OK) + size += (CurBlk == blm1) ? last : Nrec; + else if (rc == RC_EF) + break; +#else // !BLK_INDX size += (CurBlk == blm1) ? last : Nrec; +#endif // !BLK_INDX CurBlk = savcur; return size; @@ -543,6 +550,9 @@ int DOSFAM::ReadBuffer(PGLOBAL g) /*******************************************************************/ /* Record file position in case of UPDATE or DELETE. */ /*******************************************************************/ +#if defined(BLK_INDX) + next: +#endif // BLK_INDX if (RecordPos(g)) return RC_FX; @@ -551,6 +561,22 @@ int DOSFAM::ReadBuffer(PGLOBAL g) if (trace > 1) htrc("ReadBuffer: CurBlk=%d\n", CurBlk); +#if defined(BLK_INDX) + /*******************************************************************/ + /* Check whether optimization on ROWID */ + /* can be done, as well as for join as for local filtering. */ + /*******************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + // Skip this record + if ((rc = SkipRecord(g, FALSE)) != RC_OK) + return rc; + + goto next; + } // endswitch rc +#endif // BLK_INDX } else Placed = false; @@ -993,7 +1019,11 @@ BLKFAM::BLKFAM(PDOSDEF tdp) : DOSFAM(tdp) Last = tdp->GetLast(); Nrec = tdp->GetElemt(); Closing = false; +#if defined(BLK_INDX) BlkPos = tdp->GetTo_Pos(); +#else // !BLK_INDX + BlkPos = NULL; +#endif // !BLK_INDX CurLine = NULL; NxtLine = NULL; OutBuf = NULL; @@ -1033,13 +1063,20 @@ int BLKFAM::Cardinality(PGLOBAL g) /***********************************************************************/ int BLKFAM::MaxBlkSize(PGLOBAL g, int s) { - int savcur = CurBlk; + int rc = RC_OK, savcur = CurBlk; int size; // Roughly estimate the table size as the sum of blocks // that can contain good rows for (size = 0, CurBlk = 0; CurBlk < Block; CurBlk++) +#if defined(BLK_INDX) + if ((rc = Tdbp->TestBlock(g)) == RC_OK) + size += (CurBlk == Block - 1) ? Last : Nrec; + else if (rc == RC_EF) + break; +#else // !BLK_INDX size += (CurBlk == Block - 1) ? Last : Nrec; +#endif // !BLK_INDX CurBlk = savcur; return size; @@ -1150,6 +1187,7 @@ int BLKFAM::SkipRecord(PGLOBAL g, bool header) /***********************************************************************/ int BLKFAM::ReadBuffer(PGLOBAL g) { +#if defined(BLK_INDX) int i, n, rc = RC_OK; /*********************************************************************/ @@ -1176,9 +1214,21 @@ int BLKFAM::ReadBuffer(PGLOBAL g) /*******************************************************************/ CurNum = 0; + next: if (++CurBlk >= Block) return RC_EF; + /*******************************************************************/ + /* Before reading a new block, check whether block optimization */ + /* can be done, as well as for join as for local filtering. */ + /*******************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + goto next; + } // endswitch rc + } // endif's if (OldBlk == CurBlk) @@ -1241,6 +1291,10 @@ int BLKFAM::ReadBuffer(PGLOBAL g) // Store the current record file position for Delete and Update Fpos = BlkPos[CurBlk] + CurLine - To_Buf; return rc; +#else // !BLK_POS + strcpy(g->Message, "This AM cannot be used in this version"); + return RC_FX; +#endif // !BLK_POS } // end of ReadBuffer /***********************************************************************/ diff --git a/storage/connect/filamvct.cpp b/storage/connect/filamvct.cpp index 11c9ac69d4d..4887d7e52fd 100755 --- a/storage/connect/filamvct.cpp +++ b/storage/connect/filamvct.cpp @@ -1,11 +1,11 @@ /*********** File AM Vct C++ Program Source Code File (.CPP) ***********/ /* PROGRAM NAME: FILAMVCT */ /* ------------- */ -/* Version 2.4 */ +/* Version 2.5 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -249,13 +249,20 @@ bool VCTFAM::SetBlockInfo(PGLOBAL g) /***********************************************************************/ int VCTFAM::MaxBlkSize(PGLOBAL g, int s) { - int savcur = CurBlk; + int rc = RC_OK, savcur = CurBlk; int size; // Roughly estimate the table size as the sum of blocks // that can contain good rows for (size = 0, CurBlk = 0; CurBlk < Block; CurBlk++) +#if defined(BLK_INDX) + if ((rc = Tdbp->TestBlock(g)) == RC_OK) + size += (CurBlk == Block - 1) ? Last : Nrec; + else if (rc == RC_EF) + break; +#else // !BLK_INDX size += (CurBlk == Block - 1) ? Last : Nrec; +#endif // !BLK_INDX CurBlk = savcur; return size; @@ -572,9 +579,25 @@ int VCTFAM::ReadBuffer(PGLOBAL g) /*******************************************************************/ CurNum = 0; +#if defined(BLK_INDX) + next: +#endif // BLK_INDX if (++CurBlk == Block) return RC_EF; // End of file +#if defined(BLK_INDX) + /*******************************************************************/ + /* Before reading a new block, check whether block optimizing */ + /* can be done, as well as for join as for local filtering. */ + /*******************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + goto next; + } // endswitch rc +#endif // BLK_INDX + num_there++; } // endif CurNum diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp index 4f1a02d8257..04184bdda71 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamzip.cpp @@ -306,10 +306,30 @@ int ZIPFAM::ReadBuffer(PGLOBAL g) /*******************************************************************/ /* Record file position in case of UPDATE or DELETE. */ /*******************************************************************/ +#if defined(BLK_INDX) + next: +#endif // BLK_INDX if (RecordPos(g)) return RC_FX; CurBlk = Rows++; // Update RowID + +#if defined(BLK_INDX) + /*******************************************************************/ + /* Check whether optimization on ROWID */ + /* can be done, as well as for join as for local filtering. */ + /*******************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + // Skip this record + if ((rc = SkipRecord(g, FALSE)) != RC_OK) + return rc; + + goto next; + } // endswitch rc +#endif // BLK_INDX } else Placed = false; @@ -403,7 +423,11 @@ ZBKFAM::ZBKFAM(PDOSDEF tdp) : ZIPFAM(tdp) CurLine = NULL; NxtLine = NULL; Closing = false; +#if defined(BLK_INDX) BlkPos = tdp->GetTo_Pos(); +#else // !BLK_INDX + BlkPos = NULL; +#endif // !BLK_INDX } // end of ZBKFAM standard constructor ZBKFAM::ZBKFAM(PZBKFAM txfp) : ZIPFAM(txfp) @@ -418,13 +442,20 @@ ZBKFAM::ZBKFAM(PZBKFAM txfp) : ZIPFAM(txfp) /***********************************************************************/ int ZBKFAM::MaxBlkSize(PGLOBAL g, int s) { - int savcur = CurBlk; + int rc = RC_OK, savcur = CurBlk; int size; // Roughly estimate the table size as the sum of blocks // that can contain good rows for (size = 0, CurBlk = 0; CurBlk < Block; CurBlk++) +#if defined(BLK_INDX) + if ((rc = Tdbp->TestBlock(g)) == RC_OK) + size += (CurBlk == Block - 1) ? Last : Nrec; + else if (rc == RC_EF) + break; +#else // !BLK_INDX size += (CurBlk == Block - 1) ? Last : Nrec; +#endif // !BLK_INDX CurBlk = savcur; return size; @@ -509,7 +540,8 @@ int ZBKFAM::SkipRecord(PGLOBAL g, bool header) /***********************************************************************/ int ZBKFAM::ReadBuffer(PGLOBAL g) { - int n, rc = RC_OK; +#if defined(BLK_INDX) + int n, skip, rc = RC_OK; /*********************************************************************/ /* Sequential reading when Placed is not true. */ @@ -532,10 +564,34 @@ int ZBKFAM::ReadBuffer(PGLOBAL g) /* New block. */ /*********************************************************************/ CurNum = 0; + skip = 0; + next: if (++CurBlk >= Block) return RC_EF; + /*********************************************************************/ + /* Before using the new block, check whether block optimization */ + /* can be done, as well as for join as for local filtering. */ + /*********************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + skip++; + goto next; + } // endswitch rc + + if (skip) + // Skip blocks rejected by block optimization + for (int i = CurBlk - skip; i < CurBlk; i++) { + BlkLen = BlkPos[i + 1] - BlkPos[i]; + + if (gzseek(Zfile, (z_off_t)BlkLen, SEEK_CUR) < 0) + return Zerror(g); + + } // endfor i + BlkLen = BlkPos[CurBlk + 1] - BlkPos[CurBlk]; if (!(n = gzread(Zfile, To_Buf, BlkLen))) { @@ -559,6 +615,10 @@ int ZBKFAM::ReadBuffer(PGLOBAL g) rc = Zerror(g); return rc; +#else // !BLK_POS + strcpy(g->Message, "This AM cannot be used in this version"); + return RC_FX; +#endif // !BLK_POS } // end of ReadBuffer /***********************************************************************/ @@ -770,8 +830,33 @@ int ZIXFAM::ReadBuffer(PGLOBAL g) CurNum = 0; Tdbp->SetLine(To_Buf); -//if (++CurBlk >= Block) -// return RC_EF; +#if defined(BLK_INDX) + int skip = 0; + + next: + if (++CurBlk >= Block) + return RC_EF; + + /*********************************************************************/ + /* Before using the new block, check whether block optimization */ + /* can be done, as well as for join as for local filtering. */ + /*********************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + skip++; + goto next; + } // endswitch rc + + if (skip) + // Skip blocks rejected by block optimization + for (int i = 0; i < skip; i++) { + if (gzseek(Zfile, (z_off_t)Buflen, SEEK_CUR) < 0) + return Zerror(g); + + } // endfor i +#endif // BLK_INDX if (!(n = gzread(Zfile, To_Buf, Buflen))) { rc = RC_EF; @@ -818,4 +903,522 @@ int ZIXFAM::WriteBuffer(PGLOBAL g) return RC_OK; } // end of WriteBuffer +#if defined(BLK_INDX) +/* --------------------------- Class ZLBFAM -------------------------- */ + +/***********************************************************************/ +/* Constructors. */ +/***********************************************************************/ +ZLBFAM::ZLBFAM(PDOSDEF tdp) : BLKFAM(tdp) + { + Zstream = NULL; + Zbuffer = NULL; + Zlenp = NULL; + Optimized = tdp->IsOptimized(); + } // end of ZLBFAM standard constructor + +ZLBFAM::ZLBFAM(PZLBFAM txfp) : BLKFAM(txfp) + { + Zstream = txfp->Zstream; + Zbuffer = txfp->Zbuffer; + Zlenp = txfp->Zlenp; + Optimized = txfp->Optimized; + } // end of ZLBFAM (dummy?) copy constructor + +/***********************************************************************/ +/* ZLB GetFileLength: returns an estimate of what would be the */ +/* uncompressed file size in number of bytes. */ +/***********************************************************************/ +int ZLBFAM::GetFileLength(PGLOBAL g) + { + int len = (Optimized) ? BlkPos[Block] : BLKFAM::GetFileLength(g); + + if (len > 0) + // Estimate size reduction to a max of 5 + len *= 5; + + return len; + } // end of GetFileLength + +/***********************************************************************/ +/* Allocate the line buffer. For mode Delete a bigger buffer has to */ +/* be allocated because is it also used to move lines into the file. */ +/***********************************************************************/ +bool ZLBFAM::AllocateBuffer(PGLOBAL g) + { + char *msg; + int n, zrc; + +#if 0 + if (!Optimized && Tdbp->NeedIndexing(g)) { + strcpy(g->Message, MSG(NOP_ZLIB_INDEX)); + return TRUE; + } // endif indexing +#endif // 0 + +#if defined(NOLIB) + if (!zlib && LoadZlib()) { + sprintf(g->Message, MSG(DLL_LOAD_ERROR), GetLastError(), "zlib.dll"); + return TRUE; + } // endif zlib +#endif + + BLKFAM::AllocateBuffer(g); +//Buflen = Nrec * (Lrecl + 2); +//Rbuf = Nrec; + + // Allocate the compressed buffer + n = Buflen + 16; // ????????????????????????????????? + Zlenp = (int*)PlugSubAlloc(g, NULL, n); + Zbuffer = (Byte*)(Zlenp + 1); + + // Allocate and initialize the Z stream + Zstream = (z_streamp)PlugSubAlloc(g, NULL, sizeof(z_stream)); + Zstream->zalloc = (alloc_func)0; + Zstream->zfree = (free_func)0; + Zstream->opaque = (voidpf)0; + Zstream->next_in = NULL; + Zstream->avail_in = 0; + + if (Tdbp->GetMode() == MODE_READ) { + msg = "inflateInit"; + zrc = inflateInit(Zstream); + } else { + msg = "deflateInit"; + zrc = deflateInit(Zstream, Z_DEFAULT_COMPRESSION); + } // endif Mode + + if (zrc != Z_OK) { + if (Zstream->msg) + sprintf(g->Message, "%s error: %s", msg, Zstream->msg); + else + sprintf(g->Message, "%s error: %d", msg, zrc); + + return TRUE; + } // endif zrc + + if (Tdbp->GetMode() == MODE_INSERT) { + // Write the file header block + if (Last == Nrec) { + CurBlk = Block; + CurNum = 0; + + if (!GetFileLength(g)) { + // Write the zlib header as an extra block + strcpy(To_Buf, "PlugDB"); + BlkLen = strlen("PlugDB") + 1; + + if (WriteCompressedBuffer(g)) + return TRUE; + + } // endif void file + + } else { + // In mode insert, if Last != Nrec, last block must be updated + CurBlk = Block - 1; + CurNum = Last; + + strcpy(g->Message, MSG(NO_PAR_BLK_INS)); + return TRUE; + } // endif Last + + } else { // MODE_READ + // First thing to do is to read the header block + void *rdbuf; + + if (Optimized) { + BlkLen = BlkPos[0]; + rdbuf = Zlenp; + } else { + // Get the stored length from the file itself + if (fread(Zlenp, sizeof(int), 1, Stream) != 1) + return FALSE; // Empty file + + BlkLen = *Zlenp; + rdbuf = Zbuffer; + } // endif Optimized + + switch (ReadCompressedBuffer(g, rdbuf)) { + case RC_EF: + return FALSE; + case RC_FX: +#if defined(UNIX) + sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno)); +#else + sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL)); +#endif + case RC_NF: + return TRUE; + } // endswitch + + // Some old tables can have PlugDB in their header + if (strcmp(To_Buf, "PlugDB")) { + sprintf(g->Message, MSG(BAD_HEADER), Tdbp->GetFile(g)); + return TRUE; + } // endif strcmp + + } // endif Mode + + return FALSE; + } // end of AllocateBuffer + +/***********************************************************************/ +/* GetPos: return the position of last read record. */ +/***********************************************************************/ +int ZLBFAM::GetPos(void) + { + return (Optimized) ? (CurNum + Nrec * CurBlk) : Fpos; + } // end of GetPos + +/***********************************************************************/ +/* GetNextPos: should not be called for this class. */ +/***********************************************************************/ +int ZLBFAM::GetNextPos(void) + { + if (Optimized) { + assert(FALSE); + return 0; + } else + return ftell(Stream); + + } // end of GetNextPos + +/***********************************************************************/ +/* ReadBuffer: Read one line for a text file. */ +/***********************************************************************/ +int ZLBFAM::ReadBuffer(PGLOBAL g) + { + int n; + void *rdbuf; + + /*********************************************************************/ + /* Sequential reading when Placed is not true. */ + /*********************************************************************/ + if (Placed) { + Placed = FALSE; + } else if (++CurNum < Rbuf) { + CurLine = NxtLine; + + // Get the position of the next line in the buffer + if (Tdbp->GetFtype() == RECFM_VAR) + while (*NxtLine++ != '\n') ; + else + NxtLine += Lrecl; + + // Set caller line buffer + n = NxtLine - CurLine - ((Tdbp->GetFtype() == RECFM_BIN) ? 0 : Ending); + memcpy(Tdbp->GetLine(), CurLine, n); + Tdbp->GetLine()[n] = '\0'; + return RC_OK; + } else if (Rbuf < Nrec && CurBlk != -1) { + CurNum--; // To have a correct Last value when optimizing + return RC_EF; + } else { + /*******************************************************************/ + /* New block. */ + /*******************************************************************/ + CurNum = 0; + + next: + if (++CurBlk >= Block) + return RC_EF; + + /*******************************************************************/ + /* Before reading a new block, check whether block optimization */ + /* can be done, as well as for join as for local filtering. */ + /*******************************************************************/ + if (Optimized) switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + goto next; + } // endswitch rc + + } // endif's + + if (OldBlk == CurBlk) + goto ok; // Block is already there + + if (Optimized) { + // Store the position of next block + Fpos = BlkPos[CurBlk]; + + // fseek is required only in non sequential reading + if (CurBlk != OldBlk + 1) + if (fseek(Stream, Fpos, SEEK_SET)) { + sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos); + return RC_FX; + } // endif fseek + + // Calculate the length of block to read + BlkLen = BlkPos[CurBlk + 1] - Fpos; + rdbuf = Zlenp; + } else { // !Optimized + if (CurBlk != OldBlk + 1) { + strcpy(g->Message, MSG(INV_RAND_ACC)); + return RC_FX; + } else + Fpos = ftell(Stream); // Used when optimizing + + // Get the stored length from the file itself + if (fread(Zlenp, sizeof(int), 1, Stream) != 1) { + if (feof(Stream)) + return RC_EF; + + goto err; + } // endif fread + + BlkLen = *Zlenp; + rdbuf = Zbuffer; + } // endif Optimized + + // Read the next block + switch (ReadCompressedBuffer(g, rdbuf)) { + case RC_FX: goto err; + case RC_NF: return RC_FX; + case RC_EF: return RC_EF; + default: Rbuf = (CurBlk == Block - 1) ? Last : Nrec; + } // endswitch ReadCompressedBuffer + + ok: + if (Tdbp->GetFtype() == RECFM_VAR) { + int i; + + // Get the position of the current line + for (i = 0, CurLine = To_Buf; i < CurNum; i++) + while (*CurLine++ != '\n') ; // What about Unix ??? + + // Now get the position of the next line + for (NxtLine = CurLine; *NxtLine++ != '\n';) ; + + // Set caller line buffer + n = NxtLine - CurLine - Ending; + } else { + CurLine = To_Buf + CurNum * Lrecl; + NxtLine = CurLine + Lrecl; + n = Lrecl - ((Tdbp->GetFtype() == RECFM_BIN) ? 0 : Ending); + } // endif Ftype + + memcpy(Tdbp->GetLine(), CurLine, n); + Tdbp->GetLine()[n] = '\0'; + + OldBlk = CurBlk; // Last block actually read + IsRead = TRUE; // Is read indeed + return RC_OK; + + err: +#if defined(UNIX) + sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno)); +#else + sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL)); +#endif + return RC_FX; + } // end of ReadBuffer + +/***********************************************************************/ +/* Read and decompress a block from the stream. */ +/***********************************************************************/ +int ZLBFAM::ReadCompressedBuffer(PGLOBAL g, void *rdbuf) + { + if (fread(rdbuf, 1, (size_t)BlkLen, Stream) == (unsigned)BlkLen) { + int zrc; + + num_read++; + + if (Optimized && BlkLen != signed(*Zlenp + sizeof(int))) { + sprintf(g->Message, MSG(BAD_BLK_SIZE), CurBlk + 1); + return RC_NF; + } // endif BlkLen + + // HERE WE MUST INFLATE THE BLOCK + Zstream->next_in = Zbuffer; + Zstream->avail_in = (uInt)(*Zlenp); + Zstream->next_out = (Byte*)To_Buf; + Zstream->avail_out = Buflen; + zrc = inflate(Zstream, Z_SYNC_FLUSH); + + if (zrc != Z_OK) { + if (Zstream->msg) + sprintf(g->Message, MSG(FUNC_ERR_S), "inflate", Zstream->msg); + else + sprintf(g->Message, MSG(FUNCTION_ERROR), "inflate", (int)zrc); + + return RC_NF; + } // endif zrc + + } else if (feof(Stream)) { + return RC_EF; + } else + return RC_FX; + + return RC_OK; + } // end of ReadCompressedBuffer + +/***********************************************************************/ +/* WriteBuffer: File write routine for DOS access method. */ +/* Update is directly written back into the file, */ +/* with this (fast) method, record size cannot change. */ +/***********************************************************************/ +int ZLBFAM::WriteBuffer(PGLOBAL g) + { + assert (Tdbp->GetMode() == MODE_INSERT); + + /*********************************************************************/ + /* Prepare the write buffer. */ + /*********************************************************************/ + if (!Closing) { + if (Tdbp->GetFtype() == RECFM_BIN) + memcpy(CurLine, Tdbp->GetLine(), Lrecl); + else + strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf); + +#if defined(_DEBUG) + if (Tdbp->GetFtype() == RECFM_FIX && + (signed)strlen(CurLine) != Lrecl + (signed)strlen(CrLf)) { + strcpy(g->Message, MSG(BAD_LINE_LEN)); + Closing = TRUE; + return RC_FX; + } // endif Lrecl +#endif // _DEBUG + } // endif Closing + + /*********************************************************************/ + /* In Insert mode, blocs are added sequentialy to the file end. */ + /*********************************************************************/ + if (++CurNum != Rbuf) { + if (Tdbp->GetFtype() == RECFM_VAR) + CurLine += strlen(CurLine); + else + CurLine += Lrecl; + + return RC_OK; // We write only full blocks + } // endif CurNum + + // HERE WE MUST DEFLATE THE BLOCK + if (Tdbp->GetFtype() == RECFM_VAR) + NxtLine = CurLine + strlen(CurLine); + else + NxtLine = CurLine + Lrecl; + + BlkLen = NxtLine - To_Buf; + + if (WriteCompressedBuffer(g)) { + Closing = TRUE; // To tell CloseDB about a Write error + return RC_FX; + } // endif WriteCompressedBuffer + + CurBlk++; + CurNum = 0; + CurLine = To_Buf; + return RC_OK; + } // end of WriteBuffer + +/***********************************************************************/ +/* Compress the buffer and write the deflated output to stream. */ +/***********************************************************************/ +bool ZLBFAM::WriteCompressedBuffer(PGLOBAL g) + { + int zrc; + + Zstream->next_in = (Byte*)To_Buf; + Zstream->avail_in = (uInt)BlkLen; + Zstream->next_out = Zbuffer; + Zstream->avail_out = Buflen + 16; + Zstream->total_out = 0; + zrc = deflate(Zstream, Z_FULL_FLUSH); + + if (zrc != Z_OK) { + if (Zstream->msg) + sprintf(g->Message, MSG(FUNC_ERR_S), "deflate", Zstream->msg); + else + sprintf(g->Message, MSG(FUNCTION_ERROR), "deflate", (int)zrc); + + return TRUE; + } else + *Zlenp = Zstream->total_out; + + // Now start the writing process. + BlkLen = *Zlenp + sizeof(int); + + if (fwrite(Zlenp, 1, BlkLen, Stream) != (size_t)BlkLen) { + sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno)); + return TRUE; + } // endif size + + return FALSE; + } // end of WriteCompressedBuffer + +/***********************************************************************/ +/* Table file close routine for DOS access method. */ +/***********************************************************************/ +void ZLBFAM::CloseTableFile(PGLOBAL g) + { + int rc = RC_OK; + + if (Tdbp->GetMode() == MODE_INSERT) { + PCATLG cat = PlgGetCatalog(g); + LPCSTR name = Tdbp->GetName(); + PDOSDEF defp = (PDOSDEF)Tdbp->GetDef(); + + // Closing is True if last Write was in error + if (CurNum && !Closing) { + // Some more inserted lines remain to be written + Last = (Nrec - Rbuf) + CurNum; + Block = CurBlk + 1; + Rbuf = CurNum--; + Closing = TRUE; + rc = WriteBuffer(g); + } else if (Rbuf == Nrec) { + Last = Nrec; + Block = CurBlk; + } // endif CurNum + + if (rc != RC_FX) { + defp->SetBlock(Block); + defp->SetLast(Last); + cat->SetIntCatInfo("Blocks", Block); + cat->SetIntCatInfo("Last", Last); + } // endif + + fclose(Stream); + } else + rc = fclose(Stream); + +#ifdef DEBTRACE + htrc("ZLB CloseTableFile: closing %s mode=%d rc=%d\n", + To_File, Tdbp->GetMode(), rc); +#endif + + Stream = NULL; // So we can know whether table is open + To_Fb->Count = 0; // Avoid double closing by PlugCloseAll + + if (Tdbp->GetMode() == MODE_READ) + rc = inflateEnd(Zstream); + else + rc = deflateEnd(Zstream); + + } // end of CloseTableFile + +/***********************************************************************/ +/* Rewind routine for ZLIB access method. */ +/***********************************************************************/ +void ZLBFAM::Rewind(void) + { + // We must be positioned after the header block + if (CurBlk >= 0) { // Nothing to do if no block read yet + if (!Optimized) { // If optimized, fseek will be done in ReadBuffer + rewind(Stream); + fread(Zlenp, sizeof(int), 1, Stream); + fseek(Stream, *Zlenp + sizeof(int), SEEK_SET); + OldBlk = -1; + } // endif Optimized + + CurBlk = -1; + CurNum = Rbuf; + } // endif CurBlk + +//OldBlk = -1; +//Rbuf = 0; commented out in case we reuse last read block + } // end of Rewind +#endif // BLK_INDX /* ------------------------ End of ZipFam ---------------------------- */ diff --git a/storage/connect/filamzip.h b/storage/connect/filamzip.h index f6f28ca5315..67d9553a4e6 100644 --- a/storage/connect/filamzip.h +++ b/storage/connect/filamzip.h @@ -122,7 +122,7 @@ class DllExport ZIXFAM : public ZBKFAM { // No additional Members }; // end of class ZIXFAM -#ifdef NOT_USED +#if defined(BLK_INDX) /***********************************************************************/ /* This is the DOS/UNIX Access Method class declaration for PlugDB */ /* fixed/variable files compressed using the zlib library functions. */ @@ -166,6 +166,6 @@ class DllExport ZLBFAM : public BLKFAM { int *Zlenp; // Pointer to block length bool Optimized; // true when opt file is available }; // end of class ZLBFAM -#endif // NOT_USED +#endif // BLK_INDX #endif // __FILAMZIP_H diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index f19cac9da50..f301ed2dcae 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -252,8 +252,8 @@ ha_create_table_option connect_table_option_list[]= ha_create_table_option connect_field_option_list[]= { HA_FOPTION_NUMBER("FLAG", offset, (ulonglong) -1, 0, INT_MAX32, 1), - HA_FOPTION_NUMBER("FREQUENCY", freq, 0, 0, INT_MAX32, 1), // not used - HA_FOPTION_NUMBER("OPT_VALUE", opt, 0, 0, 2, 1), // used for indexing + HA_FOPTION_NUMBER("MAX_DIST", freq, 0, 0, INT_MAX32, 1), // BLK_INDX + HA_FOPTION_NUMBER("DISTRIB", opt, 0, 0, 2, 1), // used for BLK_INDX HA_FOPTION_NUMBER("FIELD_LENGTH", fldlen, 0, 0, INT_MAX32, 1), HA_FOPTION_STRING("DATE_FORMAT", dateformat), HA_FOPTION_STRING("FIELD_FORMAT", fieldformat), @@ -331,11 +331,12 @@ DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir) delete_table method in handler.cc */ static const char *ha_connect_exts[]= { - ".dos", ".fix", ".csv",".bin", ".fmt", ".dbf", ".xml", ".ini", ".vec", + ".dos", ".fix", ".csv", ".bin", ".fmt", ".dbf", ".xml", ".ini", ".vec", ".dnx", ".fnx", ".bnx", ".vnx", ".dbx", - NULL -}; - +#if defined(BLK_INDX) + ".dop", ".fop", ".bop", ".vop", +#endif // BLK_INDX + NULL}; /** @brief @@ -453,7 +454,7 @@ static handler* connect_create_handler(handlerton *hton, handler *h= new (mem_root) ha_connect(hton, table); if (xtrace) - printf("New CONNECT %p, table: %s\n", + htrc("New CONNECT %p, table: %s\n", h, table ? table->table_name.str : "<null>"); return h; @@ -500,7 +501,7 @@ ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg) ha_connect::~ha_connect(void) { if (xtrace) - printf("Delete CONNECT %p, table: %s, xp=%p count=%d\n", this, + htrc("Delete CONNECT %p, table: %s, xp=%p count=%d\n", this, table ? table->s->table_name.str : "<null>", xp, xp ? xp->count : 0); @@ -932,12 +933,12 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) if (fop) { pcf->Offset= (int)fop->offset; -// pcf->Freq= fop->freq; + pcf->Freq= (int)fop->freq; pcf->Datefmt= (char*)fop->dateformat; pcf->Fieldfmt= (char*)fop->fieldformat; } else { pcf->Offset= -1; -// pcf->Freq= 0; + pcf->Freq= 0; pcf->Datefmt= NULL; pcf->Fieldfmt= NULL; } // endif fop @@ -1046,7 +1047,7 @@ PIXDEF ha_connect::GetIndexInfo(TABLE_SHARE *s) for (int n= 0; (unsigned)n < s->keynames.count; n++) { if (xtrace) - printf("Getting created index %d info\n", n + 1); + htrc("Getting created index %d info\n", n + 1); // Find the index to describe kp= s->key_info[n]; @@ -1182,7 +1183,7 @@ PTDB ha_connect::GetTDB(PGLOBAL g) valid_query_id= xp->last_query_id; tp->SetMode(xmod); } else - printf("GetTDB: %s\n", g->Message); + htrc("GetTDB: %s\n", g->Message); return tp; } // end of GetTDB @@ -1197,7 +1198,7 @@ int ha_connect::OpenTable(PGLOBAL g, bool del) // Double test to be on the safe side if (!g || !table) { - printf("OpenTable logical error; g=%p table=%p\n", g, table); + htrc("OpenTable logical error; g=%p table=%p\n", g, table); return HA_ERR_INITIALIZATION; } // endif g @@ -1278,9 +1279,8 @@ int ha_connect::OpenTable(PGLOBAL g, bool del) PIXDEF oldpix= GetIndexInfo(); } // endif xmod -// tdbp->SetOrig((PTBX)table); // used by CheckCond } else - printf("OpenTable: %s\n", g->Message); + htrc("OpenTable: %s\n", g->Message); if (rc) { tdbp= NULL; @@ -1334,7 +1334,7 @@ int ha_connect::MakeRecord(char *buf) DBUG_ENTER("ha_connect::MakeRecord"); if (xtrace > 1) - printf("Maps: read=%08X write=%08X vcol=%08X defr=%08X defw=%08X\n", + htrc("Maps: read=%08X write=%08X vcol=%08X defr=%08X defw=%08X\n", *table->read_set->bitmap, *table->write_set->bitmap, *table->vcol_set->bitmap, *table->def_read_set.bitmap, *table->def_write_set.bitmap); @@ -1372,7 +1372,7 @@ int ha_connect::MakeRecord(char *buf) if (mrr) continue; #endif // MRRBKA_SUPPORT - printf("Column %s not found\n", fp->field_name); + htrc("Column %s not found\n", fp->field_name); dbug_tmp_restore_column_map(table->write_set, org_bitmap); DBUG_RETURN(HA_ERR_WRONG_IN_RECORD); } // endif colp @@ -1487,7 +1487,7 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *buf) break; if (!colp) { - printf("Column %s not found\n", fp->field_name); + htrc("Column %s not found\n", fp->field_name); rc= HA_ERR_WRONG_IN_RECORD; goto err; } else @@ -1612,16 +1612,16 @@ const char *ha_connect::GetValStr(OPVAL vop, bool neg) val= (neg) ? " NOT IN (" : " IN ("; break; case OP_NULL: - val= " IS NULL"; + val= (neg) ? " IS NOT NULL" : " IS NULL"; break; case OP_LIKE: val= " LIKE "; break; case OP_XX: - val= " BETWEEN "; + val= (neg) ? " NOT BETWEEN " : " BETWEEN "; break; case OP_EXIST: - val= " EXISTS "; + val= (neg) ? " NOT EXISTS " : " EXISTS "; break; case OP_AND: val= " AND "; @@ -1656,22 +1656,204 @@ const char *ha_connect::GetValStr(OPVAL vop, bool neg) } // end of GetValStr +#if defined(BLK_INDX) /***********************************************************************/ -/* Check the WHERE condition and return an ODBC/WQL filter. */ +/* Check the WHERE condition and return a CONNECT filter. */ /***********************************************************************/ -PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) +PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond) +{ + unsigned int i; + bool ismul= false; + OPVAL vop= OP_XX; + PFIL filp= NULL; + + if (!cond) + return NULL; + + if (xtrace) + htrc("Cond type=%d\n", cond->type()); + + if (cond->type() == COND::COND_ITEM) { + PFIL fp; + Item_cond *cond_item= (Item_cond *)cond; + + if (xtrace) + htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(), + cond_item->func_name()); + + switch (cond_item->functype()) { + case Item_func::COND_AND_FUNC: vop= OP_AND; break; + case Item_func::COND_OR_FUNC: vop= OP_OR; break; + default: return NULL; + } // endswitch functype + + List<Item>* arglist= cond_item->argument_list(); + List_iterator<Item> li(*arglist); + Item *subitem; + + for (i= 0; i < arglist->elements; i++) + if ((subitem= li++)) { + if (!(fp= CondFilter(g, subitem))) { + if (vop == OP_OR) + return NULL; + } else + filp= (filp) ? MakeFilter(g, filp, vop, fp) : fp; + + } else + return NULL; + + } else if (cond->type() == COND::FUNC_ITEM) { + unsigned int i; + bool iscol, neg= FALSE; + PCOL colp[2]= {NULL,NULL}; + PPARM pfirst= NULL, pprec= NULL; + POPER pop; + Item_func *condf= (Item_func *)cond; + Item* *args= condf->arguments(); + + if (xtrace) + htrc("Func type=%d argnum=%d\n", condf->functype(), + condf->argument_count()); + + switch (condf->functype()) { + case Item_func::EQUAL_FUNC: + case Item_func::EQ_FUNC: vop= OP_EQ; break; + case Item_func::NE_FUNC: vop= OP_NE; break; + case Item_func::LT_FUNC: vop= OP_LT; break; + case Item_func::LE_FUNC: vop= OP_LE; break; + case Item_func::GE_FUNC: vop= OP_GE; break; + case Item_func::GT_FUNC: vop= OP_GT; break; + case Item_func::IN_FUNC: vop= OP_IN; + case Item_func::BETWEEN: + ismul= true; + neg= ((Item_func_opt_neg *)condf)->negated; + break; + default: return NULL; + } // endswitch functype + + pop= (POPER)PlugSubAlloc(g, NULL, sizeof(OPER)); + pop->Name= NULL; + pop->Val=vop; + pop->Mod= 0; + + if (condf->argument_count() < 2) + return NULL; + + for (i= 0; i < condf->argument_count(); i++) { + if (xtrace) + htrc("Argtype(%d)=%d\n", i, args[i]->type()); + + if (i >= 2 && !ismul) { + if (xtrace) + htrc("Unexpected arg for vop=%d\n", vop); + + continue; + } // endif i + + if ((iscol= args[i]->type() == COND::FIELD_ITEM)) { + Item_field *pField= (Item_field *)args[i]; + + // IN and BETWEEN clauses should be col VOP list + if (i && ismul) + return NULL; + + if (pField->field->table != table || + !(colp[i]= tdbp->ColDB(g, (PSZ)pField->field->field_name, 0))) + return NULL; // Column does not belong to this table + + if (xtrace) { + htrc("Field index=%d\n", pField->field->field_index); + htrc("Field name=%s\n", pField->field->field_name); + } // endif xtrace + + } else { + char buff[256]; + String *res, tmp(buff, sizeof(buff), &my_charset_bin); + Item_basic_constant *pval= (Item_basic_constant *)args[i]; + PPARM pp= (PPARM)PlugSubAlloc(g, NULL, sizeof(PARM)); + + // IN and BETWEEN clauses should be col VOP list + if (!i && (ismul)) + return NULL; + + if ((res= pval->val_str(&tmp)) == NULL) + return NULL; // To be clarified + + switch (args[i]->real_type()) { + case COND::STRING_ITEM: + pp->Type= TYPE_STRING; + pp->Value= PlugSubAlloc(g, NULL, res->length() + 1); + strncpy((char*)pp->Value, res->ptr(), res->length() + 1); + break; + case COND::INT_ITEM: + pp->Type= TYPE_INT; + pp->Value= PlugSubAlloc(g, NULL, sizeof(int)); + *((int*)pp->Value)= (int)pval->val_int(); + break; + case COND::DATE_ITEM: + pp->Type= TYPE_DATE; + pp->Value= PlugSubAlloc(g, NULL, sizeof(int)); + *((int*)pp->Value)= (int)pval->val_int_from_date(); + break; + case COND::REAL_ITEM: + pp->Type= TYPE_DOUBLE; + pp->Value= PlugSubAlloc(g, NULL, sizeof(double)); + *((double*)pp->Value)= pval->val_real(); + break; + case COND::DECIMAL_ITEM: + pp->Type= TYPE_DOUBLE; + pp->Value= PlugSubAlloc(g, NULL, sizeof(double)); + *((double*)pp->Value)= pval->val_real_from_decimal(); + break; + case COND::CACHE_ITEM: // Possible ??? + case COND::NULL_ITEM: // TODO: handle this + default: + return NULL; + } // endswitch type + + if (xtrace) + htrc("Value=%.*s\n", res->length(), res->ptr()); + + // Append the value to the argument list + if (pprec) + pprec->Next= pp; + else + pfirst= pp; + + pp->Domain= i; + pp->Next= NULL; + pprec= pp; + } // endif type + + } // endfor i + + filp= MakeFilter(g, colp, pop, pfirst, neg); + } else { + if (xtrace) + htrc("Unsupported condition\n"); + + return NULL; + } // endif's type + + return filp; +} // end of CondFilter +#endif // BLK_INDX + +/***********************************************************************/ +/* Check the WHERE condition and return a MYSQL/ODBC/WQL filter. */ +/***********************************************************************/ +PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond) { char *body= filp->Body; unsigned int i; bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC); - PPARM pfirst= NULL, pprec= NULL, pp[2]= {NULL, NULL}; OPVAL vop= OP_XX; if (!cond) return NULL; if (xtrace) - printf("Cond type=%d\n", cond->type()); + htrc("Cond type=%d\n", cond->type()); if (cond->type() == COND::COND_ITEM) { char *p1, *p2; @@ -1681,7 +1863,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) return NULL; if (xtrace) - printf("Cond: Ftype=%d name=%s\n", cond_item->functype(), + htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(), cond_item->func_name()); switch (cond_item->functype()) { @@ -1728,7 +1910,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) Item* *args= condf->arguments(); if (xtrace) - printf("Func type=%d argnum=%d\n", condf->functype(), + htrc("Func type=%d argnum=%d\n", condf->functype(), condf->argument_count()); // neg= condf-> @@ -1742,8 +1924,10 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) case Item_func::GE_FUNC: vop= OP_GE; break; case Item_func::GT_FUNC: vop= OP_GT; break; case Item_func::IN_FUNC: vop= OP_IN; + case Item_func::BETWEEN: + ismul= true; neg= ((Item_func_opt_neg *)condf)->negated; - case Item_func::BETWEEN: ismul= true; break; + break; default: return NULL; } // endswitch functype @@ -1757,11 +1941,11 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) for (i= 0; i < condf->argument_count(); i++) { if (xtrace) - printf("Argtype(%d)=%d\n", i, args[i]->type()); + htrc("Argtype(%d)=%d\n", i, args[i]->type()); if (i >= 2 && !ismul) { if (xtrace) - printf("Unexpected arg for vop=%d\n", vop); + htrc("Unexpected arg for vop=%d\n", vop); continue; } // endif i @@ -1793,8 +1977,8 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) fnm= pField->field->field_name; if (xtrace) { - printf("Field index=%d\n", pField->field->field_index); - printf("Field name=%s\n", pField->field->field_name); + htrc("Field index=%d\n", pField->field->field_index); + htrc("Field name=%s\n", pField->field->field_name); } // endif xtrace // IN and BETWEEN clauses should be col VOP list @@ -1815,7 +1999,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) String *res, tmp(buff, sizeof(buff), &my_charset_bin); Item_basic_constant *pval= (Item_basic_constant *)args[i]; - switch (args[i]->type()) { + switch (args[i]->real_type()) { case COND::STRING_ITEM: case COND::INT_ITEM: case COND::REAL_ITEM: @@ -1832,7 +2016,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) return NULL; // To be clarified if (xtrace) - printf("Value=%.*s\n", res->length(), res->ptr()); + htrc("Value=%.*s\n", res->length(), res->ptr()); // IN and BETWEEN clauses should be col VOP list if (!i && (x || ismul)) @@ -1877,7 +2061,7 @@ PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond) } else { if (xtrace) - printf("Unsupported condition\n"); + htrc("Unsupported condition\n"); return NULL; } // endif's type @@ -1912,32 +2096,45 @@ const COND *ha_connect::cond_push(const COND *cond) if (tdbp) { AMT tty= tdbp->GetAmType(); bool x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC); - - if (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC || - tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL || - tty == TYPE_AM_PLG || x) { + bool b= (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC || + tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL || + tty == TYPE_AM_PLG || x); +#if defined(BLK_INDX) + bool go= true; +#else // !BLK_INDX) + bool go= b; +#endif // !BLK_INDX + + if (go) { PGLOBAL& g= xp->g; - PFIL filp= (PFIL)PlugSubAlloc(g, NULL, sizeof(FILTER)); - filp->Body= (char*)PlugSubAlloc(g, NULL, (x) ? 128 : 0); - *filp->Body= 0; - filp->Op= OP_XX; - filp->Cmds= NULL; + if (b) { + PCFIL filp= (PCFIL)PlugSubAlloc(g, NULL, sizeof(CONDFIL)); - if (CheckCond(g, filp, tty, (Item *)cond)) { - if (xtrace) - printf("cond_push: %s\n", filp->Body); + filp->Body= (char*)PlugSubAlloc(g, NULL, (x) ? 128 : 0); + *filp->Body= 0; + filp->Op= OP_XX; + filp->Cmds= NULL; + + if (CheckCond(g, filp, tty, (Item *)cond)) { + if (xtrace) + htrc("cond_push: %s\n", filp->Body); + + if (!x) + PlugSubAlloc(g, NULL, strlen(filp->Body) + 1); + else + cond= NULL; // Does this work? + + tdbp->SetCondFil(filp); + } else if (x && cond) + tdbp->SetCondFil(filp); // Wrong filter - if (!x) - PlugSubAlloc(g, NULL, strlen(filp->Body) + 1); + } // endif b +#if defined(BLK_INDX) else - cond= NULL; // Does this work? - - tdbp->SetFilter(filp); - } else if (x && cond) - tdbp->SetFilter(filp); // Wrong filter - - } // endif tty + tdbp->SetFilter(CondFilter(g, (Item *)cond)); +#endif // BLK_INDX + } // endif go } // endif tdbp @@ -2019,7 +2216,7 @@ int ha_connect::open(const char *name, int mode, uint test_if_locked) DBUG_ENTER("ha_connect::open"); if (xtrace) - printf("open: name=%s mode=%d test=%u\n", name, mode, test_if_locked); + htrc("open: name=%s mode=%d test=%u\n", name, mode, test_if_locked); if (!(share= get_share())) DBUG_RETURN(1); @@ -2063,11 +2260,23 @@ int ha_connect::optimize(THD* thd, HA_CHECK_OPT* check_opt) dup->Check |= CHK_OPT; if (tdbp || (tdbp= GetTDB(g))) { +#if defined(BLK_INDX) + bool b= ((PTDBASE)tdbp)->GetDef()->Indexable(); + + if ((rc= ((PTDBASE)tdbp)->ResetTableOpt(g, true, b))) { + if (rc == RC_INFO) { + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); + rc= 0; + } else + rc= HA_ERR_INTERNAL_ERROR; + + } // endif rc +#else // !BLK_INDX if (!((PTDBASE)tdbp)->GetDef()->Indexable()) { sprintf(g->Message, "optimize: Table %s is not indexable", tdbp->GetName()); my_message(ER_INDEX_REBUILD, g->Message, MYF(0)); rc= HA_ERR_UNSUPPORTED; - } else if ((rc= ((PTDBASE)tdbp)->ResetTableOpt(g, true))) { + } else if ((rc= ((PTDBASE)tdbp)->ResetTableOpt(g, false, true))) { if (rc == RC_INFO) { push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); rc= 0; @@ -2075,6 +2284,8 @@ int ha_connect::optimize(THD* thd, HA_CHECK_OPT* check_opt) rc= HA_ERR_INTERNAL_ERROR; } // endif's +#endif // !BLK_INDX + } else rc= HA_ERR_INTERNAL_ERROR; @@ -2179,7 +2390,7 @@ int ha_connect::write_row(uchar *buf) // Return result code from write operation if (CntWriteRow(g, tdbp)) { DBUG_PRINT("write_row", ("%s", g->Message)); - printf("write_row: %s\n", g->Message); + htrc("write_row: %s\n", g->Message); rc= HA_ERR_INTERNAL_ERROR; } // endif RC @@ -2216,7 +2427,7 @@ int ha_connect::update_row(const uchar *old_data, uchar *new_data) DBUG_ENTER("ha_connect::update_row"); if (xtrace > 1) - printf("update_row: old=%s new=%s\n", old_data, new_data); + htrc("update_row: old=%s new=%s\n", old_data, new_data); // Check values for possible change in indexed column if ((rc= CheckRecord(g, old_data, new_data))) @@ -2224,7 +2435,7 @@ int ha_connect::update_row(const uchar *old_data, uchar *new_data) if (CntUpdateRow(g, tdbp)) { DBUG_PRINT("update_row", ("%s", g->Message)); - printf("update_row CONNECT: %s\n", g->Message); + htrc("update_row CONNECT: %s\n", g->Message); rc= HA_ERR_INTERNAL_ERROR; } // endif RC @@ -2258,7 +2469,7 @@ int ha_connect::delete_row(const uchar *buf) if (CntDeleteRow(xp->g, tdbp, false)) { rc= HA_ERR_INTERNAL_ERROR; - printf("delete_row CONNECT: %s\n", xp->g->Message); + htrc("delete_row CONNECT: %s\n", xp->g->Message); } // endif DeleteRow DBUG_RETURN(rc); @@ -2275,7 +2486,7 @@ int ha_connect::index_init(uint idx, bool sorted) DBUG_ENTER("index_init"); if (xtrace) - printf("index_init: this=%p idx=%u sorted=%d\n", this, idx, sorted); + htrc("index_init: this=%p idx=%u sorted=%d\n", this, idx, sorted); if ((rc= rnd_init(0))) return rc; @@ -2291,7 +2502,7 @@ int ha_connect::index_init(uint idx, bool sorted) if (indexing <= 0) { DBUG_PRINT("index_init", ("%s", g->Message)); - printf("index_init CONNECT: %s\n", g->Message); + htrc("index_init CONNECT: %s\n", g->Message); active_index= MAX_KEY; rc= HA_ERR_INTERNAL_ERROR; } else { @@ -2307,7 +2518,7 @@ int ha_connect::index_init(uint idx, bool sorted) } // endif indexing if (xtrace) - printf("index_init: rc=%d indexing=%d active_index=%d\n", + htrc("index_init: rc=%d indexing=%d active_index=%d\n", rc, indexing, active_index); DBUG_RETURN(rc); @@ -2350,13 +2561,13 @@ int ha_connect::ReadIndexed(uchar *buf, OPVAL op, const uchar *key, uint key_len break; default: // Read error DBUG_PRINT("ReadIndexed", ("%s", xp->g->Message)); - printf("ReadIndexed: %s\n", xp->g->Message); + htrc("ReadIndexed: %s\n", xp->g->Message); rc= HA_ERR_INTERNAL_ERROR; break; } // endswitch RC if (xtrace > 1) - printf("ReadIndexed: op=%d rc=%d\n", op, rc); + htrc("ReadIndexed: op=%d rc=%d\n", op, rc); table->status= (rc == RC_OK) ? 0 : STATUS_NOT_FOUND; return rc; @@ -2399,7 +2610,7 @@ int ha_connect::index_read(uchar * buf, const uchar * key, uint key_len, } // endswitch find_flag if (xtrace > 1) - printf("%p index_read: op=%d\n", this, op); + htrc("%p index_read: op=%d\n", this, op); if (indexing > 0) rc= ReadIndexed(buf, op, key, key_len); @@ -2542,7 +2753,7 @@ int ha_connect::rnd_init(bool scan) } // endif xmod if (xtrace) - printf("rnd_init: this=%p scan=%d xmod=%d alter=%d\n", + htrc("rnd_init: this=%p scan=%d xmod=%d alter=%d\n", this, scan, xmod, alter); if (!g || !table || xmod == MODE_INSERT) @@ -2637,22 +2848,23 @@ int ha_connect::rnd_next(uchar *buf) rc= HA_ERR_RECORD_DELETED; break; default: // Read error - printf("rnd_next CONNECT: %s\n", xp->g->Message); + htrc("rnd_next CONNECT: %s\n", xp->g->Message); rc= (records()) ? HA_ERR_INTERNAL_ERROR : HA_ERR_END_OF_FILE; break; } // endswitch RC -#ifndef DBUG_OFF - if (rc || !(xp->nrd++ % 16384)) { + if (xtrace > 1 && (rc || !(xp->nrd++ % 16384))) { ulonglong tb2= my_interval_timer(); double elapsed= (double) (tb2 - xp->tb1) / 1000000000ULL; DBUG_PRINT("rnd_next", ("rc=%d nrd=%u fnd=%u nfd=%u sec=%.3lf\n", rc, (uint)xp->nrd, (uint)xp->fnd, (uint)xp->nfd, elapsed)); + htrc("rnd_next: rc=%d nrd=%u fnd=%u nfd=%u sec=%.3lf\n", + rc, (uint)xp->nrd, (uint)xp->fnd, + (uint)xp->nfd, elapsed); xp->tb1= tb2; xp->fnd= xp->nfd= 0; } // endif nrd -#endif table->status= (!rc) ? 0 : STATUS_NOT_FOUND; DBUG_RETURN(rc); @@ -2766,7 +2978,7 @@ int ha_connect::info(uint flag) DBUG_ENTER("ha_connect::info"); if (xtrace) - printf("%p In info: flag=%u valid_info=%d\n", this, flag, valid_info); + htrc("%p In info: flag=%u valid_info=%d\n", this, flag, valid_info); if (!valid_info) { // tdbp must be available to get updated info @@ -2879,7 +3091,7 @@ int ha_connect::delete_all_rows() if (!(rc= OpenTable(g))) { if (CntDeleteRow(g, tdbp, true)) { - printf("%s\n", g->Message); + htrc("%s\n", g->Message); rc= HA_ERR_INTERNAL_ERROR; } // endif @@ -2989,8 +3201,8 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, { if (xtrace) { LEX_STRING *query_string= thd_query_string(thd); - printf("%p check_mode: cmdtype=%d\n", this, thd_sql_command(thd)); - printf("Cmd=%.*s\n", (int) query_string->length, query_string->str); + htrc("%p check_mode: cmdtype=%d\n", this, thd_sql_command(thd)); + htrc("Cmd=%.*s\n", (int) query_string->length, query_string->str); } // endif xtrace // Next code is temporarily replaced until sql_command is set @@ -3040,7 +3252,7 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, newmode= MODE_ALTER; break; default: - printf("Unsupported sql_command=%d", thd_sql_command(thd)); + htrc("Unsupported sql_command=%d", thd_sql_command(thd)); strcpy(g->Message, "CONNECT Unsupported command"); my_message(ER_NOT_ALLOWED_COMMAND, g->Message, MYF(0)); newmode= MODE_ERROR; @@ -3085,7 +3297,7 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, newmode= MODE_ALTER; break; default: - printf("Unsupported sql_command=%d", thd_sql_command(thd)); + htrc("Unsupported sql_command=%d", thd_sql_command(thd)); strcpy(g->Message, "CONNECT Unsupported command"); my_message(ER_NOT_ALLOWED_COMMAND, g->Message, MYF(0)); newmode= MODE_ERROR; @@ -3095,7 +3307,7 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, } // endif's newmode if (xtrace) - printf("New mode=%d\n", newmode); + htrc("New mode=%d\n", newmode); return newmode; } // end of check_mode @@ -3170,7 +3382,7 @@ int ha_connect::external_lock(THD *thd, int lock_type) DBUG_ASSERT(thd == current_thd); if (xtrace) - printf("external_lock: this=%p thd=%p xp=%p g=%p lock_type=%d\n", + htrc("external_lock: this=%p thd=%p xp=%p g=%p lock_type=%d\n", this, thd, xp, g, lock_type); if (!g) @@ -3309,7 +3521,7 @@ int ha_connect::external_lock(THD *thd, int lock_type) if (check_privileges(thd, options, table->s->db.str)) { strcpy(g->Message, "This operation requires the FILE privilege"); - printf("%s\n", g->Message); + htrc("%s\n", g->Message); DBUG_RETURN(HA_ERR_INTERNAL_ERROR); } // endif check_privileges @@ -3343,18 +3555,18 @@ int ha_connect::external_lock(THD *thd, int lock_type) if (xtrace) { #if 0 - printf("xcheck=%d cras=%d\n", xcheck, cras); + htrc("xcheck=%d cras=%d\n", xcheck, cras); if (xcheck) - printf("oldsep=%d oldpix=%p\n", + htrc("oldsep=%d oldpix=%p\n", ((PCHK)g->Xchk)->oldsep, ((PCHK)g->Xchk)->oldpix); #endif // 0 - printf("Calling CntCheckDB db=%s cras=%d\n", GetDBName(NULL), cras); + htrc("Calling CntCheckDB db=%s cras=%d\n", GetDBName(NULL), cras); } // endif xtrace // Set or reset the good database environment if (CntCheckDB(g, this, GetDBName(NULL))) { - printf("%p external_lock: %s\n", this, g->Message); + htrc("%p external_lock: %s\n", this, g->Message); rc= HA_ERR_INTERNAL_ERROR; // This can NOT be called without open called first, but // the table can have been closed since then @@ -3375,7 +3587,7 @@ int ha_connect::external_lock(THD *thd, int lock_type) } // endif tdbp if (xtrace) - printf("external_lock: rc=%d\n", rc); + htrc("external_lock: rc=%d\n", rc); DBUG_RETURN(rc); } // end of external_lock @@ -3517,10 +3729,10 @@ int ha_connect::delete_or_rename_table(const char *name, const char *to) if (xtrace) { if (to) - printf("rename_table: this=%p thd=%p sqlcom=%d from=%s to=%s\n", + htrc("rename_table: this=%p thd=%p sqlcom=%d from=%s to=%s\n", this, thd, sqlcom, name, to); else - printf("delete_table: this=%p thd=%p sqlcom=%d name=%s\n", + htrc("delete_table: this=%p thd=%p sqlcom=%d name=%s\n", this, thd, sqlcom, name); } // endif xtrace @@ -3625,7 +3837,7 @@ ha_rows ha_connect::records_in_range(uint inx, key_range *min_key, index_init(inx, false); if (xtrace) - printf("records_in_range: inx=%d indexing=%d\n", inx, indexing); + htrc("records_in_range: inx=%d indexing=%d\n", inx, indexing); if (indexing > 0) { int nval; @@ -4626,7 +4838,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, table= table_arg; // Used by called functions if (xtrace) - printf("create: this=%p thd=%p xp=%p g=%p sqlcom=%d name=%s\n", + htrc("create: this=%p thd=%p xp=%p g=%p sqlcom=%d name=%s\n", this, thd, xp, g, sqlcom, GetTableName()); // CONNECT engine specific table options: @@ -4954,7 +5166,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, } // endif if (xtrace) - printf("xchk=%p createas=%d\n", g->Xchk, g->Createas); + htrc("xchk=%p createas=%d\n", g->Xchk, g->Createas); // To check whether indices have to be made or remade if (!g->Xchk) { @@ -4985,7 +5197,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, cat->SetDataPath(g, table_arg->s->db.str); if ((rc= optimize(table->in_use, NULL))) { - printf("Create rc=%d %s\n", rc, g->Message); + htrc("Create rc=%d %s\n", rc, g->Message); my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); rc= HA_ERR_INTERNAL_ERROR; } else @@ -5025,7 +5237,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, g->Xchk= NULL; if (xtrace && g->Xchk) - printf("oldsep=%d newsep=%d oldpix=%p newpix=%p\n", + htrc("oldsep=%d newsep=%d oldpix=%p newpix=%p\n", xcp->oldsep, xcp->newsep, xcp->oldpix, xcp->newpix); // if (g->Xchk && @@ -5306,7 +5518,7 @@ ha_connect::check_if_supported_inplace_alter(TABLE *altered_table, tshp= NULL; if (xtrace && g->Xchk) - printf( + htrc( "oldsep=%d newsep=%d oldopn=%s newopn=%s oldpix=%p newpix=%p\n", xcp->oldsep, xcp->newsep, SVP(xcp->oldopn), SVP(xcp->newopn), diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h index 1bd3991e907..a2d3c5d6801 100644 --- a/storage/connect/ha_connect.h +++ b/storage/connect/ha_connect.h @@ -334,8 +334,11 @@ public: condition stack. */ virtual const COND *cond_push(const COND *cond); -PFIL CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond); +PCFIL CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond); const char *GetValStr(OPVAL vop, bool neg); +#if defined(BLK_INDX) +PFIL CondFilter(PGLOBAL g, Item *cond); +#endif // BLK_INDX /** Number of rows in table. It will only be called if diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index e251ded13df..99e9fb8fb08 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -29,6 +29,10 @@ enum BLKTYP {TYPE_TABLE = 50, /* Table Name/Srcdef/... Block */ // TYPE_OPVAL = 52, /* Operator value (OPVAL) */ TYPE_TDB = 53, /* Table Description Block */ TYPE_COLBLK = 54, /* Column Description Block */ +#if defined(BLK_INDX) + TYPE_FILTER = 55, /* Filter Description Block */ + TYPE_ARRAY = 63, /* General array type */ +#endif // BLK_INDX TYPE_PSZ = 64, /* Pointer to String ended by 0 */ TYPE_SQL = 65, /* Pointer to SQL block */ TYPE_XOBJECT = 69, /* Extended DB object */ @@ -144,21 +148,19 @@ enum RECFM {RECFM_NAF = -2, /* Not a file */ RECFM_PLG = 5, /* Table accessed via PLGconn */ RECFM_DBF = 6}; /* DBase formatted file */ -#if 0 enum MISC {DB_TABNO = 1, /* DB routines in Utility Table */ MAX_MULT_KEY = 10, /* Max multiple key number */ NAM_LEN = 128, /* Length of col and tab names */ ARRAY_SIZE = 50, /* Default array block size */ - MAXRES = 500, /* Default maximum result lines */ - MAXLIN = 10000, /* Default maximum data lines */ +// MAXRES = 500, /* Default maximum result lines */ +// MAXLIN = 10000, /* Default maximum data lines */ MAXBMP = 32}; /* Default XDB2 max bitmap size */ +#if 0 enum ALGMOD {AMOD_AUTO = 0, /* PLG chooses best algorithm */ AMOD_SQL = 1, /* Use SQL algorithm */ AMOD_QRY = 2}; /* Use QUERY algorithm */ -#else // !0 -#define NAM_LEN 128 -#endif // !0 +#endif // 0 enum MODE {MODE_ERROR = -1, /* Invalid mode */ MODE_ANY = 0, /* Unspecified mode */ @@ -342,7 +344,7 @@ typedef class XTAB *PTABLE; typedef class COLUMN *PCOLUMN; typedef class XOBJECT *PXOB; typedef class COLBLK *PCOL; -typedef class TBX *PTBX; +//pedef class TBX *PTBX; typedef class TDB *PTDB; typedef void *PSQL; // Not used typedef class TDBASE *PTDBASE; @@ -376,6 +378,9 @@ typedef class COLDEF *PCOLDEF; typedef class CONSTANT *PCONST; typedef class VALUE *PVAL; typedef class VALBLK *PVBLK; +#if defined(BLK_INDX) +typedef class FILTER *PFIL; +#endif // BLK_INDX typedef struct _fblock *PFBLOCK; typedef struct _mblock *PMBLOCK; @@ -431,7 +436,9 @@ typedef struct { /* User application block */ //int Maxres; /* Result Max nb of lines */ //int Maxtmp; /* Intermediate tables Maxres */ //int Maxlin; /* Query Max nb of data lines */ -//int Maxbmp; /* Maximum XDB2 bitmap size */ +#if defined(BLK_INDX) + int Maxbmp; /* Maximum XDB2 bitmap size */ +#endif // BLK_INDX int Check; /* General level of checking */ int Numlines; /* Number of lines involved */ //ALGMOD AlgChoice; /* Choice of algorithm mode */ @@ -481,6 +488,38 @@ typedef struct _tabs { PTABADR P3; } TABS; +#if defined(BLK_INDX) +/***********************************************************************/ +/* Argument of expression, function, filter etc. (Xobject) */ +/***********************************************************************/ +typedef struct _arg { /* Argument */ + PXOB To_Obj; /* To the argument object */ + PVAL Value; /* Argument value */ + bool Conv; /* TRUE if conversion is required */ + } ARGBLK, *PARG; + +typedef struct _oper { /* Operator */ + PSZ Name; /* The input/output operator name */ + OPVAL Val; /* Operator numeric value */ + int Mod; /* The modificator */ + } OPER, *POPER; + +#if 0 +/***********************************************************************/ +/* Definitions and table of Scalar Functions. */ +/***********************************************************************/ +typedef struct _sfdsc { /* Scalar function description block*/ + char Name[16]; /* Scalar function name */ + EVAL EvalType; /* Type of Init and Eval functions */ + OPVAL Op; /* Equivalent operator number */ + int R_Type; /* Result Type */ + int R_Length; /* Result Length */ + int R_Prec; /* Result Precision */ + int Numarg; /* Number of arguments */ + } SFDSC, *PSFDSC; +#endif // 0 +#endif // BLK_INDX + /***********************************************************************/ /* Following definitions are used to define table fields (columns). */ /***********************************************************************/ diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index c51100e0141..f52515e540b 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -382,7 +382,9 @@ PDBUSER PlgMakeUser(PGLOBAL g) //#endif //dbuserp->Maxres = MAXRES; //dbuserp->Maxlin = MAXLIN; -//dbuserp->Maxbmp = MAXBMP; +#if defined(BLK_INDX) + dbuserp->Maxbmp = MAXBMP; +#endif // BLK_INDX //dbuserp->AlgChoice = AMOD_AUTO; dbuserp->UseTemp = TMP_AUTO; dbuserp->Check = CHK_ALL; diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp index 81c9bf9faca..a36901a5d65 100644 --- a/storage/connect/reldef.cpp +++ b/storage/connect/reldef.cpp @@ -204,6 +204,7 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g) return xdefp; } // end of GetXdef +#if 0 /***********************************************************************/ /* DeleteTableFile: Delete an OEM table file if applicable. */ /***********************************************************************/ @@ -214,6 +215,7 @@ bool OEMDEF::DeleteTableFile(PGLOBAL g) return (Pxdef) ? Pxdef->DeleteTableFile(g) : true; } // end of DeleteTableFile +#endif // 0 /***********************************************************************/ /* Define: initialize the table definition block from XDB file. */ @@ -285,8 +287,11 @@ PTDB OEMDEF::GetTable(PGLOBAL g, MODE mode) if (cmpr == 1) txfp = new(g) ZIPFAM(defp); else { +#if defined(BLK_INDX) + txfp = new(g) ZLBFAM(defp); +#else // !BLK_INDX strcpy(g->Message, "Compress 2 not supported yet"); -// txfp = new(g) ZLBFAM(defp); +#endif // !BLK_INDX return NULL; } // endelse #else // !ZIP_SUPPORT @@ -339,6 +344,7 @@ COLCRT::COLCRT(PSZ name) Offset = -1; Long = -1; Precision = -1; + Freq = -1; Key = -1; Scale = -1; Opt = -1; @@ -355,6 +361,7 @@ COLCRT::COLCRT(void) Offset = 0; Long = 0; Precision = 0; + Freq = 0; Key = 0; Scale = 0; Opt = 0; @@ -368,6 +375,16 @@ COLCRT::COLCRT(void) /***********************************************************************/ COLDEF::COLDEF(void) : COLCRT() { +#if defined(BLK_INDX) + To_Min = NULL; + To_Max = NULL; + To_Pos = NULL; + Xdb2 = FALSE; + To_Bmap = NULL; + To_Dval = NULL; + Ndv = 0; + Nbm = 0; +#endif // BLK_INDX Buf_Type = TYPE_ERROR; Clen = 0; Poff = 0; @@ -401,7 +418,7 @@ int COLDEF::Define(PGLOBAL g, void *memp, PCOLINFO cfp, int poff) Long = cfp->Length; Opt = cfp->Opt; Key = cfp->Key; -// Freq = cfp->Freq; + Freq = cfp->Freq; if (cfp->Remark && *cfp->Remark) { Desc = (PSZ)PlugSubAlloc(g, memp, strlen(cfp->Remark) + 1); diff --git a/storage/connect/reldef.h b/storage/connect/reldef.h index a877c8ee915..c54d81f30cb 100644 --- a/storage/connect/reldef.h +++ b/storage/connect/reldef.h @@ -38,7 +38,7 @@ class DllExport RELDEF : public BLOCK { // Relation definition block void SetCat(PCATLG cat) { Cat=cat; } // Methods - virtual bool DeleteTableFile(PGLOBAL g) {return true;} +//virtual bool DeleteTableFile(PGLOBAL g) {return true;} virtual bool Indexable(void) {return false;} virtual bool Define(PGLOBAL g, PCATLG cat, LPCSTR name, LPCSTR am) = 0; virtual PTDB GetTable(PGLOBAL g, MODE mode) = 0; @@ -116,7 +116,7 @@ class DllExport OEMDEF : public TABDEF { /* OEM table */ virtual AMT GetDefType(void) {return TYPE_AM_OEM;} // Methods - virtual bool DeleteTableFile(PGLOBAL g); +//virtual bool DeleteTableFile(PGLOBAL g); virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); virtual PTDB GetTable(PGLOBAL g, MODE mode); @@ -148,6 +148,7 @@ class DllExport COLCRT : public BLOCK { /* Column description block PSZ GetDecode(void) {return Decode;} PSZ GetFmt(void) {return Fmt;} int GetOpt(void) {return Opt;} + int GetFreq(void) {return Freq;} int GetLong(void) {return Long;} int GetPrecision(void) {return Precision;} int GetOffset(void) {return Offset;} @@ -165,6 +166,7 @@ class DllExport COLCRT : public BLOCK { /* Column description block int Precision; /* Logical column length */ int Scale; /* Decimals for float/decimal values */ int Opt; /* 0:Not 1:clustered 2:sorted-asc 3:desc */ + int Freq; /* Estimated number of different values */ char DataType; /* Internal data type (C, N, F, T) */ }; // end of COLCRT @@ -188,10 +190,36 @@ class DllExport COLDEF : public COLCRT { /* Column description block int GetClen(void) {return Clen;} int GetType(void) {return Buf_Type;} int GetPoff(void) {return Poff;} +#if defined(BLK_INDX) + void *GetMin(void) {return To_Min;} + void SetMin(void *minp) {To_Min = minp;} + void *GetMax(void) {return To_Max;} + void SetMax(void *maxp) {To_Max = maxp;} + bool GetXdb2(void) {return Xdb2;} + void SetXdb2(bool b) {Xdb2 = b;} + void *GetBmap(void) {return To_Bmap;} + void SetBmap(void *bmp) {To_Bmap = bmp;} + void *GetDval(void) {return To_Dval;} + void SetDval(void *dvp) {To_Dval = dvp;} + int GetNdv(void) {return Ndv;} + void SetNdv(int ndv) {Ndv = ndv;} + int GetNbm(void) {return Nbm;} + void SetNbm(int nbm) {Nbm = nbm;} +#endif // BLK_INDX int Define(PGLOBAL g, void *memp, PCOLINFO cfp, int poff); void Define(PGLOBAL g, PCOL colp); protected: +#if defined(BLK_INDX) + void *To_Min; /* Point to array of block min values */ + void *To_Max; /* Point to array of block max values */ + int *To_Pos; /* Point to array of block positions */ + bool Xdb2; /* TRUE if to be optimized by XDB2 */ + void *To_Bmap; /* To array of block bitmap values */ + void *To_Dval; /* To array of column distinct values */ + int Ndv; /* Number of distinct values */ + int Nbm; /* Number of ULONG in bitmap (XDB2) */ +#endif // BLK_INDX int Buf_Type; /* Internal data type */ int Clen; /* Internal data size in chars (bytes) */ int Poff; /* Calculated offset for Packed tables */ diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp index 15215dc0f01..c1da09080cb 100644 --- a/storage/connect/tabdos.cpp +++ b/storage/connect/tabdos.cpp @@ -1,11 +1,11 @@ /************* TabDos C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABDOS */ /* ------------- */ -/* Version 4.8 */ +/* Version 4.9 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2014 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -57,27 +57,32 @@ #include "tabdos.h" #include "tabfix.h" #include "tabmul.h" - -#define PLGINI "plugdb.ini" // Configuration settings file - -#if defined(UNIX) -#define _fileno fileno -#define _O_RDONLY O_RDONLY -#endif +#if defined(BLK_INDX) +#include "array.h" +#include "blkfil.h" +//nclude "token.h" +//#include "scalfnc.h" +#endif // BLK_INDX /***********************************************************************/ /* DB static variables. */ /***********************************************************************/ int num_read, num_there, num_eq[2]; // Statistics -extern "C" char plgini[_MAX_PATH]; extern "C" int trace; +#if defined(BLK_INDX) +/***********************************************************************/ +/* Size of optimize file header. */ +/***********************************************************************/ +#define NZ 4 + /***********************************************************************/ -/* Min and Max blocks contains zero ended fields (blank = false). */ -/* No conversion of block values (check = true). */ +/* Min and Max blocks contains zero ended fields (blank = FALSE). */ +/* No conversion of block values (check = TRUE). */ /***********************************************************************/ PVBLK AllocValBlock(PGLOBAL, void *, int, int, int len = 0, int prec = 0, - bool check = true, bool blank = false, bool un = false); + bool check = TRUE, bool blank = FALSE, bool un = FALSE); +#endif // BLK_INDX /* --------------------------- Class DOSDEF -------------------------- */ @@ -96,7 +101,11 @@ DOSDEF::DOSDEF(void) Huge = false; Accept = false; Eof = false; +#if defined(BLK_INDX) To_Pos = NULL; + Optimized = 0; + AllocBlks = 0; +#endif // BLK_INDX Compressed = 0; Lrecl = 0; AvgLen = 0; @@ -110,6 +119,98 @@ DOSDEF::DOSDEF(void) } // end of DOSDEF constructor /***********************************************************************/ +/* DefineAM: define specific AM block values from XDB file. */ +/***********************************************************************/ +bool DOSDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) + { + char buf[8]; + bool map = (am && (*am == 'M' || *am == 'm')); + LPCSTR dfm = (am && (*am == 'F' || *am == 'f')) ? "F" + : (am && (*am == 'B' || *am == 'b')) ? "B" + : (am && !stricmp(am, "DBF")) ? "D" : "V"; + + Desc = Fn = Cat->GetStringCatInfo(g, "Filename", NULL); + Ofn = Cat->GetStringCatInfo(g, "Optname", Fn); + Cat->GetCharCatInfo("Recfm", (PSZ)dfm, buf, sizeof(buf)); + Recfm = (toupper(*buf) == 'F') ? RECFM_FIX : + (toupper(*buf) == 'B') ? RECFM_BIN : + (toupper(*buf) == 'D') ? RECFM_DBF : RECFM_VAR; + Lrecl = Cat->GetIntCatInfo("Lrecl", 0); + + if (Recfm != RECFM_DBF) + Compressed = Cat->GetIntCatInfo("Compressed", 0); + + Mapped = Cat->GetBoolCatInfo("Mapped", map); + Block = Cat->GetIntCatInfo("Blocks", 0); + Last = Cat->GetIntCatInfo("Last", 0); + Ending = Cat->GetIntCatInfo("Ending", CRLF); + + if (Recfm == RECFM_FIX || Recfm == RECFM_BIN) { + Huge = Cat->GetBoolCatInfo("Huge", Cat->GetDefHuge()); + Padded = Cat->GetBoolCatInfo("Padded", false); + Blksize = Cat->GetIntCatInfo("Blksize", 0); + Eof = (Cat->GetIntCatInfo("EOF", 0) != 0); + } else if (Recfm == RECFM_DBF) { + Maxerr = Cat->GetIntCatInfo("Maxerr", 0); + Accept = (Cat->GetIntCatInfo("Accept", 0) != 0); + ReadMode = Cat->GetIntCatInfo("Readmode", 0); + } else // (Recfm == RECFM_VAR) + AvgLen = Cat->GetIntCatInfo("Avglen", 0); + + // Ignore wrong Index definitions for catalog commands + return (Cat->GetIndexInfo(g, this) /*&& !Cat->GetCatFnc()*/); + } // end of DefineAM + +#if 0 +#if defined(BLK_INDX) +/***********************************************************************/ +/* DeleteTableFile: Delete DOS/UNIX table files using platform API. */ +/* If the table file is protected (declared as read/only) we still */ +/* erase the the eventual optimize and index files but return TRUE. */ +/***********************************************************************/ +bool DOSDEF::DeleteTableFile(PGLOBAL g) + { + char filename[_MAX_PATH]; + bool rc, irc, orc = FALSE; + PIXDEF pxd; + PCOLDEF cdp = NULL; + + /*********************************************************************/ + /* Check for potential optimization. These tests are done */ + /* because Optimized is set to 1 only after the first use of an */ + /* optimized table and can be 0 if it has not been used yet. */ + /*********************************************************************/ + if (!Optimized) + for (cdp = To_Cols; cdp; cdp = cdp->GetNext()) + if (cdp->GetOpt()) + break; + + if (IsOptimized() || cdp || (Recfm == RECFM_VAR && Elemt > 1 && Block)) + if (!GetOptFileName(g, filename)) +#if defined(WIN32) + orc = !DeleteFile(filename); +#else // UNIX + orc = remove(filename); +#endif // WIN32 + + // Now delete the table file itself if not protected + if (!IsReadOnly()) { + rc = Erase(filename); + } else + rc = true; + + // Delete eventual index file(s) + if ((pxd = To_Indx)) { + To_Indx = NULL; // So file can be erase + irc = DeleteIndexFile(g, pxd); + } else + irc = false; + + return rc || orc || irc; // Return TRUE if error + } // end of DeleteTableFile + +#else // !BLK_INDX +/***********************************************************************/ /* DeleteTableFile: Delete DOS/UNIX table files using platform API. */ /* If the table file is protected (declared as read/only) we still */ /* erase the the eventual optimize and index files but return true. */ @@ -127,6 +228,7 @@ bool DOSDEF::DeleteTableFile(PGLOBAL g) return rc; // Return true if error } // end of DeleteTableFile +#endif // !BLK_INDX /***********************************************************************/ /* Erase: This was made a separate routine because a strange thing */ @@ -147,6 +249,66 @@ bool DOSDEF::Erase(char *filename) return rc; // Return true if error } // end of Erase +#endif // 0 + +#if defined(BLK_INDX) +/***********************************************************************/ +/* Get the full path/name of the optization file. */ +/***********************************************************************/ +bool DOSDEF::GetOptFileName(PGLOBAL g, char *filename) + { + char *ftype; + + switch (Recfm) { + case RECFM_VAR: ftype = ".dop"; break; + case RECFM_FIX: ftype = ".fop"; break; + case RECFM_BIN: ftype = ".bop"; break; + case RECFM_VCT: ftype = ".vop"; break; + case RECFM_DBF: ftype = ".dbp"; break; + default: + sprintf(g->Message, MSG(INVALID_FTYPE), Recfm); + return TRUE; + } // endswitch Ftype + + PlugSetPath(filename, Ofn, GetPath()); + strcat(PlugRemoveType(filename, filename), ftype); + return FALSE; + } // end of GetOptFileName + +/***********************************************************************/ +/* After an optimize error occured, remove all set optimize values. */ +/***********************************************************************/ +void DOSDEF::RemoveOptValues(PGLOBAL g) + { + char filename[_MAX_PATH]; + PCOLDEF cdp; + + // Delete settings of optimized columns + for (cdp = To_Cols; cdp; cdp = cdp->GetNext()) + if (cdp->GetOpt()) { + cdp->SetMin(NULL); + cdp->SetMax(NULL); + cdp->SetNdv(0); + cdp->SetNbm(0); + cdp->SetDval(NULL); + cdp->SetBmap(NULL); + } // endif Opt + + // Delete block position setting for not fixed tables + To_Pos = NULL; + AllocBlks = 0; + + // Delete any eventually ill formed non matching optimization file + if (!GetOptFileName(g, filename)) +#if defined(WIN32) + DeleteFile(filename); +#else // UNIX + remove(filename); +#endif // WIN32 + + Optimized = 0; + } // end of RemoveOptValues +#endif // BLK_INDX /***********************************************************************/ /* DeleteIndexFile: Delete DOS/UNIX index file(s) using platform API. */ @@ -222,49 +384,6 @@ bool DOSDEF::DeleteIndexFile(PGLOBAL g, PIXDEF pxdf) } // end of DeleteIndexFile /***********************************************************************/ -/* DefineAM: define specific AM block values from XDB file. */ -/***********************************************************************/ -bool DOSDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) - { - char buf[8]; - bool map = (am && (*am == 'M' || *am == 'm')); - LPCSTR dfm = (am && (*am == 'F' || *am == 'f')) ? "F" - : (am && (*am == 'B' || *am == 'b')) ? "B" - : (am && !stricmp(am, "DBF")) ? "D" : "V"; - - Desc = Fn = Cat->GetStringCatInfo(g, "Filename", NULL); - Ofn = Cat->GetStringCatInfo(g, "Optname", Fn); - Cat->GetCharCatInfo("Recfm", (PSZ)dfm, buf, sizeof(buf)); - Recfm = (toupper(*buf) == 'F') ? RECFM_FIX : - (toupper(*buf) == 'B') ? RECFM_BIN : - (toupper(*buf) == 'D') ? RECFM_DBF : RECFM_VAR; - Lrecl = Cat->GetIntCatInfo("Lrecl", 0); - - if (Recfm != RECFM_DBF) - Compressed = Cat->GetIntCatInfo("Compressed", 0); - - Mapped = Cat->GetBoolCatInfo("Mapped", map); - Block = Cat->GetIntCatInfo("Blocks", 0); - Last = Cat->GetIntCatInfo("Last", 0); - Ending = Cat->GetIntCatInfo("Ending", CRLF); - - if (Recfm == RECFM_FIX || Recfm == RECFM_BIN) { - Huge = Cat->GetBoolCatInfo("Huge", Cat->GetDefHuge()); - Padded = Cat->GetBoolCatInfo("Padded", false); - Blksize = Cat->GetIntCatInfo("Blksize", 0); - Eof = (Cat->GetIntCatInfo("EOF", 0) != 0); - } else if (Recfm == RECFM_DBF) { - Maxerr = Cat->GetIntCatInfo("Maxerr", 0); - Accept = (Cat->GetIntCatInfo("Accept", 0) != 0); - ReadMode = Cat->GetIntCatInfo("Readmode", 0); - } else // (Recfm == RECFM_VAR) - AvgLen = Cat->GetIntCatInfo("Avglen", 0); - - // Ignore wrong Index definitions for catalog commands - return (Cat->GetIndexInfo(g, this) /*&& !Cat->GetCatFnc()*/); - } // end of DefineAM - -/***********************************************************************/ /* InvalidateIndex: mark all indexes as invalid. */ /***********************************************************************/ bool DOSDEF::InvalidateIndex(PGLOBAL g) @@ -311,28 +430,35 @@ PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode) txfp = new(g) BGXFAM(this); else if (map) txfp = new(g) MPXFAM(this); + else if (Compressed) { #if defined(ZIP_SUPPORT) - else if (Compressed) txfp = new(g) ZIXFAM(this); -#endif // ZIP_SUPPORT - else +#else // !ZIP_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; +#endif // !ZIP_SUPPORT + } else txfp = new(g) FIXFAM(this); tdbp = new(g) TDBFIX(this, txfp); } else { -#if defined(ZIP_SUPPORT) if (Compressed) { +#if defined(ZIP_SUPPORT) if (Compressed == 1) txfp = new(g) ZIPFAM(this); else { +#if defined(BLK_INDX) + txfp = new(g) ZLBFAM(this); +#else // !BLK_INDX strcpy(g->Message, "Compress 2 not supported yet"); -// txfp = new(g) ZLBFAM(defp); return NULL; +#endif // !BLK_INDX } // endelse - - } else -#endif // ZIP_SUPPORT - if (map) +#else // !ZIP_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; +#endif // !ZIP_SUPPORT + } else if (map) txfp = new(g) MAPFAM(this); else txfp = new(g) DOSFAM(this); @@ -344,6 +470,38 @@ PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode) if (Multiple) tdbp = new(g) TDBMUL(tdbp); +#if defined(BLK_INDX) + else + /*******************************************************************/ + /* For block tables, get eventually saved optimization values. */ + /*******************************************************************/ + if (tdbp->GetBlockValues(g)) { + PushWarning(g, tdbp); +// return NULL; // causes a crash when deleting index + } else if (Recfm == RECFM_VAR || Compressed > 1) { + if (IsOptimized()) { + if (map) { + txfp = new(g) MBKFAM(this); + } else if (Compressed) { +#if defined(ZIP_SUPPORT) + if (Compressed == 1) + txfp = new(g) ZBKFAM(this); + else { + txfp->SetBlkPos(To_Pos); + ((PZLBFAM)txfp)->SetOptimized(To_Pos != NULL); + } // endelse +#else + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; +#endif + } else + txfp = new(g) BLKFAM(this); + + ((PTDBDOS)tdbp)->SetTxfp(txfp); + } // endif Optimized + + } // endif Recfm +#endif // BLK_INDX return tdbp; } // end of GetTable @@ -364,6 +522,13 @@ TDBDOS::TDBDOS(PDOSDEF tdp, PTXF txfp) : TDBASE(tdp) Ftype = tdp->Recfm; To_Line = NULL; Cardinal = -1; +#if defined(BLK_INDX) +//To_BlkIdx = NULL; + To_BlkFil = NULL; + SavFil = NULL; +//Xeval = 0; + Beval = 0; +#endif // BLK_INDX } // end of TDBDOS standard constructor TDBDOS::TDBDOS(PGLOBAL g, PTDBDOS tdbp) : TDBASE(tdbp) @@ -374,6 +539,13 @@ TDBDOS::TDBDOS(PGLOBAL g, PTDBDOS tdbp) : TDBASE(tdbp) Ftype = tdbp->Ftype; To_Line = tdbp->To_Line; Cardinal = tdbp->Cardinal; +#if defined(BLK_INDX) +//To_BlkIdx = tdbp->To_BlkIdx; + To_BlkFil = tdbp->To_BlkFil; + SavFil = tdbp->SavFil; +//Xeval = tdbp->Xeval; + Beval = tdbp->Beval; +#endif // BLK_INDX } // end of TDBDOS copy constructor // Method @@ -416,14 +588,49 @@ void TDBDOS::PrintAM(FILE *f, char *m) /***********************************************************************/ /* Remake the indexes after the table was modified. */ /***********************************************************************/ -int TDBDOS::ResetTableOpt(PGLOBAL g, bool dox) +int TDBDOS::ResetTableOpt(PGLOBAL g, bool dop, bool dox) { - int rc = RC_OK; + int prc = RC_OK, rc = RC_OK; MaxSize = -1; // Size must be recalculated Cardinal = -1; // as well as Cardinality - if (dox) { +#if defined(BLK_INDX) + PTXF xp = Txfp; + + To_Filter = NULL; // Disable filtering +//To_BlkIdx = NULL; // and index filtering + To_BlkFil = NULL; // and block filtering + + if (dop) { + Columns = NULL; // Not used anymore + + if (Txfp->Blocked) { + // MakeBlockValues must be executed in non blocked mode + // except for ZLIB access method. + if (Txfp->GetAmType() == TYPE_AM_MAP) { + Txfp = new(g) MAPFAM((PDOSDEF)To_Def); +#if defined(ZIP_SUPPORT) + } else if (Txfp->GetAmType() == TYPE_AM_ZIP) { + Txfp = new(g) ZIPFAM((PDOSDEF)To_Def); + } else if (Txfp->GetAmType() == TYPE_AM_ZLIB) { + Txfp->Reset(); + ((PZLBFAM)Txfp)->SetOptimized(FALSE); +#endif // ZIP_SUPPORT + } else // (Txfp->GetAmType() == TYPE_AM_BLK) + Txfp = new(g) DOSFAM((PDOSDEF)To_Def); + + Txfp->SetTdbp(this); + } else + Txfp->Reset(); + + Use = USE_READY; // So the table can be reopened + Mode = MODE_ANY; // Just to be clean + rc = MakeBlockValues(g); // Redo optimization + } // endif dop +#endif // BLK_INDX + + if (dox && (rc == RC_OK || rc == RC_INFO)) { // Remake eventual indexes if (Mode != MODE_UPDATE) To_SetCols = NULL; // Only used on Update @@ -432,6 +639,7 @@ int TDBDOS::ResetTableOpt(PGLOBAL g, bool dox) Txfp->Reset(); // New start Use = USE_READY; // So the table can be reopened Mode = MODE_READ; // New mode + prc = rc; if (!(PlgGetUser(g)->Check & CHK_OPT)) { // After the table was modified the indexes @@ -441,11 +649,1020 @@ int TDBDOS::ResetTableOpt(PGLOBAL g, bool dox) // ... or we should remake them. rc = MakeIndex(g, NULL, false); +#if defined(BLK_INDX) + rc = (rc == RC_INFO) ? prc : rc; +#endif // BLK_INDX } // endif dox return rc; } // end of ResetTableOpt +#if defined(BLK_INDX) +/***********************************************************************/ +/* Calculate the block sizes so block I/O can be used and also the */ +/* Min/Max values for clustered/sorted table columns. */ +/***********************************************************************/ +int TDBDOS::MakeBlockValues(PGLOBAL g) + { + int i, lg, nrec, rc; + int curnum, curblk, block, last, savndv, savnbm; + void *savmin, *savmax; + bool blocked, xdb2 = FALSE; +//POOLHEADER save; + PCOLDEF cdp; + PDOSDEF defp = (PDOSDEF)To_Def; + PDOSCOL colp = NULL; + PDBUSER dup = PlgGetUser(g); + PCATLG cat = defp->GetCat(); +//void *memp = cat->GetDescp(); + + if ((nrec = defp->GetElemt()) < 2) { + strcpy(g->Message, MSG(TABLE_NOT_OPT)); + return RC_INFO; // Not to be optimized + } else if (GetMaxSize(g) == 0 || !(dup->Check & CHK_OPT)) { + // Suppress the opt file firstly if the table is void, + // secondly when it was modified with OPTIMIZATION unchecked + // because it is no more valid. + defp->RemoveOptValues(g); // Erase opt file + return RC_OK; // void table + } else if (MaxSize < 0) + return RC_FX; + + defp->SetOptimized(0); + + // Estimate the number of needed blocks + block = (int)((MaxSize + (int)nrec - 1) / (int)nrec); + + // We have to use local variables because Txfp->CurBlk is set + // to Rows+1 by unblocked variable length table access methods. + curblk = -1; + curnum = nrec - 1; + last = 0; + Txfp->Block = block; // This is useful mainly for + Txfp->CurBlk = curblk; // blocked tables (ZLBFAM), for + Txfp->CurNum = curnum; // others it is just to be clean. + + /*********************************************************************/ + /* Allocate the array of block starting positions. */ + /*********************************************************************/ +//if (memp) +// save = *(PPOOLHEADER)memp; + + Txfp->BlkPos = (int*)PlugSubAlloc(g, NULL, (block + 1) * sizeof(int)); + + /*********************************************************************/ + /* Allocate the blocks for clustered columns. */ + /*********************************************************************/ + blocked = Txfp->Blocked; // Save + Txfp->Blocked = TRUE; // So column block can be allocated + + for (cdp = defp->GetCols(), i = 1; cdp; cdp = cdp->GetNext(), i++) + if (cdp->GetOpt()) { + lg = cdp->GetClen(); + + if (cdp->GetFreq() && cdp->GetFreq() <= dup->Maxbmp) { + cdp->SetXdb2(TRUE); + savndv = cdp->GetNdv(); + cdp->SetNdv(0); // Reset Dval number of values + xdb2 = TRUE; + savmax = cdp->GetDval(); + cdp->SetDval(PlugSubAlloc(g, NULL, cdp->GetFreq() * lg)); + savnbm = cdp->GetNbm(); + cdp->SetNbm(0); // Prevent Bmap allocation +// savmin = cdp->GetBmap(); +// cdp->SetBmap(PlugSubAlloc(g, NULL, block * sizeof(int))); + + if (trace) + htrc("Dval(%p) Bmap(%p) col(%d) %s Block=%d lg=%d\n", + cdp->GetDval(), cdp->GetBmap(), i, cdp->GetName(), block, lg); + + // colp will be initialized with proper Dval VALBLK + colp = (PDOSCOL)MakeCol(g, cdp, colp, i); + colp->InitValue(g); // Allocate column value buffer + cdp->SetNbm(savnbm); +// cdp->SetBmap(savmin); // Can be reused if the new size + cdp->SetDval(savmax); // is not greater than this one. + cdp->SetNdv(savndv); + } else { + cdp->SetXdb2(FALSE); // Maxbmp may have been reset + savmin = cdp->GetMin(); + savmax = cdp->GetMax(); + cdp->SetMin(PlugSubAlloc(g, NULL, block * lg)); + cdp->SetMax(PlugSubAlloc(g, NULL, block * lg)); + + if (trace) + htrc("min(%p) max(%p) col(%d) %s Block=%d lg=%d\n", + cdp->GetMin(), cdp->GetMax(), i, cdp->GetName(), block, lg); + + // colp will be initialized with proper opt VALBLK's + colp = (PDOSCOL)MakeCol(g, cdp, colp, i); + colp->InitValue(g); // Allocate column value buffer + cdp->SetMin(savmin); // Can be reused if the number + cdp->SetMax(savmax); // of blocks does not change. + } // endif Freq + + } // endif Clustered + +//if (!colp) +// return RC_INFO; + + Txfp->Blocked = blocked; + + /*********************************************************************/ + /* Now do calculate the optimization values. */ + /*********************************************************************/ + Mode = MODE_READ; + + if (OpenDB(g)) + return RC_FX; + + if (xdb2) { + /*********************************************************************/ + /* Retrieve the distinct values of XDB2 columns. */ + /*********************************************************************/ + if (GetDistinctColumnValues(g, nrec)) + return RC_FX; + + OpenDB(g); // Rewind the table file + } // endif xdb2 + +#if defined(PROG_INFO) + /*********************************************************************/ + /* Initialize progress information */ + /*********************************************************************/ + char *p = (char *)PlugSubAlloc(g, NULL, 24 + strlen(Name)); + + dup->Step = strcat(strcpy(p, MSG(OPTIMIZING)), Name); + dup->ProgMax = GetProgMax(g); + dup->ProgCur = 0; +#endif // SOCKET_MODE || THREAD + + /*********************************************************************/ + /* Make block starting pos and min/max values of cluster columns. */ + /*********************************************************************/ + while ((rc = ReadDB(g)) == RC_OK) { + if (blocked) { + // A blocked FAM class handles CurNum and CurBlk (ZLBFAM) + if (!Txfp->CurNum) + Txfp->BlkPos[Txfp->CurBlk] = Txfp->GetPos(); + + } else { + if (++curnum >= nrec) { + if (++curblk >= block) { + strcpy(g->Message, MSG(BAD_BLK_ESTIM)); + goto err; + } else + curnum = 0; + + // Get block starting position + Txfp->BlkPos[curblk] = Txfp->GetPos(); + } // endif CurNum + + last = curnum + 1; // curnum is zero based + Txfp->CurBlk = curblk; // Used in COLDOS::SetMinMax + Txfp->CurNum = curnum; // Used in COLDOS::SetMinMax + } // endif blocked + + /*******************************************************************/ + /* Now calculate the min and max values for the cluster columns. */ + /*******************************************************************/ + for (colp = (PDOSCOL)Columns; colp; colp = (PDOSCOL)colp->GetNext()) + if (colp->Clustered == 2) { + if (colp->SetBitMap(g)) + goto err; + + } else + if (colp->SetMinMax(g)) + goto err; // Currently: column is not sorted + +#if defined(SOCKET_MODE) || defined(THREAD) +#if defined(SOCKET_MODE) + if (SendProgress(dup)) { + strcpy(g->Message, MSG(OPT_CANCELLED)); + goto err; + } else +#elif defined(THREAD) + if (!dup->Step) { + strcpy(g->Message, MSG(OPT_CANCELLED)); + goto err; + } else +#endif // THREAD + dup->ProgCur = GetProgCur(); +#endif // SOCKET_MODE || THREAD + + } // endwhile + + if (rc == RC_EF) { + Txfp->Nrec = nrec; + + if (blocked) { + Txfp->Block = Txfp->CurBlk + 1; + Txfp->Last = (Txfp->CurNum) ? Txfp->CurNum + 1 : nrec; + } else { + Txfp->Block = curblk + 1; + Txfp->Last = last; + } // endif blocked + + // This is needed to be able to calculate the last block size + Txfp->BlkPos[Txfp->Block] = Txfp->GetNextPos(); + } else + goto err; + + /*********************************************************************/ + /* Save the optimization values for this table. */ + /*********************************************************************/ + if (!SaveBlockValues(g)) { + PCATLG cat = PlgGetCatalog(g); + + defp->Block = Txfp->Block; + defp->Last = Txfp->Last; + CloseDB(g); + cat->SetIntCatInfo("Blocks", Txfp->Block); + cat->SetIntCatInfo("Last", Txfp->Last); + return RC_OK; + } // endif SaveBlockValues + + err: + // Restore Desc memory suballocation +//if (memp) +// *(PPOOLHEADER)memp = save; + + defp->RemoveOptValues(g); + CloseDB(g); + return RC_FX; + } // end of MakeBlockValues + +/***********************************************************************/ +/* Save the block and Min/Max values for this table. */ +/* The problem here is to avoid name duplication, because more than */ +/* one data file can have the same name (but different types) and/or */ +/* the same data file can be used with different block sizes. This is */ +/* why we use Ofn that defaults to the file name but can be set to a */ +/* different name if necessary. */ +/***********************************************************************/ +bool TDBDOS::SaveBlockValues(PGLOBAL g) + { + char filename[_MAX_PATH]; + int lg, n[NZ + 2]; + size_t nbk, ndv, nbm, block = Txfp->Block; + bool rc = FALSE; + FILE *opfile; + PDOSCOL colp; + PDOSDEF defp = (PDOSDEF)To_Def; + + if (defp->GetOptFileName(g, filename)) + return TRUE; + + if (!(opfile = fopen(filename, "wb"))) { + sprintf(g->Message, MSG(OPEN_MODE_ERROR), + "wb", (int)errno, filename); + strcat(strcat(g->Message, ": "), strerror(errno)); + + if (trace) + htrc("%s\n", g->Message); + + return TRUE; + } // endif opfile + + if (Ftype == RECFM_VAR || defp->Compressed == 2) { + /*******************************************************************/ + /* Write block starting positions into the opt file. */ + /*******************************************************************/ + block++; + lg = sizeof(int); + n[0] = Txfp->Last; n[1] = lg; n[2] = Txfp->Nrec; n[3] = Txfp->Block; + + if (fwrite(n, sizeof(int), NZ, opfile) != NZ) { + sprintf(g->Message, MSG(OPT_HEAD_WR_ERR), strerror(errno)); + rc = TRUE; + } // endif size + + if (fwrite(Txfp->BlkPos, lg, block, opfile) != block) { + sprintf(g->Message, MSG(OPTBLK_WR_ERR), strerror(errno)); + rc = TRUE; + } // endif size + + block--; // = Txfp->Block; + } // endif Ftype + + /*********************************************************************/ + /* Write the Min/Max values into the opt file. */ + /*********************************************************************/ + for (colp = (PDOSCOL)Columns; colp; colp = (PDOSCOL)colp->Next) { + lg = colp->Value->GetClen(); + + // Now start the writing process + if (colp->Clustered == 2) { + // New XDB2 block optimization. Will be recognized when reading + // because the column index is negated. + ndv = colp->Ndv; nbm = colp->Nbm; + nbk = nbm * block; + n[0] = -colp->Index; n[1] = lg; n[2] = Txfp->Nrec; n[3] = block; + n[4] = ndv; n[5] = nbm; + + if (fwrite(n, sizeof(int), NZ + 2, opfile) != NZ + 2) { + sprintf(g->Message, MSG(OPT_HEAD_WR_ERR), strerror(errno)); + rc = TRUE; + } // endif size + + if (fwrite(colp->Dval->GetValPointer(), lg, ndv, opfile) != ndv) { + sprintf(g->Message, MSG(OPT_DVAL_WR_ERR), strerror(errno)); + rc = TRUE; + } // endif size + + if (fwrite(colp->Bmap->GetValPointer(), sizeof(int), nbk, opfile) != nbk) { + sprintf(g->Message, MSG(OPT_BMAP_WR_ERR), strerror(errno)); + rc = TRUE; + } // endif size + + } else { + n[0] = colp->Index; n[1] = lg; n[2] = Txfp->Nrec; n[3] = block; + + if (fwrite(n, sizeof(int), NZ, opfile) != NZ) { + sprintf(g->Message, MSG(OPT_HEAD_WR_ERR), strerror(errno)); + rc = TRUE; + } // endif size + + if (fwrite(colp->Min->GetValPointer(), lg, block, opfile) != block) { + sprintf(g->Message, MSG(OPT_MIN_WR_ERR), strerror(errno)); + rc = TRUE; + } // endif size + + if (fwrite(colp->Max->GetValPointer(), lg, block, opfile) != block) { + sprintf(g->Message, MSG(OPT_MAX_WR_ERR), strerror(errno)); + rc = TRUE; + } // endif size + + } // endif Clustered + + } // endfor colp + + fclose(opfile); + return rc; + } // end of SaveBlockValues + +/***********************************************************************/ +/* Read the Min/Max values for this table. */ +/* The problem here is to avoid name duplication, because more than */ +/* one data file can have the same name (but different types) and/or */ +/* the same data file can be used with different block sizes. This is */ +/* why we use Ofn that defaults to the file name but can be set to a */ +/* different name if necessary. */ +/***********************************************************************/ +bool TDBDOS::GetBlockValues(PGLOBAL g) + { + char filename[_MAX_PATH]; + int i, lg, n[NZ]; + int nrec, block, last = 0, allocblk = 0; + int len; + bool newblk = FALSE; + size_t ndv, nbm, nbk, blk; + FILE *opfile; + PCOLDEF cdp; + PDOSDEF defp = (PDOSDEF)To_Def; + PCATLG cat = defp->GetCat(); + + if (defp->Optimized) + return FALSE; // Already done or to be redone + + if (Ftype == RECFM_VAR || defp->Compressed == 2) { + /*******************************************************************/ + /* Variable length file that can be read by block. */ + /*******************************************************************/ + block = defp->GetBlock(); + nrec = (defp->GetElemt()) ? defp->GetElemt() : 1; + last = defp->GetLast(); + + if (nrec > 1 && block) + len = (int)((block - 1) * nrec + last); + else + len = 0; + + if (!len) { + if (nrec > 1) { + // The table can be declared optimized if it is void. + // This is useful to handle Insert in optimized mode. + char filename[_MAX_PATH]; + int h; + int flen = -1; + + PlugSetPath(filename, defp->Fn, GetPath()); + h = open(filename, _O_RDONLY); + flen = (h == -1 && errno == ENOENT) ? 0 : _filelength(h); + defp->SetOptimized((flen) ? 0 : 1); + + if (h != -1) + close(h); + + } // endif nrec + + return FALSE; // Opt file does not exist yet + } else if (len < 0) + return TRUE; // Table error + + cdp = defp->GetCols(); + i = 1; + } else { + /*******************************************************************/ + /* Fixed length file. Opt file exists only for clustered columns. */ + /*******************************************************************/ + // Check for existence of clustered columns + for (cdp = defp->GetCols(), i = 1; cdp; cdp = cdp->GetNext(), i++) + if (cdp->GetOpt()) + break; + + if (!cdp) + return FALSE; // No optimization needed + + if ((len = Cardinality(g)) < 0) + return TRUE; // Table error + else if (!len) + return FALSE; // File does not exist yet + + block = Txfp->Block; // Was set in Cardinality + nrec = Txfp->Nrec; + } // endif Ftype + + if (defp->GetOptFileName(g, filename)) + return TRUE; + + if (!(opfile = fopen(filename, "rb"))) + return FALSE; // No saved values + +//if (memp) { +// save = *(PPOOLHEADER)memp; +// allocblk = defp->GetAllocBlks(); +// } // endif memp + + if (block > allocblk) + newblk = TRUE; // Current allocation is too small + + if (Ftype == RECFM_VAR || defp->Compressed == 2) { + /*******************************************************************/ + /* Read block starting positions from the opt file. */ + /*******************************************************************/ + blk = block + 1; + lg = sizeof(int); + + if (fread(n, sizeof(int), NZ, opfile) != NZ) { + sprintf(g->Message, MSG(OPT_HEAD_RD_ERR), strerror(errno)); + goto err; + } // endif size + + if (n[0] != last || n[1] != lg || n[2] != nrec || n[3] != block) { + sprintf(g->Message, MSG(OPT_NOT_MATCH), filename); + goto err; + } // endif + + if (newblk) + defp->To_Pos = (int*)PlugSubAlloc(g, NULL, blk * lg); + + if (fread(defp->To_Pos, lg, blk, opfile) != blk) { + sprintf(g->Message, MSG(OPTBLK_RD_ERR), strerror(errno)); + goto err; + } // endif size + + } // endif Ftype + + /*********************************************************************/ + /* Read the Min/Max values from the opt file. */ + /*********************************************************************/ + for (; cdp; cdp = cdp->GetNext(), i++) + if (cdp->GetOpt()) { + lg = cdp->GetClen(); + blk = block; + + // Now start the reading process. + if (fread(n, sizeof(int), NZ, opfile) != NZ) { + sprintf(g->Message, MSG(OPT_HEAD_RD_ERR), strerror(errno)); + goto err; + } // endif size + + if (n[0] == -i) { + // Read the XDB2 opt values from the opt file + if (n[1] != lg || n[2] != nrec || n[3] != block) { + sprintf(g->Message, MSG(OPT_NOT_MATCH), filename); + goto err; + } // endif + + if (fread(n, sizeof(int), 2, opfile) != 2) { + sprintf(g->Message, MSG(OPT_HEAD_RD_ERR), strerror(errno)); + goto err; + } // endif fread + + ndv = n[0]; nbm = n[1]; nbk = nbm * blk; + + if (cdp->GetNdv() < (int)ndv || !cdp->GetDval()) + cdp->SetDval(PlugSubAlloc(g, NULL, ndv * lg)); + + cdp->SetNdv((int)ndv); + + if (fread(cdp->GetDval(), lg, ndv, opfile) != ndv) { + sprintf(g->Message, MSG(OPT_DVAL_RD_ERR), strerror(errno)); + goto err; + } // endif size + + if (newblk || cdp->GetNbm() < (int)nbm || !cdp->GetBmap()) + cdp->SetBmap(PlugSubAlloc(g, NULL, nbk * sizeof(int))); + + cdp->SetNbm((int)nbm); + + if (fread(cdp->GetBmap(), sizeof(int), nbk, opfile) != nbk) { + sprintf(g->Message, MSG(OPT_BMAP_RD_ERR), strerror(errno)); + goto err; + } // endif size + + cdp->SetXdb2(TRUE); + } else { + // Read the Min/Max values from the opt file + if (n[0] != i || n[1] != lg || n[2] != nrec || n[3] != block) { + sprintf(g->Message, MSG(OPT_NOT_MATCH), filename); + goto err; + } // endif + + if (newblk || !cdp->GetMin()) + cdp->SetMin(PlugSubAlloc(g, NULL, blk * lg)); + + if (fread(cdp->GetMin(), lg, blk, opfile) != blk) { + sprintf(g->Message, MSG(OPT_MIN_RD_ERR), strerror(errno)); + goto err; + } // endif size + + if (newblk || !cdp->GetMax()) + cdp->SetMax(PlugSubAlloc(g, NULL, blk * lg)); + + if (fread(cdp->GetMax(), lg, blk, opfile) != blk) { + sprintf(g->Message, MSG(OPT_MAX_RD_ERR), strerror(errno)); + goto err; + } // endif size + + cdp->SetXdb2(FALSE); + } // endif n[0] (XDB2) + + } // endif Clustered + + defp->SetBlock(block); + + if (newblk) + defp->SetAllocBlks(block); + + defp->SetOptimized(1); + fclose(opfile); + MaxSize = -1; // Can be refined later + return FALSE; + + err: + defp->RemoveOptValues(g); + fclose(opfile); +//return TRUE; + // Ignore error if not in mode CHK_OPT + return (PlgGetUser(g)->Check & CHK_OPT) != 0; + } // end of GetBlockValues + +/***********************************************************************/ +/* This fonction is used while making XDB2 block optimization. */ +/* It constructs for each elligible columns, the sorted list of the */ +/* distinct values existing in the column. This function uses an */ +/* algorithm that permit to get several sets of distinct values by */ +/* reading the table only once, which cannot be done using a standard */ +/* SQL query. */ +/***********************************************************************/ +bool TDBDOS::GetDistinctColumnValues(PGLOBAL g, int nrec) + { + char *p; + int rc, blk, n = 0; + PDOSCOL colp; + PDBUSER dup = PlgGetUser(g); + + /*********************************************************************/ + /* Initialize progress information */ + /*********************************************************************/ + p = (char *)PlugSubAlloc(g, NULL, 48 + strlen(Name)); + dup->Step = strcat(strcpy(p, MSG(GET_DIST_VALS)), Name); + dup->ProgMax = GetProgMax(g); + dup->ProgCur = 0; + + while ((rc = ReadDB(g)) == RC_OK) { + for (colp = (PDOSCOL)Columns; colp; colp = (PDOSCOL)colp->Next) + if (colp->Clustered == 2) + if (colp->AddDistinctValue(g)) + return TRUE; // Too many distinct values + +#if defined(SOCKET_MODE) + if (SendProgress(dup)) { + strcpy(g->Message, MSG(OPT_CANCELLED)); + return TRUE; + } else +#elif defined(THREAD) + if (!dup->Step) { + strcpy(g->Message, MSG(OPT_CANCELLED)); + return TRUE; + } else +#endif // THREAD + dup->ProgCur = GetProgCur(); + + n++; + } // endwhile + + if (rc != RC_EF) + return TRUE; + + // Reset the number of table blocks +//nrec = ((PDOSDEF)To_Def)->GetElemt(); (or default value) + blk = (n + nrec - 1) / nrec; + Txfp->Block = blk; // Useful mainly for ZLBFAM ??? + + // Set Nbm, Bmap for XDB2 columns + for (colp = (PDOSCOL)Columns; colp; colp = (PDOSCOL)colp->Next) + if (colp->Clustered == 2) { +// colp->Cdp->SetNdv(colp->Ndv); + colp->Nbm = (colp->Ndv + MAXBMP - 1) / MAXBMP; + colp->Bmap = AllocValBlock(g, NULL, TYPE_INT, colp->Nbm * blk); + } // endif Clustered + + return FALSE; + } // end of GetDistinctColumnValues + +/***********************************************************************/ +/* Analyze the filter and construct the Block Evaluation Filter. */ +/* This is possible when a filter contains predicates implying a */ +/* column marked as "clustered" or "sorted" matched to a constant */ +/* argument. It is then possible by comparison against the smallest */ +/* and largest column values in each block to determine whether the */ +/* filter condition will be always true or always false for the block.*/ +/***********************************************************************/ +PBF TDBDOS::InitBlockFilter(PGLOBAL g, PFIL filp) + { + bool blk = Txfp->Blocked; + + if (To_BlkFil) + return To_BlkFil; // Already done + else if (!filp) + return NULL; + else if (blk) { + if (Txfp->GetAmType() == TYPE_AM_DBF) + /*****************************************************************/ + /* If RowID is used in this query, block optimization cannot be */ + /* used because currently the file must be read sequentially. */ + /*****************************************************************/ + for (PCOL cp = Columns; cp; cp = cp->GetNext()) + if (cp->GetAmType() == TYPE_AM_ROWID && !((RIDBLK*)cp)->GetRnm()) + return NULL; + + } // endif blk + + int i, op = filp->GetOpc(), opm = filp->GetOpm(), n = 0; + bool cnv[2]; + PCOL colp; + PXOB arg[2] = {NULL,NULL}; + PBF *fp = NULL, bfp = NULL; + + switch (op) { + case OP_EQ: + case OP_NE: + case OP_GT: + case OP_GE: + case OP_LT: + case OP_LE: + if (! opm) { + for (i = 0; i < 2; i++) { + arg[i] = filp->Arg(i); + cnv[i] = filp->Conv(i); + } // endfor i + + bfp = CheckBlockFilari(g, arg, op, cnv); + break; + } // endif !opm + + // if opm, pass thru + case OP_IN: + if (filp->GetArgType(0) == TYPE_COLBLK && + filp->GetArgType(1) == TYPE_ARRAY) { + arg[0] = filp->Arg(0); + arg[1] = filp->Arg(1); + colp = (PCOL)arg[0]; + + if (colp->GetTo_Tdb() == this) { + // Block evaluation is possible for... + if (colp->GetAmType() == TYPE_AM_ROWID) { + // Special column ROWID and constant array, but + // currently we don't know how to retrieve a RowID + // from a DBF table that is not sequentially read. +// if (Txfp->GetAmType() != TYPE_AM_DBF || +// ((RIDBLK*)arg[0])->GetRnm()) + bfp = new(g) BLKSPCIN(g, this, op, opm, arg, Txfp->Nrec); + + } else if (blk && Txfp->Nrec > 1 && colp->IsClustered()) + // Clustered column and constant array + if (colp->GetClustered() == 2) + bfp = new(g) BLKFILIN2(g, this, op, opm, arg); + else + bfp = new(g) BLKFILIN(g, this, op, opm, arg); + + } // endif this + +#if 0 + } else if (filp->GetArgType(0) == TYPE_SCALF && + filp->GetArgType(1) == TYPE_ARRAY) { + arg[0] = filp->Arg(0); + arg[1] = filp->Arg(1); + + if (((PSCALF)arg[0])->GetOp() == OP_ROW && + arg[1]->GetResultType() == TYPE_LIST) { + PARRAY par = (PARRAY)arg[1]; + LSTVAL *vlp = (LSTVAL*)par->GetValue(); + + ((SFROW*)arg[0])->GetParms(n); + + if (n != vlp->GetN()) + return NULL; + else + n = par->GetNval(); + + arg[1] = new(g) CONSTANT(vlp); + fp = (PBF*)PlugSubAlloc(g, NULL, n * sizeof(PBF)); + cnv[0] = cnv[1] = FALSE; + + if (op == OP_IN) + op = OP_EQ; + + for (i = 0; i < n; i++) { + par->GetNthValue(vlp, i); + + if (!(fp[i] = CheckBlockFilari(g, arg, op, cnv))) + return NULL; + + } // endfor i + + bfp = new(g) BLKFILLOG(this, (opm == 2 ? OP_AND : OP_OR), fp, n); + } // endif ROW +#endif // 0 + + } // endif Type + + break; + case OP_AND: + case OP_OR: + fp = (PBF*)PlugSubAlloc(g, NULL, 2 * sizeof(PBF)); + fp[0] = InitBlockFilter(g, (PFIL)(filp->Arg(0))); + fp[1] = InitBlockFilter(g, (PFIL)(filp->Arg(1))); + + if (fp[0] || fp[1]) + bfp = new(g) BLKFILLOG(this, op, fp, 2); + + break; + case OP_NOT: + fp = (PBF*)PlugSubAlloc(g, NULL, sizeof(PBF)); + + if ((*fp = InitBlockFilter(g, (PFIL)(filp->Arg(0))))) + bfp = new(g) BLKFILLOG(this, op, fp, 1); + + break; + case OP_LIKE: + default: + break; + } // endswitch op + + return bfp; + } // end of InitBlockFilter + +/***********************************************************************/ +/* Analyze the passed arguments and construct the Block Filter. */ +/***********************************************************************/ +PBF TDBDOS::CheckBlockFilari(PGLOBAL g, PXOB *arg, int op, bool *cnv) + { +//int i, n1, n2, ctype = TYPE_ERROR, n = 0, type[2] = {0,0}; +//bool conv = FALSE, xdb2 = FALSE, ok = FALSE, b[2]; +//PXOB *xarg1, *xarg2 = NULL, xp[2]; + int i, ctype = TYPE_ERROR, n = 0, type[2] = {0,0}; + bool conv = FALSE, xdb2 = FALSE, ok = FALSE; + PXOB *xarg2 = NULL, xp[2]; + PCOL colp; +//LSTVAL *vlp = NULL; +//SFROW *sfr[2]; + PBF *fp = NULL, bfp = NULL; + + for (i = 0; i < 2; i++) { + switch (arg[i]->GetType()) { + case TYPE_CONST: + type[i] = 1; + ctype = arg[i]->GetResultType(); + break; + case TYPE_COLBLK: + conv = cnv[i]; + colp = (PCOL)arg[i]; + + if (colp->GetTo_Tdb() == this) { + if (colp->GetAmType() == TYPE_AM_ROWID) { + // Currently we don't know how to retrieve a RowID + // from a DBF table that is not sequentially read. +// if (Txfp->GetAmType() != TYPE_AM_DBF || +// ((RIDBLK*)arg[i])->GetRnm()) + type[i] = 5; + + } else if (Txfp->Blocked && Txfp->Nrec > 1 && + colp->IsClustered()) { + type[i] = 2; + xdb2 = colp->GetClustered() == 2; + } // endif Clustered + + } else if (colp->GetColUse(U_CORREL)) { + // This is a column pointing to the outer query of a + // correlated subquery, it has a constant value during + // each execution of the subquery. + type[i] = 1; + ctype = arg[i]->GetResultType(); + } // endif this + + break; +// case TYPE_SCALF: +// if (((PSCALF)arg[i])->GetOp() == OP_ROW) { +// sfr[i] = (SFROW*)arg[i]; +// type[i] = 7; +// } // endif Op + +// break; + default: + break; + } // endswitch ArgType + + if (!type[i]) + break; + + n += type[i]; + } // endfor i + + if (n == 3 || n == 6) { + if (conv) { + // The constant has not the good type and will not match + // the block min/max values. What we can do here is either + // abort with an error message or simply not do the block + // optimization (as column values can be converted when + // evaluating the filter.) Currently we prefer aborting + // because the user may count on the performance enhancing + // and silently not doing it is probably worse than just + // telling him to fix his query. + sprintf(g->Message, "Block opt: %s", MSG(VALTYPE_NOMATCH)); + longjmp(g->jumper[g->jump_level], 99); + } // endif Conv + + if (type[0] == 1) { + // Make it always as Column-op-Value + *xp = arg[0]; + arg[0] = arg[1]; + arg[1] = *xp; + + switch (op) { + case OP_GT: op = OP_LT; break; + case OP_GE: op = OP_LE; break; + case OP_LT: op = OP_GT; break; + case OP_LE: op = OP_GE; break; + } // endswitch op + + } // endif + +#if defined(_DEBUG) +// assert(arg[0]->GetResultType() == ctype); +#endif + + if (n == 3) { + if (xdb2) { + if (((PDOSCOL)arg[0])->GetNbm() == 1) + bfp = new(g) BLKFILAR2(g, this, op, arg); + else // Multiple bitmap made of several ULONG's + bfp = new(g) BLKFILMR2(g, this, op, arg); + } else + bfp = new(g) BLKFILARI(g, this, op, arg); + + } else // n = 6 + bfp = new(g) BLKSPCARI(this, op, arg, Txfp->Nrec); + +#if 0 + } else if (n == 8 || n == 14) { + if (n == 8 && ctype != TYPE_LIST) { + // Should never happen + strcpy(g->Message, "Block opt: bad constant"); + longjmp(g->jumper[g->jump_level], 99); + } // endif Conv + + if (type[0] == 1) { + // Make it always as Column-op-Value + sfr[0] = sfr[1]; + arg[1] = arg[0]; + + switch (op) { + case OP_GT: op = OP_LT; break; + case OP_GE: op = OP_LE; break; + case OP_LT: op = OP_GT; break; + case OP_LE: op = OP_GE; break; + } // endswitch op + + } // endif + + xarg1 = sfr[0]->GetParms(n1); + + if (n == 8) { + vlp = (LSTVAL*)arg[1]->GetValue(); + n2 = vlp->GetN(); + xp[1] = new(g) CONSTANT((PVAL)NULL); + } else + xarg2 = sfr[1]->GetParms(n2); + + if (n1 != n2) + return NULL; // Should we flag an error ? + + fp = (PBF*)PlugSubAlloc(g, NULL, n1 * sizeof(PBF)); + + for (i = 0; i < n1; i++) { + xp[0] = xarg1[i]; + + if (n == 8) + ((CONSTANT*)xp[1])->SetValue(vlp->GetSubVal(i)); + else + xp[1] = xarg2[i]; + + b[0] = b[1] = (xp[0]->GetResultType() != xp[1]->GetResultType()); + ok |= ((fp[i] = CheckBlockFilari(g, xp, op, b)) != NULL); + } // endfor i + + if (ok) + bfp = new(g) BLKFILLOG(this, OP_AND, fp, n1); +#endif // 0 + + } // endif n + + return bfp; + } // end of CheckBlockFilari + +/***********************************************************************/ +/* ResetBlkFil: reset the block filter and restore filtering. */ +/***********************************************************************/ +void TDBDOS::ResetBlockFilter(PGLOBAL g) + { + if (!To_BlkFil) + return; + + To_BlkFil->Reset(g); + + if (SavFil && !To_Filter) { + // Restore filter if it was disabled by optimization + To_Filter = SavFil; + SavFil = NULL; + } // endif + + Beval = 0; + } // end of ResetBlockFilter + +/***********************************************************************/ +/* Block optimization: evaluate the block index filter against */ +/* the min and max values of this block and return: */ +/* RC_OK: if some records in the block can meet filter criteria. */ +/* RC_NF: if no record in the block can meet filter criteria. */ +/* RC_EF: if no record in the remaining file can meet filter criteria.*/ +/* In addition, temporarily supress filtering if all the records in */ +/* the block meet filter criteria. */ +/***********************************************************************/ +int TDBDOS::TestBlock(PGLOBAL g) + { + int rc = RC_OK; + + if (To_BlkFil && Beval != 2) { + // Check for block filtering evaluation + if (Beval == 1) { + // Filter was removed for last block, restore it + To_Filter = SavFil; + SavFil = NULL; + } // endif Beval + + // Check for valid records in new block + switch (Beval = To_BlkFil->BlockEval(g)) { + case -2: // No more valid values in file + rc = RC_EF; + break; + case -1: // No valid values in block + rc = RC_NF; + break; + case 1: // All block values are valid + case 2: // All subsequent file values are Ok + // Before suppressing the filter for the block(s) it is + // necessary to reset the filtered columns to NOT_READ + // so their new values are retrieved by the SELECT list. + if (To_Filter) // Can be NULL when externally called (XDB) + To_Filter->Reset(); + + SavFil = To_Filter; + To_Filter = NULL; // So remove filter + } // endswitch Beval + + if (trace) + htrc("BF Eval Beval=%d\n", Beval); + + } // endif To_BlkFil + + return rc; + } // end of TestBlock +#endif // BLK_INDX + /***********************************************************************/ /* Check whether we have to create/update permanent indexes. */ /***********************************************************************/ @@ -730,11 +1947,21 @@ bool TDBDOS::OpenDB(PGLOBAL g) /*******************************************************************/ /* Table already open, just replace it at its beginning. */ /*******************************************************************/ - Txfp->Rewind(); // see comment in Work.log + if (!To_Kindex) { + Txfp->Rewind(); // see comment in Work.log - if (SkipHeader(g)) - return true; + if (SkipHeader(g)) + return TRUE; + + } else + /*****************************************************************/ + /* Table is to be accessed through a sorted index table. */ + /*****************************************************************/ + To_Kindex->Reset(); +#if defined(BLK_INDX) + ResetBlockFilter(g); +#endif // BLK_INDX return false; } // endif use @@ -770,6 +1997,13 @@ bool TDBDOS::OpenDB(PGLOBAL g) Use = USE_OPEN; // Do it now in case we are recursively called +#if defined(BLK_INDX) + /*********************************************************************/ + /* Allocate the block filter tree if evaluation is possible. */ + /*********************************************************************/ + To_BlkFil = InitBlockFilter(g, To_Filter); +#endif // BLK_INDX + /*********************************************************************/ /* Allocate the line buffer plus a null character. */ /*********************************************************************/ @@ -928,6 +2162,42 @@ DOSCOL::DOSCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PSZ am) Long = cdp->GetLong(); To_Val = NULL; +#if defined(BLK_INDX) + Clustered = 0; + Sorted = 0; + Ndv = 0; // Currently used only for XDB2 + Nbm = 0; // Currently used only for XDB2 + Min = NULL; + Max = NULL; + Bmap = NULL; + Dval = NULL; + Buf = NULL; + + if (txfp->Blocked && Opt && (cdp->GetMin() || cdp->GetDval())) { + int nblk = txfp->GetBlock(); + + Clustered = (cdp->GetXdb2()) ? 2 : 1; + Sorted = (cdp->GetOpt() > 1) ? 1 : 0; // Currently ascending only + + if (Clustered == 1) { + Min = AllocValBlock(g, cdp->GetMin(), Buf_Type, nblk, Long, prec); + Max = AllocValBlock(g, cdp->GetMax(), Buf_Type, nblk, Long, prec); + } else { // Clustered == 2 + // Ndv is the number of distinct values in Dval. Ndv and Nbm + // may be 0 when optimizing because Ndval is not filled yet, + // but the size of the passed Dval memory block is Ok. + Ndv = cdp->GetNdv(); + Dval = AllocValBlock(g, cdp->GetDval(), Buf_Type, Ndv, Long, prec); + + // Bmap cannot be allocated when optimizing, we must know Nbm first + if ((Nbm = cdp->GetNbm())) + Bmap = AllocValBlock(g, cdp->GetBmap(), TYPE_INT, Nbm * nblk); + + } // endif Clustered + + } // endif Opt +#endif // BLK_INDX + OldVal = NULL; // Currently used only in MinMax Ldz = false; Nod = false; @@ -969,8 +2239,19 @@ DOSCOL::DOSCOL(DOSCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp) Dcm = col1->Dcm; OldVal = col1->OldVal; Buf = col1->Buf; +#if defined(BLK_INDX) + Clustered = col1->Clustered; + Sorted = col1->Sorted; + Min = col1->Min; + Max = col1->Max; + Bmap = col1->Bmap; + Dval = col1->Dval; + Ndv = col1->Ndv; + Nbm = col1->Nbm; +#endif // BLK_INDX } // end of DOSCOL copy constructor +#if defined(BLK_INDX) /***********************************************************************/ /* VarSize: This function tells UpdateDB whether or not the block */ /* optimization file must be redone if this column is updated, even */ @@ -992,6 +2273,7 @@ bool DOSCOL::VarSize(void) return false; } // end VarSize +#endif // BLK_INDX /***********************************************************************/ /* SetBuffer: prepare a column block for write operation. */ @@ -1151,6 +2433,13 @@ void DOSCOL::WriteColumn(PGLOBAL g) htrc("Lrecl=%d deplac=%d int=%d\n", tdbp->Lrecl, Deplac, Long); field = Long; + len = (signed)strlen(tdbp->To_Line); + + if (tdbp->GetAmType() == TYPE_AM_DOS && len > tdbp->Lrecl) { + sprintf(g->Message, "Line size %d is bigger than lrecl %d", + len, tdbp->Lrecl); + longjmp(g->jumper[g->jump_level], 32); + } // endif if (tdbp->Ftype == RECFM_VAR && tdbp->Mode == MODE_UPDATE) { len = (signed)strlen(tdbp->To_Line); @@ -1269,6 +2558,146 @@ void DOSCOL::WriteColumn(PGLOBAL g) } // end of WriteColumn +#if defined(BLK_INDX) +/***********************************************************************/ +/* SetMinMax: Calculate minimum and maximum values for one block. */ +/* Note: TYPE_STRING is stored and processed with zero ended strings */ +/* to be matching the way the FILTER Eval function processes them. */ +/***********************************************************************/ +bool DOSCOL::SetMinMax(PGLOBAL g) + { + PTDBDOS tp = (PTDBDOS)To_Tdb; + + ReadColumn(g); // Extract column value from current line + + if (CheckSorted(g)) + return TRUE; + + if (!tp->Txfp->CurNum) { + Min->SetValue(Value, tp->Txfp->CurBlk); + Max->SetValue(Value, tp->Txfp->CurBlk); + } else { + Min->SetMin(Value, tp->Txfp->CurBlk); + Max->SetMax(Value, tp->Txfp->CurBlk); + } // endif CurNum + + return FALSE; + } // end of SetMinMax + +/***********************************************************************/ +/* SetBitMap: Calculate the bit map of existing values in one block. */ +/* Note: TYPE_STRING is processed with zero ended strings */ +/* to be matching the way the FILTER Eval function processes them. */ +/***********************************************************************/ +bool DOSCOL::SetBitMap(PGLOBAL g) + { + int i, m, n; + PULONG bmp; + PTDBDOS tp = (PTDBDOS)To_Tdb; + PDBUSER dup = PlgGetUser(g); + + n = tp->Txfp->CurNum; + bmp = (PULONG)Bmap->GetValPtr(Nbm * tp->Txfp->CurBlk); + + // Extract column value from current line + ReadColumn(g); + + if (CheckSorted(g)) + return TRUE; + + if (!n) // New block + for (m = 0; m < Nbm; m++) + bmp[m] = 0; // Reset the new bit map + + if ((i = Dval->Find(Value)) < 0) { + char buf[32]; + + sprintf(g->Message, MSG(DVAL_NOTIN_LIST), + Value->GetCharString(buf), Name); + return TRUE; + } else if (i >= dup->Maxbmp) { + sprintf(g->Message, MSG(OPT_LOGIC_ERR), i); + return TRUE; + } else { + m = i / MAXBMP; +#if defined(_DEBUG) + assert (m < Nbm); +#endif // _DEBUG + bmp[m] |= (1 << (i % MAXBMP)); + } // endif's i + + return FALSE; + } // end of SetBitMap + +/***********************************************************************/ +/* Checks whether a column declared as sorted is sorted indeed. */ +/***********************************************************************/ +bool DOSCOL::CheckSorted(PGLOBAL g) + { + if (Sorted) + if (OldVal) { + // Verify whether this column is sorted all right + if (OldVal->CompareValue(Value) > 0) { + // Column is no more in ascending order + sprintf(g->Message, MSG(COL_NOT_SORTED), Name, To_Tdb->GetName()); + Sorted = FALSE; + return TRUE; + } else + OldVal->SetValue_pval(Value); + + } else + OldVal = AllocateValue(g, Value); + + return FALSE; + } // end of CheckSorted + +/***********************************************************************/ +/* AddDistinctValue: Check whether this value already exist in the */ +/* list and if not add it to the distinct values list. */ +/***********************************************************************/ +bool DOSCOL::AddDistinctValue(PGLOBAL g) + { + bool found = FALSE; + int i, m, n; + + ReadColumn(g); // Extract column value from current line + + // Perhaps a better algorithm can be used when Ndv gets bigger + // Here we cannot use Find because we must get the index of where + // to insert a new value if it is not found in the array. + for (n = 0; n < Ndv; n++) { + m = Dval->CompVal(Value, n); + + if (m > 0) + continue; + else if (!m) + found = TRUE; // Already there + + break; + } // endfor n + + if (!found) { + // Check whether we have room for an additional value + if (Ndv == Freq) { + // Too many values because of wrong Freq setting + sprintf(g->Message, MSG(BAD_FREQ_SET), Name); + return TRUE; + } // endif Ndv + + // New value, add it to the list before the nth value + Dval->SetNval(Ndv + 1); + + for (i = Ndv; i > n; i--) + Dval->Move(i - 1, i); + + Dval->SetValue(Value, n); + Ndv++; + } // endif found + + return FALSE; + } // end of AddDistinctValue +#endif // BLK_INDX + /***********************************************************************/ /* Make file output of a Dos column descriptor block. */ /***********************************************************************/ diff --git a/storage/connect/tabdos.h b/storage/connect/tabdos.h index 5f67ffad92f..52bb1450c29 100644 --- a/storage/connect/tabdos.h +++ b/storage/connect/tabdos.h @@ -1,7 +1,7 @@ /*************** TabDos H Declares Source Code File (.H) ***************/ -/* Name: TABDOS.H Version 3.2 */ +/* Name: TABDOS.H Version 3.3 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 1999-2012 */ +/* (C) Copyright to the author Olivier BERTRAND 1999-2014 */ /* */ /* This file contains the DOS classes declares. */ /***********************************************************************/ @@ -12,9 +12,16 @@ #include "xtable.h" // Table base class declares #include "colblk.h" // Column base class declares #include "xindex.h" +#if defined(BLK_INDX) +#include "filter.h" +#endif // BLK_INDX //pedef struct _tabdesc *PTABD; // For friend setting typedef class TXTFAM *PTXF; +#if defined(BLK_INDX) +typedef class BLOCKFILTER *PBF; +typedef class BLOCKINDEX *PBX; +#endif // BLK_INDX /***********************************************************************/ /* DOS table. */ @@ -34,6 +41,7 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ virtual const char *GetType(void) {return "DOS";} virtual PIXDEF GetIndx(void) {return To_Indx;} virtual void SetIndx(PIXDEF xdp) {To_Indx = xdp;} + virtual bool IsHuge(void) {return Huge;} PSZ GetFn(void) {return Fn;} PSZ GetOfn(void) {return Ofn;} void SetBlock(int block) {Block = block;} @@ -46,19 +54,28 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ bool GetEof(void) {return Eof;} int GetBlksize(void) {return Blksize;} int GetEnding(void) {return Ending;} +#if defined(BLK_INDX) + bool IsOptimized(void) {return (Optimized == 1);} + void SetOptimized(int opt) {Optimized = opt;} + void SetAllocBlks(int blks) {AllocBlks = blks;} + int GetAllocBlks(void) {return AllocBlks;} int *GetTo_Pos(void) {return To_Pos;} - virtual bool IsHuge(void) {return Huge;} +#endif // BLK_INDX // Methods - virtual bool DeleteTableFile(PGLOBAL g); +//virtual bool DeleteTableFile(PGLOBAL g); virtual bool Indexable(void) {return Compressed != 1;} virtual bool DeleteIndexFile(PGLOBAL g, PIXDEF pxdf); virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); virtual PTDB GetTable(PGLOBAL g, MODE mode); bool InvalidateIndex(PGLOBAL g); +#if defined(BLK_INDX) + bool GetOptFileName(PGLOBAL g, char *filename); + void RemoveOptValues(PGLOBAL g); +#endif // BLK_INDX protected: - virtual bool Erase(char *filename); +//virtual bool Erase(char *filename); // Members PSZ Fn; /* Path/Name of corresponding file */ @@ -70,7 +87,11 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ bool Huge; /* true for files larger than 2GB */ bool Accept; /* true if wrong lines are accepted (DBF)*/ bool Eof; /* true if an EOF (0xA) character exists */ - int *To_Pos; /* To array of block starting positions */ +#if defined(BLK_INDX) + int *To_Pos; /* To array of block starting positions */ + int Optimized; /* 0: No, 1:Yes, 2:Redo optimization */ + int AllocBlks; /* Number of suballocated opt blocks */ +#endif // BLK_INDX int Compressed; /* 0: No, 1: gz, 2:zlib compressed file */ int Lrecl; /* Size of biggest record */ int AvgLen; /* Average size of records */ @@ -129,13 +150,15 @@ class DllExport TDBDOS : public TDBASE { virtual bool IsUsingTemp(PGLOBAL g); //virtual bool NeedIndexing(PGLOBAL g); virtual void ResetSize(void) {MaxSize = Cardinal = -1;} - virtual int ResetTableOpt(PGLOBAL g, bool dox); -//virtual int MakeBlockValues(PGLOBAL g); -//virtual bool SaveBlockValues(PGLOBAL g); -//virtual bool GetBlockValues(PGLOBAL g); -//virtual PBF InitBlockFilter(PGLOBAL g, PFIL filp); + virtual int ResetTableOpt(PGLOBAL g, bool dop, bool dox); +#if defined(BLK_INDX) + virtual int MakeBlockValues(PGLOBAL g); + virtual bool SaveBlockValues(PGLOBAL g); + virtual bool GetBlockValues(PGLOBAL g); + virtual PBF InitBlockFilter(PGLOBAL g, PFIL filp); //virtual PBX InitBlockIndex(PGLOBAL g); -//virtual int TestBlock(PGLOBAL g); + virtual int TestBlock(PGLOBAL g); +#endif // BLK_INDX virtual void PrintAM(FILE *f, char *m); // Database routines @@ -162,25 +185,31 @@ class DllExport TDBDOS : public TDBASE { virtual int EstimatedLength(PGLOBAL g); // Optimization routines -// void ResetBlockFilter(PGLOBAL g); - int MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add); -// bool GetDistinctColumnValues(PGLOBAL g, int nrec); + int MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add); +#if defined(BLK_INDX) + void ResetBlockFilter(PGLOBAL g); + bool GetDistinctColumnValues(PGLOBAL g, int nrec); protected: -// PBF CheckBlockFilari(PGLOBAL g, PXOB *arg, int op, bool *cnv); + PBF CheckBlockFilari(PGLOBAL g, PXOB *arg, int op, bool *cnv); +#endif // BLK_INDX // Members PTXF Txfp; // To the File access method class +#if defined(BLK_INDX) //PBX To_BlkIdx; // To index test block -//PBF To_BlkFil; // To evaluation block filter -//PFIL SavFil; // Saved hidden filter + PBF To_BlkFil; // To evaluation block filter + PFIL SavFil; // Saved hidden filter +#endif // BLK_INDX char *To_Line; // Points to current processed line int Cardinal; // Table Cardinality RECFM Ftype; // File type: 0-var 1-fixed 2-binary (VCT) int Lrecl; // Logical Record Length int AvgLen; // Logical Record Average Length +#if defined(BLK_INDX) //int Xeval; // BlockTest return value -//int Beval; // BlockEval return value + int Beval; // BlockEval return value +#endif // BLK_INDX }; // end of class TDBDOS /***********************************************************************/ @@ -198,50 +227,60 @@ class DllExport DOSCOL : public COLBLK { // Implementation virtual int GetAmType(void) {return TYPE_AM_DOS;} -//virtual int GetClustered(void) {return Clustered;} -//virtual int IsClustered(void) {return (Clustered && -// ((PDOSDEF)(((PTDBDOS)To_Tdb)->To_Def))->IsOptimized());} -//virtual int IsSorted(void) {return Sorted;} virtual void SetTo_Val(PVAL valp) {To_Val = valp;} -//virtual PVBLK GetMin(void) {return Min;} -//virtual PVBLK GetMax(void) {return Max;} -//virtual int GetNdv(void) {return Ndv;} -//virtual int GetNbm(void) {return Nbm;} -//virtual PVBLK GetBmap(void) {return Bmap;} -//virtual PVBLK GetDval(void) {return Dval;} +#if defined(BLK_INDX) + virtual int GetClustered(void) {return Clustered;} + virtual int IsClustered(void) {return (Clustered && + ((PDOSDEF)(((PTDBDOS)To_Tdb)->To_Def))->IsOptimized());} + virtual int IsSorted(void) {return Sorted;} + virtual PVBLK GetMin(void) {return Min;} + virtual PVBLK GetMax(void) {return Max;} + virtual int GetNdv(void) {return Ndv;} + virtual int GetNbm(void) {return Nbm;} + virtual PVBLK GetBmap(void) {return Bmap;} + virtual PVBLK GetDval(void) {return Dval;} +#endif // BLK_INDX // Methods +#if defined(BLK_INDX) virtual bool VarSize(void); +#endif // BLK_INDX virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check); virtual void ReadColumn(PGLOBAL g); virtual void WriteColumn(PGLOBAL g); virtual void Print(PGLOBAL g, FILE *, uint); protected: -//virtual bool SetMinMax(PGLOBAL g); -//virtual bool SetBitMap(PGLOBAL g); -// bool CheckSorted(PGLOBAL g); -// bool AddDistinctValue(PGLOBAL g); +#if defined(BLK_INDX) + virtual bool SetMinMax(PGLOBAL g); + virtual bool SetBitMap(PGLOBAL g); + bool CheckSorted(PGLOBAL g); + bool AddDistinctValue(PGLOBAL g); +#endif // BLK_INDX // Default constructor not to be used DOSCOL(void) {} // Members -//PVBLK Min; // Array of block min values -//PVBLK Max; // Array of block max values -//PVBLK Bmap; // Array of block bitmap values -//PVBLK Dval; // Array of column distinct values +#if defined(BLK_INDX) + PVBLK Min; // Array of block min values + PVBLK Max; // Array of block max values + PVBLK Bmap; // Array of block bitmap values + PVBLK Dval; // Array of column distinct values +#endif // BLK_INDX PVAL To_Val; // To value used for Update/Insert PVAL OldVal; // The previous value of the object. char *Buf; // Buffer used in write operations bool Ldz; // True if field contains leading zeros bool Nod; // True if no decimal point int Dcm; // Last Dcm digits are decimals -//int Clustered; // 0:No 1:Yes -//int Sorted; // 0:No 1:Asc (2:Desc - NIY) int Deplac; // Offset in dos_buf -//int Ndv; // Number of distinct values -//int Nbm; // Number of uint in bitmap +#if defined(BLK_INDX) + int Clustered; // 0:No 1:Yes + int Sorted; // 0:No 1:Asc (2:Desc - NIY) + int Ndv; // Number of distinct values + int Nbm; // Number of uint in bitmap +#endif // BLK_INDX }; // end of class DOSCOL #endif // __TABDOS_H diff --git a/storage/connect/tabfix.cpp b/storage/connect/tabfix.cpp index 99063e86b57..cb95cebe7d1 100644 --- a/storage/connect/tabfix.cpp +++ b/storage/connect/tabfix.cpp @@ -1,11 +1,11 @@ /************* TabFix C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABFIX */ /* ------------- */ -/* Version 4.8 */ +/* Version 4.9 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2014 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -45,6 +45,10 @@ #include "filamfix.h" #include "filamdbf.h" #include "tabfix.h" // TDBFIX, FIXCOL classes declares +#if defined(BLK_INDX) +#include "array.h" +#include "blkfil.h" +#endif // BLK_INDX /***********************************************************************/ /* DB static variables. */ @@ -123,10 +127,52 @@ PCOL TDBFIX::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) /***********************************************************************/ /* Remake the indexes after the table was modified. */ /***********************************************************************/ -int TDBFIX::ResetTableOpt(PGLOBAL g, bool dox) +int TDBFIX::ResetTableOpt(PGLOBAL g, bool dop, bool dox) { +#if defined(BLK_INDX) + int prc, rc = RC_OK; + + To_Filter = NULL; // Disable filtering +//To_BlkIdx = NULL; // and block filtering + To_BlkFil = NULL; // and index filtering + RestoreNrec(); // May have been modified + MaxSize = -1; // Size must be recalculated + Cardinal = -1; // as well as Cardinality + + if (dop) { + Columns = NULL; // Not used anymore + Txfp->Reset(); +// OldBlk = CurBlk = -1; +// ReadBlks = CurNum = Rbuf = Modif = 0; + Use = USE_READY; // So the table can be reopened + Mode = MODE_ANY; // Just to be clean + rc = MakeBlockValues(g); // Redo optimization + } // endif dop + + if (dox && (rc == RC_OK || rc == RC_INFO)) { + // Remake eventual indexes + Columns = NULL; // Not used anymore + Txfp->Reset(); // New start + Use = USE_READY; // So the table can be reopened + Mode = MODE_READ; // New mode + prc = rc; + + if (!(PlgGetUser(g)->Check & CHK_OPT)) { + // After the table was modified the indexes + // are invalid and we should mark them as such... + rc = ((PDOSDEF)To_Def)->InvalidateIndex(g); + } else + // ... or we should remake them. + rc = MakeIndex(g, NULL, FALSE); + + rc = (rc == RC_INFO) ? prc : rc; + } // endif dox + + return rc; +#else // !BLK_INDX RestoreNrec(); // May have been modified - return TDBDOS::ResetTableOpt(g, dox); + return TDBDOS::ResetTableOpt(g, dop, dox); +#endif // !BLK_INDX } // end of ResetTableOpt /***********************************************************************/ @@ -163,8 +209,17 @@ int TDBFIX::Cardinality(PGLOBAL g) /***********************************************************************/ int TDBFIX::GetMaxSize(PGLOBAL g) { - if (MaxSize < 0) + if (MaxSize < 0) { MaxSize = Cardinality(g); +#if defined(BLK_INDX) + if (MaxSize > 0 && (To_BlkFil = InitBlockFilter(g, To_Filter)) + && !To_BlkFil->Correlated()) { + // Use BlockTest to reduce the estimated size + MaxSize = Txfp->MaxBlkSize(g, MaxSize); + ResetBlockFilter(g); + } // endif To_BlkFil +#endif // BLK_INDX + } // endif MaxSize return MaxSize; } // end of GetMaxSize @@ -246,6 +301,9 @@ bool TDBFIX::OpenDB(PGLOBAL g) else Txfp->Rewind(); // see comment in Work.log +#if defined(BLK_INDX) + ResetBlockFilter(g); +#endif // BLK_INDX return false; } // endif use @@ -277,6 +335,13 @@ bool TDBFIX::OpenDB(PGLOBAL g) /*********************************************************************/ To_Line = Txfp->GetBuf(); // For WriteDB +#if defined(BLK_INDX) + /*********************************************************************/ + /* Allocate the block filter tree if evaluation is possible. */ + /*********************************************************************/ + To_BlkFil = InitBlockFilter(g, To_Filter); +#endif // BLK_INDX + if (trace) htrc("OpenDos: R%hd mode=%d\n", Tdb_No, Mode); diff --git a/storage/connect/tabfix.h b/storage/connect/tabfix.h index bcd171b37bb..5feb3589928 100644 --- a/storage/connect/tabfix.h +++ b/storage/connect/tabfix.h @@ -38,7 +38,7 @@ class DllExport TDBFIX : public TDBDOS { virtual void ResetDB(void); virtual bool IsUsingTemp(PGLOBAL g); virtual int RowNumber(PGLOBAL g, bool b = false); - virtual int ResetTableOpt(PGLOBAL g, bool dox); + virtual int ResetTableOpt(PGLOBAL g, bool dop, bool dox); virtual void ResetSize(void); virtual int GetBadLines(void) {return Txfp->GetNerr();} diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index 9a121b9ab9a..18ecaae430a 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -459,9 +459,12 @@ PTDB CSVDEF::GetTable(PGLOBAL g, MODE mode) if (Compressed == 1) txfp = new(g) ZIPFAM(this); else { +#if defined(BLK_INDX) + txfp = new(g) ZLBFAM(this); +#else // !BLK_INDX strcpy(g->Message, "Compress 2 not supported yet"); -// txfp = new(g) ZLBFAM(defp); return NULL; +#endif // !BLK_INDX } // endelse #else // !ZIP_SUPPORT strcpy(g->Message, "Compress not supported"); @@ -1272,6 +1275,7 @@ CSVCOL::CSVCOL(CSVCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp) Fldnum = col1->Fldnum; } // end of CSVCOL copy constructor +#if defined(BLK_INDX) /***********************************************************************/ /* VarSize: This function tells UpdateDB whether or not the block */ /* optimization file must be redone if this column is updated, even */ @@ -1290,6 +1294,7 @@ bool CSVCOL::VarSize(void) return false; } // end VarSize +#endif // BLK_INDX /***********************************************************************/ /* ReadColumn: call DOSCOL::ReadColumn after having set the offet */ diff --git a/storage/connect/tabfmt.h b/storage/connect/tabfmt.h index d4a7f4105d6..52b0094bfef 100644 --- a/storage/connect/tabfmt.h +++ b/storage/connect/tabfmt.h @@ -112,7 +112,9 @@ class CSVCOL : public DOSCOL { virtual int GetAmType() {return TYPE_AM_CSV;} // Methods +#if defined(BLK_INDX) virtual bool VarSize(void); +#endif // BLK_INDX virtual void ReadColumn(PGLOBAL g); virtual void WriteColumn(PGLOBAL g); // void Print(FILE *, uint); diff --git a/storage/connect/table.cpp b/storage/connect/table.cpp index 37035ed752d..d23740394b4 100644 --- a/storage/connect/table.cpp +++ b/storage/connect/table.cpp @@ -36,27 +36,6 @@ extern "C" int trace; // The general trace value void NewPointer(PTABS, void *, void *); void AddPointer(PTABS, void *); -/* ---------------------------- class TBX ---------------------------- */ - -/***********************************************************************/ -/* TBX public constructors. */ -/***********************************************************************/ -TBX::TBX(void) - { - Use = USE_NO; - To_Orig = NULL; - To_Filter = NULL; - } // end of TBX constructor - -TBX::TBX(PTBX txp) - { - Use = txp->Use; - To_Orig = txp; - To_Filter = NULL; - } // end of TBX copy constructor - -// Methods - /* ---------------------------- class TDB ---------------------------- */ /***********************************************************************/ @@ -64,6 +43,12 @@ TBX::TBX(PTBX txp) /***********************************************************************/ TDB::TDB(PTABDEF tdp) : Tdb_No(++Tnum) { + Use = USE_NO; + To_Orig = NULL; +#if defined(BLK_INDX) + To_Filter = NULL; +#endif // BLK_FILTER + To_CondFil = NULL; Next = NULL; Name = (tdp) ? tdp->GetName() : NULL; To_Table = NULL; @@ -72,8 +57,14 @@ TDB::TDB(PTABDEF tdp) : Tdb_No(++Tnum) Mode = MODE_READ; } // end of TDB standard constructor -TDB::TDB(PTDB tdbp) : TBX(tdbp), Tdb_No(++Tnum) +TDB::TDB(PTDB tdbp) : Tdb_No(++Tnum) { + Use = tdbp->Use; + To_Orig = tdbp; +#if defined(BLK_INDX) + To_Filter = NULL; +#endif // BLK_FILTER + To_CondFil = NULL; Next = NULL; Name = tdbp->Name; To_Table = tdbp->To_Table; @@ -179,7 +170,7 @@ int TDB::RowNumber(PGLOBAL g, bool b) return 0; } // end of RowNumber -PTBX TDB::Copy(PTABS t) +PTDB TDB::Copy(PTABS t) { PTDB tp, tdb1, tdb2 = NULL, outp = NULL; //PGLOBAL g = t->G; // Is this really useful ??? @@ -398,7 +389,7 @@ PCOL TDBASE::InsertSpcBlk(PGLOBAL g, PCOLDEF cdp) /***********************************************************************/ /* ResetTableOpt: Wrong for this table type. */ /***********************************************************************/ -int TDBASE::ResetTableOpt(PGLOBAL g, bool dox) +int TDBASE::ResetTableOpt(PGLOBAL g, bool dop, bool dox) { strcpy(g->Message, "This table is not indexable"); return RC_INFO; diff --git a/storage/connect/tabmac.h b/storage/connect/tabmac.h index cfdf842cdc8..eb115b18049 100644 --- a/storage/connect/tabmac.h +++ b/storage/connect/tabmac.h @@ -31,7 +31,7 @@ class DllExport MACDEF : public TABDEF { /* Logical table description */ // Methods virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); virtual PTDB GetTable(PGLOBAL g, MODE m); - virtual bool DeleteTableFile(PGLOBAL g) {return true;} +//virtual bool DeleteTableFile(PGLOBAL g) {return true;} protected: // Members diff --git a/storage/connect/tabmul.h b/storage/connect/tabmul.h index 052b4e7d33e..379e8f88e93 100644 --- a/storage/connect/tabmul.h +++ b/storage/connect/tabmul.h @@ -38,7 +38,7 @@ class DllExport TDBMUL : public TDBASE { // Methods virtual void ResetDB(void); virtual PTDB CopyOne(PTABS t); - virtual bool IsSame(PTBX tp) {return tp == (PTBX)Tdbp;} + virtual bool IsSame(PTDB tp) {return tp == (PTDB)Tdbp;} virtual PSZ GetFile(PGLOBAL g) {return Tdbp->GetFile(g);} virtual int GetRecpos(void) {return 0;} virtual PCOL ColDB(PGLOBAL g, PSZ name, int num); diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index 9b4f0dbe3ce..ce41a8429be 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -527,8 +527,8 @@ bool TDBMYSQL::MakeSelect(PGLOBAL g) strcat(strcat(strcat(strcat(Query, " FROM "), tk), Tabname), tk); - if (To_Filter) - strcat(strcat(Query, " WHERE "), To_Filter->Body); + if (To_CondFil) + strcat(strcat(Query, " WHERE "), To_CondFil->Body); if (trace) htrc("Query=%s\n", Query); @@ -1395,11 +1395,11 @@ PCMD TDBMYEXC::MakeCMD(PGLOBAL g) { PCMD xcmd = NULL; - if (To_Filter) { + if (To_CondFil) { if (Cmdcol) { - if (!stricmp(Cmdcol, To_Filter->Body) && - (To_Filter->Op == OP_EQ || To_Filter->Op == OP_IN)) { - xcmd = To_Filter->Cmds; + if (!stricmp(Cmdcol, To_CondFil->Body) && + (To_CondFil->Op == OP_EQ || To_CondFil->Op == OP_IN)) { + xcmd = To_CondFil->Cmds; } else strcpy(g->Message, "Invalid command specification filter"); diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp index 1fb71e33646..c7513601979 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -408,7 +408,7 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt) // Below 14 is length of 'select ' + length of ' from ' + 1 len = (strlen(colist) + strlen(buf) + 14); - len += (To_Filter ? strlen(To_Filter->Body) + 7 : 0); + len += (To_CondFil ? strlen(To_CondFil->Body) + 7 : 0); if (Catalog && *Catalog) catp = Catalog; @@ -441,8 +441,8 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt) strcat(sql, tabname); - if (To_Filter) - strcat(strcat(sql, " WHERE "), To_Filter->Body); + if (To_CondFil) + strcat(strcat(sql, " WHERE "), To_CondFil->Body); return sql; } // end of MakeSQL @@ -1229,11 +1229,11 @@ PCMD TDBXDBC::MakeCMD(PGLOBAL g) { PCMD xcmd = NULL; - if (To_Filter) { + if (To_CondFil) { if (Cmdcol) { - if (!stricmp(Cmdcol, To_Filter->Body) && - (To_Filter->Op == OP_EQ || To_Filter->Op == OP_IN)) { - xcmd = To_Filter->Cmds; + if (!stricmp(Cmdcol, To_CondFil->Body) && + (To_CondFil->Op == OP_EQ || To_CondFil->Op == OP_IN)) { + xcmd = To_CondFil->Cmds; } else strcpy(g->Message, "Invalid command specification filter"); diff --git a/storage/connect/tabsys.cpp b/storage/connect/tabsys.cpp index 2bb5532cea0..409352fdee6 100644 --- a/storage/connect/tabsys.cpp +++ b/storage/connect/tabsys.cpp @@ -113,6 +113,7 @@ PTDB INIDEF::GetTable(PGLOBAL g, MODE m) return tdbp; } // end of GetTable +#if 0 /***********************************************************************/ /* DeleteTableFile: Delete INI table files using platform API. */ /***********************************************************************/ @@ -134,6 +135,7 @@ bool INIDEF::DeleteTableFile(PGLOBAL g) return rc; // Return true if error } // end of DeleteTableFile +#endif // 0 /* ------------------------------------------------------------------- */ diff --git a/storage/connect/tabsys.h b/storage/connect/tabsys.h index 2780eb3ca98..714f2475873 100644 --- a/storage/connect/tabsys.h +++ b/storage/connect/tabsys.h @@ -32,7 +32,7 @@ class DllExport INIDEF : public TABDEF { /* INI table description */ // Methods virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); virtual PTDB GetTable(PGLOBAL g, MODE m); - virtual bool DeleteTableFile(PGLOBAL g); +//virtual bool DeleteTableFile(PGLOBAL g); protected: // Members diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp index 56305871c69..c78c62af9cc 100644 --- a/storage/connect/tabtbl.cpp +++ b/storage/connect/tabtbl.cpp @@ -1,11 +1,11 @@ /************* TabTbl C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABTBL */ /* ------------- */ -/* Version 1.6 */ +/* Version 1.7 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to PlugDB Software Development 2008-2013 */ +/* (C) Copyright to PlugDB Software Development 2008-2014 */ /* Author: Olivier BERTRAND */ /* */ /* WHAT THIS PROGRAM DOES: */ @@ -66,7 +66,6 @@ #include "global.h" // global declarations #include "plgdbsem.h" // DB application declarations #include "reldef.h" // DB definition declares -//#include "filter.h" // FILTER classes dcls #include "filamtxt.h" #include "tabcol.h" #include "tabdos.h" // TDBDOS and DOSCOL class dcls @@ -245,7 +244,7 @@ bool TDBTBL::InitTableList(PGLOBAL g) // PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath()); for (n = 0, tp = tdp->Tablep; tp; tp = tp->GetNext()) { - if (TestFil(g, To_Filter, tp)) { + if (TestFil(g, To_CondFil, tp)) { tabp = new(g) XTAB(tp); if (tabp->GetSrc()) { @@ -286,14 +285,14 @@ bool TDBTBL::InitTableList(PGLOBAL g) hc->get_table()->s->connect_string.length = sln; //NumTables = n; - To_Filter = NULL; // To avoid doing it several times + To_CondFil = NULL; // To avoid doing it several times return FALSE; } // end of InitTableList /***********************************************************************/ /* Test the tablename against the pseudo "local" filter. */ /***********************************************************************/ -bool TDBTBL::TestFil(PGLOBAL g, PFIL filp, PTABLE tabp) +bool TDBTBL::TestFil(PGLOBAL g, PCFIL filp, PTABLE tabp) { char *body, *fil, op[8], tn[NAME_LEN]; bool neg; @@ -421,12 +420,12 @@ bool TDBTBL::OpenDB(PGLOBAL g) } // endif use /*********************************************************************/ - /* When GetMaxsize was called, To_Filter was not set yet. */ + /* When GetMaxsize was called, To_CondFil was not set yet. */ /*********************************************************************/ - if (To_Filter && Tablist) { + if (To_CondFil && Tablist) { Tablist = NULL; Nbc = 0; - } // endif To_Filter + } // endif To_CondFil /*********************************************************************/ /* Open the first table of the list. */ @@ -661,12 +660,12 @@ bool TDBTBM::OpenDB(PGLOBAL g) #if 0 /*********************************************************************/ - /* When GetMaxsize was called, To_Filter was not set yet. */ + /* When GetMaxsize was called, To_CondFil was not set yet. */ /*********************************************************************/ - if (To_Filter && Tablist) { + if (To_CondFil && Tablist) { Tablist = NULL; Nbc = 0; - } // endif To_Filter + } // endif To_CondFil #endif // 0 /*********************************************************************/ diff --git a/storage/connect/tabtbl.h b/storage/connect/tabtbl.h index 48371e40ade..0ff6c37eaed 100644 --- a/storage/connect/tabtbl.h +++ b/storage/connect/tabtbl.h @@ -87,7 +87,7 @@ class DllExport TDBTBL : public TDBPRX { protected: // Internal functions bool InitTableList(PGLOBAL g); - bool TestFil(PGLOBAL g, PFIL filp, PTABLE tabp); + bool TestFil(PGLOBAL g, PCFIL filp, PTABLE tabp); // Members PTABLE Tablist; // Points to the table list @@ -152,7 +152,7 @@ class DllExport TDBTBM : public TDBTBL { protected: // Internal functions //bool InitTableList(PGLOBAL g); -//bool TestFil(PGLOBAL g, PFIL filp, PTABLE tabp); +//bool TestFil(PGLOBAL g, PCFIL filp, PTABLE tabp); bool OpenTables(PGLOBAL g); int ReadNextRemote(PGLOBAL g); diff --git a/storage/connect/tabvct.cpp b/storage/connect/tabvct.cpp index 8b7d8ba91eb..cb5e6f3200c 100644 --- a/storage/connect/tabvct.cpp +++ b/storage/connect/tabvct.cpp @@ -1,11 +1,11 @@ /************* TabVct C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABVCT */ /* ------------- */ -/* Version 3.7 */ +/* Version 3.8 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 1999-2012 */ +/* (C) Copyright to the author Olivier BERTRAND 1999-2014 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -118,6 +118,7 @@ bool VCTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) return false; } // end of DefineAM +#if 0 /***********************************************************************/ /* Erase: This was made a separate routine because a strange thing */ /* happened when DeleteTablefile was defined for the VCTDEF class: */ @@ -157,6 +158,7 @@ bool VCTDEF::Erase(char *filename) return rc; // Return true if error } // end of Erase +#endif // 0 /***********************************************************************/ /* Prepare the column file name pattern for a split table. */ @@ -231,7 +233,8 @@ PTDB VCTDEF::GetTable(PGLOBAL g, MODE mode) /*********************************************************************/ if (mode != MODE_INSERT) if (tdbp->GetBlockValues(g)) - return NULL; + PushWarning(g, (PTDBASE)tdbp); +// return NULL; // causes a crash when deleting index return tdbp; } // end of GetTable @@ -298,6 +301,9 @@ bool TDBVCT::OpenDB(PGLOBAL g) To_Kindex->Reset(); Txfp->Rewind(); +#if defined(BLK_INDX) + ResetBlockFilter(g); +#endif // BLK_INDX return false; } // endif Use @@ -319,6 +325,13 @@ bool TDBVCT::OpenDB(PGLOBAL g) // This was not done in previous version Use = USE_OPEN; // Do it now in case we are recursively called +#if defined(BLK_INDX) + /*********************************************************************/ + /* Allocate the block filter tree if evaluation is possible. */ + /*********************************************************************/ + To_BlkFil = InitBlockFilter(g, To_Filter); +#endif // BLK_INDX + /*********************************************************************/ /* Reset buffer access according to indexing and to mode. */ /*********************************************************************/ diff --git a/storage/connect/tabvct.h b/storage/connect/tabvct.h index 4049b4f7683..f1c0a8a3a98 100644 --- a/storage/connect/tabvct.h +++ b/storage/connect/tabvct.h @@ -37,7 +37,7 @@ class DllExport VCTDEF : public DOSDEF { /* Logical table description */ protected: // Specific file erase routine for vertical tables - virtual bool Erase(char *filename); +//virtual bool Erase(char *filename); int MakeFnPattern(char *fpat); // Members diff --git a/storage/connect/tabwmi.cpp b/storage/connect/tabwmi.cpp index 8f91d9b3ed8..5052268b9e2 100644 --- a/storage/connect/tabwmi.cpp +++ b/storage/connect/tabwmi.cpp @@ -14,7 +14,7 @@ #include "reldef.h" #include "xtable.h" #include "colblk.h" -#include "filter.h" +//#include "filter.h" //#include "xindex.h" #include "tabwmi.h" #include "valblk.h" @@ -480,8 +480,8 @@ bool TDBWMI::Initialize(PGLOBAL g) /***********************************************************************/ void TDBWMI::DoubleSlash(PGLOBAL g) { - if (To_Filter && strchr(To_Filter->Body, '\\')) { - char *body = To_Filter->Body; + if (To_CondFil && strchr(To_CondFil->Body, '\\')) { + char *body = To_CondFil->Body; char *buf = (char*)PlugSubAlloc(g, NULL, strlen(body) * 2); int i = 0, k = 0; @@ -492,8 +492,8 @@ void TDBWMI::DoubleSlash(PGLOBAL g) buf[k++] = body[i]; } while (body[i++]); - To_Filter->Body = buf; - } // endif To_Filter + To_CondFil->Body = buf; + } // endif To_CondFil } // end of DoubleSlash @@ -540,13 +540,13 @@ char *TDBWMI::MakeWQL(PGLOBAL g) // Below 14 is length of 'select ' + length of ' from ' + 1 len = (strlen(colist) + strlen(Wclass) + 14); - len += (To_Filter ? strlen(To_Filter->Body) + 7 : 0); + len += (To_CondFil ? strlen(To_CondFil->Body) + 7 : 0); wql = (char*)PlugSubAlloc(g, NULL, len); strcat(strcat(strcpy(wql, "SELECT "), colist), " FROM "); strcat(wql, Wclass); - if (To_Filter) - strcat(strcat(wql, " WHERE "), To_Filter->Body); + if (To_CondFil) + strcat(strcat(wql, " WHERE "), To_CondFil->Body); return wql; } // end of MakeWQL @@ -659,8 +659,8 @@ bool TDBWMI::OpenDB(PGLOBAL g) return true; } // endif Mode - if (!To_Filter && !stricmp(Wclass, "CIM_Datafile") - && !stricmp(Nspace, "root\\cimv2")) { + if (!To_CondFil && !stricmp(Wclass, "CIM_Datafile") + && !stricmp(Nspace, "root\\cimv2")) { strcpy(g->Message, "Would last forever when not filtered, use DIR table instead"); return true; diff --git a/storage/connect/tabwmi.h b/storage/connect/tabwmi.h index 9df57e7c579..558e527773e 100644 --- a/storage/connect/tabwmi.h +++ b/storage/connect/tabwmi.h @@ -48,7 +48,7 @@ class WMIDEF : public TABDEF { /* Logical table description */ // Methods virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); virtual PTDB GetTable(PGLOBAL g, MODE m); - virtual bool DeleteTableFile(PGLOBAL g) {return true;} +//virtual bool DeleteTableFile(PGLOBAL g) {return true;} protected: // Members diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp index 7e4ee3453ae..7a2c0169c2b 100644 --- a/storage/connect/tabxml.cpp +++ b/storage/connect/tabxml.cpp @@ -187,6 +187,7 @@ PTDB XMLDEF::GetTable(PGLOBAL g, MODE m) return tdbp; } // end of GetTable +#if 0 /***********************************************************************/ /* DeleteTableFile: Delete XML table files using platform API. */ /***********************************************************************/ @@ -208,6 +209,7 @@ bool XMLDEF::DeleteTableFile(PGLOBAL g) return rc; // Return true if error } // end of DeleteTableFile +#endif // 0 /* ------------------------- TDBXML Class ---------------------------- */ diff --git a/storage/connect/tabxml.h b/storage/connect/tabxml.h index 817bea45b3b..20998589967 100644 --- a/storage/connect/tabxml.h +++ b/storage/connect/tabxml.h @@ -30,7 +30,7 @@ class DllExport XMLDEF : public TABDEF { /* Logical table description */ // Methods virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); virtual PTDB GetTable(PGLOBAL g, MODE m); - virtual bool DeleteTableFile(PGLOBAL g); +//virtual bool DeleteTableFile(PGLOBAL g); protected: // Members diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp index c0127072896..e8da2044a47 100644 --- a/storage/connect/valblk.cpp +++ b/storage/connect/valblk.cpp @@ -40,7 +40,8 @@ #include "plgdbsem.h" #include "valblk.h" -#define CheckBlanks assert(!Blanks); +#define CheckBlanks assert(!Blanks); +#define CheckParms(V, N) ChkIndx(N); ChkTyp(V); /***********************************************************************/ /* AllocValBlock: allocate a VALBLK according to type. */ @@ -447,6 +448,38 @@ template <> uchar TYPBLK<uchar>::GetTypedValue(PVBLK blk, int n) {return blk->GetUTinyValue(n);} +#if defined(BLK_INDX) +/***********************************************************************/ +/* Set one value in a block if val is less than the current value. */ +/***********************************************************************/ +template <class TYPE> +void TYPBLK<TYPE>::SetMin(PVAL valp, int n) + { + CheckParms(valp, n) + TYPE tval = GetTypedValue(valp); + TYPE& tmin = Typp[n]; + + if (tval < tmin) + tmin = tval; + + } // end of SetMin + +/***********************************************************************/ +/* Set one value in a block if val is greater than the current value. */ +/***********************************************************************/ +template <class TYPE> +void TYPBLK<TYPE>::SetMax(PVAL valp, int n) + { + CheckParms(valp, n) + TYPE tval = GetTypedValue(valp); + TYPE& tmin = Typp[n]; + + if (tval > tmin) + tmin = tval; + + } // end of SetMax +#endif // BLK_INDX + #if 0 /***********************************************************************/ /* Set many values in a block from values in another block. */ @@ -779,6 +812,38 @@ void CHRBLK::SetValue(PVBLK pv, int n1, int n2) SetNull(n1, b); } // end of SetValue +#if defined(BLK_INDX) +/***********************************************************************/ +/* Set one value in a block if val is less than the current value. */ +/***********************************************************************/ +void CHRBLK::SetMin(PVAL valp, int n) + { + CheckParms(valp, n) + CheckBlanks + char *vp = valp->GetCharValue(); + char *bp = Chrp + n * Long; + + if (((Ci) ? strnicmp(vp, bp, Long) : strncmp(vp, bp, Long)) < 0) + memcpy(bp, vp, Long); + + } // end of SetMin + +/***********************************************************************/ +/* Set one value in a block if val is greater than the current value. */ +/***********************************************************************/ +void CHRBLK::SetMax(PVAL valp, int n) + { + CheckParms(valp, n) + CheckBlanks + char *vp = valp->GetCharValue(); + char *bp = Chrp + n * Long; + + if (((Ci) ? strnicmp(vp, bp, Long) : strncmp(vp, bp, Long)) > 0) + memcpy(bp, vp, Long); + + } // end of SetMax +#endif // BLK_INDX + #if 0 /***********************************************************************/ /* Set many values in a block from values in another block. */ @@ -1101,6 +1166,36 @@ void STRBLK::SetValue(char *sp, uint len, int n) Strp[n] = p; } // end of SetValue +#if defined(BLK_INDX) +/***********************************************************************/ +/* Set one value in a block if val is less than the current value. */ +/***********************************************************************/ +void STRBLK::SetMin(PVAL valp, int n) + { + CheckParms(valp, n) + char *vp = valp->GetCharValue(); + char *bp = Strp[n]; + + if (strcmp(vp, bp) < 0) + SetValue(valp, n); + + } // end of SetMin + +/***********************************************************************/ +/* Set one value in a block if val is greater than the current value. */ +/***********************************************************************/ +void STRBLK::SetMax(PVAL valp, int n) + { + CheckParms(valp, n) + char *vp = valp->GetCharValue(); + char *bp = Strp[n]; + + if (strcmp(vp, bp) > 0) + SetValue(valp, n); + + } // end of SetMax +#endif // BLK_INDX + /***********************************************************************/ /* Move one value from i to j. */ /***********************************************************************/ @@ -1240,5 +1335,51 @@ void DATBLK::SetValue(PSZ p, int n) } // end of SetValue +#if defined(BLK_INDX) +/* -------------------------- Class MBVALS --------------------------- */ + +/***********************************************************************/ +/* Allocate a value block according to type,len, and nb of values. */ +/***********************************************************************/ +PVBLK MBVALS::Allocate(PGLOBAL g, int type, int len, int prec, + int n, bool sub) + { + Mblk.Sub = sub; + Mblk.Size = n * GetTypeSize(type, len); + + if (!PlgDBalloc(g, NULL, Mblk)) { + sprintf(g->Message, MSG(ALLOC_ERROR), "MBVALS::Allocate"); + return NULL; + } else + Vblk = AllocValBlock(g, Mblk.Memp, type, n, len, prec, + TRUE, TRUE, FALSE); + + return Vblk; + } // end of Allocate + +/***********************************************************************/ +/* Reallocate the value block according to the new size. */ +/***********************************************************************/ +bool MBVALS::ReAllocate(PGLOBAL g, int n) + { + if (!PlgDBrealloc(g, NULL, Mblk, n * Vblk->GetVlen())) { + sprintf(g->Message, MSG(ALLOC_ERROR), "MBVALS::ReAllocate"); + return TRUE; + } else + Vblk->ReAlloc(Mblk.Memp, n); + + return FALSE; + } // end of ReAllocate + +/***********************************************************************/ +/* Free the value block. */ +/***********************************************************************/ +void MBVALS::Free(void) + { + PlgDBfree(Mblk); + Vblk = NULL; + } // end of Free +#endif // BLK_INDX + /* ------------------------- End of Valblk --------------------------- */ diff --git a/storage/connect/valblk.h b/storage/connect/valblk.h index 1edfe7f76b4..6b427512332 100644 --- a/storage/connect/valblk.h +++ b/storage/connect/valblk.h @@ -22,6 +22,38 @@ DllExport PVBLK AllocValBlock(PGLOBAL, void*, int, int, int, int, bool, bool, bool); const char *GetFmt(int type, bool un = false); +#if defined(BLK_INDX) +/***********************************************************************/ +/* DB static external variables. */ +/***********************************************************************/ +extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */ + +/***********************************************************************/ +/* Class MBVALS is a utility class for (re)allocating VALBLK's. */ +/***********************************************************************/ +class MBVALS : public BLOCK { +//friend class LSTBLK; + friend class ARRAY; + public: + // Constructors + MBVALS(void) {Vblk = NULL; Mblk = Nmblk;} + + // Methods + void *GetMemp(void) {return Mblk.Memp;} + PVBLK Allocate(PGLOBAL g, int type, int len, int prec, + int n, bool sub = FALSE); + bool ReAllocate(PGLOBAL g, int n); + void Free(void); + + protected: + // Members + PVBLK Vblk; // Pointer to VALBLK + MBLOCK Mblk; // The memory block + }; // end of class MBVALS + +typedef class MBVALS *PMBV; +#endif // BLK_INDX + /***********************************************************************/ /* Class VALBLK represent a base class for variable blocks. */ /***********************************************************************/ @@ -79,9 +111,11 @@ class VALBLK : public BLOCK { virtual void SetValue(char *sp, uint len, int n) {assert(false);} virtual void SetValue(PVAL valp, int n) = 0; virtual void SetValue(PVBLK pv, int n1, int n2) = 0; -#if 0 +#if defined(BLK_INDX) virtual void SetMin(PVAL valp, int n) = 0; virtual void SetMax(PVAL valp, int n) = 0; +#endif // BLK_INDX +#if 0 virtual void SetValues(PVBLK pv, int i, int n) = 0; virtual void AddMinus1(PVBLK pv, int n1, int n2) {assert(false);} #endif // 0 @@ -161,6 +195,10 @@ class TYPBLK : public VALBLK { virtual void SetValue(PVAL valp, int n); virtual void SetValue(PVBLK pv, int n1, int n2); //virtual void SetValues(PVBLK pv, int k, int n); +#if defined(BLK_INDX) + virtual void SetMin(PVAL valp, int n); + virtual void SetMax(PVAL valp, int n); +#endif // BLK_INDX virtual void Move(int i, int j); virtual int CompVal(PVAL vp, int n); virtual int CompVal(int i1, int i2); @@ -212,6 +250,10 @@ class CHRBLK : public VALBLK { virtual void SetValue(PVAL valp, int n); virtual void SetValue(PVBLK pv, int n1, int n2); //virtual void SetValues(PVBLK pv, int k, int n); +#if defined(BLK_INDX) + virtual void SetMin(PVAL valp, int n); + virtual void SetMax(PVAL valp, int n); +#endif // BLK_INDX virtual void Move(int i, int j); virtual int CompVal(PVAL vp, int n); virtual int CompVal(int i1, int i2); @@ -264,6 +306,10 @@ class STRBLK : public VALBLK { virtual void SetValue(PVAL valp, int n); virtual void SetValue(PVBLK pv, int n1, int n2); //virtual void SetValues(PVBLK pv, int k, int n); +#if defined(BLK_INDX) + virtual void SetMin(PVAL valp, int n); + virtual void SetMax(PVAL valp, int n); +#endif // BLK_INDX virtual void Move(int i, int j); virtual int CompVal(PVAL vp, int n); virtual int CompVal(int i1, int i2); diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index c818070b970..7653b222a41 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -83,6 +83,7 @@ int DTVAL::Shift = 0; /* Routines called externally. */ /***********************************************************************/ bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool); + #if !defined(WIN32) extern "C" { PSZ strupr(PSZ s); @@ -90,6 +91,34 @@ PSZ strlwr(PSZ s); } #endif // !WIN32 +#if defined(BLK_INDX) +/***********************************************************************/ +/* Returns the bitmap representing the conditions that must not be */ +/* met when returning from TestValue for a given operator. */ +/* Bit one is EQ, bit 2 is LT, and bit 3 is GT. */ +/***********************************************************************/ +BYTE OpBmp(PGLOBAL g, OPVAL opc) + { + BYTE bt; + + switch (opc) { + case OP_IN: + case OP_EQ: bt = 0x06; break; + case OP_NE: bt = 0x01; break; + case OP_GT: bt = 0x03; break; + case OP_GE: bt = 0x02; break; + case OP_LT: bt = 0x05; break; + case OP_LE: bt = 0x04; break; + case OP_EXIST: bt = 0x00; break; + default: + sprintf(g->Message, MSG(BAD_FILTER_OP), opc); + longjmp(g->jumper[g->jump_level], TYPE_ARRAY); + } // endswitch opc + + return bt; + } // end of OpBmp +#endif // BLK_INDX + /***********************************************************************/ /* Get a long long number from its character representation. */ /* IN p: Pointer to the numeric string */ @@ -277,7 +306,7 @@ const char *GetFmt(int type, bool un) return fmt; } // end of GetFmt -#if 0 +#if defined(BLK_INDX) /***********************************************************************/ /* ConvertType: what this function does is to determine the type to */ /* which should be converted a value so no precision would be lost. */ @@ -324,7 +353,7 @@ int ConvertType(int target, int type, CONV kind, bool match) } // endswitch kind } // end of ConvertType -#endif // 0 +#endif // BLK_INDX /***********************************************************************/ /* AllocateConstant: allocates a constant Value. */ @@ -422,7 +451,7 @@ PVAL AllocateValue(PGLOBAL g, int type, int len, int prec, return valp; } // end of AllocateValue -#if 0 +#if defined(BLK_INDX) /***********************************************************************/ /* Allocate a constant Value converted to newtype. */ /* Can also be used to copy a Value eventually converted. */ @@ -490,7 +519,7 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns) valp->SetGlobal(g); return valp; } // end of AllocateValue -#endif // 0 +#endif // BLK_INDX /* -------------------------- Class VALUE ---------------------------- */ @@ -527,6 +556,20 @@ const char *VALUE::GetXfmt(void) return fmt; } // end of GetFmt +#if defined(BLK_INDX) +/***********************************************************************/ +/* Returns a BYTE indicating the comparison between two values. */ +/* Bit 1 indicates equality, Bit 2 less than, and Bit3 greater than. */ +/* More than 1 bit can be set only in the case of TYPE_LIST. */ +/***********************************************************************/ +BYTE VALUE::TestValue(PVAL vp) + { + int n = CompareValue(vp); + + return (n > 0) ? 0x04 : (n < 0) ? 0x02 : 0x01; + } // end of TestValue +#endif // BLK_INDX + /* -------------------------- Class TYPVAL ---------------------------- */ /***********************************************************************/ @@ -897,6 +940,26 @@ bool TYPVAL<TYPE>::IsEqual(PVAL vp, bool chktype) } // end of IsEqual +#if defined(BLK_INDX) +/***********************************************************************/ +/* Compare values and returns 1, 0 or -1 according to comparison. */ +/* This function is used for evaluation of numeric filters. */ +/***********************************************************************/ +template <class TYPE> +int TYPVAL<TYPE>::CompareValue(PVAL vp) + { +//assert(vp->GetType() == Type); + + // Process filtering on numeric values. + TYPE n = GetTypedValue(vp); + +//if (trace) +// htrc(" Comparing: val=%d,%d\n", Tval, n); + + return (Tval > n) ? 1 : (Tval < n) ? (-1) : 0; + } // end of CompareValue +#endif // BLK_INDX + /***********************************************************************/ /* FormatValue: This function set vp (a STRING value) to the string */ /* constructed from its own value formated using the fmt format. */ @@ -1347,6 +1410,34 @@ bool TYPVAL<PSZ>::IsEqual(PVAL vp, bool chktype) } // end of IsEqual +#if defined(BLK_INDX) +/***********************************************************************/ +/* Compare values and returns 1, 0 or -1 according to comparison. */ +/* This function is used for evaluation of numeric filters. */ +/***********************************************************************/ +int TYPVAL<PSZ>::CompareValue(PVAL vp) + { + int n; +//assert(vp->GetType() == Type); + + if (trace) + htrc(" Comparing: val='%s','%s'\n", Strp, vp->GetCharValue()); + + // Process filtering on character strings. + if (Ci || vp->IsCi()) + n = stricmp(Strp, vp->GetCharValue()); + else + n = strcmp(Strp, vp->GetCharValue()); + +#if defined(WIN32) + if (n == _NLSCMPERROR) + return n; // Here we should raise an error +#endif // WIN32 + + return (n > 0) ? 1 : (n < 0) ? -1 : 0; + } // end of CompareValue +#endif // BLK_INDX + /***********************************************************************/ /* FormatValue: This function set vp (a STRING value) to the string */ /* constructed from its own value formated using the fmt format. */ @@ -1573,6 +1664,25 @@ bool DECVAL::IsEqual(PVAL vp, bool chktype) return !strcmp(Strp, vp->GetCharString(buf)); } // end of IsEqual +#if defined(BLK_INDX) +/***********************************************************************/ +/* Compare values and returns 1, 0 or -1 according to comparison. */ +/* This function is used for evaluation of numeric filters. */ +/***********************************************************************/ +int DECVAL::CompareValue(PVAL vp) + { +//assert(vp->GetType() == Type); + + // Process filtering on numeric values. + double f = atof(Strp), n = vp->GetFloatValue(); + +//if (trace) +// htrc(" Comparing: val=%d,%d\n", f, n); + + return (f > n) ? 1 : (f < n) ? (-1) : 0; + } // end of CompareValue +#endif // BLK_INDX + #if 0 /***********************************************************************/ /* FormatValue: This function set vp (a STRING value) to the string */ diff --git a/storage/connect/value.h b/storage/connect/value.h index f8e89ba55fd..39fee7f73bb 100644 --- a/storage/connect/value.h +++ b/storage/connect/value.h @@ -46,8 +46,10 @@ DllExport char *GetFormatType(int); DllExport int GetFormatType(char); DllExport bool IsTypeChar(int type); DllExport bool IsTypeNum(int type); -//lExport int ConvertType(int, int, CONV, bool match = false); -//lExport PVAL AllocateValue(PGLOBAL, PVAL, int = TYPE_VOID, int = 0); +#if defined(BLK_INDX) +DllExport int ConvertType(int, int, CONV, bool match = false); +DllExport PVAL AllocateValue(PGLOBAL, PVAL, int = TYPE_VOID, int = 0); +#endif // BLK_INDX DllExport PVAL AllocateValue(PGLOBAL, int, int len = 0, int prec = 0, bool uns = false, PSZ fmt = NULL); DllExport ulonglong CharToNumber(char *, int, ulonglong, bool, @@ -95,6 +97,11 @@ class DllExport VALUE : public BLOCK { virtual bool SetValue_pval(PVAL valp, bool chktype = false) = 0; virtual bool SetValue_char(char *p, int n) = 0; virtual void SetValue_psz(PSZ s) = 0; +#if defined(BLK_INDX) + virtual void SetValue_bool(bool b) {assert(FALSE);} + virtual int CompareValue(PVAL vp) = 0; + virtual BYTE TestValue(PVAL vp); +#endif // BLK_INDX virtual void SetValue(char c) {assert(false);} virtual void SetValue(uchar c) {assert(false);} virtual void SetValue(short i) {assert(false);} @@ -163,6 +170,10 @@ class DllExport TYPVAL : public VALUE { virtual bool SetValue_pval(PVAL valp, bool chktype); virtual bool SetValue_char(char *p, int n); virtual void SetValue_psz(PSZ s); +#if defined(BLK_INDX) + virtual void SetValue_bool(bool b) {Tval = (b) ? 1 : 0;} + virtual int CompareValue(PVAL vp); +#endif // BLK_INDX virtual void SetValue(char c) {Tval = (TYPE)c; Null = false;} virtual void SetValue(uchar c) {Tval = (TYPE)c; Null = false;} virtual void SetValue(short i) {Tval = (TYPE)i; Null = false;} @@ -242,6 +253,9 @@ class DllExport TYPVAL<PSZ>: public VALUE { virtual void SetValue(ulonglong n); virtual void SetValue(double f); virtual void SetBinValue(void *p); +#if defined(BLK_INDX) + virtual int CompareValue(PVAL vp); +#endif // BLK_INDX virtual bool GetBinValue(void *buf, int buflen, bool go); virtual char *ShowValue(char *buf, int); virtual char *GetCharString(char *p); @@ -280,6 +294,9 @@ class DllExport DECVAL: public TYPVAL<PSZ> { virtual char *ShowValue(char *buf, int); //virtual char *GetCharString(char *p); virtual bool IsEqual(PVAL vp, bool chktype); +#if defined(BLK_INDX) + virtual int CompareValue(PVAL vp); +#endif // BLK_INDX //virtual bool FormatValue(PVAL vp, char *fmt); //virtual bool SetConstFormat(PGLOBAL, FORMAT&); diff --git a/storage/connect/xobject.cpp b/storage/connect/xobject.cpp index aa87517bd2e..4050fd520fa 100644 --- a/storage/connect/xobject.cpp +++ b/storage/connect/xobject.cpp @@ -109,7 +109,7 @@ int CONSTANT::GetLengthEx(void) return Value->GetValLen(); } // end of GetLengthEx -#if 0 +#if defined(BLK_INDX) /***********************************************************************/ /* Convert a constant to the given type. */ /***********************************************************************/ @@ -120,7 +120,7 @@ void CONSTANT::Convert(PGLOBAL g, int newtype) longjmp(g->jumper[g->jump_level], TYPE_CONST); } // end of Convert -#endif // 0 +#endif // BLK_INDX /***********************************************************************/ /* Compare: returns true if this object is equivalent to xp. */ diff --git a/storage/connect/xobject.h b/storage/connect/xobject.h index b7869be96b2..793a08ddb9e 100644 --- a/storage/connect/xobject.h +++ b/storage/connect/xobject.h @@ -68,7 +68,7 @@ class DllExport XOBJECT : public BLOCK { virtual bool CheckLocal(PTDB) {return true;} virtual int CheckSpcCol(PTDB, int) {return 2;} virtual bool CheckSort(PTDB) {return false;} - virtual bool VerifyColumn(PTBX txp) {return false;} + virtual bool VerifyColumn(PTDB txp) {return false;} virtual bool VerifyTdb(PTDB& tdbp) {return false;} virtual bool IsColInside(PCOL colp) {return false;} @@ -123,10 +123,12 @@ class DllExport CONSTANT : public XOBJECT { virtual bool SetFormat(PGLOBAL g, FORMAT& fmt) {return Value->SetConstFormat(g, fmt);} virtual int CheckSpcCol(PTDB, int) {return 1;} -// void Convert(PGLOBAL g, int newtype); +#if defined(BLK_INDX) + void Convert(PGLOBAL g, int newtype); +#endif // BLK_INDX // bool Rephrase(PGLOBAL g, PSZ work); void SetValue(PVAL vp) {Value = vp;} - virtual bool VerifyColumn(PTBX txp) {return true;} + virtual bool VerifyColumn(PTDB txp) {return true;} virtual bool VerifyTdb(PTDB& tdbp) {return true;} virtual void Print(PGLOBAL g, FILE *, uint); virtual void Print(PGLOBAL g, char *, uint); diff --git a/storage/connect/xtable.h b/storage/connect/xtable.h index 8884860cb5b..79b343e8a6d 100644 --- a/storage/connect/xtable.h +++ b/storage/connect/xtable.h @@ -33,58 +33,20 @@ class CMD : public BLOCK { char *Cmd; }; // end of class CMD -// Filter passed all tables -typedef struct _filter { +// Condition filter structure +typedef struct _cond_filter { char *Body; OPVAL Op; PCMD Cmds; -} FILTER, *PFIL; +} CONDFIL, *PCFIL; typedef class TDBCAT *PTDBCAT; typedef class CATCOL *PCATCOL; /***********************************************************************/ -/* Definition of class TBX (pure virtual class for TDB and OPJOIN) */ -/***********************************************************************/ -class DllExport TBX: public BLOCK { // Base class for OPJOIN and TDB classes. - public: - // Constructors - TBX(void); - TBX(PTBX txp); - - // Implementation - inline PTBX GetOrig(void) {return To_Orig;} - inline TUSE GetUse(void) {return Use;} - inline void SetUse(TUSE n) {Use = n;} - inline PFIL GetFilter(void) {return To_Filter;} - inline void SetOrig(PTBX txp) {To_Orig = txp;} - inline void SetFilter(PFIL fp) {To_Filter = fp;} - - // Methods - virtual bool IsSame(PTBX tp) {return tp == this;} - virtual int GetTdb_No(void) = 0; // Convenience during conversion - virtual PTDB GetNext(void) = 0; - virtual int Cardinality(PGLOBAL) = 0; - virtual int GetMaxSize(PGLOBAL) = 0; - virtual int GetProgMax(PGLOBAL) = 0; - virtual int GetProgCur(void) = 0; - virtual int GetBadLines(void) {return 0;} - virtual PTBX Copy(PTABS t) = 0; - - protected: -//virtual void PrepareFilters(PGLOBAL g) = 0; - - protected: - // Members - PTBX To_Orig; // Pointer to original if it is a copy - PFIL To_Filter; - TUSE Use; - }; // end of class TBX - -/***********************************************************************/ /* Definition of class TDB with all its method functions. */ /***********************************************************************/ -class DllExport TDB: public TBX { // Table Descriptor Block. +class DllExport TDB: public BLOCK { // Table Descriptor Block. public: // Constructors TDB(PTABDEF tdp = NULL); @@ -92,11 +54,21 @@ class DllExport TDB: public TBX { // Table Descriptor Block. // Implementation static void SetTnum(int n) {Tnum = n;} + inline PTDB GetOrig(void) {return To_Orig;} + inline TUSE GetUse(void) {return Use;} + inline PCFIL GetCondFil(void) {return To_CondFil;} inline LPCSTR GetName(void) {return Name;} inline PTABLE GetTable(void) {return To_Table;} inline PCOL GetColumns(void) {return Columns;} inline int GetDegree(void) {return Degree;} inline MODE GetMode(void) {return Mode;} +#if defined(BLK_INDX) + inline PFIL GetFilter(void) {return To_Filter;} + inline void SetFilter(PFIL fp) {To_Filter = fp;} +#endif // BLK_INDX + inline void SetOrig(PTDB txp) {To_Orig = txp;} + inline void SetUse(TUSE n) {Use = n;} + inline void SetCondFil(PCFIL cfp) {To_CondFil = cfp;} inline void SetNext(PTDB tdbp) {Next = tdbp;} inline void SetName(LPCSTR name) {Name = name;} inline void SetTable(PTABLE tablep) {To_Table = tablep;} @@ -105,25 +77,30 @@ class DllExport TDB: public TBX { // Table Descriptor Block. inline void SetMode(MODE mode) {Mode = mode;} //Properties + virtual AMT GetAmType(void) {return TYPE_AM_ERROR;} virtual int GetTdb_No(void) {return Tdb_No;} virtual PTDB GetNext(void) {return Next;} virtual PCATLG GetCat(void) {return NULL;} // Methods - virtual AMT GetAmType(void) {return TYPE_AM_ERROR;} + virtual bool IsSame(PTDB tp) {return tp == this;} virtual bool GetBlockValues(PGLOBAL g) {return false;} virtual int Cardinality(PGLOBAL g) {return (g) ? -1 : 0;} + virtual int GetMaxSize(PGLOBAL) = 0; + virtual int GetProgMax(PGLOBAL) = 0; + virtual int GetProgCur(void) = 0; virtual int RowNumber(PGLOBAL g, bool b = false); virtual bool IsReadOnly(void) {return true;} - virtual const CHARSET_INFO *data_charset() { return NULL; } + virtual const CHARSET_INFO *data_charset() {return NULL;} virtual PTDB Duplicate(PGLOBAL g) {return NULL;} virtual PTDB CopyOne(PTABS t) {return this;} - virtual PTBX Copy(PTABS t); + virtual PTDB Copy(PTABS t); virtual void PrintAM(FILE *f, char *m) {fprintf(f, "%s AM(%d)\n", m, GetAmType());} virtual void Print(PGLOBAL g, FILE *f, uint n); virtual void Print(PGLOBAL g, char *ps, uint z); virtual PSZ GetServer(void) = 0; + virtual int GetBadLines(void) {return 0;} // Database pure virtual routines virtual PCOL ColDB(PGLOBAL g, PSZ name, int num) = 0; @@ -141,6 +118,12 @@ class DllExport TDB: public TBX { // Table Descriptor Block. protected: // Members + PTDB To_Orig; // Pointer to original if it is a copy + TUSE Use; +#if defined(BLK_INDX) + PFIL To_Filter; +#endif // BLK_INDX + PCFIL To_CondFil; // To condition filter structure static int Tnum; // Used to generate Tdb_no's const int Tdb_No; // GetTdb_No() is always 0 for OPJOIN PTDB Next; // Next in linearized queries @@ -194,7 +177,7 @@ class DllExport TDBASE : public TDB { virtual void ResetDB(void) {} virtual void ResetSize(void) {MaxSize = -1;} virtual void RestoreNrec(void) {} - virtual int ResetTableOpt(PGLOBAL g, bool dox); + virtual int ResetTableOpt(PGLOBAL g, bool dop, bool dox); virtual PSZ GetServer(void) {return "Current";} // Database routines |