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 | |