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)
76char *strerror(int num);
77#endif // UNIX
78
79/***********************************************************************/
80/* External function. */
81/***********************************************************************/
82USETEMP 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/***********************************************************************/
88PVBLK 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/***********************************************************************/
97bool 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/***********************************************************************/
136bool 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/***********************************************************************/
175int 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/***********************************************************************/
205PTDB 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/***********************************************************************/
255TDBVCT::TDBVCT(PVCTDEF tdp, PTXF txfp) : TDBFIX(tdp, txfp)
256 {
257 To_SetCols = NULL;
258 } // end of TDBVCT standard constructor
259
260TDBVCT::TDBVCT(PGLOBAL g, PTDBVCT tdbp) : TDBFIX(g, tdbp)
261 {
262 To_SetCols = tdbp->To_SetCols;
263 } // end of TDBVCT copy constructor
264
265// Method
266PTDB 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/***********************************************************************/
285PCOL 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/***********************************************************************/
293bool 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/***********************************************************************/
305bool 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/***********************************************************************/
365int 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/***********************************************************************/
403void 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/***********************************************************************/
418VCTCOL::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/***********************************************************************/
433VCTCOL::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/***********************************************************************/
444bool 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/***********************************************************************/
474void 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/***********************************************************************/
486void 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/***********************************************************************/
513void 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/***********************************************************************/
541void 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/***********************************************************************/
573void 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