mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1428 lines
		
	
	
	
		
			47 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1428 lines
		
	
	
	
		
			47 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/************ File AM GZ C++ Program Source Code File (.CPP) ***********/
 | 
						|
/* PROGRAM NAME: FILAMGZ                                               */
 | 
						|
/* -------------                                                       */
 | 
						|
/*  Version 1.5                                                        */
 | 
						|
/*                                                                     */
 | 
						|
/* COPYRIGHT:                                                          */
 | 
						|
/* ----------                                                          */
 | 
						|
/*  (C) Copyright to the author Olivier BERTRAND          2005-2016    */
 | 
						|
/*                                                                     */
 | 
						|
/* WHAT THIS PROGRAM DOES:                                             */
 | 
						|
/* -----------------------                                             */
 | 
						|
/*  This program are the ZLIB compressed files classes.                */
 | 
						|
/*                                                                     */
 | 
						|
/***********************************************************************/
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Include relevant MariaDB header file.                  */
 | 
						|
/***********************************************************************/
 | 
						|
#include "my_global.h"
 | 
						|
#if defined(_WIN32)
 | 
						|
#include <io.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#if defined(__BORLANDC__)
 | 
						|
#define __MFC_COMPAT__                   // To define min/max as macro
 | 
						|
#endif
 | 
						|
//#include <windows.h>
 | 
						|
#else   // !_WIN32
 | 
						|
#if defined(UNIX)
 | 
						|
#include <errno.h>
 | 
						|
#else   // !UNIX
 | 
						|
#include <io.h>
 | 
						|
#endif
 | 
						|
#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.  */
 | 
						|
/*  tabdos.h    is header containing the TABDOS class declarations.    */
 | 
						|
/***********************************************************************/
 | 
						|
#include "global.h"
 | 
						|
#include "plgdbsem.h"
 | 
						|
//#include "catalog.h"
 | 
						|
//#include "reldef.h"
 | 
						|
//#include "xobject.h"
 | 
						|
//#include "kindex.h"
 | 
						|
#include "filamtxt.h"
 | 
						|
#include "tabdos.h"
 | 
						|
#if defined(UNIX)
 | 
						|
#include "osutil.h"
 | 
						|
#endif
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  This define prepares ZLIB function declarations.                   */
 | 
						|
/***********************************************************************/
 | 
						|
//#define ZLIB_DLL
 | 
						|
 | 
						|
#include "filamgz.h"
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  DB static variables.                                               */
 | 
						|
/***********************************************************************/
 | 
						|
extern int num_read, num_there, num_eq[];                 // Statistics
 | 
						|
 | 
						|
/* ------------------------------------------------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Implementation of the GZFAM class.                                 */
 | 
						|
/***********************************************************************/
 | 
						|
GZFAM::GZFAM(PGZFAM txfp) : TXTFAM(txfp)
 | 
						|
  {
 | 
						|
  Zfile = txfp->Zfile;
 | 
						|
  Zpos = txfp->Zpos;
 | 
						|
  } // end of GZFAM copy constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Zerror: Error function for gz calls.                               */
 | 
						|
/*  gzerror returns the error message for the last error which occurred*/
 | 
						|
/*  on the given compressed file. errnum is set to zlib error number.  */
 | 
						|
/*  If an error occurred in the file system and not in the compression */
 | 
						|
/*  library, errnum is set to Z_ERRNO and the application may consult  */
 | 
						|
/*  errno to get the exact error code.                                 */
 | 
						|
/***********************************************************************/
 | 
						|
int GZFAM::Zerror(PGLOBAL g)
 | 
						|
  {
 | 
						|
  int errnum;
 | 
						|
 | 
						|
  snprintf(g->Message, sizeof(g->Message), "%s", gzerror(Zfile, &errnum));
 | 
						|
 | 
						|
  if (errnum == Z_ERRNO)
 | 
						|
#if defined(_WIN32)
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, strerror(NULL));
 | 
						|
#else   // !_WIN32
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, strerror(errno));
 | 
						|
#endif  // !_WIN32
 | 
						|
 | 
						|
    return (errnum == Z_STREAM_END) ? RC_EF : RC_FX;
 | 
						|
  } // end of Zerror
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Reset: reset position values at the beginning of file.             */
 | 
						|
/***********************************************************************/
 | 
						|
void GZFAM::Reset(void)
 | 
						|
  {
 | 
						|
  TXTFAM::Reset();
 | 
						|
//gzrewind(Zfile);                  // Useful ?????
 | 
						|
  Zpos = 0;
 | 
						|
  } // end of Reset
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  GZ GetFileLength: returns an estimate of what would be the         */
 | 
						|
/*  uncompressed file size in number of bytes.                         */
 | 
						|
/***********************************************************************/
 | 
						|
int GZFAM::GetFileLength(PGLOBAL g)
 | 
						|
  {
 | 
						|
  int len = TXTFAM::GetFileLength(g);
 | 
						|
 | 
						|
  if (len > 0)
 | 
						|
    // Estimate size reduction to a max of 6
 | 
						|
    len *= 6;
 | 
						|
 | 
						|
  return len;
 | 
						|
  } // end of GetFileLength
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  GZ Access Method opening routine.                                  */
 | 
						|
/***********************************************************************/
 | 
						|
bool GZFAM::OpenTableFile(PGLOBAL g)
 | 
						|
  {
 | 
						|
  const char *opmode;
 | 
						|
  char filename[_MAX_PATH];
 | 
						|
  MODE mode = Tdbp->GetMode();
 | 
						|
 | 
						|
  switch (mode) {
 | 
						|
    case MODE_READ:
 | 
						|
      opmode = "rb";
 | 
						|
      break;
 | 
						|
    case MODE_UPDATE:
 | 
						|
      /*****************************************************************/
 | 
						|
      /* Updating GZ files not implemented yet.                        */
 | 
						|
      /*****************************************************************/
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(UPD_ZIP_NOT_IMP));
 | 
						|
      return true;
 | 
						|
    case MODE_DELETE:
 | 
						|
      if (!Tdbp->GetNext()) {
 | 
						|
        // Store the number of deleted lines
 | 
						|
        DelRows = Cardinality(g);
 | 
						|
 | 
						|
        // This will erase the entire file
 | 
						|
        opmode = "wb";
 | 
						|
//      Block = 0;                // For ZBKFAM
 | 
						|
//      Last = Nrec;              // For ZBKFAM
 | 
						|
        Tdbp->ResetSize();
 | 
						|
      } else {
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(NO_PART_DEL), "GZ");
 | 
						|
        return true;
 | 
						|
      } // endif filter
 | 
						|
 | 
						|
      break;
 | 
						|
    case MODE_INSERT:
 | 
						|
      opmode = "a+b";
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(BAD_OPEN_MODE), mode);
 | 
						|
      return true;
 | 
						|
    } // endswitch Mode
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Open according to logical input/output mode required.            */
 | 
						|
  /*  Use specific zlib functions.                                     */
 | 
						|
  /*  Treat files as binary.                                           */
 | 
						|
  /*********************************************************************/
 | 
						|
  Zfile = gzopen(PlugSetPath(filename, To_File, Tdbp->GetPath()), opmode);
 | 
						|
 | 
						|
  if (Zfile == NULL) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(GZOPEN_ERROR) ": %s",
 | 
						|
            opmode, (int)errno, filename, strerror(errno));
 | 
						|
    return (mode == MODE_READ && errno == ENOENT)
 | 
						|
            ? PushWarning(g, Tdbp) : true;
 | 
						|
    } // endif Zfile
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Something to be done here. >>>>>>>> NOT DONE <<<<<<<<            */
 | 
						|
  /*********************************************************************/
 | 
						|
//To_Fb = dbuserp->Openlist;     // Keep track of File block
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Allocate the line buffer.                                        */
 | 
						|
  /*********************************************************************/
 | 
						|
  return AllocateBuffer(g);
 | 
						|
  } // end of OpenTableFile
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Allocate the line buffer. For mode Delete a bigger buffer has to   */
 | 
						|
/*  be allocated because is it also used to move lines into the file.  */
 | 
						|
/***********************************************************************/
 | 
						|
bool GZFAM::AllocateBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  MODE mode = Tdbp->GetMode();
 | 
						|
 | 
						|
  Buflen = Lrecl + 2;                     // Lrecl does not include CRLF
 | 
						|
//Buflen *= ((Mode == MODE_DELETE) ? DOS_BUFF_LEN : 1);    NIY
 | 
						|
 | 
						|
  if (trace(1))
 | 
						|
    htrc("SubAllocating a buffer of %d bytes\n", Buflen);
 | 
						|
 | 
						|
  To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
 | 
						|
 | 
						|
  if (mode == MODE_INSERT) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  For Insert buffer must be prepared.                            */
 | 
						|
    /*******************************************************************/
 | 
						|
    memset(To_Buf, ' ', Buflen);
 | 
						|
    To_Buf[Buflen - 2] = '\n';
 | 
						|
    To_Buf[Buflen - 1] = '\0';
 | 
						|
    } // endif Insert
 | 
						|
 | 
						|
  return false;
 | 
						|
  } // end of AllocateBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  GetRowID: return the RowID of last read record.                    */
 | 
						|
/***********************************************************************/
 | 
						|
int GZFAM::GetRowID(void)
 | 
						|
  {
 | 
						|
  return Rows;
 | 
						|
  } // end of GetRowID
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  GetPos: return the position of last read record.                   */
 | 
						|
/***********************************************************************/
 | 
						|
int GZFAM::GetPos(void)
 | 
						|
  {
 | 
						|
  return (int)Zpos;
 | 
						|
  } // end of GetPos
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  GetNextPos: return the position of next record.                    */
 | 
						|
/***********************************************************************/
 | 
						|
int GZFAM::GetNextPos(void)
 | 
						|
  {
 | 
						|
  return gztell(Zfile);
 | 
						|
  } // end of GetNextPos
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  SetPos: Replace the table at the specified position.               */
 | 
						|
/***********************************************************************/
 | 
						|
bool GZFAM::SetPos(PGLOBAL g, int pos __attribute__((unused)))
 | 
						|
  {
 | 
						|
  snprintf(g->Message, sizeof(g->Message), MSG(NO_SETPOS_YET), "GZ");
 | 
						|
  return true;
 | 
						|
#if 0
 | 
						|
  Fpos = pos;
 | 
						|
 | 
						|
  if (fseek(Stream, Fpos, SEEK_SET)) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(FSETPOS_ERROR), Fpos);
 | 
						|
    return true;
 | 
						|
    } // endif
 | 
						|
 | 
						|
  Placed = true;
 | 
						|
  return false;
 | 
						|
#endif // 0
 | 
						|
  } // end of SetPos
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Record file position in case of UPDATE or DELETE.                  */
 | 
						|
/***********************************************************************/
 | 
						|
bool GZFAM::RecordPos(PGLOBAL)
 | 
						|
  {
 | 
						|
  Zpos = gztell(Zfile);
 | 
						|
  return false;
 | 
						|
  } // end of RecordPos
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Skip one record in file.                                           */
 | 
						|
/***********************************************************************/
 | 
						|
int GZFAM::SkipRecord(PGLOBAL g, bool header)
 | 
						|
  {
 | 
						|
  // Skip this record
 | 
						|
  if (gzeof(Zfile))
 | 
						|
    return RC_EF;
 | 
						|
  else if (gzgets(Zfile, To_Buf, Buflen) == Z_NULL)
 | 
						|
    return Zerror(g);
 | 
						|
 | 
						|
  if (header)
 | 
						|
    RecordPos(g);
 | 
						|
 | 
						|
  return RC_OK;
 | 
						|
  } // end of SkipRecord
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  ReadBuffer: Read one line from a compressed text file.             */
 | 
						|
/***********************************************************************/
 | 
						|
int GZFAM::ReadBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  char *p;
 | 
						|
  int   rc;
 | 
						|
 | 
						|
  if (!Zfile)
 | 
						|
    return RC_EF;
 | 
						|
 | 
						|
  if (!Placed) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  Record file position in case of UPDATE or DELETE.              */
 | 
						|
    /*******************************************************************/
 | 
						|
   next:
 | 
						|
    if (RecordPos(g))
 | 
						|
      return RC_FX;
 | 
						|
 | 
						|
    CurBlk = Rows++;                        // Update RowID
 | 
						|
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  Check whether optimization on ROWID                            */
 | 
						|
    /*  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:
 | 
						|
        // Skip this record
 | 
						|
        if ((rc = SkipRecord(g, FALSE)) != RC_OK)
 | 
						|
          return rc;
 | 
						|
 | 
						|
        goto next;
 | 
						|
      } // endswitch rc
 | 
						|
 | 
						|
  } else
 | 
						|
    Placed = false;
 | 
						|
 | 
						|
  if (gzeof(Zfile)) {
 | 
						|
    rc = RC_EF;
 | 
						|
  } else if (gzgets(Zfile, To_Buf, Buflen) != Z_NULL) {
 | 
						|
    p = To_Buf + strlen(To_Buf) - 1;
 | 
						|
 | 
						|
    if (*p == '\n')
 | 
						|
      *p = '\0';              // Eliminate ending new-line character
 | 
						|
 | 
						|
    if (*(--p) == '\r')
 | 
						|
      *p = '\0';              // Eliminate eventual carriage return
 | 
						|
 | 
						|
    strcpy(Tdbp->GetLine(), To_Buf);
 | 
						|
    IsRead = true;
 | 
						|
    rc = RC_OK;
 | 
						|
    num_read++;
 | 
						|
  } else
 | 
						|
    rc = Zerror(g);
 | 
						|
 | 
						|
  if (trace(2))
 | 
						|
    htrc(" Read: '%s' rc=%d\n", To_Buf, rc);
 | 
						|
 | 
						|
  return rc;
 | 
						|
  } // end of ReadBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  WriteDB: Data Base write routine for ZDOS access method.           */
 | 
						|
/*  Update is not possible without using a temporary file (NIY).       */
 | 
						|
/***********************************************************************/
 | 
						|
int GZFAM::WriteBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Prepare the write buffer.                                        */
 | 
						|
  /*********************************************************************/
 | 
						|
  strcat(strcpy(To_Buf, Tdbp->GetLine()), CrLf);
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Now start the writing process.                                   */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (gzputs(Zfile, To_Buf) < 0)
 | 
						|
    return Zerror(g);
 | 
						|
 | 
						|
  return RC_OK;
 | 
						|
  } // end of WriteBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Data Base delete line routine for ZDOS access method.  (NIY)       */
 | 
						|
/***********************************************************************/
 | 
						|
int GZFAM::DeleteRecords(PGLOBAL g, int)
 | 
						|
  {
 | 
						|
  snprintf(g->Message, sizeof(g->Message), MSG(NO_ZIP_DELETE));
 | 
						|
  return RC_FX;
 | 
						|
  } // end of DeleteRecords
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Data Base close routine for DOS access method.                     */
 | 
						|
/***********************************************************************/
 | 
						|
void GZFAM::CloseTableFile(PGLOBAL, bool)
 | 
						|
  {
 | 
						|
  int rc = gzclose(Zfile);
 | 
						|
 | 
						|
  if (trace(1))
 | 
						|
    htrc("GZ CloseDB: closing %s rc=%d\n", To_File, rc);
 | 
						|
 | 
						|
  Zfile = NULL;            // So we can know whether table is open
 | 
						|
//To_Fb->Count = 0;        // Avoid double closing by PlugCloseAll
 | 
						|
  } // end of CloseTableFile
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Rewind routine for GZ access method.                               */
 | 
						|
/***********************************************************************/
 | 
						|
void GZFAM::Rewind(void)
 | 
						|
  {
 | 
						|
  gzrewind(Zfile);
 | 
						|
  } // end of Rewind
 | 
						|
 | 
						|
/* ------------------------------------------------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Constructors.                                                      */
 | 
						|
/***********************************************************************/
 | 
						|
ZBKFAM::ZBKFAM(PDOSDEF tdp) : GZFAM(tdp)
 | 
						|
  {
 | 
						|
  Blocked = true;
 | 
						|
  Block = tdp->GetBlock();
 | 
						|
  Last = tdp->GetLast();
 | 
						|
  Nrec = tdp->GetElemt();
 | 
						|
  CurLine = NULL;
 | 
						|
  NxtLine = NULL;
 | 
						|
  Closing = false;
 | 
						|
  BlkPos = tdp->GetTo_Pos();
 | 
						|
  } // end of ZBKFAM standard constructor
 | 
						|
 | 
						|
ZBKFAM::ZBKFAM(PZBKFAM txfp) : GZFAM(txfp)
 | 
						|
  {
 | 
						|
  CurLine = txfp->CurLine;
 | 
						|
  NxtLine = txfp->NxtLine;
 | 
						|
  Closing = txfp->Closing;
 | 
						|
  } // end of ZBKFAM copy constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Use BlockTest to reduce the table estimated size.                  */
 | 
						|
/***********************************************************************/
 | 
						|
int ZBKFAM::MaxBlkSize(PGLOBAL g, int)
 | 
						|
  {
 | 
						|
  int rc = RC_OK, savcur = CurBlk;
 | 
						|
  int size;
 | 
						|
 | 
						|
  // Roughly estimate the table size as the sum of blocks
 | 
						|
  // that can contain good rows
 | 
						|
  for (size = 0, CurBlk = 0; CurBlk < Block; CurBlk++)
 | 
						|
    if ((rc = Tdbp->TestBlock(g)) == RC_OK)
 | 
						|
      size += (CurBlk == Block - 1) ? Last : Nrec;
 | 
						|
    else if (rc == RC_EF)
 | 
						|
      break;
 | 
						|
 | 
						|
  CurBlk = savcur;
 | 
						|
  return size;
 | 
						|
  } // end of MaxBlkSize
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  ZBK 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 ZBKFAM::Cardinality(PGLOBAL g)
 | 
						|
  {
 | 
						|
  return (g) ? (int)((Block - 1) * Nrec + Last) : 1;
 | 
						|
  } // end of Cardinality
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Allocate the line buffer. For mode Delete a bigger buffer has to   */
 | 
						|
/*  be allocated because is it also used to move lines into the file.  */
 | 
						|
/***********************************************************************/
 | 
						|
bool ZBKFAM::AllocateBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  Buflen = Nrec * (Lrecl + 2);
 | 
						|
  CurLine = To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
 | 
						|
 | 
						|
  if (Tdbp->GetMode() == MODE_INSERT) {
 | 
						|
    // Set values so Block and Last can be recalculated
 | 
						|
    if (Last == Nrec) {
 | 
						|
      CurBlk = Block;
 | 
						|
      Rbuf = Nrec;                   // To be used by WriteDB
 | 
						|
    } else {
 | 
						|
      // The last block must be completed
 | 
						|
      CurBlk = Block - 1;
 | 
						|
      Rbuf = Nrec - Last;            // To be used by WriteDB
 | 
						|
    } // endif Last
 | 
						|
 | 
						|
    } // endif Insert
 | 
						|
 | 
						|
  return false;
 | 
						|
  } // end of AllocateBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  GetRowID: return the RowID of last read record.                    */
 | 
						|
/***********************************************************************/
 | 
						|
int ZBKFAM::GetRowID(void)
 | 
						|
  {
 | 
						|
  return CurNum + Nrec * CurBlk + 1;
 | 
						|
  } // end of GetRowID
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  GetPos: return the position of last read record.                   */
 | 
						|
/***********************************************************************/
 | 
						|
int ZBKFAM::GetPos(void)
 | 
						|
  {
 | 
						|
  return CurNum + Nrec * CurBlk;            // Computed file index
 | 
						|
  } // end of GetPos
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Record file position in case of UPDATE or DELETE.                  */
 | 
						|
/*  Not used yet for fixed tables.                                     */
 | 
						|
/***********************************************************************/
 | 
						|
bool ZBKFAM::RecordPos(PGLOBAL /*g*/)
 | 
						|
  {
 | 
						|
//strcpy(g->Message, "RecordPos not implemented for gz blocked tables");
 | 
						|
//return true;
 | 
						|
  return RC_OK;
 | 
						|
  } // end of RecordPos
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Skip one record in file.                                           */
 | 
						|
/***********************************************************************/
 | 
						|
int ZBKFAM::SkipRecord(PGLOBAL /*g*/, bool)
 | 
						|
  {
 | 
						|
//strcpy(g->Message, "SkipRecord not implemented for gz blocked tables");
 | 
						|
//return RC_FX;
 | 
						|
  return RC_OK;
 | 
						|
  } // end of SkipRecord
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  ReadBuffer: Read one line from a compressed text file.             */
 | 
						|
/***********************************************************************/
 | 
						|
int ZBKFAM::ReadBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  int     n, skip, rc = RC_OK;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Sequential reading when Placed is not true.                      */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (++CurNum < Rbuf) {
 | 
						|
    CurLine = NxtLine;
 | 
						|
 | 
						|
    // Get the position of the next line in the buffer
 | 
						|
    while (*NxtLine++ != '\n') ;
 | 
						|
 | 
						|
    // Set caller line buffer
 | 
						|
    n = (int)(NxtLine - CurLine - Ending);
 | 
						|
    memcpy(Tdbp->GetLine(), CurLine, n);
 | 
						|
    Tdbp->GetLine()[n] = '\0';
 | 
						|
    return RC_OK;
 | 
						|
  } else if (Rbuf < Nrec && CurBlk != -1)
 | 
						|
    return RC_EF;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  New block.                                                       */
 | 
						|
  /*********************************************************************/
 | 
						|
  CurNum = 0;
 | 
						|
  skip = 0;
 | 
						|
 | 
						|
 next:
 | 
						|
  if (++CurBlk >= Block)
 | 
						|
    return RC_EF;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Before using the 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:
 | 
						|
      skip++;
 | 
						|
      goto next;
 | 
						|
    } // endswitch rc
 | 
						|
 | 
						|
  if (skip)
 | 
						|
    // Skip blocks rejected by block optimization
 | 
						|
    for (int i = CurBlk - skip; i < CurBlk; i++) {
 | 
						|
      BlkLen = BlkPos[i + 1] - BlkPos[i];
 | 
						|
 | 
						|
      if (gzseek(Zfile, (z_off_t)BlkLen, SEEK_CUR) < 0)
 | 
						|
        return Zerror(g);
 | 
						|
 | 
						|
      } // endfor i
 | 
						|
 | 
						|
  BlkLen = BlkPos[CurBlk + 1] - BlkPos[CurBlk];
 | 
						|
 | 
						|
  if (!(n = gzread(Zfile, To_Buf, BlkLen))) {
 | 
						|
    rc = RC_EF;
 | 
						|
  } else if (n > 0) {
 | 
						|
    // Get the position of the current line
 | 
						|
    CurLine = To_Buf;
 | 
						|
 | 
						|
    // Now get the position of the next line
 | 
						|
    for (NxtLine = CurLine; *NxtLine++ != '\n';) ;
 | 
						|
 | 
						|
    // Set caller line buffer
 | 
						|
    n = (int)(NxtLine - CurLine - Ending);
 | 
						|
    memcpy(Tdbp->GetLine(), CurLine, n);
 | 
						|
    Tdbp->GetLine()[n] = '\0';
 | 
						|
    Rbuf = (CurBlk == Block - 1) ? Last : Nrec;
 | 
						|
    IsRead = true;
 | 
						|
    rc = RC_OK;
 | 
						|
    num_read++;
 | 
						|
  } else
 | 
						|
    rc = Zerror(g);
 | 
						|
 | 
						|
  return rc;
 | 
						|
  } // end of ReadBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  WriteDB: Data Base write routine for ZDOS access method.           */
 | 
						|
/*  Update is not possible without using a temporary file (NIY).       */
 | 
						|
/***********************************************************************/
 | 
						|
int ZBKFAM::WriteBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Prepare the write buffer.                                        */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (!Closing)
 | 
						|
    strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf);
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  In Insert mode, blocs are added sequentialy to the file end.     */
 | 
						|
  /*  Note: Update mode is not handled for gz files.                   */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (++CurNum == Rbuf) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  New block, start the writing process.                          */
 | 
						|
    /*******************************************************************/
 | 
						|
    BlkLen = CurLine + strlen(CurLine) - To_Buf;
 | 
						|
 | 
						|
    if (gzwrite(Zfile, To_Buf, BlkLen) != BlkLen ||
 | 
						|
        gzflush(Zfile, Z_FULL_FLUSH)) {
 | 
						|
      Closing = true;
 | 
						|
      return Zerror(g);
 | 
						|
      } // endif gzwrite
 | 
						|
 | 
						|
    Rbuf = Nrec;
 | 
						|
    CurBlk++;
 | 
						|
    CurNum = 0;
 | 
						|
    CurLine = To_Buf;
 | 
						|
  } else
 | 
						|
    CurLine += strlen(CurLine);
 | 
						|
 | 
						|
  return RC_OK;
 | 
						|
  } // end of WriteBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Data Base delete line routine for ZBK access method.               */
 | 
						|
/*  Implemented only for total deletion of the table, which is done    */
 | 
						|
/*  by opening the file in mode "wb".                                  */
 | 
						|
/***********************************************************************/
 | 
						|
int ZBKFAM::DeleteRecords(PGLOBAL g, int irc)
 | 
						|
  {
 | 
						|
  if (irc == RC_EF) {
 | 
						|
    (void) Tdbp->GetName();                     // XXX Should be removed ?
 | 
						|
    PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
 | 
						|
 | 
						|
    defp->SetBlock(0);
 | 
						|
    defp->SetLast(Nrec);
 | 
						|
 | 
						|
    if (!defp->SetIntCatInfo("Blocks", 0) ||
 | 
						|
        !defp->SetIntCatInfo("Last", 0)) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(UPDATE_ERROR), "Header");
 | 
						|
      return RC_FX;
 | 
						|
    } else
 | 
						|
      return RC_OK;
 | 
						|
 | 
						|
  } else
 | 
						|
    return irc;
 | 
						|
 | 
						|
  } // end of DeleteRecords
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Data Base close routine for ZBK access method.                     */
 | 
						|
/***********************************************************************/
 | 
						|
void ZBKFAM::CloseTableFile(PGLOBAL g, bool)
 | 
						|
  {
 | 
						|
  int rc = RC_OK;
 | 
						|
 | 
						|
  if (Tdbp->GetMode() == MODE_INSERT) {
 | 
						|
    (void) Tdbp->GetName();                     // XXX Should be removed?
 | 
						|
    PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
 | 
						|
 | 
						|
    if (CurNum && !Closing) {
 | 
						|
      // Some more inserted lines remain to be written
 | 
						|
      Last = (Nrec - Rbuf) + CurNum;
 | 
						|
      Block = CurBlk + 1;
 | 
						|
      Rbuf = CurNum--;
 | 
						|
      Closing = true;
 | 
						|
      rc = WriteBuffer(g);
 | 
						|
    } else if (Rbuf == Nrec) {
 | 
						|
      Last = Nrec;
 | 
						|
      Block = CurBlk;
 | 
						|
    } // endif CurNum
 | 
						|
 | 
						|
    if (rc != RC_FX) {
 | 
						|
      defp->SetBlock(Block);
 | 
						|
      defp->SetLast(Last);
 | 
						|
      defp->SetIntCatInfo("Blocks", Block);
 | 
						|
      defp->SetIntCatInfo("Last", Last);
 | 
						|
      } // endif
 | 
						|
 | 
						|
    gzclose(Zfile);
 | 
						|
  } else if (Tdbp->GetMode() == MODE_DELETE) {
 | 
						|
    rc = DeleteRecords(g, RC_EF);
 | 
						|
    gzclose(Zfile);
 | 
						|
  } else
 | 
						|
    rc = gzclose(Zfile);
 | 
						|
 | 
						|
  if (trace(1))
 | 
						|
    htrc("GZ CloseDB: closing %s rc=%d\n", To_File, rc);
 | 
						|
 | 
						|
  Zfile = NULL;            // So we can know whether table is open
 | 
						|
//To_Fb->Count = 0;        // Avoid double closing by PlugCloseAll
 | 
						|
  } // end of CloseTableFile
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Rewind routine for ZBK access method.                              */
 | 
						|
/***********************************************************************/
 | 
						|
void ZBKFAM::Rewind(void)
 | 
						|
  {
 | 
						|
  gzrewind(Zfile);
 | 
						|
  CurBlk = -1;
 | 
						|
  CurNum = Rbuf;
 | 
						|
  } // end of Rewind
 | 
						|
 | 
						|
/* ------------------------------------------------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Constructors.                                                      */
 | 
						|
/***********************************************************************/
 | 
						|
GZXFAM::GZXFAM(PDOSDEF tdp) : ZBKFAM(tdp)
 | 
						|
  {
 | 
						|
//Block = tdp->GetBlock();
 | 
						|
//Last = tdp->GetLast();
 | 
						|
  Nrec = (tdp->GetElemt()) ? tdp->GetElemt() : DOS_BUFF_LEN;
 | 
						|
  Blksize = Nrec * Lrecl;
 | 
						|
  } // end of GZXFAM standard constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  ZIX 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 GZXFAM::Cardinality(PGLOBAL g)
 | 
						|
  {
 | 
						|
  if (Last)
 | 
						|
    return (g) ? (int)((Block - 1) * Nrec + Last) : 1;
 | 
						|
  else  // Last and Block not defined, cannot do it yet
 | 
						|
    return 0;
 | 
						|
 | 
						|
  } // end of Cardinality
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Allocate the line buffer. For mode Delete a bigger buffer has to   */
 | 
						|
/*  be allocated because is it also used to move lines into the file.  */
 | 
						|
/***********************************************************************/
 | 
						|
bool GZXFAM::AllocateBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  Buflen = Blksize;
 | 
						|
  To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
 | 
						|
 | 
						|
  if (Tdbp->GetMode() == MODE_INSERT) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  For Insert the buffer must be prepared.                        */
 | 
						|
    /*******************************************************************/
 | 
						|
    memset(To_Buf, ' ', Buflen);
 | 
						|
 | 
						|
    if (Tdbp->GetFtype() < 2)
 | 
						|
      // if not binary, the file is physically a text file
 | 
						|
      for (int len = Lrecl; len <= Buflen; len += Lrecl) {
 | 
						|
#if defined(_WIN32)
 | 
						|
        To_Buf[len - 2] = '\r';
 | 
						|
#endif   // _WIN32
 | 
						|
        To_Buf[len - 1] = '\n';
 | 
						|
        } // endfor len
 | 
						|
 | 
						|
    // Set values so Block and Last can be recalculated
 | 
						|
    if (Last == Nrec) {
 | 
						|
      CurBlk = Block;
 | 
						|
      Rbuf = Nrec;                   // To be used by WriteDB
 | 
						|
    } else {
 | 
						|
      // The last block must be completed
 | 
						|
      CurBlk = Block - 1;
 | 
						|
      Rbuf = Nrec - Last;            // To be used by WriteDB
 | 
						|
    } // endif Last
 | 
						|
 | 
						|
    } // endif Insert
 | 
						|
 | 
						|
  return false;
 | 
						|
  } // end of AllocateBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  ReadBuffer: Read one line from a compressed text file.             */
 | 
						|
/***********************************************************************/
 | 
						|
int GZXFAM::ReadBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  int n, rc = RC_OK;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Sequential reading when Placed is not true.                      */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (++CurNum < Rbuf) {
 | 
						|
    Tdbp->IncLine(Lrecl);                // Used by DOSCOL functions
 | 
						|
    return RC_OK;
 | 
						|
  } else if (Rbuf < Nrec && CurBlk != -1)
 | 
						|
    return RC_EF;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  New block.                                                       */
 | 
						|
  /*********************************************************************/
 | 
						|
  CurNum = 0;
 | 
						|
  Tdbp->SetLine(To_Buf);
 | 
						|
 | 
						|
  int skip = 0;
 | 
						|
 | 
						|
 next:
 | 
						|
  if (++CurBlk >= Block)
 | 
						|
    return RC_EF;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Before using the 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:
 | 
						|
      skip++;
 | 
						|
      goto next;
 | 
						|
    } // endswitch rc
 | 
						|
 | 
						|
  if (skip)
 | 
						|
    // Skip blocks rejected by block optimization
 | 
						|
    for (int i = 0; i < skip; i++) {
 | 
						|
      if (gzseek(Zfile, (z_off_t)Buflen, SEEK_CUR) < 0)
 | 
						|
        return Zerror(g);
 | 
						|
 | 
						|
      } // endfor i
 | 
						|
 | 
						|
  if (!(n = gzread(Zfile, To_Buf, Buflen))) {
 | 
						|
    rc = RC_EF;
 | 
						|
  } else if (n > 0) {
 | 
						|
    Rbuf = n / Lrecl;
 | 
						|
    IsRead = true;
 | 
						|
    rc = RC_OK;
 | 
						|
    num_read++;
 | 
						|
  } else
 | 
						|
    rc = Zerror(g);
 | 
						|
 | 
						|
  return rc;
 | 
						|
  } // end of ReadBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  WriteDB: Data Base write routine for ZDOS access method.           */
 | 
						|
/*  Update is not possible without using a temporary file (NIY).       */
 | 
						|
/***********************************************************************/
 | 
						|
int GZXFAM::WriteBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  In Insert mode, blocs are added sequentialy to the file end.     */
 | 
						|
  /*  Note: Update mode is not handled for gz files.                   */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (++CurNum == Rbuf) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  New block, start the writing process.                          */
 | 
						|
    /*******************************************************************/
 | 
						|
    BlkLen = Rbuf * Lrecl;
 | 
						|
 | 
						|
    if (gzwrite(Zfile, To_Buf, BlkLen) != BlkLen ||
 | 
						|
        gzflush(Zfile, Z_FULL_FLUSH)) {
 | 
						|
      Closing = true;
 | 
						|
      return Zerror(g);
 | 
						|
      } // endif gzwrite
 | 
						|
 | 
						|
    Rbuf = Nrec;
 | 
						|
    CurBlk++;
 | 
						|
    CurNum = 0;
 | 
						|
    Tdbp->SetLine(To_Buf);
 | 
						|
  } else
 | 
						|
    Tdbp->IncLine(Lrecl);            // Used by FIXCOL functions
 | 
						|
 | 
						|
  return RC_OK;
 | 
						|
  } // end of WriteBuffer
 | 
						|
 | 
						|
/* --------------------------- Class ZLBFAM -------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Constructors.                                                      */
 | 
						|
/***********************************************************************/
 | 
						|
ZLBFAM::ZLBFAM(PDOSDEF tdp) : BLKFAM(tdp)
 | 
						|
  {
 | 
						|
  Zstream = NULL;
 | 
						|
  Zbuffer = NULL;
 | 
						|
  Zlenp = NULL;
 | 
						|
  Optimized = tdp->IsOptimized();
 | 
						|
  } // end of ZLBFAM standard constructor
 | 
						|
 | 
						|
ZLBFAM::ZLBFAM(PZLBFAM txfp) : BLKFAM(txfp)
 | 
						|
  {
 | 
						|
  Zstream = txfp->Zstream;
 | 
						|
  Zbuffer = txfp->Zbuffer;
 | 
						|
  Zlenp = txfp->Zlenp;
 | 
						|
  Optimized = txfp->Optimized;
 | 
						|
  } // end of ZLBFAM (dummy?) copy constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  ZLB GetFileLength: returns an estimate of what would be the        */
 | 
						|
/*  uncompressed file size in number of bytes.                         */
 | 
						|
/***********************************************************************/
 | 
						|
int ZLBFAM::GetFileLength(PGLOBAL g)
 | 
						|
  {
 | 
						|
  int len = (Optimized) ? BlkPos[Block] : BLKFAM::GetFileLength(g);
 | 
						|
 | 
						|
  if (len > 0)
 | 
						|
    // Estimate size reduction to a max of 5
 | 
						|
    len *= 5;
 | 
						|
 | 
						|
  return len;
 | 
						|
  } // end of GetFileLength
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Allocate the line buffer. For mode Delete a bigger buffer has to   */
 | 
						|
/*  be allocated because is it also used to move lines into the file.  */
 | 
						|
/***********************************************************************/
 | 
						|
bool ZLBFAM::AllocateBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  PCSZ msg;
 | 
						|
  int  n, zrc;
 | 
						|
 | 
						|
#if 0
 | 
						|
  if (!Optimized && Tdbp->NeedIndexing(g)) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(NOP_ZLIB_INDEX));
 | 
						|
    return TRUE;
 | 
						|
    } // endif indexing
 | 
						|
#endif // 0
 | 
						|
 | 
						|
#if defined(NOLIB)
 | 
						|
  if (!zlib && LoadZlib()) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(DLL_LOAD_ERROR), GetLastError(), "zlib.dll");
 | 
						|
    return TRUE;
 | 
						|
    } // endif zlib
 | 
						|
#endif
 | 
						|
 | 
						|
  BLKFAM::AllocateBuffer(g);
 | 
						|
//Buflen = Nrec * (Lrecl + 2);
 | 
						|
//Rbuf = Nrec;
 | 
						|
 | 
						|
  // Allocate the compressed buffer
 | 
						|
  n = Buflen + 16;             // ?????????????????????????????????
 | 
						|
  Zlenp = (int*)PlugSubAlloc(g, NULL, n);
 | 
						|
  Zbuffer = (Byte*)(Zlenp + 1);
 | 
						|
 | 
						|
  // Allocate and initialize the Z stream
 | 
						|
  Zstream = (z_streamp)PlugSubAlloc(g, NULL, sizeof(z_stream));
 | 
						|
  Zstream->zalloc = (alloc_func)0;
 | 
						|
  Zstream->zfree = (free_func)0;
 | 
						|
  Zstream->opaque = (voidpf)0;
 | 
						|
  Zstream->next_in = NULL;
 | 
						|
  Zstream->avail_in = 0;
 | 
						|
 | 
						|
  if (Tdbp->GetMode() == MODE_READ) {
 | 
						|
    msg = "inflateInit";
 | 
						|
    zrc = inflateInit(Zstream);
 | 
						|
  } else {
 | 
						|
    msg = "deflateInit";
 | 
						|
    zrc = deflateInit(Zstream, Z_DEFAULT_COMPRESSION);
 | 
						|
  } // endif Mode
 | 
						|
 | 
						|
  if (zrc != Z_OK) {
 | 
						|
    if (Zstream->msg)
 | 
						|
      snprintf(g->Message, sizeof(g->Message), "%s error: %s", msg, Zstream->msg);
 | 
						|
    else
 | 
						|
      snprintf(g->Message, sizeof(g->Message), "%s error: %d", msg, zrc);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
    } // endif zrc
 | 
						|
 | 
						|
  if (Tdbp->GetMode() == MODE_INSERT) {
 | 
						|
    // Write the file header block
 | 
						|
    if (Last == Nrec) {
 | 
						|
      CurBlk = Block;
 | 
						|
      CurNum = 0;
 | 
						|
 | 
						|
      if (!GetFileLength(g)) {
 | 
						|
        // Write the zlib header as an extra block
 | 
						|
        strcpy(To_Buf, "PlugDB");
 | 
						|
        BlkLen = strlen("PlugDB") + 1;
 | 
						|
 | 
						|
        if (WriteCompressedBuffer(g))
 | 
						|
          return TRUE;
 | 
						|
 | 
						|
        } // endif void file
 | 
						|
 | 
						|
    } else {
 | 
						|
      // In mode insert, if Last != Nrec, last block must be updated
 | 
						|
      CurBlk = Block - 1;
 | 
						|
      CurNum = Last;
 | 
						|
 | 
						|
      snprintf(g->Message, sizeof(g->Message), "%s",MSG(NO_PAR_BLK_INS));
 | 
						|
      return TRUE;
 | 
						|
    } // endif Last
 | 
						|
 | 
						|
  } else { // MODE_READ
 | 
						|
    // First thing to do is to read the header block
 | 
						|
    void *rdbuf;
 | 
						|
 | 
						|
    if (Optimized) {
 | 
						|
      BlkLen = BlkPos[0];
 | 
						|
      rdbuf = Zlenp;
 | 
						|
    } else {
 | 
						|
      // Get the stored length from the file itself
 | 
						|
      if (fread(Zlenp, sizeof(int), 1, Stream) != 1)
 | 
						|
        return FALSE;             // Empty file
 | 
						|
 | 
						|
      BlkLen = *Zlenp;
 | 
						|
      rdbuf = Zbuffer;
 | 
						|
    } // endif Optimized
 | 
						|
 | 
						|
    switch (ReadCompressedBuffer(g, rdbuf)) {
 | 
						|
      case RC_EF:
 | 
						|
        return FALSE;
 | 
						|
      case RC_FX:
 | 
						|
#if defined(UNIX)
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, strerror(errno));
 | 
						|
#else
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, _strerror(NULL));
 | 
						|
#endif
 | 
						|
        /* falls through */
 | 
						|
      case RC_NF:
 | 
						|
        return TRUE;
 | 
						|
      } // endswitch
 | 
						|
 | 
						|
    // Some old tables can have PlugDB in their header
 | 
						|
    if (strcmp(To_Buf, "PlugDB")) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(BAD_HEADER), Tdbp->GetFile(g));
 | 
						|
      return TRUE;
 | 
						|
      } // endif strcmp
 | 
						|
 | 
						|
  } // endif Mode
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
  } // end of AllocateBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  GetPos: return the position of last read record.                   */
 | 
						|
/***********************************************************************/
 | 
						|
int ZLBFAM::GetPos(void)
 | 
						|
  {
 | 
						|
  return (Optimized) ? (CurNum + Nrec * CurBlk) : Fpos;
 | 
						|
  } // end of GetPos
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  GetNextPos: should not be called for this class.                   */
 | 
						|
/***********************************************************************/
 | 
						|
int ZLBFAM::GetNextPos(void)
 | 
						|
  {
 | 
						|
  if (Optimized) {
 | 
						|
    assert(FALSE);
 | 
						|
    return 0;
 | 
						|
  } else
 | 
						|
    return ftell(Stream);
 | 
						|
 | 
						|
  } // end of GetNextPos
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  SetPos: Replace the table at the specified position.               */
 | 
						|
/***********************************************************************/
 | 
						|
bool ZLBFAM::SetPos(PGLOBAL g, int pos __attribute__((unused)))
 | 
						|
  {
 | 
						|
  snprintf(g->Message, sizeof(g->Message), MSG(NO_SETPOS_YET), "GZ");
 | 
						|
  return true;
 | 
						|
#if 0 // All this must be checked
 | 
						|
  if (pos < 0) {
 | 
						|
    snprintf(g->Message, sizeof(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;
 | 
						|
#endif // 0
 | 
						|
  } // end of SetPos
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  ReadBuffer: Read one line for a text file.                         */
 | 
						|
/***********************************************************************/
 | 
						|
int ZLBFAM::ReadBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  size_t   n;
 | 
						|
  void *rdbuf;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Sequential reading when Placed is not true.                      */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (Placed) {
 | 
						|
    Placed = FALSE;
 | 
						|
  } else if (++CurNum < Rbuf) {
 | 
						|
    CurLine = NxtLine;
 | 
						|
 | 
						|
    // Get the position of the next line in the buffer
 | 
						|
    if (Tdbp->GetFtype() == RECFM_VAR)
 | 
						|
      while (*NxtLine++ != '\n') ;
 | 
						|
    else
 | 
						|
      NxtLine += Lrecl;
 | 
						|
 | 
						|
    // Set caller line buffer
 | 
						|
    n = NxtLine - CurLine - ((Tdbp->GetFtype() == RECFM_BIN) ? 0 : Ending);
 | 
						|
    memcpy(Tdbp->GetLine(), CurLine, n);
 | 
						|
    Tdbp->GetLine()[n] = '\0';
 | 
						|
    return RC_OK;
 | 
						|
  } else if (Rbuf < Nrec && CurBlk != -1) {
 | 
						|
    CurNum--;         // To have a correct Last value when optimizing
 | 
						|
    return RC_EF;
 | 
						|
  } else {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  New block.                                                     */
 | 
						|
    /*******************************************************************/
 | 
						|
    CurNum = 0;
 | 
						|
 | 
						|
   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.       */
 | 
						|
    /*******************************************************************/
 | 
						|
    if (Optimized) switch (Tdbp->TestBlock(g)) {
 | 
						|
      case RC_EF:
 | 
						|
        return RC_EF;
 | 
						|
      case RC_NF:
 | 
						|
        goto next;
 | 
						|
      } // endswitch rc
 | 
						|
 | 
						|
  } // endif's
 | 
						|
 | 
						|
  if (OldBlk == CurBlk)
 | 
						|
    goto ok;         // Block is already there
 | 
						|
 | 
						|
  if (Optimized) {
 | 
						|
    // Store the position of next block
 | 
						|
    Fpos = BlkPos[CurBlk];
 | 
						|
 | 
						|
    // fseek is required only in non sequential reading
 | 
						|
    if (CurBlk != OldBlk + 1)
 | 
						|
      if (fseek(Stream, Fpos, SEEK_SET)) {
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(FSETPOS_ERROR), Fpos);
 | 
						|
        return RC_FX;
 | 
						|
        } // endif fseek
 | 
						|
 | 
						|
    // Calculate the length of block to read
 | 
						|
    BlkLen = BlkPos[CurBlk + 1] - Fpos;
 | 
						|
    rdbuf = Zlenp;
 | 
						|
  } else {                     // !Optimized
 | 
						|
    if (CurBlk != OldBlk + 1) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(INV_RAND_ACC));
 | 
						|
      return RC_FX;
 | 
						|
    } else
 | 
						|
      Fpos = ftell(Stream);    // Used when optimizing
 | 
						|
 | 
						|
    // Get the stored length from the file itself
 | 
						|
    if (fread(Zlenp, sizeof(int), 1, Stream) != 1) {
 | 
						|
      if (feof(Stream))
 | 
						|
        return RC_EF;
 | 
						|
 | 
						|
      goto err;
 | 
						|
      } // endif fread
 | 
						|
 | 
						|
    BlkLen = *Zlenp;
 | 
						|
    rdbuf = Zbuffer;
 | 
						|
  } // endif Optimized
 | 
						|
 | 
						|
  // Read the next block
 | 
						|
  switch (ReadCompressedBuffer(g, rdbuf)) {
 | 
						|
    case RC_FX: goto err;
 | 
						|
    case RC_NF: return RC_FX;
 | 
						|
    case RC_EF: return RC_EF;
 | 
						|
    default: Rbuf = (CurBlk == Block - 1) ? Last : Nrec;
 | 
						|
    } // endswitch ReadCompressedBuffer
 | 
						|
 | 
						|
 ok:
 | 
						|
  if (Tdbp->GetFtype() == RECFM_VAR) {
 | 
						|
    int i;
 | 
						|
 | 
						|
    // Get the position of the current line
 | 
						|
    for (i = 0, CurLine = To_Buf; i < CurNum; i++)
 | 
						|
      while (*CurLine++ != '\n') ;      // What about Unix ???
 | 
						|
 | 
						|
    // Now get the position of the next line
 | 
						|
    for (NxtLine = CurLine; *NxtLine++ != '\n';) ;
 | 
						|
 | 
						|
    // Set caller line buffer
 | 
						|
    n = NxtLine - CurLine - Ending;
 | 
						|
  } else {
 | 
						|
    CurLine = To_Buf + CurNum * Lrecl;
 | 
						|
    NxtLine = CurLine + Lrecl;
 | 
						|
    n = Lrecl - ((Tdbp->GetFtype() == RECFM_BIN) ? 0 : Ending);
 | 
						|
  } // endif Ftype
 | 
						|
 | 
						|
  memcpy(Tdbp->GetLine(), CurLine, n);
 | 
						|
  Tdbp->GetLine()[n] = '\0';
 | 
						|
 | 
						|
  OldBlk = CurBlk;         // Last block actually read
 | 
						|
  IsRead = TRUE;           // Is read indeed
 | 
						|
  return RC_OK;
 | 
						|
 | 
						|
 err:
 | 
						|
#if defined(UNIX)
 | 
						|
  snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, strerror(errno));
 | 
						|
#else
 | 
						|
  snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, _strerror(NULL));
 | 
						|
#endif
 | 
						|
  return RC_FX;
 | 
						|
  } // end of ReadBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Read and decompress a block from the stream.                       */
 | 
						|
/***********************************************************************/
 | 
						|
int ZLBFAM::ReadCompressedBuffer(PGLOBAL g, void *rdbuf)
 | 
						|
  {
 | 
						|
  if (fread(rdbuf, 1, (size_t)BlkLen, Stream) == (unsigned)BlkLen) {
 | 
						|
    int zrc;
 | 
						|
 | 
						|
    num_read++;
 | 
						|
 | 
						|
    if (Optimized && BlkLen != signed(*Zlenp + sizeof(int))) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(BAD_BLK_SIZE), CurBlk + 1);
 | 
						|
      return RC_NF;
 | 
						|
      } // endif BlkLen
 | 
						|
 | 
						|
    // HERE WE MUST INFLATE THE BLOCK
 | 
						|
    Zstream->next_in = Zbuffer;
 | 
						|
    Zstream->avail_in = (uInt)(*Zlenp);
 | 
						|
    Zstream->next_out = (Byte*)To_Buf;
 | 
						|
    Zstream->avail_out = Buflen;
 | 
						|
    zrc = inflate(Zstream, Z_SYNC_FLUSH);
 | 
						|
 | 
						|
    if (zrc != Z_OK) {
 | 
						|
      if (Zstream->msg)
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(FUNC_ERR_S), "inflate", Zstream->msg);
 | 
						|
      else
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(FUNCTION_ERROR), "inflate", (int)zrc);
 | 
						|
 | 
						|
      return RC_NF;
 | 
						|
      } // endif zrc
 | 
						|
 | 
						|
  } else if (feof(Stream)) {
 | 
						|
    return RC_EF;
 | 
						|
  } else
 | 
						|
    return RC_FX;
 | 
						|
 | 
						|
  return RC_OK;
 | 
						|
  } // end of ReadCompressedBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  WriteBuffer: File write routine for DOS access method.             */
 | 
						|
/*  Update is directly written back into the file,                     */
 | 
						|
/*         with this (fast) method, record size cannot change.         */
 | 
						|
/***********************************************************************/
 | 
						|
int ZLBFAM::WriteBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  assert (Tdbp->GetMode() == MODE_INSERT);
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Prepare the write buffer.                                        */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (!Closing) {
 | 
						|
    if (Tdbp->GetFtype() == RECFM_BIN)
 | 
						|
      memcpy(CurLine, Tdbp->GetLine(), Lrecl);
 | 
						|
    else
 | 
						|
      strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf);
 | 
						|
 | 
						|
#if defined(_DEBUG)
 | 
						|
    if (Tdbp->GetFtype() == RECFM_FIX &&
 | 
						|
      (signed)strlen(CurLine) != Lrecl + (signed)strlen(CrLf)) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(BAD_LINE_LEN));
 | 
						|
      Closing = TRUE;
 | 
						|
      return RC_FX;
 | 
						|
      } // endif Lrecl
 | 
						|
#endif   // _DEBUG
 | 
						|
    } // endif Closing
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  In Insert mode, blocs are added sequentialy to the file end.     */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (++CurNum != Rbuf) {
 | 
						|
    if (Tdbp->GetFtype() == RECFM_VAR)
 | 
						|
      CurLine += strlen(CurLine);
 | 
						|
    else
 | 
						|
      CurLine += Lrecl;
 | 
						|
 | 
						|
    return RC_OK;                    // We write only full blocks
 | 
						|
    } // endif CurNum
 | 
						|
 | 
						|
  // HERE WE MUST DEFLATE THE BLOCK
 | 
						|
  if (Tdbp->GetFtype() == RECFM_VAR)
 | 
						|
    NxtLine = CurLine + strlen(CurLine);
 | 
						|
  else
 | 
						|
    NxtLine = CurLine + Lrecl;
 | 
						|
 | 
						|
  BlkLen = (int)(NxtLine - To_Buf);
 | 
						|
 | 
						|
  if (WriteCompressedBuffer(g)) {
 | 
						|
    Closing = TRUE;      // To tell CloseDB about a Write error
 | 
						|
    return RC_FX;
 | 
						|
    } // endif WriteCompressedBuffer
 | 
						|
 | 
						|
  CurBlk++;
 | 
						|
  CurNum = 0;
 | 
						|
  CurLine = To_Buf;
 | 
						|
  return RC_OK;
 | 
						|
  } // end of WriteBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Compress the buffer and write the deflated output to stream.       */
 | 
						|
/***********************************************************************/
 | 
						|
bool ZLBFAM::WriteCompressedBuffer(PGLOBAL g)
 | 
						|
  {
 | 
						|
  int zrc;
 | 
						|
 | 
						|
  Zstream->next_in = (Byte*)To_Buf;
 | 
						|
  Zstream->avail_in = (uInt)BlkLen;
 | 
						|
  Zstream->next_out = Zbuffer;
 | 
						|
  Zstream->avail_out = Buflen + 16;
 | 
						|
  Zstream->total_out = 0;
 | 
						|
  zrc = deflate(Zstream, Z_FULL_FLUSH);
 | 
						|
 | 
						|
  if (zrc != Z_OK) {
 | 
						|
    if (Zstream->msg)
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(FUNC_ERR_S), "deflate", Zstream->msg);
 | 
						|
    else
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(FUNCTION_ERROR), "deflate", (int)zrc);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  } else
 | 
						|
    *Zlenp = Zstream->total_out;
 | 
						|
 | 
						|
  //  Now start the writing process.
 | 
						|
  BlkLen = *Zlenp + sizeof(int);
 | 
						|
 | 
						|
  if (fwrite(Zlenp, 1, BlkLen, Stream) != (size_t)BlkLen) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(FWRITE_ERROR), strerror(errno));
 | 
						|
    return TRUE;
 | 
						|
    } // endif size
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
  } // end of WriteCompressedBuffer
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Table file close routine for DOS access method.                    */
 | 
						|
/***********************************************************************/
 | 
						|
void ZLBFAM::CloseTableFile(PGLOBAL g, bool)
 | 
						|
  {
 | 
						|
  int rc = RC_OK;
 | 
						|
 | 
						|
  if (Tdbp->GetMode() == MODE_INSERT) {
 | 
						|
    (void) Tdbp->GetName();                     // XXX Should be removed?
 | 
						|
    PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
 | 
						|
 | 
						|
    // Closing is True if last Write was in error
 | 
						|
    if (CurNum && !Closing) {
 | 
						|
      // Some more inserted lines remain to be written
 | 
						|
      Last = (Nrec - Rbuf) + CurNum;
 | 
						|
      Block = CurBlk + 1;
 | 
						|
      Rbuf = CurNum--;
 | 
						|
      Closing = TRUE;
 | 
						|
      rc = WriteBuffer(g);
 | 
						|
    } else if (Rbuf == Nrec) {
 | 
						|
      Last = Nrec;
 | 
						|
      Block = CurBlk;
 | 
						|
    } // endif CurNum
 | 
						|
 | 
						|
    if (rc != RC_FX) {
 | 
						|
      defp->SetBlock(Block);
 | 
						|
      defp->SetLast(Last);
 | 
						|
      defp->SetIntCatInfo("Blocks", Block);
 | 
						|
      defp->SetIntCatInfo("Last", Last);
 | 
						|
      } // endif
 | 
						|
 | 
						|
    fclose(Stream);
 | 
						|
  } else
 | 
						|
    rc = fclose(Stream);
 | 
						|
 | 
						|
  if (trace(1))
 | 
						|
    htrc("ZLB CloseTableFile: closing %s mode=%d rc=%d\n",
 | 
						|
         To_File, Tdbp->GetMode(), rc);
 | 
						|
 | 
						|
  Stream = NULL;           // So we can know whether table is open
 | 
						|
  To_Fb->Count = 0;        // Avoid double closing by PlugCloseAll
 | 
						|
 | 
						|
  if (Tdbp->GetMode() == MODE_READ)
 | 
						|
    rc = inflateEnd(Zstream);
 | 
						|
  else
 | 
						|
    rc = deflateEnd(Zstream);
 | 
						|
 | 
						|
  } // end of CloseTableFile
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Rewind routine for ZLIB access method.                             */
 | 
						|
/***********************************************************************/
 | 
						|
void ZLBFAM::Rewind(void)
 | 
						|
  {
 | 
						|
  // We must be positioned after the header block
 | 
						|
  if (CurBlk >= 0) {   // Nothing to do if no block read yet
 | 
						|
    if (!Optimized) {  // If optimized, fseek will be done in ReadBuffer
 | 
						|
			size_t st;
 | 
						|
 | 
						|
      rewind(Stream);
 | 
						|
 | 
						|
			if (!(st = fread(Zlenp, sizeof(int), 1, Stream)) && trace(1))
 | 
						|
				htrc("fread error %d in Rewind", errno);
 | 
						|
 | 
						|
      fseek(Stream, *Zlenp + sizeof(int), SEEK_SET);
 | 
						|
      OldBlk = -1;
 | 
						|
      } // endif Optimized
 | 
						|
 | 
						|
    CurBlk = -1;
 | 
						|
    CurNum = Rbuf;
 | 
						|
    } // endif CurBlk
 | 
						|
 | 
						|
//OldBlk = -1;
 | 
						|
//Rbuf = 0;        commented out in case we reuse last read block
 | 
						|
  } // end of Rewind
 | 
						|
 | 
						|
/* ------------------------ End of GzFam ---------------------------- */
 |