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(__WIN__) |
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 // !__WIN__ |
28 | #if defined(UNIX) |
29 | #include <errno.h> |
30 | #else // !UNIX |
31 | #include <io.h> |
32 | #endif |
33 | #include <fcntl.h> |
34 | #endif // !__WIN__ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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(__WIN__) |
93 | sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(NULL)); |
94 | #else // !__WIN__ |
95 | sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno)); |
96 | #endif // !__WIN__ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
279 | int GZFAM::SkipRecord(PGLOBAL g, bool ) |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
402 | void GZFAM::Rewind(void) |
403 | { |
404 | gzrewind(Zfile); |
405 | } // end of Rewind |
406 | |
407 | /* ------------------------------------------------------------------- */ |
408 | |
409 | /***********************************************************************/ |
410 | /* Constructors. */ |
411 | /***********************************************************************/ |
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 | |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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(__WIN__) |
768 | To_Buf[len - 2] = '\r'; |
769 | #endif // __WIN__ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | |