mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
e049f92392
commit ac275d0b4ad (connect/10.0) Author: Olivier Bertrand <bertrandop@gmail.com> Date: Wed Mar 27 12:46:20 2019 +0100 Comment out unrecognized command line options: Modified CMakeLists.txt commit 592f1f75ad6 Author: Olivier Bertrand <bertrandop@gmail.com> Date: Tue Mar 26 19:52:33 2019 +0100 Replace Command not recognized by CMake modified: CMakeLists.txt commit 00f72199b16 Author: Olivier Bertrand <bertrandop@gmail.com> Date: Tue Mar 26 18:15:08 2019 +0100 - Fix MDEV-15793: Server crash in PlugCloseFile with sql_mode='' Fixed by replacing sprinf by snprintf in ShowValue to avoid buffer overflow. It nows always use a buffer and returns int. modified: storage/connect/tabdos.cpp modified: storage/connect/tabfmt.cpp modified: storage/connect/value.cpp modified: storage/connect/value.h - Fix MDEV-18292: CONNECT Engine JDBC not able to issue simple UPDATE statement from trigger or stored procedure Was not fixed when the same table was called several times with different modes. Fixed by checking if a new statement is compatible in the start_stmt function. It nows do the same checks than external_lock. modified: storage/connect/ha_connect.cc modified: storage/connect/ha_connect.h - typo modified: storage/connect/user_connect.cc - Fix GetTableName that returned wrong value under Windows modified: storage/connect/ha_connect.cc - Fix MDEV-13136: enhance CREATE SERVER MyServerName FOREIGN DATA WRAPPER to work with CONNECT engine modified: storage/connect/tabjdbc.cpp - Add a function to retrieve User variable value (DEVELOPMENT only) modified: storage/connect/ha_connect.cc modified: storage/connect/jsonudf.cpp modified: storage/connect/jsonudf.h modified: storage/connect/tabjdbc.cpp - Fix MDEV-18192: CONNECT Engine JDBC not able to issue simple UPDATE statement from trigger or stored procedure modified: storage/connect/tabext.cpp modified: storage/connect/tabext.h modified: storage/connect/tabjdbc.cpp - Enable CONNECT tables to have triggers Update version number modified: storage/connect/ha_connect.cc - Make user and password defined in CREATE TABLE have precedence on the ones specified in a Federated Server. modified: storage/connect/tabjdbc.cpp - JSONColumns: Copy locally constant strings to fix error in OEM modules modified: storage/connect/tabjson.cpp commit 99de7f4e486 Author: Olivier Bertrand <bertrandop@gmail.com> Date: Sun Jan 27 15:16:15 2019 +0100 - Fix MDEV-18192: CONNECT Engine JDBC not able to issue simple UPDATE statement from trigger or stored procedure modified: storage/connect/tabext.cpp modified: storage/connect/tabext.h modified: storage/connect/tabjdbc.cpp - Enable CONNECT tables to have triggers Update version number modified: storage/connect/ha_connect.cc - Make user and password defined in CREATE TABLE have precedence on the ones specified in a Federated Server. modified: storage/connect/tabjdbc.cpp - JSONColumns: Copy locally constant strings to fix error in OEM modules modified: storage/connect/tabjson.cpp
720 lines
20 KiB
C++
720 lines
20 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(__WIN__)
|
|
#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, '='))) {
|
|
strcpy(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) {
|
|
strcpy(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);
|
|
|
|
if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL)))
|
|
Read_Only = true;
|
|
|
|
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);
|
|
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);
|
|
|
|
// Memory was Boolean, it is now integer
|
|
if (!(Memory = GetIntCatInfo("Memory", 0)))
|
|
Memory = GetBoolCatInfo("Memory", false) ? 1 : 0;
|
|
|
|
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());
|
|
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;
|
|
Rows = 0;
|
|
Memory = 0;
|
|
Scrollable = false;
|
|
} // endif tdp
|
|
|
|
Quote = NULL;
|
|
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;
|
|
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_utf8_general_ci,
|
|
&dummy_errors);
|
|
buf[len] = '\0';
|
|
return 0;
|
|
} // end of Decode
|
|
|
|
/***********************************************************************/
|
|
/* MakeSrcdef: make the SQL statement from SRDEF option. */
|
|
/***********************************************************************/
|
|
bool TDBEXT::MakeSrcdef(PGLOBAL g)
|
|
{
|
|
char *catp = strstr(Srcdef, "%s");
|
|
|
|
if (catp) {
|
|
char *fil1 = 0, *fil2;
|
|
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
|
|
|
|
if (!stricmp(ph, "W")) {
|
|
Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1));
|
|
Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1));
|
|
} else if (!stricmp(ph, "WH")) {
|
|
Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
|
|
Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1, fil2));
|
|
} else if (!stricmp(ph, "H")) {
|
|
Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil2));
|
|
Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2));
|
|
} else if (!stricmp(ph, "HW")) {
|
|
Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
|
|
Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2, fil1));
|
|
} else {
|
|
strcpy(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;
|
|
PTABLE tablep = To_Table;
|
|
PCOL colp;
|
|
|
|
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) {
|
|
// 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()) {
|
|
strcpy(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;
|
|
|
|
// 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 = (char*)PlugSubAlloc(g, NULL, strlen(qrystr)
|
|
+ strlen(body) + 64);
|
|
} else
|
|
stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
|
|
|
|
// Check whether the table name is equal to a keyword
|
|
// If so, it must be quoted in the original query
|
|
strlwr(strcat(strcat(strcpy(name, " "), Name), " "));
|
|
|
|
if (strstr(" update delete low_priority ignore quick from ", name)) {
|
|
if (Quote) {
|
|
strlwr(strcat(strcat(strcpy(name, Quote), Name), Quote));
|
|
k += 2;
|
|
} else {
|
|
strcpy(g->Message, "Quoted must be specified");
|
|
return true;
|
|
} // endif Quote
|
|
|
|
} else
|
|
strlwr(strcpy(name, Name)); // Not a keyword
|
|
|
|
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)
|
|
strcat(strcat(stmt, schmp), ".");
|
|
|
|
strcat(strcat(strcat(stmt, Quote), TableName), Quote);
|
|
} else {
|
|
if (schmp) {
|
|
if (qtd && *(p - 1) != ' ') {
|
|
stmt[i - 1] = 0;
|
|
strcat(strcat(strcat(stmt, schmp), "."), Quote);
|
|
} else
|
|
strcat(strcat(stmt, schmp), ".");
|
|
|
|
} // endif schmp
|
|
|
|
strcat(stmt, TableName);
|
|
} // endif's
|
|
|
|
i = (int)strlen(stmt);
|
|
|
|
do {
|
|
stmt[i++] = (Qrystr[k] == '`') ? q : Qrystr[k];
|
|
} while (Qrystr[k++]);
|
|
|
|
RemoveConst(g, stmt);
|
|
|
|
if (body)
|
|
strcat(stmt, body);
|
|
|
|
} else {
|
|
sprintf(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)) {
|
|
sprintf(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) {
|
|
sprintf(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
|
|
|