1 /************ File AM GZ C++ Program Source Code File (.CPP) ***********/
2 /* PROGRAM NAME: FILAMGZ                                               */
3 /* -------------                                                       */
4 /*  Version 1.5                                                        */
5 /*                                                                     */
6 /* COPYRIGHT:                                                          */
7 /* ----------                                                          */
8 /*  (C) Copyright to the author Olivier BERTRAND          2005-2016    */
9 /*                                                                     */
10 /* WHAT THIS PROGRAM DOES:                                             */
11 /* -----------------------                                             */
12 /*  This program are the ZLIB compressed files classes.                */
13 /*                                                                     */
14 /***********************************************************************/
15 
16 /***********************************************************************/
17 /*  Include relevant MariaDB header file.                  */
18 /***********************************************************************/
19 #include "my_global.h"
20 #if defined(_WIN32)
21 #include <io.h>
22 #include <fcntl.h>
23 #if defined(__BORLANDC__)
24 #define __MFC_COMPAT__                   // To define min/max as macro
25 #endif
26 //#include <windows.h>
27 #else   // !_WIN32
28 #if defined(UNIX)
29 #include <errno.h>
30 #else   // !UNIX
31 #include <io.h>
32 #endif
33 #include <fcntl.h>
34 #endif  // !_WIN32
35 
36 /***********************************************************************/
37 /*  Include application header files:                                  */
38 /*  global.h    is header containing all global declarations.          */
39 /*  plgdbsem.h  is header containing the DB application declarations.  */
40 /*  tabdos.h    is header containing the TABDOS class declarations.    */
41 /***********************************************************************/
42 #include "global.h"
43 #include "plgdbsem.h"
44 //#include "catalog.h"
45 //#include "reldef.h"
46 //#include "xobject.h"
47 //#include "kindex.h"
48 #include "filamtxt.h"
49 #include "tabdos.h"
50 #if defined(UNIX)
51 #include "osutil.h"
52 #endif
53 
54 /***********************************************************************/
55 /*  This define prepares ZLIB function declarations.                   */
56 /***********************************************************************/
57 //#define ZLIB_DLL
58 
59 #include "filamgz.h"
60 
61 /***********************************************************************/
62 /*  DB static variables.                                               */
63 /***********************************************************************/
64 extern int num_read, num_there, num_eq[];                 // Statistics
65 
66 /* ------------------------------------------------------------------- */
67 
68 /***********************************************************************/
69 /*  Implementation of the GZFAM class.                                 */
70 /***********************************************************************/
GZFAM(PGZFAM txfp)71 GZFAM::GZFAM(PGZFAM txfp) : TXTFAM(txfp)
72   {
73   Zfile = txfp->Zfile;
74   Zpos = txfp->Zpos;
75   } // end of GZFAM copy constructor
76 
77 /***********************************************************************/
78 /*  Zerror: Error function for gz calls.                               */
79 /*  gzerror returns the error message for the last error which occurred*/
80 /*  on the given compressed file. errnum is set to zlib error number.  */
81 /*  If an error occurred in the file system and not in the compression */
82 /*  library, errnum is set to Z_ERRNO and the application may consult  */
83 /*  errno to get the exact error code.                                 */
84 /***********************************************************************/
Zerror(PGLOBAL g)85 int GZFAM::Zerror(PGLOBAL g)
86   {
87   int errnum;
88 
89   strcpy(g->Message, gzerror(Zfile, &errnum));
90 
91   if (errnum == Z_ERRNO)
92 #if defined(_WIN32)
93     sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(NULL));
94 #else   // !_WIN32
95     sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
96 #endif  // !_WIN32
97 
98     return (errnum == Z_STREAM_END) ? RC_EF : RC_FX;
99   } // end of Zerror
100 
101 /***********************************************************************/
102 /*  Reset: reset position values at the beginning of file.             */
103 /***********************************************************************/
Reset(void)104 void GZFAM::Reset(void)
105   {
106   TXTFAM::Reset();
107 //gzrewind(Zfile);                  // Useful ?????
108   Zpos = 0;
109   } // end of Reset
110 
111 /***********************************************************************/
112 /*  GZ GetFileLength: returns an estimate of what would be the         */
113 /*  uncompressed file size in number of bytes.                         */
114 /***********************************************************************/
GetFileLength(PGLOBAL g)115 int GZFAM::GetFileLength(PGLOBAL g)
116   {
117   int len = TXTFAM::GetFileLength(g);
118 
119   if (len > 0)
120     // Estimate size reduction to a max of 6
121     len *= 6;
122 
123   return len;
124   } // end of GetFileLength
125 
126 /***********************************************************************/
127 /*  GZ Access Method opening routine.                                  */
128 /***********************************************************************/
OpenTableFile(PGLOBAL g)129 bool GZFAM::OpenTableFile(PGLOBAL g)
130   {
131   char    opmode[4], filename[_MAX_PATH];
132   MODE    mode = Tdbp->GetMode();
133 
134   switch (mode) {
135     case MODE_READ:
136       strcpy(opmode, "r");
137       break;
138     case MODE_UPDATE:
139       /*****************************************************************/
140       /* Updating GZ files not implemented yet.                        */
141       /*****************************************************************/
142       strcpy(g->Message, MSG(UPD_ZIP_NOT_IMP));
143       return true;
144     case MODE_DELETE:
145       if (!Tdbp->GetNext()) {
146         // Store the number of deleted lines
147         DelRows = Cardinality(g);
148 
149         // This will erase the entire file
150         strcpy(opmode, "w");
151 //      Block = 0;                // For ZBKFAM
152 //      Last = Nrec;              // For ZBKFAM
153         Tdbp->ResetSize();
154       } else {
155         sprintf(g->Message, MSG(NO_PART_DEL), "GZ");
156         return true;
157       } // endif filter
158 
159       break;
160     case MODE_INSERT:
161       strcpy(opmode, "a+");
162       break;
163     default:
164       sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
165       return true;
166     } // endswitch Mode
167 
168   /*********************************************************************/
169   /*  Open according to logical input/output mode required.            */
170   /*  Use specific zlib functions.                                     */
171   /*  Treat files as binary.                                           */
172   /*********************************************************************/
173   strcat(opmode, "b");
174   Zfile = gzopen(PlugSetPath(filename, To_File, Tdbp->GetPath()), opmode);
175 
176   if (Zfile == NULL) {
177     sprintf(g->Message, MSG(GZOPEN_ERROR),
178             opmode, (int)errno, filename);
179     strcat(strcat(g->Message, ": "), strerror(errno));
180     return (mode == MODE_READ && errno == ENOENT)
181             ? PushWarning(g, Tdbp) : true;
182     } // endif Zfile
183 
184   /*********************************************************************/
185   /*  Something to be done here. >>>>>>>> NOT DONE <<<<<<<<            */
186   /*********************************************************************/
187 //To_Fb = dbuserp->Openlist;     // Keep track of File block
188 
189   /*********************************************************************/
190   /*  Allocate the line buffer.                                        */
191   /*********************************************************************/
192   return AllocateBuffer(g);
193   } // end of OpenTableFile
194 
195 /***********************************************************************/
196 /*  Allocate the line buffer. For mode Delete a bigger buffer has to   */
197 /*  be allocated because is it also used to move lines into the file.  */
198 /***********************************************************************/
AllocateBuffer(PGLOBAL g)199 bool GZFAM::AllocateBuffer(PGLOBAL g)
200   {
201   MODE mode = Tdbp->GetMode();
202 
203   Buflen = Lrecl + 2;                     // Lrecl does not include CRLF
204 //Buflen *= ((Mode == MODE_DELETE) ? DOS_BUFF_LEN : 1);    NIY
205 
206   if (trace(1))
207     htrc("SubAllocating a buffer of %d bytes\n", Buflen);
208 
209   To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
210 
211   if (mode == MODE_INSERT) {
212     /*******************************************************************/
213     /*  For Insert buffer must be prepared.                            */
214     /*******************************************************************/
215     memset(To_Buf, ' ', Buflen);
216     To_Buf[Buflen - 2] = '\n';
217     To_Buf[Buflen - 1] = '\0';
218     } // endif Insert
219 
220   return false;
221   } // end of AllocateBuffer
222 
223 /***********************************************************************/
224 /*  GetRowID: return the RowID of last read record.                    */
225 /***********************************************************************/
GetRowID(void)226 int GZFAM::GetRowID(void)
227   {
228   return Rows;
229   } // end of GetRowID
230 
231 /***********************************************************************/
232 /*  GetPos: return the position of last read record.                   */
233 /***********************************************************************/
GetPos(void)234 int GZFAM::GetPos(void)
235   {
236   return (int)Zpos;
237   } // end of GetPos
238 
239 /***********************************************************************/
240 /*  GetNextPos: return the position of next record.                    */
241 /***********************************************************************/
GetNextPos(void)242 int GZFAM::GetNextPos(void)
243   {
244   return gztell(Zfile);
245   } // end of GetNextPos
246 
247 /***********************************************************************/
248 /*  SetPos: Replace the table at the specified position.               */
249 /***********************************************************************/
SetPos(PGLOBAL g,int pos)250 bool GZFAM::SetPos(PGLOBAL g, int pos __attribute__((unused)))
251   {
252   sprintf(g->Message, MSG(NO_SETPOS_YET), "GZ");
253   return true;
254 #if 0
255   Fpos = pos;
256 
257   if (fseek(Stream, Fpos, SEEK_SET)) {
258     sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
259     return true;
260     } // endif
261 
262   Placed = true;
263   return false;
264 #endif // 0
265   } // end of SetPos
266 
267 /***********************************************************************/
268 /*  Record file position in case of UPDATE or DELETE.                  */
269 /***********************************************************************/
RecordPos(PGLOBAL)270 bool GZFAM::RecordPos(PGLOBAL)
271   {
272   Zpos = gztell(Zfile);
273   return false;
274   } // end of RecordPos
275 
276 /***********************************************************************/
277 /*  Skip one record in file.                                           */
278 /***********************************************************************/
SkipRecord(PGLOBAL g,bool header)279 int GZFAM::SkipRecord(PGLOBAL g, bool header)
280   {
281   // Skip this record
282   if (gzeof(Zfile))
283     return RC_EF;
284   else if (gzgets(Zfile, To_Buf, Buflen) == Z_NULL)
285     return Zerror(g);
286 
287   if (header)
288     RecordPos(g);
289 
290   return RC_OK;
291   } // end of SkipRecord
292 
293 /***********************************************************************/
294 /*  ReadBuffer: Read one line from a compressed text file.             */
295 /***********************************************************************/
ReadBuffer(PGLOBAL g)296 int GZFAM::ReadBuffer(PGLOBAL g)
297   {
298   char *p;
299   int   rc;
300 
301   if (!Zfile)
302     return RC_EF;
303 
304   if (!Placed) {
305     /*******************************************************************/
306     /*  Record file position in case of UPDATE or DELETE.              */
307     /*******************************************************************/
308    next:
309     if (RecordPos(g))
310       return RC_FX;
311 
312     CurBlk = Rows++;                        // Update RowID
313 
314     /*******************************************************************/
315     /*  Check whether optimization on ROWID                            */
316     /*  can be done, as well as for join as for local filtering.       */
317     /*******************************************************************/
318     switch (Tdbp->TestBlock(g)) {
319       case RC_EF:
320         return RC_EF;
321       case RC_NF:
322         // Skip this record
323         if ((rc = SkipRecord(g, FALSE)) != RC_OK)
324           return rc;
325 
326         goto next;
327       } // endswitch rc
328 
329   } else
330     Placed = false;
331 
332   if (gzeof(Zfile)) {
333     rc = RC_EF;
334   } else if (gzgets(Zfile, To_Buf, Buflen) != Z_NULL) {
335     p = To_Buf + strlen(To_Buf) - 1;
336 
337     if (*p == '\n')
338       *p = '\0';              // Eliminate ending new-line character
339 
340     if (*(--p) == '\r')
341       *p = '\0';              // Eliminate eventuel carriage return
342 
343     strcpy(Tdbp->GetLine(), To_Buf);
344     IsRead = true;
345     rc = RC_OK;
346     num_read++;
347   } else
348     rc = Zerror(g);
349 
350   if (trace(2))
351     htrc(" Read: '%s' rc=%d\n", To_Buf, rc);
352 
353   return rc;
354   } // end of ReadBuffer
355 
356 /***********************************************************************/
357 /*  WriteDB: Data Base write routine for ZDOS access method.           */
358 /*  Update is not possible without using a temporary file (NIY).       */
359 /***********************************************************************/
WriteBuffer(PGLOBAL g)360 int GZFAM::WriteBuffer(PGLOBAL g)
361   {
362   /*********************************************************************/
363   /*  Prepare the write buffer.                                        */
364   /*********************************************************************/
365   strcat(strcpy(To_Buf, Tdbp->GetLine()), CrLf);
366 
367   /*********************************************************************/
368   /*  Now start the writing process.                                   */
369   /*********************************************************************/
370   if (gzputs(Zfile, To_Buf) < 0)
371     return Zerror(g);
372 
373   return RC_OK;
374   } // end of WriteBuffer
375 
376 /***********************************************************************/
377 /*  Data Base delete line routine for ZDOS access method.  (NIY)       */
378 /***********************************************************************/
DeleteRecords(PGLOBAL g,int)379 int GZFAM::DeleteRecords(PGLOBAL g, int)
380   {
381   strcpy(g->Message, MSG(NO_ZIP_DELETE));
382   return RC_FX;
383   } // end of DeleteRecords
384 
385 /***********************************************************************/
386 /*  Data Base close routine for DOS access method.                     */
387 /***********************************************************************/
CloseTableFile(PGLOBAL,bool)388 void GZFAM::CloseTableFile(PGLOBAL, bool)
389   {
390   int rc = gzclose(Zfile);
391 
392   if (trace(1))
393     htrc("GZ CloseDB: closing %s rc=%d\n", To_File, rc);
394 
395   Zfile = NULL;            // So we can know whether table is open
396 //To_Fb->Count = 0;        // Avoid double closing by PlugCloseAll
397   } // end of CloseTableFile
398 
399 /***********************************************************************/
400 /*  Rewind routine for GZ access method.                               */
401 /***********************************************************************/
Rewind(void)402 void GZFAM::Rewind(void)
403   {
404   gzrewind(Zfile);
405   } // end of Rewind
406 
407 /* ------------------------------------------------------------------- */
408 
409 /***********************************************************************/
410 /*  Constructors.                                                      */
411 /***********************************************************************/
ZBKFAM(PDOSDEF tdp)412 ZBKFAM::ZBKFAM(PDOSDEF tdp) : GZFAM(tdp)
413   {
414   Blocked = true;
415   Block = tdp->GetBlock();
416   Last = tdp->GetLast();
417   Nrec = tdp->GetElemt();
418   CurLine = NULL;
419   NxtLine = NULL;
420   Closing = false;
421   BlkPos = tdp->GetTo_Pos();
422   } // end of ZBKFAM standard constructor
423 
ZBKFAM(PZBKFAM txfp)424 ZBKFAM::ZBKFAM(PZBKFAM txfp) : GZFAM(txfp)
425   {
426   CurLine = txfp->CurLine;
427   NxtLine = txfp->NxtLine;
428   Closing = txfp->Closing;
429   } // end of ZBKFAM copy constructor
430 
431 /***********************************************************************/
432 /*  Use BlockTest to reduce the table estimated size.                  */
433 /***********************************************************************/
MaxBlkSize(PGLOBAL g,int)434 int ZBKFAM::MaxBlkSize(PGLOBAL g, int)
435   {
436   int rc = RC_OK, savcur = CurBlk;
437   int size;
438 
439   // Roughly estimate the table size as the sum of blocks
440   // that can contain good rows
441   for (size = 0, CurBlk = 0; CurBlk < Block; CurBlk++)
442     if ((rc = Tdbp->TestBlock(g)) == RC_OK)
443       size += (CurBlk == Block - 1) ? Last : Nrec;
444     else if (rc == RC_EF)
445       break;
446 
447   CurBlk = savcur;
448   return size;
449   } // end of MaxBlkSize
450 
451 /***********************************************************************/
452 /*  ZBK Cardinality: returns table cardinality in number of rows.      */
453 /*  This function can be called with a null argument to test the       */
454 /*  availability of Cardinality implementation (1 yes, 0 no).          */
455 /***********************************************************************/
Cardinality(PGLOBAL g)456 int ZBKFAM::Cardinality(PGLOBAL g)
457   {
458   return (g) ? (int)((Block - 1) * Nrec + Last) : 1;
459   } // end of Cardinality
460 
461 /***********************************************************************/
462 /*  Allocate the line buffer. For mode Delete a bigger buffer has to   */
463 /*  be allocated because is it also used to move lines into the file.  */
464 /***********************************************************************/
AllocateBuffer(PGLOBAL g)465 bool ZBKFAM::AllocateBuffer(PGLOBAL g)
466   {
467   Buflen = Nrec * (Lrecl + 2);
468   CurLine = To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
469 
470   if (Tdbp->GetMode() == MODE_INSERT) {
471     // Set values so Block and Last can be recalculated
472     if (Last == Nrec) {
473       CurBlk = Block;
474       Rbuf = Nrec;                   // To be used by WriteDB
475     } else {
476       // The last block must be completed
477       CurBlk = Block - 1;
478       Rbuf = Nrec - Last;            // To be used by WriteDB
479     } // endif Last
480 
481     } // endif Insert
482 
483   return false;
484   } // end of AllocateBuffer
485 
486 /***********************************************************************/
487 /*  GetRowID: return the RowID of last read record.                    */
488 /***********************************************************************/
GetRowID(void)489 int ZBKFAM::GetRowID(void)
490   {
491   return CurNum + Nrec * CurBlk + 1;
492   } // end of GetRowID
493 
494 /***********************************************************************/
495 /*  GetPos: return the position of last read record.                   */
496 /***********************************************************************/
GetPos(void)497 int ZBKFAM::GetPos(void)
498   {
499   return CurNum + Nrec * CurBlk;            // Computed file index
500   } // end of GetPos
501 
502 /***********************************************************************/
503 /*  Record file position in case of UPDATE or DELETE.                  */
504 /*  Not used yet for fixed tables.                                     */
505 /***********************************************************************/
RecordPos(PGLOBAL)506 bool ZBKFAM::RecordPos(PGLOBAL /*g*/)
507   {
508 //strcpy(g->Message, "RecordPos not implemented for gz blocked tables");
509 //return true;
510   return RC_OK;
511   } // end of RecordPos
512 
513 /***********************************************************************/
514 /*  Skip one record in file.                                           */
515 /***********************************************************************/
SkipRecord(PGLOBAL,bool)516 int ZBKFAM::SkipRecord(PGLOBAL /*g*/, bool)
517   {
518 //strcpy(g->Message, "SkipRecord not implemented for gz blocked tables");
519 //return RC_FX;
520   return RC_OK;
521   } // end of SkipRecord
522 
523 /***********************************************************************/
524 /*  ReadBuffer: Read one line from a compressed text file.             */
525 /***********************************************************************/
ReadBuffer(PGLOBAL g)526 int ZBKFAM::ReadBuffer(PGLOBAL g)
527   {
528   int     n, skip, rc = RC_OK;
529 
530   /*********************************************************************/
531   /*  Sequential reading when Placed is not true.                      */
532   /*********************************************************************/
533   if (++CurNum < Rbuf) {
534     CurLine = NxtLine;
535 
536     // Get the position of the next line in the buffer
537     while (*NxtLine++ != '\n') ;
538 
539     // Set caller line buffer
540     n = (int)(NxtLine - CurLine - Ending);
541     memcpy(Tdbp->GetLine(), CurLine, n);
542     Tdbp->GetLine()[n] = '\0';
543     return RC_OK;
544   } else if (Rbuf < Nrec && CurBlk != -1)
545     return RC_EF;
546 
547   /*********************************************************************/
548   /*  New block.                                                       */
549   /*********************************************************************/
550   CurNum = 0;
551   skip = 0;
552 
553  next:
554   if (++CurBlk >= Block)
555     return RC_EF;
556 
557   /*********************************************************************/
558   /*  Before using the new block, check whether block optimization     */
559   /*  can be done, as well as for join as for local filtering.         */
560   /*********************************************************************/
561   switch (Tdbp->TestBlock(g)) {
562     case RC_EF:
563       return RC_EF;
564     case RC_NF:
565       skip++;
566       goto next;
567     } // endswitch rc
568 
569   if (skip)
570     // Skip blocks rejected by block optimization
571     for (int i = CurBlk - skip; i < CurBlk; i++) {
572       BlkLen = BlkPos[i + 1] - BlkPos[i];
573 
574       if (gzseek(Zfile, (z_off_t)BlkLen, SEEK_CUR) < 0)
575         return Zerror(g);
576 
577       } // endfor i
578 
579   BlkLen = BlkPos[CurBlk + 1] - BlkPos[CurBlk];
580 
581   if (!(n = gzread(Zfile, To_Buf, BlkLen))) {
582     rc = RC_EF;
583   } else if (n > 0) {
584     // Get the position of the current line
585     CurLine = To_Buf;
586 
587     // Now get the position of the next line
588     for (NxtLine = CurLine; *NxtLine++ != '\n';) ;
589 
590     // Set caller line buffer
591     n = (int)(NxtLine - CurLine - Ending);
592     memcpy(Tdbp->GetLine(), CurLine, n);
593     Tdbp->GetLine()[n] = '\0';
594     Rbuf = (CurBlk == Block - 1) ? Last : Nrec;
595     IsRead = true;
596     rc = RC_OK;
597     num_read++;
598   } else
599     rc = Zerror(g);
600 
601   return rc;
602   } // end of ReadBuffer
603 
604 /***********************************************************************/
605 /*  WriteDB: Data Base write routine for ZDOS access method.           */
606 /*  Update is not possible without using a temporary file (NIY).       */
607 /***********************************************************************/
WriteBuffer(PGLOBAL g)608 int ZBKFAM::WriteBuffer(PGLOBAL g)
609   {
610   /*********************************************************************/
611   /*  Prepare the write buffer.                                        */
612   /*********************************************************************/
613   if (!Closing)
614     strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf);
615 
616   /*********************************************************************/
617   /*  In Insert mode, blocs are added sequentialy to the file end.     */
618   /*  Note: Update mode is not handled for gz files.                   */
619   /*********************************************************************/
620   if (++CurNum == Rbuf) {
621     /*******************************************************************/
622     /*  New block, start the writing process.                          */
623     /*******************************************************************/
624     BlkLen = CurLine + strlen(CurLine) - To_Buf;
625 
626     if (gzwrite(Zfile, To_Buf, BlkLen) != BlkLen ||
627         gzflush(Zfile, Z_FULL_FLUSH)) {
628       Closing = true;
629       return Zerror(g);
630       } // endif gzwrite
631 
632     Rbuf = Nrec;
633     CurBlk++;
634     CurNum = 0;
635     CurLine = To_Buf;
636   } else
637     CurLine += strlen(CurLine);
638 
639   return RC_OK;
640   } // end of WriteBuffer
641 
642 /***********************************************************************/
643 /*  Data Base delete line routine for ZBK access method.               */
644 /*  Implemented only for total deletion of the table, which is done    */
645 /*  by opening the file in mode "wb".                                  */
646 /***********************************************************************/
DeleteRecords(PGLOBAL g,int irc)647 int ZBKFAM::DeleteRecords(PGLOBAL g, int irc)
648   {
649   if (irc == RC_EF) {
650     LPCSTR  name __attribute__((unused)) = Tdbp->GetName();
651     PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
652 
653     defp->SetBlock(0);
654     defp->SetLast(Nrec);
655 
656     if (!defp->SetIntCatInfo("Blocks", 0) ||
657         !defp->SetIntCatInfo("Last", 0)) {
658       sprintf(g->Message, MSG(UPDATE_ERROR), "Header");
659       return RC_FX;
660     } else
661       return RC_OK;
662 
663   } else
664     return irc;
665 
666   } // end of DeleteRecords
667 
668 /***********************************************************************/
669 /*  Data Base close routine for ZBK access method.                     */
670 /***********************************************************************/
CloseTableFile(PGLOBAL g,bool)671 void ZBKFAM::CloseTableFile(PGLOBAL g, bool)
672   {
673   int rc = RC_OK;
674 
675   if (Tdbp->GetMode() == MODE_INSERT) {
676     LPCSTR  name __attribute__((unused))= Tdbp->GetName();
677     PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
678 
679     if (CurNum && !Closing) {
680       // Some more inserted lines remain to be written
681       Last = (Nrec - Rbuf) + CurNum;
682       Block = CurBlk + 1;
683       Rbuf = CurNum--;
684       Closing = true;
685       rc = WriteBuffer(g);
686     } else if (Rbuf == Nrec) {
687       Last = Nrec;
688       Block = CurBlk;
689     } // endif CurNum
690 
691     if (rc != RC_FX) {
692       defp->SetBlock(Block);
693       defp->SetLast(Last);
694       defp->SetIntCatInfo("Blocks", Block);
695       defp->SetIntCatInfo("Last", Last);
696       } // endif
697 
698     gzclose(Zfile);
699   } else if (Tdbp->GetMode() == MODE_DELETE) {
700     rc = DeleteRecords(g, RC_EF);
701     gzclose(Zfile);
702   } else
703     rc = gzclose(Zfile);
704 
705   if (trace(1))
706     htrc("GZ CloseDB: closing %s rc=%d\n", To_File, rc);
707 
708   Zfile = NULL;            // So we can know whether table is open
709 //To_Fb->Count = 0;        // Avoid double closing by PlugCloseAll
710   } // end of CloseTableFile
711 
712 /***********************************************************************/
713 /*  Rewind routine for ZBK access method.                              */
714 /***********************************************************************/
Rewind(void)715 void ZBKFAM::Rewind(void)
716   {
717   gzrewind(Zfile);
718   CurBlk = -1;
719   CurNum = Rbuf;
720   } // end of Rewind
721 
722 /* ------------------------------------------------------------------- */
723 
724 /***********************************************************************/
725 /*  Constructors.                                                      */
726 /***********************************************************************/
GZXFAM(PDOSDEF tdp)727 GZXFAM::GZXFAM(PDOSDEF tdp) : ZBKFAM(tdp)
728   {
729 //Block = tdp->GetBlock();
730 //Last = tdp->GetLast();
731   Nrec = (tdp->GetElemt()) ? tdp->GetElemt() : DOS_BUFF_LEN;
732   Blksize = Nrec * Lrecl;
733   } // end of GZXFAM standard constructor
734 
735 /***********************************************************************/
736 /*  ZIX Cardinality: returns table cardinality in number of rows.      */
737 /*  This function can be called with a null argument to test the       */
738 /*  availability of Cardinality implementation (1 yes, 0 no).          */
739 /***********************************************************************/
Cardinality(PGLOBAL g)740 int GZXFAM::Cardinality(PGLOBAL g)
741   {
742   if (Last)
743     return (g) ? (int)((Block - 1) * Nrec + Last) : 1;
744   else  // Last and Block not defined, cannot do it yet
745     return 0;
746 
747   } // end of Cardinality
748 
749 /***********************************************************************/
750 /*  Allocate the line buffer. For mode Delete a bigger buffer has to   */
751 /*  be allocated because is it also used to move lines into the file.  */
752 /***********************************************************************/
AllocateBuffer(PGLOBAL g)753 bool GZXFAM::AllocateBuffer(PGLOBAL g)
754   {
755   Buflen = Blksize;
756   To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
757 
758   if (Tdbp->GetMode() == MODE_INSERT) {
759     /*******************************************************************/
760     /*  For Insert the buffer must be prepared.                        */
761     /*******************************************************************/
762     memset(To_Buf, ' ', Buflen);
763 
764     if (Tdbp->GetFtype() < 2)
765       // if not binary, the file is physically a text file
766       for (int len = Lrecl; len <= Buflen; len += Lrecl) {
767 #if defined(_WIN32)
768         To_Buf[len - 2] = '\r';
769 #endif   // _WIN32
770         To_Buf[len - 1] = '\n';
771         } // endfor len
772 
773     // Set values so Block and Last can be recalculated
774     if (Last == Nrec) {
775       CurBlk = Block;
776       Rbuf = Nrec;                   // To be used by WriteDB
777     } else {
778       // The last block must be completed
779       CurBlk = Block - 1;
780       Rbuf = Nrec - Last;            // To be used by WriteDB
781     } // endif Last
782 
783     } // endif Insert
784 
785   return false;
786   } // end of AllocateBuffer
787 
788 /***********************************************************************/
789 /*  ReadBuffer: Read one line from a compressed text file.             */
790 /***********************************************************************/
ReadBuffer(PGLOBAL g)791 int GZXFAM::ReadBuffer(PGLOBAL g)
792   {
793   int n, rc = RC_OK;
794 
795   /*********************************************************************/
796   /*  Sequential reading when Placed is not true.                      */
797   /*********************************************************************/
798   if (++CurNum < Rbuf) {
799     Tdbp->IncLine(Lrecl);                // Used by DOSCOL functions
800     return RC_OK;
801   } else if (Rbuf < Nrec && CurBlk != -1)
802     return RC_EF;
803 
804   /*********************************************************************/
805   /*  New block.                                                       */
806   /*********************************************************************/
807   CurNum = 0;
808   Tdbp->SetLine(To_Buf);
809 
810   int skip = 0;
811 
812  next:
813   if (++CurBlk >= Block)
814     return RC_EF;
815 
816   /*********************************************************************/
817   /*  Before using the new block, check whether block optimization     */
818   /*  can be done, as well as for join as for local filtering.         */
819   /*********************************************************************/
820   switch (Tdbp->TestBlock(g)) {
821     case RC_EF:
822       return RC_EF;
823     case RC_NF:
824       skip++;
825       goto next;
826     } // endswitch rc
827 
828   if (skip)
829     // Skip blocks rejected by block optimization
830     for (int i = 0; i < skip; i++) {
831       if (gzseek(Zfile, (z_off_t)Buflen, SEEK_CUR) < 0)
832         return Zerror(g);
833 
834       } // endfor i
835 
836   if (!(n = gzread(Zfile, To_Buf, Buflen))) {
837     rc = RC_EF;
838   } else if (n > 0) {
839     Rbuf = n / Lrecl;
840     IsRead = true;
841     rc = RC_OK;
842     num_read++;
843   } else
844     rc = Zerror(g);
845 
846   return rc;
847   } // end of ReadBuffer
848 
849 /***********************************************************************/
850 /*  WriteDB: Data Base write routine for ZDOS access method.           */
851 /*  Update is not possible without using a temporary file (NIY).       */
852 /***********************************************************************/
WriteBuffer(PGLOBAL g)853 int GZXFAM::WriteBuffer(PGLOBAL g)
854   {
855   /*********************************************************************/
856   /*  In Insert mode, blocs are added sequentialy to the file end.     */
857   /*  Note: Update mode is not handled for gz files.                   */
858   /*********************************************************************/
859   if (++CurNum == Rbuf) {
860     /*******************************************************************/
861     /*  New block, start the writing process.                          */
862     /*******************************************************************/
863     BlkLen = Rbuf * Lrecl;
864 
865     if (gzwrite(Zfile, To_Buf, BlkLen) != BlkLen ||
866         gzflush(Zfile, Z_FULL_FLUSH)) {
867       Closing = true;
868       return Zerror(g);
869       } // endif gzwrite
870 
871     Rbuf = Nrec;
872     CurBlk++;
873     CurNum = 0;
874     Tdbp->SetLine(To_Buf);
875   } else
876     Tdbp->IncLine(Lrecl);            // Used by FIXCOL functions
877 
878   return RC_OK;
879   } // end of WriteBuffer
880 
881 /* --------------------------- Class ZLBFAM -------------------------- */
882 
883 /***********************************************************************/
884 /*  Constructors.                                                      */
885 /***********************************************************************/
ZLBFAM(PDOSDEF tdp)886 ZLBFAM::ZLBFAM(PDOSDEF tdp) : BLKFAM(tdp)
887   {
888   Zstream = NULL;
889   Zbuffer = NULL;
890   Zlenp = NULL;
891   Optimized = tdp->IsOptimized();
892   } // end of ZLBFAM standard constructor
893 
ZLBFAM(PZLBFAM txfp)894 ZLBFAM::ZLBFAM(PZLBFAM txfp) : BLKFAM(txfp)
895   {
896   Zstream = txfp->Zstream;
897   Zbuffer = txfp->Zbuffer;
898   Zlenp = txfp->Zlenp;
899   Optimized = txfp->Optimized;
900   } // end of ZLBFAM (dummy?) copy constructor
901 
902 /***********************************************************************/
903 /*  ZLB GetFileLength: returns an estimate of what would be the        */
904 /*  uncompressed file size in number of bytes.                         */
905 /***********************************************************************/
GetFileLength(PGLOBAL g)906 int ZLBFAM::GetFileLength(PGLOBAL g)
907   {
908   int len = (Optimized) ? BlkPos[Block] : BLKFAM::GetFileLength(g);
909 
910   if (len > 0)
911     // Estimate size reduction to a max of 5
912     len *= 5;
913 
914   return len;
915   } // end of GetFileLength
916 
917 /***********************************************************************/
918 /*  Allocate the line buffer. For mode Delete a bigger buffer has to   */
919 /*  be allocated because is it also used to move lines into the file.  */
920 /***********************************************************************/
AllocateBuffer(PGLOBAL g)921 bool ZLBFAM::AllocateBuffer(PGLOBAL g)
922   {
923   PCSZ msg;
924   int  n, zrc;
925 
926 #if 0
927   if (!Optimized && Tdbp->NeedIndexing(g)) {
928     strcpy(g->Message, MSG(NOP_ZLIB_INDEX));
929     return TRUE;
930     } // endif indexing
931 #endif // 0
932 
933 #if defined(NOLIB)
934   if (!zlib && LoadZlib()) {
935     sprintf(g->Message, MSG(DLL_LOAD_ERROR), GetLastError(), "zlib.dll");
936     return TRUE;
937     } // endif zlib
938 #endif
939 
940   BLKFAM::AllocateBuffer(g);
941 //Buflen = Nrec * (Lrecl + 2);
942 //Rbuf = Nrec;
943 
944   // Allocate the compressed buffer
945   n = Buflen + 16;             // ?????????????????????????????????
946   Zlenp = (int*)PlugSubAlloc(g, NULL, n);
947   Zbuffer = (Byte*)(Zlenp + 1);
948 
949   // Allocate and initialize the Z stream
950   Zstream = (z_streamp)PlugSubAlloc(g, NULL, sizeof(z_stream));
951   Zstream->zalloc = (alloc_func)0;
952   Zstream->zfree = (free_func)0;
953   Zstream->opaque = (voidpf)0;
954   Zstream->next_in = NULL;
955   Zstream->avail_in = 0;
956 
957   if (Tdbp->GetMode() == MODE_READ) {
958     msg = "inflateInit";
959     zrc = inflateInit(Zstream);
960   } else {
961     msg = "deflateInit";
962     zrc = deflateInit(Zstream, Z_DEFAULT_COMPRESSION);
963   } // endif Mode
964 
965   if (zrc != Z_OK) {
966     if (Zstream->msg)
967       sprintf(g->Message, "%s error: %s", msg, Zstream->msg);
968     else
969       sprintf(g->Message, "%s error: %d", msg, zrc);
970 
971     return TRUE;
972     } // endif zrc
973 
974   if (Tdbp->GetMode() == MODE_INSERT) {
975     // Write the file header block
976     if (Last == Nrec) {
977       CurBlk = Block;
978       CurNum = 0;
979 
980       if (!GetFileLength(g)) {
981         // Write the zlib header as an extra block
982         strcpy(To_Buf, "PlugDB");
983         BlkLen = strlen("PlugDB") + 1;
984 
985         if (WriteCompressedBuffer(g))
986           return TRUE;
987 
988         } // endif void file
989 
990     } else {
991       // In mode insert, if Last != Nrec, last block must be updated
992       CurBlk = Block - 1;
993       CurNum = Last;
994 
995       strcpy(g->Message, MSG(NO_PAR_BLK_INS));
996       return TRUE;
997     } // endif Last
998 
999   } else { // MODE_READ
1000     // First thing to do is to read the header block
1001     void *rdbuf;
1002 
1003     if (Optimized) {
1004       BlkLen = BlkPos[0];
1005       rdbuf = Zlenp;
1006     } else {
1007       // Get the stored length from the file itself
1008       if (fread(Zlenp, sizeof(int), 1, Stream) != 1)
1009         return FALSE;             // Empty file
1010 
1011       BlkLen = *Zlenp;
1012       rdbuf = Zbuffer;
1013     } // endif Optimized
1014 
1015     switch (ReadCompressedBuffer(g, rdbuf)) {
1016       case RC_EF:
1017         return FALSE;
1018       case RC_FX:
1019 #if defined(UNIX)
1020         sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
1021 #else
1022         sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
1023 #endif
1024         /* falls through */
1025       case RC_NF:
1026         return TRUE;
1027       } // endswitch
1028 
1029     // Some old tables can have PlugDB in their header
1030     if (strcmp(To_Buf, "PlugDB")) {
1031       sprintf(g->Message, MSG(BAD_HEADER), Tdbp->GetFile(g));
1032       return TRUE;
1033       } // endif strcmp
1034 
1035   } // endif Mode
1036 
1037   return FALSE;
1038   } // end of AllocateBuffer
1039 
1040 /***********************************************************************/
1041 /*  GetPos: return the position of last read record.                   */
1042 /***********************************************************************/
GetPos(void)1043 int ZLBFAM::GetPos(void)
1044   {
1045   return (Optimized) ? (CurNum + Nrec * CurBlk) : Fpos;
1046   } // end of GetPos
1047 
1048 /***********************************************************************/
1049 /*  GetNextPos: should not be called for this class.                   */
1050 /***********************************************************************/
GetNextPos(void)1051 int ZLBFAM::GetNextPos(void)
1052   {
1053   if (Optimized) {
1054     assert(FALSE);
1055     return 0;
1056   } else
1057     return ftell(Stream);
1058 
1059   } // end of GetNextPos
1060 
1061 /***********************************************************************/
1062 /*  SetPos: Replace the table at the specified position.               */
1063 /***********************************************************************/
SetPos(PGLOBAL g,int pos)1064 bool ZLBFAM::SetPos(PGLOBAL g, int pos __attribute__((unused)))
1065   {
1066   sprintf(g->Message, MSG(NO_SETPOS_YET), "GZ");
1067   return true;
1068 #if 0 // All this must be checked
1069   if (pos < 0) {
1070     strcpy(g->Message, MSG(INV_REC_POS));
1071     return true;
1072     } // endif recpos
1073 
1074   CurBlk = pos / Nrec;
1075   CurNum = pos % Nrec;
1076 #if defined(_DEBUG)
1077   num_eq[(CurBlk == OldBlk) ? 1 : 0]++;
1078 #endif
1079 
1080   // Indicate the table position was externally set
1081   Placed = true;
1082   return false;
1083 #endif // 0
1084   } // end of SetPos
1085 
1086 /***********************************************************************/
1087 /*  ReadBuffer: Read one line for a text file.                         */
1088 /***********************************************************************/
ReadBuffer(PGLOBAL g)1089 int ZLBFAM::ReadBuffer(PGLOBAL g)
1090   {
1091   size_t   n;
1092   void *rdbuf;
1093 
1094   /*********************************************************************/
1095   /*  Sequential reading when Placed is not true.                      */
1096   /*********************************************************************/
1097   if (Placed) {
1098     Placed = FALSE;
1099   } else if (++CurNum < Rbuf) {
1100     CurLine = NxtLine;
1101 
1102     // Get the position of the next line in the buffer
1103     if (Tdbp->GetFtype() == RECFM_VAR)
1104       while (*NxtLine++ != '\n') ;
1105     else
1106       NxtLine += Lrecl;
1107 
1108     // Set caller line buffer
1109     n = NxtLine - CurLine - ((Tdbp->GetFtype() == RECFM_BIN) ? 0 : Ending);
1110     memcpy(Tdbp->GetLine(), CurLine, n);
1111     Tdbp->GetLine()[n] = '\0';
1112     return RC_OK;
1113   } else if (Rbuf < Nrec && CurBlk != -1) {
1114     CurNum--;         // To have a correct Last value when optimizing
1115     return RC_EF;
1116   } else {
1117     /*******************************************************************/
1118     /*  New block.                                                     */
1119     /*******************************************************************/
1120     CurNum = 0;
1121 
1122    next:
1123     if (++CurBlk >= Block)
1124       return RC_EF;
1125 
1126     /*******************************************************************/
1127     /*  Before reading a new block, check whether block optimization   */
1128     /*  can be done, as well as for join as for local filtering.       */
1129     /*******************************************************************/
1130     if (Optimized) switch (Tdbp->TestBlock(g)) {
1131       case RC_EF:
1132         return RC_EF;
1133       case RC_NF:
1134         goto next;
1135       } // endswitch rc
1136 
1137   } // endif's
1138 
1139   if (OldBlk == CurBlk)
1140     goto ok;         // Block is already there
1141 
1142   if (Optimized) {
1143     // Store the position of next block
1144     Fpos = BlkPos[CurBlk];
1145 
1146     // fseek is required only in non sequential reading
1147     if (CurBlk != OldBlk + 1)
1148       if (fseek(Stream, Fpos, SEEK_SET)) {
1149         sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
1150         return RC_FX;
1151         } // endif fseek
1152 
1153     // Calculate the length of block to read
1154     BlkLen = BlkPos[CurBlk + 1] - Fpos;
1155     rdbuf = Zlenp;
1156   } else {                     // !Optimized
1157     if (CurBlk != OldBlk + 1) {
1158       strcpy(g->Message, MSG(INV_RAND_ACC));
1159       return RC_FX;
1160     } else
1161       Fpos = ftell(Stream);    // Used when optimizing
1162 
1163     // Get the stored length from the file itself
1164     if (fread(Zlenp, sizeof(int), 1, Stream) != 1) {
1165       if (feof(Stream))
1166         return RC_EF;
1167 
1168       goto err;
1169       } // endif fread
1170 
1171     BlkLen = *Zlenp;
1172     rdbuf = Zbuffer;
1173   } // endif Optimized
1174 
1175   // Read the next block
1176   switch (ReadCompressedBuffer(g, rdbuf)) {
1177     case RC_FX: goto err;
1178     case RC_NF: return RC_FX;
1179     case RC_EF: return RC_EF;
1180     default: Rbuf = (CurBlk == Block - 1) ? Last : Nrec;
1181     } // endswitch ReadCompressedBuffer
1182 
1183  ok:
1184   if (Tdbp->GetFtype() == RECFM_VAR) {
1185     int i;
1186 
1187     // Get the position of the current line
1188     for (i = 0, CurLine = To_Buf; i < CurNum; i++)
1189       while (*CurLine++ != '\n') ;      // What about Unix ???
1190 
1191     // Now get the position of the next line
1192     for (NxtLine = CurLine; *NxtLine++ != '\n';) ;
1193 
1194     // Set caller line buffer
1195     n = NxtLine - CurLine - Ending;
1196   } else {
1197     CurLine = To_Buf + CurNum * Lrecl;
1198     NxtLine = CurLine + Lrecl;
1199     n = Lrecl - ((Tdbp->GetFtype() == RECFM_BIN) ? 0 : Ending);
1200   } // endif Ftype
1201 
1202   memcpy(Tdbp->GetLine(), CurLine, n);
1203   Tdbp->GetLine()[n] = '\0';
1204 
1205   OldBlk = CurBlk;         // Last block actually read
1206   IsRead = TRUE;           // Is read indeed
1207   return RC_OK;
1208 
1209  err:
1210 #if defined(UNIX)
1211   sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
1212 #else
1213   sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
1214 #endif
1215   return RC_FX;
1216   } // end of ReadBuffer
1217 
1218 /***********************************************************************/
1219 /*  Read and decompress a block from the stream.                       */
1220 /***********************************************************************/
ReadCompressedBuffer(PGLOBAL g,void * rdbuf)1221 int ZLBFAM::ReadCompressedBuffer(PGLOBAL g, void *rdbuf)
1222   {
1223   if (fread(rdbuf, 1, (size_t)BlkLen, Stream) == (unsigned)BlkLen) {
1224     int zrc;
1225 
1226     num_read++;
1227 
1228     if (Optimized && BlkLen != signed(*Zlenp + sizeof(int))) {
1229       sprintf(g->Message, MSG(BAD_BLK_SIZE), CurBlk + 1);
1230       return RC_NF;
1231       } // endif BlkLen
1232 
1233     // HERE WE MUST INFLATE THE BLOCK
1234     Zstream->next_in = Zbuffer;
1235     Zstream->avail_in = (uInt)(*Zlenp);
1236     Zstream->next_out = (Byte*)To_Buf;
1237     Zstream->avail_out = Buflen;
1238     zrc = inflate(Zstream, Z_SYNC_FLUSH);
1239 
1240     if (zrc != Z_OK) {
1241       if (Zstream->msg)
1242         sprintf(g->Message, MSG(FUNC_ERR_S), "inflate", Zstream->msg);
1243       else
1244         sprintf(g->Message, MSG(FUNCTION_ERROR), "inflate", (int)zrc);
1245 
1246       return RC_NF;
1247       } // endif zrc
1248 
1249   } else if (feof(Stream)) {
1250     return RC_EF;
1251   } else
1252     return RC_FX;
1253 
1254   return RC_OK;
1255   } // end of ReadCompressedBuffer
1256 
1257 /***********************************************************************/
1258 /*  WriteBuffer: File write routine for DOS access method.             */
1259 /*  Update is directly written back into the file,                     */
1260 /*         with this (fast) method, record size cannot change.         */
1261 /***********************************************************************/
WriteBuffer(PGLOBAL g)1262 int ZLBFAM::WriteBuffer(PGLOBAL g)
1263   {
1264   assert (Tdbp->GetMode() == MODE_INSERT);
1265 
1266   /*********************************************************************/
1267   /*  Prepare the write buffer.                                        */
1268   /*********************************************************************/
1269   if (!Closing) {
1270     if (Tdbp->GetFtype() == RECFM_BIN)
1271       memcpy(CurLine, Tdbp->GetLine(), Lrecl);
1272     else
1273       strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf);
1274 
1275 #if defined(_DEBUG)
1276     if (Tdbp->GetFtype() == RECFM_FIX &&
1277       (signed)strlen(CurLine) != Lrecl + (signed)strlen(CrLf)) {
1278       strcpy(g->Message, MSG(BAD_LINE_LEN));
1279       Closing = TRUE;
1280       return RC_FX;
1281       } // endif Lrecl
1282 #endif   // _DEBUG
1283     } // endif Closing
1284 
1285   /*********************************************************************/
1286   /*  In Insert mode, blocs are added sequentialy to the file end.     */
1287   /*********************************************************************/
1288   if (++CurNum != Rbuf) {
1289     if (Tdbp->GetFtype() == RECFM_VAR)
1290       CurLine += strlen(CurLine);
1291     else
1292       CurLine += Lrecl;
1293 
1294     return RC_OK;                    // We write only full blocks
1295     } // endif CurNum
1296 
1297   // HERE WE MUST DEFLATE THE BLOCK
1298   if (Tdbp->GetFtype() == RECFM_VAR)
1299     NxtLine = CurLine + strlen(CurLine);
1300   else
1301     NxtLine = CurLine + Lrecl;
1302 
1303   BlkLen = (int)(NxtLine - To_Buf);
1304 
1305   if (WriteCompressedBuffer(g)) {
1306     Closing = TRUE;      // To tell CloseDB about a Write error
1307     return RC_FX;
1308     } // endif WriteCompressedBuffer
1309 
1310   CurBlk++;
1311   CurNum = 0;
1312   CurLine = To_Buf;
1313   return RC_OK;
1314   } // end of WriteBuffer
1315 
1316 /***********************************************************************/
1317 /*  Compress the buffer and write the deflated output to stream.       */
1318 /***********************************************************************/
WriteCompressedBuffer(PGLOBAL g)1319 bool ZLBFAM::WriteCompressedBuffer(PGLOBAL g)
1320   {
1321   int zrc;
1322 
1323   Zstream->next_in = (Byte*)To_Buf;
1324   Zstream->avail_in = (uInt)BlkLen;
1325   Zstream->next_out = Zbuffer;
1326   Zstream->avail_out = Buflen + 16;
1327   Zstream->total_out = 0;
1328   zrc = deflate(Zstream, Z_FULL_FLUSH);
1329 
1330   if (zrc != Z_OK) {
1331     if (Zstream->msg)
1332       sprintf(g->Message, MSG(FUNC_ERR_S), "deflate", Zstream->msg);
1333     else
1334       sprintf(g->Message, MSG(FUNCTION_ERROR), "deflate", (int)zrc);
1335 
1336     return TRUE;
1337   } else
1338     *Zlenp = Zstream->total_out;
1339 
1340   //  Now start the writing process.
1341   BlkLen = *Zlenp + sizeof(int);
1342 
1343   if (fwrite(Zlenp, 1, BlkLen, Stream) != (size_t)BlkLen) {
1344     sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
1345     return TRUE;
1346     } // endif size
1347 
1348   return FALSE;
1349   } // end of WriteCompressedBuffer
1350 
1351 /***********************************************************************/
1352 /*  Table file close routine for DOS access method.                    */
1353 /***********************************************************************/
CloseTableFile(PGLOBAL g,bool)1354 void ZLBFAM::CloseTableFile(PGLOBAL g, bool)
1355   {
1356   int rc = RC_OK;
1357 
1358   if (Tdbp->GetMode() == MODE_INSERT) {
1359     LPCSTR  name __attribute__((unused))= Tdbp->GetName();
1360     PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
1361 
1362     // Closing is True if last Write was in error
1363     if (CurNum && !Closing) {
1364       // Some more inserted lines remain to be written
1365       Last = (Nrec - Rbuf) + CurNum;
1366       Block = CurBlk + 1;
1367       Rbuf = CurNum--;
1368       Closing = TRUE;
1369       rc = WriteBuffer(g);
1370     } else if (Rbuf == Nrec) {
1371       Last = Nrec;
1372       Block = CurBlk;
1373     } // endif CurNum
1374 
1375     if (rc != RC_FX) {
1376       defp->SetBlock(Block);
1377       defp->SetLast(Last);
1378       defp->SetIntCatInfo("Blocks", Block);
1379       defp->SetIntCatInfo("Last", Last);
1380       } // endif
1381 
1382     fclose(Stream);
1383   } else
1384     rc = fclose(Stream);
1385 
1386   if (trace(1))
1387     htrc("ZLB CloseTableFile: closing %s mode=%d rc=%d\n",
1388          To_File, Tdbp->GetMode(), rc);
1389 
1390   Stream = NULL;           // So we can know whether table is open
1391   To_Fb->Count = 0;        // Avoid double closing by PlugCloseAll
1392 
1393   if (Tdbp->GetMode() == MODE_READ)
1394     rc = inflateEnd(Zstream);
1395   else
1396     rc = deflateEnd(Zstream);
1397 
1398   } // end of CloseTableFile
1399 
1400 /***********************************************************************/
1401 /*  Rewind routine for ZLIB access method.                             */
1402 /***********************************************************************/
Rewind(void)1403 void ZLBFAM::Rewind(void)
1404   {
1405   // We must be positioned after the header block
1406   if (CurBlk >= 0) {   // Nothing to do if no block read yet
1407     if (!Optimized) {  // If optimized, fseek will be done in ReadBuffer
1408 			size_t st;
1409 
1410       rewind(Stream);
1411 
1412 			if (!(st = fread(Zlenp, sizeof(int), 1, Stream)) && trace(1))
1413 				htrc("fread error %d in Rewind", errno);
1414 
1415       fseek(Stream, *Zlenp + sizeof(int), SEEK_SET);
1416       OldBlk = -1;
1417       } // endif Optimized
1418 
1419     CurBlk = -1;
1420     CurNum = Rbuf;
1421     } // endif CurBlk
1422 
1423 //OldBlk = -1;
1424 //Rbuf = 0;        commented out in case we reuse last read block
1425   } // end of Rewind
1426 
1427 /* ------------------------ End of GzFam ---------------------------- */
1428