summaryrefslogtreecommitdiffstats
path: root/storage/connect/filamgz.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/connect/filamgz.cpp')
-rw-r--r--storage/connect/filamgz.cpp1427
1 files changed, 1427 insertions, 0 deletions
diff --git a/storage/connect/filamgz.cpp b/storage/connect/filamgz.cpp
new file mode 100644
index 00000000..634599ec
--- /dev/null
+++ b/storage/connect/filamgz.cpp
@@ -0,0 +1,1427 @@
+/************ 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 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;
+
+ strcpy(g->Message, gzerror(Zfile, &errnum));
+
+ if (errnum == Z_ERRNO)
+#if defined(_WIN32)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(NULL));
+#else // !_WIN32
+ sprintf(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)
+ {
+ char opmode[4], filename[_MAX_PATH];
+ MODE mode = Tdbp->GetMode();
+
+ switch (mode) {
+ case MODE_READ:
+ strcpy(opmode, "r");
+ break;
+ case MODE_UPDATE:
+ /*****************************************************************/
+ /* Updating GZ files not implemented yet. */
+ /*****************************************************************/
+ strcpy(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
+ strcpy(opmode, "w");
+// Block = 0; // For ZBKFAM
+// Last = Nrec; // For ZBKFAM
+ Tdbp->ResetSize();
+ } else {
+ sprintf(g->Message, MSG(NO_PART_DEL), "GZ");
+ return true;
+ } // endif filter
+
+ break;
+ case MODE_INSERT:
+ strcpy(opmode, "a+");
+ break;
+ default:
+ sprintf(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. */
+ /*********************************************************************/
+ strcat(opmode, "b");
+ Zfile = gzopen(PlugSetPath(filename, To_File, Tdbp->GetPath()), opmode);
+
+ if (Zfile == NULL) {
+ sprintf(g->Message, MSG(GZOPEN_ERROR),
+ opmode, (int)errno, filename);
+ strcat(strcat(g->Message, ": "), 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)))
+ {
+ sprintf(g->Message, MSG(NO_SETPOS_YET), "GZ");
+ return true;
+#if 0
+ Fpos = pos;
+
+ if (fseek(Stream, Fpos, SEEK_SET)) {
+ sprintf(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)
+ {
+ strcpy(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)) {
+ sprintf(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)) {
+ strcpy(g->Message, MSG(NOP_ZLIB_INDEX));
+ return TRUE;
+ } // endif indexing
+#endif // 0
+
+#if defined(NOLIB)
+ if (!zlib && LoadZlib()) {
+ sprintf(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)
+ sprintf(g->Message, "%s error: %s", msg, Zstream->msg);
+ else
+ sprintf(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;
+
+ strcpy(g->Message, 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)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
+#else
+ sprintf(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")) {
+ sprintf(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)))
+ {
+ sprintf(g->Message, MSG(NO_SETPOS_YET), "GZ");
+ return true;
+#if 0 // All this must be checked
+ if (pos < 0) {
+ strcpy(g->Message, MSG(INV_REC_POS));
+ return true;
+ } // endif recpos
+
+ CurBlk = pos / Nrec;
+ CurNum = pos % Nrec;
+#if defined(_DEBUG)
+ num_eq[(CurBlk == OldBlk) ? 1 : 0]++;
+#endif
+
+ // Indicate the table position was externally set
+ Placed = true;
+ return false;
+#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)) {
+ sprintf(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) {
+ strcpy(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)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
+#else
+ sprintf(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))) {
+ sprintf(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)
+ sprintf(g->Message, MSG(FUNC_ERR_S), "inflate", Zstream->msg);
+ else
+ sprintf(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)) {
+ strcpy(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)
+ sprintf(g->Message, MSG(FUNC_ERR_S), "deflate", Zstream->msg);
+ else
+ sprintf(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) {
+ sprintf(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 ---------------------------- */