1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

- Add (limited) support for UPDATE and DELETE to ODBC tables

(also provide the possibility to issue NOTE warnings)

modified:
  storage/connect/connect.cc
  storage/connect/ha_connect.cc
  storage/connect/ha_connect.h
  storage/connect/odbconn.cpp
  storage/connect/odbconn.h
  storage/connect/plgdbsem.h
  storage/connect/tabodbc.cpp
  storage/connect/tabodbc.h

- Return proper error number when modifying read only tables

modified:
  storage/connect/connect.cc
  storage/connect/ha_connect.cc
  storage/connect/ha_connect.h
  storage/connect/mysql-test/connect/r/bin.result
  storage/connect/mysql-test/connect/r/csv.result
  storage/connect/mysql-test/connect/r/dbf.result
  storage/connect/mysql-test/connect/r/fix.result
  storage/connect/mysql-test/connect/r/ini.result
  storage/connect/mysql-test/connect/r/vec.result
  storage/connect/mysql-test/connect/t/bin.test
  storage/connect/mysql-test/connect/t/csv.test
  storage/connect/mysql-test/connect/t/dbf.test
  storage/connect/mysql-test/connect/t/fix.test
  storage/connect/mysql-test/connect/t/ini.test
  storage/connect/mysql-test/connect/t/vec.test
  storage/connect/table.cpp
  storage/connect/taboccur.cpp
  storage/connect/tabpivot.cpp
  storage/connect/tabutil.cpp
  storage/connect/tabwmi.cpp
  storage/connect/tabxcl.cpp
This commit is contained in:
Olivier Bertrand
2013-11-11 13:00:39 +01:00
parent e5c589a8da
commit eca84a9b18
26 changed files with 1314 additions and 1251 deletions

View File

@@ -90,8 +90,8 @@ extern int num_read, num_there, num_eq[2]; // Statistics
/***********************************************************************/
ODBCDEF::ODBCDEF(void)
{
Connect = Tabname = Tabowner = Tabqual = Srcdef = Qchar = Qrystr = NULL;
Catver = Options = 0;
Connect = Tabname = Tabowner = Tabqual = Srcdef = Qrystr = NULL;
Catver = Options = Quoted = 0;
Xsrc = false;
} // end of ODBCDEF constructor
@@ -107,11 +107,11 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Tabowner = Cat->GetStringCatInfo(g, "Owner", "");
Tabqual = Cat->GetStringCatInfo(g, "Qualifier", "");
Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL);
Qchar = Cat->GetStringCatInfo(g, "Qchar", "");
Qrystr = Cat->GetStringCatInfo(g, "Query_String", "?");
Catver = Cat->GetIntCatInfo("Catver", 2);
Xsrc = Cat->GetBoolCatInfo("Execsrc", FALSE);
Mxr = Cat->GetIntCatInfo("Maxerr", 0);
Quoted = Cat->GetIntCatInfo("Quoted", 0);
Options = ODBConn::noOdbcDialog;
Pseudo = 2; // FILID is Ok but not ROWID
return false;
@@ -171,9 +171,9 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
Owner = tdp->Tabowner;
Qualifier = tdp->Tabqual;
Srcdef = tdp->Srcdef;
Quote = tdp->GetQchar();
Qrystr = tdp->Qrystr;
Options = tdp->Options;
Quoted = max(0, tdp->GetQuoted());
Rows = tdp->GetElemt();
Catver = tdp->Catver;
} else {
@@ -182,13 +182,14 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
Owner = NULL;
Qualifier = NULL;
Srcdef = NULL;
Quote = NULL;
Qrystr = NULL;
Options = 0;
Quoted = 0;
Rows = 0;
Catver = 0;
} // endif tdp
Quote = NULL;
Query = NULL;
Count = NULL;
//Where = NULL;
@@ -211,14 +212,15 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
Owner = tdbp->Owner;
Qualifier = tdbp->Qualifier;
Srcdef = tdbp->Srcdef;
Quote = tdbp->Quote;
Qrystr = tdbp->Qrystr;
Quote = tdbp->Quote;
Query = tdbp->Query;
Count = tdbp->Count;
//Where = tdbp->Where;
MulConn = tdbp->MulConn;
DBQ = tdbp->DBQ;
Options = tdbp->Options;
Quoted = tdbp->Quoted;
Rows = tdbp->Rows;
Fpos = tdbp->Fpos;
AftRows = tdbp->AftRows;
@@ -445,21 +447,18 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
/***********************************************************************/
/* MakeInsert: make the Insert statement used with ODBC connection. */
/***********************************************************************/
bool TDBODBC::MakeInsert(PGLOBAL g)
char *TDBODBC::MakeInsert(PGLOBAL g)
{
char *colist, *valist;
char *stmt, *colist, *valist;
// char *tk = "`";
int len = 0;
bool b = FALSE;
PCOL colp;
if (Query)
return false; // already done
for (colp = Columns; colp; colp = colp->GetNext())
if (colp->IsSpecial()) {
strcpy(g->Message, MSG(NO_ODBC_SPECOL));
return true;
return NULL;
} else {
len += (strlen(colp->GetName()) + 4);
((PODBCCOL)colp)->Rank = ++Nparm;
@@ -487,18 +486,18 @@ bool TDBODBC::MakeInsert(PGLOBAL g)
// Below 32 is enough to contain the fixed part of the query
len = (strlen(TableName) + strlen(colist) + strlen(valist) + 32);
Query = (char*)PlugSubAlloc(g, NULL, len);
strcpy(Query, "INSERT INTO ");
stmt = (char*)PlugSubAlloc(g, NULL, len);
strcpy(stmt, "INSERT INTO ");
if (Quote)
strcat(strcat(strcat(Query, Quote), TableName), Quote);
strcat(strcat(strcat(stmt, Quote), TableName), Quote);
else
strcat(Query, TableName);
strcat(stmt, TableName);
strcat(strcat(strcat(Query, " ("), colist), ") VALUES (");
strcat(strcat(Query, valist), ")");
strcat(strcat(strcat(stmt, " ("), colist), ") VALUES (");
strcat(strcat(stmt, valist), ")");
return false;
return stmt;
} // end of MakeInsert
/***********************************************************************/
@@ -520,27 +519,58 @@ bool TDBODBC::BindParameters(PGLOBAL g)
} // end of BindParameters
/***********************************************************************/
/* MakeCMD: make the SQL statement to send to ODBC connection. */
/* MakeUpdate: make the SQL statement to send to ODBC connection. */
/***********************************************************************/
char *TDBODBC::MakeStmt(PGLOBAL g)
char *TDBODBC::MakeUpdate(PGLOBAL g)
{
char *qc, *stmt = NULL, cmd[8], tab[96], end[512];
int n = (Mode == MODE_DELETE) ? 1 : 2;
char *qc, *stmt = NULL, cmd[8], tab[96], end[1024];
stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
*end = 0;
qc = (Quote) ? Quote : "\"";
memset(end, 0, sizeof(end));
if (sscanf(Qrystr, "%s `%[^`]`%511c", cmd, tab, end) > n ||
sscanf(Qrystr, "%s \"%[^\"]\"%511c", cmd, tab, end) > n ||
sscanf(Qrystr, "%s %s%511c", cmd, tab, end) > n)
strcat(strcat(strcpy(tab, qc), TableName), qc);
if (sscanf(Qrystr, "%s `%[^`]`%1023c", cmd, tab, end) > 2 ||
sscanf(Qrystr, "%s \"%[^\"]\"%1023c", cmd, tab, end) > 2)
qc = Ocp->GetQuoteChar();
else if (sscanf(Qrystr, "%s %s%1023c", cmd, tab, end) > 2)
qc = (Quoted) ? Quote : "";
else {
strcpy(g->Message, "Cannot use this UPDATE/DELETE command");
strcpy(g->Message, "Cannot use this UPDATE command");
return NULL;
} // endif sscanf
strcat(strcat(strcpy(stmt, cmd), " "), tab);
assert(!stricmp(cmd, "update"));
strcat(strcat(strcat(strcpy(stmt, "UPDATE "), qc), TableName), qc);
for (int i = 0; end[i]; i++)
if (end[i] == '`')
end[i] = *qc;
strcat(stmt, end);
return stmt;
} // end of MakeUpdate
/***********************************************************************/
/* MakeDelete: make the SQL statement to send to ODBC connection. */
/***********************************************************************/
char *TDBODBC::MakeDelete(PGLOBAL g)
{
char *qc, *stmt = NULL, cmd[8], from[8], tab[96], end[512];
stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
memset(end, 0, sizeof(end));
if (sscanf(Qrystr, "%s %s `%[^`]`%511c", cmd, from, tab, end) > 2 ||
sscanf(Qrystr, "%s %s \"%[^\"]\"%511c", cmd, from, tab, end) > 2)
qc = Ocp->GetQuoteChar();
else if (sscanf(Qrystr, "%s %s %s%511c", cmd, from, tab, end) > 2)
qc = (Quoted) ? Quote : "";
else {
strcpy(g->Message, "Cannot use this DELETE command");
return NULL;
} // endif sscanf
assert(!stricmp(cmd, "delete") && !stricmp(from, "from"));
strcat(strcat(strcat(strcpy(stmt, "DELETE FROM "), qc), TableName), qc);
if (*end) {
for (int i = 0; end[i]; i++)
@@ -551,7 +581,7 @@ char *TDBODBC::MakeStmt(PGLOBAL g)
} // endif end
return stmt;
} // end of MakeStmt
} // end of MakeDelete
/***********************************************************************/
/* ResetSize: call by TDBMUL when calculating size estimate. */
@@ -572,7 +602,7 @@ int TDBODBC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
// Make MariaDB happy
MaxSize = 100;
MaxSize = (Mode == MODE_READ) ? 100 : 0;
#if 0
// This is unuseful and takes time
if (Srcdef) {
@@ -655,51 +685,42 @@ bool TDBODBC::OpenDB(PGLOBAL g)
if (Ocp->Open(Connect, Options) < 1)
return true;
else if (Quoted)
Quote = Ocp->GetQuoteChar();
Use = USE_OPEN; // Do it now in case we are recursively called
/*********************************************************************/
/* Allocate whatever is used for getting results. */
/* Make the command and allocate whatever is used for getting results. */
/*********************************************************************/
if (Mode == MODE_READ) {
/*******************************************************************/
/* The issue here is that if max result size is needed, it must be */
/* calculated before the result set for the final data retrieval is*/
/* allocated and the final statement prepared so we call GetMaxSize*/
/* here. It can be a waste of time if the max size is not needed */
/* but currently we always are asking for it (for progress info). */
/*******************************************************************/
GetMaxSize(g); // Will be set for next call
if ((Query = MakeSQL(g, false))) {
for (PODBCCOL colp = (PODBCCOL)Columns; colp;
colp = (PODBCCOL)colp->GetNext())
if (!colp->IsSpecial())
colp->AllocateBuffers(g, Rows);
if (!Query)
if ((Query = MakeSQL(g, false))) {
for (PODBCCOL colp = (PODBCCOL)Columns;
colp; colp = (PODBCCOL)colp->GetNext())
if (!colp->IsSpecial())
colp->AllocateBuffers(g, Rows);
} else {
Ocp->Close();
return true;
rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0);
} // endif Query
if (!rc)
rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0);
} else if (Mode == MODE_INSERT) {
if (!(rc = MakeInsert(g)))
if ((Query = MakeInsert(g))) {
if (Nparm != Ocp->PrepareSQL(Query)) {
strcpy(g->Message, MSG(PARM_CNT_MISS));
rc = true;
} else
rc = BindParameters(g);
} else {
strcpy(g->Message, "No DELETE/UPDATE of ODBC tablesd");
return true;
} // endelse
} // endif Query
if (rc) {
} else if (Mode == MODE_UPDATE)
Query = MakeUpdate(g);
else if (Mode == MODE_DELETE)
Query = MakeDelete(g);
else
sprintf(g->Message, "Invalid mode %d", Mode);
if (!Query || rc) {
Ocp->Close();
return true;
} // endif rc
@@ -730,6 +751,21 @@ int TDBODBC::ReadDB(PGLOBAL g)
htrc("ODBC ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p\n",
GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex);
if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
// Send the UPDATE/DELETE command to the remote table
if (!Ocp->ExecSQLcommand(Query)) {
sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
if (trace)
htrc("%s\n", g->Message);
PushWarning(g, this, 0); // 0 means a Note
return RC_EF; // Nothing else to do
} else
return RC_FX; // Error
} // endif Mode
if (To_Kindex) {
// Direct access of ODBC tables is not implemented yet
strcpy(g->Message, MSG(NO_ODBC_DIRECT));
@@ -775,8 +811,22 @@ int TDBODBC::WriteDB(PGLOBAL g)
/***********************************************************************/
int TDBODBC::DeleteDB(PGLOBAL g, int irc)
{
strcpy(g->Message, MSG(NO_ODBC_DELETE));
return RC_FX;
if (irc == RC_FX) {
// Send the DELETE (all) command to the remote table
if (!Ocp->ExecSQLcommand(Query)) {
sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
if (trace)
htrc("%s\n", g->Message);
PushWarning(g, this, 0); // 0 means a Note
return RC_OK; // This is a delete all
} else
return RC_FX; // Error
} else
return RC_OK; // Ignore
} // end of DeleteDB
/***********************************************************************/
@@ -790,6 +840,7 @@ void TDBODBC::CloseDB(PGLOBAL g)
// } // endif
if (Ocp)
Ocp->Close();
if (trace)
@@ -1226,6 +1277,15 @@ int TDBXDBC::WriteDB(PGLOBAL g)
return RC_FX;
} // end of DeleteDB
/***********************************************************************/
/* Data Base delete line routine for ODBC access method. */
/***********************************************************************/
int TDBXDBC::DeleteDB(PGLOBAL g, int irc)
{
strcpy(g->Message, MSG(NO_ODBC_DELETE));
return RC_FX;
} // end of DeleteDB
/* --------------------------- XSRCCOL ------------------------------- */
/***********************************************************************/