mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 04:22:27 +01:00
19af1890b5
This commit replaces sprintf(buf, ...) with snprintf(buf, sizeof(buf), ...), specifically in the "easy" cases where buf is allocated with a size known at compile time. The changes make sure we are not write outside array/string bounds which will lead to undefined behaviour. In case the code is trying to write outside bounds - safe version of functions simply cut the string messages so we process this gracefully. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc. bsonudf.cpp warnings cleanup by Daniel Black Reviewer: Daniel Black
1426 lines
47 KiB
C++
1426 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 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)
|
|
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)
|
|
{
|
|
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 {
|
|
snprintf(g->Message, sizeof(g->Message), MSG(NO_PART_DEL), "GZ");
|
|
return true;
|
|
} // endif filter
|
|
|
|
break;
|
|
case MODE_INSERT:
|
|
strcpy(opmode, "a+");
|
|
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. */
|
|
/*********************************************************************/
|
|
strcat(opmode, "b");
|
|
Zfile = gzopen(PlugSetPath(filename, To_File, Tdbp->GetPath()), opmode);
|
|
|
|
if (Zfile == NULL) {
|
|
snprintf(g->Message, sizeof(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)))
|
|
{
|
|
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)
|
|
{
|
|
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) {
|
|
LPCSTR name = Tdbp->GetName();
|
|
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) {
|
|
LPCSTR name = Tdbp->GetName();
|
|
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()) {
|
|
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;
|
|
|
|
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)
|
|
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
|
|
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) {
|
|
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)) {
|
|
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) {
|
|
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)
|
|
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)) {
|
|
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)
|
|
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) {
|
|
LPCSTR name = Tdbp->GetName();
|
|
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 ---------------------------- */
|