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
30int TDB::Tnum = 0;
31
32/***********************************************************************/
33/* Utility routines. */
34/***********************************************************************/
35void NewPointer(PTABS, void *, void *);
36void AddPointer(PTABS, void *);
37
38/* ---------------------------- class TDB ---------------------------- */
39
40/***********************************************************************/
41/* TDB public constructors. */
42/***********************************************************************/
43TDB::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
65TDB::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/***********************************************************************/
91CHARSET_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/***********************************************************************/
102PCSZ 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/***********************************************************************/
110bool 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/***********************************************************************/
125PCOL 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/***********************************************************************/
178PCOL 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/***********************************************************************/
191PCOL 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/***********************************************************************/
257void 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/***********************************************************************/
267int 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
273PTDB 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/***********************************************************************/
296bool TDB::SetRecpos(PGLOBAL g, int)
297{
298 strcpy(g->Message, MSG(SETRECPOS_NIY));
299 return true;
300} // end of SetRecpos
301
302void 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
324void 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/***********************************************************************/
335TDBASE::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
351TDBASE::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/***********************************************************************/
370PCATLG 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/***********************************************************************/
379CHARSET_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/***********************************************************************/
390PSZ 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/***********************************************************************/
398bool 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/***********************************************************************/
413PCOL 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/***********************************************************************/
466PCOL 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/***********************************************************************/
479PCOL 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/***********************************************************************/
542int 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/***********************************************************************/
551void 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/***********************************************************************/
570bool 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/***********************************************************************/
580void 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/***********************************************************************/
593void 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/***********************************************************************/
606TDBCAT::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/***********************************************************************/
616PCOL 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/***********************************************************************/
636bool 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/***********************************************************************/
661int 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/***********************************************************************/
677bool 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/***********************************************************************/
708bool 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/***********************************************************************/
737bool 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/***********************************************************************/
746int 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/***********************************************************************/
754int 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/***********************************************************************/
763int 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/***********************************************************************/
772void TDBCAT::CloseDB(PGLOBAL)
773 {
774 // Nothing to do
775 } // end of CloseDB
776
777// ------------------------ CATCOL functions ----------------------------
778
779/***********************************************************************/
780/* CATCOL public constructor. */
781/***********************************************************************/
782CATCOL::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/***********************************************************************/
793void 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