/*********** 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" #ifdefined(_WIN32) #ifdefined(__BORLANDC__) #define __MFC_COMPAT__ // To define min/max as macro #endif// __BORLANDC__ //#include <windows.h> #else// !_WIN32 #ifdefined(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;
#ifdefined(_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;
/*******************************************************************/ /* 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(); returnfalse;
} // endif len
#ifdefined(_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;
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)); returntrue;
} // endif Mempos
Placed = true; returnfalse;
} // end of SetPos
/***********************************************************************/ /* Record file position in case of UPDATE or DELETE. */ /***********************************************************************/ bool MAPFAM::RecordPos(PGLOBAL)
{
Fpos = Mempos; returnfalse;
} // 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; elseif (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)))
{ #ifdefined(_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 (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;
} elseif ((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);
} elseif (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);
#ifdefined(_WIN32)
DWORD drc = SetFilePointer(fp->Handle, n, NULL, FILE_BEGIN);
/***********************************************************************/ /* 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;
} elseif (Mempos >= Top) { // Are we at the end of the memory if ((rc = GetNext(g)) != RC_OK) return rc;
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;
// 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 -------------------------- */
CurNum = Nrec;
} // end of MPXFAM standard constructor
#if0// 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)); returntrue;
} // endif recpos
// Indicate the table position was externally set
Placed = true; returnfalse;
} // 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;
} elseif (Mempos >= Top) { // Are we at the end of the memory 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;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.