diff options
Diffstat (limited to 'storage/connect')
47 files changed, 2844 insertions, 1812 deletions
diff --git a/storage/connect/array.cpp b/storage/connect/array.cpp index 75aed1503d9..6cd175a0f0a 100644 --- a/storage/connect/array.cpp +++ b/storage/connect/array.cpp @@ -124,6 +124,9 @@ PARRAY MakeValueArray(PGLOBAL g, PPARM pp) case TYPE_DOUBLE: par->AddValue(g, *(double*)parmp->Value); break; + case TYPE_PCHAR: + par->AddValue(g, parmp->Value); + break; } // endswitch valtyp /*********************************************************************/ @@ -156,6 +159,7 @@ ARRAY::ARRAY(PGLOBAL g, int type, int size, int length, int prec) case TYPE_SHORT: case TYPE_INT: case TYPE_DOUBLE: + case TYPE_PCHAR: break; #if 0 case TYPE_TOKEN: @@ -172,12 +176,13 @@ ARRAY::ARRAY(PGLOBAL g, int type, int size, int length, int prec) } // endswitch type Valblk = new(g) MBVALS; - Vblp = Valblk->Allocate(g, Type, Len, prec, Size); - if (!Valblk->GetMemp() && Type != TYPE_LIST) + if (!(Vblp = Valblk->Allocate(g, Type, Len, prec, Size))) + Type = TYPE_ERROR; + else if (!Valblk->GetMemp() && Type != TYPE_LIST) // The error message was built by PlgDBalloc Type = TYPE_ERROR; - else + else if (type != TYPE_PCHAR) Value = AllocateValue(g, type, Len, prec, NULL); Constant = TRUE; @@ -288,7 +293,24 @@ bool ARRAY::AddValue(PGLOBAL g, PSZ strp) } // end of AddValue /***********************************************************************/ -/* Add a SHORT integer element to an array. */ +/* Add a char pointer element to an array. */ +/***********************************************************************/ +bool ARRAY::AddValue(PGLOBAL g, void *p) + { + if (Type != TYPE_PCHAR) { + sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "PCHAR"); + return TRUE; + } // endif Type + + if (trace) + htrc(" adding pointer(%d): %p\n", Nval, p); + + Vblp->SetValue((PSZ)p, Nval++); + return FALSE; + } // end of AddValue + +/***********************************************************************/ +/* Add a short integer element to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, short n) { @@ -307,7 +329,7 @@ bool ARRAY::AddValue(PGLOBAL g, short n) } // end of AddValue /***********************************************************************/ -/* Add a int integer element to an array. */ +/* Add an integer element to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, int n) { @@ -404,15 +426,24 @@ bool ARRAY::GetSubValue(PGLOBAL g, PVAL valp, int *kp) vblp = ((LSTBLK*)Vblp)->Mbvk[kp[0]]->Vblk; valp->SetValue_pvblk(vblp, kp[1]); return FALSE; - } // end of GetNthValue + } // end of GetSubValue #endif // 0 /***********************************************************************/ +/* Return the nth value of an integer array. */ +/***********************************************************************/ +int ARRAY::GetIntValue(int n) + { + assert (Type == TYPE_INT); + return Vblp->GetIntValue(n); + } // end of GetIntValue + +/***********************************************************************/ /* Return the nth value of a STRING array. */ /***********************************************************************/ char *ARRAY::GetStringValue(int n) { - assert (Type == TYPE_STRING); + assert (Type == TYPE_STRING || Type == TYPE_PCHAR); return Vblp->GetCharValue(n); } // end of GetStringValue @@ -766,6 +797,44 @@ bool ARRAY::Sort(PGLOBAL g) } // end of Sort /***********************************************************************/ +/* Sort and return the sort index. */ +/* Note: This is meant if the array contains unique values. */ +/* Returns Index.Memp if Ok or NULL in case of error. */ +/***********************************************************************/ +void *ARRAY::GetSortIndex(PGLOBAL g) + { + // Prepare non conservative sort with offet values + Index.Size = Nval * sizeof(int); + + if (!PlgDBalloc(g, NULL, Index)) + goto error; + + Offset.Size = (Nval + 1) * sizeof(int); + + if (!PlgDBalloc(g, NULL, Offset)) + goto error; + + // Call the sort program, it returns the number of distinct values + Ndif = Qsort(g, Nval); + + if (Ndif < 0) + goto error; + + if (Ndif < Nval) + goto error; + + PlgDBfree(Offset); + return Index.Memp; + + error: + Nval = Ndif = 0; + Valblk->Free(); + PlgDBfree(Index); + PlgDBfree(Offset); + return NULL; + } // end of GetSortIndex + +/***********************************************************************/ /* Block filter testing for IN operator on Column/Array operands. */ /* Here we call Find that returns TRUE if the value is in the array */ /* with X equal to the index of the found value in the array, or */ diff --git a/storage/connect/array.h b/storage/connect/array.h index 01b5b935def..4a818414e9c 100644 --- a/storage/connect/array.h +++ b/storage/connect/array.h @@ -5,6 +5,9 @@ /* */ /* This file contains the ARRAY and VALBASE derived classes declares. */ /***********************************************************************/ +#ifndef __ARRAY_H +#define __ARRAY_H + /***********************************************************************/ /* Include required application header files */ @@ -57,18 +60,21 @@ class DllExport ARRAY : public XOBJECT, public CSORT { // Array descblock // void Empty(void); void SetPrecision(PGLOBAL g, int p); bool AddValue(PGLOBAL g, PSZ sp); + bool AddValue(PGLOBAL g, void *p); bool AddValue(PGLOBAL g, short n); bool AddValue(PGLOBAL g, int n); bool AddValue(PGLOBAL g, double f); bool AddValue(PGLOBAL g, PXOB xp); bool AddValue(PGLOBAL g, PVAL vp); void GetNthValue(PVAL valp, int n); + int GetIntValue(int n); char *GetStringValue(int n); BYTE Vcompare(PVAL vp, int n); void Save(int); void Restore(int); void Move(int, int); bool Sort(PGLOBAL g); + void *GetSortIndex(PGLOBAL g); bool Find(PVAL valp); bool FilTest(PGLOBAL g, PVAL valp, OPVAL opc, int opm); int Convert(PGLOBAL g, int k, PVAL vp = NULL); @@ -120,3 +126,5 @@ class MULAR : public CSORT, public BLOCK { // No need to be an XOBJECT int Narray; // The number of sub-arrays PARRAY *Pars; // To the block of real arrays }; // end of class ARRAY + +#endif // __ARRAY_H diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index e782fbbfff3..8b0aadd52c5 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -169,7 +169,8 @@ bool CntInfo(PGLOBAL g, PTDB tp, PXF info) info->data_file_length= (b) ? (ulonglong)tdbp->GetFileLength(g) : 0; if (!b || info->data_file_length) - info->records= (unsigned)tdbp->GetMaxSize(g); + info->records= (unsigned)tdbp->Cardinality(g); +// info->records= (unsigned)tdbp->GetMaxSize(g); else info->records= 0; @@ -578,6 +579,7 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp, bool nox, bool abort) } // endif if ((rc = setjmp(g->jumper[++g->jump_level])) != 0) { + rc= RC_FX; g->jump_level--; goto err; } // endif diff --git a/storage/connect/filamap.cpp b/storage/connect/filamap.cpp index 1e7a9ba0d12..b5958c1a854 100644 --- a/storage/connect/filamap.cpp +++ b/storage/connect/filamap.cpp @@ -1,727 +1,798 @@ -/*********** File AM Map C++ Program Source Code File (.CPP) ***********/
-/* PROGRAM NAME: FILAMAP */
-/* ------------- */
-/* Version 1.5 */
-/* */
-/* COPYRIGHT: */
-/* ---------- */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */
-/* */
-/* WHAT THIS PROGRAM DOES: */
-/* ----------------------- */
-/* This program are the MAP file access method classes. */
-/* */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include relevant sections of the System header files. */
-/***********************************************************************/
-#include "my_global.h"
-#if defined(WIN32)
-#if defined(__BORLANDC__)
-#define __MFC_COMPAT__ // To define min/max as macro
-#endif // __BORLANDC__
-//#include <windows.h>
-#else // !WIN32
-#if defined(UNIX)
-#include <errno.h>
-#include <unistd.h>
-#else // !UNIX
-#include <io.h>
-#endif // !UNIX
-#include <fcntl.h>
-#endif // !WIN32
-
-/***********************************************************************/
-/* Include application header files: */
-/* global.h is header containing all global declarations. */
-/* plgdbsem.h is header containing the DB application declarations. */
-/* filamtxt.h is header containing the file AM classes declarations. */
-/* Note: these files are included inside the include files below. */
-/***********************************************************************/
-#include "global.h"
-#include "plgdbsem.h"
-#include "osutil.h"
-#include "maputil.h"
-#include "filamap.h"
-#include "tabdos.h"
-
-extern "C" int trace;
-
-/* --------------------------- Class MAPFAM -------------------------- */
-
-/***********************************************************************/
-/* Constructors. */
-/***********************************************************************/
-MAPFAM::MAPFAM(PDOSDEF tdp) : TXTFAM(tdp)
- {
- Memory = NULL;
- Mempos = NULL;
- Tpos = NULL;
- Fpos = NULL;
- Spos = NULL;
- Top = NULL;
- } // end of MAPFAM standard constructor
-
-MAPFAM::MAPFAM(PMAPFAM tmfp) : TXTFAM(tmfp)
- {
- Memory = tmfp->Memory;
- Mempos = tmfp->Mempos;
- Fpos = tmfp->Fpos;
- Spos = tmfp->Spos;
- Tpos = tmfp->Tpos;
- Top = tmfp->Top;
- } // end of MAPFAM copy constructor
-
-/***********************************************************************/
-/* Reset: reset position values at the beginning of file. */
-/***********************************************************************/
-void MAPFAM::Reset(void)
- {
- TXTFAM::Reset();
- Fpos = Tpos = Spos = NULL;
- } // end of Reset
-
-/***********************************************************************/
-/* MAP GetFileLength: returns file size in number of bytes. */
-/***********************************************************************/
-int MAPFAM::GetFileLength(PGLOBAL g)
- {
- int len;
-
- len = (To_Fb) ? To_Fb->Length : TXTFAM::GetFileLength(g);
-
- if (trace)
- htrc("Mapped file length=%d\n", len);
-
- return len;
- } // end of GetFileLength
-
-/***********************************************************************/
-/* OpenTableFile: Open a DOS/UNIX table file as a mapped file. */
-/***********************************************************************/
-bool MAPFAM::OpenTableFile(PGLOBAL g)
- {
- char filename[_MAX_PATH];
- int len;
- MODE mode = Tdbp->GetMode();
- PFBLOCK fp;
- PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
-
-#if defined(_DEBUG)
- // Insert mode is no more handled using file mapping
- assert(mode != MODE_INSERT);
-#endif // _DEBUG
-
- /*********************************************************************/
- /* We used the file name relative to recorded datapath. */
- /*********************************************************************/
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
- /*********************************************************************/
- /* Under Win32 the whole file will be mapped so we can use it as */
- /* if it were entirely read into virtual memory. */
- /* Firstly we check whether this file have been already mapped. */
- /*********************************************************************/
- if (mode == MODE_READ) {
- for (fp = dbuserp->Openlist; fp; fp = fp->Next)
- if (fp->Type == TYPE_FB_MAP && !stricmp(fp->Fname, filename)
- && fp->Count && fp->Mode == mode)
- break;
-
-#ifdef DEBTRACE
- htrc("Mapping file, fp=%p\n", fp);
-#endif
- } else
- fp = NULL;
-
- if (fp) {
- /*******************************************************************/
- /* File already mapped. Just increment use count and get pointer. */
- /*******************************************************************/
- fp->Count++;
- Memory = fp->Memory;
- len = fp->Length;
- } else {
- /*******************************************************************/
- /* If required, delete the whole file if no filtering is implied. */
- /*******************************************************************/
- bool del;
- HANDLE hFile;
- MEMMAP mm;
-
- del = mode == MODE_DELETE && !Tdbp->GetNext();
-
- if (del)
- DelRows = Cardinality(g);
-
- /*******************************************************************/
- /* Create the mapping file object. */
- /*******************************************************************/
- hFile = CreateFileMap(g, filename, &mm, mode, del);
-
- if (hFile == INVALID_HANDLE_VALUE) {
- DWORD rc = GetLastError();
-
- if (!(*g->Message))
- sprintf(g->Message, MSG(OPEN_MODE_ERROR),
- "map", (int) rc, filename);
-
- if (trace)
- htrc("CreateFileMap: %s\n", g->Message);
-
- return (mode == MODE_READ && rc == ENOENT)
- ? PushWarning(g, Tdbp) : true;
- } // endif hFile
-
- /*******************************************************************/
- /* Get the file size (assuming file is smaller than 4 GB) */
- /*******************************************************************/
- len = mm.lenL;
- Memory = (char *)mm.memory;
-
- if (!len) { // Empty or deleted file
- CloseFileHandle(hFile);
- Tdbp->ResetSize();
- return false;
- } // endif len
-
- if (!Memory) {
- CloseFileHandle(hFile);
- sprintf(g->Message, MSG(MAP_VIEW_ERROR),
- filename, GetLastError());
- return true;
- } // endif Memory
-
-#if defined(WIN32)
- if (mode != MODE_DELETE) {
-#else // !WIN32
- if (mode == MODE_READ) {
-#endif // !WIN32
- CloseFileHandle(hFile); // Not used anymore
- hFile = INVALID_HANDLE_VALUE; // For Fblock
- } // endif Mode
-
- /*******************************************************************/
- /* Link a Fblock. This make possible to reuse already opened maps */
- /* and also to automatically unmap them in case of error g->jump. */
- /* Note: block can already exist for previously closed file. */
- /*******************************************************************/
- fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
- fp->Type = TYPE_FB_MAP;
- fp->Fname = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
- strcpy((char*)fp->Fname, filename);
- fp->Next = dbuserp->Openlist;
- dbuserp->Openlist = fp;
- fp->Count = 1;
- fp->Length = len;
- fp->Memory = Memory;
- fp->Mode = mode;
- fp->File = NULL;
- fp->Handle = hFile; // Used for Delete
- } // endif fp
-
- To_Fb = fp; // Useful when closing
-
- /*********************************************************************/
- /* The pseudo "buffer" is here the entire file mapping view. */
- /*********************************************************************/
- Fpos = Mempos = Memory;
- Top = Memory + len;
-
- if (trace)
- htrc("fp=%p count=%d MapView=%p len=%d Top=%p\n",
- fp, fp->Count, Memory, len, Top);
-
- return AllocateBuffer(g); // Useful for DBF files
- } // end of OpenTableFile
-
-/***********************************************************************/
-/* GetRowID: return the RowID of last read record. */
-/***********************************************************************/
-int MAPFAM::GetRowID(void)
- {
- return Rows;
- } // end of GetRowID
-
-/***********************************************************************/
-/* GetPos: return the position of last read record. */
-/***********************************************************************/
-int MAPFAM::GetPos(void)
- {
- return Fpos - Memory;
- } // end of GetPos
-
-/***********************************************************************/
-/* GetNextPos: return the position of next record. */
-/***********************************************************************/
-int MAPFAM::GetNextPos(void)
- {
- return Mempos - Memory;
- } // end of GetNextPos
-
-/***********************************************************************/
-/* SetPos: Replace the table at the specified position. */
-/***********************************************************************/
-bool MAPFAM::SetPos(PGLOBAL g, int pos)
- {
- Fpos = Mempos = Memory + pos;
-
- if (Mempos >= Top || Mempos < Memory) {
- strcpy(g->Message, MSG(INV_MAP_POS));
- return true;
- } // endif Mempos
-
- Placed = true;
- return false;
- } // end of SetPos
-
-/***********************************************************************/
-/* Record file position in case of UPDATE or DELETE. */
-/***********************************************************************/
-bool MAPFAM::RecordPos(PGLOBAL g)
- {
- Fpos = Mempos;
- return false;
- } // end of RecordPos
-
-/***********************************************************************/
-/* Skip one record in file. */
-/***********************************************************************/
-int MAPFAM::SkipRecord(PGLOBAL g, bool header)
- {
- PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
-
- // Skip this record
- while (*Mempos++ != '\n') ; // What about Unix ???
-
- if (Mempos >= Top)
- return RC_EF;
-
- // Update progress information
- dup->ProgCur = GetPos();
-
- if (header)
- Fpos = Tpos = Spos = Mempos; // For Delete
-
- return RC_OK;
- } // end of SkipRecord
-
-/***********************************************************************/
-/* ReadBuffer: Read one line for a mapped text file. */
-/***********************************************************************/
-int MAPFAM::ReadBuffer(PGLOBAL g)
- {
- int len;
-
- // Are we at the end of the memory
- if (Mempos >= Top)
- return RC_EF;
-
- if (!Placed) {
- /*******************************************************************/
- /* Record file position in case of UPDATE or DELETE. */
- /*******************************************************************/
- int rc;
-
- next:
- Fpos = Mempos;
- CurBlk = (int)Rows++;
-
- /*******************************************************************/
- /* 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
- } else
- Placed = false;
-
- // Immediately calculate next position (Used by DeleteDB)
- while (*Mempos++ != '\n') ; // What about Unix ???
-
- // Set caller line buffer
- len = (Mempos - Fpos) - Ending;
- memcpy(Tdbp->GetLine(), Fpos, len);
- Tdbp->GetLine()[len] = '\0';
- return RC_OK;
- } // end of ReadBuffer
-
-/***********************************************************************/
-/* WriteBuffer: File write routine for MAP access method. */
-/***********************************************************************/
-int MAPFAM::WriteBuffer(PGLOBAL g)
- {
-#if defined(_DEBUG)
- // Insert mode is no more handled using file mapping
- if (Tdbp->GetMode() == MODE_INSERT) {
- strcpy(g->Message, MSG(NO_MAP_INSERT));
- return RC_FX;
- } // endif
-#endif // _DEBUG
-
- /*********************************************************************/
- /* Copy the updated record back into the memory mapped file. */
- /*********************************************************************/
- memcpy(Fpos, Tdbp->GetLine(), strlen(Tdbp->GetLine()));
- return RC_OK;
- } // end of WriteBuffer
-
-/***********************************************************************/
-/* Data Base delete line routine for MAP (and FIX?) access methods. */
-/* Lines between deleted lines are moved in the mapfile view. */
-/***********************************************************************/
-int MAPFAM::DeleteRecords(PGLOBAL g, int irc)
- {
- int n;
-
- if (trace)
- htrc("MAP DeleteDB: irc=%d mempos=%p tobuf=%p Tpos=%p Spos=%p\n",
- irc, Mempos, To_Buf, Tpos, Spos);
-
- if (irc != RC_OK) {
- /*******************************************************************/
- /* EOF: position Fpos at the top of map position. */
- /*******************************************************************/
- Fpos = Top;
-
- if (trace)
- htrc("Fpos placed at file top=%p\n", Fpos);
-
- } // endif irc
-
- if (Tpos == Spos)
- /*******************************************************************/
- /* First line to delete. Move of eventual preceeding lines is */
- /* not required here, just setting of future Spos and Tpos. */
- /*******************************************************************/
- Tpos = Fpos; // Spos is set below
- else if ((n = Fpos - Spos) > 0) {
- /*******************************************************************/
- /* Non consecutive line to delete. Move intermediate lines. */
- /*******************************************************************/
- memmove(Tpos, Spos, n);
- Tpos += n;
-
- if (trace)
- htrc("move %d bytes\n", n);
-
- } // endif n
-
- if (irc == RC_OK) {
- Spos = Mempos; // New start position
-
- if (trace)
- htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos);
-
- } else if (To_Fb) { // Can be NULL for deleted files
- /*******************************************************************/
- /* Last call after EOF has been reached. */
- /* We must firstly Unmap the view and use the saved file handle */
- /* to put an EOF at the end of the copied part of the file. */
- /*******************************************************************/
- PFBLOCK fp = To_Fb;
-
- CloseMemMap(fp->Memory, (size_t)fp->Length);
- fp->Count = 0; // Avoid doing it twice
-
- /*******************************************************************/
- /* Remove extra records. */
- /*******************************************************************/
- n = Tpos - Memory;
-
-#if defined(WIN32)
- DWORD drc = SetFilePointer(fp->Handle, n, NULL, FILE_BEGIN);
-
- if (drc == 0xFFFFFFFF) {
- sprintf(g->Message, MSG(FUNCTION_ERROR),
- "SetFilePointer", GetLastError());
- CloseHandle(fp->Handle);
- return RC_FX;
- } // endif
-
- if (trace)
- htrc("done, Tpos=%p newsize=%d drc=%d\n", Tpos, n, drc);
-
- if (!SetEndOfFile(fp->Handle)) {
- sprintf(g->Message, MSG(FUNCTION_ERROR),
- "SetEndOfFile", GetLastError());
- CloseHandle(fp->Handle);
- return RC_FX;
- } // endif
-
- CloseHandle(fp->Handle);
-#else // UNIX
- if (ftruncate(fp->Handle, (off_t)n)) {
- sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
- close(fp->Handle);
- return RC_FX;
- } // endif
-
- close(fp->Handle);
-#endif // UNIX
- } // endif irc
-
- return RC_OK; // All is correct
- } // end of DeleteRecords
-
-/***********************************************************************/
-/* Table file close routine for MAP access method. */
-/***********************************************************************/
-void MAPFAM::CloseTableFile(PGLOBAL g, bool abort)
- {
- PlugCloseFile(g, To_Fb);
- To_Fb = NULL; // To get correct file size in Cardinality
-
- if (trace)
- htrc("MAP Close: closing %s count=%d\n",
- To_File, (To_Fb) ? To_Fb->Count : 0);
-
- } // end of CloseTableFile
-
-/***********************************************************************/
-/* Rewind routine for MAP access method. */
-/***********************************************************************/
-void MAPFAM::Rewind(void)
- {
- Mempos = Memory;
- } // end of Rewind
-
-/* --------------------------- Class MBKFAM -------------------------- */
-
-/***********************************************************************/
-/* Constructors. */
-/***********************************************************************/
-MBKFAM::MBKFAM(PDOSDEF tdp) : MAPFAM(tdp)
- {
- Blocked = true;
- Block = tdp->GetBlock();
- Last = tdp->GetLast();
- Nrec = tdp->GetElemt();
- BlkPos = tdp->GetTo_Pos();
- CurNum = Nrec;
- } // end of MBKFAM standard constructor
-
-/***********************************************************************/
-/* Reset: reset position values at the beginning of file. */
-/***********************************************************************/
-void MBKFAM::Reset(void)
- {
- MAPFAM::Reset();
- CurNum = Nrec; // To start by a new block
- } // end of Reset
-
-/***********************************************************************/
-/* Cardinality: returns table cardinality in number of rows. */
-/* This function can be called with a null argument to test the */
-/* availability of Cardinality implementation (1 yes, 0 no). */
-/***********************************************************************/
-int MBKFAM::Cardinality(PGLOBAL g)
- {
- return (g) ? (int)((Block - 1) * Nrec + Last) : 1;
- } // end of Cardinality
-
-/***********************************************************************/
-/* Skip one record in file. */
-/***********************************************************************/
-int MBKFAM::SkipRecord(PGLOBAL g, bool header)
- {
- return RC_OK;
- } // end of SkipRecord
-
-/***********************************************************************/
-/* GetRowID: return the RowID of last read record. */
-/***********************************************************************/
-int MBKFAM::GetRowID(void)
- {
- return CurNum + Nrec * CurBlk + 1;
- } // end of GetRowID
-
-/***********************************************************************/
-/* ReadBuffer: Read one line for a mapped Fix file. */
-/***********************************************************************/
-int MBKFAM::ReadBuffer(PGLOBAL g)
- {
- int len;
-
- /*********************************************************************/
- /* Sequential block reading when Placed is not true. */
- /*********************************************************************/
- if (Placed) {
- Placed = false;
- } else if (Mempos >= Top) { // Are we at the end of the memory
- return RC_EF;
- } else if (++CurNum < Nrec) {
- Fpos = Mempos;
- } 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. */
- /*******************************************************************/
- switch (Tdbp->TestBlock(g)) {
- case RC_EF:
- return RC_EF;
- case RC_NF:
- goto next;
- } // endswitch rc
-
- Fpos = Mempos = Memory + BlkPos[CurBlk];
- } // endif's
-
- // Immediately calculate next position (Used by DeleteDB)
- while (*Mempos++ != '\n') ; // What about Unix ???
-
- // Set caller line buffer
- len = (Mempos - Fpos) - Ending;
- memcpy(Tdbp->GetLine(), Fpos, len);
- Tdbp->GetLine()[len] = '\0';
- return RC_OK;
- } // end of ReadBuffer
-
-/***********************************************************************/
-/* Rewind routine for FIX MAP access method. */
-/***********************************************************************/
-void MBKFAM::Rewind(void)
- {
- Mempos = Memory + Headlen;
- CurBlk = -1;
- CurNum = Nrec;
- } // end of Rewind
-
-/* --------------------------- Class MPXFAM -------------------------- */
-
-/***********************************************************************/
-/* Constructors. */
-/***********************************************************************/
-MPXFAM::MPXFAM(PDOSDEF tdp) : MBKFAM(tdp)
- {
- Blksize = tdp->GetBlksize();
- Padded = tdp->GetPadded();
-
- if (Padded && Blksize)
- Nrec = Blksize / Lrecl;
- else {
- Nrec = (tdp->GetElemt()) ? tdp->GetElemt() : DOS_BUFF_LEN;
- Blksize = Nrec * Lrecl;
- Padded = false;
- } // endelse
-
- CurNum = Nrec;
- } // end of MPXFAM standard constructor
-
-#if 0 // MBKFAM routine is correct
-/***********************************************************************/
-/* GetRowID: return the RowID of last read record. */
-/***********************************************************************/
-int MPXFAM::GetRowID(void)
- {
- return (Mempos - Memory - Headlen) / Lrecl;
- } // end of GetRowID
-#endif
-
-/***********************************************************************/
-/* GetPos: return the position of last read record. */
-/***********************************************************************/
-int MPXFAM::GetPos(void)
- {
- return (CurNum + Nrec * CurBlk); // Computed file index
- } // end of GetPos
-
-/***********************************************************************/
-/* SetPos: Replace the table at the specified position. */
-/***********************************************************************/
-bool MPXFAM::SetPos(PGLOBAL g, int pos)
- {
- if (pos < 0) {
- strcpy(g->Message, MSG(INV_REC_POS));
- return true;
- } // endif recpos
-
- CurBlk = pos / Nrec;
- CurNum = pos % Nrec;
- Fpos = Mempos = Memory + Headlen + pos * Lrecl;
-
- // Indicate the table position was externally set
- Placed = true;
- return false;
- } // end of SetPos
-
-/***********************************************************************/
-/* ReadBuffer: Read one line for a mapped Fix file. */
-/***********************************************************************/
-int MPXFAM::ReadBuffer(PGLOBAL g)
- {
- /*********************************************************************/
- /* Sequential block reading when Placed is not true. */
- /*********************************************************************/
- if (Placed) {
- Placed = false;
- } else if (Mempos >= Top) { // Are we at the end of the memory
- return RC_EF;
- } else if (++CurNum < Nrec) {
- Fpos = Mempos;
- } 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. */
- /*******************************************************************/
- switch (Tdbp->TestBlock(g)) {
- case RC_EF:
- return RC_EF;
- case RC_NF:
- goto next;
- } // endswitch rc
-
- Fpos = Mempos = Headlen + Memory + CurBlk * Blksize;
- } // endif's
-
- Tdbp->SetLine(Mempos);
-
- // Immediately calculate next position (Used by DeleteDB)
- Mempos += Lrecl;
- return RC_OK;
- } // end of ReadBuffer
-
-/***********************************************************************/
-/* WriteBuffer: File write routine for MAP access method. */
-/***********************************************************************/
-int MPXFAM::WriteBuffer(PGLOBAL g)
- {
-#if defined(_DEBUG)
- // Insert mode is no more handled using file mapping
- if (Tdbp->GetMode() == MODE_INSERT) {
- strcpy(g->Message, MSG(NO_MAP_INSERT));
- return RC_FX;
- } // endif
-#endif // _DEBUG
-
- // In Update mode, file was modified in memory
- return RC_OK;
- } // end of WriteBuffer
-
+/*********** File AM Map C++ Program Source Code File (.CPP) ***********/ +/* PROGRAM NAME: FILAMAP */ +/* ------------- */ +/* Version 1.6 */ +/* */ +/* COPYRIGHT: */ +/* ---------- */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */ +/* */ +/* WHAT THIS PROGRAM DOES: */ +/* ----------------------- */ +/* This program are the MAP file access method classes. */ +/* */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant sections of the System header files. */ +/***********************************************************************/ +#include "my_global.h" +#if defined(WIN32) +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif // __BORLANDC__ +//#include <windows.h> +#else // !WIN32 +#if defined(UNIX) +#include <errno.h> +#include <unistd.h> +#else // !UNIX +#include <io.h> +#endif // !UNIX +#include <fcntl.h> +#endif // !WIN32 + +/***********************************************************************/ +/* Include application header files: */ +/* global.h is header containing all global declarations. */ +/* plgdbsem.h is header containing the DB application declarations. */ +/* filamtxt.h is header containing the file AM classes declarations. */ +/* Note: these files are included inside the include files below. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "osutil.h" +#include "maputil.h" +#include "filamap.h" +#include "tabdos.h" + +extern "C" int trace; + +/***********************************************************************/ +/* Routine called externally by MAPFAM MakeDeletedFile function. */ +/***********************************************************************/ +PARRAY MakeValueArray(PGLOBAL g, PPARM pp); + +/* --------------------------- Class MAPFAM -------------------------- */ + +/***********************************************************************/ +/* Constructors. */ +/***********************************************************************/ +MAPFAM::MAPFAM(PDOSDEF tdp) : TXTFAM(tdp) + { + Memory = NULL; + Mempos = NULL; + Tpos = NULL; + Fpos = NULL; + Spos = NULL; + Top = NULL; + } // end of MAPFAM standard constructor + +MAPFAM::MAPFAM(PMAPFAM tmfp) : TXTFAM(tmfp) + { + Memory = tmfp->Memory; + Mempos = tmfp->Mempos; + Fpos = tmfp->Fpos; + Spos = tmfp->Spos; + Tpos = tmfp->Tpos; + Top = tmfp->Top; + } // end of MAPFAM copy constructor + +/***********************************************************************/ +/* Reset: reset position values at the beginning of file. */ +/***********************************************************************/ +void MAPFAM::Reset(void) + { + TXTFAM::Reset(); + Fpos = Tpos = Spos = NULL; + } // end of Reset + +/***********************************************************************/ +/* MAP GetFileLength: returns file size in number of bytes. */ +/***********************************************************************/ +int MAPFAM::GetFileLength(PGLOBAL g) + { + int len; + + len = (To_Fb) ? To_Fb->Length : TXTFAM::GetFileLength(g); + + if (trace) + htrc("Mapped file length=%d\n", len); + + return len; + } // end of GetFileLength + +/***********************************************************************/ +/* OpenTableFile: Open a DOS/UNIX table file as a mapped file. */ +/***********************************************************************/ +bool MAPFAM::OpenTableFile(PGLOBAL g) + { + char filename[_MAX_PATH]; + int len; + MODE mode = Tdbp->GetMode(); + PFBLOCK fp; + PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr; + +#if defined(_DEBUG) + // Insert mode is no more handled using file mapping + assert(mode != MODE_INSERT); +#endif // _DEBUG + + /*********************************************************************/ + /* We used the file name relative to recorded datapath. */ + /*********************************************************************/ + PlugSetPath(filename, To_File, Tdbp->GetPath()); + + /*********************************************************************/ + /* Under Win32 the whole file will be mapped so we can use it as */ + /* if it were entirely read into virtual memory. */ + /* Firstly we check whether this file have been already mapped. */ + /*********************************************************************/ + if (mode == MODE_READ) { + for (fp = dbuserp->Openlist; fp; fp = fp->Next) + if (fp->Type == TYPE_FB_MAP && !stricmp(fp->Fname, filename) + && fp->Count && fp->Mode == mode) + break; + +#ifdef DEBTRACE + htrc("Mapping file, fp=%p\n", fp); +#endif + } else + fp = NULL; + + if (fp) { + /*******************************************************************/ + /* File already mapped. Just increment use count and get pointer. */ + /*******************************************************************/ + fp->Count++; + Memory = fp->Memory; + len = fp->Length; + } else { + /*******************************************************************/ + /* If required, delete the whole file if no filtering is implied. */ + /*******************************************************************/ + bool del; + HANDLE hFile; + MEMMAP mm; + + del = mode == MODE_DELETE && !Tdbp->GetNext(); + + if (del) + DelRows = Cardinality(g); + + /*******************************************************************/ + /* Create the mapping file object. */ + /*******************************************************************/ + hFile = CreateFileMap(g, filename, &mm, mode, del); + + if (hFile == INVALID_HANDLE_VALUE) { + DWORD rc = GetLastError(); + + if (!(*g->Message)) + sprintf(g->Message, MSG(OPEN_MODE_ERROR), + "map", (int) rc, filename); + + if (trace) + htrc("CreateFileMap: %s\n", g->Message); + + return (mode == MODE_READ && rc == ENOENT) + ? PushWarning(g, Tdbp) : true; + } // endif hFile + + /*******************************************************************/ + /* Get the file size (assuming file is smaller than 4 GB) */ + /*******************************************************************/ + len = mm.lenL; + Memory = (char *)mm.memory; + + if (!len) { // Empty or deleted file + CloseFileHandle(hFile); + Tdbp->ResetSize(); + return false; + } // endif len + + if (!Memory) { + CloseFileHandle(hFile); + sprintf(g->Message, MSG(MAP_VIEW_ERROR), + filename, GetLastError()); + return true; + } // endif Memory + +#if defined(WIN32) + if (mode != MODE_DELETE) { +#else // !WIN32 + if (mode == MODE_READ) { +#endif // !WIN32 + CloseFileHandle(hFile); // Not used anymore + hFile = INVALID_HANDLE_VALUE; // For Fblock + } // endif Mode + + /*******************************************************************/ + /* Link a Fblock. This make possible to reuse already opened maps */ + /* and also to automatically unmap them in case of error g->jump. */ + /* Note: block can already exist for previously closed file. */ + /*******************************************************************/ + fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK)); + fp->Type = TYPE_FB_MAP; + fp->Fname = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1); + strcpy((char*)fp->Fname, filename); + fp->Next = dbuserp->Openlist; + dbuserp->Openlist = fp; + fp->Count = 1; + fp->Length = len; + fp->Memory = Memory; + fp->Mode = mode; + fp->File = NULL; + fp->Handle = hFile; // Used for Delete + } // endif fp + + To_Fb = fp; // Useful when closing + + /*********************************************************************/ + /* The pseudo "buffer" is here the entire file mapping view. */ + /*********************************************************************/ + Fpos = Mempos = Memory; + Top = Memory + len; + + if (trace) + htrc("fp=%p count=%d MapView=%p len=%d Top=%p\n", + fp, fp->Count, Memory, len, Top); + + return AllocateBuffer(g); // Useful for DBF files + } // end of OpenTableFile + +/***********************************************************************/ +/* GetRowID: return the RowID of last read record. */ +/***********************************************************************/ +int MAPFAM::GetRowID(void) + { + return Rows; + } // end of GetRowID + +/***********************************************************************/ +/* GetPos: return the position of last read record. */ +/***********************************************************************/ +int MAPFAM::GetPos(void) + { + return Fpos - Memory; + } // end of GetPos + +/***********************************************************************/ +/* GetNextPos: return the position of next record. */ +/***********************************************************************/ +int MAPFAM::GetNextPos(void) + { + return Mempos - Memory; + } // end of GetNextPos + +/***********************************************************************/ +/* SetPos: Replace the table at the specified position. */ +/***********************************************************************/ +bool MAPFAM::SetPos(PGLOBAL g, int pos) + { + Fpos = Mempos = Memory + pos; + + if (Mempos >= Top || Mempos < Memory) { + strcpy(g->Message, MSG(INV_MAP_POS)); + return true; + } // endif Mempos + + Placed = true; + return false; + } // end of SetPos + +/***********************************************************************/ +/* Record file position in case of UPDATE or DELETE. */ +/***********************************************************************/ +bool MAPFAM::RecordPos(PGLOBAL g) + { + Fpos = Mempos; + return false; + } // end of RecordPos + +/***********************************************************************/ +/* Skip one record in file. */ +/***********************************************************************/ +int MAPFAM::SkipRecord(PGLOBAL g, bool header) + { + PDBUSER dup = (PDBUSER)g->Activityp->Aptr; + + // Skip this record + while (*Mempos++ != '\n') ; // What about Unix ??? + + if (Mempos >= Top) + return RC_EF; + + // Update progress information + dup->ProgCur = GetPos(); + + if (header) + Fpos = Tpos = Spos = Mempos; // For Delete + + return RC_OK; + } // end of SkipRecord + +/***********************************************************************/ +/* ReadBuffer: Read one line for a mapped text file. */ +/***********************************************************************/ +int MAPFAM::ReadBuffer(PGLOBAL g) + { + int len; + + // Are we at the end of the memory + if (Mempos >= Top) + return RC_EF; + + if (!Placed) { + /*******************************************************************/ + /* Record file position in case of UPDATE or DELETE. */ + /*******************************************************************/ + int rc; + + next: + Fpos = Mempos; + CurBlk = (int)Rows++; + + /*******************************************************************/ + /* 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 + } else + Placed = false; + + // Immediately calculate next position (Used by DeleteDB) + while (*Mempos++ != '\n') ; // What about Unix ??? + + // Set caller line buffer + len = (Mempos - Fpos) - Ending; + memcpy(Tdbp->GetLine(), Fpos, len); + Tdbp->GetLine()[len] = '\0'; + return RC_OK; + } // end of ReadBuffer + +/***********************************************************************/ +/* WriteBuffer: File write routine for MAP access method. */ +/***********************************************************************/ +int MAPFAM::WriteBuffer(PGLOBAL g) + { +#if defined(_DEBUG) + // Insert mode is no more handled using file mapping + if (Tdbp->GetMode() == MODE_INSERT) { + strcpy(g->Message, MSG(NO_MAP_INSERT)); + return RC_FX; + } // endif +#endif // _DEBUG + + /*********************************************************************/ + /* Copy the updated record back into the memory mapped file. */ + /*********************************************************************/ + memcpy(Fpos, Tdbp->GetLine(), strlen(Tdbp->GetLine())); + return RC_OK; + } // end of WriteBuffer + +/***********************************************************************/ +/* Data Base delete line routine for MAP (and FIX?) access methods. */ +/* Lines between deleted lines are moved in the mapfile view. */ +/***********************************************************************/ +int MAPFAM::DeleteRecords(PGLOBAL g, int irc) + { + int n; + + if (trace) + htrc("MAP DeleteDB: irc=%d mempos=%p tobuf=%p Tpos=%p Spos=%p\n", + irc, Mempos, To_Buf, Tpos, Spos); + + if (irc != RC_OK) { + /*******************************************************************/ + /* EOF: position Fpos at the top of map position. */ + /*******************************************************************/ + Fpos = Top; + + if (trace) + htrc("Fpos placed at file top=%p\n", Fpos); + + } // endif irc + + if (Tpos == Spos) { + /*******************************************************************/ + /* First line to delete. Move of eventual preceeding lines is */ + /* not required here, just setting of future Spos and Tpos. */ + /*******************************************************************/ + Tpos = Spos = Fpos; + Indxd = Tdbp->GetKindex() != NULL; + } // endif Tpos + + if (Indxd) { + // Moving will be done later, must be done in sequential order + (void)AddListValue(g, TYPE_PCHAR, Fpos, &To_Pos); + (void)AddListValue(g, TYPE_PCHAR, Mempos, &To_Sos); + } else if ((n = Fpos - Spos) > 0) { + /*****************************************************************/ + /* Non consecutive line to delete. Move intermediate lines. */ + /*****************************************************************/ + memmove(Tpos, Spos, n); + Tpos += n; + + if (trace) + htrc("move %d bytes\n", n); + + } // endif n + + if (irc == RC_OK) { + Spos = Mempos; // New start position + + if (trace) + htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos); + + } else if (To_Fb) { // Can be NULL for deleted files + /*******************************************************************/ + /* Last call after EOF has been reached. */ + /*******************************************************************/ + Abort = (Indxd && MakeDeletedFile(g)); + + /*******************************************************************/ + /* We must firstly Unmap the view and use the saved file handle */ + /* to put an EOF at the end of the copied part of the file. */ + /*******************************************************************/ + PFBLOCK fp = To_Fb; + + CloseMemMap(fp->Memory, (size_t)fp->Length); + fp->Count = 0; // Avoid doing it twice + + if (!Abort) { + /*****************************************************************/ + /* Remove extra records. */ + /*****************************************************************/ + n = Tpos - Memory; + +#if defined(WIN32) + DWORD drc = SetFilePointer(fp->Handle, n, NULL, FILE_BEGIN); + + if (drc == 0xFFFFFFFF) { + sprintf(g->Message, MSG(FUNCTION_ERROR), + "SetFilePointer", GetLastError()); + CloseHandle(fp->Handle); + return RC_FX; + } // endif + + if (trace) + htrc("done, Tpos=%p newsize=%d drc=%d\n", Tpos, n, drc); + + if (!SetEndOfFile(fp->Handle)) { + sprintf(g->Message, MSG(FUNCTION_ERROR), + "SetEndOfFile", GetLastError()); + CloseHandle(fp->Handle); + return RC_FX; + } // endif + +#else // UNIX + if (ftruncate(fp->Handle, (off_t)n)) { + sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno)); + close(fp->Handle); + return RC_FX; + } // endif + +#endif // UNIX + } // endif Abort + +#if defined(WIN32) + CloseHandle(fp->Handle); +#else // UNIX + close(fp->Handle); +#endif // UNIX + } // endif irc + + return RC_OK; // All is correct + } // end of DeleteRecords + +/***********************************************************************/ +/* MakeDeletedFile. When deleting using indexing, the issue is that */ +/* record are not necessarily deleted in sequential order. Moving */ +/* intermediate lines cannot be done while deleting them. */ +/* What we do here is to reorder the deleted records and move the */ +/* intermediate files from the ordered deleted record positions. */ +/***********************************************************************/ +bool MAPFAM::MakeDeletedFile(PGLOBAL g) + { + int *ix, i, n; + + /*********************************************************************/ + /* Make and order the arrays from the saved values. */ + /*********************************************************************/ + if (!(Posar = MakeValueArray(g, To_Pos))) { + strcpy(g->Message, "Position array is null"); + goto err; + } else if (!(Sosar = MakeValueArray(g, To_Sos))) { + strcpy(g->Message, "Start position array is null"); + goto err; + } else if (!(ix = (int*)Posar->GetSortIndex(g))) { + strcpy(g->Message, "Error getting array sort index"); + goto err; + } // endif's + + for (i = 0; i < Posar->GetNval(); i++) { + Fpos = Posar->GetStringValue(ix[i]); + + if (!i) { + Tpos = Fpos; + } else if ((n = Fpos - Spos) >= 0) { + // Move all not deleted lines preceding this one + memmove(Tpos, Spos, n); + Tpos += n; + } // endif n + + // New start position + Spos = Sosar->GetStringValue(ix[i]); + } // endfor i + + return false; + +err: + if (trace) + htrc("%s\n", g->Message); + + return true; + } // end of MakeDeletedFile + +/***********************************************************************/ +/* Table file close routine for MAP access method. */ +/***********************************************************************/ +void MAPFAM::CloseTableFile(PGLOBAL g, bool abort) + { + PlugCloseFile(g, To_Fb); + To_Fb = NULL; // To get correct file size in Cardinality + + if (trace) + htrc("MAP Close: closing %s count=%d\n", + To_File, (To_Fb) ? To_Fb->Count : 0); + + } // end of CloseTableFile + +/***********************************************************************/ +/* Rewind routine for MAP access method. */ +/***********************************************************************/ +void MAPFAM::Rewind(void) + { + Mempos = Memory; + } // end of Rewind + +/* --------------------------- Class MBKFAM -------------------------- */ + +/***********************************************************************/ +/* Constructors. */ +/***********************************************************************/ +MBKFAM::MBKFAM(PDOSDEF tdp) : MAPFAM(tdp) + { + Blocked = true; + Block = tdp->GetBlock(); + Last = tdp->GetLast(); + Nrec = tdp->GetElemt(); + BlkPos = tdp->GetTo_Pos(); + CurNum = Nrec; + } // end of MBKFAM standard constructor + +/***********************************************************************/ +/* Reset: reset position values at the beginning of file. */ +/***********************************************************************/ +void MBKFAM::Reset(void) + { + MAPFAM::Reset(); + CurNum = Nrec; // To start by a new block + } // end of Reset + +/***********************************************************************/ +/* Cardinality: returns table cardinality in number of rows. */ +/* This function can be called with a null argument to test the */ +/* availability of Cardinality implementation (1 yes, 0 no). */ +/***********************************************************************/ +int MBKFAM::Cardinality(PGLOBAL g) + { + return (g) ? (int)((Block - 1) * Nrec + Last) : 1; + } // end of Cardinality + +/***********************************************************************/ +/* Skip one record in file. */ +/***********************************************************************/ +int MBKFAM::SkipRecord(PGLOBAL g, bool header) + { + return RC_OK; + } // end of SkipRecord + +/***********************************************************************/ +/* GetRowID: return the RowID of last read record. */ +/***********************************************************************/ +int MBKFAM::GetRowID(void) + { + return CurNum + Nrec * CurBlk + 1; + } // end of GetRowID + +/***********************************************************************/ +/* ReadBuffer: Read one line for a mapped Fix file. */ +/***********************************************************************/ +int MBKFAM::ReadBuffer(PGLOBAL g) + { + int len; + + /*********************************************************************/ + /* Sequential block reading when Placed is not true. */ + /*********************************************************************/ + if (Placed) { + Placed = false; + } else if (Mempos >= Top) { // Are we at the end of the memory + return RC_EF; + } else if (++CurNum < Nrec) { + Fpos = Mempos; + } 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. */ + /*******************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + goto next; + } // endswitch rc + + Fpos = Mempos = Memory + BlkPos[CurBlk]; + } // endif's + + // Immediately calculate next position (Used by DeleteDB) + while (*Mempos++ != '\n') ; // What about Unix ??? + + // Set caller line buffer + len = (Mempos - Fpos) - Ending; + memcpy(Tdbp->GetLine(), Fpos, len); + Tdbp->GetLine()[len] = '\0'; + return RC_OK; + } // end of ReadBuffer + +/***********************************************************************/ +/* Rewind routine for FIX MAP access method. */ +/***********************************************************************/ +void MBKFAM::Rewind(void) + { + Mempos = Memory + Headlen; + CurBlk = -1; + CurNum = Nrec; + } // end of Rewind + +/* --------------------------- Class MPXFAM -------------------------- */ + +/***********************************************************************/ +/* Constructors. */ +/***********************************************************************/ +MPXFAM::MPXFAM(PDOSDEF tdp) : MBKFAM(tdp) + { + Blksize = tdp->GetBlksize(); + Padded = tdp->GetPadded(); + + if (Padded && Blksize) + Nrec = Blksize / Lrecl; + else { + Nrec = (tdp->GetElemt()) ? tdp->GetElemt() : DOS_BUFF_LEN; + Blksize = Nrec * Lrecl; + Padded = false; + } // endelse + + CurNum = Nrec; + } // end of MPXFAM standard constructor + +#if 0 // MBKFAM routine is correct +/***********************************************************************/ +/* GetRowID: return the RowID of last read record. */ +/***********************************************************************/ +int MPXFAM::GetRowID(void) + { + return (Mempos - Memory - Headlen) / Lrecl; + } // end of GetRowID +#endif + +/***********************************************************************/ +/* GetPos: return the position of last read record. */ +/***********************************************************************/ +int MPXFAM::GetPos(void) + { + return (CurNum + Nrec * CurBlk); // Computed file index + } // end of GetPos + +/***********************************************************************/ +/* SetPos: Replace the table at the specified position. */ +/***********************************************************************/ +bool MPXFAM::SetPos(PGLOBAL g, int pos) + { + if (pos < 0) { + strcpy(g->Message, MSG(INV_REC_POS)); + return true; + } // endif recpos + + CurBlk = pos / Nrec; + CurNum = pos % Nrec; + Fpos = Mempos = Memory + Headlen + pos * Lrecl; + + // Indicate the table position was externally set + Placed = true; + return false; + } // end of SetPos + +/***********************************************************************/ +/* ReadBuffer: Read one line for a mapped Fix file. */ +/***********************************************************************/ +int MPXFAM::ReadBuffer(PGLOBAL g) + { + /*********************************************************************/ + /* Sequential block reading when Placed is not true. */ + /*********************************************************************/ + if (Placed) { + Placed = false; + } else if (Mempos >= Top) { // Are we at the end of the memory + return RC_EF; + } else if (++CurNum < Nrec) { + Fpos = Mempos; + } 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. */ + /*******************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + goto next; + } // endswitch rc + + Fpos = Mempos = Headlen + Memory + CurBlk * Blksize; + } // endif's + + Tdbp->SetLine(Mempos); + + // Immediately calculate next position (Used by DeleteDB) + Mempos += Lrecl; + return RC_OK; + } // end of ReadBuffer + +/***********************************************************************/ +/* WriteBuffer: File write routine for MAP access method. */ +/***********************************************************************/ +int MPXFAM::WriteBuffer(PGLOBAL g) + { +#if defined(_DEBUG) + // Insert mode is no more handled using file mapping + if (Tdbp->GetMode() == MODE_INSERT) { + strcpy(g->Message, MSG(NO_MAP_INSERT)); + return RC_FX; + } // endif +#endif // _DEBUG + + // In Update mode, file was modified in memory + return RC_OK; + } // end of WriteBuffer + diff --git a/storage/connect/filamap.h b/storage/connect/filamap.h index ccdbf6cb8bd..7d3203d7ff2 100644 --- a/storage/connect/filamap.h +++ b/storage/connect/filamap.h @@ -1,113 +1,115 @@ -/*************** FilAMap H Declares Source Code File (.H) **************/
-/* Name: FILAMAP.H Version 1.2 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
-/* */
-/* This file contains the MAP file access method classes declares. */
-/***********************************************************************/
-#ifndef __FILAMAP_H
-#define __FILAMAP_H
-
-#include "block.h"
-#include "filamtxt.h"
-
-typedef class MAPFAM *PMAPFAM;
-
-/***********************************************************************/
-/* This is the variable file access method using file mapping. */
-/***********************************************************************/
-class DllExport MAPFAM : public TXTFAM {
- public:
- // Constructor
- MAPFAM(PDOSDEF tdp);
- MAPFAM(PMAPFAM tmfp);
-
- // Implementation
- virtual AMT GetAmType(void) {return TYPE_AM_MAP;}
- virtual int GetPos(void);
- virtual int GetNextPos(void);
- virtual PTXF Duplicate(PGLOBAL g)
- {return (PTXF)new(g) MAPFAM(this);}
-
- // Methods
- virtual void Reset(void);
- virtual int GetFileLength(PGLOBAL g);
- virtual int Cardinality(PGLOBAL g) {return (g) ? -1 : 0;}
- virtual int MaxBlkSize(PGLOBAL g, int s) {return s;}
- virtual int GetRowID(void);
- virtual bool RecordPos(PGLOBAL g);
- virtual bool SetPos(PGLOBAL g, int recpos);
- virtual int SkipRecord(PGLOBAL g, bool header);
- virtual bool OpenTableFile(PGLOBAL g);
- virtual bool DeferReading(void) {return false;}
- virtual int ReadBuffer(PGLOBAL g);
- virtual int WriteBuffer(PGLOBAL g);
- virtual int DeleteRecords(PGLOBAL g, int irc);
- virtual void CloseTableFile(PGLOBAL g, bool abort);
- virtual void Rewind(void);
-
- protected:
- // Members
- char *Memory; // Pointer on file mapping view.
- char *Mempos; // Position of next data to read
- char *Fpos; // Position of last read record
- char *Tpos; // Target Position for delete move
- char *Spos; // Start position for delete move
- char *Top; // Mark end of file mapping view
- }; // end of class MAPFAM
-
-/***********************************************************************/
-/* This is the blocked file access method using file mapping. */
-/***********************************************************************/
-class DllExport MBKFAM : public MAPFAM {
- public:
- // Constructor
- MBKFAM(PDOSDEF tdp);
- MBKFAM(PMAPFAM tmfp) : MAPFAM(tmfp) {}
-
- // Implementation
- virtual PTXF Duplicate(PGLOBAL g)
- {return (PTXF)new(g) MBKFAM(this);}
-
- // Methods
- virtual void Reset(void);
- virtual int Cardinality(PGLOBAL g);
- virtual int MaxBlkSize(PGLOBAL g, int s)
- {return TXTFAM::MaxBlkSize(g, s);}
- virtual int GetRowID(void);
- virtual int SkipRecord(PGLOBAL g, bool header);
- virtual int ReadBuffer(PGLOBAL g);
- virtual void Rewind(void);
-
- protected:
- // No additional members
- }; // end of class MBKFAM
-
-/***********************************************************************/
-/* This is the fixed file access method using file mapping. */
-/***********************************************************************/
-class DllExport MPXFAM : public MBKFAM {
- public:
- // Constructor
- MPXFAM(PDOSDEF tdp);
- MPXFAM(PMAPFAM tmfp) : MBKFAM(tmfp) {}
-
- // Implementation
- virtual int GetPos(void);
- virtual PTXF Duplicate(PGLOBAL g)
- {return (PTXF)new(g) MPXFAM(this);}
-
- // Methods
- virtual int Cardinality(PGLOBAL g) {return TXTFAM::Cardinality(g);}
- virtual int MaxBlkSize(PGLOBAL g, int s)
- {return TXTFAM::MaxBlkSize(g, s);}
- virtual bool SetPos(PGLOBAL g, int recpos);
- virtual bool DeferReading(void) {return false;}
- virtual int ReadBuffer(PGLOBAL g);
- virtual int WriteBuffer(PGLOBAL g);
-
- protected:
- // No additional members
- }; // end of class MPXFAM
-
-#endif // __FILAMAP_H
+/*************** FilAMap H Declares Source Code File (.H) **************/ +/* Name: FILAMAP.H Version 1.3 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */ +/* */ +/* This file contains the MAP file access method classes declares. */ +/***********************************************************************/ +#ifndef __FILAMAP_H +#define __FILAMAP_H + +#include "block.h" +#include "filamtxt.h" + +typedef class MAPFAM *PMAPFAM; + +/***********************************************************************/ +/* This is the variable file access method using file mapping. */ +/***********************************************************************/ +class DllExport MAPFAM : public TXTFAM { + public: + // Constructor + MAPFAM(PDOSDEF tdp); + MAPFAM(PMAPFAM tmfp); + + // Implementation + virtual AMT GetAmType(void) {return TYPE_AM_MAP;} + virtual int GetPos(void); + virtual int GetNextPos(void); + virtual PTXF Duplicate(PGLOBAL g) + {return (PTXF)new(g) MAPFAM(this);} + + // Methods + virtual void Reset(void); + virtual int GetFileLength(PGLOBAL g); + virtual int Cardinality(PGLOBAL g) {return (g) ? -1 : 0;} + virtual int MaxBlkSize(PGLOBAL g, int s) {return s;} + virtual int GetRowID(void); + virtual bool RecordPos(PGLOBAL g); + virtual bool SetPos(PGLOBAL g, int recpos); + virtual int SkipRecord(PGLOBAL g, bool header); + virtual bool OpenTableFile(PGLOBAL g); + virtual bool DeferReading(void) {return false;} + virtual int ReadBuffer(PGLOBAL g); + virtual int WriteBuffer(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); + virtual void Rewind(void); + + protected: + bool MakeDeletedFile(PGLOBAL g); + + // Members + char *Memory; // Pointer on file mapping view. + char *Mempos; // Position of next data to read + char *Fpos; // Position of last read record + char *Tpos; // Target Position for delete move + char *Spos; // Start position for delete move + char *Top; // Mark end of file mapping view + }; // end of class MAPFAM + +/***********************************************************************/ +/* This is the blocked file access method using file mapping. */ +/***********************************************************************/ +class DllExport MBKFAM : public MAPFAM { + public: + // Constructor + MBKFAM(PDOSDEF tdp); + MBKFAM(PMAPFAM tmfp) : MAPFAM(tmfp) {} + + // Implementation + virtual PTXF Duplicate(PGLOBAL g) + {return (PTXF)new(g) MBKFAM(this);} + + // Methods + virtual void Reset(void); + virtual int Cardinality(PGLOBAL g); + virtual int MaxBlkSize(PGLOBAL g, int s) + {return TXTFAM::MaxBlkSize(g, s);} + virtual int GetRowID(void); + virtual int SkipRecord(PGLOBAL g, bool header); + virtual int ReadBuffer(PGLOBAL g); + virtual void Rewind(void); + + protected: + // No additional members + }; // end of class MBKFAM + +/***********************************************************************/ +/* This is the fixed file access method using file mapping. */ +/***********************************************************************/ +class DllExport MPXFAM : public MBKFAM { + public: + // Constructor + MPXFAM(PDOSDEF tdp); + MPXFAM(PMAPFAM tmfp) : MBKFAM(tmfp) {} + + // Implementation + virtual int GetPos(void); + virtual PTXF Duplicate(PGLOBAL g) + {return (PTXF)new(g) MPXFAM(this);} + + // Methods + virtual int Cardinality(PGLOBAL g) {return TXTFAM::Cardinality(g);} + virtual int MaxBlkSize(PGLOBAL g, int s) + {return TXTFAM::MaxBlkSize(g, s);} + virtual bool SetPos(PGLOBAL g, int recpos); + virtual bool DeferReading(void) {return false;} + virtual int ReadBuffer(PGLOBAL g); + virtual int WriteBuffer(PGLOBAL g); + + protected: + // No additional members + }; // end of class MPXFAM + +#endif // __FILAMAP_H diff --git a/storage/connect/filamdbf.cpp b/storage/connect/filamdbf.cpp index e840800a117..5d01ee06df0 100644 --- a/storage/connect/filamdbf.cpp +++ b/storage/connect/filamdbf.cpp @@ -1,11 +1,11 @@ /*********** File AM Dbf C++ Program Source Code File (.CPP) ****************/ /* PROGRAM NAME: FILAMDBF */ /* ------------- */ -/* Version 1.6 */ +/* Version 1.7 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -668,12 +668,9 @@ void DBFFAM::ResetBuffer(PGLOBAL g) /*********************************************************************/ /* If access is random, performances can be much better when the */ /* reads are done on only one row, except for small tables that can */ - /* be entirely read in one block. If the index is just used as a */ - /* bitmap filter, as for Update or delete, reading will be */ - /* sequential and we better keep block reading. */ + /* be entirely read in one block. */ /*********************************************************************/ - if (Tdbp->GetKindex() && Tdbp->GetMode() == MODE_READ && - ReadBlks != 1) { + if (Tdbp->GetKindex() && ReadBlks != 1) { Nrec = 1; // Better for random access Rbuf = 0; Blksize = Lrecl; @@ -763,12 +760,16 @@ int DBFFAM::DeleteRecords(PGLOBAL g, int irc) // T_Stream is the temporary stream or the table file stream itself if (!T_Stream) if (UseTemp) { - if (OpenTempFile(g)) + if ((Indxd = Tdbp->GetKindex() != NULL)) { + strcpy(g->Message, "DBF indexed udate using temp file NIY"); + return RC_FX; + } else if (OpenTempFile(g)) return RC_FX; if (CopyHeader(g)) // For DBF tables return RC_FX; +// Indxd = Tdbp->GetKindex() != NULL; } else T_Stream = Stream; @@ -796,6 +797,8 @@ void DBFFAM::CloseTableFile(PGLOBAL g, bool abort) int rc = RC_OK, wrc = RC_OK; MODE mode = Tdbp->GetMode(); + Abort = abort; + // Closing is True if last Write was in error if (mode == MODE_INSERT && CurNum && !Closing) { // Some more inserted lines remain to be written @@ -810,16 +813,16 @@ void DBFFAM::CloseTableFile(PGLOBAL g, bool abort) } // endif Modif if (UseTemp && T_Stream && wrc == RC_OK) { - if (!abort) { + if (!Abort) { // Copy any remaining lines bool b; Fpos = Tdbp->Cardinality(g); - abort = MoveIntermediateLines(g, &b) != RC_OK; - } // endif abort + Abort = MoveIntermediateLines(g, &b) != RC_OK; + } // endif Abort // Delete the old file and rename the new temp file. - RenameTempFile(g, abort); + RenameTempFile(g); goto fin; } // endif UseTemp diff --git a/storage/connect/filamfix.cpp b/storage/connect/filamfix.cpp index e37dff3b90e..98e6520b8e0 100644 --- a/storage/connect/filamfix.cpp +++ b/storage/connect/filamfix.cpp @@ -1,7 +1,7 @@ /*********** File AM Fix C++ Program Source Code File (.CPP) ***********/ /* PROGRAM NAME: FILAMFIX */ /* ------------- */ -/* Version 1.5 */ +/* Version 1.6 */ /* */ /* COPYRIGHT: */ /* ---------- */ @@ -55,6 +55,11 @@ extern "C" int trace; extern int num_read, num_there, num_eq[2]; // Statistics +/***********************************************************************/ +/* Routine called externally by BGXFAM MakeDeletedFile function. */ +/***********************************************************************/ +PARRAY MakeValueArray(PGLOBAL g, PPARM pp); + /* --------------------------- Class FIXFAM -------------------------- */ /***********************************************************************/ @@ -80,6 +85,27 @@ FIXFAM::FIXFAM(PFIXFAM txfp) : BLKFAM(txfp) } // end of FIXFAM copy constructor /***********************************************************************/ +/* SetPos: Replace the table at the specified position. */ +/***********************************************************************/ +bool FIXFAM::SetPos(PGLOBAL g, int pos) + { + if (pos < 0) { + strcpy(g->Message, MSG(INV_REC_POS)); + return true; + } // endif recpos + + CurBlk = pos / Nrec; + CurNum = pos % Nrec; +#if defined(_DEBUG) + num_eq[(CurBlk == OldBlk) ? 1 : 0]++; +#endif + + // Indicate the table position was externally set + Placed = true; + return false; + } // end of SetPos + +/***********************************************************************/ /* Allocate the block buffer for the table. */ /***********************************************************************/ bool FIXFAM::AllocateBuffer(PGLOBAL g) @@ -128,12 +154,9 @@ void FIXFAM::ResetBuffer(PGLOBAL g) /*********************************************************************/ /* If access is random, performances can be much better when the */ /* reads are done on only one row, except for small tables that can */ - /* be entirely read in one block. If the index is just used as a */ - /* bitmap filter as for Update or Delete reading will be sequential */ - /* and we better keep block reading. */ + /* be entirely read in one block. */ /*********************************************************************/ - if (Tdbp->GetMode() == MODE_READ && ReadBlks != 1 && !Padded && - Tdbp->GetKindex() /*&& Tdbp->GetKindex()->IsRandom()*/) { + if (Tdbp->GetKindex() && ReadBlks != 1 && !Padded) { Nrec = 1; // Better for random access Rbuf = 0; Blksize = Lrecl; @@ -316,13 +339,16 @@ int FIXFAM::WriteBuffer(PGLOBAL g) } else { // Mode == MODE_UPDATE // T_Stream is the temporary stream or the table file stream itself if (!T_Stream) { - if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) { - if (OpenTempFile(g)) + if (UseTemp) { + if ((Indxd = Tdbp->GetKindex() != NULL)) { + strcpy(g->Message, "FIX indexed udate using temp file NIY"); return RC_FX; - - if (CopyHeader(g)) // For DBF tables + } else if (OpenTempFile(g)) + return RC_FX; + else if (CopyHeader(g)) // For DBF tables return RC_FX; +// Indxd = Tdbp->GetKindex() != NULL; } else T_Stream = Stream; @@ -387,12 +413,17 @@ int FIXFAM::DeleteRecords(PGLOBAL g, int irc) Spos = Tpos = Fpos; } // endif UseTemp + Indxd = Tdbp->GetKindex() != NULL; } // endif Tpos == Spos /*********************************************************************/ /* Move any intermediate lines. */ /*********************************************************************/ - if (MoveIntermediateLines(g, &moved)) + if (Indxd) { + // Moving will be done later, must be done in sequential order + (void)AddListValue(g, TYPE_INT, &Fpos, &To_Pos); + moved = false; + } else if (MoveIntermediateLines(g, &moved)) return RC_FX; if (irc == RC_OK) { @@ -421,10 +452,13 @@ int FIXFAM::DeleteRecords(PGLOBAL g, int irc) /*****************************************************************/ /* Ok, now delete old file and rename new temp file. */ /*****************************************************************/ - if (RenameTempFile(g, false)) + if (RenameTempFile(g)) return RC_FX; } else { + if (Indxd && (Abort = MakeDeletedFile(g))) + return RC_FX; + /*****************************************************************/ /* Because the chsize functionality is only accessible with a */ /* system call we must close the file and reopen it with the */ @@ -526,6 +560,59 @@ bool FIXFAM::MoveIntermediateLines(PGLOBAL g, bool *b) } // end of MoveIntermediate Lines /***********************************************************************/ +/* MakeDeletedFile. When deleting using indexing, the issue is that */ +/* record are not necessarily deleted in sequential order. Moving */ +/* intermediate lines cannot be done while deleing them because */ +/* this can cause extra wrong records to be included in the new file. */ +/* What we do here is to reorder the deleted record and make the new */ +/* deleted file from the ordered deleted records. */ +/***********************************************************************/ +bool FIXFAM::MakeDeletedFile(PGLOBAL g) + { + char *crlf = "\n", *mode = UseTemp ? "rb" : "r+b"; + int *ix, i; + bool moved; + + /*********************************************************************/ + /* Open the temporary file, Spos is at the beginning of file. */ + /*********************************************************************/ + if (!(Posar = MakeValueArray(g, To_Pos))) { + strcpy(g->Message, "Position array is null"); + goto err; + } else if (!(ix = (int*)Posar->GetSortIndex(g))) { + strcpy(g->Message, "Error getting array sort index"); + goto err; + } // endif's + + Spos = 0; + + for (i = 0; i < Posar->GetNval(); i++) { + Fpos = Posar->GetIntValue(ix[i]); + + if (i || UseTemp) { + // Copy all not updated lines preceding this one + if (MoveIntermediateLines(g, &moved)) + goto err; + + } else + Tpos = Fpos; + + // New start position + Spos = Fpos + 1; + } // endfor i + + if (!PlugCloseFile(g, To_Fbt) && !PlugCloseFile(g, To_Fb)) + return false; + +err: + if (trace) + htrc("%s\n", g->Message); + + PlugCloseFile(g, To_Fbt); + return true; + } // end of MakeDeletedFile + +/***********************************************************************/ /* Table file close routine for FIX access method. */ /***********************************************************************/ void FIXFAM::CloseTableFile(PGLOBAL g, bool abort) @@ -533,6 +620,8 @@ void FIXFAM::CloseTableFile(PGLOBAL g, bool abort) int rc = RC_OK, wrc = RC_OK; MODE mode = Tdbp->GetMode(); + Abort = abort; + // Closing is True if last Write was in error if (mode == MODE_INSERT && CurNum && !Closing) { // Some more inserted lines remain to be written @@ -547,16 +636,17 @@ void FIXFAM::CloseTableFile(PGLOBAL g, bool abort) } // endif Modif if (UseTemp && T_Stream && wrc == RC_OK) { - if (!abort) { + if (!Abort) { // Copy any remaining lines bool b; + // Note: Indxd is not implemented yet Fpos = Tdbp->Cardinality(g); - abort = MoveIntermediateLines(g, &b) != RC_OK; - } // endif // abort + Abort = MoveIntermediateLines(g, &b) != RC_OK; + } // endif Abort // Delete the old file and rename the new temp file. - RenameTempFile(g, abort); + RenameTempFile(g); goto fin; } // endif UseTemp @@ -1143,7 +1233,10 @@ int BGXFAM::WriteBuffer(PGLOBAL g) if (Tfile == INVALID_HANDLE_VALUE) { if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) { - if (OpenTempFile(g)) + if ((Indxd = Tdbp->GetKindex() != NULL)) { + strcpy(g->Message, "FIX indexed udate using temp file NIY"); + return RC_FX; + } else if (OpenTempFile(g)) return RC_FX; } else @@ -1210,15 +1303,19 @@ int BGXFAM::DeleteRecords(PGLOBAL g, int irc) Spos = Tpos = Fpos; } // endif UseTemp + Indxd = Tdbp->GetKindex() != NULL; } // endif Tpos == Spos /*********************************************************************/ /* Move any intermediate lines. */ /*********************************************************************/ - if (MoveIntermediateLines(g, &moved)) + if (Indxd) + // Moving will be done later, must be done in sequential order + (void)AddListValue(g, TYPE_INT, &Fpos, &To_Pos); + else if (MoveIntermediateLines(g, &moved)) return RC_FX; - if (irc == RC_OK) { + if (irc == RC_OK && !Indxd) { if (trace) assert(Spos == Fpos); @@ -1234,22 +1331,21 @@ int BGXFAM::DeleteRecords(PGLOBAL g, int irc) if (trace > 1) htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos); - } else { + } else if (irc != RC_OK) { /*******************************************************************/ /* Last call after EOF has been reached. */ /*******************************************************************/ - char filename[_MAX_PATH]; - - PlugSetPath(filename, To_File, Tdbp->GetPath()); - if (UseTemp) { /*****************************************************************/ /* Ok, now delete old file and rename new temp file. */ /*****************************************************************/ - if (RenameTempFile(g, false)) + if (RenameTempFile(g)) return RC_FX; } else { + if (Indxd && (Abort = MakeDeletedFile(g))) + return RC_FX; + /*****************************************************************/ /* Remove extra records. */ /*****************************************************************/ @@ -1374,6 +1470,59 @@ bool BGXFAM::MoveIntermediateLines(PGLOBAL g, bool *b) } // end of MoveIntermediateLines /***********************************************************************/ +/* MakeDeletedFile. When deleting using indexing, the issue is that */ +/* record are not necessarily deleted in sequential order. Moving */ +/* intermediate lines cannot be done while deleing them because */ +/* this can cause extra wrong records to be included in the new file. */ +/* What we do here is to reorder the deleted record and make the new */ +/* deleted file from the ordered deleted records. */ +/***********************************************************************/ +bool BGXFAM::MakeDeletedFile(PGLOBAL g) + { + char *crlf = "\n", *mode = UseTemp ? "rb" : "r+b"; + int *ix, i; + bool moved; + + /*********************************************************************/ + /* Open the temporary file, Spos is at the beginning of file. */ + /*********************************************************************/ + if (!(Posar = MakeValueArray(g, To_Pos))) { + strcpy(g->Message, "Position array is null"); + goto err; + } else if (!(ix = (int*)Posar->GetSortIndex(g))) { + strcpy(g->Message, "Error getting array sort index"); + goto err; + } // endif's + + Spos = 0; + + for (i = 0; i < Posar->GetNval(); i++) { + Fpos = Posar->GetIntValue(ix[i]); + + if (i || UseTemp) { + // Copy all not updated lines preceding this one + if (MoveIntermediateLines(g, &moved)) + goto err; + + } else + Tpos = Fpos; + + // New start position + Spos = Fpos + 1; + } // endfor i + + if (!PlugCloseFile(g, To_Fbt)) + return false; + +err: + if (trace) + htrc("%s\n", g->Message); + + PlugCloseFile(g, To_Fbt); + return true; + } // end of MakeDeletedFile + +/***********************************************************************/ /* Data Base close routine for BIGFIX access method. */ /***********************************************************************/ void BGXFAM::CloseTableFile(PGLOBAL g, bool abort) @@ -1381,6 +1530,8 @@ void BGXFAM::CloseTableFile(PGLOBAL g, bool abort) int rc = RC_OK, wrc = RC_OK; MODE mode = Tdbp->GetMode(); + Abort = abort; + // Closing is True if last Write was in error if (mode == MODE_INSERT && CurNum && !Closing) { // Some more inserted lines remain to be written @@ -1394,16 +1545,17 @@ void BGXFAM::CloseTableFile(PGLOBAL g, bool abort) } // endif Modif if (UseTemp && Tfile && wrc == RC_OK) { - if (!abort) { + if (!Abort) { // Copy any remaining lines bool b; + // Indxd is not implemented yet Fpos = Tdbp->Cardinality(g); - abort = MoveIntermediateLines(g, &b) != RC_OK; - } // endif abort + Abort = MoveIntermediateLines(g, &b) != RC_OK; + } // endif Abort // Delete the old file and rename the new temp file. - RenameTempFile(g, abort); + RenameTempFile(g); goto fin; } // endif UseTemp diff --git a/storage/connect/filamfix.h b/storage/connect/filamfix.h index 22f84552320..a29bfbbeb48 100644 --- a/storage/connect/filamfix.h +++ b/storage/connect/filamfix.h @@ -1,88 +1,91 @@ -/************** FilAMFix H Declares Source Code File (.H) **************/
-/* Name: FILAMFIX.H Version 1.3 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 2005 - 2014 */
-/* */
-/* This file contains the FIX file access method classes declares. */
-/***********************************************************************/
-
-#ifndef __FILAMFIX_H
-#define __FILAMFIX_H
-
-#include "filamtxt.h"
-
-typedef class FIXFAM *PFIXFAM;
-typedef class BGXFAM *PBGXFAM;
-
-/***********************************************************************/
-/* This is the DOS/UNIX Access Method class declaration for standard */
-/* files with fixed record format (FIX, BIN) */
-/***********************************************************************/
-class DllExport FIXFAM : public BLKFAM {
- public:
- // Constructor
- FIXFAM(PDOSDEF tdp);
- FIXFAM(PFIXFAM txfp);
-
- // Implementation
- virtual AMT GetAmType(void) {return TYPE_AM_FIX;}
- virtual PTXF Duplicate(PGLOBAL g)
- {return (PTXF)new(g) FIXFAM(this);}
-
- // Methods
- 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, bool abort);
-
- protected:
- virtual bool CopyHeader(PGLOBAL g) {return false;}
- virtual bool MoveIntermediateLines(PGLOBAL g, bool *b);
-
- // No additional members
- }; // end of class FIXFAM
-
-
-/***********************************************************************/
-/* This is the DOS/UNIX Access Method class declaration for files */
-/* that are standard files with columns starting at fixed offset */
-/* This class is for fixed formatted files of more than 2 gigabytes. */
-/***********************************************************************/
-class BGXFAM : public FIXFAM {
- public:
- // Constructor
- BGXFAM(PDOSDEF tdp);
- BGXFAM(PBGXFAM txfp);
-
- // Implementation
- virtual PTXF Duplicate(PGLOBAL g)
- {return (PTXF)new(g) BGXFAM(this);}
-
- // Methods
- virtual int Cardinality(PGLOBAL g);
- virtual bool OpenTableFile(PGLOBAL g);
- virtual int ReadBuffer(PGLOBAL g);
- virtual int WriteBuffer(PGLOBAL g);
- virtual int DeleteRecords(PGLOBAL g, int irc);
- virtual void CloseTableFile(PGLOBAL g, bool abort);
- virtual void Rewind(void);
-
- protected:
- bool BigSeek(PGLOBAL g, HANDLE h, BIGINT pos
- , 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 MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
-
- // Members
- HANDLE Hfile; // Handle(descriptor) to big file
- HANDLE Tfile; // Handle(descriptor) to big temp file
- }; // end of class BGXFAM
-
-#endif // __FILAMFIX_H
+/************** FilAMFix H Declares Source Code File (.H) **************/ +/* Name: FILAMFIX.H Version 1.3 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2005 - 2014 */ +/* */ +/* This file contains the FIX file access method classes declares. */ +/***********************************************************************/ + +#ifndef __FILAMFIX_H +#define __FILAMFIX_H + +#include "filamtxt.h" + +typedef class FIXFAM *PFIXFAM; +typedef class BGXFAM *PBGXFAM; + +/***********************************************************************/ +/* This is the DOS/UNIX Access Method class declaration for standard */ +/* files with fixed record format (FIX, BIN) */ +/***********************************************************************/ +class DllExport FIXFAM : public BLKFAM { + public: + // Constructor + FIXFAM(PDOSDEF tdp); + FIXFAM(PFIXFAM txfp); + + // Implementation + virtual AMT GetAmType(void) {return TYPE_AM_FIX;} + virtual PTXF Duplicate(PGLOBAL g) + {return (PTXF)new(g) FIXFAM(this);} + + // Methods + virtual int Cardinality(PGLOBAL g) {return TXTFAM::Cardinality(g);} + virtual int MaxBlkSize(PGLOBAL g, int s) + {return TXTFAM::MaxBlkSize(g, s);} + virtual bool SetPos(PGLOBAL g, int recpos); + 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, bool abort); + + protected: + virtual bool CopyHeader(PGLOBAL g) {return false;} + virtual bool MoveIntermediateLines(PGLOBAL g, bool *b); + virtual bool MakeDeletedFile(PGLOBAL g); + + // No additional members + }; // end of class FIXFAM + + +/***********************************************************************/ +/* This is the DOS/UNIX Access Method class declaration for files */ +/* that are standard files with columns starting at fixed offset */ +/* This class is for fixed formatted files of more than 2 gigabytes. */ +/***********************************************************************/ +class BGXFAM : public FIXFAM { + public: + // Constructor + BGXFAM(PDOSDEF tdp); + BGXFAM(PBGXFAM txfp); + + // Implementation + virtual PTXF Duplicate(PGLOBAL g) + {return (PTXF)new(g) BGXFAM(this);} + + // Methods + virtual int Cardinality(PGLOBAL g); + virtual bool OpenTableFile(PGLOBAL g); + virtual int ReadBuffer(PGLOBAL g); + virtual int WriteBuffer(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); + virtual void Rewind(void); + + protected: + virtual bool OpenTempFile(PGLOBAL g); + virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL); + virtual bool MakeDeletedFile(PGLOBAL g); + int BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req); + bool BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req); + bool BigSeek(PGLOBAL g, HANDLE h, BIGINT pos + , int org = FILE_BEGIN); + + // Members + HANDLE Hfile; // Handle(descriptor) to big file + HANDLE Tfile; // Handle(descriptor) to big temp file + }; // end of class BGXFAM + +#endif // __FILAMFIX_H diff --git a/storage/connect/filamtxt.cpp b/storage/connect/filamtxt.cpp index 0812fa935fb..9687a52b8ef 100644 --- a/storage/connect/filamtxt.cpp +++ b/storage/connect/filamtxt.cpp @@ -1,7 +1,7 @@ /*********** File AM Txt C++ Program Source Code File (.CPP) ***********/ /* PROGRAM NAME: FILAMTXT */ /* ------------- */ -/* Version 1.5 */ +/* Version 1.6 */ /* */ /* COPYRIGHT: */ /* ---------- */ @@ -58,6 +58,11 @@ extern int num_read, num_there, num_eq[2]; // Statistics extern "C" int trace; +/***********************************************************************/ +/* Routine called externally by DOSFAM MakeUpdatedFile function. */ +/***********************************************************************/ +PARRAY MakeValueArray(PGLOBAL g, PPARM pp); + /* --------------------------- Class TXTFAM -------------------------- */ /***********************************************************************/ @@ -75,6 +80,12 @@ TXTFAM::TXTFAM(PDOSDEF tdp) To_Buf = NULL; DelBuf = NULL; BlkPos = NULL; + To_Pos = NULL; + To_Sos = NULL; + To_Upd = NULL; + Posar = NULL; + Sosar = NULL; + Updar = NULL; BlkLen = 0; Buflen = 0; Dbflen = 0; @@ -94,7 +105,9 @@ TXTFAM::TXTFAM(PDOSDEF tdp) Padded = false; Eof = tdp->Eof; Ending = tdp->Ending; - CrLf = (char*)(Ending == 2 ? "\r\n" : "\n"); + Indxd = false; + Abort = false; + CrLf = (char*)(Ending == 1 ? "\n" : "\r\n"); } // end of TXTFAM standard constructor TXTFAM::TXTFAM(PTXF txfp) @@ -109,6 +122,12 @@ TXTFAM::TXTFAM(PTXF txfp) To_Buf = txfp->To_Buf; DelBuf = txfp->DelBuf; BlkPos = txfp->BlkPos; + To_Pos = txfp->To_Pos; + To_Sos = txfp->To_Sos; + To_Upd = txfp->To_Upd; + Posar = txfp->Posar; + Sosar = txfp->Sosar; + Updar = txfp->Updar; BlkLen = txfp->BlkLen; Buflen = txfp->Buflen; Dbflen = txfp->Dbflen; @@ -128,6 +147,9 @@ TXTFAM::TXTFAM(PTXF txfp) Padded = txfp->Padded; Eof = txfp->Eof; Ending = txfp->Ending; + Indxd = txfp->Indxd; + Abort = txfp->Abort; + CrLf = txfp->CrLf; } // end of TXTFAM copy constructor /***********************************************************************/ @@ -151,9 +173,9 @@ void TXTFAM::Reset(void) /***********************************************************************/ int TXTFAM::GetFileLength(PGLOBAL g) { - char filename[_MAX_PATH]; - int h; - int len; + char filename[_MAX_PATH]; + int h; + int len; PlugSetPath(filename, To_File, Tdbp->GetPath()); h= global_open(g, MSGID_OPEN_MODE_STRERROR, filename, _O_RDONLY); @@ -165,13 +187,13 @@ int TXTFAM::GetFileLength(PGLOBAL g) if (errno != ENOENT) { if (trace) htrc("%s\n", g->Message); + len = -1; - } - else - { + } else { len = 0; // File does not exist yet g->Message[0]= '\0'; - } + } // endif errno + } else { if ((len = _filelength(h)) < 0) sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", filename); @@ -250,6 +272,36 @@ int TXTFAM::MaxBlkSize(PGLOBAL g, int s) return size; } // end of MaxBlkSize +/***********************************************************************/ +/* AddListValue: Used when doing indexed update or delete. */ +/***********************************************************************/ +bool TXTFAM::AddListValue(PGLOBAL g, int type, void *val, PPARM *top) + { + PPARM pp = (PPARM)PlugSubAlloc(g, NULL, sizeof(PARM)); + + switch (type) { + case TYPE_INT: + pp->Value = PlugSubAlloc(g, NULL, sizeof(int)); + *((int*)pp->Value) = *((int*)val); + break; + case TYPE_STRING: + pp->Value = PlugSubAlloc(g, NULL, strlen((char*)val) + 1); + strcpy((char*)pp->Value, (char*)val); + break; + case TYPE_PCHAR: + pp->Value = val; + break; + default: + return true; + } // endswitch type + + pp->Type = type; + pp->Domain = 0; + pp->Next = *top; + *top = pp; + return false; + } // end of AddListValue + /* --------------------------- Class DOSFAM -------------------------- */ /***********************************************************************/ @@ -277,6 +329,17 @@ DOSFAM::DOSFAM(PDOSFAM tdfp) : TXTFAM(tdfp) Bin = tdfp->Bin; } // end of DOSFAM copy constructor +DOSFAM::DOSFAM(PBLKFAM tdfp, PDOSDEF tdp) : TXTFAM(tdp) + { + Tdbp = tdfp->Tdbp; + To_Fb = tdfp->To_Fb; + To_Fbt = tdfp->To_Fbt; + Stream = tdfp->Stream; + T_Stream = tdfp->T_Stream; + UseTemp = tdfp->UseTemp; + Bin = tdfp->Bin; + } // end of DOSFAM constructor from BLKFAM + /***********************************************************************/ /* Reset: reset position values at the beginning of file. */ /***********************************************************************/ @@ -335,8 +398,8 @@ bool DOSFAM::OpenTableFile(PGLOBAL g) MODE mode = Tdbp->Mode; PDBUSER dbuserp = PlgGetUser(g); - // This is required when using Unix files under Windows - Bin = (Ending == 1); + // This is required when using Unix files under Windows and vice versa + Bin = (Ending != CRLF); switch (mode) { case MODE_READ: @@ -641,19 +704,21 @@ int DOSFAM::ReadBuffer(PGLOBAL g) /***********************************************************************/ int DOSFAM::WriteBuffer(PGLOBAL g) { - char *crlf = "\n"; - int curpos = 0; + int curpos = 0; bool moved = true; // T_Stream is the temporary stream or the table file stream itself - if (!T_Stream) + if (!T_Stream) { if (UseTemp && Tdbp->Mode == MODE_UPDATE) { if (OpenTempFile(g)) return RC_FX; + Indxd = Tdbp->To_Kindex != NULL; } else T_Stream = Stream; + } // endif T_Stream + if (Tdbp->Mode == MODE_UPDATE) { /*******************************************************************/ /* Here we simply rewrite a record on itself. There are two cases */ @@ -669,14 +734,21 @@ int DOSFAM::WriteBuffer(PGLOBAL g) if (UseTemp) { /*****************************************************************/ - /* We are using a temporary file. Before writing the updated */ - /* record, we must eventually copy all the intermediate records */ - /* that have not been updated. */ + /* We are using a temporary file. */ /*****************************************************************/ - if (MoveIntermediateLines(g, &moved)) - return RC_FX; + if (Indxd) { + // Copying will be done later, must be done in sequential order + (void)AddListValue(g, TYPE_INT, &Fpos, &To_Pos); + (void)AddListValue(g, TYPE_INT, &curpos, &To_Sos); + } else { + // Before writing the updated record, we must eventually copy + // all the intermediate records that have not been updated. + if (MoveIntermediateLines(g, &moved)) + return RC_FX; + + Spos = curpos; // New start position + } // endif Indxd - Spos = curpos; // New start position } else // Update is directly written back into the file, // with this (fast) method, record size cannot change. @@ -688,30 +760,30 @@ int DOSFAM::WriteBuffer(PGLOBAL g) } // endif mode /*********************************************************************/ - /* Prepare the write buffer. */ - /*********************************************************************/ -#if defined(WIN32) - if (Bin) - crlf = "\r\n"; -#endif // WIN32 - strcat(strcpy(To_Buf, Tdbp->To_Line), crlf); - - /*********************************************************************/ - /* Now start the writing process. */ + /* Prepare the write the updated line. */ /*********************************************************************/ - if ((fputs(To_Buf, T_Stream)) == EOF) { - sprintf(g->Message, MSG(FPUTS_ERROR), strerror(errno)); - return RC_FX; - } // endif EOF + if (!Indxd) { + strcat(strcpy(To_Buf, Tdbp->To_Line), (Bin) ? CrLf : "\n"); - if (Tdbp->Mode == MODE_UPDATE && moved) - if (fseek(Stream, curpos, SEEK_SET)) { - sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno)); + /*******************************************************************/ + /* Now start the writing process. */ + /*******************************************************************/ + if ((fputs(To_Buf, T_Stream)) == EOF) { + sprintf(g->Message, MSG(FPUTS_ERROR), strerror(errno)); return RC_FX; - } // endif + } // endif EOF - if (trace) - htrc("write done\n"); + if (Tdbp->Mode == MODE_UPDATE && moved) + if (fseek(Stream, curpos, SEEK_SET)) { + sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno)); + return RC_FX; + } // endif + + if (trace) + htrc("write done\n"); + + } else // Add this updated line to the updated line list + (void)AddListValue(g, TYPE_STRING, Tdbp->To_Line, &To_Upd); return RC_OK; } // end of WriteBuffer @@ -722,7 +794,7 @@ int DOSFAM::WriteBuffer(PGLOBAL g) int DOSFAM::DeleteRecords(PGLOBAL g, int irc) { bool moved; - int curpos = ftell(Stream); + int curpos = ftell(Stream); /*********************************************************************/ /* There is an alternative here: */ @@ -731,8 +803,7 @@ int DOSFAM::DeleteRecords(PGLOBAL g, int irc) /* the temporary file renamed to the original file name. */ /* 2 - directly move the not deleted lines inside the original */ /* file, and at the end erase all trailing records. */ - /* This will be experimented, but method 1 must be used for Unix as */ - /* the function needed to erase trailing records is not available. */ + /* This will be experimented. */ /*********************************************************************/ if (trace) htrc( @@ -769,12 +840,18 @@ int DOSFAM::DeleteRecords(PGLOBAL g, int irc) Spos = Tpos = Fpos; } // endif UseTemp + Indxd = Tdbp->To_Kindex != NULL; } // endif Tpos == Spos /*********************************************************************/ /* Move any intermediate lines. */ /*********************************************************************/ - if (MoveIntermediateLines(g, &moved)) + if (Indxd) { + // Moving will be done later, must be done in sequential order + (void)AddListValue(g, TYPE_INT, &Fpos, &To_Pos); + (void)AddListValue(g, TYPE_INT, &curpos, &To_Sos); + moved = false; + } else if (MoveIntermediateLines(g, &moved)) return RC_FX; if (irc == RC_OK) { @@ -797,7 +874,10 @@ int DOSFAM::DeleteRecords(PGLOBAL g, int irc) /* Last call after EOF has been reached. */ /* The UseTemp case is treated in CloseTableFile. */ /*******************************************************************/ - if (!UseTemp) { + if (Indxd) + Abort = MakeDeletedFile(g); + + if (!UseTemp & !Abort) { /*****************************************************************/ /* Because the chsize functionality is only accessible with a */ /* system call we must close the file and reopen it with the */ @@ -921,10 +1001,141 @@ bool DOSFAM::MoveIntermediateLines(PGLOBAL g, bool *b) } // end of MoveIntermediate Lines /***********************************************************************/ +/* MakeUpdatedFile. When updating using indexing, the issue is that */ +/* record are not necessarily updated in sequential order. */ +/* Moving intermediate lines cannot be done while making them because */ +/* this can cause extra wrong records to be included in the new file. */ +/* What we do here is to reorder the updated record and make the new */ +/* updated file from the ordered updated records. */ +/***********************************************************************/ +bool DOSFAM::MakeUpdatedFile(PGLOBAL g) + { + char *crlf = "\n", *mode = UseTemp ? "rb" : "r+b"; + int *ix, i; + bool moved, b = false; + + /*********************************************************************/ + /* Open the temporary file, Spos is at the beginning of file. */ + /*********************************************************************/ + if (!(Stream = PlugReopenFile(g, To_Fb, mode))) { + goto err; + } else if (!(Posar = MakeValueArray(g, To_Pos))) { + strcpy(g->Message, "Position array is null"); + goto err; + } else if (!(Sosar = MakeValueArray(g, To_Sos))) { + strcpy(g->Message, "Start position array is null"); + goto err; + } else if (!(Updar = MakeValueArray(g, To_Upd))) { + strcpy(g->Message, "Updated line array is null"); + goto err; + } else if (!(ix = (int*)Posar->GetSortIndex(g))) { + strcpy(g->Message, "Error getting array sort index"); + goto err; + } // endif's + + Spos = 0; + + for (i = 0; i < Posar->GetNval(); i++) { + Fpos = Posar->GetIntValue(ix[i]); + + if (i || UseTemp) { + // Copy all not updated lines preceding this one + if (MoveIntermediateLines(g, &moved)) + goto err; + + } else + Tpos = Fpos; + + // Now write the updated line. + strcat(strcpy(To_Buf, Updar->GetStringValue(ix[i])), CrLf); + + if ((fputs(To_Buf, T_Stream)) == EOF) { + sprintf(g->Message, MSG(FPUTS_ERROR), strerror(errno)); + goto err; + } // endif EOF + + // New start position + Spos = Sosar->GetIntValue(ix[i]); + } // endfor i + + // Copy eventually remaining lines + fseek(Stream, 0, SEEK_END); + Fpos = ftell(Stream); + b = MoveIntermediateLines(g, &moved) != RC_OK; + + if (!PlugCloseFile(g, To_Fbt) && !PlugCloseFile(g, To_Fb) && !b) + return false; + +err: + if (trace) + htrc("%s\n", g->Message); + + PlugCloseFile(g, To_Fbt); + return true; + } // end of MakeUpdatedFile + +/***********************************************************************/ +/* MakeDeletedFile. When deleting using indexing, the issue is that */ +/* record are not necessarily deleted in sequential order. Moving */ +/* intermediate lines cannot be done while deleing them because */ +/* this can cause extra wrong records to be included in the new file. */ +/* What we do here is to reorder the deleted record and make the new */ +/* deleted file from the ordered deleted records. */ +/***********************************************************************/ +bool DOSFAM::MakeDeletedFile(PGLOBAL g) + { + char *crlf = "\n", *mode = UseTemp ? "rb" : "r+b"; + int *ix, i; + bool moved; + + /*********************************************************************/ + /* Open the temporary file, Spos is at the beginning of file. */ + /*********************************************************************/ + if (!(Posar = MakeValueArray(g, To_Pos))) { + strcpy(g->Message, "Position array is null"); + goto err; + } else if (!(Sosar = MakeValueArray(g, To_Sos))) { + strcpy(g->Message, "Start position array is null"); + goto err; + } else if (!(ix = (int*)Posar->GetSortIndex(g))) { + strcpy(g->Message, "Error getting array sort index"); + goto err; + } // endif's + + Spos = 0; + + for (i = 0; i < Posar->GetNval(); i++) { + Fpos = Posar->GetIntValue(ix[i]); + + if (i || UseTemp) { + // Copy all not updated lines preceding this one + if (MoveIntermediateLines(g, &moved)) + goto err; + + } else + Tpos = Fpos; + + // New start position + Spos = Sosar->GetIntValue(ix[i]); + } // endfor i + + if (!PlugCloseFile(g, To_Fbt) && !PlugCloseFile(g, To_Fb)) + return false; + +err: + if (trace) + htrc("%s\n", g->Message); + + PlugCloseFile(g, To_Fbt); + return true; + } // end of MakeDeletedFile + +/***********************************************************************/ /* Delete the old file and rename the new temp file. */ /* If aborting just delete the new temp file. */ +/* If indexed, make the temp file from the arrays. */ /***********************************************************************/ -int DOSFAM::RenameTempFile(PGLOBAL g, bool abort) +int DOSFAM::RenameTempFile(PGLOBAL g) { char *tempname, filetemp[_MAX_PATH], filename[_MAX_PATH]; int rc = RC_OK; @@ -937,10 +1148,22 @@ int DOSFAM::RenameTempFile(PGLOBAL g, bool abort) // This loop is necessary because, in case of join, // To_File can have been open several times. for (PFBLOCK fb = PlgGetUser(g)->Openlist; fb; fb = fb->Next) - if (fb == To_Fb || fb == To_Fbt) + if (fb == To_Fb || (fb == To_Fbt && !Indxd)) rc = PlugCloseFile(g, fb); + + if (!Abort) { + // If indexed the temp file must be made + if (Indxd) { + Abort = (Tdbp->Mode == MODE_UPDATE) ? MakeUpdatedFile(g) + : MakeDeletedFile(g); + + if (Abort) { + remove(tempname); + return RC_FX; + } // endif Abort + + } // endif Indxd - if (!abort) { PlugSetPath(filename, To_File, Tdbp->GetPath()); strcat(PlugRemoveType(filetemp, filename), ".ttt"); remove(filetemp); // May still be there from previous error @@ -948,12 +1171,12 @@ int DOSFAM::RenameTempFile(PGLOBAL g, bool abort) if (rename(filename, filetemp)) { // Save file for security sprintf(g->Message, MSG(RENAME_ERROR), filename, filetemp, strerror(errno)); - rc = RC_FX; + longjmp(g->jumper[g->jump_level], 51); } else if (rename(tempname, filename)) { sprintf(g->Message, MSG(RENAME_ERROR), tempname, filename, strerror(errno)); rc = rename(filetemp, filename); // Restore saved file - rc = RC_FX; + longjmp(g->jumper[g->jump_level], 52); } else if (remove(filetemp)) { sprintf(g->Message, MSG(REMOVE_ERROR), filetemp, strerror(errno)); @@ -973,18 +1196,20 @@ void DOSFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc; + Abort = abort; + if (UseTemp && T_Stream) { - if (Tdbp->Mode == MODE_UPDATE && !abort) { + if (Tdbp->Mode == MODE_UPDATE && !Indxd && !Abort) { // Copy eventually remaining lines bool b; fseek(Stream, 0, SEEK_END); Fpos = ftell(Stream); - abort = MoveIntermediateLines(g, &b) != RC_OK; - } // endif abort + Abort = MoveIntermediateLines(g, &b) != RC_OK; + } // endif Abort // Delete the old file and rename the new temp file. - RenameTempFile(g, abort); // Also close all files + rc = RenameTempFile(g); // Also close all files } else { rc = PlugCloseFile(g, To_Fb); @@ -994,6 +1219,7 @@ void DOSFAM::CloseTableFile(PGLOBAL g, bool abort) } // endif UseTemp Stream = NULL; // So we can know whether table is open + T_Stream = NULL; } // end of CloseTableFile /***********************************************************************/ @@ -1050,7 +1276,7 @@ void BLKFAM::Reset(void) /***********************************************************************/ int BLKFAM::Cardinality(PGLOBAL g) { - return (g) ? (int)((Block - 1) * Nrec + Last) : 1; + return (g) ? ((Block > 0) ? (int)((Block - 1) * Nrec + Last) : 0) : 1; } // end of Cardinality /***********************************************************************/ @@ -1129,20 +1355,8 @@ int BLKFAM::GetNextPos(void) /***********************************************************************/ bool BLKFAM::SetPos(PGLOBAL g, int pos) { - if (pos < 0) { - strcpy(g->Message, MSG(INV_REC_POS)); - return true; - } // endif recpos - - CurBlk = pos / Nrec; - CurNum = pos % Nrec; -#if defined(_DEBUG) - num_eq[(CurBlk == OldBlk) ? 1 : 0]++; -#endif - - // Indicate the table position was externally set - Placed = true; - return false; + strcpy(g->Message, "Blocked variable tables cannot be used indexed"); + return true; } // end of SetPos /***********************************************************************/ @@ -1389,18 +1603,20 @@ void BLKFAM::CloseTableFile(PGLOBAL g, bool abort) { int rc, wrc = RC_OK; + Abort = abort; + if (UseTemp && T_Stream) { - if (Tdbp->GetMode() == MODE_UPDATE && !abort) { + if (Tdbp->GetMode() == MODE_UPDATE && !Abort) { // Copy eventually remaining lines bool b; fseek(Stream, 0, SEEK_END); Fpos = ftell(Stream); - abort = MoveIntermediateLines(g, &b) != RC_OK; - } // endif abort + Abort = MoveIntermediateLines(g, &b) != RC_OK; + } // endif Abort // Delete the old file and rename the new temp file. - rc = RenameTempFile(g, abort); // Also close all files + rc = RenameTempFile(g); // Also close all files } else { // Closing is True if last Write was in error if (Tdbp->GetMode() == MODE_INSERT && CurNum && !Closing) { diff --git a/storage/connect/filamtxt.h b/storage/connect/filamtxt.h index abe8f2f2324..83c93ecc6f2 100644 --- a/storage/connect/filamtxt.h +++ b/storage/connect/filamtxt.h @@ -1,196 +1,210 @@ -/************** FilAMTxt H Declares Source Code File (.H) **************/
-/* Name: FILAMTXT.H Version 1.2 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
-/* */
-/* This file contains the file access method classes declares. */
-/***********************************************************************/
-
-#ifndef __FILAMTXT_H
-#define __FILAMTXT_H
-
-#include "block.h"
-
-typedef class TXTFAM *PTXF;
-typedef class DOSFAM *PDOSFAM;
-typedef class BLKFAM *PBLKFAM;
-typedef class DOSDEF *PDOSDEF;
-typedef class TDBDOS *PTDBDOS;
-
-/***********************************************************************/
-/* This is the base class for all file access method classes. */
-/***********************************************************************/
-class DllExport TXTFAM : public BLOCK {
- friend class TDBDOS;
- friend class TDBCSV;
- friend class TDBFIX;
- friend class TDBVCT;
- friend class DOSCOL;
- friend class BINCOL;
- friend class VCTCOL;
- public:
- // Constructor
- TXTFAM(PDOSDEF tdp);
- TXTFAM(PTXF txfp);
-
- // Implementation
- virtual AMT GetAmType(void) = 0;
- virtual int GetPos(void) = 0;
- virtual int GetNextPos(void) = 0;
- virtual PTXF Duplicate(PGLOBAL g) = 0;
- virtual bool GetUseTemp(void) {return false;}
- virtual int GetDelRows(void) {return DelRows;}
- int GetCurBlk(void) {return CurBlk;}
- void SetTdbp(PTDBDOS tdbp) {Tdbp = tdbp;}
- int GetBlock(void) {return Block;}
- void SetBlkPos(int *bkp) {BlkPos = bkp;}
- void SetNrec(int n) {Nrec = n;}
- char *GetBuf(void) {return To_Buf;}
- int GetRows(void) {return Rows;}
- bool IsBlocked(void) {return Blocked;}
-
- // Methods
- virtual void Reset(void);
- virtual int GetFileLength(PGLOBAL g);
- virtual int Cardinality(PGLOBAL g);
- virtual int MaxBlkSize(PGLOBAL g, int s);
- virtual bool AllocateBuffer(PGLOBAL g) {return false;}
- virtual void ResetBuffer(PGLOBAL g) {}
- virtual int GetNerr(void) {return 0;}
- virtual int GetRowID(void) = 0;
- virtual bool RecordPos(PGLOBAL g) = 0;
- virtual bool SetPos(PGLOBAL g, int recpos) = 0;
- virtual int SkipRecord(PGLOBAL g, bool header) = 0;
- virtual bool OpenTableFile(PGLOBAL g) = 0;
- virtual bool DeferReading(void) {IsRead = false; return true;}
- virtual int ReadBuffer(PGLOBAL g) = 0;
- virtual int WriteBuffer(PGLOBAL g) = 0;
- virtual int DeleteRecords(PGLOBAL g, int irc) = 0;
- virtual void CloseTableFile(PGLOBAL g, bool abort) = 0;
- virtual void Rewind(void) = 0;
-
- protected:
- // Members
- PTDBDOS Tdbp; // To table class
- PSZ To_File; // Points to table file name
- PFBLOCK To_Fb; // Pointer to file block
- bool Placed; // true if Recpos was externally set
- bool IsRead; // false for deferred reading
- bool Blocked; // true if using blocked I/O
- char *To_Buf; // Points to I/O buffer
- void *DelBuf; // Buffer used to move lines in Delete
- int *BlkPos; // To array of block positions
- int BlkLen; // Current block length
- int Buflen; // Buffer length
- int Dbflen; // Delete buffer length
- int Rows; // Number of rows read so far
- int DelRows; // Number of deleted rows
- int Headlen; // Number of bytes in header
- int Lrecl; // Logical Record Length
- int Block; // Number of blocks in table
- int Last; // Number of elements of last block
- int Nrec; // Number of records in buffer
- int OldBlk; // Index of last read block
- int CurBlk; // Index of current block
- int CurNum; // Current buffer line number
- int ReadBlks; // Number of blocks read (selected)
- int Rbuf; // Number of lines read in buffer
- int Modif; // Number of modified lines in block
- int Blksize; // Size of padded blocks
- int Ending; // Length of line end
- bool Padded; // true if fixed size blocks are padded
- bool Eof; // true if an EOF (0xA) character exists
- char *CrLf; // End of line character(s)
- }; // end of class TXTFAM
-
-/***********************************************************************/
-/* This is the DOS/UNIX Access Method class declaration for standard */
-/* text files with variable record format (DOS, CSV, FMT) */
-/***********************************************************************/
-class DllExport DOSFAM : public TXTFAM {
- public:
- // Constructor
- DOSFAM(PDOSDEF tdp);
- DOSFAM(PDOSFAM txfp);
-
- // Implementation
- virtual AMT GetAmType(void) {return TYPE_AM_DOS;}
- virtual bool GetUseTemp(void) {return UseTemp;}
- virtual int GetPos(void);
- virtual int GetNextPos(void);
- virtual PTXF Duplicate(PGLOBAL g)
- {return (PTXF)new(g) DOSFAM(this);}
-
- // Methods
- virtual void Reset(void);
- virtual int GetFileLength(PGLOBAL g);
- virtual int Cardinality(PGLOBAL g);
- virtual int MaxBlkSize(PGLOBAL g, int s);
- virtual bool AllocateBuffer(PGLOBAL g);
- virtual int GetRowID(void);
- virtual bool RecordPos(PGLOBAL g);
- virtual bool SetPos(PGLOBAL g, int recpos);
- virtual int SkipRecord(PGLOBAL g, bool header);
- virtual bool OpenTableFile(PGLOBAL g);
- virtual int ReadBuffer(PGLOBAL g);
- virtual int WriteBuffer(PGLOBAL g);
- virtual int DeleteRecords(PGLOBAL g, int irc);
- virtual void CloseTableFile(PGLOBAL g, bool abort);
- virtual void Rewind(void);
-
- protected:
- virtual bool OpenTempFile(PGLOBAL g);
- virtual bool MoveIntermediateLines(PGLOBAL g, bool *b);
- virtual int RenameTempFile(PGLOBAL g, bool abort);
-
- // Members
- FILE *Stream; // Points to Dos file structure
- FILE *T_Stream; // Points to temporary file structure
- PFBLOCK To_Fbt; // Pointer to temp file block
- int Fpos; // Position of last read record
- int Tpos; // Target Position for delete move
- int Spos; // Start position for delete move
- bool UseTemp; // True to use a temporary file in Delete
- bool Bin; // True to force binary mode
- }; // end of class DOSFAM
-
-/***********************************************************************/
-/* This is the DOS/UNIX Access Method class declaration for standard */
-/* text files with variable record format (DOS, CSV, FMT) */
-/***********************************************************************/
-class DllExport BLKFAM : public DOSFAM {
- public:
- // Constructor
- BLKFAM(PDOSDEF tdp);
- BLKFAM(PBLKFAM txfp);
-
- // Implementation
- virtual AMT GetAmType(void) {return TYPE_AM_BLK;}
- virtual int GetPos(void);
- virtual int GetNextPos(void);
- virtual PTXF Duplicate(PGLOBAL g)
- {return (PTXF)new(g) BLKFAM(this);}
-
- // Methods
- virtual void Reset(void);
- virtual int Cardinality(PGLOBAL g);
- virtual int MaxBlkSize(PGLOBAL g, int s);
- virtual bool AllocateBuffer(PGLOBAL g);
- virtual int GetRowID(void);
- virtual bool RecordPos(PGLOBAL g);
- virtual bool SetPos(PGLOBAL g, int recpos);
- virtual int SkipRecord(PGLOBAL g, bool header);
- virtual int ReadBuffer(PGLOBAL g);
- virtual int WriteBuffer(PGLOBAL g);
- virtual void CloseTableFile(PGLOBAL g, bool abort);
- virtual void Rewind(void);
-
- protected:
- // Members
- char *CurLine; // Position of current line in buffer
- char *NxtLine; // Position of Next line in buffer
- char *OutBuf; // Buffer to write in temporary file
- bool Closing; // True when closing on Update
- }; // end of class BLKFAM
-
-#endif // __FILAMTXT_H
+/************** FilAMTxt H Declares Source Code File (.H) **************/ +/* Name: FILAMTXT.H Version 1.3 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */ +/* */ +/* This file contains the file access method classes declares. */ +/***********************************************************************/ + +#ifndef __FILAMTXT_H +#define __FILAMTXT_H + +#include "block.h" +#include "array.h" + +typedef class TXTFAM *PTXF; +typedef class DOSFAM *PDOSFAM; +typedef class BLKFAM *PBLKFAM; +typedef class DOSDEF *PDOSDEF; +typedef class TDBDOS *PTDBDOS; + +/***********************************************************************/ +/* This is the base class for all file access method classes. */ +/***********************************************************************/ +class DllExport TXTFAM : public BLOCK { + friend class TDBDOS; + friend class TDBCSV; + friend class TDBFIX; + friend class TDBVCT; + friend class DOSCOL; + friend class BINCOL; + friend class VCTCOL; + public: + // Constructor + TXTFAM(PDOSDEF tdp); + TXTFAM(PTXF txfp); + + // Implementation + virtual AMT GetAmType(void) = 0; + virtual int GetPos(void) = 0; + virtual int GetNextPos(void) = 0; + virtual PTXF Duplicate(PGLOBAL g) = 0; + virtual bool GetUseTemp(void) {return false;} + virtual int GetDelRows(void) {return DelRows;} + int GetCurBlk(void) {return CurBlk;} + void SetTdbp(PTDBDOS tdbp) {Tdbp = tdbp;} + int GetBlock(void) {return Block;} + void SetBlkPos(int *bkp) {BlkPos = bkp;} + void SetNrec(int n) {Nrec = n;} + char *GetBuf(void) {return To_Buf;} + int GetRows(void) {return Rows;} + bool IsBlocked(void) {return Blocked;} + + // Methods + virtual void Reset(void); + virtual int GetFileLength(PGLOBAL g); + virtual int Cardinality(PGLOBAL g); + virtual int MaxBlkSize(PGLOBAL g, int s); + virtual bool AllocateBuffer(PGLOBAL g) {return false;} + virtual void ResetBuffer(PGLOBAL g) {} + virtual int GetNerr(void) {return 0;} + virtual int GetRowID(void) = 0; + virtual bool RecordPos(PGLOBAL g) = 0; + virtual bool SetPos(PGLOBAL g, int recpos) = 0; + virtual int SkipRecord(PGLOBAL g, bool header) = 0; + virtual bool OpenTableFile(PGLOBAL g) = 0; + virtual bool DeferReading(void) {IsRead = false; return true;} + virtual int ReadBuffer(PGLOBAL g) = 0; + virtual int WriteBuffer(PGLOBAL g) = 0; + virtual int DeleteRecords(PGLOBAL g, int irc) = 0; + virtual void CloseTableFile(PGLOBAL g, bool abort) = 0; + virtual void Rewind(void) = 0; + + protected: + bool AddListValue(PGLOBAL g, int type, void *val, PPARM *top); + + // Members + PTDBDOS Tdbp; // To table class + PSZ To_File; // Points to table file name + PFBLOCK To_Fb; // Pointer to file block + PPARM To_Pos; // Pointer to position list + PPARM To_Sos; // Pointer to start position list + PPARM To_Upd; // Pointer to udated line list + PARRAY Posar; // Pointer to position array + PARRAY Sosar; // Pointer to start position array + PARRAY Updar; // Pointer to udated lines array + bool Placed; // true if Recpos was externally set + bool IsRead; // false for deferred reading + bool Blocked; // true if using blocked I/O + char *To_Buf; // Points to I/O buffer + void *DelBuf; // Buffer used to move lines in Delete + int *BlkPos; // To array of block positions + int BlkLen; // Current block length + int Buflen; // Buffer length + int Dbflen; // Delete buffer length + int Rows; // Number of rows read so far + int DelRows; // Number of deleted rows + int Headlen; // Number of bytes in header + int Lrecl; // Logical Record Length + int Block; // Number of blocks in table + int Last; // Number of elements of last block + int Nrec; // Number of records in buffer + int OldBlk; // Index of last read block + int CurBlk; // Index of current block + int CurNum; // Current buffer line number + int ReadBlks; // Number of blocks read (selected) + int Rbuf; // Number of lines read in buffer + int Modif; // Number of modified lines in block + int Blksize; // Size of padded blocks + int Ending; // Length of line end + bool Padded; // true if fixed size blocks are padded + bool Eof; // true if an EOF (0xA) character exists + bool Indxd; // True for indexed UPDATE/DELETE + bool Abort; // To abort on error + char *CrLf; // End of line character(s) + }; // end of class TXTFAM + +/***********************************************************************/ +/* This is the DOS/UNIX Access Method class declaration for standard */ +/* text files with variable record format (DOS, CSV, FMT) */ +/***********************************************************************/ +class DllExport DOSFAM : public TXTFAM { + public: + // Constructor + DOSFAM(PDOSDEF tdp); + DOSFAM(PDOSFAM txfp); + DOSFAM(PBLKFAM tdfp, PDOSDEF tdp); + + // Implementation + virtual AMT GetAmType(void) {return TYPE_AM_DOS;} + virtual bool GetUseTemp(void) {return UseTemp;} + virtual int GetPos(void); + virtual int GetNextPos(void); + virtual PTXF Duplicate(PGLOBAL g) + {return (PTXF)new(g) DOSFAM(this);} + + // Methods + virtual void Reset(void); + virtual int GetFileLength(PGLOBAL g); + virtual int Cardinality(PGLOBAL g); + virtual int MaxBlkSize(PGLOBAL g, int s); + virtual bool AllocateBuffer(PGLOBAL g); + virtual int GetRowID(void); + virtual bool RecordPos(PGLOBAL g); + virtual bool SetPos(PGLOBAL g, int recpos); + virtual int SkipRecord(PGLOBAL g, bool header); + virtual bool OpenTableFile(PGLOBAL g); + virtual int ReadBuffer(PGLOBAL g); + virtual int WriteBuffer(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); + virtual void Rewind(void); + + protected: + virtual bool OpenTempFile(PGLOBAL g); + virtual bool MoveIntermediateLines(PGLOBAL g, bool *b); + virtual int RenameTempFile(PGLOBAL g); + virtual bool MakeUpdatedFile(PGLOBAL g); + virtual bool MakeDeletedFile(PGLOBAL g); + + // Members + FILE *Stream; // Points to Dos file structure + FILE *T_Stream; // Points to temporary file structure + PFBLOCK To_Fbt; // Pointer to temp file block + int Fpos; // Position of last read record + int Tpos; // Target Position for delete move + int Spos; // Start position for update/delete move + bool UseTemp; // True to use a temporary file in Upd/Del + bool Bin; // True to force binary mode + }; // end of class DOSFAM + +/***********************************************************************/ +/* This is the DOS/UNIX Access Method class declaration for standard */ +/* text files with variable record format (DOS, CSV, FMT) */ +/***********************************************************************/ +class DllExport BLKFAM : public DOSFAM { + public: + // Constructor + BLKFAM(PDOSDEF tdp); + BLKFAM(PBLKFAM txfp); + + // Implementation + virtual AMT GetAmType(void) {return TYPE_AM_BLK;} + virtual int GetPos(void); + virtual int GetNextPos(void); + virtual PTXF Duplicate(PGLOBAL g) + {return (PTXF)new(g) BLKFAM(this);} + + // Methods + virtual void Reset(void); + virtual int Cardinality(PGLOBAL g); + virtual int MaxBlkSize(PGLOBAL g, int s); + virtual bool AllocateBuffer(PGLOBAL g); + virtual int GetRowID(void); + virtual bool RecordPos(PGLOBAL g); + virtual bool SetPos(PGLOBAL g, int recpos); + virtual int SkipRecord(PGLOBAL g, bool header); + virtual int ReadBuffer(PGLOBAL g); + virtual int WriteBuffer(PGLOBAL g); + virtual void CloseTableFile(PGLOBAL g, bool abort); + virtual void Rewind(void); + + protected: + // Members + char *CurLine; // Position of current line in buffer + char *NxtLine; // Position of Next line in buffer + char *OutBuf; // Buffer to write in temporary file + bool Closing; // True when closing on Update + }; // end of class BLKFAM + +#endif // __FILAMTXT_H diff --git a/storage/connect/filamvct.cpp b/storage/connect/filamvct.cpp index 076222e9e7f..392d5b4d850 100755 --- a/storage/connect/filamvct.cpp +++ b/storage/connect/filamvct.cpp @@ -1,7 +1,7 @@ /*********** File AM Vct C++ Program Source Code File (.CPP) ***********/ /* PROGRAM NAME: FILAMVCT */ /* ------------- */ -/* Version 2.5 */ +/* Version 2.6 */ /* */ /* COPYRIGHT: */ /* ---------- */ @@ -10,7 +10,7 @@ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ /* This program are the VCT file access method classes. */ -/* Added in version 2: F */ +/* Added in version 2: */ /* - Split Vec format. */ /* - Partial delete. */ /* - Use of tempfile for update. */ @@ -29,7 +29,7 @@ #endif // __BORLAND__ //#include <windows.h> #include <sys/stat.h> -#else // !WIN32 F +#else // !WIN32 #if defined(UNIX) #include <sys/types.h> #include <sys/stat.h> @@ -93,6 +93,11 @@ typedef struct _vecheader { PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int, bool check = true, bool blank = true, bool un = false); +/***********************************************************************/ +/* Routine called externally by VCTFAM MakeUpdatedFile function. */ +/***********************************************************************/ +PARRAY MakeValueArray(PGLOBAL g, PPARM pp); + /* -------------------------- Class VCTFAM --------------------------- */ /***********************************************************************/ @@ -354,7 +359,7 @@ int VCTFAM::Cardinality(PGLOBAL g) } // endif split - return (int)((Block - 1) * Nrec + Last); + return (Block) ? ((Block - 1) * Nrec + Last) : 0; } // end of Cardinality /***********************************************************************/ @@ -363,7 +368,7 @@ int VCTFAM::Cardinality(PGLOBAL g) int VCTFAM::GetRowID(void) { return 1 + ((CurBlk < Block) ? CurNum + Nrec * CurBlk - : (Block - 1) * Nrec + Last); + : (Block - 1) * Nrec + Last); } // end of GetRowID /***********************************************************************/ @@ -447,7 +452,7 @@ bool VCTFAM::OpenTableFile(PGLOBAL g) return true; strcpy(opmode, "r+b"); // Required to update empty blocks - } else if (Last == Nrec) + } else if (!Block || Last == Nrec) strcpy(opmode, "ab"); else strcpy(opmode, "r+b"); // Required to update the last block @@ -665,7 +670,10 @@ int VCTFAM::WriteBuffer(PGLOBAL g) // Mode Update is done in ReadDB, we just initialize it here if (!T_Stream) { if (UseTemp) { - if (OpenTempFile(g)) + if ((Indxd = Tdbp->GetKindex() != NULL)) { + strcpy(g->Message, "VCT indexed udate using temp file NIY"); + return RC_FX; + } else if (OpenTempFile(g)) return RC_FX; // Most of the time, not all table columns are updated. @@ -784,12 +792,17 @@ int VCTFAM::DeleteRecords(PGLOBAL g, int irc) Spos = Tpos = Fpos; } // endif UseTemp + Indxd = Tdbp->GetKindex() != NULL; } // endif Tpos == Spos /*********************************************************************/ /* Move any intermediate lines. */ /*********************************************************************/ - if (MoveIntermediateLines(g, &eof)) + if (Indxd) { + // Moving will be done later, must be done in sequential order + (void)AddListValue(g, TYPE_INT, &Fpos, &To_Pos); + Spos = Fpos; + } else if (MoveIntermediateLines(g, &eof)) return RC_FX; if (irc == RC_OK) { @@ -809,6 +822,11 @@ int VCTFAM::DeleteRecords(PGLOBAL g, int irc) /* Last call after EOF has been reached. */ /* Update the Block and Last values. */ /*******************************************************************/ + if (Indxd && (Abort = MakeDeletedFile(g))) + return RC_FX; + else + Indxd = false; // Not to be redone by RenameTempFile + Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0; Last = (Tpos + Nrec - 1) % Nrec + 1; @@ -908,7 +926,7 @@ bool VCTFAM::OpenTempFile(PGLOBAL g) bool VCTFAM::MoveIntermediateLines(PGLOBAL g, bool *b) { int i, dep, off; - int n; + int n; bool eof = (b) ? *b : false; size_t req, len; @@ -1009,6 +1027,63 @@ bool VCTFAM::MoveIntermediateLines(PGLOBAL g, bool *b) } // end of MoveIntermediateLines /***********************************************************************/ +/* MakeDeletedFile. When deleting using indexing, the issue is that */ +/* record are not necessarily deleted in sequential order. Moving */ +/* intermediate lines cannot be done while deleing them because */ +/* this can cause extra wrong records to be included in the new file. */ +/* What we do here is to reorder the deleted record and make the new */ +/* deleted file from the ordered deleted records. */ +/***********************************************************************/ +bool VCTFAM::MakeDeletedFile(PGLOBAL g) + { +//char *crlf = "\n", *mode = UseTemp ? "rb" : "r+b"; + int *ix, i, n; + bool eof = false; + + /*********************************************************************/ + /* Open the temporary file, Spos is at the beginning of file. */ + /*********************************************************************/ + if (!(Posar = MakeValueArray(g, To_Pos))) { + strcpy(g->Message, "Position array is null"); + goto err; + } else if (!(ix = (int*)Posar->GetSortIndex(g))) { + strcpy(g->Message, "Error getting array sort index"); + goto err; + } // endif's + + n = Posar->GetNval(); + Spos = 0; + + for (i = 0; i < n; i++) { + if (i == n - 1 && !MaxBlk && UseTemp) + eof = true; + + Fpos = Posar->GetIntValue(ix[i]); + + if (i || UseTemp) { + // Copy all not updated lines preceding this one + if (MoveIntermediateLines(g, &eof)) + goto err; + + } else + Tpos = Fpos; + + // New start position + Spos = Fpos + 1; + } // endfor i + + if (!PlugCloseFile(g, To_Fbt)) + return false; + +err: + if (trace) + htrc("%s\n", g->Message); + + PlugCloseFile(g, To_Fbt); + return true; + } // end of MakeDeletedFile + +/***********************************************************************/ /* Clean deleted space in a VCT or Vec table file. */ /***********************************************************************/ bool VCTFAM::CleanUnusedSpace(PGLOBAL g) @@ -1080,6 +1155,8 @@ void VCTFAM::CloseTableFile(PGLOBAL g, bool abort) int rc = 0, wrc = RC_OK; MODE mode = Tdbp->GetMode(); + Abort = abort; + if (mode == MODE_INSERT) { if (Closing) wrc = RC_FX; // Last write was in error @@ -1111,7 +1188,7 @@ void VCTFAM::CloseTableFile(PGLOBAL g, bool abort) colp->WriteBlock(g); if (UseTemp && T_Stream) { - rc = RenameTempFile(g, abort); + rc = RenameTempFile(g); if (Header) { // Header must be set because it was not set in temp file @@ -1125,7 +1202,7 @@ void VCTFAM::CloseTableFile(PGLOBAL g, bool abort) if (MaxBlk) rc = CleanUnusedSpace(g); - if ((rc = RenameTempFile(g, abort)) != RC_FX) { + if ((rc = RenameTempFile(g)) != RC_FX) { Stream = T_Stream = NULL; // For SetBlockInfo rc = ResetTableSize(g, Block, Last); } // endif rc @@ -1602,9 +1679,6 @@ int VCMFAM::WriteBuffer(PGLOBAL g) /***********************************************************************/ int VCMFAM::DeleteRecords(PGLOBAL g, int irc) { - int i; - int m, n; - if (trace) htrc("VCM DeleteDB: irc=%d tobuf=%p Tpos=%p Spos=%p\n", irc, To_Buf, Tpos, Spos); @@ -1621,52 +1695,20 @@ int VCMFAM::DeleteRecords(PGLOBAL g, int irc) } else // Fpos is the Deleted line position Fpos = CurBlk * Nrec + CurNum; - if (Tpos == Spos) + if (Tpos == Spos) { /*******************************************************************/ /* First line to delete. Move of eventual preceeding lines is */ /* not required here, just setting of future Spos and Tpos. */ /*******************************************************************/ - Tpos = Fpos; // Spos is set below - else if (Fpos > Spos) { - /*******************************************************************/ - /* Non consecutive line to delete. Move intermediate lines. */ - /*******************************************************************/ - if (!MaxBlk) { - // Old VCT format, moving must respect block limits - char *ps, *pt; - int req, soff, toff; - - for (n = Fpos - Spos; n > 0; n -= req) { - soff = Spos % Nrec; - toff = Tpos % Nrec; - req = (size_t)MY_MIN(n, Nrec - MY_MAX(soff, toff)); - - for (i = 0; i < Ncol; i++) { - ps = Memcol[i] + (Spos / Nrec) * Blksize + soff * Clens[i]; - pt = Memcol[i] + (Tpos / Nrec) * Blksize + toff * Clens[i]; - memmove(pt, ps, req * Clens[i]); - } // endfor i - - Tpos += req; - Spos += req; - } // endfor n - - } else { - // True vector format, all is simple... - n = Fpos - Spos; - - for (i = 0; i < Ncol; i++) { - m = Clens[i]; - memmove(Memcol[i] + Tpos * m, Memcol[i] + Spos * m, n * m); - } // endfor i - - Tpos += n; - } // endif MaxBlk - - if (trace) - htrc("move %d bytes\n", n); + Tpos = Spos = Fpos; + Indxd = Tdbp->GetKindex() != NULL; + } // endif Tpos - } // endif n + if (Indxd) + // Moving will be done later, must be done in sequential order + (void)AddListValue(g, TYPE_INT, &Fpos, &To_Pos); + else + (void)MoveIntermediateLines(g); if (irc == RC_OK) { Spos = Fpos + 1; // New start position @@ -1674,10 +1716,14 @@ int VCMFAM::DeleteRecords(PGLOBAL g, int irc) if (trace) htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos); - } else { + } else if (!(Abort = (Indxd && MakeDeletedFile(g)))) { + /*******************************************************************/ + /* Last call after EOF has been reached. */ + /*******************************************************************/ + int i, m, n; + /*******************************************************************/ - /* Last call after EOF has been reached. Reset the Block and */ - /* Last values for TDBVCT::MakeBlockValues. */ + /* Reset the Block and Last values for TDBVCT::MakeBlockValues. */ /*******************************************************************/ Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0; Last = (Tpos + Nrec - 1) % Nrec + 1; @@ -1740,12 +1786,105 @@ int VCMFAM::DeleteRecords(PGLOBAL g, int irc) // Reset Last and Block values in the catalog PlugCloseFile(g, To_Fb); // in case of Header ResetTableSize(g, Block, Last); - } // endif irc + } else + return RC_FX; return RC_OK; // All is correct } // end of DeleteRecords /***********************************************************************/ +/* Move intermediate deleted or updated lines. */ +/***********************************************************************/ +bool VCMFAM::MoveIntermediateLines(PGLOBAL g, bool *b) + { + int i, m, n; + + if ((n = Fpos - Spos) > 0) { + /*******************************************************************/ + /* Non consecutive line to delete. Move intermediate lines. */ + /*******************************************************************/ + if (!MaxBlk) { + // Old VCT format, moving must respect block limits + char *ps, *pt; + int req, soff, toff; + + for (; n > 0; n -= req) { + soff = Spos % Nrec; + toff = Tpos % Nrec; + req = (size_t)MY_MIN(n, Nrec - MY_MAX(soff, toff)); + + for (i = 0; i < Ncol; i++) { + ps = Memcol[i] + (Spos / Nrec) * Blksize + soff * Clens[i]; + pt = Memcol[i] + (Tpos / Nrec) * Blksize + toff * Clens[i]; + memmove(pt, ps, req * Clens[i]); + } // endfor i + + Tpos += req; + Spos += req; + } // endfor n + + } else { + // True vector format, all is simple... + for (i = 0; i < Ncol; i++) { + m = Clens[i]; + memmove(Memcol[i] + Tpos * m, Memcol[i] + Spos * m, n * m); + } // endfor i + + Tpos += n; + } // endif MaxBlk + + if (trace) + htrc("move %d bytes\n", n); + + } // endif n + + return false; + } // end of MoveIntermediate Lines + +/***********************************************************************/ +/* MakeDeletedFile. When deleting using indexing, the issue is that */ +/* record are not necessarily deleted in sequential order. Moving */ +/* intermediate lines cannot be done while deleting them. */ +/* What we do here is to reorder the deleted records and move the */ +/* intermediate files from the ordered deleted record positions. */ +/***********************************************************************/ +bool VCMFAM::MakeDeletedFile(PGLOBAL g) + { + int *ix, i; + + /*********************************************************************/ + /* Make and order the arrays from the saved values. */ + /*********************************************************************/ + if (!(Posar = MakeValueArray(g, To_Pos))) { + strcpy(g->Message, "Position array is null"); + goto err; + } else if (!(ix = (int*)Posar->GetSortIndex(g))) { + strcpy(g->Message, "Error getting array sort index"); + goto err; + } // endif's + + for (i = 0; i < Posar->GetNval(); i++) { + Fpos = Posar->GetIntValue(ix[i]); + + if (!i) { + Tpos = Fpos; + } else + (void)MoveIntermediateLines(g); + + // New start position + Spos = Fpos + 1; + } // endfor i + + return false; + +err: + if (trace) + htrc("%s\n", g->Message); + + return true; + } // end of MakeDeletedFile + +/***********************************************************************/ /* Data Base close routine for VMP access method. */ /***********************************************************************/ void VCMFAM::CloseTableFile(PGLOBAL g, bool abort) @@ -1775,7 +1914,7 @@ void VCMFAM::CloseTableFile(PGLOBAL g, bool abort) if (wrc != RC_FX) /*rc =*/ ResetTableSize(g, Block, Last); - } else if (mode != MODE_DELETE) + } else if (mode != MODE_DELETE || Abort) PlugCloseFile(g, To_Fb); } // end of CloseTableFile @@ -1903,7 +2042,7 @@ bool VECFAM::OpenTableFile(PGLOBAL g) // Selective delete, pass thru case MODE_UPDATE: UseTemp = Tdbp->IsUsingTemp(g); - strcpy(opmode, (UseTemp) ? "r": "r+"); + strcpy(opmode, (UseTemp) ? "rb": "r+b"); break; case MODE_INSERT: strcpy(opmode, "ab"); @@ -1962,10 +2101,13 @@ bool VECFAM::OpenTableFile(PGLOBAL g) // Check for void table or missing columns for (i = 0, cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next) - if (!i++) - b = !Streams[cp->Index - 1]; - else if (b != !Streams[cp->Index - 1]) - return true; + if (!cp->IsSpecial()) { + if (!i++) + b = !Streams[cp->Index - 1]; + else if (b != !Streams[cp->Index - 1]) + return true; + + } // endif Special } // endif mode @@ -2167,7 +2309,10 @@ int VECFAM::WriteBuffer(PGLOBAL g) } else // Mode Update // Writing updates being done in ReadDB we do initialization only. if (InitUpdate) { - if (OpenTempFile(g)) + if ((Indxd = Tdbp->GetKindex() != NULL)) { + strcpy(g->Message, "VEC indexed udate using temp file NIY"); + return RC_FX; + } else if (OpenTempFile(g)) return RC_FX; InitUpdate = false; // Done @@ -2179,18 +2324,10 @@ int VECFAM::WriteBuffer(PGLOBAL g) /***********************************************************************/ /* Data Base delete line routine for split vertical access methods. */ /* Note: lines are moved directly in the files (ooops...) */ +/* Using temp file depends on the Check setting, false by default. */ /***********************************************************************/ int VECFAM::DeleteRecords(PGLOBAL g, int irc) { - /*********************************************************************/ - /* There is an alternative here: */ - /* 1 - use a temporary file in which are copied all not deleted */ - /* lines, at the end the original file will be deleted and */ - /* the temporary file renamed to the original file name. */ - /* 2 - directly move the not deleted lines inside the original */ - /* file, and at the end erase all trailing records. */ - /* This depends on the Check setting, false by default. */ - /*********************************************************************/ if (trace) htrc("VEC DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n", irc, UseTemp, Fpos, Tpos, Spos); @@ -2207,7 +2344,7 @@ int VECFAM::DeleteRecords(PGLOBAL g, int irc) } else // Fpos is the Deleted line position Fpos = CurBlk * Nrec + CurNum; - if (Tpos == Spos) + if (Tpos == Spos) { // First line to delete if (UseTemp) { /*****************************************************************/ @@ -2223,10 +2360,17 @@ int VECFAM::DeleteRecords(PGLOBAL g, int irc) /*****************************************************************/ Spos = Tpos = Fpos; + Indxd = Tdbp->GetKindex() != NULL; + } // endif Tpos == Spos + /*********************************************************************/ /* Move any intermediate lines. */ /*********************************************************************/ - if (MoveIntermediateLines(g)) + if (Indxd) { + // Moving will be done later, must be done in sequential order + (void)AddListValue(g, TYPE_INT, &Fpos, &To_Pos); + Spos = Fpos; + } else if (MoveIntermediateLines(g)) return RC_FX; if (irc == RC_OK) { @@ -2242,10 +2386,15 @@ int VECFAM::DeleteRecords(PGLOBAL g, int irc) /*******************************************************************/ /* Last call after EOF has been reached. */ /*******************************************************************/ + if (Indxd && (Abort = MakeDeletedFile(g))) + return RC_FX; +// else +// Indxd = false; // Not to be redone by RenameTempFile + if (!UseTemp) { /*****************************************************************/ /* Because the chsize functionality is only accessible with a */ - /* system call we must close the file and reopen it with the */ + /* system call we must close the files and reopen them with the */ /* open function (_fopen for MS??) this is still to be checked */ /* for compatibility with other OS's. */ /*****************************************************************/ @@ -2285,7 +2434,7 @@ int VECFAM::DeleteRecords(PGLOBAL g, int irc) } else // UseTemp // Ok, now delete old files and rename new temp files - if (RenameTempFile(g, false) == RC_FX) + if (RenameTempFile(g) == RC_FX) return RC_FX; // Reset these values for TDBVCT::MakeBlockValues @@ -2353,8 +2502,7 @@ bool VECFAM::MoveLines(PGLOBAL g) /***********************************************************************/ bool VECFAM::MoveIntermediateLines(PGLOBAL g, bool *bn) { - int i; - int n; + int i, n; bool b = false; size_t req, len; @@ -2413,9 +2561,59 @@ bool VECFAM::MoveIntermediateLines(PGLOBAL g, bool *bn) } // end of MoveIntermediate Lines /***********************************************************************/ +/* MakeDeletedFile. When deleting using indexing, the issue is that */ +/* record are not necessarily deleted in sequential order. Moving */ +/* intermediate lines cannot be done while deleing them because */ +/* this can cause extra wrong records to be included in the new file. */ +/* What we do here is to reorder the deleted record and make the new */ +/* deleted file from the ordered deleted records. */ +/***********************************************************************/ +bool VECFAM::MakeDeletedFile(PGLOBAL g) + { + int *ix, i, n; + + /*********************************************************************/ + /* Open the temporary file, Spos is at the beginning of file. */ + /*********************************************************************/ + if (!(Posar = MakeValueArray(g, To_Pos))) { + strcpy(g->Message, "Position array is null"); + goto err; + } else if (!(ix = (int*)Posar->GetSortIndex(g))) { + strcpy(g->Message, "Error getting array sort index"); + goto err; + } // endif's + + n = Posar->GetNval(); + Spos = 0; + + for (i = 0; i < n; i++) { + Fpos = Posar->GetIntValue(ix[i]); + + if (i || UseTemp) { + // Copy all not updated lines preceding this one + if (MoveIntermediateLines(g)) + goto err; + + } else + Tpos = Fpos; + + // New start position + Spos = Fpos + 1; + } // endfor i + + return false; + +err: + if (trace) + htrc("%s\n", g->Message); + + return true; + } // end of MakeDeletedFile + +/***********************************************************************/ /* Delete the old files and rename the new temporary files. */ /***********************************************************************/ -int VECFAM::RenameTempFile(PGLOBAL g, bool abort) +int VECFAM::RenameTempFile(PGLOBAL g) { char *tempname, filetemp[_MAX_PATH], filename[_MAX_PATH]; int rc = RC_OK; @@ -2432,7 +2630,7 @@ int VECFAM::RenameTempFile(PGLOBAL g, bool abort) tempname = (char*)T_Fbs[i]->Fname; - if (!abort) { + if (!Abort) { sprintf(filename, Colfn, i+1); PlugSetPath(filename, filename, Tdbp->GetPath()); strcat(PlugRemoveType(filetemp, filename), ".ttt"); @@ -2469,6 +2667,8 @@ void VECFAM::CloseTableFile(PGLOBAL g, bool abort) int rc = 0, wrc = RC_OK; MODE mode = Tdbp->GetMode(); + Abort = abort; + if (mode == MODE_INSERT) { if (Closing) wrc = RC_FX; // Last write was in error @@ -2491,10 +2691,10 @@ void VECFAM::CloseTableFile(PGLOBAL g, bool abort) longjmp(g->jumper[g->jump_level], 44); } else if (mode == MODE_UPDATE) { - if (UseTemp && !InitUpdate && !abort) { + if (UseTemp && !InitUpdate && !Abort) { // Write any intermediate lines to temp file Fpos = OldBlk * Nrec; - abort = MoveIntermediateLines(g) != RC_OK; + Abort = MoveIntermediateLines(g) != RC_OK; // Spos = Fpos + Nrec; } // endif UseTemp @@ -2504,17 +2704,17 @@ void VECFAM::CloseTableFile(PGLOBAL g, bool abort) colp; colp = (PVCTCOL)colp->Next) colp->WriteBlock(g); - if (wrc == RC_OK && UseTemp && !InitUpdate && !abort) { + if (wrc == RC_OK && UseTemp && !InitUpdate && !Abort) { // Write any intermediate lines to temp file Fpos = (Block - 1) * Nrec + Last; - abort = MoveIntermediateLines(g) != RC_OK; + Abort = MoveIntermediateLines(g) != RC_OK; } // endif UseTemp } // endif's mode if (UseTemp && !InitUpdate) { // If they are errors, leave files unchanged - rc = RenameTempFile(g, abort); + rc = RenameTempFile(g); } else if (Streams) for (int i = 0; i < Ncol; i++) @@ -2660,7 +2860,7 @@ VMPFAM::VMPFAM(PVMPFAM txfp) : VCMFAM(txfp) bool VMPFAM::OpenTableFile(PGLOBAL g) { int i; - bool b; + bool b = false; MODE mode = Tdbp->GetMode(); PCOLDEF cdp; PVCTCOL cp; @@ -2706,7 +2906,7 @@ bool VMPFAM::OpenTableFile(PGLOBAL g) } else { /*******************************************************************/ - /* Open the files corresponding updated columns of the query. */ + /* Open the files corresponding to updated columns of the query. */ /*******************************************************************/ for (cp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols; cp; cp = (PVCTCOL)cp->Next) @@ -2721,14 +2921,18 @@ bool VMPFAM::OpenTableFile(PGLOBAL g) if (MapColumnFile(g, MODE_READ, cp->Index - 1)) return true; - } // endif mode + // Check for void table or missing columns + for (i = 0, cp = (PVCTCOL)Tdbp->GetColumns(); cp; + cp = (PVCTCOL)cp->Next) + if (!cp->IsSpecial()) { + if (!i++) + b = !Memcol[cp->Index - 1]; + else if (b != !Memcol[cp->Index - 1]) + return true; - /*********************************************************************/ - /* Check for void table or missing columns */ - /*********************************************************************/ - for (b = !Memcol[0], i = 1; i < Ncol; i++) - if (b != !Memcol[i]) - return true; + } // endif Special + + } // endif mode /*********************************************************************/ /* Allocate the table and column block buffer. */ @@ -2899,12 +3103,18 @@ int VMPFAM::DeleteRecords(PGLOBAL g, int irc) } else // Fpos is the Deleted line position Fpos = CurBlk * Nrec + CurNum; - if (Tpos == Spos) + if (Tpos == Spos) { /*******************************************************************/ /* First line to delete. Move of eventual preceeding lines is */ /* not required here, just setting of future Spos and Tpos. */ /*******************************************************************/ Tpos = Fpos; // Spos is set below + Indxd = Tdbp->GetKindex() != NULL; + } // endif Tpos + + if (Indxd) + // Moving will be done later, must be done in sequential order + (void)AddListValue(g, TYPE_INT, &Fpos, &To_Pos); else if ((n = Fpos - Spos) > 0) { /*******************************************************************/ /* Non consecutive line to delete. Move intermediate lines. */ @@ -2927,7 +3137,7 @@ int VMPFAM::DeleteRecords(PGLOBAL g, int irc) if (trace) htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos); - } else { + } else if (!(Abort = (Indxd && MakeDeletedFile(g)))) { /*******************************************************************/ /* Last call after EOF has been reached. */ /* We must firstly Unmap the view and use the saved file handle */ @@ -2935,6 +3145,12 @@ int VMPFAM::DeleteRecords(PGLOBAL g, int irc) /*******************************************************************/ PFBLOCK fp; + /*******************************************************************/ + /* Reset the Block and Last values for TDBVCT::MakeBlockValues. */ + /*******************************************************************/ +// Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0; +// Last = (Tpos + Nrec - 1) % Nrec + 1; + for (i = 0; i < Ncol; i++) { fp = To_Fbs[i]; CloseMemMap(fp->Memory, (size_t)fp->Length); @@ -2983,6 +3199,55 @@ int VMPFAM::DeleteRecords(PGLOBAL g, int irc) } // end of DeleteRecords /***********************************************************************/ +/* MakeDeletedFile. When deleting using indexing, the issue is that */ +/* record are not necessarily deleted in sequential order. Moving */ +/* intermediate lines cannot be done while deleting them. */ +/* What we do here is to reorder the deleted records and move the */ +/* intermediate files from the ordered deleted record positions. */ +/***********************************************************************/ +bool VMPFAM::MakeDeletedFile(PGLOBAL g) + { + int *ix, i, j, m, n; + + /*********************************************************************/ + /* Make and order the arrays from the saved values. */ + /*********************************************************************/ + if (!(Posar = MakeValueArray(g, To_Pos))) { + strcpy(g->Message, "Position array is null"); + goto err; + } else if (!(ix = (int*)Posar->GetSortIndex(g))) { + strcpy(g->Message, "Error getting array sort index"); + goto err; + } // endif's + + for (i = 0; i < Posar->GetNval(); i++) { + Fpos = Posar->GetIntValue(ix[i]); + + if (!i) { + Tpos = Fpos; + } else if ((n = Fpos - Spos) > 0) { + for (j = 0; j < Ncol; j++) { + m = Clens[j]; + memmove(Memcol[j] + Tpos * m, Memcol[j] + Spos * m, m * n); + } // endif j + + Tpos += n; + } // endif n + + // New start position + Spos = Fpos + 1; + } // endfor i + + return false; + +err: + if (trace) + htrc("%s\n", g->Message); + + return true; + } // end of MakeDeletedFile + +/***********************************************************************/ /* Data Base close routine for VMP access method. */ /***********************************************************************/ void VMPFAM::CloseTableFile(PGLOBAL g, bool abort) @@ -3704,7 +3969,10 @@ int BGVFAM::WriteBuffer(PGLOBAL g) // Mode Update is done in ReadDB, we just initialize it here if (Tfile == INVALID_HANDLE_VALUE) { if (UseTemp) { - if (OpenTempFile(g)) + if ((Indxd = Tdbp->GetKindex() != NULL)) { + strcpy(g->Message, "VEC indexed udate using temp file NIY"); + return RC_FX; + } else if (OpenTempFile(g)) return RC_FX; // Most of the time, not all table columns are updated. @@ -3831,12 +4099,17 @@ int BGVFAM::DeleteRecords(PGLOBAL g, int irc) Spos = Tpos = Fpos; } // endif UseTemp + Indxd = Tdbp->GetKindex() != NULL; } // endif Tpos == Spos /*********************************************************************/ /* Move any intermediate lines. */ /*********************************************************************/ - if (MoveIntermediateLines(g, &eof)) + if (Indxd) { + // Moving will be done later, must be done in sequential order + (void)AddListValue(g, TYPE_INT, &Fpos, &To_Pos); + Spos = Fpos; + } else if (MoveIntermediateLines(g, &eof)) return RC_FX; if (irc == RC_OK) { @@ -3852,6 +4125,11 @@ int BGVFAM::DeleteRecords(PGLOBAL g, int irc) /*******************************************************************/ /* Last call after EOF has been reached. */ /*******************************************************************/ + if (Indxd && (Abort = MakeDeletedFile(g))) + return RC_FX; + else + Indxd = false; // Not to be redone by RenameTempFile + Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0; Last = (Tpos + Nrec - 1) % Nrec + 1; @@ -4112,6 +4390,8 @@ void BGVFAM::CloseTableFile(PGLOBAL g, bool abort) int rc = 0, wrc = RC_OK; MODE mode = Tdbp->GetMode(); + Abort = abort; + if (mode == MODE_INSERT) { if (Closing) wrc = RC_FX; // Last write was in error @@ -4143,7 +4423,7 @@ void BGVFAM::CloseTableFile(PGLOBAL g, bool abort) colp->WriteBlock(g); if (UseTemp && Tfile) { - rc = RenameTempFile(g, abort); + rc = RenameTempFile(g); Hfile = Tfile = INVALID_HANDLE_VALUE; if (Header) @@ -4156,7 +4436,7 @@ void BGVFAM::CloseTableFile(PGLOBAL g, bool abort) if (MaxBlk) rc = CleanUnusedSpace(g); - if ((rc = RenameTempFile(g, abort)) != RC_FX) { + if ((rc = RenameTempFile(g)) != RC_FX) { Hfile = Tfile = INVALID_HANDLE_VALUE; // For SetBlockInfo rc = ResetTableSize(g, Block, Last); } // endif rc diff --git a/storage/connect/filamvct.h b/storage/connect/filamvct.h index 2e599ccc749..8acb62b14dc 100644 --- a/storage/connect/filamvct.h +++ b/storage/connect/filamvct.h @@ -1,250 +1,256 @@ -/************** FilAMVct H Declares Source Code File (.H) **************/
-/* Name: FILAMVCT.H Version 1.5 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
-/* */
-/* This file contains the VCT file access method classes declares. */
-/***********************************************************************/
-#ifndef __FILAMVCT__
-#define __FILAMVCT__
-
-#include "filamfix.h"
-
-typedef class VCTFAM *PVCTFAM;
-typedef class VCTCOL *PVCTCOL;
-typedef class VCMFAM *PVCMFAM;
-typedef class VECFAM *PVECFAM;
-typedef class VMPFAM *PVMPFAM;
-typedef class BGVFAM *PBGVFAM;
-
-/***********************************************************************/
-/* This is the DOS/UNIX Access Method class declaration for files */
-/* in vector format. If MaxBlk=0, each block containing "Elements" */
-/* records, values of each columns are consecutively stored (vector). */
-/* Otherwise, data is arranged by column in the file and MaxBlk is */
-/* used to set the maximum number of blocks. This leave some white */
-/* space allowing to insert new values up to this maximum size. */
-/***********************************************************************/
-class DllExport VCTFAM : public FIXFAM {
- friend class TDBVCT;
- friend class VCTCOL;
- public:
- // Constructor
- VCTFAM(PVCTDEF tdp);
- VCTFAM(PVCTFAM txfp);
-
- // Implementation
- virtual AMT GetAmType(void) {return TYPE_AM_VCT;}
- virtual PTXF Duplicate(PGLOBAL g)
- {return (PTXF)new(g) VCTFAM(this);}
- virtual int GetFileLength(PGLOBAL g);
-
- // Methods
- virtual void Reset(void);
- virtual int MaxBlkSize(PGLOBAL g, int s);
- virtual bool AllocateBuffer(PGLOBAL g);
- virtual bool InitInsert(PGLOBAL g);
- virtual void ResetBuffer(PGLOBAL g) {}
- virtual int Cardinality(PGLOBAL g);
- virtual int GetRowID(void);
-
- // Database routines
- virtual bool OpenTableFile(PGLOBAL g);
- virtual int ReadBuffer(PGLOBAL g);
- virtual int WriteBuffer(PGLOBAL g);
- virtual int DeleteRecords(PGLOBAL g, int irc);
- virtual void CloseTableFile(PGLOBAL g, bool abort);
- virtual void Rewind(void);
-
- // Specific functions
- virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp);
- virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp);
-
- protected:
- virtual bool MakeEmptyFile(PGLOBAL g, char *fn);
- virtual bool OpenTempFile(PGLOBAL g);
- virtual bool MoveLines(PGLOBAL g) {return false;}
- virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
- virtual bool CleanUnusedSpace(PGLOBAL g);
- virtual int GetBlockInfo(PGLOBAL g);
- virtual bool SetBlockInfo(PGLOBAL g);
- bool ResetTableSize(PGLOBAL g, int block, int last);
-
- // Members
- char *NewBlock; // To block written on Insert
- char *Colfn; // Pattern for column file names (VEC)
- char *Tempat; // Pattern for temp file names (VEC)
- int *Clens; // Pointer to col size array
- int *Deplac; // Pointer to col start position array
- bool *Isnum; // Pointer to buffer type isnum result
- bool AddBlock; // True when adding new blocks on Insert
- bool Split; // true: split column file vector format
- int Header; // 0: no, 1: separate, 2: in data file
- int MaxBlk; // Max number of blocks (True vector format)
- int Bsize; // Because Nrec can be modified
- int Ncol; // The number of columns;
- }; // end of class VCTFAM
-
-/***********************************************************************/
-/* This is the DOS/UNIX Access Method class declaration for files */
-/* in vector format accessed using file mapping. */
-/***********************************************************************/
-class DllExport VCMFAM : public VCTFAM {
- friend class TDBVCT;
- friend class VCTCOL;
- public:
- // Constructor
- VCMFAM(PVCTDEF tdp);
- VCMFAM(PVCMFAM txfp);
-
- // Implementation
- virtual AMT GetAmType(void) {return TYPE_AM_VMP;}
- virtual PTXF Duplicate(PGLOBAL g)
- {return (PTXF)new(g) VCMFAM(this);}
-
- // Methods
- virtual bool AllocateBuffer(PGLOBAL g);
- virtual bool InitInsert(PGLOBAL g);
-
- // Database routines
- virtual bool OpenTableFile(PGLOBAL g);
- virtual int WriteBuffer(PGLOBAL g);
- virtual int DeleteRecords(PGLOBAL g, int irc);
- virtual void CloseTableFile(PGLOBAL g, bool abort);
-
- // Specific functions
- virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp);
- virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp);
-
- // Members
- char* Memory; // Pointer on file mapping view.
- char* *Memcol; // Pointer on column start.
- }; // end of class VCMFAM
-
-/***********************************************************************/
-/* This is the DOS/UNIX Access Method class declaration for files */
-/* in full vertical format. Each column is contained in a separate */
-/* file whose name is the table name followed by the column number. */
-/***********************************************************************/
-class DllExport VECFAM : public VCTFAM {
- friend class TDBVCT;
- friend class VCTCOL;
- public:
- // Constructor
- VECFAM(PVCTDEF tdp);
- VECFAM(PVECFAM txfp);
-
- // Implementation
- virtual PTXF Duplicate(PGLOBAL g)
- {return (PTXF)new(g) VECFAM(this);}
-
- // Methods
- virtual bool AllocateBuffer(PGLOBAL g);
- virtual bool InitInsert(PGLOBAL g);
- virtual void ResetBuffer(PGLOBAL g);
-
- // Database routines
- virtual bool OpenTableFile(PGLOBAL g);
- virtual int WriteBuffer(PGLOBAL g);
- virtual int DeleteRecords(PGLOBAL g, int irc);
- virtual void CloseTableFile(PGLOBAL g, bool abort);
-
- // Specific functions
- virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp);
- virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp);
-
- protected:
- virtual bool OpenTempFile(PGLOBAL g);
- virtual bool MoveLines(PGLOBAL g);
- virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
- virtual int RenameTempFile(PGLOBAL g, bool abort);
- bool OpenColumnFile(PGLOBAL g, char *opmode, int i);
-
- // Members
- FILE* *Streams; // Points to Dos file structure array
- FILE* *T_Streams; // Points to temp file structure array
- PFBLOCK *To_Fbs; // Pointer to file block array
- PFBLOCK *T_Fbs; // Pointer to temp file block array
- void* *To_Bufs; // Pointer to col val block array
- bool InitUpdate; // Used to initialize updating
- }; // end of class VECFAM
-
-/***********************************************************************/
-/* This is the DOS/UNIX Access Method class declaration for files */
-/* in full vertical format accessed using file mapping. */
-/***********************************************************************/
-class DllExport VMPFAM : public VCMFAM {
- friend class TDBVCT;
- friend class VCTCOL;
- public:
- // Constructor
- VMPFAM(PVCTDEF tdp);
- VMPFAM(PVMPFAM txfp);
-
- // Implementation
- virtual PTXF Duplicate(PGLOBAL g)
- {return (PTXF)new(g) VMPFAM(this);}
-
- // Methods
- virtual bool AllocateBuffer(PGLOBAL g);
-
- // Database routines
- virtual bool OpenTableFile(PGLOBAL g);
- virtual int DeleteRecords(PGLOBAL g, int irc);
- virtual void CloseTableFile(PGLOBAL g, bool abort);
-
- protected:
- bool MapColumnFile(PGLOBAL g, MODE mode, int i);
-
- // Members
- PFBLOCK *To_Fbs; // Pointer to file block array
- }; // end of class VMPFAM
-
-/***********************************************************************/
-/* This is the DOS/UNIX Access Method class declaration for files */
-/* in (possibly blocked) vector format that can be larger than 2GB. */
-/***********************************************************************/
-class BGVFAM : public VCTFAM {
- friend class VCTCOL;
- public:
- // Constructors
- BGVFAM(PVCTDEF tdp);
- BGVFAM(PBGVFAM txfp);
-
- // Implementation
- virtual PTXF Duplicate(PGLOBAL g)
- {return (PTXF)new(g) BGVFAM(this);}
-
- // Methods
- virtual bool AllocateBuffer(PGLOBAL g);
-
- // Database routines
- virtual bool OpenTableFile(PGLOBAL g);
- virtual int WriteBuffer(PGLOBAL g);
- virtual int DeleteRecords(PGLOBAL g, int irc);
- virtual void CloseTableFile(PGLOBAL g, bool abort);
- virtual void Rewind(void);
-
- // Specific functions
- virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp);
- virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp);
-
- protected:
- bool BigSeek(PGLOBAL g, HANDLE h, BIGINT pos, bool b = false);
- bool BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req);
- bool BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req);
- virtual bool MakeEmptyFile(PGLOBAL g, char *fn);
- virtual bool OpenTempFile(PGLOBAL g);
- virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
- virtual bool CleanUnusedSpace(PGLOBAL g);
- virtual bool SetBlockInfo(PGLOBAL g);
- virtual int GetBlockInfo(PGLOBAL g);
-
- // Members
- HANDLE Hfile; // Handle to big file
- HANDLE Tfile; // Handle to temporary file
- BIGINT *BigDep; // Pointer to col start position array
- }; // end of class BGVFAM
-
-#endif // __FILAMVCT__
-
+/************** FilAMVct H Declares Source Code File (.H) **************/ +/* Name: FILAMVCT.H Version 1.5 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */ +/* */ +/* This file contains the VCT file access method classes declares. */ +/***********************************************************************/ +#ifndef __FILAMVCT__ +#define __FILAMVCT__ + +#include "filamfix.h" + +typedef class VCTFAM *PVCTFAM; +typedef class VCTCOL *PVCTCOL; +typedef class VCMFAM *PVCMFAM; +typedef class VECFAM *PVECFAM; +typedef class VMPFAM *PVMPFAM; +typedef class BGVFAM *PBGVFAM; + +/***********************************************************************/ +/* This is the DOS/UNIX Access Method class declaration for files */ +/* in vector format. If MaxBlk=0, each block containing "Elements" */ +/* records, values of each columns are consecutively stored (vector). */ +/* Otherwise, data is arranged by column in the file and MaxBlk is */ +/* used to set the maximum number of blocks. This leave some white */ +/* space allowing to insert new values up to this maximum size. */ +/***********************************************************************/ +class DllExport VCTFAM : public FIXFAM { + friend class TDBVCT; + friend class VCTCOL; + public: + // Constructor + VCTFAM(PVCTDEF tdp); + VCTFAM(PVCTFAM txfp); + + // Implementation + virtual AMT GetAmType(void) {return TYPE_AM_VCT;} + virtual PTXF Duplicate(PGLOBAL g) + {return (PTXF)new(g) VCTFAM(this);} + virtual int GetFileLength(PGLOBAL g); + + // Methods + virtual void Reset(void); + virtual int MaxBlkSize(PGLOBAL g, int s); + virtual bool AllocateBuffer(PGLOBAL g); + virtual bool InitInsert(PGLOBAL g); + virtual void ResetBuffer(PGLOBAL g) {} + virtual int Cardinality(PGLOBAL g); + virtual int GetRowID(void); + + // Database routines + virtual bool OpenTableFile(PGLOBAL g); + virtual int ReadBuffer(PGLOBAL g); + virtual int WriteBuffer(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); + virtual void Rewind(void); + + // Specific functions + virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp); + virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp); + + protected: + virtual bool MakeEmptyFile(PGLOBAL g, char *fn); + virtual bool OpenTempFile(PGLOBAL g); + virtual bool MoveLines(PGLOBAL g) {return false;} + virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL); + virtual bool CleanUnusedSpace(PGLOBAL g); + virtual bool MakeDeletedFile(PGLOBAL g); + virtual int GetBlockInfo(PGLOBAL g); + virtual bool SetBlockInfo(PGLOBAL g); + bool ResetTableSize(PGLOBAL g, int block, int last); + + // Members + char *NewBlock; // To block written on Insert + char *Colfn; // Pattern for column file names (VEC) + char *Tempat; // Pattern for temp file names (VEC) + int *Clens; // Pointer to col size array + int *Deplac; // Pointer to col start position array + bool *Isnum; // Pointer to buffer type isnum result + bool AddBlock; // True when adding new blocks on Insert + bool Split; // true: split column file vector format + int Header; // 0: no, 1: separate, 2: in data file + int MaxBlk; // Max number of blocks (True vector format) + int Bsize; // Because Nrec can be modified + int Ncol; // The number of columns; + }; // end of class VCTFAM + +/***********************************************************************/ +/* This is the DOS/UNIX Access Method class declaration for files */ +/* in vector format accessed using file mapping. */ +/***********************************************************************/ +class DllExport VCMFAM : public VCTFAM { + friend class TDBVCT; + friend class VCTCOL; + public: + // Constructor + VCMFAM(PVCTDEF tdp); + VCMFAM(PVCMFAM txfp); + + // Implementation + virtual AMT GetAmType(void) {return TYPE_AM_VMP;} + virtual PTXF Duplicate(PGLOBAL g) + {return (PTXF)new(g) VCMFAM(this);} + + // Methods + virtual bool AllocateBuffer(PGLOBAL g); + virtual bool InitInsert(PGLOBAL g); + + // Database routines + virtual bool OpenTableFile(PGLOBAL g); + virtual int WriteBuffer(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); + + protected: + // Specific functions + virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL); + virtual bool MakeDeletedFile(PGLOBAL g); + virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp); + virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp); + + // Members + char* Memory; // Pointer on file mapping view. + char* *Memcol; // Pointer on column start. + }; // end of class VCMFAM + +/***********************************************************************/ +/* This is the DOS/UNIX Access Method class declaration for files */ +/* in full vertical format. Each column is contained in a separate */ +/* file whose name is the table name followed by the column number. */ +/***********************************************************************/ +class DllExport VECFAM : public VCTFAM { + friend class TDBVCT; + friend class VCTCOL; + public: + // Constructor + VECFAM(PVCTDEF tdp); + VECFAM(PVECFAM txfp); + + // Implementation + virtual PTXF Duplicate(PGLOBAL g) + {return (PTXF)new(g) VECFAM(this);} + + // Methods + virtual bool AllocateBuffer(PGLOBAL g); + virtual bool InitInsert(PGLOBAL g); + virtual void ResetBuffer(PGLOBAL g); + + // Database routines + virtual bool OpenTableFile(PGLOBAL g); + virtual int WriteBuffer(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); + + // Specific functions + virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp); + virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp); + + protected: + virtual bool OpenTempFile(PGLOBAL g); + virtual bool MoveLines(PGLOBAL g); + virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL); + virtual int RenameTempFile(PGLOBAL g); + virtual bool MakeDeletedFile(PGLOBAL g); + bool OpenColumnFile(PGLOBAL g, char *opmode, int i); + + // Members + FILE* *Streams; // Points to Dos file structure array + FILE* *T_Streams; // Points to temp file structure array + PFBLOCK *To_Fbs; // Pointer to file block array + PFBLOCK *T_Fbs; // Pointer to temp file block array + void* *To_Bufs; // Pointer to col val block array + bool InitUpdate; // Used to initialize updating + }; // end of class VECFAM + +/***********************************************************************/ +/* This is the DOS/UNIX Access Method class declaration for files */ +/* in full vertical format accessed using file mapping. */ +/***********************************************************************/ +class DllExport VMPFAM : public VCMFAM { + friend class TDBVCT; + friend class VCTCOL; + public: + // Constructor + VMPFAM(PVCTDEF tdp); + VMPFAM(PVMPFAM txfp); + + // Implementation + virtual PTXF Duplicate(PGLOBAL g) + {return (PTXF)new(g) VMPFAM(this);} + + // Methods + virtual bool AllocateBuffer(PGLOBAL g); + + // Database routines + virtual bool OpenTableFile(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); + + protected: + virtual bool MakeDeletedFile(PGLOBAL g); + bool MapColumnFile(PGLOBAL g, MODE mode, int i); + + // Members + PFBLOCK *To_Fbs; // Pointer to file block array + }; // end of class VMPFAM + +/***********************************************************************/ +/* This is the DOS/UNIX Access Method class declaration for files */ +/* in (possibly blocked) vector format that can be larger than 2GB. */ +/***********************************************************************/ +class BGVFAM : public VCTFAM { + friend class VCTCOL; + public: + // Constructors + BGVFAM(PVCTDEF tdp); + BGVFAM(PBGVFAM txfp); + + // Implementation + virtual PTXF Duplicate(PGLOBAL g) + {return (PTXF)new(g) BGVFAM(this);} + + // Methods + virtual bool AllocateBuffer(PGLOBAL g); + + // Database routines + virtual bool OpenTableFile(PGLOBAL g); + virtual int WriteBuffer(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); + virtual void Rewind(void); + + // Specific functions + virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp); + virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp); + + protected: + bool BigSeek(PGLOBAL g, HANDLE h, BIGINT pos, bool b = false); + bool BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req); + bool BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req); + virtual bool MakeEmptyFile(PGLOBAL g, char *fn); + virtual bool OpenTempFile(PGLOBAL g); + virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL); + virtual bool CleanUnusedSpace(PGLOBAL g); + virtual bool SetBlockInfo(PGLOBAL g); + virtual int GetBlockInfo(PGLOBAL g); + + // Members + HANDLE Hfile; // Handle to big file + HANDLE Tfile; // Handle to temporary file + BIGINT *BigDep; // Pointer to col start position array + }; // end of class BGVFAM + +#endif // __FILAMVCT__ + diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp index 8e4bce2bf3e..8473011ab8b 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamzip.cpp @@ -1059,6 +1059,31 @@ int ZLBFAM::GetNextPos(void) } // end of GetNextPos /***********************************************************************/ +/* SetPos: Replace the table at the specified position. */ +/***********************************************************************/ +bool ZLBFAM::SetPos(PGLOBAL g, int pos) + { + sprintf(g->Message, MSG(NO_SETPOS_YET), "ZIP"); + return true; +#if 0 // All this must be checked + if (pos < 0) { + strcpy(g->Message, MSG(INV_REC_POS)); + return true; + } // endif recpos + + CurBlk = pos / Nrec; + CurNum = pos % Nrec; +#if defined(_DEBUG) + num_eq[(CurBlk == OldBlk) ? 1 : 0]++; +#endif + + // Indicate the table position was externally set + Placed = true; + return false; +#endif // 0 + } // end of SetPos + +/***********************************************************************/ /* ReadBuffer: Read one line for a text file. */ /***********************************************************************/ int ZLBFAM::ReadBuffer(PGLOBAL g) diff --git a/storage/connect/filamzip.h b/storage/connect/filamzip.h index d0b03f8cd9a..6d27cb67e81 100644 --- a/storage/connect/filamzip.h +++ b/storage/connect/filamzip.h @@ -149,6 +149,7 @@ class DllExport ZLBFAM : public BLKFAM { // Methods
virtual int GetFileLength(PGLOBAL g);
+ virtual bool SetPos(PGLOBAL g, int recpos); virtual bool AllocateBuffer(PGLOBAL g);
virtual int ReadBuffer(PGLOBAL g);
virtual int WriteBuffer(PGLOBAL g);
diff --git a/storage/connect/global.h b/storage/connect/global.h index d7cab0f543f..d35cef2de6f 100644 --- a/storage/connect/global.h +++ b/storage/connect/global.h @@ -85,6 +85,7 @@ #define TYPE_INT 7 #define TYPE_DECIM 9 #define TYPE_BIN 10 +#define TYPE_PCHAR 11 #if defined(OS32) #define SYS_STAMP "OS32" diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index eacfe293b7c..3d57ae9aaaa 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -558,7 +558,6 @@ ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg) nox= false; abort= false; indexing= -1; - only= -1; locked= 0; part_id= NULL; data_file_name= NULL; @@ -1593,7 +1592,6 @@ int ha_connect::CloseTable(PGLOBAL g) indexing= -1; nox= false; abort= false; - only= -1; return rc; } // end of CloseTable @@ -2513,7 +2511,7 @@ ha_rows ha_connect::records() if (!valid_info) info(HA_STATUS_VARIABLE); - if (tdbp && tdbp->Cardinality(NULL)) + if (tdbp) return stats.records; else return HA_POS_ERROR; @@ -2877,13 +2875,13 @@ int ha_connect::index_init(uint idx, bool sorted) xmod= MODE_READX; if (!(rc= rnd_init(0))) { - if (xmod == MODE_READX) { +// if (xmod == MODE_READX) { active_index= idx; indexing= IsUnique(idx) ? 1 : 2; - } else { - active_index= MAX_KEY; - indexing= 0; - } // endif xmod +// } else { +// active_index= MAX_KEY; +// indexing= 0; +// } // endif xmod } //endif rc @@ -2893,17 +2891,11 @@ int ha_connect::index_init(uint idx, bool sorted) if ((rc= rnd_init(0))) DBUG_RETURN(rc); - if ((xmod == MODE_UPDATE && ((TDBASE*)tdbp)->IsUsingTemp(g)) || - xmod == MODE_DELETE || locked == 2) { + if (locked == 2) { // Indexes are not updated in lock write mode - // and cannot be used for DELETE or UPDATE using temp file. - if (locked == 2 || xmod == MODE_DELETE || !IsUnique(idx)) { - active_index= MAX_KEY; - indexing= 0; - DBUG_RETURN(0); - } else - only= 1; // Indexing acceptable for only one value - + active_index= MAX_KEY; + indexing= 0; + DBUG_RETURN(0); } // endif locked indexing= CntIndexInit(g, tdbp, (signed)idx); @@ -2922,6 +2914,7 @@ int ha_connect::index_init(uint idx, bool sorted) } else // Void table indexing= 0; + rc= 0; } // endif indexing if (xtrace) @@ -3017,16 +3010,16 @@ int ha_connect::index_read(uchar * buf, const uchar * key, uint key_len, if (xtrace > 1) htrc("%p index_read: op=%d\n", this, op); - if ((indexing > 0 && (only < 0 || (only == 1 && op == OP_EQ))) - || GetIndexType(GetRealType()) == 2) { + if (indexing > 0) { rc= ReadIndexed(buf, op, key, key_len); - only= (only == 1) ? 0 : -1; - } else { - nox= true; // To block making indexes - abort= true; // Don't rename temp file - strcpy(xp->g->Message, "Cannot use indexing for this command"); + + if (rc == HA_ERR_INTERNAL_ERROR) { + nox= true; // To block making indexes + abort= true; // Don't rename temp file + } // endif rc + + } else rc= HA_ERR_INTERNAL_ERROR; // HA_ERR_KEY_NOT_FOUND ? - } // endelse DBUG_RETURN(rc); } // end of index_read @@ -4291,7 +4284,7 @@ ha_rows ha_connect::records_in_range(uint inx, key_range *min_key, if (xtrace) htrc("records_in_range: inx=%d indexing=%d\n", inx, indexing); - if (indexing > 0 && only < 0) { + if (indexing > 0) { int nval; uint len[2]; const uchar *key[2]; @@ -4312,10 +4305,9 @@ ha_rows ha_connect::records_in_range(uint inx, key_range *min_key, else rows= (ha_rows)nval; - } else if (indexing == 0) { + } else if (indexing == 0) rows= 100000000; // Don't use missing index - only= -1; - } else + else rows= HA_POS_ERROR; DBUG_RETURN(rows); diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h index 610e9019b60..f12582b9b19 100644 --- a/storage/connect/ha_connect.h +++ b/storage/connect/ha_connect.h @@ -535,7 +535,6 @@ protected: bool nox; // True when index should not be made bool abort; // True after error in UPDATE/DELETE int indexing; // Type of indexing for CONNECT - int only; // If only one action is accepted int locked; // Table lock MY_BITMAP *part_id; // Columns used for partition func THR_LOCK_DATA lock_data; diff --git a/storage/connect/macutil.cpp b/storage/connect/macutil.cpp index 3069aa71cd6..4d3022b91b6 100644 --- a/storage/connect/macutil.cpp +++ b/storage/connect/macutil.cpp @@ -103,7 +103,7 @@ int MACINFO::GetNadap(PGLOBAL g) } // endif MaxSize return N; - } // end of GetMaxSize + } // end of GetNadap /***********************************************************************/ /* GetMacInfo: Get info for all found adapters. */ diff --git a/storage/connect/mysql-test/connect/r/part_table.result b/storage/connect/mysql-test/connect/r/part_table.result index 4fded3e992b..09d46687f00 100644 --- a/storage/connect/mysql-test/connect/r/part_table.result +++ b/storage/connect/mysql-test/connect/r/part_table.result @@ -144,14 +144,16 @@ SELECT * FROM t1 WHERE id = 35; id msg 35 thirty five UPDATE t1 SET msg = 'number' WHERE id in (60,72); -ERROR HY000: Got error 122 'Remote: Got error 122 'Cannot use indexing for this command' from CONNECT' from CONNECT +Warnings: +Note 1105 xt3: 2 affected rows +Note 1105 xt3: 0 affected rows UPDATE t1 SET msg = 'soixante' WHERE id = 60; Warnings: Note 1105 xt3: 1 affected rows SELECT * FROM t1 WHERE id > 50; id msg 60 soixante -72 seventy two +72 number 81 eighty one UPDATE t1 SET msg = 'big' WHERE id > 50; Warnings: @@ -173,7 +175,20 @@ id msg 60 big 81 big DELETE FROM t1 WHERE id in (60,72); -ERROR HY000: Got error 122 'Remote: Got error 122 'Cannot use indexing for this command' from CONNECT' from CONNECT +Warnings: +Note 1105 xt3: 2 affected rows +Note 1105 xt3: 0 affected rows +SELECT * FROM t1; +id msg +4 four +7 sept +1 one +8 eight +40 forty +10 ten +11 eleven +35 thirty five +81 big DROP TABLE t1; DROP TABLE xt1; DROP TABLE xt2; diff --git a/storage/connect/mysql-test/connect/t/part_table.test b/storage/connect/mysql-test/connect/t/part_table.test index a2b88f81c69..34e224efa6f 100644 --- a/storage/connect/mysql-test/connect/t/part_table.test +++ b/storage/connect/mysql-test/connect/t/part_table.test @@ -71,15 +71,14 @@ SELECT * FROM t1; EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 81;
SELECT * FROM t1 WHERE id = 7;
SELECT * FROM t1 WHERE id = 35;
---error ER_GET_ERRMSG
UPDATE t1 SET msg = 'number' WHERE id in (60,72);
UPDATE t1 SET msg = 'soixante' WHERE id = 60;
SELECT * FROM t1 WHERE id > 50;
UPDATE t1 SET msg = 'big' WHERE id > 50;
UPDATE t1 SET msg = 'sept' WHERE id = 7;
SELECT * FROM t1;
---error ER_GET_ERRMSG
DELETE FROM t1 WHERE id in (60,72);
+SELECT * FROM t1;
DROP TABLE t1;
DROP TABLE xt1;
DROP TABLE xt2;
diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index e0022baed93..1e540dfb2fe 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -567,6 +567,7 @@ DllExport PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids, /* Exported utility routines. */ /***********************************************************************/ DllExport FILE *PlugOpenFile(PGLOBAL, LPCSTR, LPCSTR); +DllExport FILE *PlugReopenFile(PGLOBAL, PFBLOCK, LPCSTR); DllExport int PlugCloseFile(PGLOBAL, PFBLOCK, bool all = false); DllExport void PlugCleanup(PGLOBAL, bool); DllExport bool GetPromptAnswer(PGLOBAL, char *); diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index 329b78c0a1a..66f7332c56a 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -836,6 +836,23 @@ FILE *PlugOpenFile(PGLOBAL g, LPCSTR fname, LPCSTR ftype) /* Close file routine: the purpose of this routine is to avoid */ /* double closing that freeze the system on some Unix platforms. */ /***********************************************************************/ +FILE *PlugReopenFile(PGLOBAL g, PFBLOCK fp, LPCSTR md) + { + FILE *fop; + + if ((fop = global_fopen(g, MSGID_OPEN_MODE_STRERROR, fp->Fname, md))) { + fp->Count = 1; + fp->Type = TYPE_FB_FILE; + fp->File = fop; + } /* endif fop */ + + return (fop); + } // end of PlugOpenFile + +/***********************************************************************/ +/* Close file routine: the purpose of this routine is to avoid */ +/* double closing that freeze the system on some Unix platforms. */ +/***********************************************************************/ int PlugCloseFile(PGLOBAL g, PFBLOCK fp, bool all) { int rc = 0; diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp index d04e1c61dcd..4a04b0c2db4 100644 --- a/storage/connect/tabdos.cpp +++ b/storage/connect/tabdos.cpp @@ -72,11 +72,11 @@ extern "C" int trace; #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); /* --------------------------- Class DOSDEF -------------------------- */ @@ -132,8 +132,8 @@ bool DOSDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Compressed = GetIntCatInfo("Compressed", 0); Mapped = GetBoolCatInfo("Mapped", map); - Block = GetIntCatInfo("Blocks", 0); - Last = GetIntCatInfo("Last", 0); +//Block = GetIntCatInfo("Blocks", 0); +//Last = GetIntCatInfo("Last", 0); Ending = GetIntCatInfo("Ending", CRLF); if (Recfm == RECFM_FIX || Recfm == RECFM_BIN) { @@ -168,12 +168,12 @@ bool DOSDEF::GetOptFileName(PGLOBAL g, char *filename) case RECFM_DBF: ftype = ".dbp"; break; default: sprintf(g->Message, MSG(INVALID_FTYPE), Recfm); - return TRUE; + return true; } // endswitch Ftype PlugSetPath(filename, Ofn, GetPath()); strcat(PlugRemoveType(filename, filename), ftype); - return FALSE; + return false; } // end of GetOptFileName /***********************************************************************/ @@ -253,6 +253,10 @@ bool DOSDEF::DeleteIndexFile(PGLOBAL g, PIXDEF pxdf) #endif char direc[_MAX_DIR]; char fname[_MAX_FNAME]; + bool all = !pxdf; + + if (all) + pxdf = To_Indx; for (; pxdf; pxdf = pxdf->GetNext()) { _splitpath(Ofn, drive, direc, fname, NULL); @@ -260,10 +264,16 @@ bool DOSDEF::DeleteIndexFile(PGLOBAL g, PIXDEF pxdf) _makepath(filename, drive, direc, fname, ftype); PlugSetPath(filename, filename, GetPath()); #if defined(WIN32) - rc |= !DeleteFile(filename); + if (!DeleteFile(filename)) + rc |= (GetLastError() != ERROR_FILE_NOT_FOUND); #else // UNIX - rc |= remove(filename); + if (remove(filename)) + rc |= (errno != ENOENT); #endif // UNIX + + if (!all) + break; + } // endfor pxdf } else { // !sep @@ -271,9 +281,11 @@ bool DOSDEF::DeleteIndexFile(PGLOBAL g, PIXDEF pxdf) PlugSetPath(filename, Ofn, GetPath()); strcat(PlugRemoveType(filename, filename), ftype); #if defined(WIN32) - rc = !DeleteFile(filename); + if (!DeleteFile(filename)) + rc = (GetLastError() != ERROR_FILE_NOT_FOUND); #else // UNIX - rc = remove(filename); + if (remove(filename)) + rc = (errno != ENOENT); #endif // UNIX } // endif sep @@ -480,6 +492,14 @@ int TDBDOS::ResetTableOpt(PGLOBAL g, bool dop, bool dox) { int prc = RC_OK, rc = RC_OK; + if (!GetFileLength(g)) { + // Void table, delete all opt and index files + PDOSDEF defp = (PDOSDEF)To_Def; + + defp->RemoveOptValues(g); + return (defp->DeleteIndexFile(g, NULL)) ? RC_INFO : RC_OK; + } // endif GetFileLength + MaxSize = -1; // Size must be recalculated Cardinal = -1; // as well as Cardinality @@ -489,6 +509,10 @@ int TDBDOS::ResetTableOpt(PGLOBAL g, bool dop, bool dox) //To_BlkIdx = NULL; // and index filtering To_BlkFil = NULL; // and block filtering + // After the table was modified the indexes + // are invalid and we should mark them as such... + (void)((PDOSDEF)To_Def)->InvalidateIndex(g); + if (dop) { Columns = NULL; // Not used anymore @@ -502,9 +526,9 @@ int TDBDOS::ResetTableOpt(PGLOBAL g, bool dop, bool dox) Txfp = new(g) ZIPFAM((PDOSDEF)To_Def); } else if (Txfp->GetAmType() == TYPE_AM_ZLIB) { Txfp->Reset(); - ((PZLBFAM)Txfp)->SetOptimized(FALSE); + ((PZLBFAM)Txfp)->SetOptimized(false); #endif // ZIP_SUPPORT - } else // (Txfp->GetAmType() == TYPE_AM_BLK) + } else if (Txfp->GetAmType() == TYPE_AM_BLK) Txfp = new(g) DOSFAM((PDOSDEF)To_Def); Txfp->SetTdbp(this); @@ -527,12 +551,8 @@ int TDBDOS::ResetTableOpt(PGLOBAL g, bool dop, bool dox) 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. + if (PlgGetUser(g)->Check & CHK_OPT) + // We must remake all indexes. rc = MakeIndex(g, NULL, false); rc = (rc == RC_INFO) ? prc : rc; @@ -547,10 +567,10 @@ int TDBDOS::ResetTableOpt(PGLOBAL g, bool dop, bool dox) /***********************************************************************/ int TDBDOS::MakeBlockValues(PGLOBAL g) { - int i, lg, nrec, rc; + int i, lg, nrec, rc, n = 0; int curnum, curblk, block, last, savndv, savnbm; void *savmin, *savmax; - bool blocked, xdb2 = FALSE; + bool blocked, xdb2 = false; //POOLHEADER save; PCOLDEF cdp; PDOSDEF defp = (PDOSDEF)To_Def; @@ -602,17 +622,17 @@ int TDBDOS::MakeBlockValues(PGLOBAL g) /* Allocate the blocks for clustered columns. */ /*********************************************************************/ blocked = Txfp->Blocked; // Save - Txfp->Blocked = TRUE; // So column block can be allocated + 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); + cdp->SetXdb2(true); savndv = cdp->GetNdv(); cdp->SetNdv(0); // Reset Dval number of values - xdb2 = TRUE; + xdb2 = true; savmax = cdp->GetDval(); cdp->SetDval(PlugSubAlloc(g, NULL, cdp->GetFreq() * lg)); savnbm = cdp->GetNbm(); @@ -632,7 +652,7 @@ int TDBDOS::MakeBlockValues(PGLOBAL g) cdp->SetDval(savmax); // is not greater than this one. cdp->SetNdv(savndv); } else { - cdp->SetXdb2(FALSE); // Maxbmp may have been reset + cdp->SetXdb2(false); // Maxbmp may have been reset savmin = cdp->GetMin(); savmax = cdp->GetMax(); cdp->SetMin(PlugSubAlloc(g, NULL, block * lg)); @@ -651,8 +671,11 @@ int TDBDOS::MakeBlockValues(PGLOBAL g) } // endif Clustered -//if (!colp) -// return RC_INFO; + // No optimised columns. Still useful for blocked variable tables. + if (!colp && defp->Recfm != RECFM_VAR) { + strcpy(g->Message, "No optimised columns"); + return RC_INFO; + } // endif colp Txfp->Blocked = blocked; @@ -723,33 +746,36 @@ int TDBDOS::MakeBlockValues(PGLOBAL g) 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 defined(PROG_INFO) if (!dup->Step) { strcpy(g->Message, MSG(OPT_CANCELLED)); goto err; } else -#endif // THREAD dup->ProgCur = GetProgCur(); -#endif // SOCKET_MODE || THREAD +#endif // PROG_INFO + n++; // Used to calculate block and last } // endwhile if (rc == RC_EF) { Txfp->Nrec = nrec; +#if 0 // No good because Curblk and CurNum after EOF are different + // depending on whether the file is mapped or not mapped. if (blocked) { - Txfp->Block = Txfp->CurBlk + 1; - Txfp->Last = (Txfp->CurNum) ? Txfp->CurNum + 1 : nrec; +// Txfp->Block = Txfp->CurBlk + 1; + Txfp->Last = (Txfp->CurNum) ? Txfp->CurNum : nrec; +// Txfp->Last = (Txfp->CurNum) ? Txfp->CurNum + 1 : nrec; + Txfp->Block = Txfp->CurBlk + (Txfp->Last == nrec ? 0 : 1); } else { Txfp->Block = curblk + 1; Txfp->Last = last; } // endif blocked +#endif // 0 + + // New values of Block and Last + Txfp->Block = (n + nrec - 1) / nrec; + Txfp->Last = (n % nrec) ? (n % nrec) : nrec; // This is needed to be able to calculate the last block size Txfp->BlkPos[Txfp->Block] = Txfp->GetNextPos(); @@ -791,13 +817,13 @@ 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; + bool rc = false; FILE *opfile; PDOSCOL colp; PDOSDEF defp = (PDOSDEF)To_Def; if (defp->GetOptFileName(g, filename)) - return TRUE; + return true; if (!(opfile = fopen(filename, "wb"))) { sprintf(g->Message, MSG(OPEN_MODE_ERROR), @@ -807,7 +833,7 @@ bool TDBDOS::SaveBlockValues(PGLOBAL g) if (trace) htrc("%s\n", g->Message); - return TRUE; + return true; } // endif opfile if (Ftype == RECFM_VAR || defp->Compressed == 2) { @@ -820,12 +846,12 @@ bool TDBDOS::SaveBlockValues(PGLOBAL g) if (fwrite(n, sizeof(int), NZ, opfile) != NZ) { sprintf(g->Message, MSG(OPT_HEAD_WR_ERR), strerror(errno)); - rc = TRUE; + rc = true; } // endif size if (fwrite(Txfp->BlkPos, lg, block, opfile) != block) { sprintf(g->Message, MSG(OPTBLK_WR_ERR), strerror(errno)); - rc = TRUE; + rc = true; } // endif size block--; // = Txfp->Block; @@ -848,17 +874,17 @@ bool TDBDOS::SaveBlockValues(PGLOBAL g) if (fwrite(n, sizeof(int), NZ + 2, opfile) != NZ + 2) { sprintf(g->Message, MSG(OPT_HEAD_WR_ERR), strerror(errno)); - rc = TRUE; + 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; + 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; + rc = true; } // endif size } else { @@ -866,17 +892,17 @@ bool TDBDOS::SaveBlockValues(PGLOBAL g) if (fwrite(n, sizeof(int), NZ, opfile) != NZ) { sprintf(g->Message, MSG(OPT_HEAD_WR_ERR), strerror(errno)); - rc = TRUE; + 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; + 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; + rc = true; } // endif size } // endif Clustered @@ -899,52 +925,50 @@ 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; + int nrec, block = 0, 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 0 + if (Mode == MODE_INSERT && Txfp->GetAmType() == TYPE_AM_DOS) + return false; +#endif // WIN32 + if (defp->Optimized) - return FALSE; // Already done or to be redone + 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 + + 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); + + if (h != -1) + close(h); + + if (!flen) { + defp->SetOptimized(1); + return false; + } // endif flen - return FALSE; // Opt file does not exist yet - } else if (len < 0) - return TRUE; // Table error + } else + return false; // Not optimisable cdp = defp->GetCols(); i = 1; @@ -958,36 +982,27 @@ bool TDBDOS::GetBlockValues(PGLOBAL g) break; if (!cdp) - return FALSE; // No optimization needed + return false; // No optimization needed if ((len = Cardinality(g)) < 0) - return TRUE; // Table error + return true; // Table error else if (!len) - return FALSE; // File does not exist yet + 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; + 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 + return false; // No saved values 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) { @@ -995,13 +1010,16 @@ bool TDBDOS::GetBlockValues(PGLOBAL g) goto err; } // endif size - if (n[0] != last || n[1] != lg || n[2] != nrec || n[3] != block) { + if (n[1] != lg || n[2] != nrec) { sprintf(g->Message, MSG(OPT_NOT_MATCH), filename); goto err; } // endif - if (newblk) - defp->To_Pos = (int*)PlugSubAlloc(g, NULL, blk * lg); + last = n[0]; + block = n[3]; + blk = block + 1; + + 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)); @@ -1058,7 +1076,7 @@ bool TDBDOS::GetBlockValues(PGLOBAL g) goto err; } // endif size - cdp->SetXdb2(TRUE); + 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) { @@ -1082,25 +1100,23 @@ bool TDBDOS::GetBlockValues(PGLOBAL g) goto err; } // endif size - cdp->SetXdb2(FALSE); + cdp->SetXdb2(false); } // endif n[0] (XDB2) } // endif Clustered defp->SetBlock(block); - - if (newblk) - defp->SetAllocBlks(block); - + defp->Last = last; // For Cardinality + defp->SetAllocBlks(block); defp->SetOptimized(1); fclose(opfile); MaxSize = -1; // Can be refined later - return FALSE; + 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 @@ -1132,17 +1148,17 @@ bool TDBDOS::GetDistinctColumnValues(PGLOBAL g, int nrec) for (colp = (PDOSCOL)Columns; colp; colp = (PDOSCOL)colp->Next) if (colp->Clustered == 2) if (colp->AddDistinctValue(g)) - return TRUE; // Too many distinct values + return true; // Too many distinct values #if defined(SOCKET_MODE) if (SendProgress(dup)) { strcpy(g->Message, MSG(OPT_CANCELLED)); - return TRUE; + return true; } else #elif defined(THREAD) if (!dup->Step) { strcpy(g->Message, MSG(OPT_CANCELLED)); - return TRUE; + return true; } else #endif // THREAD dup->ProgCur = GetProgCur(); @@ -1151,7 +1167,7 @@ bool TDBDOS::GetDistinctColumnValues(PGLOBAL g, int nrec) } // endwhile if (rc != RC_EF) - return TRUE; + return true; // Reset the number of table blocks //nrec = ((PDOSDEF)To_Def)->GetElemt(); (or default value) @@ -1166,7 +1182,7 @@ bool TDBDOS::GetDistinctColumnValues(PGLOBAL g, int nrec) colp->Bmap = AllocValBlock(g, NULL, TYPE_INT, colp->Nbm * blk); } // endif Clustered - return FALSE; + return false; } // end of GetDistinctColumnValues /***********************************************************************/ @@ -1267,7 +1283,7 @@ PBF TDBDOS::InitBlockFilter(PGLOBAL g, PFIL filp) arg[1] = new(g) CONSTANT(vlp); fp = (PBF*)PlugSubAlloc(g, NULL, n * sizeof(PBF)); - cnv[0] = cnv[1] = FALSE; + cnv[0] = cnv[1] = false; if (op == OP_IN) op = OP_EQ; @@ -1318,10 +1334,10 @@ PBF TDBDOS::InitBlockFilter(PGLOBAL g, PFIL filp) 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]; +//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; + bool conv = false, xdb2 = false, ok = false; PXOB *xarg2 = NULL, xp[2]; PCOL colp; //LSTVAL *vlp = NULL; @@ -1575,7 +1591,7 @@ int TDBDOS::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add) (void)dfp->DeleteIndexFile(g, NULL); return RC_OK; } else - fixed = Cardinality(g) >= 0; + fixed = Ftype != RECFM_VAR; // Are we are called from CreateTable or CreateIndex? if (pxdf) { @@ -1783,8 +1799,16 @@ bool TDBDOS::InitialyzeIndex(PGLOBAL g, PIXDEF xdp) } else brc = kxp->Init(g); - if (!brc) + if (!brc) { + if (Txfp->GetAmType() == TYPE_AM_BLK) { + // Cannot use indexing in DOS block mode + Txfp = new(g) DOSFAM((PBLKFAM)Txfp, (PDOSDEF)To_Def); + Txfp->AllocateBuffer(g); + To_BlkFil = NULL; + } // endif AmType + To_Kindex= kxp; + } // endif brc } else brc = true; @@ -1839,12 +1863,12 @@ int TDBDOS::Cardinality(PGLOBAL g) return (Mode == MODE_ANY) ? 1 : n; if (Cardinal < 0) { - if (Mode == MODE_ANY && n == 0) { - // Info command, we must return exact row number + if (!Txfp->Blocked && n == 0) { + // Info command, we try to return exact row number PDOSDEF dfp = (PDOSDEF)To_Def; PIXDEF xdp = dfp->To_Indx; - if (xdp) { + if (xdp && xdp->IsValid()) { // Cardinality can be retreived from one index PXLOAD pxp; @@ -1860,19 +1884,51 @@ int TDBDOS::Cardinality(PGLOBAL g) } // endif Mode - // Using index impossible or failed, do it the hard way - Mode = MODE_READ; - To_Line = (char*)PlugSubAlloc(g, NULL, Lrecl + 1); + if (Mode == MODE_ANY) { + // Using index impossible or failed, do it the hard way + Mode = MODE_READ; + To_Line = (char*)PlugSubAlloc(g, NULL, Lrecl + 1); + + if (Txfp->OpenTableFile(g)) + return (Cardinal = Txfp->Cardinality(g)); + + for (Cardinal = 0; n != RC_EF;) + if (!(n = Txfp->ReadBuffer(g))) + Cardinal++; + + Txfp->CloseTableFile(g, false); + Mode = MODE_ANY; + } else { + // Return the best estimate + int len = GetFileLength(g); + + if (len >= 0) { + int rec; - if (Txfp->OpenTableFile(g)) - return (Cardinal = Txfp->Cardinality(g)); + if (trace) + htrc("Estimating lines len=%d ending=%d/n", + len, ((PDOSDEF)To_Def)->Ending); - for (Cardinal = 0; n != RC_EF;) - if (!(n = Txfp->ReadBuffer(g))) - Cardinal++; + /*************************************************************/ + /* Estimate the number of lines in the table (if not known) */ + /* by dividing the file length by the average record length. */ + /*************************************************************/ + rec = ((PDOSDEF)To_Def)->Ending; + + if (AvgLen <= 0) // No given average estimate + rec += EstimatedLength(g); + else // An estimate was given for the average record length + rec += AvgLen; + + Cardinal = (len + rec - 1) / rec; + + if (trace) + htrc("avglen=%d MaxSize%d\n", rec, Cardinal); + + } // endif len + + } // endif Mode - Txfp->CloseTableFile(g, false); - Mode = MODE_ANY; } else Cardinal = Txfp->Cardinality(g); @@ -1902,15 +1958,9 @@ int TDBDOS::GetMaxSize(PGLOBAL g) /*****************************************************************/ /* Estimate the number of lines in the table (if not known) by */ - /* dividing the file length by average record length. */ + /* dividing the file length by minimum record length. */ /*****************************************************************/ - rec = ((PDOSDEF)To_Def)->Ending; - - if (AvgLen <= 0) // No given average estimate - rec += EstimatedLength(g); - else // An estimate was given for the average record length - rec += AvgLen; - + rec = EstimatedLength(g) + ((PDOSDEF)To_Def)->Ending; MaxSize = (len + rec - 1) / rec; if (trace) @@ -1973,7 +2023,7 @@ bool TDBDOS::OpenDB(PGLOBAL g) Txfp->Rewind(); // see comment in Work.log if (SkipHeader(g)) - return TRUE; + return true; } else /*****************************************************************/ @@ -2001,7 +2051,7 @@ bool TDBDOS::OpenDB(PGLOBAL g) else if (Txfp->GetAmType() == TYPE_AM_ZIP) Txfp = new(g) ZIPFAM((PDOSDEF)To_Def); #endif // ZIP_SUPPORT - else if (Txfp->GetAmType() != TYPE_AM_DOS) + else // if (Txfp->GetAmType() != TYPE_AM_DOS) ??? Txfp = new(g) DOSFAM((PDOSDEF)To_Def); Txfp->SetTdbp(this); @@ -2591,7 +2641,7 @@ bool DOSCOL::SetMinMax(PGLOBAL g) ReadColumn(g); // Extract column value from current line if (CheckSorted(g)) - return TRUE; + return true; if (!tp->Txfp->CurNum) { Min->SetValue(Value, tp->Txfp->CurBlk); @@ -2601,7 +2651,7 @@ bool DOSCOL::SetMinMax(PGLOBAL g) Max->SetMax(Value, tp->Txfp->CurBlk); } // endif CurNum - return FALSE; + return false; } // end of SetMinMax /***********************************************************************/ @@ -2623,7 +2673,7 @@ bool DOSCOL::SetBitMap(PGLOBAL g) ReadColumn(g); if (CheckSorted(g)) - return TRUE; + return true; if (!n) // New block for (m = 0; m < Nbm; m++) @@ -2634,10 +2684,10 @@ bool DOSCOL::SetBitMap(PGLOBAL g) sprintf(g->Message, MSG(DVAL_NOTIN_LIST), Value->GetCharString(buf), Name); - return TRUE; + return true; } else if (i >= dup->Maxbmp) { sprintf(g->Message, MSG(OPT_LOGIC_ERR), i); - return TRUE; + return true; } else { m = i / MAXBMP; #if defined(_DEBUG) @@ -2646,7 +2696,7 @@ bool DOSCOL::SetBitMap(PGLOBAL g) bmp[m] |= (1 << (i % MAXBMP)); } // endif's i - return FALSE; + return false; } // end of SetBitMap /***********************************************************************/ @@ -2660,15 +2710,15 @@ bool DOSCOL::CheckSorted(PGLOBAL g) 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; + Sorted = false; + return true; } else OldVal->SetValue_pval(Value); } else OldVal = AllocateValue(g, Value); - return FALSE; + return false; } // end of CheckSorted /***********************************************************************/ @@ -2677,7 +2727,7 @@ bool DOSCOL::CheckSorted(PGLOBAL g) /***********************************************************************/ bool DOSCOL::AddDistinctValue(PGLOBAL g) { - bool found = FALSE; + bool found = false; int i, m, n; ReadColumn(g); // Extract column value from current line @@ -2691,7 +2741,7 @@ bool DOSCOL::AddDistinctValue(PGLOBAL g) if (m > 0) continue; else if (!m) - found = TRUE; // Already there + found = true; // Already there break; } // endfor n @@ -2701,7 +2751,7 @@ bool DOSCOL::AddDistinctValue(PGLOBAL g) if (Ndv == Freq) { // Too many values because of wrong Freq setting sprintf(g->Message, MSG(BAD_FREQ_SET), Name); - return TRUE; + return true; } // endif Ndv // New value, add it to the list before the nth value @@ -2714,7 +2764,7 @@ bool DOSCOL::AddDistinctValue(PGLOBAL g) Ndv++; } // endif found - return FALSE; + return false; } // end of AddDistinctValue /***********************************************************************/ diff --git a/storage/connect/tabdos.h b/storage/connect/tabdos.h index 3f1fff0c72b..7f2c4f5e7ee 100644 --- a/storage/connect/tabdos.h +++ b/storage/connect/tabdos.h @@ -152,7 +152,7 @@ class DllExport TDBDOS : public TDBASE { virtual int GetFileLength(PGLOBAL g) {return Txfp->GetFileLength(g);} virtual int GetProgMax(PGLOBAL g); virtual int GetProgCur(void); - virtual int GetAffectedRows(void) {return Txfp->GetDelRows();} +//virtual int GetAffectedRows(void) {return Txfp->GetDelRows();} virtual int GetRecpos(void) {return Txfp->GetPos();} virtual bool SetRecpos(PGLOBAL g, int recpos) {return Txfp->SetPos(g, recpos);} @@ -184,7 +184,6 @@ class DllExport TDBDOS : public TDBASE { PBF To_BlkFil; // To evaluation block filter PFIL SavFil; // Saved hidden filter char *To_Line; // Points to current processed line - RECFM Ftype; // File type: 0-var 1-fixed 2-binary (VCT) bool Abort; // TRUE when aborting UPDATE/DELETE int Lrecl; // Logical Record Length int AvgLen; // Logical Record Average Length diff --git a/storage/connect/tabfix.cpp b/storage/connect/tabfix.cpp index f4bdb3011e3..fe04fe52627 100644 --- a/storage/connect/tabfix.cpp +++ b/storage/connect/tabfix.cpp @@ -176,9 +176,11 @@ void TDBFIX::RestoreNrec(void) Txfp->Nrec = (To_Def && To_Def->GetElemt()) ? To_Def->GetElemt() : DOS_BUFF_LEN; Txfp->Blksize = Txfp->Nrec * Txfp->Lrecl; - assert(Cardinal >= 0); - Txfp->Block = (Cardinal > 0) - ? (Cardinal + Txfp->Nrec - 1) / Txfp->Nrec : 0; + + if (Cardinal >= 0) + Txfp->Block = (Cardinal > 0) + ? (Cardinal + Txfp->Nrec - 1) / Txfp->Nrec : 0; + } // endif Padded } // end of RestoreNrec diff --git a/storage/connect/table.cpp b/storage/connect/table.cpp index 4683cabcb41..94c00ebb061 100644 --- a/storage/connect/table.cpp +++ b/storage/connect/table.cpp @@ -143,6 +143,7 @@ TDBASE::TDBASE(PTABDEF tdp) : TDB(tdp) To_Kindex = NULL; To_Xdp = NULL; To_SetCols = NULL; + Ftype = RECFM_NAF; MaxSize = -1; Knum = 0; Read_Only = (tdp) ? tdp->IsReadOnly() : false; @@ -157,6 +158,7 @@ TDBASE::TDBASE(PTDBASE tdbp) : TDB(tdbp) To_Kindex = tdbp->To_Kindex; To_Xdp = tdbp->To_Xdp; To_SetCols = tdbp->To_SetCols; // ??? + Ftype = tdbp->Ftype; MaxSize = tdbp->MaxSize; Knum = tdbp->Knum; Read_Only = tdbp->Read_Only; diff --git a/storage/connect/tabmac.h b/storage/connect/tabmac.h index eb115b18049..5e6c98d68fb 100644 --- a/storage/connect/tabmac.h +++ b/storage/connect/tabmac.h @@ -58,6 +58,7 @@ class TDBMAC : public TDBASE { // Database routines virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); + virtual int Cardinality(PGLOBAL g) {return GetMaxSize(g);} virtual int GetMaxSize(PGLOBAL g); virtual bool OpenDB(PGLOBAL g); virtual int ReadDB(PGLOBAL g); diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index 6c7c58152b3..d84f6c9aab4 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -771,7 +771,8 @@ int TDBMYSQL::Cardinality(PGLOBAL g) Cardinal = myc.GetTableSize(g, query); myc.Close(); - } // endif Cardinal + } else + Cardinal = 10; // To make MySQL happy return Cardinal; } // end of Cardinality diff --git a/storage/connect/tabmysql.h b/storage/connect/tabmysql.h index 5400ab1985a..68cf453a9e6 100644 --- a/storage/connect/tabmysql.h +++ b/storage/connect/tabmysql.h @@ -81,7 +81,7 @@ class TDBMYSQL : public TDBASE { // Methods virtual PTDB CopyOne(PTABS t); - virtual int GetAffectedRows(void) {return AftRows;} +//virtual int GetAffectedRows(void) {return AftRows;} virtual int GetRecpos(void) {return N;} virtual int GetProgMax(PGLOBAL g); virtual void ResetDB(void) {N = 0;} diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp index 0b05fc68299..5542e832a54 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -696,7 +696,8 @@ int TDBODBC::Cardinality(PGLOBAL g) return -3; ocp->Close(); - } // endif Cardinal + } else + Cardinal = 10; // To make MySQL happy return Cardinal; } // end of Cardinality diff --git a/storage/connect/tabodbc.h b/storage/connect/tabodbc.h index e1594b3b44e..360f52c9d21 100644 --- a/storage/connect/tabodbc.h +++ b/storage/connect/tabodbc.h @@ -88,7 +88,7 @@ class TDBODBC : public TDBASE { virtual PSZ GetFile(PGLOBAL g); virtual void SetFile(PGLOBAL g, PSZ fn); virtual void ResetSize(void); - virtual int GetAffectedRows(void) {return AftRows;} +//virtual int GetAffectedRows(void) {return AftRows;} virtual PSZ GetServer(void) {return "ODBC";} virtual int Indexable(void) {return 2;} diff --git a/storage/connect/tabpivot.h b/storage/connect/tabpivot.h index c7248ee2e1d..25d139e895f 100644 --- a/storage/connect/tabpivot.h +++ b/storage/connect/tabpivot.h @@ -105,6 +105,7 @@ class TDBPIVOT : public TDBPRX { // Database routines virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); + virtual int Cardinality(PGLOBAL g) {return (g) ? 10 : 0;} virtual int GetMaxSize(PGLOBAL g); virtual bool OpenDB(PGLOBAL g); virtual int ReadDB(PGLOBAL g); diff --git a/storage/connect/tabsys.cpp b/storage/connect/tabsys.cpp index c7b0baddadc..ae92c0771b6 100644 --- a/storage/connect/tabsys.cpp +++ b/storage/connect/tabsys.cpp @@ -656,7 +656,7 @@ int TDBXIN::GetRecpos(void) { union { short X[2]; // Section and Key offsets - int Xpos; // File position + int Xpos; // File position }; // end of union X[0] = (short)(Section - Seclist); @@ -671,7 +671,7 @@ bool TDBXIN::SetRecpos(PGLOBAL g, int recpos) { union { short X[2]; // Section and Key offsets - int Xpos; // File position + int Xpos; // File position }; // end of union Xpos = recpos; diff --git a/storage/connect/tabsys.h b/storage/connect/tabsys.h index 9741a43434c..aa45c260bc2 100644 --- a/storage/connect/tabsys.h +++ b/storage/connect/tabsys.h @@ -60,7 +60,7 @@ class TDBINI : public TDBASE { virtual PTDB CopyOne(PTABS t);
virtual int GetRecpos(void) {return N;}
virtual int GetProgCur(void) {return N;}
- virtual int GetAffectedRows(void) {return 0;}
+//virtual int GetAffectedRows(void) {return 0;}
virtual PSZ GetFile(PGLOBAL g) {return Ifile;}
virtual void SetFile(PGLOBAL g, PSZ fn) {Ifile = fn;}
virtual void ResetDB(void) {Seclist = Section = NULL; N = 0;}
diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp index 4f2cf3038b9..f5a516ad1d0 100644 --- a/storage/connect/tabtbl.cpp +++ b/storage/connect/tabtbl.cpp @@ -350,7 +350,34 @@ bool TDBTBL::TestFil(PGLOBAL g, PCFIL filp, PTABLE tabp) } // end of TestFil /***********************************************************************/ -/* Sum up the sizes of all sub-tables. */ +/* Sum up the cardinality of all sub-tables. */ +/***********************************************************************/ +int TDBTBL::Cardinality(PGLOBAL g) + { + if (Cardinal < 0) { + int tsz; + + if (!Tablist && InitTableList(g)) + return 0; // Cannot be calculated at this stage + + Cardinal = 0; + + for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext()) { + if ((tsz = tabp->GetTo_Tdb()->Cardinality(g)) < 0) { + Cardinal = -1; + return tsz; + } // endif mxsz + + Cardinal += tsz; + } // endfor i + + } // endif Cardinal + + return Cardinal; + } // end of Cardinality + +/***********************************************************************/ +/* Sum up the maximum sizes of all sub-tables. */ /***********************************************************************/ int TDBTBL::GetMaxSize(PGLOBAL g) { diff --git a/storage/connect/tabtbl.h b/storage/connect/tabtbl.h index 783f3da2c9e..a28d852f332 100644 --- a/storage/connect/tabtbl.h +++ b/storage/connect/tabtbl.h @@ -78,6 +78,7 @@ class DllExport TDBTBL : public TDBPRX { // Database routines
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g); virtual int GetMaxSize(PGLOBAL g);
virtual int RowNumber(PGLOBAL g, bool b = FALSE);
virtual PCOL InsertSpecialColumn(PGLOBAL g, PCOL scp);
diff --git a/storage/connect/tabutil.cpp b/storage/connect/tabutil.cpp index bc048f1bdfe..f4a8f2ee470 100644 --- a/storage/connect/tabutil.cpp +++ b/storage/connect/tabutil.cpp @@ -498,6 +498,21 @@ PCOL TDBPRX::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) } // end of MakeCol /***********************************************************************/ +/* PRX Cardinality: returns the number of rows in the table. */ +/***********************************************************************/ +int TDBPRX::Cardinality(PGLOBAL g) + { + if (Cardinal < 0) { + if (InitTable(g)) + return 0; + + Cardinal = Tdbp->Cardinality(g); + } // endif MaxSize + + return Cardinal; + } // end of GetMaxSize + +/***********************************************************************/ /* PRX GetMaxSize: returns the maximum number of rows in the table. */ /***********************************************************************/ int TDBPRX::GetMaxSize(PGLOBAL g) diff --git a/storage/connect/tabutil.h b/storage/connect/tabutil.h index 5344372a30b..11f18be074a 100644 --- a/storage/connect/tabutil.h +++ b/storage/connect/tabutil.h @@ -76,6 +76,7 @@ class DllExport TDBPRX : public TDBASE { // Database routines virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); virtual bool InitTable(PGLOBAL g); + virtual int Cardinality(PGLOBAL g); virtual int GetMaxSize(PGLOBAL g); virtual bool OpenDB(PGLOBAL g); virtual int ReadDB(PGLOBAL g); diff --git a/storage/connect/tabvct.cpp b/storage/connect/tabvct.cpp index d90ec66c982..043d3c2c496 100644 --- a/storage/connect/tabvct.cpp +++ b/storage/connect/tabvct.cpp @@ -95,7 +95,10 @@ bool VCTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) { DOSDEF::DefineAM(g, "BIN", poff); - Estimate = GetIntCatInfo("Estimate", 0); + if ((Estimate = GetIntCatInfo("Estimate", 0))) + Elemt = MY_MIN(Elemt, Estimate); + + // Split treated as INT to get default value Split = GetIntCatInfo("Split", (Estimate) ? 0 : 1); Header = GetIntCatInfo("Header", 0); @@ -103,7 +106,7 @@ bool VCTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) if (Estimate && !Split && !Header) { char *fn = GetStringCatInfo(g, "Filename", "?"); - // No separate header file fo urbi tables + // No separate header file for urbi tables Header = (*fn == '?') ? 3 : 2; } // endif Estimate @@ -309,8 +312,12 @@ bool TDBVCT::OpenDB(PGLOBAL g) /*********************************************************************/ /* Delete all is not handled using file mapping. */ /*********************************************************************/ - if (Mode == MODE_DELETE && !Next && Txfp->GetAmType() == TYPE_AM_MAP) { - Txfp = new(g) VCTFAM((PVCTDEF)To_Def); + if (Mode == MODE_DELETE && !Next && Txfp->GetAmType() == TYPE_AM_VMP) { + if (IsSplit()) + Txfp = new(g) VECFAM((PVCTDEF)To_Def); + else + Txfp = new(g) VCTFAM((PVCTDEF)To_Def); + Txfp->SetTdbp(this); } // endif Mode diff --git a/storage/connect/tabvct.h b/storage/connect/tabvct.h index b744dbb2529..0a67a5e03b2 100644 --- a/storage/connect/tabvct.h +++ b/storage/connect/tabvct.h @@ -26,7 +26,7 @@ class DllExport VCTDEF : public DOSDEF { /* Logical table description */ friend class VMPFAM;
public:
// Constructor
- VCTDEF(void) {Split = Estimate = Header = 0;}
+ VCTDEF(void) {Split = false; Estimate = Header = 0;}
// Implementation
virtual const char *GetType(void) {return "VCT";}
@@ -40,9 +40,9 @@ class DllExport VCTDEF : public DOSDEF { /* Logical table description */ int MakeFnPattern(char *fpat);
// Members
- int Split; /* Columns in separate files */
+ bool Split; /* Columns in separate files */
int Estimate; /* Estimated maximum size of table */
- int Header; /* 0: no, 1: separate, 2: in data file */
+ int Header; /* 0: no, 1: separate, 2: in data file */
}; // end of VCTDEF
/***********************************************************************/
diff --git a/storage/connect/tabwmi.h b/storage/connect/tabwmi.h index b26f66fb04b..6f25c0de258 100644 --- a/storage/connect/tabwmi.h +++ b/storage/connect/tabwmi.h @@ -75,6 +75,7 @@ class TDBWMI : public TDBASE { // Database routines
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g) {return GetMaxSize(g);} virtual int GetMaxSize(PGLOBAL g);
virtual bool OpenDB(PGLOBAL g);
virtual int ReadDB(PGLOBAL g);
diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp index 8e7618a9dde..e435a49cbd2 100644 --- a/storage/connect/valblk.cpp +++ b/storage/connect/valblk.cpp @@ -101,6 +101,9 @@ PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len, blkp = new(g) TYPBLK<char>(mp, nval, type); break; + case TYPE_PCHAR: + blkp = new(g) PTRBLK(g, mp, nval); + break; default: sprintf(g->Message, MSG(BAD_VALBLK_TYPE), type); return NULL; @@ -1353,6 +1356,18 @@ void DATBLK::SetValue(PSZ p, int n) } // end of SetValue + +/* -------------------------- Class PTRBLK --------------------------- */ + +/***********************************************************************/ +/* Compare two values of the block. */ +/***********************************************************************/ +int PTRBLK::CompVal(int i1, int i2) + { + return (Strp[i1] > Strp[i2]) ? 1 : (Strp[i1] < Strp[i2]) ? (-1) : 0; + } // end of CompVal + + /* -------------------------- Class MBVALS --------------------------- */ /***********************************************************************/ diff --git a/storage/connect/valblk.h b/storage/connect/valblk.h index 67d1c5a27ee..654db0b57b7 100644 --- a/storage/connect/valblk.h +++ b/storage/connect/valblk.h @@ -329,5 +329,28 @@ class DATBLK : public TYPBLK<int> { PVAL Dvalp; // Date value used to convert string }; // end of class DATBLK +/***********************************************************************/ +/* Class PTRBLK: represent a block of char pointers. */ +/* Currently this class is used only by the ARRAY class to make and */ +/* sort a list of char pointers. */ +/***********************************************************************/ +class PTRBLK : public STRBLK { + friend class ARRAY; + friend PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int, + bool, bool, bool); + protected: + // Constructors + PTRBLK(PGLOBAL g, void *mp, int size) : STRBLK(g, mp, size) {} + + // Implementation + + // Methods + virtual void SetValue(PSZ p, int n) {Strp[n] = p;} + virtual int CompVal(int i1, int i2); + + protected: + // Members + }; // end of class PTRBLK + #endif // __VALBLK__H__ diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index 3541ebedd39..4c1c36369ef 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -184,6 +184,7 @@ PSZ GetTypeName(int type) case TYPE_TINY: name = "TINY"; break; case TYPE_DECIM: name = "DECIMAL"; break; case TYPE_BIN: name = "BINARY"; break; + case TYPE_PCHAR: name = "PCHAR"; break; default: name = "UNKNOWN"; break; } // endswitch type @@ -205,6 +206,7 @@ int GetTypeSize(int type, int len) case TYPE_DATE: len = sizeof(int); break; case TYPE_DOUBLE: len = sizeof(double); break; case TYPE_TINY: len = sizeof(char); break; + case TYPE_PCHAR: len = sizeof(char*); break; default: len = 0; } // endswitch type @@ -228,6 +230,7 @@ char *GetFormatType(int type) case TYPE_TINY: c = "T"; break; case TYPE_DECIM: c = "M"; break; case TYPE_BIN: c = "B"; break; + case TYPE_PCHAR: c = "P"; break; } // endswitch type return c; @@ -250,6 +253,7 @@ int GetFormatType(char c) case 'T': type = TYPE_TINY; break; case 'M': type = TYPE_DECIM; break; case 'B': type = TYPE_BIN; break; + case 'P': type = TYPE_PCHAR; break; } // endswitch type return type; diff --git a/storage/connect/xindex.cpp b/storage/connect/xindex.cpp index 4f8cab213fe..12781b2ac05 100755 --- a/storage/connect/xindex.cpp +++ b/storage/connect/xindex.cpp @@ -439,7 +439,7 @@ bool XINDEX::Make(PGLOBAL g, PIXDEF sxp) /* Standard init: read the file and construct the index table. */ /* Note: reading will be sequential as To_Kindex is not set. */ /*********************************************************************/ - for (i = nkey = 0; i < n && rc != RC_EF; i++) { + for (i = nkey = 0; rc != RC_EF; i++) { #if 0 if (!dup->Step) { strcpy(g->Message, MSG(QUERY_CANCELLED)); @@ -555,6 +555,7 @@ bool XINDEX::Make(PGLOBAL g, PIXDEF sxp) if (!Mul) if (Ndif < Num_K) { strcpy(g->Message, MSG(INDEX_NOT_UNIQ)); + brc = true; goto err; } else PlgDBfree(Offset); // Not used anymore @@ -649,9 +650,11 @@ bool XINDEX::Make(PGLOBAL g, PIXDEF sxp) /*********************************************************************/ /* For sorted columns and fixed record size, file position can be */ /* calculated, so the Record array can be discarted. */ + /* Not true for DBF tables because of eventual soft deleted lines. */ /* Note: for Num_K = 1 any non null value is Ok. */ /*********************************************************************/ - if (Srtd && !filp && Tdbp->Ftype != RECFM_VAR) { + if (Srtd && !filp && Tdbp->Ftype != RECFM_VAR + && Tdbp->Txfp->GetAmType() != TYPE_AM_DBF) { Incr = (Num_K > 1) ? To_Rec[1] : Num_K; PlgDBfree(Record); } // endif Srtd diff --git a/storage/connect/xindex.h b/storage/connect/xindex.h index c5ab829b33f..4988a12326a 100644 --- a/storage/connect/xindex.h +++ b/storage/connect/xindex.h @@ -89,6 +89,7 @@ class DllExport INDEXDEF : public BLOCK { /* Index description block */ bool IsUnique(void) {return Unique;} bool IsDynamic(void) {return Dynamic;} bool IsAuto(void) {return AutoInc;} + bool IsValid(void) {return !Invalid;} void SetAuto(bool b) {AutoInc = b;} void SetInvalid(bool b) {Invalid = b;} int GetNparts(void) {return Nparts;} diff --git a/storage/connect/xtable.h b/storage/connect/xtable.h index ff1f0bce899..2d95acdb6d4 100644 --- a/storage/connect/xtable.h +++ b/storage/connect/xtable.h @@ -84,7 +84,7 @@ class DllExport TDB: public BLOCK { // Table Descriptor Block. // Methods 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 Cardinality(PGLOBAL g) {return 0;} virtual int GetMaxSize(PGLOBAL) = 0; virtual int GetProgMax(PGLOBAL) = 0; virtual int GetProgCur(void) = 0; @@ -160,7 +160,7 @@ class DllExport TDBASE : public TDB { virtual PSZ GetPath(void); virtual void PrintAM(FILE *f, char *m); virtual RECFM GetFtype(void) {return RECFM_NAF;} - virtual int GetAffectedRows(void) {return -1;} +//virtual int GetAffectedRows(void) {return -1;} virtual int GetRecpos(void) = 0; virtual bool SetRecpos(PGLOBAL g, int recpos); virtual bool IsReadOnly(void) {return Read_Only;} @@ -197,6 +197,7 @@ class DllExport TDBASE : public TDB { PKXBASE To_Kindex; // Points to table key index PIXDEF To_Xdp; // To the index definition block PCOL To_SetCols; // Points to updated columns + RECFM Ftype; // File type: 0-var 1-fixed 2-binary (VCT) int MaxSize; // Max size in number of lines int Knum; // Size of key arrays bool Read_Only; // True for read only tables |