1 | /************* TabVct C++ Program Source Code File (.CPP) **************/ |
2 | /* PROGRAM NAME: TABVCT */ |
3 | /* ------------- */ |
4 | /* Version 3.9 */ |
5 | /* */ |
6 | /* COPYRIGHT: */ |
7 | /* ---------- */ |
8 | /* (C) Copyright to the author Olivier BERTRAND 1999-2017 */ |
9 | /* */ |
10 | /* WHAT THIS PROGRAM DOES: */ |
11 | /* ----------------------- */ |
12 | /* This is the TDBVCT and VCTCOL classes implementation routines. */ |
13 | /* */ |
14 | /* WHAT YOU NEED TO COMPILE THIS PROGRAM: */ |
15 | /* -------------------------------------- */ |
16 | /* */ |
17 | /* REQUIRED FILES: */ |
18 | /* --------------- */ |
19 | /* TABVCT.C - Source code */ |
20 | /* PLGDBSEM.H - DB application declaration file */ |
21 | /* TABDOS.H - TABDOS classes declaration file */ |
22 | /* GLOBAL.H - Global declaration file */ |
23 | /* */ |
24 | /* REQUIRED LIBRARIES: */ |
25 | /* ------------------- */ |
26 | /* Large model C library */ |
27 | /* */ |
28 | /* REQUIRED PROGRAMS: */ |
29 | /* ------------------ */ |
30 | /* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */ |
31 | /* */ |
32 | /***********************************************************************/ |
33 | |
34 | /***********************************************************************/ |
35 | /* Include relevant MariaDB header file. */ |
36 | /***********************************************************************/ |
37 | #include "my_global.h" |
38 | #if defined(__WIN__) |
39 | #include <io.h> |
40 | #include <fcntl.h> |
41 | #if defined(__BORLANDC__) |
42 | #define __MFC_COMPAT__ // To define min/max as macro |
43 | #endif |
44 | //#include <windows.h> |
45 | #include <sys/stat.h> |
46 | #else |
47 | #if defined(UNIX) |
48 | #include <sys/types.h> |
49 | #include <sys/stat.h> |
50 | #include <unistd.h> |
51 | #include <errno.h> |
52 | #define NO_ERROR 0 |
53 | #else |
54 | #include <io.h> |
55 | #endif |
56 | #include <fcntl.h> |
57 | #endif |
58 | |
59 | /***********************************************************************/ |
60 | /* Include application header files: */ |
61 | /* global.h is header containing all global declarations. */ |
62 | /* plgdbsem.h is header containing the DB application declarations. */ |
63 | /* tabdos.h is header containing the TABDOS class declarations. */ |
64 | /***********************************************************************/ |
65 | #include "global.h" |
66 | #include "plgdbsem.h" |
67 | #include "reldef.h" |
68 | #include "osutil.h" |
69 | #include "filamvct.h" |
70 | #include "tabdos.h" |
71 | #include "tabvct.h" |
72 | #include "valblk.h" |
73 | |
74 | #if defined(UNIX) |
75 | //add dummy strerror (NGC) |
76 | char *strerror(int num); |
77 | #endif // UNIX |
78 | |
79 | /***********************************************************************/ |
80 | /* External function. */ |
81 | /***********************************************************************/ |
82 | USETEMP UseTemp(void); |
83 | |
84 | /***********************************************************************/ |
85 | /* Char VCT column blocks are right filled with blanks (blank = true) */ |
86 | /* Conversion of block values allowed conditionally for insert only. */ |
87 | /***********************************************************************/ |
88 | PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int, |
89 | bool check = true, bool blank = true, bool un = false); |
90 | |
91 | |
92 | /* --------------------------- Class VCTDEF -------------------------- */ |
93 | |
94 | /***********************************************************************/ |
95 | /* DefineAM: define specific AM block values from XDB file. */ |
96 | /***********************************************************************/ |
97 | bool VCTDEF::DefineAM(PGLOBAL g, LPCSTR, int poff) |
98 | { |
99 | DOSDEF::DefineAM(g, "BIN" , poff); |
100 | |
101 | if ((Estimate = GetIntCatInfo("Estimate" , 0))) |
102 | Elemt = MY_MIN(Elemt, Estimate); |
103 | |
104 | // Split treated as INT to get default value |
105 | Split = GetIntCatInfo("Split" , (Estimate) ? 0 : 1); |
106 | Header = GetIntCatInfo("Header" , 0); |
107 | |
108 | // CONNECT must have Block/Last info for VEC tables |
109 | if (Estimate && !Split && !Header) { |
110 | char *fn = GetStringCatInfo(g, "Filename" , "?" ); |
111 | |
112 | // No separate header file for urbi tables |
113 | Header = (*fn == '?') ? 3 : 2; |
114 | } // endif Estimate |
115 | |
116 | Recfm = RECFM_VCT; |
117 | |
118 | // For packed files the logical record length is calculated in poff |
119 | if (poff != Lrecl) { |
120 | Lrecl = poff; |
121 | SetIntCatInfo("Lrecl" , poff); |
122 | } // endif poff |
123 | |
124 | Padded = false; |
125 | Blksize = 0; |
126 | return false; |
127 | } // end of DefineAM |
128 | |
129 | #if 0 |
130 | /***********************************************************************/ |
131 | /* Erase: This was made a separate routine because a strange thing */ |
132 | /* happened when DeleteTablefile was defined for the VCTDEF class: */ |
133 | /* when called from Catalog, the DOSDEF routine was still called even */ |
134 | /* for a VCTDEF class. It also minimizes the specific code. */ |
135 | /***********************************************************************/ |
136 | bool VCTDEF::Erase(char *filename) |
137 | { |
138 | bool rc = false; |
139 | |
140 | if (Split) { |
141 | char fpat[_MAX_PATH]; |
142 | int i; |
143 | PCOLDEF cdp; |
144 | |
145 | MakeFnPattern(fpat); |
146 | |
147 | for (i = 1, cdp = To_Cols; cdp; i++, cdp = cdp->GetNext()) { |
148 | sprintf(filename, fpat, i); |
149 | //#if defined(__WIN__) |
150 | // rc |= !DeleteFile(filename); |
151 | //#else // UNIX |
152 | rc |= remove(filename); |
153 | //#endif // UNIX |
154 | } // endfor cdp |
155 | |
156 | } else { |
157 | rc = DOSDEF::Erase(filename); |
158 | |
159 | if (Estimate && Header == 2) { |
160 | PlugSetPath(filename, Fn, GetPath()); |
161 | strcat(PlugRemoveType(filename, filename), ".blk" ); |
162 | rc |= remove(filename); |
163 | } // endif Header |
164 | |
165 | } // endif Split |
166 | |
167 | return rc; // Return true if error |
168 | } // end of Erase |
169 | #endif // 0 |
170 | |
171 | /***********************************************************************/ |
172 | /* Prepare the column file name pattern for a split table. */ |
173 | /* This function returns the number of columns of the table. */ |
174 | /***********************************************************************/ |
175 | int VCTDEF::MakeFnPattern(char *fpat) |
176 | { |
177 | char pat[16]; |
178 | #if defined(__WIN__) |
179 | char drive[_MAX_DRIVE]; |
180 | #else |
181 | char *drive = NULL; |
182 | #endif |
183 | char direc[_MAX_DIR]; |
184 | char fname[_MAX_FNAME]; |
185 | char ftype[_MAX_EXT]; // File extention |
186 | int n, m, ncol = 0; |
187 | PCOLDEF cdp; |
188 | |
189 | for (cdp = To_Cols; cdp; cdp = cdp->GetNext()) |
190 | ncol++; |
191 | |
192 | for (n = 1, m = ncol; m /= 10; n++) ; |
193 | |
194 | sprintf(pat, "%%0%dd" , n); |
195 | _splitpath(Fn, drive, direc, fname, ftype); |
196 | strcat(fname, pat); |
197 | _makepath(fpat, drive, direc, fname, ftype); |
198 | PlugSetPath(fpat, fpat, GetPath()); |
199 | return ncol; |
200 | } // end of MakeFnPattern |
201 | |
202 | /***********************************************************************/ |
203 | /* GetTable: makes a new Table Description Block. */ |
204 | /***********************************************************************/ |
205 | PTDB VCTDEF::GetTable(PGLOBAL g, MODE mode) |
206 | { |
207 | /*********************************************************************/ |
208 | /* Allocate a TDB of the proper type. */ |
209 | /* Column blocks will be allocated only when needed. */ |
210 | /*********************************************************************/ |
211 | // Mapping not used for insert (except for true VEC not split tables) |
212 | // or when UseTemp is forced |
213 | bool map = Mapped && (Estimate || mode != MODE_INSERT) && |
214 | !(UseTemp() == TMP_FORCE && |
215 | (mode == MODE_UPDATE || mode == MODE_DELETE)); |
216 | PTXF txfp; |
217 | PTDB tdbp; |
218 | |
219 | if (Multiple) { |
220 | strcpy(g->Message, MSG(NO_MUL_VCT)); |
221 | return NULL; |
222 | } // endif Multiple |
223 | |
224 | if (Split) { |
225 | if (map) |
226 | txfp = new(g) VMPFAM(this); |
227 | else |
228 | txfp = new(g) VECFAM(this); |
229 | |
230 | } else if (Huge) |
231 | txfp = new(g) BGVFAM(this); |
232 | else if (map) |
233 | txfp = new(g) VCMFAM(this); |
234 | else |
235 | txfp = new(g) VCTFAM(this); |
236 | |
237 | tdbp = new(g) TDBVCT(this, txfp); |
238 | |
239 | /*********************************************************************/ |
240 | /* For block tables, get eventually saved optimization values. */ |
241 | /*********************************************************************/ |
242 | if (mode != MODE_INSERT) |
243 | if (tdbp->GetBlockValues(g)) |
244 | PushWarning(g, tdbp); |
245 | // return NULL; // causes a crash when deleting index |
246 | |
247 | return tdbp; |
248 | } // end of GetTable |
249 | |
250 | /* --------------------------- Class TDBVCT -------------------------- */ |
251 | |
252 | /***********************************************************************/ |
253 | /* Implementation of the TDBVCT class. */ |
254 | /***********************************************************************/ |
255 | TDBVCT::TDBVCT(PVCTDEF tdp, PTXF txfp) : TDBFIX(tdp, txfp) |
256 | { |
257 | To_SetCols = NULL; |
258 | } // end of TDBVCT standard constructor |
259 | |
260 | TDBVCT::TDBVCT(PGLOBAL g, PTDBVCT tdbp) : TDBFIX(g, tdbp) |
261 | { |
262 | To_SetCols = tdbp->To_SetCols; |
263 | } // end of TDBVCT copy constructor |
264 | |
265 | // Method |
266 | PTDB TDBVCT::Clone(PTABS t) |
267 | { |
268 | PTDB tp; |
269 | PVCTCOL cp1, cp2; |
270 | PGLOBAL g = t->G; // Is this really useful ??? |
271 | |
272 | tp = new(g) TDBVCT(g, this); |
273 | |
274 | for (cp1 = (PVCTCOL)Columns; cp1; cp1 = (PVCTCOL)cp1->Next) { |
275 | cp2 = new(g) VCTCOL(cp1, tp); // Make a copy |
276 | NewPointer(t, cp1, cp2); |
277 | } // endfor cp1 |
278 | |
279 | return tp; |
280 | } // end of Clone |
281 | |
282 | /***********************************************************************/ |
283 | /* Allocate VCT column description block. */ |
284 | /***********************************************************************/ |
285 | PCOL TDBVCT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) |
286 | { |
287 | return new(g) VCTCOL(g, cdp, this, cprec, n); |
288 | } // end of MakeCol |
289 | |
290 | /***********************************************************************/ |
291 | /* VEC tables are not ready yet to use temporary files. */ |
292 | /***********************************************************************/ |
293 | bool TDBVCT::IsUsingTemp(PGLOBAL) |
294 | { |
295 | // For developpers |
296 | return (UseTemp() == TMP_TEST); |
297 | } // end of IsUsingTemp |
298 | |
299 | /***********************************************************************/ |
300 | /* VCT Access Method opening routine. */ |
301 | /* New method now that this routine is called recursively (last table */ |
302 | /* first in reverse order): index blocks are immediately linked to */ |
303 | /* join block of next table if it exists or else are discarted. */ |
304 | /***********************************************************************/ |
305 | bool TDBVCT::OpenDB(PGLOBAL g) |
306 | { |
307 | if (trace(1)) |
308 | htrc("VCT OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n" , |
309 | this, Tdb_No, Use, To_Key_Col, Mode); |
310 | |
311 | if (Use == USE_OPEN) { |
312 | /*******************************************************************/ |
313 | /* Table already open, just replace it at its beginning. */ |
314 | /*******************************************************************/ |
315 | if (To_Kindex) |
316 | // Table is to be accessed through a sorted index table |
317 | To_Kindex->Reset(); |
318 | |
319 | Txfp->Rewind(); |
320 | ResetBlockFilter(g); |
321 | return false; |
322 | } // endif Use |
323 | |
324 | /*********************************************************************/ |
325 | /* Delete all is not handled using file mapping. */ |
326 | /*********************************************************************/ |
327 | if (Mode == MODE_DELETE && !Next && Txfp->GetAmType() == TYPE_AM_VMP) { |
328 | if (IsSplit()) |
329 | Txfp = new(g) VECFAM((PVCTDEF)To_Def); |
330 | else |
331 | Txfp = new(g) VCTFAM((PVCTDEF)To_Def); |
332 | |
333 | Txfp->SetTdbp(this); |
334 | } // endif Mode |
335 | |
336 | /*********************************************************************/ |
337 | /* Open according to input/output mode required and */ |
338 | /* allocate the block buffers for columns used in the query. */ |
339 | /*********************************************************************/ |
340 | if (Txfp->OpenTableFile(g)) |
341 | return true; |
342 | |
343 | // This was not done in previous version |
344 | Use = USE_OPEN; // Do it now in case we are recursively called |
345 | |
346 | /*********************************************************************/ |
347 | /* Allocate the block filter tree if evaluation is possible. */ |
348 | /*********************************************************************/ |
349 | To_BlkFil = InitBlockFilter(g, To_Filter); |
350 | |
351 | /*********************************************************************/ |
352 | /* Reset buffer access according to indexing and to mode. */ |
353 | /*********************************************************************/ |
354 | Txfp->ResetBuffer(g); |
355 | |
356 | return false; |
357 | } // end of OpenDB |
358 | |
359 | /***********************************************************************/ |
360 | /* Data Base read routine for VCT access method. */ |
361 | /* This routine just set the new block index and record position. */ |
362 | /* For index accessed tables the physical reading is deferred to the */ |
363 | /* ReadColumn routine so only really used column are physically read. */ |
364 | /***********************************************************************/ |
365 | int TDBVCT::ReadDB(PGLOBAL g) |
366 | { |
367 | if (trace(1)) |
368 | htrc("VCT ReadDB: R%d Mode=%d CurBlk=%d CurNum=%d key=%p link=%p Kindex=%p\n" , |
369 | GetTdb_No(), Mode, Txfp->CurBlk, Txfp->CurNum, |
370 | To_Key_Col, To_Link, To_Kindex); |
371 | |
372 | if (To_Kindex) { |
373 | /*******************************************************************/ |
374 | /* Reading is by an index table. */ |
375 | /*******************************************************************/ |
376 | int recpos = To_Kindex->Fetch(g); |
377 | |
378 | switch (recpos) { |
379 | case -1: // End of file reached |
380 | return RC_EF; |
381 | case -2: // No match for join |
382 | return RC_NF; |
383 | case -3: // Same record as last non null one |
384 | // num_there++; |
385 | return RC_OK; |
386 | default: |
387 | /***************************************************************/ |
388 | /* Set the file position according to record to read. */ |
389 | /***************************************************************/ |
390 | if (SetRecpos(g, recpos)) |
391 | return RC_FX; |
392 | |
393 | } // endswitch recpos |
394 | |
395 | } // endif To_Kindex |
396 | |
397 | return ReadBuffer(g); |
398 | } // end of ReadDB |
399 | |
400 | /***********************************************************************/ |
401 | /* Data Base close routine for VEC access method. */ |
402 | /***********************************************************************/ |
403 | void TDBVCT::CloseDB(PGLOBAL g) |
404 | { |
405 | if (To_Kindex) { |
406 | To_Kindex->Close(); |
407 | To_Kindex = NULL; |
408 | } // endif |
409 | |
410 | Txfp->CloseTableFile(g, false); |
411 | } // end of CloseDB |
412 | |
413 | // ------------------------ VCTCOL functions ---------------------------- |
414 | |
415 | /***********************************************************************/ |
416 | /* VCTCOL public constructor. */ |
417 | /***********************************************************************/ |
418 | VCTCOL::VCTCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) |
419 | : DOSCOL(g, cdp, tdbp, cprec, i, "VCT" ) |
420 | { |
421 | Deplac = cdp->GetPoff(); |
422 | Clen = cdp->GetClen(); // Length of the field in the file |
423 | ColBlk = -1; |
424 | ColPos = -1; |
425 | Blk = NULL; |
426 | Modif = 0; |
427 | } // end of VCTCOL constructor |
428 | |
429 | /***********************************************************************/ |
430 | /* VCTCOL constructor used for copying columns. */ |
431 | /* tdbp is the pointer to the new table descriptor. */ |
432 | /***********************************************************************/ |
433 | VCTCOL::VCTCOL(VCTCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp) |
434 | { |
435 | ColBlk = col1->ColBlk; |
436 | ColPos = col1->ColPos; |
437 | Blk = col1->Blk; // Should be NULL when copying ???? |
438 | Modif = col1->Modif; // Should be 0 ???? |
439 | } // end of VCTCOL copy constructor |
440 | |
441 | /***********************************************************************/ |
442 | /* SetBuffer: allocate and set the buffers needed for write operation.*/ |
443 | /***********************************************************************/ |
444 | bool VCTCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check) |
445 | { |
446 | // Eventual conversion will be done when setting ValBlk from Value. |
447 | Value = value; // Force To_Val == Value |
448 | |
449 | if (DOSCOL::SetBuffer(g, value, ok, check)) |
450 | return true; |
451 | |
452 | if (To_Tdb->GetMode() != MODE_INSERT) { |
453 | // Allocate the block buffer to use for read/writing except when |
454 | // updating a mapped VCT table and Ok is true. |
455 | PTDBVCT tdbp = (PTDBVCT)To_Tdb; |
456 | |
457 | if (tdbp->Txfp->GetAmType() == TYPE_AM_VMP && ok) { |
458 | Blk = AllocValBlock(g, (void*)1, Buf_Type, tdbp->Txfp->Nrec, |
459 | Format.Length, |
460 | Format.Prec, check); |
461 | Status |= BUF_MAPPED; // Will point into mapped file |
462 | } else |
463 | Blk = AllocValBlock(g, NULL, Buf_Type, tdbp->Txfp->Nrec, |
464 | Format.Length, |
465 | Format.Prec, check); |
466 | } // endif Mode |
467 | |
468 | return false; |
469 | } // end of SetBuffer |
470 | |
471 | /***********************************************************************/ |
472 | /* ReadBlock: Indicate it is Ok to make updates. */ |
473 | /***********************************************************************/ |
474 | void VCTCOL::SetOk(void) |
475 | { |
476 | if (((PTDBVCT)To_Tdb)->Txfp->GetAmType() == TYPE_AM_VMP) |
477 | Status |= BUF_MAPPED; |
478 | |
479 | Status |= BUF_EMPTY; |
480 | Modif = 0; |
481 | } // end of SetOk |
482 | |
483 | /***********************************************************************/ |
484 | /* ReadBlock: Read column values from current block. */ |
485 | /***********************************************************************/ |
486 | void VCTCOL::ReadBlock(PGLOBAL g) |
487 | { |
488 | PVCTFAM txfp = (PVCTFAM)((PTDBVCT)To_Tdb)->Txfp; |
489 | |
490 | #if defined(_DEBUG) |
491 | if (!Blk) { |
492 | strcpy(g->Message, MSG(TO_BLK_IS_NULL)); |
493 | throw 58; |
494 | } // endif |
495 | #endif |
496 | |
497 | /*********************************************************************/ |
498 | /* Read column block according to used access method. */ |
499 | /*********************************************************************/ |
500 | if (txfp->ReadBlock(g, this)) |
501 | throw 6; |
502 | |
503 | ColBlk = txfp->CurBlk; |
504 | ColPos = -1; // Any invalid position |
505 | } // end of ReadBlock |
506 | |
507 | /***********************************************************************/ |
508 | /* WriteBlock: Write back current column values for one block. */ |
509 | /* Note: the test of Status is meant to prevent physical writing of */ |
510 | /* the block during the checking loop in mode Update. It is set to */ |
511 | /* BUF_EMPTY when reopening the table between the two loops. */ |
512 | /***********************************************************************/ |
513 | void VCTCOL::WriteBlock(PGLOBAL g) |
514 | { |
515 | if (Modif && (Status & BUF_EMPTY)) { |
516 | PVCTFAM txfp = (PVCTFAM)((PTDBVCT)To_Tdb)->Txfp; |
517 | |
518 | #if defined(_DEBUG) |
519 | if (!Blk) { |
520 | strcpy(g->Message, MSG(BLK_IS_NULL)); |
521 | throw 56; |
522 | } // endif |
523 | #endif |
524 | |
525 | /*******************************************************************/ |
526 | /* Write column block according to used access method. */ |
527 | /*******************************************************************/ |
528 | if (txfp->WriteBlock(g, this)) |
529 | throw 6; |
530 | |
531 | Modif = 0; |
532 | } // endif Modif |
533 | |
534 | } // end of WriteBlock |
535 | |
536 | /***********************************************************************/ |
537 | /* ReadColumn: what this routine does is to check whether a column */ |
538 | /* block has been read from the file, then to extract from it the */ |
539 | /* field corresponding to this column and convert it to buffer type. */ |
540 | /***********************************************************************/ |
541 | void VCTCOL::ReadColumn(PGLOBAL g) |
542 | { |
543 | PTXF txfp = ((PTDBVCT)To_Tdb)->Txfp; |
544 | |
545 | #if defined(_DEBUG) |
546 | assert (!To_Kcol); |
547 | #endif |
548 | |
549 | if (trace(2)) |
550 | htrc("VCT ReadColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n" , |
551 | Name, To_Tdb->GetTdb_No(), ColUse, Status, Buf_Type); |
552 | |
553 | if (ColBlk != txfp->CurBlk) |
554 | ReadBlock(g); |
555 | else if (ColPos == txfp->CurNum) |
556 | return; // Value is already there |
557 | |
558 | //ColBlk = txfp->CurBlk; done in ReadBlock |
559 | ColPos = txfp->CurNum; |
560 | Value->SetValue_pvblk(Blk, ColPos); |
561 | |
562 | // Set null when applicable |
563 | if (Nullable) |
564 | Value->SetNull(Value->IsZero()); |
565 | |
566 | } // end of ReadColumn |
567 | |
568 | /***********************************************************************/ |
569 | /* WriteColumn: Modifications are written back into column buffer. */ |
570 | /* On each change of block the buffer is written back to file and */ |
571 | /* in mode Insert the buffer is filled with the block to update. */ |
572 | /***********************************************************************/ |
573 | void VCTCOL::WriteColumn(PGLOBAL) |
574 | { |
575 | PTXF txfp = ((PTDBVCT)To_Tdb)->Txfp;; |
576 | |
577 | if (trace(2)) |
578 | htrc("VCT WriteColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n" , |
579 | Name, To_Tdb->GetTdb_No(), ColUse, Status, Buf_Type); |
580 | |
581 | ColBlk = txfp->CurBlk; |
582 | ColPos = txfp->CurNum; |
583 | Blk->SetValue(Value, ColPos); |
584 | Modif++; |
585 | } // end of WriteColumn |
586 | |
587 | /* ------------------------ End of TabVct ---------------------------- */ |
588 | |