mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
740d3e7a74
- 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
|
|
|