1 | /************* Tabutil cpp Declares Source Code File (.CPP) ************/ |
2 | /* Name: TABUTIL.CPP Version 1.2 */ |
3 | /* */ |
4 | /* (C) Copyright to the author Olivier BERTRAND 2013 - 2017 */ |
5 | /* */ |
6 | /* Utility function used by the PROXY, XCOL, OCCUR, and TBL tables. */ |
7 | /***********************************************************************/ |
8 | |
9 | /***********************************************************************/ |
10 | /* Include relevant section of system dependant header files. */ |
11 | /***********************************************************************/ |
12 | #define MYSQL_SERVER 1 |
13 | #include <my_global.h> |
14 | #include "sql_class.h" |
15 | #include "table.h" |
16 | #include "field.h" |
17 | #if defined(__WIN__) |
18 | #include <stdlib.h> |
19 | #include <stdio.h> |
20 | #if defined(__BORLANDC__) |
21 | #define __MFC_COMPAT__ // To define min/max as macro |
22 | #endif |
23 | //#include <windows.h> |
24 | #else |
25 | #if defined(UNIX) |
26 | #include <fnmatch.h> |
27 | #include <errno.h> |
28 | #include <stdlib.h> |
29 | #include <stdio.h> |
30 | #include <string.h> |
31 | #include "osutil.h" |
32 | #else |
33 | //#include <io.h> |
34 | #endif |
35 | //#include <fcntl.h> |
36 | #endif |
37 | |
38 | /***********************************************************************/ |
39 | /* Include application header files: */ |
40 | /***********************************************************************/ |
41 | #include "table.h" // MySQL table definitions |
42 | #include "global.h" |
43 | #include "plgdbsem.h" |
44 | #include "plgcnx.h" // For DB types |
45 | #include "myutil.h" |
46 | #include "valblk.h" |
47 | #include "resource.h" |
48 | //#include "reldef.h" |
49 | #include "xtable.h" |
50 | #include "tabext.h" |
51 | #include "tabmysql.h" |
52 | #include "tabcol.h" |
53 | #include "tabutil.h" |
54 | #include "ha_connect.h" |
55 | |
56 | int GetConvSize(void); |
57 | |
58 | /************************************************************************/ |
59 | /* Used by MYSQL tables to get MySQL parameters from the calling proxy */ |
60 | /* table (PROXY, TBL, XCL, or OCCUR) when used by one of these. */ |
61 | /************************************************************************/ |
62 | void Remove_tshp(PCATLG cat) |
63 | { |
64 | ((MYCAT*)cat)->GetHandler()->tshp = NULL; |
65 | } // end of Remove_thsp |
66 | |
67 | /************************************************************************/ |
68 | /* GetTableShare: allocates and open a table share. */ |
69 | /************************************************************************/ |
70 | TABLE_SHARE *GetTableShare(PGLOBAL g, THD *thd, const char *db, |
71 | const char *name, bool& mysql) |
72 | { |
73 | char key[256]; |
74 | uint k; |
75 | TABLE_SHARE *s; |
76 | |
77 | k = sprintf(key, "%s" , db) + 1; |
78 | k += sprintf(key + k, "%s" , name); |
79 | key[++k] = 0; |
80 | |
81 | if (!(s = alloc_table_share(db, name, key, ++k))) { |
82 | strcpy(g->Message, "Error allocating share\n" ); |
83 | return NULL; |
84 | } // endif s |
85 | |
86 | if (!open_table_def(thd, s, GTS_TABLE | GTS_VIEW)) { |
87 | if (!s->is_view) { |
88 | if (stricmp(plugin_name(s->db_plugin)->str, "connect" )) |
89 | mysql = true; |
90 | else |
91 | mysql = false; |
92 | |
93 | } else |
94 | mysql = true; |
95 | |
96 | } else { |
97 | if (thd->is_error()) |
98 | thd->clear_error(); // Avoid stopping info commands |
99 | |
100 | sprintf(g->Message, "Error %d opening share\n" , s->error); |
101 | free_table_share(s); |
102 | return NULL; |
103 | } // endif open_table_def |
104 | |
105 | return s; |
106 | } // end of GetTableShare |
107 | |
108 | /************************************************************************/ |
109 | /* TabColumns: constructs the result blocks containing all the columns */ |
110 | /* description of the object table that will be retrieved by discovery.*/ |
111 | /************************************************************************/ |
112 | PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, |
113 | const char *name, bool& info) |
114 | { |
115 | int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, |
116 | TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, |
117 | TYPE_STRING, TYPE_STRING, TYPE_STRING}; |
118 | XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, |
119 | FLD_LENGTH, FLD_SCALE, FLD_RADIX, FLD_NULL, |
120 | FLD_REM, FLD_NO, FLD_CHARSET}; |
121 | unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 0, 32, 32}; |
122 | PCSZ fmt; |
123 | char *pn, *tn, *fld, *colname, v; // *chset |
124 | int i, n, ncol = sizeof(buftyp) / sizeof(int); |
125 | int prec, len, type, scale; |
126 | int zconv = GetConvSize(); |
127 | bool mysql; |
128 | TABLE_SHARE *s = NULL; |
129 | Field* *field; |
130 | Field *fp; |
131 | PQRYRES qrp; |
132 | PCOLRES crp; |
133 | |
134 | if (!info) { |
135 | // Analyze the table name, it may have the format: [dbname.]tabname |
136 | if (strchr((char*)name, '.')) { |
137 | tn = (char*)PlugDup(g, name); |
138 | pn = strchr(tn, '.'); |
139 | *pn++ = 0; |
140 | db = tn; |
141 | name = pn; |
142 | } // endif pn |
143 | |
144 | if (!(s = GetTableShare(g, thd, db, name, mysql))) { |
145 | return NULL; |
146 | } else if (s->is_view) { |
147 | strcpy(g->Message, "Use MYSQL type to see columns from a view" ); |
148 | info = true; // To tell caller name is a view |
149 | free_table_share(s); |
150 | return NULL; |
151 | } else |
152 | n = s->fieldnames.count; |
153 | |
154 | } else { |
155 | n = 0; |
156 | length[0] = 128; |
157 | } // endif info |
158 | |
159 | /**********************************************************************/ |
160 | /* Allocate the structures used to refer to the result set. */ |
161 | /**********************************************************************/ |
162 | if (!(qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, |
163 | buftyp, fldtyp, length, false, true))) |
164 | return NULL; |
165 | |
166 | // Some columns must be renamed |
167 | for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next) |
168 | switch (++i) { |
169 | case 2: crp->Nulls = (char*)PlugSubAlloc(g, NULL, n); break; |
170 | case 10: crp->Name = "Date_fmt" ; break; |
171 | case 11: crp->Name = "Collation" ; break; |
172 | } // endswitch i |
173 | |
174 | if (info) |
175 | return qrp; |
176 | |
177 | /**********************************************************************/ |
178 | /* Now get the results into blocks. */ |
179 | /**********************************************************************/ |
180 | for (i = 0, field= s->field; *field; field++) { |
181 | fp= *field; |
182 | |
183 | // Get column name |
184 | crp = qrp->Colresp; // Column_Name |
185 | colname = (char *)fp->field_name.str; |
186 | crp->Kdata->SetValue(colname, i); |
187 | |
188 | // chset = (char *)fp->charset()->name; |
189 | // v = (!strcmp(chset, "binary")) ? 'B' : 0; |
190 | v = 0; |
191 | |
192 | if ((type = MYSQLtoPLG(fp->type(), &v)) == TYPE_ERROR) { |
193 | if (v == 'K') { |
194 | // Skip this column |
195 | sprintf(g->Message, "Column %s skipped (unsupported type)" , colname); |
196 | push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); |
197 | continue; |
198 | } // endif v |
199 | |
200 | sprintf(g->Message, "Column %s unsupported type" , colname); |
201 | qrp = NULL; |
202 | break; |
203 | } // endif type |
204 | |
205 | if (v == 'X') { |
206 | len = zconv; |
207 | sprintf(g->Message, "Column %s converted to varchar(%d)" , |
208 | colname, len); |
209 | push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); |
210 | } // endif v |
211 | |
212 | crp = crp->Next; // Data_Type |
213 | crp->Kdata->SetValue(type, i); |
214 | |
215 | if (fp->flags & ZEROFILL_FLAG) |
216 | crp->Nulls[i] = 'Z'; |
217 | else if (fp->flags & UNSIGNED_FLAG) |
218 | crp->Nulls[i] = 'U'; |
219 | else // X means TEXT field |
220 | crp->Nulls[i] = (v == 'X') ? 'V' : v; |
221 | |
222 | crp = crp->Next; // Type_Name |
223 | crp->Kdata->SetValue(GetTypeName(type), i); |
224 | fmt = NULL; |
225 | |
226 | if (type == TYPE_DATE) { |
227 | // When creating tables we do need info about date columns |
228 | if (mysql) { |
229 | fmt = MyDateFmt(fp->type()); |
230 | prec = len = strlen(fmt); |
231 | } else { |
232 | fmt = (PCSZ)fp->option_struct->dateformat; |
233 | prec = len = fp->field_length; |
234 | } // endif mysql |
235 | |
236 | } else if (v != 'X') { |
237 | if (type == TYPE_DECIM) |
238 | prec = ((Field_new_decimal*)fp)->precision; |
239 | else |
240 | prec = fp->field_length; |
241 | // prec = (prec(???) == NOT_FIXED_DEC) ? 0 : fp->field_length; |
242 | |
243 | len = fp->char_length(); |
244 | } else |
245 | prec = len = zconv; |
246 | |
247 | crp = crp->Next; // Precision |
248 | crp->Kdata->SetValue(prec, i); |
249 | |
250 | crp = crp->Next; // Length |
251 | crp->Kdata->SetValue(len, i); |
252 | |
253 | crp = crp->Next; // Scale |
254 | scale = (type == TYPE_DOUBLE || type == TYPE_DECIM) ? fp->decimals() |
255 | : 0; |
256 | crp->Kdata->SetValue(scale, i); |
257 | |
258 | crp = crp->Next; // Radix |
259 | crp->Kdata->SetValue(0, i); |
260 | |
261 | crp = crp->Next; // Nullable |
262 | crp->Kdata->SetValue((fp->null_ptr != 0) ? 1 : 0, i); |
263 | |
264 | crp = crp->Next; // Remark |
265 | |
266 | // For Valgrind |
267 | if (fp->comment.length > 0 && (fld = (char*) fp->comment.str)) |
268 | crp->Kdata->SetValue(fld, fp->comment.length, i); |
269 | else |
270 | crp->Kdata->Reset(i); |
271 | |
272 | crp = crp->Next; // New (date format) |
273 | crp->Kdata->SetValue((fmt) ? fmt : (char*) "" , i); |
274 | |
275 | crp = crp->Next; // New (charset) |
276 | fld = (char *)fp->charset()->name; |
277 | crp->Kdata->SetValue(fld, i); |
278 | |
279 | // Add this item |
280 | qrp->Nblin++; |
281 | i++; // Can be skipped |
282 | } // endfor field |
283 | |
284 | /**********************************************************************/ |
285 | /* Return the result pointer for use by GetData routines. */ |
286 | /**********************************************************************/ |
287 | if (s) |
288 | free_table_share(s); |
289 | |
290 | return qrp; |
291 | } // end of TabColumns |
292 | |
293 | /* -------------- Implementation of the PROXY classes ---------------- */ |
294 | |
295 | /***********************************************************************/ |
296 | /* PRXDEF constructor. */ |
297 | /***********************************************************************/ |
298 | PRXDEF::PRXDEF(void) |
299 | { |
300 | Tablep = NULL; |
301 | Pseudo = 3; |
302 | } // end of PRXDEF constructor |
303 | |
304 | /***********************************************************************/ |
305 | /* DefineAM: define specific AM block values from XCOL file. */ |
306 | /***********************************************************************/ |
307 | bool PRXDEF::DefineAM(PGLOBAL g, LPCSTR, int) |
308 | { |
309 | char *pn, *db, *tab, *def = NULL; |
310 | |
311 | db = GetStringCatInfo(g, "Dbname" , "*" ); |
312 | def = GetStringCatInfo(g, "Srcdef" , NULL); |
313 | |
314 | if (!(tab = GetStringCatInfo(g, "Tabname" , NULL))) { |
315 | if (!def) { |
316 | strcpy(g->Message, "Missing object table definition" ); |
317 | return true; |
318 | } else |
319 | tab = PlugDup(g, "Noname" ); |
320 | |
321 | } else |
322 | // Analyze the table name, it may have the format: [dbname.]tabname |
323 | if ((pn = strchr(tab, '.'))) { |
324 | *pn++ = 0; |
325 | db = tab; |
326 | tab = pn; |
327 | } // endif pn |
328 | |
329 | Tablep = new(g) XTAB(tab, def); |
330 | Tablep->SetSchema(db); |
331 | return false; |
332 | } // end of DefineAM |
333 | |
334 | /***********************************************************************/ |
335 | /* GetTable: makes a new TDB of the proper type. */ |
336 | /***********************************************************************/ |
337 | PTDB PRXDEF::GetTable(PGLOBAL g, MODE) |
338 | { |
339 | if (Catfunc == FNC_COL) |
340 | return new(g) TDBTBC(this); |
341 | else |
342 | return new(g) TDBPRX(this); |
343 | |
344 | } // end of GetTable |
345 | |
346 | /* ------------------------------------------------------------------- */ |
347 | |
348 | /***********************************************************************/ |
349 | /* Implementation of the TDBPRX class. */ |
350 | /***********************************************************************/ |
351 | TDBPRX::TDBPRX(PPRXDEF tdp) : TDBASE(tdp) |
352 | { |
353 | Tdbp = NULL; // The object table |
354 | } // end of TDBPRX constructor |
355 | |
356 | TDBPRX::TDBPRX(PTDBPRX tdbp) : TDBASE(tdbp) |
357 | { |
358 | Tdbp = tdbp->Tdbp; |
359 | } // end of TDBPRX copy constructor |
360 | |
361 | // Method |
362 | PTDB TDBPRX::Clone(PTABS t) |
363 | { |
364 | PTDB tp; |
365 | PPRXCOL cp1, cp2; |
366 | PGLOBAL g = t->G; |
367 | |
368 | tp = new(g) TDBPRX(this); |
369 | |
370 | for (cp1 = (PPRXCOL)Columns; cp1; cp1 = (PPRXCOL)cp1->GetNext()) { |
371 | cp2 = new(g) PRXCOL(cp1, tp); // Make a copy |
372 | NewPointer(t, cp1, cp2); |
373 | } // endfor cp1 |
374 | |
375 | return tp; |
376 | } // end of Clone |
377 | |
378 | /***********************************************************************/ |
379 | /* Get the PTDB of the sub-table. */ |
380 | /***********************************************************************/ |
381 | PTDB TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp, bool b) |
382 | { |
383 | const char *sp = NULL; |
384 | char *db, *name; |
385 | bool mysql = true; |
386 | PTDB tdbp = NULL; |
387 | TABLE_SHARE *s = NULL; |
388 | Field* *fp = NULL; |
389 | PCATLG cat = To_Def->GetCat(); |
390 | PHC hc = ((MYCAT*)cat)->GetHandler(); |
391 | LPCSTR cdb, curdb = hc->GetDBName(NULL); |
392 | THD *thd = (hc->GetTable())->in_use; |
393 | |
394 | db = (char*)(tabp->GetSchema() ? tabp->GetSchema() : curdb); |
395 | name = (char*)tabp->GetName(); |
396 | |
397 | // Check for eventual loop |
398 | for (PTABLE tp = To_Table; tp; tp = tp->Next) { |
399 | cdb = (tp->Schema) ? tp->Schema : curdb; |
400 | |
401 | if (!stricmp(name, tp->Name) && !stricmp(db, cdb)) { |
402 | sprintf(g->Message, "Table %s.%s pointing on itself" , db, name); |
403 | return NULL; |
404 | } // endif |
405 | |
406 | } // endfor tp |
407 | |
408 | if (!tabp->GetSrc()) { |
409 | if (!(s = GetTableShare(g, thd, db, name, mysql))) |
410 | return NULL; |
411 | |
412 | if (s->is_view && !b) |
413 | s->field = hc->get_table()->s->field; |
414 | |
415 | hc->tshp = s; |
416 | } else if (b) { |
417 | // Don't use caller's columns |
418 | fp = hc->get_table()->field; |
419 | hc->get_table()->field = NULL; |
420 | |
421 | // Make caller use the source definition |
422 | sp = hc->get_table()->s->option_struct->srcdef; |
423 | hc->get_table()->s->option_struct->srcdef = tabp->GetSrc(); |
424 | } // endif srcdef |
425 | |
426 | if (mysql) { |
427 | // Access sub-table via MySQL API |
428 | if (!(tdbp= cat->GetTable(g, tabp, Mode, "MYPRX" ))) { |
429 | char buf[MAX_STR]; |
430 | |
431 | strcpy(buf, g->Message); |
432 | sprintf(g->Message, "Error accessing %s.%s: %s" , db, name, buf); |
433 | hc->tshp = NULL; |
434 | goto err; |
435 | } // endif Define |
436 | |
437 | if (db) |
438 | ((PTDBMY)tdbp)->SetDatabase(tabp->GetSchema()); |
439 | |
440 | if (Mode == MODE_UPDATE || Mode == MODE_DELETE) |
441 | tdbp->SetName(Name); // For Make_Command |
442 | |
443 | } else { |
444 | // Sub-table is a CONNECT table |
445 | tabp->Next = To_Table; // For loop checking |
446 | tdbp = cat->GetTable(g, tabp, Mode); |
447 | } // endif mysql |
448 | |
449 | if (s) { |
450 | if (s->is_view && !b) |
451 | s->field = NULL; |
452 | |
453 | hc->tshp = NULL; |
454 | } else if (b) { |
455 | // Restore s structure that can be in cache |
456 | hc->get_table()->field = fp; |
457 | hc->get_table()->s->option_struct->srcdef = sp; |
458 | } // endif s |
459 | |
460 | if (trace(1) && tdbp) |
461 | htrc("Subtable %s in %s\n" , |
462 | name, SVP(tdbp->GetDef()->GetDB())); |
463 | |
464 | err: |
465 | if (s) |
466 | free_table_share(s); |
467 | |
468 | return tdbp; |
469 | } // end of GetSubTable |
470 | |
471 | /***********************************************************************/ |
472 | /* Initializes the table. */ |
473 | /***********************************************************************/ |
474 | bool TDBPRX::InitTable(PGLOBAL g) |
475 | { |
476 | if (!Tdbp) { |
477 | // Get the table description block of this table |
478 | if (!(Tdbp = GetSubTable(g, ((PPRXDEF)To_Def)->Tablep))) |
479 | return true; |
480 | |
481 | // Tdbp->SetMode(Mode); |
482 | } // endif Tdbp |
483 | |
484 | return false; |
485 | } // end of InitTable |
486 | |
487 | /***********************************************************************/ |
488 | /* Allocate PRX column description block. */ |
489 | /***********************************************************************/ |
490 | PCOL TDBPRX::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) |
491 | { |
492 | return new(g) PRXCOL(cdp, this, cprec, n); |
493 | } // end of MakeCol |
494 | |
495 | /***********************************************************************/ |
496 | /* PRX Cardinality: returns the number of rows in the table. */ |
497 | /***********************************************************************/ |
498 | int TDBPRX::Cardinality(PGLOBAL g) |
499 | { |
500 | if (Cardinal < 0) { |
501 | if (InitTable(g)) |
502 | return 0; |
503 | |
504 | Cardinal = Tdbp->Cardinality(g); |
505 | } // endif MaxSize |
506 | |
507 | return Cardinal; |
508 | } // end of GetMaxSize |
509 | |
510 | /***********************************************************************/ |
511 | /* PRX GetMaxSize: returns the maximum number of rows in the table. */ |
512 | /***********************************************************************/ |
513 | int TDBPRX::GetMaxSize(PGLOBAL g) |
514 | { |
515 | if (MaxSize < 0) { |
516 | if (InitTable(g)) |
517 | return 0; |
518 | |
519 | MaxSize = Tdbp->GetMaxSize(g); |
520 | } // endif MaxSize |
521 | |
522 | return MaxSize; |
523 | } // end of GetMaxSize |
524 | |
525 | /***********************************************************************/ |
526 | /* In this sample, ROWID will be the (virtual) row number, */ |
527 | /* while ROWNUM will be the occurence rank in the multiple column. */ |
528 | /***********************************************************************/ |
529 | int TDBPRX::RowNumber(PGLOBAL g, bool b) |
530 | { |
531 | return Tdbp->RowNumber(g, b); |
532 | } // end of RowNumber |
533 | |
534 | /***********************************************************************/ |
535 | /* PROXY Access Method opening routine. */ |
536 | /***********************************************************************/ |
537 | bool TDBPRX::OpenDB(PGLOBAL g) |
538 | { |
539 | if (Use == USE_OPEN) { |
540 | /*******************************************************************/ |
541 | /* Table already open, just replace it at its beginning. */ |
542 | /*******************************************************************/ |
543 | return Tdbp->OpenDB(g); |
544 | } // endif use |
545 | |
546 | if (InitTable(g)) |
547 | return true; |
548 | else if (Mode != MODE_READ && (Read_Only || Tdbp->IsReadOnly())) { |
549 | strcpy(g->Message, "Cannot modify a read only table" ); |
550 | return true; |
551 | } // endif tp |
552 | |
553 | /*********************************************************************/ |
554 | /* Check and initialize the subtable columns. */ |
555 | /*********************************************************************/ |
556 | for (PCOL cp = Columns; cp; cp = cp->GetNext()) |
557 | if (((PPRXCOL)cp)->Init(g, Tdbp)) |
558 | return true; |
559 | |
560 | /*********************************************************************/ |
561 | /* In Update mode, the updated column blocks must be distinct from */ |
562 | /* the read column blocks. So make a copy of the TDB and allocate */ |
563 | /* its column blocks in mode write (required by XML tables). */ |
564 | /*********************************************************************/ |
565 | if (Mode == MODE_UPDATE) { |
566 | PTDB utp; |
567 | |
568 | if (!(utp= Tdbp->Duplicate(g))) { |
569 | sprintf(g->Message, MSG(INV_UPDT_TABLE), Tdbp->GetName()); |
570 | return true; |
571 | } // endif tp |
572 | |
573 | for (PCOL cp = To_SetCols; cp; cp = cp->GetNext()) |
574 | if (((PPRXCOL)cp)->Init(g, utp)) |
575 | return true; |
576 | |
577 | } else if (Mode == MODE_DELETE) |
578 | Tdbp->SetNext(Next); |
579 | |
580 | /*********************************************************************/ |
581 | /* Physically open the object table. */ |
582 | /*********************************************************************/ |
583 | if (Tdbp->OpenDB(g)) |
584 | return true; |
585 | |
586 | Tdbp->SetNext(NULL); |
587 | Use = USE_OPEN; |
588 | return false; |
589 | } // end of OpenDB |
590 | |
591 | /***********************************************************************/ |
592 | /* Data Base read routine for PROY access method. */ |
593 | /***********************************************************************/ |
594 | int TDBPRX::ReadDB(PGLOBAL g) |
595 | { |
596 | /*********************************************************************/ |
597 | /* Now start the reading process. */ |
598 | /*********************************************************************/ |
599 | return Tdbp->ReadDB(g); |
600 | } // end of ReadDB |
601 | |
602 | /***********************************************************************/ |
603 | /* WriteDB: Data Base write routine for PROXY access methods. */ |
604 | /***********************************************************************/ |
605 | int TDBPRX::WriteDB(PGLOBAL g) |
606 | { |
607 | return Tdbp->WriteDB(g); |
608 | } // end of WriteDB |
609 | |
610 | /***********************************************************************/ |
611 | /* Data Base delete line routine for PROXY access methods. */ |
612 | /***********************************************************************/ |
613 | int TDBPRX::DeleteDB(PGLOBAL g, int irc) |
614 | { |
615 | return Tdbp->DeleteDB(g, irc); |
616 | } // end of DeleteDB |
617 | |
618 | /***********************************************************************/ |
619 | /* Used by the TBL tables. */ |
620 | /***********************************************************************/ |
621 | void TDBPRX::RemoveNext(PTABLE tp) |
622 | { |
623 | tp->Next = NULL; |
624 | } // end of RemoveNext |
625 | |
626 | /* ---------------------------- PRXCOL ------------------------------- */ |
627 | |
628 | /***********************************************************************/ |
629 | /* PRXCOL public constructor. */ |
630 | /***********************************************************************/ |
631 | PRXCOL::PRXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am) |
632 | : COLBLK(cdp, tdbp, i) |
633 | { |
634 | if (cprec) { |
635 | Next = cprec->GetNext(); |
636 | cprec->SetNext(this); |
637 | } else { |
638 | Next = tdbp->GetColumns(); |
639 | tdbp->SetColumns(this); |
640 | } // endif cprec |
641 | |
642 | // Set additional Dos access method information for column. |
643 | Long = cdp->GetLong(); // Useful ??? |
644 | //strcpy(F_Date, cdp->F_Date); |
645 | Colp = NULL; |
646 | To_Val = NULL; |
647 | Pseudo = false; |
648 | Colnum = cdp->GetOffset(); // If columns are retrieved by number |
649 | |
650 | if (trace(1)) |
651 | htrc(" making new %sCOL C%d %s at %p\n" , am, Index, Name, this); |
652 | |
653 | } // end of PRXCOL constructor |
654 | |
655 | /***********************************************************************/ |
656 | /* PRXCOL constructor used for copying columns. */ |
657 | /* tdbp is the pointer to the new table descriptor. */ |
658 | /***********************************************************************/ |
659 | PRXCOL::PRXCOL(PRXCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp) |
660 | { |
661 | Colp = col1->Colp; |
662 | To_Val = col1->To_Val; |
663 | Pseudo = col1->Pseudo; |
664 | Colnum = col1->Colnum; |
665 | } // end of PRXCOL copy constructor |
666 | |
667 | /***********************************************************************/ |
668 | /* Convert an UTF-8 name to latin characters. */ |
669 | /***********************************************************************/ |
670 | char *PRXCOL::Decode(PGLOBAL g, const char *cnm) |
671 | { |
672 | char *buf= (char*)PlugSubAlloc(g, NULL, strlen(cnm) + 1); |
673 | uint dummy_errors; |
674 | uint32 len= copy_and_convert(buf, strlen(cnm) + 1, |
675 | &my_charset_latin1, |
676 | cnm, strlen(cnm), |
677 | &my_charset_utf8_general_ci, |
678 | &dummy_errors); |
679 | buf[len]= '\0'; |
680 | return buf; |
681 | } // end of Decode |
682 | |
683 | /***********************************************************************/ |
684 | /* PRXCOL initialization routine. */ |
685 | /* Look for the matching column in the object table. */ |
686 | /***********************************************************************/ |
687 | bool PRXCOL::Init(PGLOBAL g, PTDB tp) |
688 | { |
689 | if (!tp) |
690 | tp = ((PTDBPRX)To_Tdb)->Tdbp; |
691 | |
692 | if (!(Colp = tp->ColDB(g, Name, 0)) && Colnum) |
693 | Colp = tp->ColDB(g, NULL, Colnum); |
694 | |
695 | if (Colp) { |
696 | MODE mode = To_Tdb->GetMode(); |
697 | |
698 | // Needed for MYSQL subtables |
699 | ((XCOLBLK*)Colp)->Name = Decode(g, Colp->GetName()); |
700 | |
701 | // May not have been done elsewhere |
702 | Colp->InitValue(g); |
703 | To_Val = Colp->GetValue(); |
704 | |
705 | if (mode == MODE_INSERT || mode == MODE_UPDATE) |
706 | if (Colp->SetBuffer(g, Colp->GetValue(), true, false)) |
707 | return true; |
708 | |
709 | // this may be needed by some tables (which?) |
710 | Colp->SetColUse(ColUse); |
711 | } else { |
712 | sprintf(g->Message, MSG(NO_MATCHING_COL), Name, tp->GetName()); |
713 | return true; |
714 | } // endif Colp |
715 | |
716 | return false; |
717 | } // end of Init |
718 | |
719 | /***********************************************************************/ |
720 | /* Reset the column descriptor to non evaluated yet. */ |
721 | /***********************************************************************/ |
722 | void PRXCOL::Reset(void) |
723 | { |
724 | if (Colp) |
725 | Colp->Reset(); |
726 | |
727 | Status &= ~BUF_READ; |
728 | } // end of Reset |
729 | |
730 | /***********************************************************************/ |
731 | /* ReadColumn: */ |
732 | /***********************************************************************/ |
733 | void PRXCOL::ReadColumn(PGLOBAL g) |
734 | { |
735 | if (trace(2)) |
736 | htrc("PRX ReadColumn: name=%s\n" , Name); |
737 | |
738 | if (Colp) { |
739 | Colp->Eval(g); |
740 | Value->SetValue_pval(To_Val); |
741 | |
742 | // Set null when applicable |
743 | if (Nullable) |
744 | Value->SetNull(Value->IsNull()); |
745 | |
746 | } else { |
747 | Value->Reset(); |
748 | |
749 | // Set null when applicable |
750 | if (Nullable) |
751 | Value->SetNull(true); |
752 | |
753 | } // endif Colp |
754 | |
755 | } // end of ReadColumn |
756 | |
757 | /***********************************************************************/ |
758 | /* WriteColumn: */ |
759 | /***********************************************************************/ |
760 | void PRXCOL::WriteColumn(PGLOBAL g) |
761 | { |
762 | if (trace(2)) |
763 | htrc("PRX WriteColumn: name=%s\n" , Name); |
764 | |
765 | if (Colp) { |
766 | To_Val->SetValue_pval(Value); |
767 | Colp->WriteColumn(g); |
768 | } // endif Colp |
769 | |
770 | } // end of WriteColumn |
771 | |
772 | /* ---------------------------TDBTBC class --------------------------- */ |
773 | |
774 | /***********************************************************************/ |
775 | /* TDBTBC class constructor. */ |
776 | /***********************************************************************/ |
777 | TDBTBC::TDBTBC(PPRXDEF tdp) : TDBCAT(tdp) |
778 | { |
779 | Db = (PSZ)tdp->Tablep->GetSchema(); |
780 | Tab = (PSZ)tdp->Tablep->GetName(); |
781 | } // end of TDBTBC constructor |
782 | |
783 | /***********************************************************************/ |
784 | /* GetResult: Get the list the MYSQL table columns. */ |
785 | /***********************************************************************/ |
786 | PQRYRES TDBTBC::GetResult(PGLOBAL g) |
787 | { |
788 | bool b = false; |
789 | |
790 | return TabColumns(g, current_thd, Db, Tab, b); |
791 | } // end of GetResult |
792 | |
793 | |