summaryrefslogtreecommitdiffstats
path: root/storage/connect/filamap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/connect/filamap.cpp')
-rw-r--r--storage/connect/filamap.cpp788
1 files changed, 788 insertions, 0 deletions
diff --git a/storage/connect/filamap.cpp b/storage/connect/filamap.cpp
new file mode 100644
index 00000000..4930e394
--- /dev/null
+++ b/storage/connect/filamap.cpp
@@ -0,0 +1,788 @@
+/*********** File AM Map C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: FILAMAP */
+/* ------------- */
+/* Version 1.6 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2020 */
+/* */
+/* 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"
+#include "tabfmt.h"
+
+/* --------------------------- 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->Count) ? To_Fb->Length : TXTFAM::GetFileLength(g);
+
+ if (trace(1))
+ 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];
+ size_t 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;
+
+ if (trace(1))
+ htrc("Mapping file, fp=%p\n", fp);
+
+ } 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(1))
+ htrc("CreateFileMap: %s\n", g->Message);
+
+ return (mode == MODE_READ && rc == ENOENT)
+ ? false : true;
+// ? PushWarning(g, Tdbp) : true; --> assert fails into MariaDB
+ } // endif hFile
+
+ /*******************************************************************/
+ /* Get the file size. */
+ /*******************************************************************/
+ len = (size_t)mm.lenL;
+
+ if (mm.lenH)
+ len += ((size_t)mm.lenH * 0x000000001LL);
+
+ 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 = PlugDup(g, 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(1))
+ 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 (int)(Fpos - Memory);
+ } // end of GetPos
+
+/***********************************************************************/
+/* GetNextPos: return the position of next record. */
+/***********************************************************************/
+int MAPFAM::GetNextPos(void)
+ {
+ return (int)(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)
+ {
+ Fpos = Mempos;
+ return false;
+ } // end of RecordPos
+
+/***********************************************************************/
+/* Initialize Fpos and Mempos for indexed DELETE. */
+/***********************************************************************/
+int MAPFAM::InitDelete(PGLOBAL, int fpos, int spos)
+ {
+ Fpos = Memory + (ptrdiff_t)fpos;
+ Mempos = Memory + (ptrdiff_t)spos;
+ return RC_OK;
+ } // end of InitDelete
+
+/***********************************************************************/
+/* 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 rc, len, n = 1;
+
+ // Are we at the end of the memory
+ if (Mempos >= Top) {
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+ else if (Tdbp->GetAmType() == TYPE_AM_CSV && ((PTDBCSV)Tdbp)->Header)
+ if ((rc = SkipRecord(g, true)) != RC_OK)
+ return rc;
+
+ } // endif Mempos
+
+
+ if (!Placed) {
+ /*******************************************************************/
+ /* Record file position in case of UPDATE or DELETE. */
+ /*******************************************************************/
+ 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:
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+
+ /* falls through */
+ 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 ???
+ if (Mempos == Top) {
+ n = 0;
+ break;
+ } // endif Mempos
+
+ // Set caller line buffer
+ len = (int)(Mempos - Fpos) - n;
+
+ // Don't rely on ENDING setting
+ if (len > 0 && *(Mempos - 2) == '\r')
+ len--; // Line ends by CRLF
+
+ 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 __attribute__((unused)))
+ {
+#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(1))
+ 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(1))
+ htrc("Fpos placed at file top=%p\n", Fpos);
+
+ } // endif irc
+
+ if (Tpos == Spos) {
+ /*******************************************************************/
+ /* First line to delete. Move of eventual preceding lines is */
+ /* not required here, just setting of future Spos and Tpos. */
+ /*******************************************************************/
+ Tpos = Spos = Fpos;
+ } else if ((n = (int)(Fpos - Spos)) > 0) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ memmove(Tpos, Spos, n);
+ Tpos += n;
+
+ if (trace(1))
+ htrc("move %d bytes\n", n);
+
+ } // endif n
+
+ if (irc == RC_OK) {
+ Spos = Mempos; // New start position
+
+ if (trace(1))
+ 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
+
+ if (!Abort) {
+ /*****************************************************************/
+ /* Remove extra records. */
+ /*****************************************************************/
+ n = (int)(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(1))
+ 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
+
+/***********************************************************************/
+/* Table file close routine for MAP access method. */
+/***********************************************************************/
+void MAPFAM::CloseTableFile(PGLOBAL g, bool)
+ {
+ PlugCloseFile(g, To_Fb);
+//To_Fb = NULL; // To get correct file size in Cardinality
+
+ if (trace(1))
+ 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, bool)
+ {
+ 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 rc, 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
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+
+ } else if (++CurNum < Nrec) {
+ Fpos = Mempos;
+ } else {
+ /*******************************************************************/
+ /* New block. */
+ /*******************************************************************/
+ CurNum = 0;
+
+ next:
+ if (++CurBlk >= Block)
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+
+ /*******************************************************************/
+ /* 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:
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+
+ break;
+ 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 ???
+ if (Mempos == Top)
+ break;
+
+ // Set caller line buffer
+ len = (int)(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
+
+/***********************************************************************/
+/* Initialize CurBlk, CurNum, Mempos and Fpos for indexed DELETE. */
+/***********************************************************************/
+int MPXFAM::InitDelete(PGLOBAL, int fpos, int)
+ {
+ Fpos = Memory + Headlen + (ptrdiff_t)fpos * Lrecl;
+ Mempos = Fpos + Lrecl;
+ return RC_OK;
+ } // end of InitDelete
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a mapped Fix file. */
+/***********************************************************************/
+int MPXFAM::ReadBuffer(PGLOBAL g)
+ {
+ int rc;
+
+ /*********************************************************************/
+ /* Sequential block reading when Placed is not true. */
+ /*********************************************************************/
+ if (Placed) {
+ Placed = false;
+ } else if (Mempos >= Top) { // Are we at the end of the memory
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+
+ } else if (++CurNum < Nrec) {
+ Fpos = Mempos;
+ } else {
+ /*******************************************************************/
+ /* New block. */
+ /*******************************************************************/
+ CurNum = 0;
+
+ next:
+ if (++CurBlk >= Block)
+ return GetNext(g);
+
+ /*******************************************************************/
+ /* 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:
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+
+ break;
+ 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 __attribute__((unused)))
+ {
+#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
+