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