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