summaryrefslogtreecommitdiffstats
path: root/storage/connect/tabtbl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/connect/tabtbl.cpp')
-rw-r--r--storage/connect/tabtbl.cpp874
1 files changed, 874 insertions, 0 deletions
diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp
new file mode 100644
index 00000000..607e7d13
--- /dev/null
+++ b/storage/connect/tabtbl.cpp
@@ -0,0 +1,874 @@
+/************* TabTbl C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABTBL */
+/* ------------- */
+/* Version 1.9 */
+/* */
+/* Author: Olivier BERTRAND 2008-2018 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the TDBTBL class DB routines. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* TABTBL.CPP - Source code */
+/* PLGDBSEM.H - DB application declaration file */
+/* TABDOS.H - TABDOS classes declaration file */
+/* TABTBL.H - TABTBL classes declaration file */
+/* GLOBAL.H - Global declaration file */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* Large model C library */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant section of system dependant header files. */
+/***********************************************************************/
+//#include "sql_base.h"
+#include "my_global.h"
+#include "table.h" // MySQL table definitions
+#if defined(_WIN32)
+#include <stdlib.h>
+#include <stdio.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#else
+#if defined(UNIX)
+#include <fnmatch.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "osutil.h"
+#else
+//#include <io.h>
+#endif
+//#include <fcntl.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/***********************************************************************/
+#include "global.h" // global declarations
+#include "plgdbsem.h" // DB application declarations
+#include "reldef.h" // DB definition declares
+#include "filamtxt.h"
+#include "tabcol.h"
+#include "tabdos.h" // TDBDOS and DOSCOL class dcls
+#include "tabtbl.h"
+#include "tabext.h"
+#include "tabmysql.h"
+#include "ha_connect.h"
+
+#if defined(_WIN32)
+#if defined(__BORLANDC__)
+#define SYSEXIT void _USERENTRY
+#else
+#define SYSEXIT void
+#endif
+#else // !_WIN32
+#define SYSEXIT void *
+#endif // !_WIN32
+
+extern pthread_mutex_t tblmut;
+
+/* ---------------------------- Class TBLDEF ---------------------------- */
+
+/**************************************************************************/
+/* Constructor. */
+/**************************************************************************/
+TBLDEF::TBLDEF(void)
+ {
+//To_Tables = NULL;
+ Accept = false;
+ Thread = false;
+ Maxerr = 0;
+ Ntables = 0;
+ Pseudo = 3;
+ } // end of TBLDEF constructor
+
+/**************************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/**************************************************************************/
+bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR, int)
+ {
+ char *tablist, *dbname, *def = NULL;
+
+ Desc = "Table list table";
+ tablist = GetStringCatInfo(g, "Tablist", "");
+ dbname = GetStringCatInfo(g, "Dbname", "*");
+ def = GetStringCatInfo(g, "Srcdef", NULL);
+ Ntables = 0;
+
+ if (*tablist) {
+ char *p, *pn, *pdb;
+ PTABLE tbl;
+
+ for (pdb = tablist; ;) {
+ if ((p = strchr(pdb, ',')))
+ *p = 0;
+
+ // Analyze the table name, it may have the format:
+ // [dbname.]tabname
+ if ((pn = strchr(pdb, '.'))) {
+ *pn++ = 0;
+ } else {
+ pn = pdb;
+ pdb = dbname;
+ } // endif p
+
+ // Allocate the TBLIST block for that table
+ tbl = new(g) XTAB(pn, def);
+ tbl->SetSchema(pdb);
+
+ if (trace(1))
+ htrc("TBL: Name=%s db=%s\n", tbl->GetName(), tbl->GetSchema());
+
+ // Link the blocks
+ if (Tablep)
+ Tablep->Link(tbl);
+ else
+ Tablep = tbl;
+
+ Ntables++;
+
+ if (p)
+ pdb = pn + strlen(pn) + 1;
+ else
+ break;
+
+ } // endfor pdb
+
+ Maxerr = GetIntCatInfo("Maxerr", 0);
+ Accept = GetBoolCatInfo("Accept", false);
+ Thread = GetBoolCatInfo("Thread", false);
+ } // endif tablist
+
+ return FALSE;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB TBLDEF::GetTable(PGLOBAL g, MODE)
+ {
+ if (Catfunc == FNC_COL)
+ return new(g) TDBTBC(this);
+ else if (Thread) {
+#if defined(DEVELOPMENT)
+ return new(g) TDBTBM(this);
+#else
+ strcpy(g->Message, "Option THREAD is no more supported");
+ return NULL;
+#endif // DEVELOPMENT
+ } else
+ return new(g) TDBTBL(this);
+
+ } // end of GetTable
+
+/* ------------------------- Class TDBTBL ---------------------------- */
+
+/***********************************************************************/
+/* TDBTBL constructors. */
+/***********************************************************************/
+TDBTBL::TDBTBL(PTBLDEF tdp) : TDBPRX(tdp)
+ {
+ Tablist = NULL;
+ CurTable = NULL;
+//Tdbp = NULL;
+ Accept = tdp->Accept;
+ Maxerr = tdp->Maxerr;
+ Nbc = 0;
+ Rows = 0;
+ Crp = 0;
+// NTables = 0;
+// iTable = 0;
+ } // end of TDBTBL standard constructor
+
+/***********************************************************************/
+/* Allocate TBL column description block. */
+/***********************************************************************/
+PCOL TDBTBL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) PRXCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* InsertSpecialColumn: Put a special column ahead of the column list.*/
+/***********************************************************************/
+PCOL TDBTBL::InsertSpecialColumn(PCOL scp)
+ {
+ PCOL colp;
+
+ if (!scp->IsSpecial())
+ return NULL;
+
+ if (scp->GetAmType() == TYPE_AM_TABID)
+ // This special column is handled locally
+ colp = new((TIDBLK*)scp) TBTBLK(scp->GetValue());
+ else // Other special columns are treated normally
+ colp = scp;
+
+ colp->SetNext(Columns);
+ Columns = colp;
+ return colp;
+ } // end of InsertSpecialColumn
+
+/***********************************************************************/
+/* Initializes the table table list. */
+/***********************************************************************/
+bool TDBTBL::InitTableList(PGLOBAL g)
+ {
+ uint sln;
+ const char *scs;
+ PTABLE tp, tabp;
+ PCOL colp;
+ PTBLDEF tdp = (PTBLDEF)To_Def;
+ PCATLG cat = To_Def->GetCat();
+ PHC hc = ((MYCAT*)cat)->GetHandler();
+
+ scs = hc->get_table()->s->connect_string.str;
+ sln = hc->get_table()->s->connect_string.length;
+// PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
+
+ for (tp = tdp->Tablep; tp; tp = tp->GetNext()) {
+ if (TestFil(g, To_CondFil, tp)) {
+ tabp = new(g) XTAB(tp);
+
+ if (tabp->GetSrc()) {
+ // Table list is a list of connections
+ hc->get_table()->s->connect_string.str = (char*)tabp->GetName();
+ hc->get_table()->s->connect_string.length = strlen(tabp->GetName());
+ } // endif Src
+
+ // Get the table description block of this table
+ if (!(Tdbp = GetSubTable(g, tabp))) {
+ if (++Nbc > Maxerr)
+ return TRUE; // Error return
+ else
+ continue; // Skip this table
+
+ } else
+ RemoveNext(tabp); // To avoid looping
+
+ // We must allocate subtable columns before GetMaxSize is called
+ // because some (PLG, ODBC?) need to have their columns attached.
+ // Real initialization will be done later.
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (!colp->IsSpecial())
+ if (((PPRXCOL)colp)->Init(g, NULL) && !Accept)
+ return TRUE;
+
+ if (Tablist)
+ Tablist->Link(tabp);
+ else
+ Tablist = tabp;
+
+ } // endif filp
+
+ } // endfor tp
+
+ hc->get_table()->s->connect_string.str = (char*)scs;
+ hc->get_table()->s->connect_string.length = sln;
+
+//NumTables = n;
+ To_CondFil = NULL; // To avoid doing it several times
+ return FALSE;
+ } // end of InitTableList
+
+/***********************************************************************/
+/* Test the tablename against the pseudo "local" filter. */
+/***********************************************************************/
+bool TDBTBL::TestFil(PGLOBAL g, PCFIL filp, PTABLE tabp)
+ {
+ char *body, *fil, op[8], tn[NAME_LEN];
+ bool neg;
+
+ if (!filp)
+ return TRUE;
+ else
+ body = filp->Body;
+
+ if (strstr(body, " OR ") || strstr(body, " AND "))
+ return TRUE; // Not handled yet
+ else
+ fil = body + (*body == '(' ? 1 : 0);
+
+ if (sscanf(fil, "TABID %s", op) != 1)
+ return TRUE; // ignore invalid filter
+
+ if ((neg = !strcmp(op, "NOT")))
+ strcpy(op, "IN");
+
+ if (!strcmp(op, "=")) {
+ // Temporarily, filter must be "TABID = 'value'" only
+ if (sscanf(fil, "TABID = '%[^']'", tn) != 1)
+ return TRUE; // ignore invalid filter
+
+ return !stricmp(tn, tabp->GetName());
+ } else if (!strcmp(op, "IN")) {
+ char *p, *tnl = (char*)PlugSubAlloc(g, NULL, strlen(fil) - 10);
+ int n;
+
+ if (neg)
+ n = sscanf(fil, "TABID NOT IN (%[^)])", tnl);
+ else
+ n = sscanf(fil, "TABID IN (%[^)])", tnl);
+
+ if (n != 1)
+ return TRUE; // ignore invalid filter
+
+ while (tnl) {
+ if ((p = strchr(tnl, ',')))
+ *p++ = 0;
+
+ if (sscanf(tnl, "'%[^']'", tn) != 1)
+ return TRUE; // ignore invalid filter
+ else if (!stricmp(tn, tabp->GetName()))
+ return !neg; // Found
+
+ tnl = p;
+ } // endwhile
+
+ return neg; // Not found
+ } // endif op
+
+ return TRUE; // invalid operator
+ } // end of TestFil
+
+/***********************************************************************/
+/* Sum up the cardinality of all sub-tables. */
+/***********************************************************************/
+int TDBTBL::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return 0; // Cannot make the table list
+ else if (Cardinal < 0) {
+ int tsz;
+
+ if (!Tablist && InitTableList(g))
+ return 0; // Cannot be calculated at this stage
+
+ Cardinal = 0;
+
+ for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext()) {
+ if ((tsz = tabp->GetTo_Tdb()->Cardinality(g)) < 0) {
+ Cardinal = -1;
+ return tsz;
+ } // endif mxsz
+
+ Cardinal += tsz;
+ } // endfor i
+
+ } // endif Cardinal
+
+ return Cardinal;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Sum up the maximum sizes of all sub-tables. */
+/***********************************************************************/
+int TDBTBL::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ int mxsz;
+
+ if (!Tablist && InitTableList(g))
+ return 0; // Cannot be calculated at this stage
+
+ MaxSize = 0;
+
+ for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext()) {
+ if ((mxsz = tabp->GetTo_Tdb()->GetMaxSize(g)) < 0) {
+ MaxSize = -1;
+ return mxsz;
+ } // endif mxsz
+
+ MaxSize += mxsz;
+ } // endfor i
+
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* Reset read/write position values. */
+/***********************************************************************/
+void TDBTBL::ResetDB(void)
+ {
+ for (PCOL colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_TABID ||
+ colp->GetAmType() == TYPE_AM_SRVID)
+ colp->COLBLK::Reset();
+
+ for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext())
+ tabp->GetTo_Tdb()->ResetDB();
+
+ Tdbp = Tablist->GetTo_Tdb();
+ Crp = 0;
+ } // end of ResetDB
+
+/***********************************************************************/
+/* Returns RowId if b is false or Rownum if b is true. */
+/***********************************************************************/
+int TDBTBL::RowNumber(PGLOBAL g, bool b)
+ {
+ return Tdbp->RowNumber(g) + ((b) ? 0 : Rows);
+ } // end of RowNumber
+
+/***********************************************************************/
+/* TBL Access Method opening routine. */
+/* Open first file, other will be opened sequencially when reading. */
+/***********************************************************************/
+bool TDBTBL::OpenDB(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("TBL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
+ this, Tdb_No, Use, To_Key_Col, Mode);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, replace it at its beginning. */
+ /*******************************************************************/
+ ResetDB();
+ return Tdbp->OpenDB(g); // Re-open fist table
+ } // endif use
+
+ /*********************************************************************/
+ /* When GetMaxsize was called, To_CondFil was not set yet. */
+ /*********************************************************************/
+ if (To_CondFil && Tablist) {
+ Tablist = NULL;
+ Nbc = 0;
+ } // endif To_CondFil
+
+ /*********************************************************************/
+ /* Open the first table of the list. */
+ /*********************************************************************/
+ if (!Tablist && InitTableList(g)) // done in GetMaxSize
+ return TRUE;
+
+ if ((CurTable = Tablist)) {
+ Tdbp = CurTable->GetTo_Tdb();
+// Tdbp->SetMode(Mode);
+// Tdbp->ResetDB();
+// Tdbp->ResetSize();
+
+ // Check and initialize the subtable columns
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_TABID)
+ cp->COLBLK::Reset();
+ else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
+ return TRUE;
+
+ if (trace(1))
+ htrc("Opening subtable %s\n", Tdbp->GetName());
+
+ // Now we can safely open the table
+ if (Tdbp->OpenDB(g))
+ return TRUE;
+
+ } // endif *Tablist
+
+ Use = USE_OPEN;
+ return FALSE;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for MUL access method. */
+/***********************************************************************/
+int TDBTBL::ReadDB(PGLOBAL g)
+ {
+ int rc;
+
+ if (!CurTable)
+ return RC_EF;
+ else if (To_Kindex) {
+ /*******************************************************************/
+ /* Reading is by an index table. */
+ /*******************************************************************/
+ strcpy(g->Message, MSG(NO_INDEX_READ));
+ rc = RC_FX;
+ } else {
+ /*******************************************************************/
+ /* Now start the reading process. */
+ /*******************************************************************/
+ retry:
+ rc = Tdbp->ReadDB(g);
+
+ if (rc == RC_EF) {
+ // Total number of rows met so far
+ Rows += Tdbp->RowNumber(g) - 1;
+ Crp += Tdbp->GetProgMax(g);
+
+ if ((CurTable = CurTable->GetNext())) {
+ /***************************************************************/
+ /* Continue reading from next table file. */
+ /***************************************************************/
+ Tdbp->CloseDB(g);
+ Tdbp = CurTable->GetTo_Tdb();
+
+ // Check and initialize the subtable columns
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_TABID ||
+ cp->GetAmType() == TYPE_AM_SRVID)
+ cp->COLBLK::Reset();
+ else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
+ return RC_FX;
+
+ if (trace(1))
+ htrc("Opening subtable %s\n", Tdbp->GetName());
+
+ // Now we can safely open the table
+ if (Tdbp->OpenDB(g)) // Open next table
+ return RC_FX;
+
+ goto retry;
+ } // endif iFile
+
+ } else if (rc == RC_FX)
+ strcat(strcat(strcat(g->Message, " ("), Tdbp->GetName()), ")");
+
+ } // endif To_Kindex
+
+ return rc;
+ } // end of ReadDB
+
+/* ---------------------------- TBTBLK ------------------------------- */
+
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void TBTBLK::ReadColumn(PGLOBAL)
+ {
+ if (trace(1))
+ htrc("TBT ReadColumn: name=%s\n", Name);
+
+ Value->SetValue_psz((char*)((PTDBTBL)To_Tdb)->Tdbp->GetName());
+
+ } // end of ReadColumn
+
+#if defined(DEVELOPMENT)
+/* ------------------------- Class TDBTBM ---------------------------- */
+
+/***********************************************************************/
+/* Thread routine that check and open one remote connection. */
+/***********************************************************************/
+pthread_handler_t ThreadOpen(void *p)
+ {
+ PTBMT cmp = (PTBMT)p;
+
+ if (!my_thread_init()) {
+ set_current_thd(cmp->Thd);
+
+ if (trace(1))
+ htrc("ThreadOpen: Thd=%d\n", cmp->Thd);
+
+ // Try to open the connection
+ pthread_mutex_lock(&tblmut);
+
+ if (!cmp->Tap->GetTo_Tdb()->OpenDB(cmp->G)) {
+// pthread_mutex_lock(&tblmut);
+ if (trace(1))
+ htrc("Table %s ready\n", cmp->Tap->GetName());
+
+ cmp->Ready = true;
+// pthread_mutex_unlock(&tblmut);
+ } else {
+// pthread_mutex_lock(&tblmut);
+ if (trace(1))
+ htrc("Opening %s failed\n", cmp->Tap->GetName());
+
+ cmp->Rc = RC_FX;
+// pthread_mutex_unlock(&tblmut);
+ } // endif OpenDB
+
+ pthread_mutex_unlock(&tblmut);
+ my_thread_end();
+ } else
+ cmp->Rc = RC_FX;
+
+ return NULL;
+ } // end of ThreadOpen
+
+/***********************************************************************/
+/* TDBTBM constructors. */
+/***********************************************************************/
+TDBTBM::TDBTBM(PTBLDEF tdp) : TDBTBL(tdp)
+ {
+ Tmp = NULL; // To data table TBMT structures
+ Cmp = NULL; // Current data table TBMT
+ Bmp = NULL; // To bad (unconnected) TBMT structures
+ Done = false; // TRUE after first GetAllResults
+ Nrc = 0; // Number of remote connections
+ Nlc = 0; // Number of local connections
+ } // end of TDBTBL standard constructor
+
+/***********************************************************************/
+/* Reset read/write position values. */
+/***********************************************************************/
+void TDBTBM::ResetDB(void)
+ {
+ for (PCOL colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_TABID)
+ colp->COLBLK::Reset();
+
+ // Local tables
+ for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext())
+ tabp->GetTo_Tdb()->ResetDB();
+
+ // Remote tables
+ for (PTBMT tp = Tmp; tp; tp = tp->Next)
+ tp->Tap->GetTo_Tdb()->ResetDB();
+
+ Tdbp = (Tablist) ? Tablist->GetTo_Tdb() : NULL;
+ Crp = 0;
+ } // end of ResetDB
+
+/***********************************************************************/
+/* Returns RowId if b is false or Rownum if b is true. */
+/***********************************************************************/
+int TDBTBM::RowNumber(PGLOBAL g, bool b)
+ {
+ return Tdbp->RowNumber(g) + ((b) ? 0 : Rows);
+ } // end of RowNumber
+
+/***********************************************************************/
+/* Returns true if this MYSQL table refers to a local table. */
+/***********************************************************************/
+bool TDBTBM::IsLocal(PTABLE tbp)
+{
+ TDBMYSQL *tdbp = (TDBMYSQL*)tbp->GetTo_Tdb();
+
+ return ((!stricmp(tdbp->Host, "localhost") ||
+ !strcmp(tdbp->Host, "127.0.0.1")) &&
+ (int) tdbp->Port == (int)GetDefaultPort());
+} // end of IsLocal
+
+/***********************************************************************/
+/* Initialyze table parallel processing. */
+/***********************************************************************/
+bool TDBTBM::OpenTables(PGLOBAL g)
+ {
+ int k;
+ THD *thd = current_thd;
+ PTABLE tabp, *ptabp = &Tablist;
+ PTBMT tp, *ptp = &Tmp;
+
+ // Allocates the TBMT blocks for the tables
+ for (tabp = Tablist; tabp; tabp = tabp->Next)
+ if (tabp->GetTo_Tdb()->GetAmType() == TYPE_AM_MYSQL && !IsLocal(tabp)) {
+ // Remove remote table from the local list
+ *ptabp = tabp->Next;
+
+ if (trace(1))
+ htrc("=====> New remote table %s\n", tabp->GetName());
+
+ // Make the remote table block
+ tp = (PTBMT)PlugSubAlloc(g, NULL, sizeof(TBMT));
+ memset(tp, 0, sizeof(TBMT));
+ tp->G = g;
+ tp->Ready = false;
+ tp->Tap = tabp;
+ tp->Thd = thd;
+
+ // Create the thread that will do the table opening.
+ pthread_attr_init(&tp->attr);
+// pthread_attr_setdetachstate(&tp->attr, PTHREAD_CREATE_JOINABLE);
+
+ if ((k = pthread_create(&tp->Tid, &tp->attr, ThreadOpen, tp))) {
+ snprintf(g->Message, sizeof(g->Message), "pthread_create error %d", k);
+ Nbc++;
+ continue;
+ } // endif k
+
+ // Add it to the remote list
+ *ptp = tp;
+ ptp = &tp->Next;
+ Nrc++; // Number of remote connections
+ } else {
+ if (trace(1))
+ htrc("=====> Local table %s\n", tabp->GetName());
+
+ ptabp = &tabp->Next;
+ Nlc++; // Number of local connections
+ } // endif Type
+
+ return false;
+ } // end of OpenTables
+
+/***********************************************************************/
+/* TBL Access Method opening routine. */
+/* Open first file, other will be opened sequencially when reading. */
+/***********************************************************************/
+bool TDBTBM::OpenDB(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("TBM OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
+ this, Tdb_No, Use, To_Key_Col, Mode);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, replace it at its beginning. */
+ /*******************************************************************/
+ ResetDB();
+ return (Tdbp) ? Tdbp->OpenDB(g) : false; // Re-open fist table
+ } // endif use
+
+#if 0
+ /*********************************************************************/
+ /* When GetMaxsize was called, To_CondFil was not set yet. */
+ /*********************************************************************/
+ if (To_CondFil && Tablist) {
+ Tablist = NULL;
+ Nbc = 0;
+ } // endif To_CondFil
+#endif // 0
+
+ /*********************************************************************/
+ /* Make the table list. */
+ /*********************************************************************/
+ if (/*!Tablist &&*/ InitTableList(g))
+ return TRUE;
+
+ /*********************************************************************/
+ /* Open all remote tables of the list. */
+ /*********************************************************************/
+ if (OpenTables(g))
+ return TRUE;
+
+ /*********************************************************************/
+ /* Proceed with local tables. */
+ /*********************************************************************/
+ if ((CurTable = Tablist)) {
+ Tdbp = CurTable->GetTo_Tdb();
+// Tdbp->SetMode(Mode);
+
+ // Check and initialize the subtable columns
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_TABID)
+ cp->COLBLK::Reset();
+ else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
+ return TRUE;
+
+ if (trace(1))
+ htrc("Opening subtable %s\n", Tdbp->GetName());
+
+ // Now we can safely open the table
+ if (Tdbp->OpenDB(g))
+ return TRUE;
+
+ } // endif *Tablist
+
+ Use = USE_OPEN;
+ return FALSE;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for MUL access method. */
+/***********************************************************************/
+int TDBTBM::ReadDB(PGLOBAL g)
+ {
+ int rc;
+
+ if (!Done) {
+ // Get result from local tables
+ if ((rc = TDBTBL::ReadDB(g)) != RC_EF)
+ return rc;
+ else if ((rc = ReadNextRemote(g)) != RC_OK)
+ return rc;
+
+ Done = true;
+ } // endif Done
+
+ /*********************************************************************/
+ /* Now start the reading process of remote tables. */
+ /*********************************************************************/
+ retry:
+ rc = Tdbp->ReadDB(g);
+
+ if (rc == RC_EF) {
+ // Total number of rows met so far
+ Rows += Tdbp->RowNumber(g) - 1;
+ Crp += Tdbp->GetProgMax(g);
+ Cmp->Complete = true;
+
+ if ((rc = ReadNextRemote(g)) == RC_OK)
+ goto retry;
+
+ } else if (rc == RC_FX)
+ strcat(strcat(strcat(g->Message, " ("), Tdbp->GetName()), ")");
+
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* ReadNext: Continue reading from next table. */
+/***********************************************************************/
+int TDBTBM::ReadNextRemote(PGLOBAL g)
+ {
+ bool b;
+
+ if (Tdbp)
+ Tdbp->CloseDB(g);
+
+ Cmp = NULL;
+
+ retry:
+ b = false;
+
+ // Search for a remote table having its result set
+ pthread_mutex_lock(&tblmut);
+ for (PTBMT tp = Tmp; tp; tp = tp->Next)
+ if (tp->Rc != RC_FX) {
+ if (tp->Ready) {
+ if (!tp->Complete) {
+ Cmp = tp;
+ break;
+ } // endif Complete
+
+ } else
+ b = true;
+
+ } // endif Rc
+
+ pthread_mutex_unlock(&tblmut);
+
+ if (!Cmp) {
+ if (b) { // more result to come
+// sleep(20);
+ goto retry;
+ } else
+ return RC_EF;
+
+ } // endif Curtable
+
+ Tdbp = Cmp->Tap->GetTo_Tdb();
+
+ // Check and initialize the subtable columns
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_TABID)
+ cp->COLBLK::Reset();
+ else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
+ return RC_FX;
+
+ if (trace(1))
+ htrc("Reading subtable %s\n", Tdbp->GetName());
+
+ return RC_OK;
+ } // end of ReadNextRemote
+#endif // DEVELOPMENT
+
+/* ------------------------------------------------------------------- */