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