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