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