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(_WIN32)
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(_WIN32)
75 #if defined(__BORLANDC__)
76 #define SYSEXIT void _USERENTRY
77 #else
78 #define SYSEXIT void
79 #endif
80 #else // !_WIN32
81 #define SYSEXIT void *
82 #endif // !_WIN32
83
84 extern pthread_mutex_t tblmut;
85
86 /* ---------------------------- Class TBLDEF ---------------------------- */
87
88 /**************************************************************************/
89 /* Constructor. */
90 /**************************************************************************/
TBLDEF(void)91 TBLDEF::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 /**************************************************************************/
DefineAM(PGLOBAL g,LPCSTR,int)104 bool 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 /***********************************************************************/
GetTable(PGLOBAL g,MODE)164 PTDB 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 /***********************************************************************/
TDBTBL(PTBLDEF tdp)185 TDBTBL::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 /***********************************************************************/
MakeCol(PGLOBAL g,PCOLDEF cdp,PCOL cprec,int n)202 PCOL 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 /***********************************************************************/
InsertSpecialColumn(PCOL scp)210 PCOL 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 /***********************************************************************/
InitTableList(PGLOBAL g)231 bool 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 = (char*)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 /***********************************************************************/
TestFil(PGLOBAL g,PCFIL filp,PTABLE tabp)295 bool 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 /***********************************************************************/
Cardinality(PGLOBAL g)355 int 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 /***********************************************************************/
GetMaxSize(PGLOBAL g)384 int 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 /***********************************************************************/
ResetDB(void)411 void 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 /***********************************************************************/
RowNumber(PGLOBAL g,bool b)428 int 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 /***********************************************************************/
OpenDB(PGLOBAL g)437 bool 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 /***********************************************************************/
ReadDB(PGLOBAL g)494 int 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 /***********************************************************************/
ReadColumn(PGLOBAL)556 void 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 /***********************************************************************/
ThreadOpen(void * p)571 pthread_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 /***********************************************************************/
TDBTBM(PTBLDEF tdp)611 TDBTBM::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 /***********************************************************************/
ResetDB(void)624 void 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 /***********************************************************************/
RowNumber(PGLOBAL g,bool b)645 int 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 /***********************************************************************/
IsLocal(PTABLE tbp)653 bool 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 /***********************************************************************/
OpenTables(PGLOBAL g)665 bool 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 /***********************************************************************/
OpenDB(PGLOBAL g)718 bool 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 /***********************************************************************/
ReadDB(PGLOBAL g)784 int 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 /***********************************************************************/
ReadNextRemote(PGLOBAL g)822 int 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