mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 10:56:12 +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 eventuel 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 ---------------------------- */
 | 
