mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			804 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			804 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/************* Tabutil cpp Declares Source Code File (.CPP) ************/
 | 
						|
/*  Name: TABUTIL.CPP   Version 1.2                                    */
 | 
						|
/*                                                                     */
 | 
						|
/*  (C) Copyright to the author Olivier BERTRAND          2013 - 2017  */
 | 
						|
/*                                                                     */
 | 
						|
/*  Utility function used by the PROXY, XCOL, OCCUR, and TBL tables.   */
 | 
						|
/***********************************************************************/
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Include relevant section of system dependant header files.         */
 | 
						|
/***********************************************************************/
 | 
						|
#define MYSQL_SERVER 1
 | 
						|
#include <my_global.h>
 | 
						|
#include "sql_class.h"
 | 
						|
#include "table.h"
 | 
						|
#include "field.h"
 | 
						|
#if defined(_WIN32)
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
#if defined(__BORLANDC__)
 | 
						|
#define __MFC_COMPAT__                   // To define min/max as macro
 | 
						|
#endif
 | 
						|
//#include <windows.h>
 | 
						|
#else
 | 
						|
#if defined(UNIX)
 | 
						|
#include <fnmatch.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
#include "osutil.h"
 | 
						|
#else
 | 
						|
//#include <io.h>
 | 
						|
#endif
 | 
						|
//#include <fcntl.h>
 | 
						|
#endif
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Include application header files:                                  */
 | 
						|
/***********************************************************************/
 | 
						|
#include "table.h"       // MySQL table definitions
 | 
						|
#include "global.h"
 | 
						|
#include "plgdbsem.h"
 | 
						|
#include "plgcnx.h"                       // For DB types
 | 
						|
#include "myutil.h"
 | 
						|
#include "valblk.h"
 | 
						|
#include "resource.h"
 | 
						|
//#include "reldef.h"
 | 
						|
#include "xtable.h"
 | 
						|
#include "tabext.h"
 | 
						|
#include "tabmysql.h"
 | 
						|
#include "tabcol.h"
 | 
						|
#include "tabutil.h"
 | 
						|
#include "ha_connect.h"
 | 
						|
 | 
						|
int GetConvSize(void);
 | 
						|
 | 
						|
/************************************************************************/
 | 
						|
/*  Used by MYSQL tables to get MySQL parameters from the calling proxy */
 | 
						|
/*  table (PROXY, TBL, XCL, or OCCUR) when used by one of these.        */
 | 
						|
/************************************************************************/
 | 
						|
TABLE_SHARE *Remove_tshp(PCATLG cat)
 | 
						|
{
 | 
						|
  TABLE_SHARE *s = ((MYCAT*)cat)->GetHandler()->tshp;
 | 
						|
 | 
						|
	((MYCAT*)cat)->GetHandler()->tshp = NULL;
 | 
						|
	return s;
 | 
						|
} // end of Remove_thsp
 | 
						|
 | 
						|
/************************************************************************/
 | 
						|
/*  Used by MYSQL tables to get MySQL parameters from the calling proxy */
 | 
						|
/*  table (PROXY, TBL, XCL, or OCCUR) when used by one of these.        */
 | 
						|
/************************************************************************/
 | 
						|
void Restore_tshp(PCATLG cat, TABLE_SHARE *s)
 | 
						|
{
 | 
						|
	((MYCAT*)cat)->GetHandler()->tshp = s;
 | 
						|
} // end of Restore_thsp
 | 
						|
 | 
						|
/************************************************************************/
 | 
						|
/*  GetTableShare: allocates and open a table share.                    */
 | 
						|
/************************************************************************/
 | 
						|
TABLE_SHARE *GetTableShare(PGLOBAL g, THD *thd, const char *db, 
 | 
						|
                                      const char *name, bool& mysql)
 | 
						|
{
 | 
						|
  char         key[256];
 | 
						|
  uint         k;
 | 
						|
  TABLE_SHARE *s;
 | 
						|
 | 
						|
	k = sprintf(key, "%s", db) + 1;
 | 
						|
	k += sprintf(key + k, "%s", name);
 | 
						|
  key[++k] = 0;
 | 
						|
 | 
						|
	if (!(s = alloc_table_share(db, name, key, ++k))) {
 | 
						|
    strcpy(g->Message, "Error allocating share\n");
 | 
						|
    return NULL;
 | 
						|
    } // endif s
 | 
						|
 | 
						|
  if (!open_table_def(thd, s, GTS_TABLE | GTS_VIEW)) {
 | 
						|
    if (!s->is_view) {
 | 
						|
      if (stricmp(plugin_name(s->db_plugin)->str, "connect"))
 | 
						|
        mysql = true;
 | 
						|
      else
 | 
						|
        mysql = false;
 | 
						|
 | 
						|
    } else
 | 
						|
      mysql = true;
 | 
						|
 | 
						|
  } else {
 | 
						|
    if (thd->is_error())
 | 
						|
      thd->clear_error();  // Avoid stopping info commands
 | 
						|
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "Error %d opening share\n", s->error);
 | 
						|
    free_table_share(s);
 | 
						|
    return NULL;
 | 
						|
  } // endif open_table_def
 | 
						|
 | 
						|
  return s;
 | 
						|
} // end of GetTableShare
 | 
						|
 | 
						|
/************************************************************************/
 | 
						|
/*  TabColumns: constructs the result blocks containing all the columns */
 | 
						|
/*  description of the object table that will be retrieved by discovery.*/
 | 
						|
/************************************************************************/
 | 
						|
PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db, 
 | 
						|
                                        const char *name, bool& info)
 | 
						|
  {
 | 
						|
  int  buftyp[] = {TYPE_STRING, TYPE_SHORT,  TYPE_STRING, TYPE_INT,
 | 
						|
                   TYPE_INT,    TYPE_SHORT,  TYPE_SHORT,  TYPE_SHORT,
 | 
						|
                   TYPE_STRING, TYPE_STRING, TYPE_STRING};
 | 
						|
  XFLD fldtyp[] = {FLD_NAME,   FLD_TYPE,  FLD_TYPENAME, FLD_PREC,
 | 
						|
                   FLD_LENGTH, FLD_SCALE, FLD_RADIX,    FLD_NULL,
 | 
						|
                   FLD_REM,    FLD_NO,    FLD_CHARSET};
 | 
						|
  unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 0, 32, 32};
 | 
						|
	PCSZ         fmt;
 | 
						|
	char        *pn, *tn, *fld, *colname, v; // *chset
 | 
						|
  int          i, n, ncol = sizeof(buftyp) / sizeof(int);
 | 
						|
  int          prec, len, type, scale;
 | 
						|
  int          zconv = GetConvSize();
 | 
						|
  bool         mysql;
 | 
						|
  TABLE_SHARE *s = NULL;
 | 
						|
  Field*      *field;
 | 
						|
  Field       *fp;
 | 
						|
  PQRYRES      qrp;
 | 
						|
  PCOLRES      crp;
 | 
						|
 | 
						|
  if (!info) {
 | 
						|
		// Analyze the table name, it may have the format: [dbname.]tabname
 | 
						|
		if (strchr((char*)name, '.')) {
 | 
						|
			tn = (char*)PlugDup(g, name);
 | 
						|
			pn = strchr(tn, '.');
 | 
						|
			*pn++ = 0;
 | 
						|
			db = tn;
 | 
						|
			name = pn;
 | 
						|
		} // endif pn
 | 
						|
 | 
						|
		if (!(s = GetTableShare(g, thd, db, name, mysql))) {
 | 
						|
      return NULL;
 | 
						|
    } else if (s->is_view) {
 | 
						|
      strcpy(g->Message, "Use MYSQL type to see columns from a view");
 | 
						|
      info = true;       // To tell caller name is a view
 | 
						|
      free_table_share(s);
 | 
						|
      return NULL;
 | 
						|
    } else
 | 
						|
      n = s->fieldnames.count;
 | 
						|
 | 
						|
  } else {
 | 
						|
    n = 0;
 | 
						|
    length[0] = 128;
 | 
						|
  } // endif info
 | 
						|
 | 
						|
  /**********************************************************************/
 | 
						|
  /*  Allocate the structures used to refer to the result set.          */
 | 
						|
  /**********************************************************************/
 | 
						|
  if (!(qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
 | 
						|
                             buftyp, fldtyp, length, false, true)))
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  // Some columns must be renamed
 | 
						|
  for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
 | 
						|
    switch (++i) {
 | 
						|
      case  2: crp->Nulls = (char*)PlugSubAlloc(g, NULL, n); break;
 | 
						|
      case 10: crp->Name = "Date_fmt";  break;
 | 
						|
      case 11: crp->Name = "Collation"; break;
 | 
						|
      } // endswitch i
 | 
						|
 | 
						|
  if (info)
 | 
						|
    return qrp;
 | 
						|
 | 
						|
  /**********************************************************************/
 | 
						|
  /*  Now get the results into blocks.                                  */
 | 
						|
  /**********************************************************************/
 | 
						|
  for (i = 0, field= s->field; *field; field++) {
 | 
						|
    fp= *field;
 | 
						|
 | 
						|
    // Get column name
 | 
						|
    crp = qrp->Colresp;                    // Column_Name
 | 
						|
    colname = (char *)fp->field_name.str;
 | 
						|
    crp->Kdata->SetValue(colname, i);
 | 
						|
 | 
						|
//  chset = (char *)fp->charset()->name;
 | 
						|
//  v = (!strcmp(chset, "binary")) ? 'B' : 0;
 | 
						|
		v = 0;
 | 
						|
 | 
						|
    if ((type = MYSQLtoPLG(fp->type(), &v)) == TYPE_ERROR) {
 | 
						|
      if (v == 'K') {
 | 
						|
        // Skip this column
 | 
						|
        snprintf(g->Message, sizeof(g->Message), "Column %s skipped (unsupported type)", colname);
 | 
						|
        push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
 | 
						|
        continue;
 | 
						|
        } // endif v
 | 
						|
 | 
						|
      snprintf(g->Message, sizeof(g->Message), "Column %s unsupported type", colname);
 | 
						|
      qrp = NULL;
 | 
						|
      break;
 | 
						|
      } // endif type
 | 
						|
 | 
						|
      if (v == 'X') {
 | 
						|
        len = zconv;
 | 
						|
        snprintf(g->Message, sizeof(g->Message), "Column %s converted to varchar(%d)",
 | 
						|
                colname, len);
 | 
						|
        push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
 | 
						|
        } // endif v
 | 
						|
 | 
						|
    crp = crp->Next;                       // Data_Type
 | 
						|
    crp->Kdata->SetValue(type, i);
 | 
						|
 | 
						|
    if (fp->flags & ZEROFILL_FLAG)
 | 
						|
      crp->Nulls[i] = 'Z';
 | 
						|
    else if (fp->flags & UNSIGNED_FLAG)
 | 
						|
      crp->Nulls[i] = 'U';
 | 
						|
    else                  // X means TEXT field
 | 
						|
      crp->Nulls[i] = (v == 'X') ? 'V' : v;
 | 
						|
 | 
						|
    crp = crp->Next;                       // Type_Name
 | 
						|
    crp->Kdata->SetValue(GetTypeName(type), i);
 | 
						|
    fmt = NULL;
 | 
						|
 | 
						|
    if (type == TYPE_DATE) {
 | 
						|
      // When creating tables we do need info about date columns
 | 
						|
      if (mysql) {
 | 
						|
        fmt = MyDateFmt(fp->type());
 | 
						|
        prec = len = strlen(fmt);
 | 
						|
      } else {
 | 
						|
        fmt = (PCSZ)fp->option_struct->dateformat;
 | 
						|
        prec = len = fp->field_length;
 | 
						|
      } // endif mysql
 | 
						|
 | 
						|
    } else if (v != 'X') {
 | 
						|
      if (type == TYPE_DECIM)
 | 
						|
        prec = ((Field_new_decimal*)fp)->precision;
 | 
						|
      else
 | 
						|
        prec = fp->field_length;
 | 
						|
//      prec = (prec(???) == NOT_FIXED_DEC) ? 0 : fp->field_length;
 | 
						|
 | 
						|
      len = fp->char_length();
 | 
						|
    } else
 | 
						|
      prec = len = zconv;
 | 
						|
 | 
						|
    crp = crp->Next;                       // Precision
 | 
						|
    crp->Kdata->SetValue(prec, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // Length
 | 
						|
    crp->Kdata->SetValue(len, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // Scale
 | 
						|
    scale = (type == TYPE_DOUBLE || type == TYPE_DECIM) ? fp->decimals()
 | 
						|
                                                        : 0;
 | 
						|
    crp->Kdata->SetValue(scale, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // Radix
 | 
						|
    crp->Kdata->SetValue(0, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // Nullable
 | 
						|
    crp->Kdata->SetValue((fp->null_ptr != 0) ? 1 : 0, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // Remark
 | 
						|
 | 
						|
    // For Valgrind
 | 
						|
    if (fp->comment.length > 0 && (fld = (char*) fp->comment.str))
 | 
						|
      crp->Kdata->SetValue(fld, fp->comment.length, i);
 | 
						|
    else
 | 
						|
      crp->Kdata->Reset(i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // New (date format)
 | 
						|
    crp->Kdata->SetValue((fmt) ? fmt : (char*) "", i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // New (charset)
 | 
						|
    fld = (char *)fp->charset()->coll_name.str;
 | 
						|
    crp->Kdata->SetValue(fld, i);
 | 
						|
 | 
						|
    // Add this item
 | 
						|
    qrp->Nblin++;
 | 
						|
    i++;                                   // Can be skipped
 | 
						|
    } // endfor field
 | 
						|
 | 
						|
  /**********************************************************************/
 | 
						|
  /*  Return the result pointer for use by GetData routines.            */
 | 
						|
  /**********************************************************************/
 | 
						|
  if (s)
 | 
						|
	  free_table_share(s);
 | 
						|
	  
 | 
						|
  return qrp;
 | 
						|
  } // end of TabColumns
 | 
						|
 | 
						|
/* -------------- Implementation of the PROXY classes	---------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  PRXDEF constructor.                                                */
 | 
						|
/***********************************************************************/
 | 
						|
PRXDEF::PRXDEF(void)
 | 
						|
  {
 | 
						|
  Tablep = NULL;
 | 
						|
  Pseudo = 3;
 | 
						|
} // end of PRXDEF constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  DefineAM: define specific AM block values from XCOL file.          */
 | 
						|
/***********************************************************************/
 | 
						|
bool PRXDEF::DefineAM(PGLOBAL g, LPCSTR, int)
 | 
						|
  {
 | 
						|
  char *pn, *db, *tab, *def = NULL;
 | 
						|
 | 
						|
  db = GetStringCatInfo(g, "Dbname", "*");
 | 
						|
  def = GetStringCatInfo(g, "Srcdef", NULL);
 | 
						|
 | 
						|
  if (!(tab = GetStringCatInfo(g, "Tabname", NULL))) {
 | 
						|
    if (!def) {
 | 
						|
      strcpy(g->Message, "Missing object table definition");
 | 
						|
      return true;
 | 
						|
    } else
 | 
						|
      tab = PlugDup(g, "Noname");
 | 
						|
 | 
						|
  } else
 | 
						|
    // Analyze the table name, it may have the format: [dbname.]tabname
 | 
						|
    if ((pn = strchr(tab, '.'))) {
 | 
						|
      *pn++ = 0;
 | 
						|
      db = tab;
 | 
						|
      tab = pn;
 | 
						|
      } // endif pn
 | 
						|
 | 
						|
  Tablep = new(g) XTAB(tab, def);
 | 
						|
  Tablep->SetSchema(db);
 | 
						|
  return false;
 | 
						|
  } // end of DefineAM
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  GetTable: makes a new TDB of the proper type.                      */
 | 
						|
/***********************************************************************/
 | 
						|
PTDB PRXDEF::GetTable(PGLOBAL g, MODE)
 | 
						|
  {
 | 
						|
  if (Catfunc == FNC_COL)
 | 
						|
    return new(g) TDBTBC(this);
 | 
						|
  else
 | 
						|
    return new(g) TDBPRX(this);
 | 
						|
 | 
						|
  } // end of GetTable
 | 
						|
 | 
						|
/* ------------------------------------------------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Implementation of the TDBPRX class.                                */
 | 
						|
/***********************************************************************/
 | 
						|
TDBPRX::TDBPRX(PPRXDEF tdp) : TDBASE(tdp)
 | 
						|
  {
 | 
						|
  Tdbp = NULL;                    // The object table
 | 
						|
  } // end of TDBPRX constructor
 | 
						|
 | 
						|
TDBPRX::TDBPRX(PTDBPRX tdbp) : TDBASE(tdbp)
 | 
						|
  {
 | 
						|
  Tdbp = tdbp->Tdbp;
 | 
						|
  } // end of TDBPRX copy constructor
 | 
						|
 | 
						|
// Method
 | 
						|
PTDB TDBPRX::Clone(PTABS t)
 | 
						|
  {
 | 
						|
  PTDB    tp;
 | 
						|
  PPRXCOL cp1, cp2;
 | 
						|
  PGLOBAL g = t->G;
 | 
						|
 | 
						|
  tp = new(g) TDBPRX(this);
 | 
						|
 | 
						|
  for (cp1 = (PPRXCOL)Columns; cp1; cp1 = (PPRXCOL)cp1->GetNext()) {
 | 
						|
    cp2 = new(g) PRXCOL(cp1, tp);  // Make a copy
 | 
						|
    NewPointer(t, cp1, cp2);
 | 
						|
    } // endfor cp1
 | 
						|
 | 
						|
  return tp;
 | 
						|
  } // end of Clone
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Get the PTDB of the sub-table.                                     */
 | 
						|
/***********************************************************************/
 | 
						|
PTDB TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp, bool b)
 | 
						|
  {
 | 
						|
  const char  *sp = NULL;
 | 
						|
  char        *db, *name;
 | 
						|
  bool         mysql = true;
 | 
						|
  PTDB         tdbp = NULL;
 | 
						|
  TABLE_SHARE *s = NULL;
 | 
						|
  Field*      *fp = NULL;
 | 
						|
  PCATLG       cat = To_Def->GetCat();
 | 
						|
  PHC          hc = ((MYCAT*)cat)->GetHandler();
 | 
						|
  LPCSTR       cdb, curdb = hc->GetDBName(NULL);
 | 
						|
  THD         *thd = (hc->GetTable())->in_use;
 | 
						|
 | 
						|
  db = (char*)(tabp->GetSchema() ? tabp->GetSchema() : curdb);
 | 
						|
  name = (char*)tabp->GetName();
 | 
						|
 | 
						|
  // Check for eventual loop
 | 
						|
  for (PTABLE tp = To_Table; tp; tp = tp->Next) {
 | 
						|
    cdb = (tp->Schema) ? tp->Schema : curdb;
 | 
						|
 | 
						|
    if (!stricmp(name, tp->Name) && !stricmp(db, cdb)) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), "Table %s.%s pointing on itself", db, name);
 | 
						|
      return NULL;
 | 
						|
      } // endif
 | 
						|
 | 
						|
    } // endfor tp
 | 
						|
 | 
						|
  if (!tabp->GetSrc()) {
 | 
						|
    if (!(s = GetTableShare(g, thd, db, name, mysql)))
 | 
						|
      return NULL;
 | 
						|
 | 
						|
    if (s->is_view && !b)
 | 
						|
      s->field = hc->get_table()->s->field;
 | 
						|
 | 
						|
    hc->tshp = s;
 | 
						|
  } else if (b) {
 | 
						|
    // Don't use caller's columns
 | 
						|
    fp = hc->get_table()->field;
 | 
						|
    hc->get_table()->field = NULL;
 | 
						|
 | 
						|
    // Make caller use the source definition
 | 
						|
    sp = hc->get_table()->s->option_struct->srcdef;
 | 
						|
    hc->get_table()->s->option_struct->srcdef = tabp->GetSrc();
 | 
						|
  } // endif srcdef
 | 
						|
 | 
						|
  if (mysql) {
 | 
						|
    // Access sub-table via MySQL API
 | 
						|
    if (!(tdbp= cat->GetTable(g, tabp, Mode, "MYPRX"))) {
 | 
						|
      char buf[MAX_STR];
 | 
						|
 | 
						|
      strcpy(buf, g->Message);
 | 
						|
      snprintf(g->Message, sizeof(g->Message), "Error accessing %s.%s: %s", db, name, buf);
 | 
						|
      hc->tshp = NULL;
 | 
						|
      goto err;
 | 
						|
      } // endif Define
 | 
						|
 | 
						|
    if (db)
 | 
						|
      ((PTDBMY)tdbp)->SetDatabase(tabp->GetSchema());
 | 
						|
 | 
						|
    if (Mode == MODE_UPDATE || Mode == MODE_DELETE)
 | 
						|
      tdbp->SetName(Name);      // For Make_Command
 | 
						|
 | 
						|
  } else {
 | 
						|
    // Sub-table is a CONNECT table
 | 
						|
    tabp->Next = To_Table;          // For loop checking
 | 
						|
    tdbp = cat->GetTable(g, tabp, Mode);
 | 
						|
  } // endif mysql
 | 
						|
 | 
						|
  if (s) {
 | 
						|
    if (s->is_view && !b)
 | 
						|
      s->field = NULL;
 | 
						|
 | 
						|
    hc->tshp = NULL;
 | 
						|
  } else if (b) {
 | 
						|
    // Restore s structure that can be in cache
 | 
						|
    hc->get_table()->field = fp;
 | 
						|
    hc->get_table()->s->option_struct->srcdef = sp;
 | 
						|
  } // endif s
 | 
						|
 | 
						|
  if (trace(1) && tdbp)
 | 
						|
    htrc("Subtable %s in %s\n", 
 | 
						|
          name, SVP(tdbp->GetDef()->GetDB()));
 | 
						|
 
 | 
						|
 err:
 | 
						|
  if (s)
 | 
						|
    free_table_share(s);
 | 
						|
 | 
						|
  return tdbp;
 | 
						|
  } // end of GetSubTable
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Initializes the table.                                             */
 | 
						|
/***********************************************************************/
 | 
						|
bool TDBPRX::InitTable(PGLOBAL g)
 | 
						|
  {
 | 
						|
  if (!Tdbp) {
 | 
						|
    // Get the table description block of this table
 | 
						|
    if (!(Tdbp = GetSubTable(g, ((PPRXDEF)To_Def)->Tablep)))
 | 
						|
      return true;
 | 
						|
 | 
						|
//  Tdbp->SetMode(Mode);
 | 
						|
    } // endif Tdbp
 | 
						|
 | 
						|
  return false;
 | 
						|
  } // end of InitTable
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Allocate PRX column description block.                             */
 | 
						|
/***********************************************************************/
 | 
						|
PCOL TDBPRX::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
 | 
						|
  {
 | 
						|
  return new(g) PRXCOL(cdp, this, cprec, n);
 | 
						|
  } // end of MakeCol
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  PRX Cardinality: returns the number of rows in the table.          */
 | 
						|
/***********************************************************************/
 | 
						|
int TDBPRX::Cardinality(PGLOBAL g)
 | 
						|
  {
 | 
						|
  if (Cardinal < 0) {
 | 
						|
    if (InitTable(g))
 | 
						|
      return 0;
 | 
						|
  
 | 
						|
  	Cardinal = Tdbp->Cardinality(g);
 | 
						|
    } // endif MaxSize
 | 
						|
 | 
						|
  return Cardinal;
 | 
						|
  } // end of GetMaxSize
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  PRX GetMaxSize: returns the maximum number of rows in the table.   */
 | 
						|
/***********************************************************************/
 | 
						|
int TDBPRX::GetMaxSize(PGLOBAL g)
 | 
						|
  {
 | 
						|
  if (MaxSize < 0) {
 | 
						|
    if (InitTable(g))
 | 
						|
      return 0;
 | 
						|
  
 | 
						|
  	MaxSize = Tdbp->GetMaxSize(g);
 | 
						|
    } // endif MaxSize
 | 
						|
 | 
						|
  return MaxSize;
 | 
						|
  } // end of GetMaxSize
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  In this sample, ROWID will be the (virtual) row number,            */
 | 
						|
/*  while ROWNUM will be the occurrence rank in the multiple column.    */
 | 
						|
/***********************************************************************/
 | 
						|
int TDBPRX::RowNumber(PGLOBAL g, bool b)
 | 
						|
	{
 | 
						|
	return Tdbp->RowNumber(g, b);
 | 
						|
	} // end of RowNumber
 | 
						|
 
 | 
						|
/***********************************************************************/
 | 
						|
/*  PROXY Access Method opening routine.                               */
 | 
						|
/***********************************************************************/
 | 
						|
bool TDBPRX::OpenDB(PGLOBAL g)
 | 
						|
  {
 | 
						|
  if (Use == USE_OPEN) {
 | 
						|
    /*******************************************************************/
 | 
						|
    /*  Table already open, just replace it at its beginning.          */
 | 
						|
    /*******************************************************************/
 | 
						|
		return Tdbp->OpenDB(g);
 | 
						|
    } // endif use
 | 
						|
 | 
						|
  if (InitTable(g))
 | 
						|
    return true;
 | 
						|
  else if (Mode != MODE_READ && (Read_Only || Tdbp->IsReadOnly())) {
 | 
						|
    strcpy(g->Message, "Cannot modify a read only table");
 | 
						|
    return true;
 | 
						|
    } // endif tp
 | 
						|
  
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Check and initialize the subtable columns.                       */
 | 
						|
  /*********************************************************************/
 | 
						|
  for (PCOL cp = Columns; cp; cp = cp->GetNext())
 | 
						|
    if (((PPRXCOL)cp)->Init(g, Tdbp))
 | 
						|
      return true;
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  In Update mode, the updated column blocks must be distinct from  */
 | 
						|
  /*  the read column blocks. So make a copy of the TDB and allocate   */
 | 
						|
  /*  its column blocks in mode write (required by XML tables).        */
 | 
						|
  /*********************************************************************/
 | 
						|
  if (Mode == MODE_UPDATE) {
 | 
						|
    PTDB utp;
 | 
						|
 | 
						|
    if (!(utp= Tdbp->Duplicate(g))) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(INV_UPDT_TABLE), Tdbp->GetName());
 | 
						|
      return true;
 | 
						|
      } // endif tp
 | 
						|
 | 
						|
    for (PCOL cp = To_SetCols; cp; cp = cp->GetNext())
 | 
						|
      if (((PPRXCOL)cp)->Init(g, utp))
 | 
						|
        return true;
 | 
						|
 | 
						|
  } else if (Mode == MODE_DELETE)
 | 
						|
    Tdbp->SetNext(Next);
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Physically open the object table.                                */
 | 
						|
  /*********************************************************************/
 | 
						|
	if (Tdbp->OpenDB(g))
 | 
						|
		return true;
 | 
						|
 | 
						|
  Tdbp->SetNext(NULL);
 | 
						|
  Use = USE_OPEN;
 | 
						|
	return false;
 | 
						|
  } // end of OpenDB
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Data Base read routine for PROY access method.                     */
 | 
						|
/***********************************************************************/
 | 
						|
int TDBPRX::ReadDB(PGLOBAL g)
 | 
						|
  {
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Now start the reading process.                                   */
 | 
						|
  /*********************************************************************/
 | 
						|
	return Tdbp->ReadDB(g);
 | 
						|
  } // end of ReadDB
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  WriteDB: Data Base write routine for PROXY access methods.         */
 | 
						|
/***********************************************************************/
 | 
						|
int TDBPRX::WriteDB(PGLOBAL g)
 | 
						|
  {
 | 
						|
  return Tdbp->WriteDB(g);
 | 
						|
  } // end of WriteDB
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Data Base delete line routine for PROXY access methods.            */
 | 
						|
/***********************************************************************/
 | 
						|
int TDBPRX::DeleteDB(PGLOBAL g, int irc)
 | 
						|
  {
 | 
						|
  return Tdbp->DeleteDB(g, irc);
 | 
						|
  } // end of DeleteDB
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Used by the TBL tables.                                            */
 | 
						|
/***********************************************************************/
 | 
						|
void TDBPRX::RemoveNext(PTABLE tp)
 | 
						|
  {
 | 
						|
  tp->Next = NULL;
 | 
						|
  } // end of RemoveNext
 | 
						|
 | 
						|
/* ---------------------------- PRXCOL ------------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  PRXCOL public constructor.                                         */
 | 
						|
/***********************************************************************/
 | 
						|
PRXCOL::PRXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
 | 
						|
      : COLBLK(cdp, tdbp, i)
 | 
						|
  {
 | 
						|
  if (cprec) {
 | 
						|
    Next = cprec->GetNext();
 | 
						|
    cprec->SetNext(this);
 | 
						|
  } else {
 | 
						|
    Next = tdbp->GetColumns();
 | 
						|
    tdbp->SetColumns(this);
 | 
						|
  } // endif cprec
 | 
						|
 | 
						|
  // Set additional Dos access method information for column.
 | 
						|
  Long = cdp->GetLong();         // Useful ???
 | 
						|
//strcpy(F_Date, cdp->F_Date);
 | 
						|
  Colp = NULL;
 | 
						|
  To_Val = NULL;
 | 
						|
  Pseudo = false;
 | 
						|
  Colnum = cdp->GetOffset();     // If columns are retrieved by number
 | 
						|
 | 
						|
  if (trace(1))
 | 
						|
    htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
 | 
						|
 | 
						|
  } // end of PRXCOL constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  PRXCOL constructor used for copying columns.                       */
 | 
						|
/*  tdbp is the pointer to the new table descriptor.                   */
 | 
						|
/***********************************************************************/
 | 
						|
PRXCOL::PRXCOL(PRXCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
 | 
						|
  {
 | 
						|
  Colp = col1->Colp;
 | 
						|
  To_Val = col1->To_Val;
 | 
						|
  Pseudo = col1->Pseudo;
 | 
						|
  Colnum = col1->Colnum;
 | 
						|
  } // end of PRXCOL copy constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Convert an UTF-8 name to latin characters.                         */
 | 
						|
/***********************************************************************/
 | 
						|
char *PRXCOL::Decode(PGLOBAL g, const char *cnm)
 | 
						|
  {
 | 
						|
  char  *buf= (char*)PlugSubAlloc(g, NULL, strlen(cnm) + 1);
 | 
						|
  uint   dummy_errors;
 | 
						|
  uint32 len= copy_and_convert(buf, strlen(cnm) + 1,
 | 
						|
                               &my_charset_latin1,
 | 
						|
                               cnm, strlen(cnm),
 | 
						|
                               &my_charset_utf8mb3_general_ci,
 | 
						|
                               &dummy_errors);
 | 
						|
  buf[len]= '\0';
 | 
						|
  return buf;
 | 
						|
  } // end of Decode
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  PRXCOL initialization routine.                                     */
 | 
						|
/*  Look for the matching column in the object table.                  */
 | 
						|
/***********************************************************************/
 | 
						|
bool PRXCOL::Init(PGLOBAL g, PTDB tp)
 | 
						|
  {
 | 
						|
  if (!tp)
 | 
						|
    tp = ((PTDBPRX)To_Tdb)->Tdbp;
 | 
						|
 | 
						|
  if (!(Colp = tp->ColDB(g, Name, 0)) && Colnum)
 | 
						|
    Colp = tp->ColDB(g, NULL, Colnum);
 | 
						|
 | 
						|
  if (Colp) {
 | 
						|
    MODE mode = To_Tdb->GetMode();
 | 
						|
 | 
						|
    // Needed for MYSQL subtables
 | 
						|
    ((COLBLK*)Colp)->SetName(Decode(g, Colp->GetName()));
 | 
						|
 | 
						|
    // May not have been done elsewhere
 | 
						|
    Colp->InitValue(g);        
 | 
						|
    To_Val = Colp->GetValue();
 | 
						|
 | 
						|
    if (mode == MODE_INSERT || mode == MODE_UPDATE)
 | 
						|
      if (Colp->SetBuffer(g, Colp->GetValue(), true, false))
 | 
						|
        return true;
 | 
						|
 | 
						|
    // this may be needed by some tables (which?)
 | 
						|
    Colp->SetColUse(ColUse);
 | 
						|
  } else {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), MSG(NO_MATCHING_COL), Name, tp->GetName());
 | 
						|
    return true;
 | 
						|
  } // endif Colp
 | 
						|
 | 
						|
  return false;
 | 
						|
  } // end of Init
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Reset the column descriptor to non evaluated yet.                  */
 | 
						|
/***********************************************************************/
 | 
						|
void PRXCOL::Reset(void)
 | 
						|
  {
 | 
						|
  if (Colp)
 | 
						|
    Colp->Reset();
 | 
						|
 | 
						|
  Status &= ~BUF_READ;
 | 
						|
  } // end of Reset
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  ReadColumn:                                                        */
 | 
						|
/***********************************************************************/
 | 
						|
void PRXCOL::ReadColumn(PGLOBAL g)
 | 
						|
  {
 | 
						|
  if (trace(2))
 | 
						|
    htrc("PRX ReadColumn: name=%s\n", Name);
 | 
						|
 | 
						|
  if (Colp) {
 | 
						|
    Colp->Eval(g);
 | 
						|
    Value->SetValue_pval(To_Val);
 | 
						|
 | 
						|
    // Set null when applicable
 | 
						|
    if (Nullable)
 | 
						|
      Value->SetNull(Value->IsNull());
 | 
						|
 | 
						|
	} else {
 | 
						|
		Value->Reset();
 | 
						|
 | 
						|
		// Set null when applicable
 | 
						|
		if (Nullable)
 | 
						|
			Value->SetNull(true);
 | 
						|
 | 
						|
	}	// endif Colp
 | 
						|
 | 
						|
  } // end of ReadColumn
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  WriteColumn:                                                       */
 | 
						|
/***********************************************************************/
 | 
						|
void PRXCOL::WriteColumn(PGLOBAL g)
 | 
						|
  {
 | 
						|
  if (trace(2))
 | 
						|
    htrc("PRX WriteColumn: name=%s\n", Name);
 | 
						|
 | 
						|
  if (Colp) {
 | 
						|
    To_Val->SetValue_pval(Value);
 | 
						|
    Colp->WriteColumn(g);
 | 
						|
    } // endif Colp
 | 
						|
 | 
						|
  } // end of WriteColumn
 | 
						|
 | 
						|
/* ---------------------------TDBTBC class --------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  TDBTBC class constructor.                                          */
 | 
						|
/***********************************************************************/
 | 
						|
TDBTBC::TDBTBC(PPRXDEF tdp) : TDBCAT(tdp)
 | 
						|
  {
 | 
						|
  Db  = (PSZ)tdp->Tablep->GetSchema();    
 | 
						|
  Tab = (PSZ)tdp->Tablep->GetName();    
 | 
						|
  } // end of TDBTBC constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  GetResult: Get the list the MYSQL table columns.                   */
 | 
						|
/***********************************************************************/
 | 
						|
PQRYRES TDBTBC::GetResult(PGLOBAL g)
 | 
						|
  {
 | 
						|
  bool b = false;
 | 
						|
 | 
						|
  return TabColumns(g, current_thd, Db, Tab, b);
 | 
						|
	} // end of GetResult
 | 
						|
 |