mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	- Removed not used variable 'file' from MYSQL_BIN_LOG::open() - Assigned not initialized variable in connect/tabext.cpp
		
			
				
	
	
		
			813 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			813 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/************* Tabext C++ Functions Source Code File (.CPP) ************/
 | 
						|
/*  Name: TABEXT.CPP  Version 1.1                                      */
 | 
						|
/*                                                                     */
 | 
						|
/*  (C) Copyright to the author Olivier BERTRAND          2017 - 2019  */
 | 
						|
/*                                                                     */
 | 
						|
/*  This file contains the TBX, TDB and OPJOIN classes functions.      */
 | 
						|
/***********************************************************************/
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Include relevant MariaDB header file.                              */
 | 
						|
/***********************************************************************/
 | 
						|
#define MYSQL_SERVER 1
 | 
						|
#include "my_global.h"
 | 
						|
#include "sql_class.h"
 | 
						|
#include "sql_servers.h"
 | 
						|
#include "sql_string.h"
 | 
						|
#if !defined(_WIN32)
 | 
						|
#include "osutil.h"
 | 
						|
#endif
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Include required application header files                          */
 | 
						|
/*  global.h    is header containing all global Plug declarations.     */
 | 
						|
/*  plgdbsem.h  is header containing the DB applic. declarations.      */
 | 
						|
/*  xobject.h   is header containing XOBJECT derived classes declares. */
 | 
						|
/***********************************************************************/
 | 
						|
#include "global.h"
 | 
						|
#include "plgdbsem.h"
 | 
						|
#include "xtable.h"
 | 
						|
#include "tabext.h"
 | 
						|
#include "ha_connect.h"
 | 
						|
 | 
						|
/* -------------------------- Class CONDFIL -------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  CONDFIL Constructor.                                               */
 | 
						|
/***********************************************************************/
 | 
						|
CONDFIL::CONDFIL(uint idx, AMT type)
 | 
						|
{
 | 
						|
//Cond = cond; 
 | 
						|
	Idx = idx; 
 | 
						|
	Type = type;
 | 
						|
	Op = OP_XX;
 | 
						|
	Cmds = NULL;
 | 
						|
	Alist = NULL;
 | 
						|
	All = true;
 | 
						|
	Bd = false;
 | 
						|
	Hv = false;
 | 
						|
	Body = NULL, 
 | 
						|
	Having = NULL;
 | 
						|
}	// end of CONDFIL constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Make and allocate the alias list.                                  */
 | 
						|
/***********************************************************************/
 | 
						|
int CONDFIL::Init(PGLOBAL g, PHC hc)
 | 
						|
{
 | 
						|
	PTOS  options = hc->GetTableOptionStruct();
 | 
						|
	char *p, *cn, *cal, *alt = NULL;
 | 
						|
	int   rc = RC_OK;
 | 
						|
	bool  h;
 | 
						|
 | 
						|
	if (options)
 | 
						|
    alt = (char*)GetListOption(g, "Alias", options->oplist, NULL);
 | 
						|
 | 
						|
	while (alt) {
 | 
						|
		if (!(p = strchr(alt, '='))) {
 | 
						|
      safe_strcpy(g->Message, sizeof(g->Message), "Invalid alias list");
 | 
						|
			rc = RC_FX;
 | 
						|
			break;
 | 
						|
		}	// endif !p
 | 
						|
 | 
						|
		cal = alt;				 // Alias
 | 
						|
		*p++ = 0;
 | 
						|
 | 
						|
		if ((h = *p == '*')) {
 | 
						|
			rc = RC_INFO;
 | 
						|
			p++;
 | 
						|
		}	// endif h
 | 
						|
 | 
						|
		cn = p;						// Remote column name
 | 
						|
 | 
						|
		if ((alt = strchr(p, ';')))
 | 
						|
			*alt++ = 0;
 | 
						|
 | 
						|
		if (*cn == 0)
 | 
						|
			cn = alt;
 | 
						|
 | 
						|
		Alist = new(g) ALIAS(Alist, cn, cal, h);
 | 
						|
	}	// endwhile alt
 | 
						|
 | 
						|
	return rc;
 | 
						|
}	// end of Init
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Make and allocate the alias list.                                  */
 | 
						|
/***********************************************************************/
 | 
						|
const char *CONDFIL::Chk(const char *fln, bool *h)
 | 
						|
{
 | 
						|
	for (PAL pal = Alist; pal; pal = pal->Next)
 | 
						|
		if (!stricmp(fln, pal->Alias)) {
 | 
						|
			*h = pal->Having;
 | 
						|
			return pal->Name;
 | 
						|
		}	// endif fln
 | 
						|
 | 
						|
	*h = false;
 | 
						|
	return fln;
 | 
						|
}	// end of Chk
 | 
						|
 | 
						|
/* --------------------------- Class EXTDEF -------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  EXTDEF Constructor.                                                */
 | 
						|
/***********************************************************************/
 | 
						|
EXTDEF::EXTDEF(void)
 | 
						|
{
 | 
						|
	Tabname = Tabschema = Username = Password = Tabcat = Tabtyp = NULL;
 | 
						|
	Colpat = Srcdef = Qchar = Qrystr = Sep = Phpos = NULL;
 | 
						|
	Options = Cto = Qto = Quoted = Maxerr = Maxres = Memory = 0;
 | 
						|
	Scrollable = Xsrc = false;
 | 
						|
} // end of EXTDEF constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  DefineAM: define specific AM block values from XDB file.           */
 | 
						|
/***********************************************************************/
 | 
						|
bool EXTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
 | 
						|
{
 | 
						|
	if (g->Createas) {
 | 
						|
		safe_strcpy(g->Message, sizeof(g->Message),
 | 
						|
			"Multiple-table UPDATE/DELETE commands are not supported");
 | 
						|
		return true;
 | 
						|
	}	// endif multi
 | 
						|
 | 
						|
	Desc = NULL;
 | 
						|
	Tabname = GetStringCatInfo(g, "Name",
 | 
						|
		(Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name);
 | 
						|
	Tabname = GetStringCatInfo(g, "Tabname", Tabname);
 | 
						|
	Tabschema = GetStringCatInfo(g, "Dbname", NULL);
 | 
						|
	Tabschema = GetStringCatInfo(g, "Schema", Tabschema);
 | 
						|
	Tabcat = GetStringCatInfo(g, "Qualifier", NULL);
 | 
						|
	Tabcat = GetStringCatInfo(g, "Catalog", Tabcat);
 | 
						|
	Username = GetStringCatInfo(g, "User", NULL);
 | 
						|
	Password = GetStringCatInfo(g, "Password", NULL);
 | 
						|
 | 
						|
	// Memory was Boolean, it is now integer
 | 
						|
	if (!(Memory = GetIntCatInfo("Memory", 0)))
 | 
						|
		Memory = GetBoolCatInfo("Memory", false) ? 1 : 0;
 | 
						|
 | 
						|
	if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL))) {
 | 
						|
		Read_Only = true;
 | 
						|
		if (Memory == 2) Memory = 1;
 | 
						|
	}	// endif Srcdef
 | 
						|
 | 
						|
	Qrystr = GetStringCatInfo(g, "Query_String", "?");
 | 
						|
	Sep = GetStringCatInfo(g, "Separator", NULL);
 | 
						|
//Alias = GetStringCatInfo(g, "Alias", NULL);
 | 
						|
	Phpos = GetStringCatInfo(g, "Phpos", NULL);
 | 
						|
	Xsrc = GetBoolCatInfo("Execsrc", FALSE);
 | 
						|
	Maxerr = GetIntCatInfo("Maxerr", 0);
 | 
						|
	Maxres = GetIntCatInfo("Maxres", 0);
 | 
						|
	Quoted = GetIntCatInfo("Quoted", 0);
 | 
						|
	Qchar = GetStringCatInfo(g,"Qchar", NULL);
 | 
						|
  if (Qchar && !Quoted)
 | 
						|
    Quoted = 1;
 | 
						|
	Options = 0;
 | 
						|
	Cto = 0;
 | 
						|
	Qto = 0;
 | 
						|
 | 
						|
	if ((Scrollable = GetBoolCatInfo("Scrollable", false)) && !Elemt)
 | 
						|
		Elemt = 1;     // Cannot merge SQLFetch and SQLExtendedFetch
 | 
						|
 | 
						|
	if (Catfunc == FNC_COL)
 | 
						|
		Colpat = GetStringCatInfo(g, "Colpat", NULL);
 | 
						|
 | 
						|
	if (Catfunc == FNC_TABLE)
 | 
						|
		Tabtyp = GetStringCatInfo(g, "Tabtype", NULL);
 | 
						|
 | 
						|
	Pseudo = 2;    // FILID is Ok but not ROWID
 | 
						|
	return false;
 | 
						|
} // end of DefineAM
 | 
						|
 | 
						|
/* ---------------------------TDBEXT class --------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Implementation of the TDBEXT class.                                */
 | 
						|
/***********************************************************************/
 | 
						|
TDBEXT::TDBEXT(EXTDEF *tdp) : TDB(tdp)
 | 
						|
{
 | 
						|
	Qrp = NULL;
 | 
						|
 | 
						|
	if (tdp) {
 | 
						|
		TableName = tdp->Tabname;
 | 
						|
		Schema = tdp->Tabschema;
 | 
						|
		User = tdp->Username;
 | 
						|
		Pwd = tdp->Password;
 | 
						|
		Catalog = tdp->Tabcat;
 | 
						|
		Srcdef = tdp->Srcdef;
 | 
						|
		Qrystr = tdp->Qrystr;
 | 
						|
		Sep = tdp->GetSep();
 | 
						|
		Options = tdp->Options;
 | 
						|
		Cto = tdp->Cto;
 | 
						|
		Qto = tdp->Qto;
 | 
						|
		Quoted = MY_MAX(0, tdp->GetQuoted());
 | 
						|
		Quote = tdp->GetQchar();
 | 
						|
		Rows = tdp->GetElemt();
 | 
						|
		Memory = tdp->Memory;
 | 
						|
		Scrollable = tdp->Scrollable;
 | 
						|
	} else {
 | 
						|
		TableName = NULL;
 | 
						|
		Schema = NULL;
 | 
						|
		User = NULL;
 | 
						|
		Pwd = NULL;
 | 
						|
		Catalog = NULL;
 | 
						|
		Srcdef = NULL;
 | 
						|
		Qrystr = NULL;
 | 
						|
		Sep = 0;
 | 
						|
		Options = 0;
 | 
						|
		Cto = 0;
 | 
						|
		Qto = 0;
 | 
						|
		Quoted = 0;
 | 
						|
		Quote = NULL;
 | 
						|
		Rows = 0;
 | 
						|
		Memory = 0;
 | 
						|
		Scrollable = false;
 | 
						|
	} // endif tdp
 | 
						|
 | 
						|
	Query = NULL;
 | 
						|
	Count = NULL;
 | 
						|
	//Where = NULL;
 | 
						|
	MulConn = NULL;
 | 
						|
	DBQ = NULL;
 | 
						|
	Qrp = NULL;
 | 
						|
	Fpos = 0;
 | 
						|
	Curpos = 0;
 | 
						|
	AftRows = 0;
 | 
						|
	CurNum = 0;
 | 
						|
	Rbuf = 0;
 | 
						|
	BufSize = 0;
 | 
						|
	Nparm = 0;
 | 
						|
	Ncol = 0;
 | 
						|
	Placed = false;
 | 
						|
} // end of TDBEXT constructor
 | 
						|
 | 
						|
TDBEXT::TDBEXT(PTDBEXT tdbp) : TDB(tdbp)
 | 
						|
{
 | 
						|
	Qrp = tdbp->Qrp;
 | 
						|
	TableName = tdbp->TableName;
 | 
						|
	Schema = tdbp->Schema;
 | 
						|
	User = tdbp->User;
 | 
						|
	Pwd = tdbp->Pwd;
 | 
						|
	Catalog = tdbp->Catalog;
 | 
						|
	Srcdef = tdbp->Srcdef;
 | 
						|
	Qrystr = tdbp->Qrystr;
 | 
						|
	Sep = tdbp->Sep;
 | 
						|
	Options = tdbp->Options;
 | 
						|
	Cto = tdbp->Cto;
 | 
						|
	Qto = tdbp->Qto;
 | 
						|
	Quoted = tdbp->Quoted;
 | 
						|
	Quote = tdbp->Quote;
 | 
						|
	Rows = tdbp->Rows;
 | 
						|
	Memory = tdbp->Memory;
 | 
						|
	Scrollable = tdbp->Scrollable;
 | 
						|
	Quote = tdbp->Quote;
 | 
						|
	Query = tdbp->Query;
 | 
						|
	Count = tdbp->Count;
 | 
						|
	//Where = tdbp->Where;
 | 
						|
	MulConn = tdbp->MulConn;
 | 
						|
	DBQ = tdbp->DBQ;
 | 
						|
	Fpos = 0;
 | 
						|
	Curpos = 0;
 | 
						|
	AftRows = 0;
 | 
						|
	CurNum = 0;
 | 
						|
	Rbuf = 0;
 | 
						|
	BufSize = tdbp->BufSize;
 | 
						|
	Nparm = tdbp->Nparm;
 | 
						|
	Ncol = tdbp->Ncol;
 | 
						|
	Placed = false;
 | 
						|
} // end of TDBEXT copy constructor
 | 
						|
 | 
						|
/******************************************************************/
 | 
						|
/*  Convert an UTF-8 string to latin characters.                  */
 | 
						|
/******************************************************************/
 | 
						|
int TDBEXT::Decode(PCSZ txt, char *buf, size_t n)
 | 
						|
{
 | 
						|
	uint   dummy_errors;
 | 
						|
	uint32 len = copy_and_convert(buf, n, &my_charset_latin1,
 | 
						|
		txt, strlen(txt),
 | 
						|
		&my_charset_utf8mb3_general_ci,
 | 
						|
		&dummy_errors);
 | 
						|
	buf[len] = '\0';
 | 
						|
	return 0;
 | 
						|
} // end of Decode
 | 
						|
 | 
						|
/*
 | 
						|
  Count number of %s placeholders in string.
 | 
						|
  Returns -1 if other sprintf placeholders are found, .g %d
 | 
						|
*/
 | 
						|
static int count_placeholders(const char *fmt)
 | 
						|
{
 | 
						|
  int cnt= 0;
 | 
						|
  for (const char *p=fmt; *p; p++)
 | 
						|
  {
 | 
						|
    if (*p == '%')
 | 
						|
    {
 | 
						|
      switch (p[1])
 | 
						|
      {
 | 
						|
      case 's':
 | 
						|
        /* %s found */
 | 
						|
        cnt++;
 | 
						|
        p++;
 | 
						|
        break;
 | 
						|
      case '%':
 | 
						|
        /* masking char for % found */
 | 
						|
        p++;
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        /* some other placeholder found */
 | 
						|
        return -1;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return cnt;
 | 
						|
}
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  MakeSrcdef: make the SQL statement from SRDEF option.              */
 | 
						|
/***********************************************************************/
 | 
						|
bool TDBEXT::MakeSrcdef(PGLOBAL g)
 | 
						|
{
 | 
						|
	char *catp = strstr(Srcdef, "%s");
 | 
						|
 | 
						|
	if (catp) {
 | 
						|
		char *fil1 = 0, *fil2 = 0;
 | 
						|
		PCSZ  ph = ((EXTDEF*)To_Def)->Phpos;
 | 
						|
 | 
						|
		if (!ph)
 | 
						|
			ph = (strstr(catp + 2, "%s")) ? "WH" : "W";
 | 
						|
 | 
						|
		if (stricmp(ph, "H")) {
 | 
						|
			fil1 = (To_CondFil && *To_CondFil->Body)
 | 
						|
				? To_CondFil->Body : PlugDup(g, "1=1");
 | 
						|
		} // endif ph
 | 
						|
 | 
						|
		if (stricmp(ph, "W")) {
 | 
						|
			fil2 = (To_CondFil && To_CondFil->Having && *To_CondFil->Having)
 | 
						|
				? To_CondFil->Having : PlugDup(g, "1=1");
 | 
						|
		} // endif ph
 | 
						|
 | 
						|
		int n_placeholders = count_placeholders(Srcdef);
 | 
						|
		if (n_placeholders < 0)
 | 
						|
		{
 | 
						|
			safe_strcpy(g->Message, sizeof(g->Message), "MakeSQL: Wrong place holders specification");
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		if (!stricmp(ph, "W") && n_placeholders <= 1) {
 | 
						|
			Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1));
 | 
						|
			Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1));
 | 
						|
		}
 | 
						|
		else if (!stricmp(ph, "WH") && n_placeholders <= 2)
 | 
						|
		{
 | 
						|
			Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
 | 
						|
			Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1, fil2));
 | 
						|
		}
 | 
						|
		else if (!stricmp(ph, "H") && n_placeholders <= 1)
 | 
						|
		{
 | 
						|
			Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil2));
 | 
						|
			Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2));
 | 
						|
		}
 | 
						|
		else if (!stricmp(ph, "HW") && n_placeholders <= 2)
 | 
						|
		{
 | 
						|
			Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
 | 
						|
			Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2, fil1));
 | 
						|
		} else {
 | 
						|
			safe_strcpy(g->Message, sizeof(g->Message), "MakeSQL: Wrong place holders specification");
 | 
						|
			return true;
 | 
						|
		} // endif's ph
 | 
						|
 | 
						|
	} else
 | 
						|
		Query = new(g)STRING(g, 0, Srcdef);
 | 
						|
 | 
						|
	return false;
 | 
						|
} // end of MakeSrcdef
 | 
						|
 | 
						|
	/***********************************************************************/
 | 
						|
	/*  MakeSQL: make the SQL statement use with remote connection.        */
 | 
						|
	/*  TODO: when implementing remote filtering, column only used in      */
 | 
						|
	/*  local filter should be removed from column list.                   */
 | 
						|
	/***********************************************************************/
 | 
						|
bool TDBEXT::MakeSQL(PGLOBAL g, bool cnt)
 | 
						|
{
 | 
						|
	PCSZ   schmp = NULL;
 | 
						|
	char  *catp = NULL, buf[NAM_LEN * 3];
 | 
						|
	int    len;
 | 
						|
	bool   first = true;
 | 
						|
	PCOL   colp;
 | 
						|
	char *res= NULL, *my_schema_table= NULL;
 | 
						|
	size_t my_len= 0;
 | 
						|
 | 
						|
	if (Srcdef)
 | 
						|
		return MakeSrcdef(g);
 | 
						|
 | 
						|
	// Allocate the string used to contain the Query
 | 
						|
	Query = new(g)STRING(g, 1023, "SELECT ");
 | 
						|
 | 
						|
	if (!cnt) {
 | 
						|
		if (Columns) {
 | 
						|
			// Normal SQL statement to retrieve results
 | 
						|
			for (colp = Columns; colp; colp = colp->GetNext())
 | 
						|
				if (!colp->IsSpecial()) {
 | 
						|
					if (!first)
 | 
						|
						Query->Append(", ");
 | 
						|
					else
 | 
						|
						first = false;
 | 
						|
 | 
						|
					// Column name can be encoded in UTF-8
 | 
						|
					Decode(colp->GetName(), buf, sizeof(buf));
 | 
						|
 | 
						|
					if (Quote) {
 | 
						|
						// Put column name between identifier quotes in case in contains blanks
 | 
						|
						Query->Append(Quote);
 | 
						|
						Query->Append(buf);
 | 
						|
						Query->Append(Quote);
 | 
						|
					} else
 | 
						|
						Query->Append(buf);
 | 
						|
 | 
						|
					((PEXTCOL)colp)->SetRank(++Ncol);
 | 
						|
				} // endif colp
 | 
						|
 | 
						|
		} else
 | 
						|
			// !Columns can occur for queries such that sql count(*) from...
 | 
						|
			// for which we will count the rows from sql * from...
 | 
						|
			Query->Append('*');
 | 
						|
 | 
						|
	} else
 | 
						|
		// SQL statement used to retrieve the size of the result
 | 
						|
		Query->Append("count(*)");
 | 
						|
 | 
						|
	Query->Append(" FROM ");
 | 
						|
 | 
						|
	if (Catalog && *Catalog)
 | 
						|
		catp = Catalog;
 | 
						|
 | 
						|
	//if (tablep->GetSchema())
 | 
						|
	//	schmp = (char*)tablep->GetSchema();
 | 
						|
	//else 
 | 
						|
	if (Schema && *Schema)
 | 
						|
		schmp = Schema;
 | 
						|
 | 
						|
	if (catp) {
 | 
						|
		Query->Append(catp);
 | 
						|
 | 
						|
		if (schmp) {
 | 
						|
			Query->Append('.');
 | 
						|
			Query->Append(schmp);
 | 
						|
		} // endif schmp
 | 
						|
 | 
						|
		Query->Append('.');
 | 
						|
	} else if (schmp) {
 | 
						|
		Query->Append(schmp);
 | 
						|
		Query->Append('.');
 | 
						|
	} // endif schmp
 | 
						|
 | 
						|
	// Table name can be encoded in UTF-8
 | 
						|
	Decode(TableName, buf, sizeof(buf));
 | 
						|
 | 
						|
	if (Quote) {
 | 
						|
		// Tabname can have both database and table identifiers, we need to parse
 | 
						|
		if ((res= strstr(buf, ".")))
 | 
						|
		{
 | 
						|
			// Parse schema
 | 
						|
			my_len= res - buf + 1;
 | 
						|
			my_schema_table= (char *) malloc(my_len);
 | 
						|
			memcpy(my_schema_table, buf, my_len - 1);
 | 
						|
			my_schema_table[my_len - 1] = 0;
 | 
						|
			Query->Append(Quote);
 | 
						|
			Query->Append(my_schema_table);
 | 
						|
			Query->Append(Quote);
 | 
						|
			free(my_schema_table);
 | 
						|
			Query->Append(".");
 | 
						|
			// Parse table
 | 
						|
			my_len= strlen(buf) - my_len + 1;
 | 
						|
			my_schema_table= (char *) malloc(my_len + 1);
 | 
						|
			memcpy(my_schema_table, ++res, my_len);
 | 
						|
			my_schema_table[my_len] = 0;
 | 
						|
			Query->Append(Quote);
 | 
						|
			Query->Append(my_schema_table);
 | 
						|
			Query->Append(Quote);
 | 
						|
			free(my_schema_table);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			// Put table name between identifier quotes in case in contains blanks
 | 
						|
			Query->Append(Quote);
 | 
						|
			Query->Append(buf);
 | 
						|
			Query->Append(Quote);
 | 
						|
		}
 | 
						|
 | 
						|
	} else
 | 
						|
		Query->Append(buf);
 | 
						|
 | 
						|
	len = Query->GetLength();
 | 
						|
 | 
						|
	if (To_CondFil) {
 | 
						|
		if (Mode == MODE_READ) {
 | 
						|
			Query->Append(" WHERE ");
 | 
						|
			Query->Append(To_CondFil->Body);
 | 
						|
			len = Query->GetLength() + 1;
 | 
						|
		} else
 | 
						|
			len += (strlen(To_CondFil->Body) + 256);
 | 
						|
 | 
						|
	} else
 | 
						|
		len += ((Mode == MODE_READX) ? 256 : 1);
 | 
						|
 | 
						|
	if (Query->IsTruncated()) {
 | 
						|
		safe_strcpy(g->Message, sizeof(g->Message), "MakeSQL: Out of memory");
 | 
						|
		return true;
 | 
						|
	} else
 | 
						|
		Query->Resize(len);
 | 
						|
 | 
						|
	if (trace(33))
 | 
						|
		htrc("Query=%s\n", Query->GetStr());
 | 
						|
 | 
						|
	return false;
 | 
						|
} // end of MakeSQL
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Remove the NAME_CONST functions that are added by procedures.      */
 | 
						|
/***********************************************************************/
 | 
						|
void TDBEXT::RemoveConst(PGLOBAL g, char *stmt)
 | 
						|
{
 | 
						|
	char *p, *p2;
 | 
						|
	char  val[1025], nval[1025];
 | 
						|
	int   n, nc;
 | 
						|
 | 
						|
	while ((p = strstr(stmt, "NAME_CONST")))
 | 
						|
        {
 | 
						|
		if ((n = sscanf(p, "%*[^,],%1024[^)])%n", val, &nc))) {
 | 
						|
			if (trace(33))
 | 
						|
				htrc("p=%s\nn=%d val=%s nc=%d\n", p, n, val, nc);
 | 
						|
 | 
						|
			*p = 0;
 | 
						|
 | 
						|
			if ((p2 = strstr(val, "'"))) {
 | 
						|
				if ((n = sscanf(p2, "%*['\\]%1024[^'\\]", nval))) {
 | 
						|
					if (trace(33))
 | 
						|
						htrc("p2=%s\nn=%d nval=%s\n", p2, n, nval);
 | 
						|
 | 
						|
					strcat(strcat(strcat(strcat(stmt, "'"), nval), "'"), p + nc);
 | 
						|
				} else
 | 
						|
					break;
 | 
						|
 | 
						|
			} else
 | 
						|
				strcat(strcat(strcat(strcat(stmt, "("), val), ")"), p + nc);
 | 
						|
 | 
						|
			if (trace(33))
 | 
						|
				htrc("stmt=%s\n", stmt);
 | 
						|
 | 
						|
		} else
 | 
						|
			break;
 | 
						|
        }
 | 
						|
	return;
 | 
						|
} // end of RemoveConst
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  MakeCommand: make the Update or Delete statement to send to the    */
 | 
						|
/*  MySQL server. Limited to remote values and filtering.              */
 | 
						|
/***********************************************************************/
 | 
						|
bool TDBEXT::MakeCommand(PGLOBAL g)
 | 
						|
{
 | 
						|
	PCSZ  schmp = NULL;
 | 
						|
	char *p, *stmt, name[132], *body = NULL;
 | 
						|
	char *qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1);
 | 
						|
	bool  qtd = Quoted > 0;
 | 
						|
	char  q = qtd ? *Quote : ' ';
 | 
						|
	int   i = 0, k = 0;
 | 
						|
	size_t stmt_sz = 0;
 | 
						|
 | 
						|
	// Make a lower case copy of the originale query and change
 | 
						|
	// back ticks to the data source identifier quoting character
 | 
						|
	do {
 | 
						|
		qrystr[i] = (Qrystr[i] == '`') ? q : tolower(Qrystr[i]);
 | 
						|
	} while (Qrystr[i++]);
 | 
						|
 | 
						|
	if (To_CondFil && (p = strstr(qrystr, " where "))) {
 | 
						|
		p[7] = 0;           // Remove where clause
 | 
						|
		Qrystr[(p - qrystr) + 7] = 0;
 | 
						|
		body = To_CondFil->Body;
 | 
						|
		stmt_sz = strlen(qrystr) + strlen(body) + 64;
 | 
						|
	} else
 | 
						|
		stmt_sz = strlen(Qrystr) + 64;
 | 
						|
	stmt = (char*)PlugSubAlloc(g, NULL, stmt_sz);
 | 
						|
 | 
						|
	// Check whether the table name is equal to a keyword
 | 
						|
	// If so, it must be quoted in the original query
 | 
						|
	snprintf(name, sizeof(name), " %s ", Name);
 | 
						|
	strlwr(name);
 | 
						|
 | 
						|
	if (strstr(" update delete low_priority ignore quick from ", name)) {
 | 
						|
		if (Quote) {
 | 
						|
			snprintf(name, sizeof(name), "%s%s%s", Quote, Name, Quote);
 | 
						|
			strlwr(name);
 | 
						|
			k += 2;
 | 
						|
		} else {
 | 
						|
			safe_strcpy(g->Message, sizeof(g->Message), "Quoted must be specified");
 | 
						|
			return true;
 | 
						|
		}	// endif Quote
 | 
						|
 | 
						|
	} else {
 | 
						|
		safe_strcpy(name, sizeof(name), Name);     // Not a keyword
 | 
						|
		strlwr(name);
 | 
						|
	}
 | 
						|
 | 
						|
	if ((p = strstr(qrystr, name))) {
 | 
						|
		for (i = 0; i < p - qrystr; i++)
 | 
						|
			stmt[i] = (Qrystr[i] == '`') ? q : Qrystr[i];
 | 
						|
 | 
						|
		stmt[i] = 0;
 | 
						|
 | 
						|
		k += i + (int)strlen(Name);
 | 
						|
 | 
						|
		if (Schema && *Schema)
 | 
						|
			schmp = Schema;
 | 
						|
 | 
						|
		if (qtd && *(p - 1) == ' ') {
 | 
						|
			if (schmp) {
 | 
						|
				safe_strcat(stmt, stmt_sz, schmp);
 | 
						|
				safe_strcat(stmt, stmt_sz, ".");
 | 
						|
			}
 | 
						|
 | 
						|
			safe_strcat(stmt, stmt_sz, Quote);
 | 
						|
			safe_strcat(stmt, stmt_sz, TableName);
 | 
						|
			safe_strcat(stmt, stmt_sz, Quote);
 | 
						|
		} else {
 | 
						|
			if (schmp) {
 | 
						|
				if (qtd && *(p - 1) != ' ') {
 | 
						|
					stmt[i - 1] = 0;
 | 
						|
					safe_strcat(stmt, stmt_sz, schmp);
 | 
						|
					safe_strcat(stmt, stmt_sz, ".");
 | 
						|
					safe_strcat(stmt, stmt_sz, Quote);
 | 
						|
				} else {
 | 
						|
					safe_strcat(stmt, stmt_sz, schmp);
 | 
						|
					safe_strcat(stmt, stmt_sz, ".");
 | 
						|
				}
 | 
						|
 | 
						|
			}	// endif schmp
 | 
						|
 | 
						|
			safe_strcat(stmt, stmt_sz, TableName);
 | 
						|
		} // endif's
 | 
						|
 | 
						|
		i = (int)strlen(stmt);
 | 
						|
 | 
						|
		do {
 | 
						|
			stmt[i++] = (Qrystr[k] == '`') ? q : Qrystr[k];
 | 
						|
		} while (Qrystr[k++]);
 | 
						|
 | 
						|
		RemoveConst(g, stmt);
 | 
						|
 | 
						|
		if (body)
 | 
						|
			safe_strcat(stmt, stmt_sz, body);
 | 
						|
 | 
						|
	} else {
 | 
						|
		snprintf(g->Message, sizeof(g->Message), "Cannot use this %s command",
 | 
						|
			(Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
 | 
						|
		return true;
 | 
						|
	} // endif p
 | 
						|
 | 
						|
	if (trace(33))
 | 
						|
		htrc("Command=%s\n", stmt);
 | 
						|
 | 
						|
	Query = new(g)STRING(g, 0, stmt);
 | 
						|
	return (!Query->GetSize());
 | 
						|
} // end of MakeCommand
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  GetRecpos: return the position of last read record.                */
 | 
						|
/***********************************************************************/
 | 
						|
int TDBEXT::GetRecpos(void)
 | 
						|
{
 | 
						|
	return Fpos;
 | 
						|
} // end of GetRecpos
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  ODBC GetMaxSize: returns table size estimate in number of lines.   */
 | 
						|
/***********************************************************************/
 | 
						|
int TDBEXT::GetMaxSize(PGLOBAL g)
 | 
						|
{
 | 
						|
	if (MaxSize < 0) {
 | 
						|
		if (Mode == MODE_DELETE)
 | 
						|
			// Return 0 in mode DELETE in case of delete all.
 | 
						|
			MaxSize = 0;
 | 
						|
		else if (!Cardinality(NULL))
 | 
						|
			MaxSize = 10;   // To make MySQL happy
 | 
						|
		else if ((MaxSize = Cardinality(g)) < 0)
 | 
						|
			MaxSize = 12;   // So we can see an error occurred
 | 
						|
 | 
						|
	} // endif MaxSize
 | 
						|
 | 
						|
	return MaxSize;
 | 
						|
} // end of GetMaxSize
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Return max size value.                                             */
 | 
						|
/***********************************************************************/
 | 
						|
int TDBEXT::GetProgMax(PGLOBAL g)
 | 
						|
{
 | 
						|
	return GetMaxSize(g);
 | 
						|
} // end of GetProgMax
 | 
						|
 | 
						|
/* ---------------------------EXTCOL class --------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  EXTCOL public constructor.                                         */
 | 
						|
/***********************************************************************/
 | 
						|
EXTCOL::EXTCOL(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
 | 
						|
 | 
						|
	if (trace(1))
 | 
						|
		htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
 | 
						|
 | 
						|
	// Set additional remote access method information for column.
 | 
						|
	Crp = NULL;
 | 
						|
	Long = Precision;
 | 
						|
	To_Val = NULL;
 | 
						|
	Bufp = NULL;
 | 
						|
	Blkp = NULL;
 | 
						|
	Rank = 0;           // Not known yet
 | 
						|
} // end of JDBCCOL constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  EXTCOL private constructor.                                        */
 | 
						|
/***********************************************************************/
 | 
						|
EXTCOL::EXTCOL(void) : COLBLK()
 | 
						|
{
 | 
						|
	Crp = NULL;
 | 
						|
	Buf_Type = TYPE_INT;     // This is a count(*) column
 | 
						|
 | 
						|
	// Set additional Dos access method information for column.
 | 
						|
	Long = sizeof(int);
 | 
						|
	To_Val = NULL;
 | 
						|
	Bufp = NULL;
 | 
						|
	Blkp = NULL;
 | 
						|
	Rank = 1;
 | 
						|
} // end of EXTCOL constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  EXTCOL constructor used for copying columns.                       */
 | 
						|
/*  tdbp is the pointer to the new table descriptor.                   */
 | 
						|
/***********************************************************************/
 | 
						|
EXTCOL::EXTCOL(PEXTCOL col1, PTDB tdbp) : COLBLK(col1, tdbp)
 | 
						|
{
 | 
						|
	Crp = col1->Crp;
 | 
						|
	Long = col1->Long;
 | 
						|
	To_Val = col1->To_Val;
 | 
						|
	Bufp = col1->Bufp;
 | 
						|
	Blkp = col1->Blkp;
 | 
						|
	Rank = col1->Rank;
 | 
						|
} // end of JDBCCOL copy constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  SetBuffer: prepare a column block for write operation.             */
 | 
						|
/***********************************************************************/
 | 
						|
bool EXTCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
 | 
						|
{
 | 
						|
	if (!(To_Val = value)) {
 | 
						|
		snprintf(g->Message, sizeof(g->Message), MSG(VALUE_ERROR), Name);
 | 
						|
		return true;
 | 
						|
	} else if (Buf_Type == value->GetType()) {
 | 
						|
		// Values are of the (good) column type
 | 
						|
		if (Buf_Type == TYPE_DATE) {
 | 
						|
			// If any of the date values is formatted
 | 
						|
			// output format must be set for the receiving table
 | 
						|
			if (GetDomain() || ((DTVAL *)value)->IsFormatted())
 | 
						|
				goto newval;          // This will make a new value;
 | 
						|
 | 
						|
		} else if (Buf_Type == TYPE_DOUBLE)
 | 
						|
			// Float values must be written with the correct (column) precision
 | 
						|
			// Note: maybe this should be forced by ShowValue instead of this ?
 | 
						|
			value->SetPrec(GetScale());
 | 
						|
 | 
						|
		Value = value;            // Directly access the external value
 | 
						|
	} else {
 | 
						|
		// Values are not of the (good) column type
 | 
						|
		if (check) {
 | 
						|
			snprintf(g->Message, sizeof(g->Message), MSG(TYPE_VALUE_ERR), Name,
 | 
						|
				GetTypeName(Buf_Type), GetTypeName(value->GetType()));
 | 
						|
			return true;
 | 
						|
		} // endif check
 | 
						|
 | 
						|
	newval:
 | 
						|
		if (InitValue(g))         // Allocate the matching value block
 | 
						|
			return true;
 | 
						|
 | 
						|
	} // endif's Value, Buf_Type
 | 
						|
 | 
						|
	// Because Colblk's have been made from a copy of the original TDB in
 | 
						|
	// case of Update, we must reset them to point to the original one.
 | 
						|
	if (To_Tdb->GetOrig())
 | 
						|
		To_Tdb = (PTDB)To_Tdb->GetOrig();
 | 
						|
 | 
						|
	// Set the Column
 | 
						|
	Status = (ok) ? BUF_EMPTY : BUF_NO;
 | 
						|
	return false;
 | 
						|
} // end of SetBuffer
 | 
						|
 |