| 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 | |
| 84 | extern pthread_mutex_t tblmut; |
| 85 | |
| 86 | /* ---------------------------- Class TBLDEF ---------------------------- */ |
| 87 | |
| 88 | /**************************************************************************/ |
| 89 | /* Constructor. */ |
| 90 | /**************************************************************************/ |
| 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 | /**************************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 = 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | /***********************************************************************/ |
| 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 | |