mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1542 lines
		
	
	
	
		
			52 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1542 lines
		
	
	
	
		
			52 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*********** File AM Fix C++ Program Source Code File (.CPP) ***********/
 | 
						|
/* PROGRAM NAME: FILAMFIX                                              */
 | 
						|
/* -------------                                                       */
 | 
						|
/*  Version 1.6                                                        */
 | 
						|
/*                                                                     */
 | 
						|
/* COPYRIGHT:                                                          */
 | 
						|
/* ----------                                                          */
 | 
						|
/*  (C) Copyright to the author Olivier BERTRAND          2005-2015    */
 | 
						|
/*                                                                     */
 | 
						|
/* WHAT THIS PROGRAM DOES:                                             */
 | 
						|
/* -----------------------                                             */
 | 
						|
/*  This program are the FIX/BIN file access method classes.           */
 | 
						|
/*                                                                     */
 | 
						|
/***********************************************************************/
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Include relevant sections of the System header files.              */
 | 
						|
/***********************************************************************/
 | 
						|
#include "my_global.h"
 | 
						|
#if defined(_WIN32)
 | 
						|
#include <io.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#include <errno.h>
 | 
						|
#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 <sys/stat.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#endif  // !_WIN32
 | 
						|
 | 
						|
#include <m_string.h>
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Include application header files:                                  */
 | 
						|
/*  global.h    is header containing all global declarations.          */
 | 
						|
/*  plgdbsem.h  is header containing the DB application declarations.  */
 | 
						|
/*  filamfix.h  is header containing the file AM classes declarations. */
 | 
						|
/***********************************************************************/
 | 
						|
#include "global.h"
 | 
						|
#include "plgdbsem.h"
 | 
						|
#include "filamfix.h"
 | 
						|
#include "tabdos.h"
 | 
						|
#include "tabfix.h"
 | 
						|
#include "osutil.h"
 | 
						|
 | 
						|
#ifndef INVALID_SET_FILE_POINTER
 | 
						|
#define INVALID_SET_FILE_POINTER  0xFFFFFFFF
 | 
						|
#endif
 | 
						|
 | 
						|
extern int num_read, num_there, num_eq[2];               // Statistics
 | 
						|
 | 
						|
/* --------------------------- Class FIXFAM -------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Constructors.                                                      */
 | 
						|
/***********************************************************************/
 | 
						|
FIXFAM::FIXFAM(PDOSDEF tdp) : BLKFAM(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
 | 
						|
 | 
						|
  } // end of FIXFAM standard constructor
 | 
						|
 | 
						|
FIXFAM::FIXFAM(PFIXFAM txfp) : BLKFAM(txfp)
 | 
						|
  {
 | 
						|
  } // end of FIXFAM copy constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  SetPos: Replace the table at the specified position.               */
 | 
						|
/***********************************************************************/
 | 
						|
bool FIXFAM::SetPos(PGLOBAL g, int pos)
 | 
						|
  {
 | 
						|
  if (pos < 0) {
 | 
						|
    strcpy(g->Message, MSG(INV_REC_POS));
 | 
						|
    return true;
 | 
						|
    } // endif recpos
 | 
						|
 | 
						|
  CurBlk = pos / Nrec;
 | 
						|
  CurNum = pos % Nrec;
 | 
						|
#if defined(_DEBUG)
 | 
						|
  num_eq[(CurBlk == OldBlk) ? 1 : 0]++;
 | 
						|
#endif
 | 
						|
 | 
						|
  // Indicate the table position was externally set
 | 
						|
  Placed = true;
 | 
						|
  return false;
 | 
						|
  } // end of SetPos
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Initialize CurBlk and CurNum for indexed DELETE.                   */
 | 
						|
/***********************************************************************/
 | 
						|
int FIXFAM::InitDelete(PGLOBAL, int fpos, int)
 | 
						|
  {
 | 
						|
  CurBlk = fpos / Nrec;
 | 
						|
  CurNum = fpos % Nrec;
 | 
						|
  return RC_OK;
 | 
						|
  } // end of InitDelete
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Allocate the block buffer for the table.                           */
 | 
						|
/***********************************************************************/
 | 
						|
bool FIXFAM::AllocateBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  Buflen = Blksize;
 | 
						|
  To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
 | 
						|
 | 
						|
  if (UseTemp || Tdbp->GetMode() == MODE_DELETE) {
 | 
						|
    if (Padded) {
 | 
						|
      strcpy(g->Message, MSG(NO_MODE_PADDED));
 | 
						|
      return true;
 | 
						|
      } // endif Padded
 | 
						|
 | 
						|
    // Allocate a separate buffer so block reading can be kept
 | 
						|
    Dbflen = Nrec;
 | 
						|
    DelBuf = PlugSubAlloc(g, NULL, Blksize);
 | 
						|
  } else if (Tdbp->GetMode() == MODE_INSERT) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  For Insert the buffer must be prepared.                        */
 | 
						|
    /*******************************************************************/
 | 
						|
    if (Tdbp->GetFtype() == RECFM_BIN) {
 | 
						|
      // The buffer must be prepared depending on column types
 | 
						|
      int     n = 0;
 | 
						|
      bool    b = false;
 | 
						|
      PBINCOL colp;
 | 
						|
 | 
						|
      // Prepare the first line of the buffer
 | 
						|
      memset(To_Buf, 0, Buflen);
 | 
						|
 | 
						|
#if 0
 | 
						|
      for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext()) {
 | 
						|
        if (!IsTypeNum(cdp->GetType())) {
 | 
						|
          memset(To_Buf + cdp->GetOffset(), ' ', cdp->GetClen()); 
 | 
						|
          b = true;
 | 
						|
          } // endif not num
 | 
						|
 | 
						|
        n = MY_MAX(n, cdp->GetOffset() + cdp->GetClen());
 | 
						|
        } // endfor cdp
 | 
						|
#endif // 0
 | 
						|
 | 
						|
      for (colp = (PBINCOL)Tdbp->GetColumns(); colp; 
 | 
						|
           colp = (PBINCOL)colp->GetNext())
 | 
						|
        if (!colp->IsSpecial()) {
 | 
						|
          if (!IsTypeNum(colp->GetResultType())) {
 | 
						|
            memset(To_Buf + colp->GetDeplac(), ' ', colp->GetLength()); 
 | 
						|
            b = true;
 | 
						|
            } // endif not num
 | 
						|
      
 | 
						|
          n = MY_MAX(n, colp->GetDeplac() + colp->GetFileSize());
 | 
						|
          } // endif !special
 | 
						|
 | 
						|
      // We do this for binary table because the lrecl can have been
 | 
						|
      // specified with additional space to include line ending.
 | 
						|
      if (n < Lrecl && Ending) {
 | 
						|
        To_Buf[Lrecl - 1] = '\n';
 | 
						|
 | 
						|
        if (n < Lrecl - 1 && Ending == 2)
 | 
						|
          To_Buf[Lrecl - 2] = '\r';
 | 
						|
 | 
						|
        } // endif n
 | 
						|
 | 
						|
      if (b)
 | 
						|
        // Now repeat this for the whole buffer
 | 
						|
        for (int len = Lrecl; len <= Buflen - Lrecl; len += Lrecl)
 | 
						|
          memcpy(To_Buf + len, To_Buf, Lrecl);
 | 
						|
 | 
						|
    } else {
 | 
						|
      memset(To_Buf, ' ', Buflen);
 | 
						|
  
 | 
						|
      if (!Padded)
 | 
						|
        // The file is physically a text file.
 | 
						|
        for (int len = Lrecl; len <= Buflen; len += Lrecl) {
 | 
						|
          if (Ending == 2)
 | 
						|
            To_Buf[len - 2] = '\r';
 | 
						|
  
 | 
						|
          To_Buf[len - 1] = '\n';
 | 
						|
          } // endfor len
 | 
						|
 | 
						|
    } // endif Ftype
 | 
						|
 | 
						|
    Rbuf = Nrec;                     // To be used by WriteDB
 | 
						|
    } // endif Insert
 | 
						|
 | 
						|
  return false;
 | 
						|
  } // end of AllocateBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Reset buffer access according to indexing and to mode.             */
 | 
						|
/*  >>>>>>>>>>>>>> TO BE RE-VISITED AND CHECKED <<<<<<<<<<<<<<<<<<<<<< */
 | 
						|
/***********************************************************************/
 | 
						|
void FIXFAM::ResetBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  If access is random, performances can be much better when the    */
 | 
						|
  /*  reads are done on only one row, except for small tables that can */
 | 
						|
  /*  be entirely read in one block.                                   */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (Tdbp->GetKindex() && ReadBlks != 1 && !Padded) {
 | 
						|
    Nrec = 1;                       // Better for random access
 | 
						|
    Rbuf = 0;
 | 
						|
    Blksize = Lrecl;
 | 
						|
    OldBlk = -2;                    // Has no meaning anymore
 | 
						|
    Block = Tdbp->Cardinality(g);   // Blocks are one line now
 | 
						|
    } // endif Mode
 | 
						|
 | 
						|
  } // end of ResetBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  WriteModifiedBlock: Used when updating.                            */
 | 
						|
/***********************************************************************/
 | 
						|
int FIXFAM::WriteModifiedBlock(PGLOBAL g)
 | 
						|
  {
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  The old block was modified in Update mode.                       */
 | 
						|
  /*  In Update mode we simply rewrite the old block on itself.        */
 | 
						|
  /*********************************************************************/
 | 
						|
  int  rc = RC_OK;
 | 
						|
  bool moved = false;
 | 
						|
 | 
						|
  // Using temp copy any intermediate lines.
 | 
						|
  if (UseTemp && MoveIntermediateLines(g, &moved))
 | 
						|
    rc = RC_FX;
 | 
						|
 | 
						|
  // Fpos is last position, Headlen is DBF file header length
 | 
						|
  else if (!moved && fseek(Stream, Headlen + Fpos * Lrecl, SEEK_SET)) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(FSETPOS_ERROR), 0);
 | 
						|
    rc = RC_FX;
 | 
						|
  } else if (fwrite(To_Buf, Lrecl, Rbuf, T_Stream) != (size_t)Rbuf) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(FWRITE_ERROR), strerror(errno));
 | 
						|
    rc = RC_FX;
 | 
						|
  } else
 | 
						|
    Spos = Fpos + Nrec;           // + Rbuf ???
 | 
						|
 | 
						|
  if (Closing || rc != RC_OK) {   // Error or called from CloseDB
 | 
						|
    Closing = true;               // To tell CloseDB about error
 | 
						|
    return rc;
 | 
						|
    } // endif Closing
 | 
						|
 | 
						|
  // NOTE: Next line was added to avoid a very strange fread bug.
 | 
						|
  // When the fseek is not executed (even the file has the good
 | 
						|
  // pointer position) the next read can happen anywhere in the file.
 | 
						|
  OldBlk = -2;            // This will force fseek to be executed
 | 
						|
  Modif = 0;
 | 
						|
  return rc;
 | 
						|
  } // end of WriteModifiedBlock
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  ReadBuffer: Read one line for a FIX file.                          */
 | 
						|
/***********************************************************************/
 | 
						|
int FIXFAM::ReadBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  int n, rc = RC_OK;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Sequential reading when Placed is not true.                      */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (Placed) {
 | 
						|
    Tdbp->SetLine(To_Buf + CurNum * Lrecl);
 | 
						|
    Placed = false;
 | 
						|
  } else if (++CurNum < Rbuf) {
 | 
						|
    Tdbp->IncLine(Lrecl);                // Used by DOSCOL functions
 | 
						|
    return RC_OK;
 | 
						|
  } else if (Rbuf < Nrec && CurBlk != -1) {
 | 
						|
    return RC_EF;
 | 
						|
  } else {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  New block.                                                     */
 | 
						|
    /*******************************************************************/
 | 
						|
    CurNum = 0;
 | 
						|
    Tdbp->SetLine(To_Buf);
 | 
						|
 | 
						|
 next:
 | 
						|
    if (++CurBlk >= Block)
 | 
						|
      return RC_EF;
 | 
						|
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  Before reading a new block, check whether block indexing       */
 | 
						|
    /*  can be done, as well as for join as for local filtering.       */
 | 
						|
    /*******************************************************************/
 | 
						|
    switch (Tdbp->TestBlock(g)) {
 | 
						|
      case RC_EF:
 | 
						|
        return RC_EF;
 | 
						|
      case RC_NF:
 | 
						|
        goto next;
 | 
						|
      } // endswitch rc
 | 
						|
   } // endif's
 | 
						|
 | 
						|
  if (OldBlk == CurBlk) {
 | 
						|
    IsRead = true;            // Was read indeed
 | 
						|
    return RC_OK;             // Block is already there
 | 
						|
    } // endif OldBlk
 | 
						|
 | 
						|
  // Write modified block in mode UPDATE
 | 
						|
  if (Modif && (rc = WriteModifiedBlock(g)) != RC_OK)
 | 
						|
    return rc;
 | 
						|
 | 
						|
  // This could be done only for new block. However note that FPOS
 | 
						|
  // is used as block position when updating and as line position
 | 
						|
  // when deleting so this has to be carefully checked.
 | 
						|
  Fpos = CurBlk * Nrec;         // Fpos is new line position
 | 
						|
 | 
						|
  // fseek is required only in non sequential reading
 | 
						|
  if (CurBlk != OldBlk + 1)
 | 
						|
    // Note: Headlen is for DBF tables
 | 
						|
    if (fseek(Stream, Headlen + Fpos * Lrecl, SEEK_SET)) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(FSETPOS_ERROR), Fpos);
 | 
						|
      return RC_FX;
 | 
						|
      } // endif fseek
 | 
						|
 | 
						|
  if (trace(2))
 | 
						|
    htrc("File position is now %d\n", ftell(Stream));
 | 
						|
 | 
						|
  if (Padded)
 | 
						|
    n = fread(To_Buf, (size_t)Blksize, 1, Stream);
 | 
						|
  else
 | 
						|
    n = fread(To_Buf, (size_t)Lrecl, (size_t)Nrec, Stream);
 | 
						|
 | 
						|
  if (n) {
 | 
						|
    rc = RC_OK;
 | 
						|
    Rbuf = (Padded) ? n * Nrec : n;
 | 
						|
    ReadBlks++;
 | 
						|
    num_read++;
 | 
						|
  } else if (feof(Stream)) {
 | 
						|
    rc = RC_EF;
 | 
						|
  } else {
 | 
						|
#if defined(_WIN32)
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, _strerror(NULL));
 | 
						|
#else
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, strerror(errno));
 | 
						|
#endif
 | 
						|
 | 
						|
    if (trace(1))
 | 
						|
      htrc("%s\n", g->Message);
 | 
						|
 | 
						|
    return RC_FX;
 | 
						|
  } // endelse
 | 
						|
 | 
						|
  OldBlk = CurBlk;              // Last block actually read
 | 
						|
  IsRead = true;                // Is read indeed
 | 
						|
  return rc;
 | 
						|
  } // end of ReadBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  WriteBuffer: File write routine for FIX access method.             */
 | 
						|
/*  Updates are written into the (Temp) file in ReadBuffer.            */
 | 
						|
/***********************************************************************/
 | 
						|
int FIXFAM::WriteBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  if (trace(2))
 | 
						|
    htrc("FIX WriteDB: Mode=%d buf=%p line=%p Nrec=%d Rbuf=%d CurNum=%d\n",
 | 
						|
         Tdbp->GetMode(), To_Buf, Tdbp->GetLine(), Nrec, Rbuf, CurNum);
 | 
						|
 | 
						|
  if (Tdbp->GetMode() == MODE_INSERT) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  In Insert mode, blocs are added sequentialy to the file end.   */
 | 
						|
    /*******************************************************************/
 | 
						|
    if (++CurNum != Rbuf) {
 | 
						|
      Tdbp->IncLine(Lrecl);            // Used by DOSCOL functions
 | 
						|
      return RC_OK;                    // We write only full blocks
 | 
						|
      } // endif CurNum
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc(" First line is '%.*s'\n", Lrecl - 2, To_Buf);
 | 
						|
 | 
						|
    //  Now start the writing process.
 | 
						|
    if (fwrite(To_Buf, Lrecl, Rbuf, Stream) != (size_t)Rbuf) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(FWRITE_ERROR), strerror(errno));
 | 
						|
      Closing = true;      // To tell CloseDB about a Write error
 | 
						|
      return RC_FX;
 | 
						|
      } // endif size
 | 
						|
 | 
						|
    CurBlk++;
 | 
						|
    CurNum = 0;
 | 
						|
    Tdbp->SetLine(To_Buf);
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("write done\n");
 | 
						|
 | 
						|
  } else {                           // Mode == MODE_UPDATE
 | 
						|
    // T_Stream is the temporary stream or the table file stream itself
 | 
						|
    if (!T_Stream) {
 | 
						|
      if (UseTemp) {
 | 
						|
        if (OpenTempFile(g))
 | 
						|
          return RC_FX;
 | 
						|
        else if (CopyHeader(g))           // For DBF tables
 | 
						|
          return RC_FX;
 | 
						|
 | 
						|
      } else
 | 
						|
        T_Stream = Stream;
 | 
						|
 | 
						|
      } // endif T_Stream
 | 
						|
 | 
						|
    if (Nrec > 1)
 | 
						|
      Modif++;                         // Modified line in blocked mode
 | 
						|
    else if (WriteModifiedBlock(g))    // Indexed update
 | 
						|
      return RC_FX;
 | 
						|
 | 
						|
  } // endif Mode
 | 
						|
 | 
						|
  return RC_OK;
 | 
						|
  } // end of WriteBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Data Base delete line routine for FIXFAM access method.            */
 | 
						|
/***********************************************************************/
 | 
						|
int FIXFAM::DeleteRecords(PGLOBAL g, int irc)
 | 
						|
  {
 | 
						|
  bool moved;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  There is an alternative here:                                    */
 | 
						|
  /*  1 - use a temporary file in which are copied all not deleted     */
 | 
						|
  /*      lines, at the end the original file will be deleted and      */
 | 
						|
  /*      the temporary file renamed to the original file name.        */
 | 
						|
  /*  2 - directly move the not deleted lines inside the original      */
 | 
						|
  /*      file, and at the end erase all trailing records.             */
 | 
						|
  /*  This will be experimented.                                       */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (trace(2))
 | 
						|
    htrc("DOS DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
 | 
						|
         irc, UseTemp, Fpos, Tpos, Spos);
 | 
						|
 | 
						|
  if (irc != RC_OK) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  EOF: position Fpos at the end-of-file position.                */
 | 
						|
    /*******************************************************************/
 | 
						|
    Fpos = Tdbp->Cardinality(g);
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("Fpos placed at file end=%d\n", Fpos);
 | 
						|
 | 
						|
  } else    // Fpos is the deleted line position
 | 
						|
    Fpos = CurBlk * Nrec + CurNum;
 | 
						|
 | 
						|
  if (Tpos == Spos) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  First line to delete.                                          */
 | 
						|
    /*******************************************************************/
 | 
						|
    if (UseTemp) {
 | 
						|
      /*****************************************************************/
 | 
						|
      /*  Open temporary file, lines before this will be moved.        */
 | 
						|
      /*****************************************************************/
 | 
						|
      if (OpenTempFile(g))
 | 
						|
        return RC_FX;
 | 
						|
 | 
						|
    } else {
 | 
						|
      /*****************************************************************/
 | 
						|
      /*  Move of eventual preceding lines is not required here.      */
 | 
						|
      /*  Set the target file as being the source file itself.         */
 | 
						|
      /*  Set the future Tpos, and give Spos a value to block moving.  */
 | 
						|
      /*****************************************************************/
 | 
						|
      T_Stream = Stream;
 | 
						|
      Spos = Tpos = Fpos;
 | 
						|
    } // endif UseTemp
 | 
						|
 | 
						|
    } // endif Tpos == Spos
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Move any intermediate lines.                                     */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (MoveIntermediateLines(g, &moved))
 | 
						|
    return RC_FX;
 | 
						|
 | 
						|
  if (irc == RC_OK) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  Reposition the file pointer and set Spos.                      */
 | 
						|
    /*******************************************************************/
 | 
						|
    Spos = Fpos + 1;          // New start position is on next line
 | 
						|
 | 
						|
    if (moved) {
 | 
						|
      if (fseek(Stream, Spos * Lrecl, SEEK_SET)) {
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(FSETPOS_ERROR), 0);
 | 
						|
        return RC_FX;
 | 
						|
        } // endif fseek
 | 
						|
 | 
						|
      OldBlk = -2;  // To force fseek to be executed on next block
 | 
						|
      } // endif moved
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
 | 
						|
 | 
						|
  } else {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  Last call after EOF has been reached.                          */
 | 
						|
    /*******************************************************************/
 | 
						|
    if (UseTemp) {
 | 
						|
      /*****************************************************************/
 | 
						|
      /*  Ok, now delete old file and rename new temp file.            */
 | 
						|
      /*****************************************************************/
 | 
						|
      if (RenameTempFile(g))
 | 
						|
        return RC_FX;
 | 
						|
 | 
						|
    } else {
 | 
						|
      /*****************************************************************/
 | 
						|
      /*  Because the chsize functionality is only accessible with a   */
 | 
						|
      /*  system call we must close the file and reopen it with the    */
 | 
						|
      /*  open function (_fopen for MS ??) this is still to be checked */
 | 
						|
      /*  for compatibility with Text files and other OS's.            */
 | 
						|
      /*****************************************************************/
 | 
						|
      char filename[_MAX_PATH];
 | 
						|
      int  h;
 | 
						|
 | 
						|
      /*rc= */PlugCloseFile(g, To_Fb);
 | 
						|
      PlugSetPath(filename, To_File, Tdbp->GetPath());
 | 
						|
 | 
						|
      if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
 | 
						|
        return RC_FX;
 | 
						|
 | 
						|
      /*****************************************************************/
 | 
						|
      /*  Remove extra records.                                        */
 | 
						|
      /*****************************************************************/
 | 
						|
#if defined(UNIX)
 | 
						|
      if (ftruncate(h, (off_t)(Tpos * Lrecl))) {
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(TRUNCATE_ERROR), strerror(errno));
 | 
						|
        close(h);
 | 
						|
        return RC_FX;
 | 
						|
        } // endif
 | 
						|
#else
 | 
						|
      if (chsize(h, Tpos * Lrecl)) {
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(CHSIZE_ERROR), strerror(errno));
 | 
						|
        close(h);
 | 
						|
        return RC_FX;
 | 
						|
        } // endif
 | 
						|
#endif
 | 
						|
 | 
						|
      close(h);
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("done, h=%d irc=%d\n", h, irc);
 | 
						|
 | 
						|
    } // endif UseTemp
 | 
						|
 | 
						|
  } // endif irc
 | 
						|
 | 
						|
  return RC_OK;                                      // All is correct
 | 
						|
  } // end of DeleteRecords
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Move intermediate deleted or updated lines.                        */
 | 
						|
/*  This works only for file open in binary mode.                      */
 | 
						|
/***********************************************************************/
 | 
						|
bool FIXFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
 | 
						|
  {
 | 
						|
  int   n;
 | 
						|
  size_t req, len;
 | 
						|
 | 
						|
  for (*b = false, n = Fpos - Spos; n > 0; n -= req) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  Non consecutive line to delete. Move intermediate lines.       */
 | 
						|
    /*******************************************************************/
 | 
						|
    if (!UseTemp || !*b)
 | 
						|
      if (fseek(Stream, Headlen + Spos * Lrecl, SEEK_SET)) {
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(READ_SEEK_ERROR), strerror(errno));
 | 
						|
        return true;
 | 
						|
        } // endif
 | 
						|
 | 
						|
    req = (size_t)MY_MIN(n, Dbflen);
 | 
						|
    len = fread(DelBuf, Lrecl, req, Stream);
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("after read req=%d len=%d\n", req, len);
 | 
						|
 | 
						|
    if (len != req) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(DEL_READ_ERROR), (int) req, (int) len);
 | 
						|
      return true;
 | 
						|
      } // endif len
 | 
						|
 | 
						|
    if (!UseTemp)         // Delete mode, cannot be a DBF file
 | 
						|
      if (fseek(T_Stream, Tpos * Lrecl, SEEK_SET)) {
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(WRITE_SEEK_ERR), strerror(errno));
 | 
						|
        return true;
 | 
						|
        } // endif
 | 
						|
 | 
						|
    if ((len = fwrite(DelBuf, Lrecl, req, T_Stream)) != req) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(DEL_WRITE_ERROR), strerror(errno));
 | 
						|
      return true;
 | 
						|
      } // endif
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("after write pos=%d\n", ftell(Stream));
 | 
						|
 | 
						|
    Tpos += (int)req;
 | 
						|
    Spos += (int)req;
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
 | 
						|
 | 
						|
    *b = true;
 | 
						|
    } // endfor n
 | 
						|
 | 
						|
  return false;
 | 
						|
  } // end of MoveIntermediate Lines
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Table file close routine for FIX access method.                    */
 | 
						|
/***********************************************************************/
 | 
						|
void FIXFAM::CloseTableFile(PGLOBAL g, bool abort)
 | 
						|
  {
 | 
						|
  int rc = RC_OK, wrc = RC_OK;
 | 
						|
  MODE mode = Tdbp->GetMode();
 | 
						|
 | 
						|
  Abort = abort;
 | 
						|
 | 
						|
  // Closing is True if last Write was in error
 | 
						|
  if (mode == MODE_INSERT && CurNum && !Closing) {
 | 
						|
    // Some more inserted lines remain to be written
 | 
						|
    Rbuf = CurNum--;
 | 
						|
    wrc = WriteBuffer(g);
 | 
						|
  } else if (mode == MODE_UPDATE) {
 | 
						|
    if (Modif && !Closing) {
 | 
						|
      // Last updated block remains to be written
 | 
						|
      Closing = true;               // ???
 | 
						|
      wrc = WriteModifiedBlock(g);
 | 
						|
      } // endif Modif
 | 
						|
 | 
						|
    if (UseTemp && T_Stream && wrc == RC_OK) {
 | 
						|
      if (!Abort) {
 | 
						|
        // Copy any remaining lines
 | 
						|
        bool b;
 | 
						|
    
 | 
						|
        Fpos = Tdbp->Cardinality(g);
 | 
						|
        Abort = MoveIntermediateLines(g, &b) != RC_OK;
 | 
						|
        } // endif Abort
 | 
						|
 | 
						|
      // Delete the old file and rename the new temp file.
 | 
						|
      RenameTempFile(g);
 | 
						|
      goto fin;
 | 
						|
      } // endif UseTemp
 | 
						|
 | 
						|
  } // endif's mode
 | 
						|
 | 
						|
  // Finally close the file
 | 
						|
  rc = PlugCloseFile(g, To_Fb);
 | 
						|
 | 
						|
 fin:
 | 
						|
  if (trace(1))
 | 
						|
    htrc("FIX CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n",
 | 
						|
         To_File, mode, wrc, rc);
 | 
						|
 | 
						|
  Stream = NULL;           // So we can know whether table is open
 | 
						|
  } // end of CloseTableFile
 | 
						|
 | 
						|
/* ------------------------- Class BGXFAM ---------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Implementation of the BGXFAM class.                                */
 | 
						|
/*  This is the FAM class for FIX tables of more than 2 gigabytes.     */
 | 
						|
/***********************************************************************/
 | 
						|
BGXFAM::BGXFAM(PDOSDEF tdp) : FIXFAM(tdp)
 | 
						|
  {
 | 
						|
  Hfile = INVALID_HANDLE_VALUE;
 | 
						|
  Tfile = INVALID_HANDLE_VALUE;
 | 
						|
  } // end of BGXFAM constructor
 | 
						|
 | 
						|
BGXFAM::BGXFAM(PBGXFAM txfp) : FIXFAM(txfp)
 | 
						|
  {
 | 
						|
  Hfile = txfp->Hfile;
 | 
						|
  Tfile = txfp->Tfile;
 | 
						|
  } // end of BGXFAM copy constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Set current position in a big file.                                */
 | 
						|
/***********************************************************************/
 | 
						|
bool BGXFAM::BigSeek(PGLOBAL g, HANDLE h, BIGINT pos, int org)
 | 
						|
  {
 | 
						|
#if defined(_WIN32)
 | 
						|
  char          buf[256];
 | 
						|
  DWORD         drc;
 | 
						|
  LARGE_INTEGER of;
 | 
						|
 | 
						|
  of.QuadPart = pos;
 | 
						|
  of.LowPart = SetFilePointer(h, of.LowPart, &of.HighPart, org);
 | 
						|
 | 
						|
  if (of.LowPart == INVALID_SET_FILE_POINTER &&
 | 
						|
           (drc = GetLastError()) != NO_ERROR) {
 | 
						|
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
 | 
						|
                  FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
 | 
						|
                  (LPTSTR)buf, sizeof(buf), NULL);
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(SFP_ERROR), buf);
 | 
						|
    return true;
 | 
						|
    } // endif
 | 
						|
#else   // !_WIN32
 | 
						|
  if (lseek64(h, pos, org) < 0) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "lseek64: %s", strerror(errno));
 | 
						|
    printf("%s\n", g->Message);
 | 
						|
    return true;
 | 
						|
    } // endif
 | 
						|
#endif  // !_WIN32
 | 
						|
 | 
						|
  return false;
 | 
						|
  } // end of BigSeek
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Read from a big file.                                              */
 | 
						|
/***********************************************************************/
 | 
						|
int BGXFAM::BigRead(PGLOBAL g __attribute__((unused)), 
 | 
						|
                    HANDLE h, void *inbuf, int req)
 | 
						|
  {
 | 
						|
  int rc;
 | 
						|
 | 
						|
#if defined(_WIN32)
 | 
						|
  DWORD nbr, drc, len = (DWORD)req;
 | 
						|
  bool  brc = ReadFile(h, inbuf, len, &nbr, NULL);
 | 
						|
 | 
						|
  if (trace(2))
 | 
						|
    htrc("after read req=%d brc=%d nbr=%d\n", req, brc, nbr);
 | 
						|
 | 
						|
  if (!brc) {
 | 
						|
    char buf[256];  // , *fn = (h == Hfile) ? To_File : "Tempfile";
 | 
						|
 | 
						|
    drc = GetLastError();
 | 
						|
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
 | 
						|
                  FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
 | 
						|
                  (LPTSTR)buf, sizeof(buf), NULL);
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, buf);
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("BIGREAD: %s\n", g->Message);
 | 
						|
 | 
						|
    rc = -1;
 | 
						|
  } else
 | 
						|
    rc = (int)nbr;
 | 
						|
#else   // !_WIN32
 | 
						|
  size_t  len = (size_t)req;
 | 
						|
  ssize_t nbr = read(h, inbuf, len);
 | 
						|
 | 
						|
  rc = (int)nbr;
 | 
						|
#endif  // !_WIN32
 | 
						|
 | 
						|
  return rc;
 | 
						|
  } // end of BigRead
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Write into a big file.                                             */
 | 
						|
/***********************************************************************/
 | 
						|
bool BGXFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req)
 | 
						|
  {
 | 
						|
  bool rc = false;
 | 
						|
 | 
						|
#if defined(_WIN32)
 | 
						|
  DWORD nbw, drc, len = (DWORD)req;
 | 
						|
  bool  brc = WriteFile(h, inbuf, len, &nbw, NULL);
 | 
						|
 | 
						|
  if (trace(2))
 | 
						|
    htrc("after write req=%d brc=%d nbw=%d\n", req, brc, nbw);
 | 
						|
 | 
						|
  if (!brc || nbw != len) {
 | 
						|
		char buf[256];
 | 
						|
		PCSZ fn = (h == Hfile) ? To_File : "Tempfile";
 | 
						|
 | 
						|
    if (brc)
 | 
						|
      strcpy(buf, MSG(BAD_BYTE_NUM));
 | 
						|
    else {
 | 
						|
      drc = GetLastError();
 | 
						|
      FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
 | 
						|
                    FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
 | 
						|
                    (LPTSTR)buf, sizeof(buf), NULL);
 | 
						|
      } // endelse brc
 | 
						|
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(WRITE_STRERROR), fn, buf);
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
 | 
						|
           nbw, len, drc, g->Message);
 | 
						|
 | 
						|
    rc = true;
 | 
						|
    } // endif brc || nbw
 | 
						|
#else   // !_WIN32
 | 
						|
  size_t  len = (size_t)req;
 | 
						|
  ssize_t nbw = write(h, inbuf, len);
 | 
						|
 | 
						|
  if (nbw != (ssize_t)len) {
 | 
						|
    const char *fn = (h == Hfile) ? To_File : "Tempfile";
 | 
						|
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(WRITE_STRERROR), fn, strerror(errno));
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
 | 
						|
           nbw, len, errno, g->Message);
 | 
						|
 | 
						|
    rc = true;
 | 
						|
    } // endif nbr
 | 
						|
#endif  // !_WIN32
 | 
						|
 | 
						|
  return rc;
 | 
						|
  } // end of BigWrite
 | 
						|
 | 
						|
#if 0
 | 
						|
/***********************************************************************/
 | 
						|
/*  Reset: reset position values at the beginning of file.             */
 | 
						|
/***********************************************************************/
 | 
						|
void BGXFAM::Reset(void)
 | 
						|
  {
 | 
						|
  FIXFAM::Reset();
 | 
						|
  Xpos = 0;
 | 
						|
  } // end of Reset
 | 
						|
#endif // 0
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  OpenTableFile: opens a huge file using Windows/Unix API's.         */
 | 
						|
/***********************************************************************/
 | 
						|
bool BGXFAM::OpenTableFile(PGLOBAL g)
 | 
						|
  {
 | 
						|
  char    filename[_MAX_PATH];
 | 
						|
  MODE    mode = Tdbp->GetMode();
 | 
						|
  PDBUSER dbuserp = PlgGetUser(g);
 | 
						|
 | 
						|
  if ((To_Fb && To_Fb->Count) || Hfile != INVALID_HANDLE_VALUE) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(FILE_OPEN_YET), To_File);
 | 
						|
    return true;
 | 
						|
    } // endif
 | 
						|
 | 
						|
  PlugSetPath(filename, To_File, Tdbp->GetPath());
 | 
						|
 | 
						|
  if (trace(1))
 | 
						|
    htrc("OpenTableFile: filename=%s mode=%d\n", filename, mode);
 | 
						|
 | 
						|
#if defined(_WIN32)
 | 
						|
  DWORD rc, access, creation, share = 0;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Create the file object according to access mode                  */
 | 
						|
  /*********************************************************************/
 | 
						|
  switch (mode) {
 | 
						|
    case MODE_READ:
 | 
						|
      access = GENERIC_READ;
 | 
						|
      share = FILE_SHARE_READ;
 | 
						|
      creation = OPEN_EXISTING;
 | 
						|
      break;
 | 
						|
    case MODE_DELETE:
 | 
						|
      if (!Tdbp->GetNext()) {
 | 
						|
        // Store the number of deleted rows
 | 
						|
        DelRows = Cardinality(g);
 | 
						|
 | 
						|
        // This will delete the whole file and provoque ReadDB to
 | 
						|
        // return immediately.
 | 
						|
        access = GENERIC_READ | GENERIC_WRITE;
 | 
						|
        creation = TRUNCATE_EXISTING;
 | 
						|
        Tdbp->ResetSize();
 | 
						|
        Headlen = 0;
 | 
						|
        break;
 | 
						|
        } // endif
 | 
						|
 | 
						|
      // Selective delete, pass thru
 | 
						|
    case MODE_UPDATE:
 | 
						|
      if ((UseTemp = Tdbp->IsUsingTemp(g)))
 | 
						|
        access = GENERIC_READ;
 | 
						|
      else
 | 
						|
        access = GENERIC_READ | GENERIC_WRITE;
 | 
						|
 | 
						|
      creation = OPEN_EXISTING;
 | 
						|
      break;
 | 
						|
    case MODE_INSERT:
 | 
						|
      access = GENERIC_WRITE;
 | 
						|
      creation = OPEN_ALWAYS;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(BAD_OPEN_MODE), mode);
 | 
						|
      return true;
 | 
						|
    } // endswitch
 | 
						|
 | 
						|
  Hfile = CreateFile(filename, access, share, NULL, creation,
 | 
						|
                               FILE_ATTRIBUTE_NORMAL, NULL);
 | 
						|
 | 
						|
  if (Hfile == INVALID_HANDLE_VALUE) {
 | 
						|
    rc = GetLastError();
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(OPEN_ERROR), rc, mode, filename);
 | 
						|
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
 | 
						|
                  FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
 | 
						|
                  (LPTSTR)filename, sizeof(filename), NULL);
 | 
						|
  } else
 | 
						|
    rc = 0;
 | 
						|
 | 
						|
  if (trace(2))
 | 
						|
    htrc(" rc=%d access=%p share=%p creation=%d handle=%p fn=%s\n",
 | 
						|
         rc, access, share, creation, Hfile, filename);
 | 
						|
 | 
						|
  if (mode == MODE_INSERT)
 | 
						|
    /*******************************************************************/
 | 
						|
    /* In Insert mode we must position the cursor at end of file.      */
 | 
						|
    /*******************************************************************/
 | 
						|
    if (BigSeek(g, Hfile, (BIGINT)0, FILE_END))
 | 
						|
      return true;
 | 
						|
 | 
						|
#else   // UNIX
 | 
						|
  int    rc = 0;
 | 
						|
  int    oflag = O_LARGEFILE;         // Enable file size > 2G
 | 
						|
  mode_t tmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Create the file object according to access mode                  */
 | 
						|
  /*********************************************************************/
 | 
						|
  switch (mode) {
 | 
						|
    case MODE_READ:
 | 
						|
      oflag |= O_RDONLY;
 | 
						|
      break;
 | 
						|
    case MODE_DELETE:
 | 
						|
      if (!Tdbp->GetNext()) {
 | 
						|
        // This will delete the whole file and provoque ReadDB to
 | 
						|
        // return immediately.
 | 
						|
        oflag |= (O_RDWR | O_TRUNC);
 | 
						|
        Tdbp->ResetSize();
 | 
						|
        break;
 | 
						|
        } // endif
 | 
						|
 | 
						|
      // Selective delete
 | 
						|
      /* fall through */
 | 
						|
    case MODE_UPDATE:
 | 
						|
      UseTemp = Tdbp->IsUsingTemp(g);
 | 
						|
      oflag |= (UseTemp) ? O_RDONLY : O_RDWR;
 | 
						|
      break;
 | 
						|
    case MODE_INSERT:
 | 
						|
      oflag |= (O_WRONLY | O_CREAT | O_APPEND);
 | 
						|
 //   tmode = S_IREAD | S_IWRITE;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(BAD_OPEN_MODE), mode);
 | 
						|
      return true;
 | 
						|
    } // endswitch
 | 
						|
 | 
						|
  Hfile= global_open(g, MSGID_OPEN_ERROR_AND_STRERROR, filename, oflag, tmode);
 | 
						|
 | 
						|
  if (Hfile == INVALID_HANDLE_VALUE) {
 | 
						|
    rc = errno;
 | 
						|
  } else
 | 
						|
    rc = 0;
 | 
						|
 | 
						|
  if (trace(2))
 | 
						|
    htrc(" rc=%d oflag=%p tmode=%p handle=%p fn=%s\n",
 | 
						|
         rc, oflag, tmode, Hfile, filename);
 | 
						|
 | 
						|
#endif  // UNIX
 | 
						|
 | 
						|
  if (!rc) {
 | 
						|
    if (!To_Fb) {
 | 
						|
      To_Fb = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
 | 
						|
      To_Fb->Fname = To_File;
 | 
						|
      To_Fb->Type = TYPE_FB_HANDLE;
 | 
						|
      To_Fb->Memory = NULL;
 | 
						|
      To_Fb->Length = 0;
 | 
						|
      To_Fb->Mode = mode;
 | 
						|
      To_Fb->File = NULL;
 | 
						|
      To_Fb->Next = dbuserp->Openlist;
 | 
						|
      dbuserp->Openlist = To_Fb;
 | 
						|
      } // endif To_Fb
 | 
						|
 | 
						|
    To_Fb->Count = 1;
 | 
						|
    To_Fb->Mode = mode;
 | 
						|
    To_Fb->Handle = Hfile;
 | 
						|
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  Allocate the block buffer.                                     */
 | 
						|
    /*******************************************************************/
 | 
						|
    return AllocateBuffer(g);
 | 
						|
  } else
 | 
						|
    return (mode == MODE_READ && rc == ENOENT)
 | 
						|
            ? PushWarning(g, Tdbp) : true;
 | 
						|
 | 
						|
  } // end of OpenTableFile
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  BIGFIX 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 BGXFAM::Cardinality(PGLOBAL g)
 | 
						|
  {
 | 
						|
  if (g) {
 | 
						|
    char   filename[_MAX_PATH];
 | 
						|
    int   card = -1;
 | 
						|
    BIGINT fsize;
 | 
						|
 | 
						|
    PlugSetPath(filename, To_File, Tdbp->GetPath());
 | 
						|
 | 
						|
#if defined(_WIN32)  // OB
 | 
						|
    LARGE_INTEGER len;
 | 
						|
    DWORD         rc = 0;
 | 
						|
 | 
						|
    len.QuadPart = -1;
 | 
						|
 | 
						|
    if (Hfile == INVALID_HANDLE_VALUE) {
 | 
						|
      HANDLE h = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
 | 
						|
                   NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 | 
						|
 | 
						|
      if (h == INVALID_HANDLE_VALUE)
 | 
						|
        if ((rc = GetLastError()) != ERROR_FILE_NOT_FOUND) {
 | 
						|
          snprintf(g->Message, sizeof(g->Message), MSG(OPEN_ERROR), rc, 10, filename);
 | 
						|
          FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
 | 
						|
                        FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
 | 
						|
                        (LPTSTR)filename, sizeof(filename), NULL);
 | 
						|
          safe_strcat(g->Message, sizeof(g->Message), filename);
 | 
						|
          return -1;
 | 
						|
        } else
 | 
						|
          return 0;                     // File does not exist
 | 
						|
 | 
						|
      // Get the size of the file (can be greater than 4 GB)
 | 
						|
      len.LowPart = GetFileSize(h, (LPDWORD)&len.HighPart);
 | 
						|
      CloseHandle(h);
 | 
						|
    } else
 | 
						|
      len.LowPart = GetFileSize(Hfile, (LPDWORD)&len.HighPart);
 | 
						|
 | 
						|
    if (len.LowPart == 0xFFFFFFFF && (rc = GetLastError()) != NO_ERROR) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(FILELEN_ERROR), "GetFileSize", filename);
 | 
						|
      return -2;
 | 
						|
    } else
 | 
						|
      fsize = len.QuadPart;
 | 
						|
 | 
						|
#else    // UNIX
 | 
						|
    if (Hfile == INVALID_HANDLE_VALUE) {
 | 
						|
      int h = open64(filename, O_RDONLY, 0);
 | 
						|
 | 
						|
      if (trace(1))
 | 
						|
        htrc(" h=%d\n", h);
 | 
						|
 | 
						|
      if (h == INVALID_HANDLE_VALUE) {
 | 
						|
        if (trace(1))
 | 
						|
          htrc("  errno=%d ENOENT=%d\n", errno, ENOENT);
 | 
						|
 | 
						|
        if (errno != ENOENT) {
 | 
						|
          snprintf(g->Message, sizeof(g->Message), MSG(OPEN_ERROR_IS),
 | 
						|
                              filename, strerror(errno));
 | 
						|
          return -1;
 | 
						|
        } else
 | 
						|
          return 0;                      // File does not exist
 | 
						|
 | 
						|
        } // endif h
 | 
						|
 | 
						|
      // Get the size of the file (can be greater than 4 GB)
 | 
						|
      fsize = lseek64(h, 0, SEEK_END);
 | 
						|
      close(h);
 | 
						|
    } else {
 | 
						|
      BIGINT curpos = lseek64(Hfile, 0, SEEK_CUR);
 | 
						|
 | 
						|
      fsize = lseek64(Hfile, 0, SEEK_END);
 | 
						|
      lseek64(Hfile, curpos, SEEK_SET);
 | 
						|
    } // endif Hfile
 | 
						|
 | 
						|
    if (fsize < 0) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(FILELEN_ERROR), "lseek64", filename);
 | 
						|
      return -2;
 | 
						|
      } // endif fsize
 | 
						|
 | 
						|
#endif   // UNIX
 | 
						|
 | 
						|
    // Check the real size of the file
 | 
						|
    if (Padded && Blksize) {
 | 
						|
      if (fsize % (BIGINT)Blksize) {
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(NOT_FIXED_LEN),
 | 
						|
                            filename, (int)fsize, Lrecl);
 | 
						|
        return -3;
 | 
						|
      } else
 | 
						|
        card = (int)(fsize / (BIGINT)Blksize) * Nrec;
 | 
						|
 | 
						|
    } else if (fsize % (BIGINT)Lrecl) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(NOT_FIXED_LEN), filename, (int)fsize, Lrecl);
 | 
						|
      return -3;
 | 
						|
    } else
 | 
						|
      card = (int)(fsize / (BIGINT)Lrecl); // Fixed length file
 | 
						|
 | 
						|
    if (trace(1))
 | 
						|
      htrc(" Computed max_K=%d fsize=%lf lrecl=%d\n",
 | 
						|
           card, (double)fsize, Lrecl);
 | 
						|
 | 
						|
    // Set number of blocks for later use
 | 
						|
    Block = (card + Nrec - 1) / Nrec;
 | 
						|
    return card;
 | 
						|
  } else
 | 
						|
    return -1;
 | 
						|
 | 
						|
  } // end of Cardinality
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  WriteModifiedBlock: Used when updating.                            */
 | 
						|
/***********************************************************************/
 | 
						|
int BGXFAM::WriteModifiedBlock(PGLOBAL g)
 | 
						|
  {
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  The old block was modified in Update mode.                       */
 | 
						|
  /*  In Update mode we simply rewrite the old block on itself.        */
 | 
						|
  /*********************************************************************/
 | 
						|
  int  rc = RC_OK;
 | 
						|
  bool moved = false;
 | 
						|
 | 
						|
  if (UseTemp)                // Copy any intermediate lines.
 | 
						|
    if (MoveIntermediateLines(g, &moved))
 | 
						|
      rc = RC_FX;
 | 
						|
 | 
						|
  if (rc == RC_OK) {
 | 
						|
    // Set file position to OldBlk position (Fpos)
 | 
						|
    if (!moved && BigSeek(g, Hfile, (BIGINT)Fpos * (BIGINT)Lrecl))
 | 
						|
      rc = RC_FX;
 | 
						|
    else if (BigWrite(g, Tfile, To_Buf, Lrecl * Rbuf))
 | 
						|
      rc = RC_FX;
 | 
						|
 | 
						|
    Spos = Fpos + Nrec;       // + Rbuf ???
 | 
						|
    } // endif rc
 | 
						|
 | 
						|
  if (Closing || rc != RC_OK) // Error or called from CloseDB
 | 
						|
    return rc;
 | 
						|
 | 
						|
  // NOTE: Next line was added to avoid a very  strange fread bug.
 | 
						|
  // When the fseek is not executed (even the file has the good
 | 
						|
  // pointer position) the next read can happen anywhere in the file.
 | 
						|
  OldBlk = CurBlk;       // This will force fseek to be executed
 | 
						|
  Modif = 0;
 | 
						|
  return rc;
 | 
						|
  } // end of WriteModifiedBlock
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  ReadBuffer: Read Nrec lines for a big fixed/binary file.           */
 | 
						|
/***********************************************************************/
 | 
						|
int BGXFAM::ReadBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  int nbr, rc = RC_OK;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Sequential reading when Placed is not true.                      */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (Placed) {
 | 
						|
    Tdbp->SetLine(To_Buf + CurNum * Lrecl);
 | 
						|
    Placed = false;
 | 
						|
  } else if (++CurNum < Rbuf) {
 | 
						|
    Tdbp->IncLine(Lrecl);                // Used by DOSCOL functions
 | 
						|
    return RC_OK;
 | 
						|
  } else if (Rbuf < Nrec && CurBlk != -1) {
 | 
						|
    return RC_EF;
 | 
						|
  } else {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  New block.                                                     */
 | 
						|
    /*******************************************************************/
 | 
						|
    CurNum = 0;
 | 
						|
    Tdbp->SetLine(To_Buf);
 | 
						|
 | 
						|
 next:
 | 
						|
    if (++CurBlk >= Block)
 | 
						|
      return RC_EF;
 | 
						|
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  Before reading a new block, check whether block optimization   */
 | 
						|
    /*  can be done, as well as for join as for local filtering.       */
 | 
						|
    /*******************************************************************/
 | 
						|
    switch (Tdbp->TestBlock(g)) {
 | 
						|
      case RC_EF:
 | 
						|
        return RC_EF;
 | 
						|
      case RC_NF:
 | 
						|
        goto next;
 | 
						|
      } // endswitch rc
 | 
						|
 | 
						|
   } // endif's
 | 
						|
 | 
						|
  if (OldBlk == CurBlk) {
 | 
						|
    IsRead = true;       // Was read indeed
 | 
						|
    return RC_OK;        // Block is already there
 | 
						|
    } // endif OldBlk
 | 
						|
 | 
						|
  // Write modified block in mode UPDATE
 | 
						|
  if (Modif && (rc = WriteModifiedBlock(g)) != RC_OK)
 | 
						|
    return rc;
 | 
						|
 | 
						|
  Fpos = CurBlk * Nrec;
 | 
						|
 | 
						|
  // Setting file pointer is required only in non sequential reading
 | 
						|
  if (CurBlk != OldBlk + 1)
 | 
						|
    if (BigSeek(g, Hfile, (BIGINT)Fpos * (BIGINT)Lrecl))
 | 
						|
      return RC_FX;
 | 
						|
 | 
						|
  if (trace(2))
 | 
						|
    htrc("File position is now %d\n", Fpos);
 | 
						|
 | 
						|
  nbr = BigRead(g, Hfile, To_Buf, (Padded) ? Blksize : Lrecl * Nrec);
 | 
						|
 | 
						|
  if (nbr > 0) {
 | 
						|
    Rbuf = (Padded) ? Nrec : nbr / Lrecl;
 | 
						|
    rc = RC_OK;
 | 
						|
    ReadBlks++;
 | 
						|
    num_read++;
 | 
						|
  } else
 | 
						|
    rc = (nbr == 0) ? RC_EF : RC_FX;
 | 
						|
 | 
						|
  OldBlk = CurBlk;             // Last block actually read
 | 
						|
  IsRead = true;               // Is read indeed
 | 
						|
  return rc;
 | 
						|
  } // end of ReadBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  WriteBuffer: File write routine for BGXFAM access method.          */
 | 
						|
/*  Updates are written into the (Temp) file in ReadBuffer.            */
 | 
						|
/***********************************************************************/
 | 
						|
int BGXFAM::WriteBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  if (trace(2))
 | 
						|
    htrc("BIG WriteDB: Mode=%d buf=%p line=%p Nrec=%d Rbuf=%d CurNum=%d\n",
 | 
						|
         Tdbp->GetMode(), To_Buf, Tdbp->GetLine(), Nrec, Rbuf, CurNum);
 | 
						|
 | 
						|
  if (Tdbp->GetMode() == MODE_INSERT) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  In Insert mode, blocks are added sequentialy to the file end.  */
 | 
						|
    /*******************************************************************/
 | 
						|
    if (++CurNum != Rbuf) {
 | 
						|
      Tdbp->IncLine(Lrecl);            // Used by DOSCOL functions
 | 
						|
      return RC_OK;                    // We write only full blocks
 | 
						|
      } // endif CurNum
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc(" First line is '%.*s'\n", Lrecl - 2, To_Buf);
 | 
						|
 | 
						|
    //  Now start the writing process.
 | 
						|
    if (BigWrite(g, Hfile, To_Buf, Lrecl * Rbuf))
 | 
						|
      return RC_FX;
 | 
						|
 | 
						|
    CurBlk++;
 | 
						|
    CurNum = 0;
 | 
						|
    Tdbp->SetLine(To_Buf);
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("write done\n");
 | 
						|
 | 
						|
  } else {                           // Mode == MODE_UPDATE
 | 
						|
    // Tfile is the temporary file or the table file handle itself
 | 
						|
    if (Tfile == INVALID_HANDLE_VALUE) {
 | 
						|
      if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) {
 | 
						|
        if (OpenTempFile(g))
 | 
						|
          return RC_FX;
 | 
						|
 | 
						|
      } else
 | 
						|
        Tfile = Hfile;
 | 
						|
 | 
						|
      } // endif Tfile
 | 
						|
 | 
						|
    if (Nrec > 1)
 | 
						|
      Modif++;                         // Modified line in blocked mode
 | 
						|
    else if (WriteModifiedBlock(g))    // Indexed update
 | 
						|
      return RC_FX;
 | 
						|
 | 
						|
  } // endif Mode
 | 
						|
 | 
						|
  return RC_OK;
 | 
						|
  } // end of WriteBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Data Base delete line routine for BGXFAM access method.            */
 | 
						|
/***********************************************************************/
 | 
						|
int BGXFAM::DeleteRecords(PGLOBAL g, int irc)
 | 
						|
  {
 | 
						|
  bool moved;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  There is an alternative here:                                    */
 | 
						|
  /*  1 - use a temporary file in which are copied all not deleted     */
 | 
						|
  /*      lines, at the end the original file will be deleted and      */
 | 
						|
  /*      the temporary file renamed to the original file name.        */
 | 
						|
  /*  2 - directly move the not deleted lines inside the original      */
 | 
						|
  /*      file, and at the end erase all trailing records.             */
 | 
						|
  /*  This will be experimented.                                       */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (trace(2))
 | 
						|
    htrc("BGX DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
 | 
						|
         irc, UseTemp, Fpos, Tpos, Spos);
 | 
						|
 | 
						|
  if (irc != RC_OK) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  EOF: position Fpos at the end-of-file position.                */
 | 
						|
    /*******************************************************************/
 | 
						|
    Fpos = Tdbp->Cardinality(g);
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("Fpos placed at file end=%d\n", Fpos);
 | 
						|
 | 
						|
  } else    // Fpos is the deleted line position
 | 
						|
    Fpos = CurBlk * Nrec + CurNum;
 | 
						|
 | 
						|
  if (Tpos == Spos) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  First line to delete. Move of eventual preceding lines is     */
 | 
						|
    /*  not required here if a temporary file is not used, just the    */
 | 
						|
    /*  setting of future Spos and Tpos.                               */
 | 
						|
    /*******************************************************************/
 | 
						|
    if (UseTemp) {
 | 
						|
      /*****************************************************************/
 | 
						|
      /*  Open the temporary file, Spos is at the beginning of file.   */
 | 
						|
      /*****************************************************************/
 | 
						|
      if (OpenTempFile(g))
 | 
						|
        return RC_FX;
 | 
						|
 | 
						|
    } else {
 | 
						|
      /*****************************************************************/
 | 
						|
      /*  Move of eventual preceding lines is not required here.      */
 | 
						|
      /*  Set the target file as being the source file itself.         */
 | 
						|
      /*  Set the future Tpos, and give Spos a value to block copying. */
 | 
						|
      /*****************************************************************/
 | 
						|
      Tfile = Hfile;
 | 
						|
      Spos = Tpos = Fpos;
 | 
						|
    } // endif UseTemp
 | 
						|
 | 
						|
    } // endif Tpos == Spos
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Move any intermediate lines.                                     */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (MoveIntermediateLines(g, &moved))
 | 
						|
    return RC_FX;
 | 
						|
 | 
						|
  if (irc == RC_OK) {
 | 
						|
    if (trace(1))
 | 
						|
      assert(Spos == Fpos);
 | 
						|
 | 
						|
    Spos++;          // New start position is on next line
 | 
						|
 | 
						|
    if (moved) {
 | 
						|
      if (BigSeek(g, Hfile, (BIGINT)Spos * (BIGINT)Lrecl))
 | 
						|
        return RC_FX;
 | 
						|
 | 
						|
      OldBlk = -2;  // To force fseek to be executed on next block
 | 
						|
      } // endif moved
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
 | 
						|
 | 
						|
  } else if (irc != RC_OK) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  Last call after EOF has been reached.                          */
 | 
						|
    /*******************************************************************/
 | 
						|
    if (UseTemp) {
 | 
						|
      /*****************************************************************/
 | 
						|
      /*  Ok, now delete old file and rename new temp file.            */
 | 
						|
      /*****************************************************************/
 | 
						|
      if (RenameTempFile(g))
 | 
						|
        return RC_FX;
 | 
						|
 | 
						|
    } else {
 | 
						|
      /*****************************************************************/
 | 
						|
      /*  Remove extra records.                                        */
 | 
						|
      /*****************************************************************/
 | 
						|
#if defined(_WIN32)
 | 
						|
      if (BigSeek(g, Hfile, (BIGINT)Tpos * (BIGINT)Lrecl))
 | 
						|
        return RC_FX;
 | 
						|
 | 
						|
      if (!SetEndOfFile(Hfile)) {
 | 
						|
        DWORD drc = GetLastError();
 | 
						|
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(SETEOF_ERROR), drc);
 | 
						|
        return RC_FX;
 | 
						|
        } // endif error
 | 
						|
#else   // !_WIN32
 | 
						|
      if (ftruncate64(Hfile, (BIGINT)(Tpos * Lrecl))) {
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(TRUNCATE_ERROR), strerror(errno));
 | 
						|
        return RC_FX;
 | 
						|
        } // endif
 | 
						|
#endif  // !_WIN32
 | 
						|
 | 
						|
    } // endif UseTemp
 | 
						|
 | 
						|
  } // endif irc
 | 
						|
 | 
						|
  return RC_OK;                                      // All is correct
 | 
						|
  } // end of DeleteRecords
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Open a temporary file used while updating or deleting.             */
 | 
						|
/***********************************************************************/
 | 
						|
bool BGXFAM::OpenTempFile(PGLOBAL g)
 | 
						|
  {
 | 
						|
  char   *tempname;
 | 
						|
  PDBUSER dup = PlgGetUser(g);
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Open the temporary file, Spos is at the beginning of file.       */
 | 
						|
  /*********************************************************************/
 | 
						|
  tempname = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
 | 
						|
  PlugSetPath(tempname, To_File, Tdbp->GetPath());
 | 
						|
  PlugRemoveType(tempname, tempname);
 | 
						|
  safe_strcat(tempname, _MAX_PATH, ".t");
 | 
						|
  remove(tempname);       // Be sure it does not exist yet
 | 
						|
 | 
						|
#if defined(_WIN32)
 | 
						|
  Tfile = CreateFile(tempname, GENERIC_WRITE, 0, NULL,
 | 
						|
                     CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
 | 
						|
 | 
						|
  if (Tfile == INVALID_HANDLE_VALUE) {
 | 
						|
    DWORD rc = GetLastError();
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(OPEN_ERROR), rc, MODE_INSERT,
 | 
						|
             tempname);
 | 
						|
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
 | 
						|
              FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
 | 
						|
              (LPTSTR)tempname, _MAX_PATH, NULL);
 | 
						|
    safe_strcat(g->Message, sizeof(g->Message), tempname);
 | 
						|
    return true;
 | 
						|
    } // endif Tfile
 | 
						|
#else    // UNIX
 | 
						|
  Tfile = open64(tempname, O_WRONLY | O_TRUNC, S_IWRITE);
 | 
						|
 | 
						|
  if (Tfile == INVALID_HANDLE_VALUE) {
 | 
						|
    int rc = errno;
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(OPEN_ERROR)" %s", rc,
 | 
						|
             MODE_INSERT, tempname, strerror(errno));
 | 
						|
    return true;
 | 
						|
    } //endif Tfile
 | 
						|
#endif   // UNIX
 | 
						|
 | 
						|
  To_Fbt = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
 | 
						|
  To_Fbt->Fname = tempname;
 | 
						|
  To_Fbt->Type = TYPE_FB_HANDLE;
 | 
						|
  To_Fbt->Memory = NULL;
 | 
						|
  To_Fbt->Length = 0;
 | 
						|
  To_Fbt->File = NULL;
 | 
						|
  To_Fbt->Next = dup->Openlist;
 | 
						|
  To_Fbt->Count = 1;
 | 
						|
  To_Fbt->Mode = MODE_INSERT;
 | 
						|
  To_Fbt->Handle = Tfile;
 | 
						|
  dup->Openlist = To_Fbt;
 | 
						|
  return false;
 | 
						|
  } // end of OpenTempFile
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Move intermediate deleted or updated lines.                        */
 | 
						|
/***********************************************************************/
 | 
						|
bool BGXFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
 | 
						|
  {
 | 
						|
  int n, req, nbr;
 | 
						|
 | 
						|
  for (*b = false, n = Fpos - Spos; n > 0; n -= req) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  Non consecutive line to delete. Move intermediate lines.       */
 | 
						|
    /*******************************************************************/
 | 
						|
    if (!UseTemp || !*b)
 | 
						|
      if (BigSeek(g, Hfile, (BIGINT)Spos * (BIGINT)Lrecl))
 | 
						|
        return true;
 | 
						|
 | 
						|
    req = MY_MIN(n, Dbflen) * Lrecl;
 | 
						|
 | 
						|
    if ((nbr = BigRead(g, Hfile, DelBuf, req)) != req) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(DEL_READ_ERROR), req, nbr);
 | 
						|
      return true;
 | 
						|
      } // endif nbr
 | 
						|
 | 
						|
    if (!UseTemp)
 | 
						|
      if (BigSeek(g, Tfile, (BIGINT)Tpos * (BIGINT)Lrecl))
 | 
						|
        return true;
 | 
						|
 | 
						|
    if (BigWrite(g, Tfile, DelBuf, req))
 | 
						|
      return true;
 | 
						|
 | 
						|
    req /= Lrecl;
 | 
						|
    Tpos += (int)req;
 | 
						|
    Spos += (int)req;
 | 
						|
 | 
						|
    if (trace(2))
 | 
						|
      htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
 | 
						|
 | 
						|
    *b = true;
 | 
						|
    } // endfor n
 | 
						|
 | 
						|
  return false;
 | 
						|
  } // end of MoveIntermediateLines
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Data Base close routine for BIGFIX access method.                  */
 | 
						|
/***********************************************************************/
 | 
						|
void BGXFAM::CloseTableFile(PGLOBAL g, bool abort)
 | 
						|
  {
 | 
						|
  int rc = RC_OK, wrc = RC_OK;
 | 
						|
  MODE mode = Tdbp->GetMode();
 | 
						|
 | 
						|
  Abort = abort;
 | 
						|
 | 
						|
  // Closing is True if last Write was in error
 | 
						|
  if (mode == MODE_INSERT && CurNum && !Closing) {
 | 
						|
    // Some more inserted lines remain to be written
 | 
						|
    Rbuf = CurNum--;
 | 
						|
    wrc = WriteBuffer(g);
 | 
						|
  } else if (mode == MODE_UPDATE) {
 | 
						|
    if (Modif && !Closing) {
 | 
						|
      // Last updated block remains to be written
 | 
						|
      Closing = true;
 | 
						|
      wrc = WriteModifiedBlock(g);
 | 
						|
      } // endif Modif
 | 
						|
 | 
						|
    if (UseTemp && Tfile && wrc == RC_OK) {
 | 
						|
      if (!Abort) {
 | 
						|
        // Copy any remaining lines
 | 
						|
        bool b;
 | 
						|
    
 | 
						|
        Fpos = Tdbp->Cardinality(g);
 | 
						|
        Abort = MoveIntermediateLines(g, &b) != RC_OK;
 | 
						|
        } // endif Abort
 | 
						|
 | 
						|
      // Delete the old file and rename the new temp file.
 | 
						|
      RenameTempFile(g);
 | 
						|
      goto fin;
 | 
						|
      } // endif UseTemp
 | 
						|
 | 
						|
  } // endif's mode
 | 
						|
 | 
						|
  // Finally close the file
 | 
						|
  rc = PlugCloseFile(g, To_Fb);
 | 
						|
 | 
						|
 fin:
 | 
						|
  if (trace(1))
 | 
						|
    htrc("BGX CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n",
 | 
						|
         To_File, mode, wrc, rc);
 | 
						|
 | 
						|
  Hfile = INVALID_HANDLE_VALUE; // So we can know whether table is open
 | 
						|
  } // end of CloseTableFile
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Rewind routine for huge FIX access method.                         */
 | 
						|
/*  Note: commenting out OldBlk = -1 has two advantages:               */
 | 
						|
/*  1 - It forces fseek on  first block, thus suppressing the need to  */
 | 
						|
/*      rewind the file, anyway unuseful when second pass if indexed.  */
 | 
						|
/*  2 - It permit to avoid re-reading small tables having only 1 block.*/
 | 
						|
/*      (even very unlikely for huge files!)                           */
 | 
						|
/***********************************************************************/
 | 
						|
void BGXFAM::Rewind(void)
 | 
						|
  {
 | 
						|
#if 0    // This is probably unuseful because file is accessed directly
 | 
						|
#if defined(_WIN32)  //OB
 | 
						|
  SetFilePointer(Hfile, 0, NULL, FILE_BEGIN);
 | 
						|
#else    // UNIX
 | 
						|
  lseek64(Hfile, 0, SEEK_SET);
 | 
						|
#endif   // UNIX
 | 
						|
#endif // 0
 | 
						|
  CurBlk = -1;
 | 
						|
  CurNum = Rbuf;
 | 
						|
//OldBlk = -1;
 | 
						|
//Rbuf = 0;        commented out in case we reuse last read block
 | 
						|
  Fpos = 0;
 | 
						|
  } // end of Rewind
 |