1/************* TabTbl C++ Program Source Code File (.CPP) **************/
2/* PROGRAM NAME: TABTBL */
3/* ------------- */
4/* Version 1.9 */
5/* */
6/* Author: Olivier BERTRAND 2008-2018 */
7/* */
8/* WHAT THIS PROGRAM DOES: */
9/* ----------------------- */
10/* This program are the TDBTBL class DB routines. */
11/* */
12/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
13/* -------------------------------------- */
14/* */
15/* REQUIRED FILES: */
16/* --------------- */
17/* TABTBL.CPP - Source code */
18/* PLGDBSEM.H - DB application declaration file */
19/* TABDOS.H - TABDOS classes declaration file */
20/* TABTBL.H - TABTBL classes declaration file */
21/* GLOBAL.H - Global declaration file */
22/* */
23/* REQUIRED LIBRARIES: */
24/* ------------------- */
25/* Large model C library */
26/* */
27/* REQUIRED PROGRAMS: */
28/* ------------------ */
29/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
30/* */
31/***********************************************************************/
32
33/***********************************************************************/
34/* Include relevant section of system dependant header files. */
35/***********************************************************************/
36//#include "sql_base.h"
37#include "my_global.h"
38#include "table.h" // MySQL table definitions
39#if defined(__WIN__)
40#include <stdlib.h>
41#include <stdio.h>
42#if defined(__BORLANDC__)
43#define __MFC_COMPAT__ // To define min/max as macro
44#endif
45//#include <windows.h>
46#else
47#if defined(UNIX)
48#include <fnmatch.h>
49#include <errno.h>
50#include <stdlib.h>
51#include <stdio.h>
52#include <string.h>
53#include "osutil.h"
54#else
55//#include <io.h>
56#endif
57//#include <fcntl.h>
58#endif
59
60/***********************************************************************/
61/* Include application header files: */
62/***********************************************************************/
63#include "global.h" // global declarations
64#include "plgdbsem.h" // DB application declarations
65#include "reldef.h" // DB definition declares
66#include "filamtxt.h"
67#include "tabcol.h"
68#include "tabdos.h" // TDBDOS and DOSCOL class dcls
69#include "tabtbl.h"
70#include "tabext.h"
71#include "tabmysql.h"
72#include "ha_connect.h"
73
74#if defined(__WIN__)
75#if defined(__BORLANDC__)
76#define SYSEXIT void _USERENTRY
77#else
78#define SYSEXIT void
79#endif
80#else // !__WIN__
81#define SYSEXIT void *
82#endif // !__WIN__
83
84extern pthread_mutex_t tblmut;
85
86/* ---------------------------- Class TBLDEF ---------------------------- */
87
88/**************************************************************************/
89/* Constructor. */
90/**************************************************************************/
91TBLDEF::TBLDEF(void)
92 {
93//To_Tables = NULL;
94 Accept = false;
95 Thread = false;
96 Maxerr = 0;
97 Ntables = 0;
98 Pseudo = 3;
99 } // end of TBLDEF constructor
100
101/**************************************************************************/
102/* DefineAM: define specific AM block values from XDB file. */
103/**************************************************************************/
104bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR, int)
105 {
106 char *tablist, *dbname, *def = NULL;
107
108 Desc = "Table list table";
109 tablist = GetStringCatInfo(g, "Tablist", "");
110 dbname = GetStringCatInfo(g, "Dbname", "*");
111 def = GetStringCatInfo(g, "Srcdef", NULL);
112 Ntables = 0;
113
114 if (*tablist) {
115 char *p, *pn, *pdb;
116 PTABLE tbl;
117
118 for (pdb = tablist; ;) {
119 if ((p = strchr(pdb, ',')))
120 *p = 0;
121
122 // Analyze the table name, it may have the format:
123 // [dbname.]tabname
124 if ((pn = strchr(pdb, '.'))) {
125 *pn++ = 0;
126 } else {
127 pn = pdb;
128 pdb = dbname;
129 } // endif p
130
131 // Allocate the TBLIST block for that table
132 tbl = new(g) XTAB(pn, def);
133 tbl->SetSchema(pdb);
134
135 if (trace(1))
136 htrc("TBL: Name=%s db=%s\n", tbl->GetName(), tbl->GetSchema());
137
138 // Link the blocks
139 if (Tablep)
140 Tablep->Link(tbl);
141 else
142 Tablep = tbl;
143
144 Ntables++;
145
146 if (p)
147 pdb = pn + strlen(pn) + 1;
148 else
149 break;
150
151 } // endfor pdb
152
153 Maxerr = GetIntCatInfo("Maxerr", 0);
154 Accept = GetBoolCatInfo("Accept", false);
155 Thread = GetBoolCatInfo("Thread", false);
156 } // endif tablist
157
158 return FALSE;
159 } // end of DefineAM
160
161/***********************************************************************/
162/* GetTable: makes a new Table Description Block. */
163/***********************************************************************/
164PTDB TBLDEF::GetTable(PGLOBAL g, MODE)
165 {
166 if (Catfunc == FNC_COL)
167 return new(g) TDBTBC(this);
168 else if (Thread) {
169#if defined(DEVELOPMENT)
170 return new(g) TDBTBM(this);
171#else
172 strcpy(g->Message, "Option THREAD is no more supported");
173 return NULL;
174#endif // DEVELOPMENT
175 } else
176 return new(g) TDBTBL(this);
177
178 } // end of GetTable
179
180/* ------------------------- Class TDBTBL ---------------------------- */
181
182/***********************************************************************/
183/* TDBTBL constructors. */
184/***********************************************************************/
185TDBTBL::TDBTBL(PTBLDEF tdp) : TDBPRX(tdp)
186 {
187 Tablist = NULL;
188 CurTable = NULL;
189//Tdbp = NULL;
190 Accept = tdp->Accept;
191 Maxerr = tdp->Maxerr;
192 Nbc = 0;
193 Rows = 0;
194 Crp = 0;
195// NTables = 0;
196// iTable = 0;
197 } // end of TDBTBL standard constructor
198
199/***********************************************************************/
200/* Allocate TBL column description block. */
201/***********************************************************************/
202PCOL TDBTBL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
203 {
204 return new(g) PRXCOL(cdp, this, cprec, n);
205 } // end of MakeCol
206
207/***********************************************************************/
208/* InsertSpecialColumn: Put a special column ahead of the column list.*/
209/***********************************************************************/
210PCOL TDBTBL::InsertSpecialColumn(PCOL scp)
211 {
212 PCOL colp;
213
214 if (!scp->IsSpecial())
215 return NULL;
216
217 if (scp->GetAmType() == TYPE_AM_TABID)
218 // This special column is handled locally
219 colp = new((TIDBLK*)scp) TBTBLK(scp->GetValue());
220 else // Other special columns are treated normally
221 colp = scp;
222
223 colp->SetNext(Columns);
224 Columns = colp;
225 return colp;
226 } // end of InsertSpecialColumn
227
228/***********************************************************************/
229/* Initializes the table table list. */
230/***********************************************************************/
231bool TDBTBL::InitTableList(PGLOBAL g)
232 {
233 int n;
234 uint sln;
235 const char *scs;
236 PTABLE tp, tabp;
237 PCOL colp;
238 PTBLDEF tdp = (PTBLDEF)To_Def;
239 PCATLG cat = To_Def->GetCat();
240 PHC hc = ((MYCAT*)cat)->GetHandler();
241
242 scs = hc->get_table()->s->connect_string.str;
243 sln = hc->get_table()->s->connect_string.length;
244// PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
245
246 for (n = 0, tp = tdp->Tablep; tp; tp = tp->GetNext()) {
247 if (TestFil(g, To_CondFil, tp)) {
248 tabp = new(g) XTAB(tp);
249
250 if (tabp->GetSrc()) {
251 // Table list is a list of connections
252 hc->get_table()->s->connect_string.str = (char*)tabp->GetName();
253 hc->get_table()->s->connect_string.length = strlen(tabp->GetName());
254 } // endif Src
255
256 // Get the table description block of this table
257 if (!(Tdbp = GetSubTable(g, tabp))) {
258 if (++Nbc > Maxerr)
259 return TRUE; // Error return
260 else
261 continue; // Skip this table
262
263 } else
264 RemoveNext(tabp); // To avoid looping
265
266 // We must allocate subtable columns before GetMaxSize is called
267 // because some (PLG, ODBC?) need to have their columns attached.
268 // Real initialization will be done later.
269 for (colp = Columns; colp; colp = colp->GetNext())
270 if (!colp->IsSpecial())
271 if (((PPRXCOL)colp)->Init(g, NULL) && !Accept)
272 return TRUE;
273
274 if (Tablist)
275 Tablist->Link(tabp);
276 else
277 Tablist = tabp;
278
279 n++;
280 } // endif filp
281
282 } // endfor tp
283
284 hc->get_table()->s->connect_string.str = scs;
285 hc->get_table()->s->connect_string.length = sln;
286
287//NumTables = n;
288 To_CondFil = NULL; // To avoid doing it several times
289 return FALSE;
290 } // end of InitTableList
291
292/***********************************************************************/
293/* Test the tablename against the pseudo "local" filter. */
294/***********************************************************************/
295bool TDBTBL::TestFil(PGLOBAL g, PCFIL filp, PTABLE tabp)
296 {
297 char *body, *fil, op[8], tn[NAME_LEN];
298 bool neg;
299
300 if (!filp)
301 return TRUE;
302 else
303 body = filp->Body;
304
305 if (strstr(body, " OR ") || strstr(body, " AND "))
306 return TRUE; // Not handled yet
307 else
308 fil = body + (*body == '(' ? 1 : 0);
309
310 if (sscanf(fil, "TABID %s", op) != 1)
311 return TRUE; // ignore invalid filter
312
313 if ((neg = !strcmp(op, "NOT")))
314 strcpy(op, "IN");
315
316 if (!strcmp(op, "=")) {
317 // Temporarily, filter must be "TABID = 'value'" only
318 if (sscanf(fil, "TABID = '%[^']'", tn) != 1)
319 return TRUE; // ignore invalid filter
320
321 return !stricmp(tn, tabp->GetName());
322 } else if (!strcmp(op, "IN")) {
323 char *p, *tnl = (char*)PlugSubAlloc(g, NULL, strlen(fil) - 10);
324 int n;
325
326 if (neg)
327 n = sscanf(fil, "TABID NOT IN (%[^)])", tnl);
328 else
329 n = sscanf(fil, "TABID IN (%[^)])", tnl);
330
331 if (n != 1)
332 return TRUE; // ignore invalid filter
333
334 while (tnl) {
335 if ((p = strchr(tnl, ',')))
336 *p++ = 0;
337
338 if (sscanf(tnl, "'%[^']'", tn) != 1)
339 return TRUE; // ignore invalid filter
340 else if (!stricmp(tn, tabp->GetName()))
341 return !neg; // Found
342
343 tnl = p;
344 } // endwhile
345
346 return neg; // Not found
347 } // endif op
348
349 return TRUE; // invalid operator
350 } // end of TestFil
351
352/***********************************************************************/
353/* Sum up the cardinality of all sub-tables. */
354/***********************************************************************/
355int TDBTBL::Cardinality(PGLOBAL g)
356 {
357 if (!g)
358 return 0; // Cannot make the table list
359 else if (Cardinal < 0) {
360 int tsz;
361
362 if (!Tablist && InitTableList(g))
363 return 0; // Cannot be calculated at this stage
364
365 Cardinal = 0;
366
367 for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext()) {
368 if ((tsz = tabp->GetTo_Tdb()->Cardinality(g)) < 0) {
369 Cardinal = -1;
370 return tsz;
371 } // endif mxsz
372
373 Cardinal += tsz;
374 } // endfor i
375
376 } // endif Cardinal
377
378 return Cardinal;
379 } // end of Cardinality
380
381/***********************************************************************/
382/* Sum up the maximum sizes of all sub-tables. */
383/***********************************************************************/
384int TDBTBL::GetMaxSize(PGLOBAL g)
385 {
386 if (MaxSize < 0) {
387 int mxsz;
388
389 if (!Tablist && InitTableList(g))
390 return 0; // Cannot be calculated at this stage
391
392 MaxSize = 0;
393
394 for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext()) {
395 if ((mxsz = tabp->GetTo_Tdb()->GetMaxSize(g)) < 0) {
396 MaxSize = -1;
397 return mxsz;
398 } // endif mxsz
399
400 MaxSize += mxsz;
401 } // endfor i
402
403 } // endif MaxSize
404
405 return MaxSize;
406 } // end of GetMaxSize
407
408/***********************************************************************/
409/* Reset read/write position values. */
410/***********************************************************************/
411void TDBTBL::ResetDB(void)
412 {
413 for (PCOL colp = Columns; colp; colp = colp->GetNext())
414 if (colp->GetAmType() == TYPE_AM_TABID ||
415 colp->GetAmType() == TYPE_AM_SRVID)
416 colp->COLBLK::Reset();
417
418 for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext())
419 tabp->GetTo_Tdb()->ResetDB();
420
421 Tdbp = Tablist->GetTo_Tdb();
422 Crp = 0;
423 } // end of ResetDB
424
425/***********************************************************************/
426/* Returns RowId if b is false or Rownum if b is true. */
427/***********************************************************************/
428int TDBTBL::RowNumber(PGLOBAL g, bool b)
429 {
430 return Tdbp->RowNumber(g) + ((b) ? 0 : Rows);
431 } // end of RowNumber
432
433/***********************************************************************/
434/* TBL Access Method opening routine. */
435/* Open first file, other will be opened sequencially when reading. */
436/***********************************************************************/
437bool TDBTBL::OpenDB(PGLOBAL g)
438 {
439 if (trace(1))
440 htrc("TBL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
441 this, Tdb_No, Use, To_Key_Col, Mode);
442
443 if (Use == USE_OPEN) {
444 /*******************************************************************/
445 /* Table already open, replace it at its beginning. */
446 /*******************************************************************/
447 ResetDB();
448 return Tdbp->OpenDB(g); // Re-open fist table
449 } // endif use
450
451 /*********************************************************************/
452 /* When GetMaxsize was called, To_CondFil was not set yet. */
453 /*********************************************************************/
454 if (To_CondFil && Tablist) {
455 Tablist = NULL;
456 Nbc = 0;
457 } // endif To_CondFil
458
459 /*********************************************************************/
460 /* Open the first table of the list. */
461 /*********************************************************************/
462 if (!Tablist && InitTableList(g)) // done in GetMaxSize
463 return TRUE;
464
465 if ((CurTable = Tablist)) {
466 Tdbp = CurTable->GetTo_Tdb();
467// Tdbp->SetMode(Mode);
468// Tdbp->ResetDB();
469// Tdbp->ResetSize();
470
471 // Check and initialize the subtable columns
472 for (PCOL cp = Columns; cp; cp = cp->GetNext())
473 if (cp->GetAmType() == TYPE_AM_TABID)
474 cp->COLBLK::Reset();
475 else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
476 return TRUE;
477
478 if (trace(1))
479 htrc("Opening subtable %s\n", Tdbp->GetName());
480
481 // Now we can safely open the table
482 if (Tdbp->OpenDB(g))
483 return TRUE;
484
485 } // endif *Tablist
486
487 Use = USE_OPEN;
488 return FALSE;
489 } // end of OpenDB
490
491/***********************************************************************/
492/* ReadDB: Data Base read routine for MUL access method. */
493/***********************************************************************/
494int TDBTBL::ReadDB(PGLOBAL g)
495 {
496 int rc;
497
498 if (!CurTable)
499 return RC_EF;
500 else if (To_Kindex) {
501 /*******************************************************************/
502 /* Reading is by an index table. */
503 /*******************************************************************/
504 strcpy(g->Message, MSG(NO_INDEX_READ));
505 rc = RC_FX;
506 } else {
507 /*******************************************************************/
508 /* Now start the reading process. */
509 /*******************************************************************/
510 retry:
511 rc = Tdbp->ReadDB(g);
512
513 if (rc == RC_EF) {
514 // Total number of rows met so far
515 Rows += Tdbp->RowNumber(g) - 1;
516 Crp += Tdbp->GetProgMax(g);
517
518 if ((CurTable = CurTable->GetNext())) {
519 /***************************************************************/
520 /* Continue reading from next table file. */
521 /***************************************************************/
522 Tdbp->CloseDB(g);
523 Tdbp = CurTable->GetTo_Tdb();
524
525 // Check and initialize the subtable columns
526 for (PCOL cp = Columns; cp; cp = cp->GetNext())
527 if (cp->GetAmType() == TYPE_AM_TABID ||
528 cp->GetAmType() == TYPE_AM_SRVID)
529 cp->COLBLK::Reset();
530 else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
531 return RC_FX;
532
533 if (trace(1))
534 htrc("Opening subtable %s\n", Tdbp->GetName());
535
536 // Now we can safely open the table
537 if (Tdbp->OpenDB(g)) // Open next table
538 return RC_FX;
539
540 goto retry;
541 } // endif iFile
542
543 } else if (rc == RC_FX)
544 strcat(strcat(strcat(g->Message, " ("), Tdbp->GetName()), ")");
545
546 } // endif To_Kindex
547
548 return rc;
549 } // end of ReadDB
550
551/* ---------------------------- TBTBLK ------------------------------- */
552
553/***********************************************************************/
554/* ReadColumn: */
555/***********************************************************************/
556void TBTBLK::ReadColumn(PGLOBAL)
557 {
558 if (trace(1))
559 htrc("TBT ReadColumn: name=%s\n", Name);
560
561 Value->SetValue_psz((char*)((PTDBTBL)To_Tdb)->Tdbp->GetName());
562
563 } // end of ReadColumn
564
565#if defined(DEVELOPMENT)
566/* ------------------------- Class TDBTBM ---------------------------- */
567
568/***********************************************************************/
569/* Thread routine that check and open one remote connection. */
570/***********************************************************************/
571pthread_handler_t ThreadOpen(void *p)
572 {
573 PTBMT cmp = (PTBMT)p;
574
575 if (!my_thread_init()) {
576 set_current_thd(cmp->Thd);
577
578 if (trace(1))
579 htrc("ThreadOpen: Thd=%d\n", cmp->Thd);
580
581 // Try to open the connection
582 pthread_mutex_lock(&tblmut);
583
584 if (!cmp->Tap->GetTo_Tdb()->OpenDB(cmp->G)) {
585// pthread_mutex_lock(&tblmut);
586 if (trace(1))
587 htrc("Table %s ready\n", cmp->Tap->GetName());
588
589 cmp->Ready = true;
590// pthread_mutex_unlock(&tblmut);
591 } else {
592// pthread_mutex_lock(&tblmut);
593 if (trace(1))
594 htrc("Opening %s failed\n", cmp->Tap->GetName());
595
596 cmp->Rc = RC_FX;
597// pthread_mutex_unlock(&tblmut);
598 } // endif OpenDB
599
600 pthread_mutex_unlock(&tblmut);
601 my_thread_end();
602 } else
603 cmp->Rc = RC_FX;
604
605 return NULL;
606 } // end of ThreadOpen
607
608/***********************************************************************/
609/* TDBTBM constructors. */
610/***********************************************************************/
611TDBTBM::TDBTBM(PTBLDEF tdp) : TDBTBL(tdp)
612 {
613 Tmp = NULL; // To data table TBMT structures
614 Cmp = NULL; // Current data table TBMT
615 Bmp = NULL; // To bad (unconnected) TBMT structures
616 Done = false; // TRUE after first GetAllResults
617 Nrc = 0; // Number of remote connections
618 Nlc = 0; // Number of local connections
619 } // end of TDBTBL standard constructor
620
621/***********************************************************************/
622/* Reset read/write position values. */
623/***********************************************************************/
624void TDBTBM::ResetDB(void)
625 {
626 for (PCOL colp = Columns; colp; colp = colp->GetNext())
627 if (colp->GetAmType() == TYPE_AM_TABID)
628 colp->COLBLK::Reset();
629
630 // Local tables
631 for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext())
632 tabp->GetTo_Tdb()->ResetDB();
633
634 // Remote tables
635 for (PTBMT tp = Tmp; tp; tp = tp->Next)
636 tp->Tap->GetTo_Tdb()->ResetDB();
637
638 Tdbp = (Tablist) ? Tablist->GetTo_Tdb() : NULL;
639 Crp = 0;
640 } // end of ResetDB
641
642/***********************************************************************/
643/* Returns RowId if b is false or Rownum if b is true. */
644/***********************************************************************/
645int TDBTBM::RowNumber(PGLOBAL g, bool b)
646 {
647 return Tdbp->RowNumber(g) + ((b) ? 0 : Rows);
648 } // end of RowNumber
649
650/***********************************************************************/
651/* Returns true if this MYSQL table refers to a local table. */
652/***********************************************************************/
653bool TDBTBM::IsLocal(PTABLE tbp)
654{
655 TDBMYSQL *tdbp = (TDBMYSQL*)tbp->GetTo_Tdb();
656
657 return ((!stricmp(tdbp->Host, "localhost") ||
658 !strcmp(tdbp->Host, "127.0.0.1")) &&
659 (int) tdbp->Port == (int)GetDefaultPort());
660} // end of IsLocal
661
662/***********************************************************************/
663/* Initialyze table parallel processing. */
664/***********************************************************************/
665bool TDBTBM::OpenTables(PGLOBAL g)
666 {
667 int k;
668 THD *thd = current_thd;
669 PTABLE tabp, *ptabp = &Tablist;
670 PTBMT tp, *ptp = &Tmp;
671
672 // Allocates the TBMT blocks for the tables
673 for (tabp = Tablist; tabp; tabp = tabp->Next)
674 if (tabp->GetTo_Tdb()->GetAmType() == TYPE_AM_MYSQL && !IsLocal(tabp)) {
675 // Remove remote table from the local list
676 *ptabp = tabp->Next;
677
678 if (trace(1))
679 htrc("=====> New remote table %s\n", tabp->GetName());
680
681 // Make the remote table block
682 tp = (PTBMT)PlugSubAlloc(g, NULL, sizeof(TBMT));
683 memset(tp, 0, sizeof(TBMT));
684 tp->G = g;
685 tp->Ready = false;
686 tp->Tap = tabp;
687 tp->Thd = thd;
688
689 // Create the thread that will do the table opening.
690 pthread_attr_init(&tp->attr);
691// pthread_attr_setdetachstate(&tp->attr, PTHREAD_CREATE_JOINABLE);
692
693 if ((k = pthread_create(&tp->Tid, &tp->attr, ThreadOpen, tp))) {
694 sprintf(g->Message, "pthread_create error %d", k);
695 Nbc++;
696 continue;
697 } // endif k
698
699 // Add it to the remote list
700 *ptp = tp;
701 ptp = &tp->Next;
702 Nrc++; // Number of remote connections
703 } else {
704 if (trace(1))
705 htrc("=====> Local table %s\n", tabp->GetName());
706
707 ptabp = &tabp->Next;
708 Nlc++; // Number of local connections
709 } // endif Type
710
711 return false;
712 } // end of OpenTables
713
714/***********************************************************************/
715/* TBL Access Method opening routine. */
716/* Open first file, other will be opened sequencially when reading. */
717/***********************************************************************/
718bool TDBTBM::OpenDB(PGLOBAL g)
719 {
720 if (trace(1))
721 htrc("TBM OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
722 this, Tdb_No, Use, To_Key_Col, Mode);
723
724 if (Use == USE_OPEN) {
725 /*******************************************************************/
726 /* Table already open, replace it at its beginning. */
727 /*******************************************************************/
728 ResetDB();
729 return (Tdbp) ? Tdbp->OpenDB(g) : false; // Re-open fist table
730 } // endif use
731
732#if 0
733 /*********************************************************************/
734 /* When GetMaxsize was called, To_CondFil was not set yet. */
735 /*********************************************************************/
736 if (To_CondFil && Tablist) {
737 Tablist = NULL;
738 Nbc = 0;
739 } // endif To_CondFil
740#endif // 0
741
742 /*********************************************************************/
743 /* Make the table list. */
744 /*********************************************************************/
745 if (/*!Tablist &&*/ InitTableList(g))
746 return TRUE;
747
748 /*********************************************************************/
749 /* Open all remote tables of the list. */
750 /*********************************************************************/
751 if (OpenTables(g))
752 return TRUE;
753
754 /*********************************************************************/
755 /* Proceed with local tables. */
756 /*********************************************************************/
757 if ((CurTable = Tablist)) {
758 Tdbp = CurTable->GetTo_Tdb();
759// Tdbp->SetMode(Mode);
760
761 // Check and initialize the subtable columns
762 for (PCOL cp = Columns; cp; cp = cp->GetNext())
763 if (cp->GetAmType() == TYPE_AM_TABID)
764 cp->COLBLK::Reset();
765 else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
766 return TRUE;
767
768 if (trace(1))
769 htrc("Opening subtable %s\n", Tdbp->GetName());
770
771 // Now we can safely open the table
772 if (Tdbp->OpenDB(g))
773 return TRUE;
774
775 } // endif *Tablist
776
777 Use = USE_OPEN;
778 return FALSE;
779 } // end of OpenDB
780
781/***********************************************************************/
782/* ReadDB: Data Base read routine for MUL access method. */
783/***********************************************************************/
784int TDBTBM::ReadDB(PGLOBAL g)
785 {
786 int rc;
787
788 if (!Done) {
789 // Get result from local tables
790 if ((rc = TDBTBL::ReadDB(g)) != RC_EF)
791 return rc;
792 else if ((rc = ReadNextRemote(g)) != RC_OK)
793 return rc;
794
795 Done = true;
796 } // endif Done
797
798 /*********************************************************************/
799 /* Now start the reading process of remote tables. */
800 /*********************************************************************/
801 retry:
802 rc = Tdbp->ReadDB(g);
803
804 if (rc == RC_EF) {
805 // Total number of rows met so far
806 Rows += Tdbp->RowNumber(g) - 1;
807 Crp += Tdbp->GetProgMax(g);
808 Cmp->Complete = true;
809
810 if ((rc = ReadNextRemote(g)) == RC_OK)
811 goto retry;
812
813 } else if (rc == RC_FX)
814 strcat(strcat(strcat(g->Message, " ("), Tdbp->GetName()), ")");
815
816 return rc;
817 } // end of ReadDB
818
819/***********************************************************************/
820/* ReadNext: Continue reading from next table. */
821/***********************************************************************/
822int TDBTBM::ReadNextRemote(PGLOBAL g)
823 {
824 bool b;
825
826 if (Tdbp)
827 Tdbp->CloseDB(g);
828
829 Cmp = NULL;
830
831 retry:
832 b = false;
833
834 // Search for a remote table having its result set
835 pthread_mutex_lock(&tblmut);
836 for (PTBMT tp = Tmp; tp; tp = tp->Next)
837 if (tp->Rc != RC_FX) {
838 if (tp->Ready) {
839 if (!tp->Complete) {
840 Cmp = tp;
841 break;
842 } // endif Complete
843
844 } else
845 b = true;
846
847 } // endif Rc
848
849 pthread_mutex_unlock(&tblmut);
850
851 if (!Cmp) {
852 if (b) { // more result to come
853// sleep(20);
854 goto retry;
855 } else
856 return RC_EF;
857
858 } // endif Curtable
859
860 Tdbp = Cmp->Tap->GetTo_Tdb();
861
862 // Check and initialize the subtable columns
863 for (PCOL cp = Columns; cp; cp = cp->GetNext())
864 if (cp->GetAmType() == TYPE_AM_TABID)
865 cp->COLBLK::Reset();
866 else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
867 return RC_FX;
868
869 if (trace(1))
870 htrc("Reading subtable %s\n", Tdbp->GetName());
871
872 return RC_OK;
873 } // end of ReadNextRemote
874#endif // DEVELOPMENT
875
876/* ------------------------------------------------------------------- */
877