mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +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
 | |
| 
 | 
