mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
788 lines
27 KiB
C++
788 lines
27 KiB
C++
/*********** 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))
|
|
snprintf(g->Message, sizeof(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);
|
|
snprintf(g->Message, sizeof(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) {
|
|
snprintf(g->Message, sizeof(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)) {
|
|
snprintf(g->Message, sizeof(g->Message), MSG(FUNCTION_ERROR),
|
|
"SetEndOfFile", GetLastError());
|
|
CloseHandle(fp->Handle);
|
|
return RC_FX;
|
|
} // endif
|
|
|
|
#else // UNIX
|
|
if (ftruncate(fp->Handle, (off_t)n)) {
|
|
snprintf(g->Message, sizeof(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
|
|
|