From 0219ac1e98cc53250a8e165c4b37e83529932256 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Thu, 7 Aug 2014 17:59:21 +0200 Subject: This is a major update that fixes most of the issues and bugs that have been created by the last addition of new CONNECT features. The version previous to this one is a preliminary test version and should not be distributed. - Handle indexed UPDATE/DELETE. Previously this was just tested and an error message send when it could not be done. Now CONNECT can do it in all the cases. It is done by a MRR like tchnique by making a list of all update or delete to do, sort them, then execute them. modified: storage/connect/array.cpp storage/connect/array.h storage/connect/filamap.cpp storage/connect/filamap.h storage/connect/filamdbf.cpp storage/connect/filamfix.cpp storage/connect/filamfix.h storage/connect/filamtxt.cpp storage/connect/filamtxt.h storage/connect/filamvct.cpp storage/connect/filamvct.h storage/connect/filamzip.cpp storage/connect/filamzip.h storage/connect/global.h storage/connect/ha_connect.cc storage/connect/ha_connect.h - Differenciate Cardinality that returns a true or estimated table size and GetMaxSize that return a value equal or greater than the table row number. This fixes the errors of non matching opt files. modified: storage/connect/connect.cc storage/connect/tabdos.cpp storage/connect/tabdos.h storage/connect/tabfix.cpp storage/connect/table.cpp storage/connect/tabmac.h storage/connect/tabmysql.cpp storage/connect/tabmysql.h storage/connect/tabodbc.cpp storage/connect/tabodbc.h storage/connect/tabpivot.h storage/connect/tabtbl.cpp storage/connect/tabtbl.h storage/connect/tabutil.cpp storage/connect/tabutil.h storage/connect/tabwmi.h storage/connect/xtable.h - Fix some errors and issues when making index and opt files. Erase opt and index files for void tables. Fix wrong calculation of Block and Last in MakeBlockValues. Invalidate indexes before making opt file. Fully handle blocked variable tables. Make opt file for blocked variable tables even when they have no optimised colums. modified: storage/connect/tabdos.cpp storage/connect/xindex.h - Fix some errors making index Return an error when the allocation is too small (should not really occur now that GetMaxSize is sure) Don't use XXROW index for DBF tables because of soft deleted lines. modified: storage/connect/xindex.cpp - Typo modified: storage/connect/macutil.cpp storage/connect/tabdos.h storage/connect/tabsys.cpp storage/connect/tabsys.h --- storage/connect/array.cpp | 83 +- storage/connect/array.h | 8 + storage/connect/connect.cc | 4 +- storage/connect/filamap.cpp | 1525 ++++++++++---------- storage/connect/filamap.h | 228 +-- storage/connect/filamdbf.cpp | 27 +- storage/connect/filamfix.cpp | 210 ++- storage/connect/filamfix.h | 179 +-- storage/connect/filamtxt.cpp | 362 ++++- storage/connect/filamtxt.h | 406 +++--- storage/connect/filamvct.cpp | 486 +++++-- storage/connect/filamvct.h | 506 +++---- storage/connect/filamzip.cpp | 25 + storage/connect/filamzip.h | 1 + storage/connect/global.h | 1 + storage/connect/ha_connect.cc | 52 +- storage/connect/ha_connect.h | 1 - storage/connect/macutil.cpp | 2 +- .../connect/mysql-test/connect/r/part_table.result | 21 +- .../connect/mysql-test/connect/t/part_table.test | 3 +- storage/connect/plgdbsem.h | 1 + storage/connect/plgdbutl.cpp | 17 + storage/connect/tabdos.cpp | 354 +++-- storage/connect/tabdos.h | 3 +- storage/connect/tabfix.cpp | 8 +- storage/connect/table.cpp | 2 + storage/connect/tabmac.h | 1 + storage/connect/tabmysql.cpp | 3 +- storage/connect/tabmysql.h | 2 +- storage/connect/tabodbc.cpp | 3 +- storage/connect/tabodbc.h | 2 +- storage/connect/tabpivot.h | 1 + storage/connect/tabsys.cpp | 4 +- storage/connect/tabsys.h | 2 +- storage/connect/tabtbl.cpp | 29 +- storage/connect/tabtbl.h | 1 + storage/connect/tabutil.cpp | 15 + storage/connect/tabutil.h | 1 + storage/connect/tabvct.cpp | 15 +- storage/connect/tabvct.h | 6 +- storage/connect/tabwmi.h | 1 + storage/connect/valblk.cpp | 15 + storage/connect/valblk.h | 23 + storage/connect/value.cpp | 4 + storage/connect/xindex.cpp | 7 +- storage/connect/xindex.h | 1 + storage/connect/xtable.h | 5 +- 47 files changed, 2844 insertions(+), 1812 deletions(-) (limited to 'storage') 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 @@ -765,6 +796,44 @@ bool ARRAY::Sort(PGLOBAL g) return TRUE; } // 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 */ 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 -#else // !WIN32 -#if defined(UNIX) -#include -#include -#else // !UNIX -#include -#endif // !UNIX -#include -#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 +#else // !WIN32 +#if defined(UNIX) +#include +#include +#else // !UNIX +#include +#endif // !UNIX +#include +#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 -------------------------- */ /***********************************************************************/ @@ -79,6 +84,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. */ /***********************************************************************/ @@ -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 */ @@ -525,6 +559,59 @@ bool FIXFAM::MoveIntermediateLines(PGLOBAL g, bool *b) 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 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. */ /***********************************************************************/ @@ -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. */ /*****************************************************************/ @@ -1373,6 +1469,59 @@ bool BGXFAM::MoveIntermediateLines(PGLOBAL g, bool *b) return false; } // 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. */ /***********************************************************************/ @@ -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 */ @@ -920,11 +1000,142 @@ bool DOSFAM::MoveIntermediateLines(PGLOBAL g, bool *b) return false; } // 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 #include -#else // !WIN32 F +#else // !WIN32 #if defined(UNIX) #include #include @@ -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; @@ -1008,6 +1026,63 @@ bool VCTFAM::MoveIntermediateLines(PGLOBAL g, bool *b) return false; } // 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. */ /***********************************************************************/ @@ -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,11 +1786,104 @@ 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. */ /***********************************************************************/ @@ -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; @@ -2412,10 +2560,60 @@ bool VECFAM::MoveIntermediateLines(PGLOBAL g, bool *bn) 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 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); @@ -2982,6 +3198,55 @@ int VMPFAM::DeleteRecords(PGLOBAL g, int 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 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. */ /***********************************************************************/ @@ -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 @@ -1058,6 +1058,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. */ /***********************************************************************/ 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 @@ -832,6 +832,23 @@ FILE *PlugOpenFile(PGLOBAL g, LPCSTR fname, LPCSTR ftype) 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. */ +/***********************************************************************/ +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. */ 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 @@ -497,6 +497,21 @@ PCOL TDBPRX::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) return new(g) PRXCOL(cdp, this, cprec, 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. */ /***********************************************************************/ 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 @@ -100,6 +100,9 @@ PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len, else blkp = new(g) TYPBLK(mp, nval, type); + break; + case TYPE_PCHAR: + blkp = new(g) PTRBLK(g, mp, nval); break; default: sprintf(g->Message, MSG(BAD_VALBLK_TYPE), type); @@ -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 { 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 -- cgit v1.2.1