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