1 /************** Table C++ Functions Source Code File (.CPP) ************/
2 /*  Name: TABLE.CPP  Version 2.8                                       */
3 /*                                                                     */
4 /*  (C) Copyright to the author Olivier BERTRAND          1999-2017    */
5 /*                                                                     */
6 /*  This file contains the TBX, TDB and OPJOIN classes functions.      */
7 /***********************************************************************/
8 
9 /***********************************************************************/
10 /*  Include relevant MariaDB header file.                  */
11 /***********************************************************************/
12 #include "my_global.h"
13 #include "sql_string.h"
14 
15 /***********************************************************************/
16 /*  Include required application header files                          */
17 /*  global.h    is header containing all global Plug declarations.     */
18 /*  plgdbsem.h  is header containing the DB applic. declarations.      */
19 /*  xobject.h   is header containing XOBJECT derived classes declares. */
20 /***********************************************************************/
21 #include "global.h"
22 #include "plgdbsem.h"
23 #include "xtable.h"
24 #include "tabcol.h"
25 #include "filamtxt.h"
26 #include "tabdos.h"
27 //#include "catalog.h"
28 #include "reldef.h"
29 
30 int TDB::Tnum = 0;
31 
32 /***********************************************************************/
33 /*  Utility routines.                                                  */
34 /***********************************************************************/
35 void NewPointer(PTABS, void *, void *);
36 void AddPointer(PTABS, void *);
37 
38 /* ---------------------------- class TDB ---------------------------- */
39 
40 /***********************************************************************/
41 /*  TDB public constructors.                                           */
42 /***********************************************************************/
TDB(PTABDEF tdp)43 TDB::TDB(PTABDEF tdp) : Tdb_No(++Tnum)
44 {
45 	To_Def = tdp;
46 	Use = USE_NO;
47   To_Orig = NULL;
48   To_Filter = NULL;
49   To_CondFil = NULL;
50 	Cond = NULL;
51   Next = NULL;
52   Name = (tdp) ? tdp->GetName() : NULL;
53   To_Table = NULL;
54   Columns = NULL;
55 	To_SetCols = NULL;
56 	Degree = (tdp) ? tdp->GetDegree() : 0;
57   Mode = MODE_ANY;
58   Cardinal = -1;
59 	MaxSize = -1;
60 	Read_Only = (tdp) ? tdp->IsReadOnly() : false;
61 	m_data_charset = (tdp) ? tdp->data_charset() : NULL;
62 	csname = (tdp) ? tdp->csname : NULL;
63 } // end of TDB standard constructor
64 
TDB(PTDB tdbp)65 TDB::TDB(PTDB tdbp) : Tdb_No(++Tnum)
66 {
67 	To_Def = tdbp->To_Def;
68 	Use = tdbp->Use;
69   To_Orig = tdbp;
70   To_Filter = NULL;
71   To_CondFil = NULL;
72 	Cond = NULL;
73   Next = NULL;
74   Name = tdbp->Name;
75   To_Table = tdbp->To_Table;
76   Columns = NULL;
77 	To_SetCols = tdbp->To_SetCols;          // ???
78 	Degree = tdbp->Degree;
79   Mode = tdbp->Mode;
80   Cardinal = tdbp->Cardinal;
81 	MaxSize = tdbp->MaxSize;
82 	Read_Only = tdbp->IsReadOnly();
83 	m_data_charset = tdbp->data_charset();
84 	csname = tdbp->csname;
85 } // end of TDB copy constructor
86 
87 // Methods
88 /***********************************************************************/
89 /*  Return the pointer on the charset of this table.                   */
90 /***********************************************************************/
data_charset(void)91 CHARSET_INFO *TDB::data_charset(void)
92 {
93 	// If no DATA_CHARSET is specified, we assume that character
94 	// set of the remote data is the same with CHARACTER SET
95 	// definition of the SQL column.
96 	return m_data_charset ? m_data_charset : &my_charset_bin;
97 } // end of data_charset
98 
99 /***********************************************************************/
100 /*  Return the datapath of the DB this table belongs to.               */
101 /***********************************************************************/
GetPath(void)102 PCSZ TDB::GetPath(void)
103 {
104 	return To_Def->GetPath();
105 }  // end of GetPath
106 
107 /***********************************************************************/
108 /*  Return true if name is a special column of this table.             */
109 /***********************************************************************/
IsSpecial(PSZ name)110 bool TDB::IsSpecial(PSZ name)
111 {
112 	for (PCOLDEF cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext())
113 		if (!stricmp(cdp->GetName(), name) && (cdp->Flags & U_SPECIAL))
114 			return true;   // Special column to ignore while inserting
115 
116 	return false;    // Not found or not special or not inserting
117 }  // end of IsSpecial
118 
119 /***********************************************************************/
120 /*  Initialize TDB based column description block construction.        */
121 /*        name is used to call columns by name.                        */
122 /*        num is used by TBL to construct columns by index number.     */
123 /*  Note: name=Null and num=0 for constructing all columns (select *)  */
124 /***********************************************************************/
ColDB(PGLOBAL g,PSZ name,int num)125 PCOL TDB::ColDB(PGLOBAL g, PSZ name, int num)
126 {
127 	int     i;
128 	PCOLDEF cdp;
129 	PCOL    cp, colp = NULL, cprec = NULL;
130 
131 	if (trace(1))
132 		htrc("ColDB: am=%d colname=%s tabname=%s num=%d\n",
133 		GetAmType(), SVP(name), Name, num);
134 
135 	for (cdp = To_Def->GetCols(), i = 1; cdp; cdp = cdp->GetNext(), i++)
136 		if ((!name && !num) ||
137 			(name && !stricmp(cdp->GetName(), name)) || num == i) {
138 			/*****************************************************************/
139 			/*  Check for existence of desired column.                       */
140 			/*  Also find where to insert the new block.                     */
141 			/*****************************************************************/
142 			for (cp = Columns; cp; cp = cp->GetNext())
143 				if ((num && cp->GetIndex() == i) ||
144 					(name && !stricmp(cp->GetName(), name)))
145 					break;             // Found
146 				else if (cp->GetIndex() < i)
147 					cprec = cp;
148 
149 			if (trace(1))
150 				htrc("cdp(%d).Name=%s cp=%p\n", i, cdp->GetName(), cp);
151 
152 			/*****************************************************************/
153 			/*  Now take care of Column Description Block.                   */
154 			/*****************************************************************/
155 			if (cp)
156 				colp = cp;
157 			else if (!(cdp->Flags & U_SPECIAL))
158 				colp = MakeCol(g, cdp, cprec, i);
159 			else if (Mode != MODE_INSERT)
160 				colp = InsertSpcBlk(g, cdp);
161 
162 			if (trace(1))
163 				htrc("colp=%p\n", colp);
164 
165 			if (name || num)
166 				break;
167 			else if (colp && !colp->IsSpecial())
168 				cprec = colp;
169 
170 		} // endif Name
171 
172 	return (colp);
173 } // end of ColDB
174 
175 /***********************************************************************/
176 /*  InsertSpecialColumn: Put a special column ahead of the column list.*/
177 /***********************************************************************/
InsertSpecialColumn(PCOL colp)178 PCOL TDB::InsertSpecialColumn(PCOL colp)
179 {
180 	if (!colp->IsSpecial())
181 		return NULL;
182 
183 	colp->SetNext(Columns);
184 	Columns = colp;
185 	return colp;
186 } // end of InsertSpecialColumn
187 
188 /***********************************************************************/
189 /*  Make a special COLBLK to insert in a table.                        */
190 /***********************************************************************/
InsertSpcBlk(PGLOBAL g,PCOLDEF cdp)191 PCOL TDB::InsertSpcBlk(PGLOBAL g, PCOLDEF cdp)
192 {
193 	//char *name = cdp->GetName();
194 	char   *name = cdp->GetFmt();
195 	PCOLUMN cp;
196 	PCOL    colp;
197 
198 	cp = new(g)COLUMN(cdp->GetName());
199 
200 	if (!To_Table) {
201 		strcpy(g->Message, "Cannot make special column: To_Table is NULL");
202 		return NULL;
203 	} else
204 		cp->SetTo_Table(To_Table);
205 
206 	if (!stricmp(name, "FILEID") || !stricmp(name, "FDISK") ||
207 		!stricmp(name, "FPATH") || !stricmp(name, "FNAME") ||
208 		!stricmp(name, "FTYPE") || !stricmp(name, "SERVID")) {
209 		if (!To_Def || !(To_Def->GetPseudo() & 2)) {
210 			sprintf(g->Message, MSG(BAD_SPEC_COLUMN));
211 			return NULL;
212 		} // endif Pseudo
213 
214 		if (!stricmp(name, "FILEID"))
215 			colp = new(g)FIDBLK(cp, OP_XX);
216 		else if (!stricmp(name, "FDISK"))
217 			colp = new(g)FIDBLK(cp, OP_FDISK);
218 		else if (!stricmp(name, "FPATH"))
219 			colp = new(g)FIDBLK(cp, OP_FPATH);
220 		else if (!stricmp(name, "FNAME"))
221 			colp = new(g)FIDBLK(cp, OP_FNAME);
222 		else if (!stricmp(name, "FTYPE"))
223 			colp = new(g)FIDBLK(cp, OP_FTYPE);
224 		else
225 			colp = new(g)SIDBLK(cp);
226 
227 	} else if (!stricmp(name, "TABID")) {
228 		colp = new(g)TIDBLK(cp);
229 	} else if (!stricmp(name, "PARTID")) {
230 		colp = new(g)PRTBLK(cp);
231 		//} else if (!stricmp(name, "CONID")) {
232 		//  colp = new(g) CIDBLK(cp);
233 	} else if (!stricmp(name, "ROWID")) {
234 		colp = new(g)RIDBLK(cp, false);
235 	} else if (!stricmp(name, "ROWNUM")) {
236 		colp = new(g)RIDBLK(cp, true);
237 	} else {
238 		sprintf(g->Message, MSG(BAD_SPECIAL_COL), name);
239 		return NULL;
240 	} // endif's name
241 
242 	if (!(colp = InsertSpecialColumn(colp))) {
243 		sprintf(g->Message, MSG(BAD_SPECIAL_COL), name);
244 		return NULL;
245 	} // endif Insert
246 
247 	return (colp);
248 } // end of InsertSpcBlk
249 
250 /***********************************************************************/
251 /*  Marks DOS/MAP table columns used in internal joins.                */
252 /*  tdb2 is the top of tree or first tdb in chained tdb's and tdbp     */
253 /*  points to the currently marked tdb.                                */
254 /*  Two questions here: exact meaning of U_J_INT ?                     */
255 /*  Why is the eventual reference to To_Key_Col not marked U_J_EXT ?   */
256 /***********************************************************************/
MarkDB(PGLOBAL,PTDB tdb2)257 void TDB::MarkDB(PGLOBAL, PTDB tdb2)
258 {
259 	if (trace(1))
260 		htrc("DOS MarkDB: tdbp=%p tdb2=%p\n", this, tdb2);
261 
262 } // end of MarkDB
263 
264 /***********************************************************************/
265 /*  RowNumber: returns the current row ordinal number.                 */
266 /***********************************************************************/
RowNumber(PGLOBAL g,bool)267 int TDB::RowNumber(PGLOBAL g, bool)
268   {
269   sprintf(g->Message, MSG(ROWID_NOT_IMPL), GetAmName(g, GetAmType()));
270   return 0;
271   } // end of RowNumber
272 
Copy(PTABS t)273 PTDB TDB::Copy(PTABS t)
274   {
275   PTDB    tp, tdb1, tdb2 = NULL, outp = NULL;
276 //PGLOBAL g = t->G;        // Is this really useful ???
277 
278   for (tdb1 = this; tdb1; tdb1 = tdb1->Next) {
279     tp = tdb1->Clone(t);
280 
281     if (!outp)
282       outp = tp;
283     else
284       tdb2->Next = tp;
285 
286     tdb2 = tp;
287     NewPointer(t, tdb1, tdb2);
288     } // endfor tdb1
289 
290   return outp;
291   } // end of Copy
292 
293 /***********************************************************************/
294 /*  SetRecpos: Replace the table at the specified position.            */
295 /***********************************************************************/
SetRecpos(PGLOBAL g,int)296 bool TDB::SetRecpos(PGLOBAL g, int)
297 {
298 	strcpy(g->Message, MSG(SETRECPOS_NIY));
299 	return true;
300 } // end of SetRecpos
301 
Printf(PGLOBAL g,FILE * f,uint n)302 void TDB::Printf(PGLOBAL g, FILE *f, uint n)
303   {
304   PCOL cp;
305   char m[64];
306 
307   memset(m, ' ', n);                    // Make margin string
308   m[n] = '\0';
309 
310   for (PTDB tp = this; tp; tp = tp->Next) {
311     fprintf(f, "%sTDB (%p) %s no=%d use=%d type=%d\n", m,
312             tp, tp->Name, tp->Tdb_No, tp->Use, tp->GetAmType());
313 
314     tp->PrintAM(f, m);
315     fprintf(f, "%s Columns (deg=%d):\n", m, tp->Degree);
316 
317     for (cp = tp->Columns; cp; cp = cp->GetNext())
318       cp->Printf(g, f, n);
319 
320     } /* endfor tp */
321 
322   } // end of Printf
323 
Prints(PGLOBAL,char * ps,uint)324 void TDB::Prints(PGLOBAL, char *ps, uint)
325   {
326   sprintf(ps, "R%d.%s", Tdb_No, Name);
327   } // end of Prints
328 
329 /* -------------------------- class TDBASE --------------------------- */
330 
331 /***********************************************************************/
332 /*  Implementation of the TDBASE class. This is the base class to all  */
333 /*  classes for tables that can be joined together.                    */
334 /***********************************************************************/
TDBASE(PTABDEF tdp)335 TDBASE::TDBASE(PTABDEF tdp) : TDB(tdp)
336   {
337 //To_Def = tdp;
338   To_Link = NULL;
339   To_Key_Col = NULL;
340   To_Kindex = NULL;
341   To_Xdp = NULL;
342 //To_SetCols = NULL;
343   Ftype = RECFM_NAF;
344 //MaxSize = -1;
345   Knum = 0;
346 //Read_Only = (tdp) ? tdp->IsReadOnly() : false;
347 //m_data_charset=  (tdp) ? tdp->data_charset() : NULL;
348 //csname = (tdp) ? tdp->csname : NULL;
349   } // end of TDBASE constructor
350 
TDBASE(PTDBASE tdbp)351 TDBASE::TDBASE(PTDBASE tdbp) : TDB(tdbp)
352   {
353 //To_Def = tdbp->To_Def;
354   To_Link = tdbp->To_Link;
355   To_Key_Col = tdbp->To_Key_Col;
356   To_Kindex = tdbp->To_Kindex;
357   To_Xdp = tdbp->To_Xdp;
358 //To_SetCols = tdbp->To_SetCols;          // ???
359   Ftype = tdbp->Ftype;
360 //MaxSize = tdbp->MaxSize;
361   Knum = tdbp->Knum;
362 //Read_Only = tdbp->Read_Only;
363 //m_data_charset= tdbp->m_data_charset;
364 //csname = tdbp->csname;
365   } // end of TDBASE copy constructor
366 
367 /***********************************************************************/
368 /*  Return the pointer on the DB catalog this table belongs to.        */
369 /***********************************************************************/
GetCat(void)370 PCATLG TDBASE::GetCat(void)
371   {
372   return (To_Def) ? To_Def->GetCat() : NULL;
373   }  // end of GetCat
374 
375 #if 0
376 /***********************************************************************/
377 /*  Return the pointer on the charset of this table.                   */
378 /***********************************************************************/
379 CHARSET_INFO *TDBASE::data_charset(void)
380   {
381   // If no DATA_CHARSET is specified, we assume that character
382   // set of the remote data is the same with CHARACTER SET
383   // definition of the SQL column.
384   return m_data_charset ? m_data_charset : &my_charset_bin;
385   } // end of data_charset
386 
387 /***********************************************************************/
388 /*  Return the datapath of the DB this table belongs to.               */
389 /***********************************************************************/
390 PSZ TDBASE::GetPath(void)
391   {
392   return To_Def->GetPath();
393   }  // end of GetPath
394 
395 /***********************************************************************/
396 /*  Return true if name is a special column of this table.             */
397 /***********************************************************************/
398 bool TDBASE::IsSpecial(PSZ name)
399   {
400   for (PCOLDEF cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext())
401     if (!stricmp(cdp->GetName(), name) && (cdp->Flags & U_SPECIAL))
402       return true;   // Special column to ignore while inserting
403 
404   return false;    // Not found or not special or not inserting
405   }  // end of IsSpecial
406 
407 /***********************************************************************/
408 /*  Initialize TDBASE based column description block construction.     */
409 /*        name is used to call columns by name.                        */
410 /*        num is used by TBL to construct columns by index number.     */
411 /*  Note: name=Null and num=0 for constructing all columns (select *)  */
412 /***********************************************************************/
413 PCOL TDBASE::ColDB(PGLOBAL g, PSZ name, int num)
414   {
415   int     i;
416   PCOLDEF cdp;
417   PCOL    cp, colp = NULL, cprec = NULL;
418 
419   if (trace(1))
420     htrc("ColDB: am=%d colname=%s tabname=%s num=%d\n",
421           GetAmType(), SVP(name), Name, num);
422 
423   for (cdp = To_Def->GetCols(), i = 1; cdp; cdp = cdp->GetNext(), i++)
424     if ((!name && !num) ||
425          (name && !stricmp(cdp->GetName(), name)) || num == i) {
426       /*****************************************************************/
427       /*  Check for existence of desired column.                       */
428       /*  Also find where to insert the new block.                     */
429       /*****************************************************************/
430       for (cp = Columns; cp; cp = cp->GetNext())
431         if ((num && cp->GetIndex() == i) ||
432             (name && !stricmp(cp->GetName(), name)))
433           break;             // Found
434         else if (cp->GetIndex() < i)
435           cprec = cp;
436 
437       if (trace(1))
438         htrc("cdp(%d).Name=%s cp=%p\n", i, cdp->GetName(), cp);
439 
440       /*****************************************************************/
441       /*  Now take care of Column Description Block.                   */
442       /*****************************************************************/
443       if (cp)
444         colp = cp;
445       else if (!(cdp->Flags & U_SPECIAL))
446         colp = MakeCol(g, cdp, cprec, i);
447       else if (Mode != MODE_INSERT)
448         colp = InsertSpcBlk(g, cdp);
449 
450       if (trace(1))
451         htrc("colp=%p\n", colp);
452 
453       if (name || num)
454         break;
455       else if (colp && !colp->IsSpecial())
456         cprec = colp;
457 
458       } // endif Name
459 
460   return (colp);
461   } // end of ColDB
462 
463 /***********************************************************************/
464 /*  InsertSpecialColumn: Put a special column ahead of the column list.*/
465 /***********************************************************************/
466 PCOL TDBASE::InsertSpecialColumn(PCOL colp)
467   {
468   if (!colp->IsSpecial())
469     return NULL;
470 
471   colp->SetNext(Columns);
472   Columns = colp;
473   return colp;
474   } // end of InsertSpecialColumn
475 
476 /***********************************************************************/
477 /*  Make a special COLBLK to insert in a table.                        */
478 /***********************************************************************/
479 PCOL TDBASE::InsertSpcBlk(PGLOBAL g, PCOLDEF cdp)
480   {
481 //char *name = cdp->GetName();
482   char   *name = cdp->GetFmt();
483   PCOLUMN cp;
484   PCOL    colp;
485 
486   cp= new(g) COLUMN(cdp->GetName());
487 
488   if (! To_Table) {
489     strcpy(g->Message, "Cannot make special column: To_Table is NULL");
490     return NULL;
491   } else
492     cp->SetTo_Table(To_Table);
493 
494   if (!stricmp(name, "FILEID") || !stricmp(name, "FDISK") ||
495       !stricmp(name, "FPATH")  || !stricmp(name, "FNAME") ||
496       !stricmp(name, "FTYPE")  || !stricmp(name, "SERVID")) {
497     if (!To_Def || !(To_Def->GetPseudo() & 2)) {
498       sprintf(g->Message, MSG(BAD_SPEC_COLUMN));
499       return NULL;
500       } // endif Pseudo
501 
502     if (!stricmp(name, "FILEID"))
503       colp = new(g) FIDBLK(cp, OP_XX);
504     else if (!stricmp(name, "FDISK"))
505       colp = new(g) FIDBLK(cp, OP_FDISK);
506     else if (!stricmp(name, "FPATH"))
507       colp = new(g) FIDBLK(cp, OP_FPATH);
508     else if (!stricmp(name, "FNAME"))
509       colp = new(g) FIDBLK(cp, OP_FNAME);
510     else if (!stricmp(name, "FTYPE"))
511       colp = new(g) FIDBLK(cp, OP_FTYPE);
512     else
513       colp = new(g) SIDBLK(cp);
514 
515   } else if (!stricmp(name, "TABID")) {
516     colp = new(g) TIDBLK(cp);
517   } else if (!stricmp(name, "PARTID")) {
518     colp = new(g) PRTBLK(cp);
519 //} else if (!stricmp(name, "CONID")) {
520 //  colp = new(g) CIDBLK(cp);
521   } else if (!stricmp(name, "ROWID")) {
522     colp = new(g) RIDBLK(cp, false);
523   } else if (!stricmp(name, "ROWNUM")) {
524       colp = new(g) RIDBLK(cp, true);
525   } else {
526     sprintf(g->Message, MSG(BAD_SPECIAL_COL), name);
527     return NULL;
528   } // endif's name
529 
530   if (!(colp = InsertSpecialColumn(colp))) {
531     sprintf(g->Message, MSG(BAD_SPECIAL_COL), name);
532     return NULL;
533     } // endif Insert
534 
535   return (colp);
536   } // end of InsertSpcBlk
537 #endif // 0
538 
539 /***********************************************************************/
540 /*  ResetTableOpt: Wrong for this table type.                          */
541 /***********************************************************************/
ResetTableOpt(PGLOBAL g,bool,bool)542 int TDBASE::ResetTableOpt(PGLOBAL g, bool, bool)
543 {
544   strcpy(g->Message, "This table is not indexable");
545   return RC_INFO;
546 } // end of ResetTableOpt
547 
548 /***********************************************************************/
549 /*  ResetKindex: set or reset the index pointer.                       */
550 /***********************************************************************/
ResetKindex(PGLOBAL g,PKXBASE kxp)551 void TDBASE::ResetKindex(PGLOBAL g, PKXBASE kxp)
552   {
553   if (To_Kindex) {
554     int pos = GetRecpos();        // To be reset in Txfp
555 
556     for (PCOL colp= Columns; colp; colp= colp->GetNext())
557       colp->SetKcol(NULL);
558 
559     To_Kindex->Close();           // Discard old index
560     SetRecpos(g, pos);            // Ignore return value
561     } // endif To_Kindex
562 
563   To_Kindex = kxp;
564   } // end of ResetKindex
565 
566 #if 0
567 /***********************************************************************/
568 /*  SetRecpos: Replace the table at the specified position.            */
569 /***********************************************************************/
570 bool TDBASE::SetRecpos(PGLOBAL g, int)
571   {
572   strcpy(g->Message, MSG(SETRECPOS_NIY));
573   return true;
574   } // end of SetRecpos
575 #endif // 0
576 
577 /***********************************************************************/
578 /*  Methods                                                            */
579 /***********************************************************************/
PrintAM(FILE * f,char * m)580 void TDBASE::PrintAM(FILE *f, char *m)
581   {
582   fprintf(f, "%s AM(%d): mode=%d\n", m, GetAmType(), Mode);
583   } // end of PrintAM
584 
585 #if 0
586 /***********************************************************************/
587 /*  Marks DOS/MAP table columns used in internal joins.                */
588 /*  tdb2 is the top of tree or first tdb in chained tdb's and tdbp     */
589 /*  points to the currently marked tdb.                                */
590 /*  Two questions here: exact meaning of U_J_INT ?                     */
591 /*  Why is the eventual reference to To_Key_Col not marked U_J_EXT ?   */
592 /***********************************************************************/
593 void TDBASE::MarkDB(PGLOBAL, PTDB tdb2)
594   {
595   if (trace(1))
596     htrc("DOS MarkDB: tdbp=%p tdb2=%p\n", this, tdb2);
597 
598   } // end of MarkDB
599 #endif // 0
600 
601 /* ---------------------------TDBCAT class --------------------------- */
602 
603 /***********************************************************************/
604 /*  Implementation of the TDBCAT class.                                */
605 /***********************************************************************/
TDBCAT(PTABDEF tdp)606 TDBCAT::TDBCAT(PTABDEF tdp) : TDBASE(tdp)
607   {
608   Qrp = NULL;
609   Init = false;
610   N = -1;
611   } // end of TDBCAT constructor
612 
613 /***********************************************************************/
614 /*  Allocate CAT column description block.                             */
615 /***********************************************************************/
MakeCol(PGLOBAL g,PCOLDEF cdp,PCOL cprec,int n)616 PCOL TDBCAT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
617   {
618   PCATCOL colp;
619 
620   colp = (PCATCOL)new(g) CATCOL(cdp, this, n);
621 
622   if (cprec) {
623     colp->SetNext(cprec->GetNext());
624     cprec->SetNext(colp);
625   } else {
626     colp->SetNext(Columns);
627     Columns = colp;
628   } // endif cprec
629 
630   return colp;
631   } // end of MakeCol
632 
633 /***********************************************************************/
634 /*  Initialize: Get the result query block.                            */
635 /***********************************************************************/
Initialize(PGLOBAL g)636 bool TDBCAT::Initialize(PGLOBAL g)
637   {
638   if (Init)
639     return false;
640 
641   if (!(Qrp = GetResult(g)))
642     return true;
643 
644   if (Qrp->Truncated) {
645     sprintf(g->Message, "Result limited to %d lines", Qrp->Maxres);
646     PushWarning(g, this);
647     } // endif Truncated
648 
649   if (Qrp->BadLines) {
650     sprintf(g->Message, "%d bad lines in result", Qrp->BadLines);
651     PushWarning(g, this);
652     } // endif Badlines
653 
654   Init = true;
655   return false;
656   } // end of Initialize
657 
658 /***********************************************************************/
659 /*  CAT: Get the number of properties.                                 */
660 /***********************************************************************/
GetMaxSize(PGLOBAL g)661 int TDBCAT::GetMaxSize(PGLOBAL g __attribute__((unused)))
662   {
663   if (MaxSize < 0) {
664 //  if (Initialize(g))
665 //    return -1;
666 
667 //  MaxSize = Qrp->Nblin;
668     MaxSize = 10;             // To make MariaDB happy
669     } // endif MaxSize
670 
671   return MaxSize;
672   } // end of GetMaxSize
673 
674 /***********************************************************************/
675 /*  CAT Access Method opening routine.                                 */
676 /***********************************************************************/
OpenDB(PGLOBAL g)677 bool TDBCAT::OpenDB(PGLOBAL g)
678   {
679   if (Use == USE_OPEN) {
680     /*******************************************************************/
681     /*  Table already open.                                            */
682     /*******************************************************************/
683     N = -1;
684     return false;
685     } // endif use
686 
687   if (Mode != MODE_READ) {
688     /*******************************************************************/
689     /* ODBC Info tables cannot be modified.                            */
690     /*******************************************************************/
691     strcpy(g->Message, "CAT tables are read only");
692     return true;
693     } // endif Mode
694 
695   /*********************************************************************/
696   /*  Initialize the ODBC processing.                                  */
697   /*********************************************************************/
698   if (Initialize(g))
699     return true;
700 
701   Use = USE_OPEN;
702   return InitCol(g);
703   } // end of OpenDB
704 
705 /***********************************************************************/
706 /*  Initialize columns.                                                */
707 /***********************************************************************/
InitCol(PGLOBAL g)708 bool TDBCAT::InitCol(PGLOBAL g)
709   {
710   PCATCOL colp;
711   PCOLRES crp;
712 
713   for (colp = (PCATCOL)Columns; colp; colp = (PCATCOL)colp->GetNext()) {
714     for (crp = Qrp->Colresp; crp; crp = crp->Next)
715       if ((colp->Flag && colp->Flag == crp->Fld) ||
716          (!colp->Flag && !stricmp(colp->Name, crp->Name))) {
717         colp->Crp = crp;
718         break;
719         } // endif Flag
720 
721 
722     if (!colp->Crp /*&& !colp->GetValue()->IsConstant()*/) {
723       sprintf(g->Message, "Invalid flag %d for column %s",
724                           colp->Flag, colp->Name);
725       return true;
726 		} else if (crp->Fld == FLD_SCALE || crp->Fld == FLD_RADIX)
727 			colp->Value->SetNullable(true);
728 
729     } // endfor colp
730 
731   return false;
732   } // end of InitCol
733 
734 /***********************************************************************/
735 /*  SetRecpos: Replace the table at the specified position.            */
736 /***********************************************************************/
SetRecpos(PGLOBAL,int recpos)737 bool TDBCAT::SetRecpos(PGLOBAL, int recpos)
738   {
739   N = recpos - 1;
740   return false;
741   } // end of SetRecpos
742 
743 /***********************************************************************/
744 /*  Data Base read routine for CAT access method.                      */
745 /***********************************************************************/
ReadDB(PGLOBAL)746 int TDBCAT::ReadDB(PGLOBAL)
747   {
748   return (++N < Qrp->Nblin) ? RC_OK : RC_EF;
749   } // end of ReadDB
750 
751 /***********************************************************************/
752 /*  WriteDB: Data Base write routine for CAT access methods.           */
753 /***********************************************************************/
WriteDB(PGLOBAL g)754 int TDBCAT::WriteDB(PGLOBAL g)
755   {
756   strcpy(g->Message, "CAT tables are read only");
757   return RC_FX;
758   } // end of WriteDB
759 
760 /***********************************************************************/
761 /*  Data Base delete line routine for CAT access methods.              */
762 /***********************************************************************/
DeleteDB(PGLOBAL g,int)763 int TDBCAT::DeleteDB(PGLOBAL g, int)
764   {
765   strcpy(g->Message, "Delete not enabled for CAT tables");
766   return RC_FX;
767   } // end of DeleteDB
768 
769 /***********************************************************************/
770 /*  Data Base close routine for WMI access method.                     */
771 /***********************************************************************/
CloseDB(PGLOBAL)772 void TDBCAT::CloseDB(PGLOBAL)
773   {
774   // Nothing to do
775   } // end of CloseDB
776 
777 // ------------------------ CATCOL functions ----------------------------
778 
779 /***********************************************************************/
780 /*  CATCOL public constructor.                                         */
781 /***********************************************************************/
CATCOL(PCOLDEF cdp,PTDB tdbp,int n)782 CATCOL::CATCOL(PCOLDEF cdp, PTDB tdbp, int n)
783       : COLBLK(cdp, tdbp, n)
784   {
785   Tdbp = (PTDBCAT)tdbp;
786   Crp = NULL;
787   Flag = cdp->GetOffset();
788   } // end of WMICOL constructor
789 
790 /***********************************************************************/
791 /*  Read the next Data Source elements.                                */
792 /***********************************************************************/
ReadColumn(PGLOBAL)793 void CATCOL::ReadColumn(PGLOBAL)
794   {
795 	bool b = (!Crp->Kdata || Crp->Kdata->IsNull(Tdbp->N));
796 
797   // Get the value of the Name or Description property
798   if (!b)
799     Value->SetValue_pvblk(Crp->Kdata, Tdbp->N);
800   else
801     Value->Reset();
802 
803 	Value->SetNull(b);
804   } // end of ReadColumn
805 
806