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 = 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 = 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       case RC_NF:
1025         return TRUE;
1026       } // endswitch
1027 
1028     // Some old tables can have PlugDB in their header
1029     if (strcmp(To_Buf, "PlugDB")) {
1030       sprintf(g->Message, MSG(BAD_HEADER), Tdbp->GetFile(g));
1031       return TRUE;
1032       } // endif strcmp
1033 
1034   } // endif Mode
1035 
1036   return FALSE;
1037   } // end of AllocateBuffer
1038 
1039 /***********************************************************************/
1040 /*  GetPos: return the position of last read record.                   */
1041 /***********************************************************************/
GetPos(void)1042 int ZLBFAM::GetPos(void)
1043   {
1044   return (Optimized) ? (CurNum + Nrec * CurBlk) : Fpos;
1045   } // end of GetPos
1046 
1047 /***********************************************************************/
1048 /*  GetNextPos: should not be called for this class.                   */
1049 /***********************************************************************/
GetNextPos(void)1050 int ZLBFAM::GetNextPos(void)
1051   {
1052   if (Optimized) {
1053     assert(FALSE);
1054     return 0;
1055   } else
1056     return ftell(Stream);
1057 
1058   } // end of GetNextPos
1059 
1060 /***********************************************************************/
1061 /*  SetPos: Replace the table at the specified position.               */
1062 /***********************************************************************/
SetPos(PGLOBAL g,int pos)1063 bool ZLBFAM::SetPos(PGLOBAL g, int pos __attribute__((unused)))
1064   {
1065   sprintf(g->Message, MSG(NO_SETPOS_YET), "GZ");
1066   return true;
1067 #if 0 // All this must be checked
1068   if (pos < 0) {
1069     strcpy(g->Message, MSG(INV_REC_POS));
1070     return true;
1071     } // endif recpos
1072 
1073   CurBlk = pos / Nrec;
1074   CurNum = pos % Nrec;
1075 #if defined(_DEBUG)
1076   num_eq[(CurBlk == OldBlk) ? 1 : 0]++;
1077 #endif
1078 
1079   // Indicate the table position was externally set
1080   Placed = true;
1081   return false;
1082 #endif // 0
1083   } // end of SetPos
1084 
1085 /***********************************************************************/
1086 /*  ReadBuffer: Read one line for a text file.                         */
1087 /***********************************************************************/
ReadBuffer(PGLOBAL g)1088 int ZLBFAM::ReadBuffer(PGLOBAL g)
1089   {
1090   size_t   n;
1091   void *rdbuf;
1092 
1093   /*********************************************************************/
1094   /*  Sequential reading when Placed is not true.                      */
1095   /*********************************************************************/
1096   if (Placed) {
1097     Placed = FALSE;
1098   } else if (++CurNum < Rbuf) {
1099     CurLine = NxtLine;
1100 
1101     // Get the position of the next line in the buffer
1102     if (Tdbp->GetFtype() == RECFM_VAR)
1103       while (*NxtLine++ != '\n') ;
1104     else
1105       NxtLine += Lrecl;
1106 
1107     // Set caller line buffer
1108     n = NxtLine - CurLine - ((Tdbp->GetFtype() == RECFM_BIN) ? 0 : Ending);
1109     memcpy(Tdbp->GetLine(), CurLine, n);
1110     Tdbp->GetLine()[n] = '\0';
1111     return RC_OK;
1112   } else if (Rbuf < Nrec && CurBlk != -1) {
1113     CurNum--;         // To have a correct Last value when optimizing
1114     return RC_EF;
1115   } else {
1116     /*******************************************************************/
1117     /*  New block.                                                     */
1118     /*******************************************************************/
1119     CurNum = 0;
1120 
1121    next:
1122     if (++CurBlk >= Block)
1123       return RC_EF;
1124 
1125     /*******************************************************************/
1126     /*  Before reading a new block, check whether block optimization   */
1127     /*  can be done, as well as for join as for local filtering.       */
1128     /*******************************************************************/
1129     if (Optimized) switch (Tdbp->TestBlock(g)) {
1130       case RC_EF:
1131         return RC_EF;
1132       case RC_NF:
1133         goto next;
1134       } // endswitch rc
1135 
1136   } // endif's
1137 
1138   if (OldBlk == CurBlk)
1139     goto ok;         // Block is already there
1140 
1141   if (Optimized) {
1142     // Store the position of next block
1143     Fpos = BlkPos[CurBlk];
1144 
1145     // fseek is required only in non sequential reading
1146     if (CurBlk != OldBlk + 1)
1147       if (fseek(Stream, Fpos, SEEK_SET)) {
1148         sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
1149         return RC_FX;
1150         } // endif fseek
1151 
1152     // Calculate the length of block to read
1153     BlkLen = BlkPos[CurBlk + 1] - Fpos;
1154     rdbuf = Zlenp;
1155   } else {                     // !Optimized
1156     if (CurBlk != OldBlk + 1) {
1157       strcpy(g->Message, MSG(INV_RAND_ACC));
1158       return RC_FX;
1159     } else
1160       Fpos = ftell(Stream);    // Used when optimizing
1161 
1162     // Get the stored length from the file itself
1163     if (fread(Zlenp, sizeof(int), 1, Stream) != 1) {
1164       if (feof(Stream))
1165         return RC_EF;
1166 
1167       goto err;
1168       } // endif fread
1169 
1170     BlkLen = *Zlenp;
1171     rdbuf = Zbuffer;
1172   } // endif Optimized
1173 
1174   // Read the next block
1175   switch (ReadCompressedBuffer(g, rdbuf)) {
1176     case RC_FX: goto err;
1177     case RC_NF: return RC_FX;
1178     case RC_EF: return RC_EF;
1179     default: Rbuf = (CurBlk == Block - 1) ? Last : Nrec;
1180     } // endswitch ReadCompressedBuffer
1181 
1182  ok:
1183   if (Tdbp->GetFtype() == RECFM_VAR) {
1184     int i;
1185 
1186     // Get the position of the current line
1187     for (i = 0, CurLine = To_Buf; i < CurNum; i++)
1188       while (*CurLine++ != '\n') ;      // What about Unix ???
1189 
1190     // Now get the position of the next line
1191     for (NxtLine = CurLine; *NxtLine++ != '\n';) ;
1192 
1193     // Set caller line buffer
1194     n = NxtLine - CurLine - Ending;
1195   } else {
1196     CurLine = To_Buf + CurNum * Lrecl;
1197     NxtLine = CurLine + Lrecl;
1198     n = Lrecl - ((Tdbp->GetFtype() == RECFM_BIN) ? 0 : Ending);
1199   } // endif Ftype
1200 
1201   memcpy(Tdbp->GetLine(), CurLine, n);
1202   Tdbp->GetLine()[n] = '\0';
1203 
1204   OldBlk = CurBlk;         // Last block actually read
1205   IsRead = TRUE;           // Is read indeed
1206   return RC_OK;
1207 
1208  err:
1209 #if defined(UNIX)
1210   sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
1211 #else
1212   sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
1213 #endif
1214   return RC_FX;
1215   } // end of ReadBuffer
1216 
1217 /***********************************************************************/
1218 /*  Read and decompress a block from the stream.                       */
1219 /***********************************************************************/
ReadCompressedBuffer(PGLOBAL g,void * rdbuf)1220 int ZLBFAM::ReadCompressedBuffer(PGLOBAL g, void *rdbuf)
1221   {
1222   if (fread(rdbuf, 1, (size_t)BlkLen, Stream) == (unsigned)BlkLen) {
1223     int zrc;
1224 
1225     num_read++;
1226 
1227     if (Optimized && BlkLen != signed(*Zlenp + sizeof(int))) {
1228       sprintf(g->Message, MSG(BAD_BLK_SIZE), CurBlk + 1);
1229       return RC_NF;
1230       } // endif BlkLen
1231 
1232     // HERE WE MUST INFLATE THE BLOCK
1233     Zstream->next_in = Zbuffer;
1234     Zstream->avail_in = (uInt)(*Zlenp);
1235     Zstream->next_out = (Byte*)To_Buf;
1236     Zstream->avail_out = Buflen;
1237     zrc = inflate(Zstream, Z_SYNC_FLUSH);
1238 
1239     if (zrc != Z_OK) {
1240       if (Zstream->msg)
1241         sprintf(g->Message, MSG(FUNC_ERR_S), "inflate", Zstream->msg);
1242       else
1243         sprintf(g->Message, MSG(FUNCTION_ERROR), "inflate", (int)zrc);
1244 
1245       return RC_NF;
1246       } // endif zrc
1247 
1248   } else if (feof(Stream)) {
1249     return RC_EF;
1250   } else
1251     return RC_FX;
1252 
1253   return RC_OK;
1254   } // end of ReadCompressedBuffer
1255 
1256 /***********************************************************************/
1257 /*  WriteBuffer: File write routine for DOS access method.             */
1258 /*  Update is directly written back into the file,                     */
1259 /*         with this (fast) method, record size cannot change.         */
1260 /***********************************************************************/
WriteBuffer(PGLOBAL g)1261 int ZLBFAM::WriteBuffer(PGLOBAL g)
1262   {
1263   assert (Tdbp->GetMode() == MODE_INSERT);
1264 
1265   /*********************************************************************/
1266   /*  Prepare the write buffer.                                        */
1267   /*********************************************************************/
1268   if (!Closing) {
1269     if (Tdbp->GetFtype() == RECFM_BIN)
1270       memcpy(CurLine, Tdbp->GetLine(), Lrecl);
1271     else
1272       strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf);
1273 
1274 #if defined(_DEBUG)
1275     if (Tdbp->GetFtype() == RECFM_FIX &&
1276       (signed)strlen(CurLine) != Lrecl + (signed)strlen(CrLf)) {
1277       strcpy(g->Message, MSG(BAD_LINE_LEN));
1278       Closing = TRUE;
1279       return RC_FX;
1280       } // endif Lrecl
1281 #endif   // _DEBUG
1282     } // endif Closing
1283 
1284   /*********************************************************************/
1285   /*  In Insert mode, blocs are added sequentialy to the file end.     */
1286   /*********************************************************************/
1287   if (++CurNum != Rbuf) {
1288     if (Tdbp->GetFtype() == RECFM_VAR)
1289       CurLine += strlen(CurLine);
1290     else
1291       CurLine += Lrecl;
1292 
1293     return RC_OK;                    // We write only full blocks
1294     } // endif CurNum
1295 
1296   // HERE WE MUST DEFLATE THE BLOCK
1297   if (Tdbp->GetFtype() == RECFM_VAR)
1298     NxtLine = CurLine + strlen(CurLine);
1299   else
1300     NxtLine = CurLine + Lrecl;
1301 
1302   BlkLen = (int)(NxtLine - To_Buf);
1303 
1304   if (WriteCompressedBuffer(g)) {
1305     Closing = TRUE;      // To tell CloseDB about a Write error
1306     return RC_FX;
1307     } // endif WriteCompressedBuffer
1308 
1309   CurBlk++;
1310   CurNum = 0;
1311   CurLine = To_Buf;
1312   return RC_OK;
1313   } // end of WriteBuffer
1314 
1315 /***********************************************************************/
1316 /*  Compress the buffer and write the deflated output to stream.       */
1317 /***********************************************************************/
WriteCompressedBuffer(PGLOBAL g)1318 bool ZLBFAM::WriteCompressedBuffer(PGLOBAL g)
1319   {
1320   int zrc;
1321 
1322   Zstream->next_in = (Byte*)To_Buf;
1323   Zstream->avail_in = (uInt)BlkLen;
1324   Zstream->next_out = Zbuffer;
1325   Zstream->avail_out = Buflen + 16;
1326   Zstream->total_out = 0;
1327   zrc = deflate(Zstream, Z_FULL_FLUSH);
1328 
1329   if (zrc != Z_OK) {
1330     if (Zstream->msg)
1331       sprintf(g->Message, MSG(FUNC_ERR_S), "deflate", Zstream->msg);
1332     else
1333       sprintf(g->Message, MSG(FUNCTION_ERROR), "deflate", (int)zrc);
1334 
1335     return TRUE;
1336   } else
1337     *Zlenp = Zstream->total_out;
1338 
1339   //  Now start the writing process.
1340   BlkLen = *Zlenp + sizeof(int);
1341 
1342   if (fwrite(Zlenp, 1, BlkLen, Stream) != (size_t)BlkLen) {
1343     sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
1344     return TRUE;
1345     } // endif size
1346 
1347   return FALSE;
1348   } // end of WriteCompressedBuffer
1349 
1350 /***********************************************************************/
1351 /*  Table file close routine for DOS access method.                    */
1352 /***********************************************************************/
CloseTableFile(PGLOBAL g,bool)1353 void ZLBFAM::CloseTableFile(PGLOBAL g, bool)
1354   {
1355   int rc = RC_OK;
1356 
1357   if (Tdbp->GetMode() == MODE_INSERT) {
1358     LPCSTR  name = Tdbp->GetName();
1359     PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
1360 
1361     // Closing is True if last Write was in error
1362     if (CurNum && !Closing) {
1363       // Some more inserted lines remain to be written
1364       Last = (Nrec - Rbuf) + CurNum;
1365       Block = CurBlk + 1;
1366       Rbuf = CurNum--;
1367       Closing = TRUE;
1368       rc = WriteBuffer(g);
1369     } else if (Rbuf == Nrec) {
1370       Last = Nrec;
1371       Block = CurBlk;
1372     } // endif CurNum
1373 
1374     if (rc != RC_FX) {
1375       defp->SetBlock(Block);
1376       defp->SetLast(Last);
1377       defp->SetIntCatInfo("Blocks", Block);
1378       defp->SetIntCatInfo("Last", Last);
1379       } // endif
1380 
1381     fclose(Stream);
1382   } else
1383     rc = fclose(Stream);
1384 
1385   if (trace(1))
1386     htrc("ZLB CloseTableFile: closing %s mode=%d rc=%d\n",
1387          To_File, Tdbp->GetMode(), rc);
1388 
1389   Stream = NULL;           // So we can know whether table is open
1390   To_Fb->Count = 0;        // Avoid double closing by PlugCloseAll
1391 
1392   if (Tdbp->GetMode() == MODE_READ)
1393     rc = inflateEnd(Zstream);
1394   else
1395     rc = deflateEnd(Zstream);
1396 
1397   } // end of CloseTableFile
1398 
1399 /***********************************************************************/
1400 /*  Rewind routine for ZLIB access method.                             */
1401 /***********************************************************************/
Rewind(void)1402 void ZLBFAM::Rewind(void)
1403   {
1404   // We must be positioned after the header block
1405   if (CurBlk >= 0) {   // Nothing to do if no block read yet
1406     if (!Optimized) {  // If optimized, fseek will be done in ReadBuffer
1407 			size_t st;
1408 
1409       rewind(Stream);
1410 
1411 			if (!(st = fread(Zlenp, sizeof(int), 1, Stream)) && trace(1))
1412 				htrc("fread error %d in Rewind", errno);
1413 
1414       fseek(Stream, *Zlenp + sizeof(int), SEEK_SET);
1415       OldBlk = -1;
1416       } // endif Optimized
1417 
1418     CurBlk = -1;
1419     CurNum = Rbuf;
1420     } // endif CurBlk
1421 
1422 //OldBlk = -1;
1423 //Rbuf = 0;        commented out in case we reuse last read block
1424   } // end of Rewind
1425 
1426 /* ------------------------ End of GzFam ---------------------------- */
1427