Commit eca84a9b authored by Olivier Bertrand's avatar Olivier Bertrand

- 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
parent e5c589a8
......@@ -251,7 +251,7 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2,
return true;
} // endif tdbp
tdbp->SetMode(mode);
//tdbp->SetMode(mode); done in ha_connect::GetTDB
if (!c1) {
if (mode == MODE_INSERT)
......@@ -498,8 +498,8 @@ RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all)
if (!tdbp || tdbp->GetMode() != MODE_DELETE)
return RC_FX;
// else
// ((PTDBDOX)tdbp)->SetModified(true);
else if (tdbp->IsReadOnly())
return RC_NF;
if (((PTDBASE)tdbp)->GetDef()->Indexable() && all)
((PTDBDOS)tdbp)->Cardinal= 0;
......@@ -518,17 +518,13 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp)
int rc= RC_OK;
TDBDOX *tbxp= NULL;
if (!tdbp)
return rc; // Already done
if (!tdbp || tdbp->GetUse() != USE_OPEN)
return rc; // Nothing to do
if (xtrace)
printf("CntCloseTable: tdbp=%p mode=%d\n", tdbp, tdbp->GetMode());
/*********************************************************************/
/* This will close the table file(s) and also finalize write */
/* operations such as Insert, Update, or Delete. */
/*********************************************************************/
if (tdbp->GetMode() == MODE_DELETE)
if (tdbp->GetMode() == MODE_DELETE && tdbp->GetUse() == USE_OPEN)
rc= tdbp->DeleteDB(g, RC_EF); // Specific A.M. delete routine
// Prepare error return
......@@ -543,6 +539,8 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp)
goto err;
} // endif
// This will close the table file(s) and also finalize write
// operations such as Insert, Update, or Delete.
tdbp->CloseDB(g);
g->jump_level--;
......
......@@ -258,17 +258,21 @@ ha_create_table_option connect_field_option_list[]=
/***********************************************************************/
/* Push G->Message as a MySQL warning. */
/***********************************************************************/
bool PushWarning(PGLOBAL g, PTDBASE tdbp)
bool PushWarning(PGLOBAL g, PTDBASE tdbp, int level)
{
PHC phc;
THD *thd;
MYCAT *cat= (MYCAT*)tdbp->GetDef()->GetCat();
Sql_condition::enum_warning_level wlvl;
if (!cat || !(phc= cat->GetHandler()) || !phc->GetTable() ||
!(thd= (phc->GetTable())->in_use))
return true;
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
//push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
wlvl= (Sql_condition::enum_warning_level)level;
push_warning(thd, wlvl, 0, g->Message);
return false;
} // end of PushWarning
......@@ -1098,19 +1102,20 @@ PTDB ha_connect::GetTDB(PGLOBAL g)
&& (tdbp->GetMode() == xmod
|| tdbp->GetAmType() == TYPE_AM_XML)) {
tp= tdbp;
tp->SetMode(xmod);
// tp->SetMode(xmod);
} else if ((tp= CntGetTDB(g, table_name, xmod, this)))
valid_query_id= xp->last_query_id;
else
printf("GetTDB: %s\n", g->Message);
tp->SetMode(xmod);
return tp;
} // end of GetTDB
/****************************************************************************/
/* Open a CONNECT table, restricting column list if cols is true. */
/****************************************************************************/
bool ha_connect::OpenTable(PGLOBAL g, bool del)
int ha_connect::OpenTable(PGLOBAL g, bool del)
{
bool rc= false;
char *c1= NULL, *c2=NULL;
......@@ -1118,11 +1123,11 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del)
// Double test to be on the safe side
if (!g || !table) {
printf("OpenTable logical error; g=%p table=%p\n", g, table);
return true;
return HA_ERR_INITIALIZATION;
} // endif g
if (!(tdbp= GetTDB(g)))
return true;
return RC_FX;
else if (tdbp->IsReadOnly())
switch (xmod) {
case MODE_WRITE:
......@@ -1130,7 +1135,7 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del)
case MODE_UPDATE:
case MODE_DELETE:
strcpy(g->Message, MSG(READ_ONLY));
return true;
return HA_ERR_TABLE_READONLY;
default:
break;
} // endswitch xmode
......@@ -1207,7 +1212,7 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del)
valid_info= false;
} // endif rc
return rc;
return (rc) ? HA_ERR_INITIALIZATION : 0;
} // end of OpenTable
......@@ -2006,14 +2011,8 @@ int ha_connect::write_row(uchar *buf)
if (IsOpened())
CloseTable(g);
if (OpenTable(g)) {
if (strstr(g->Message, "read only"))
rc= HA_ERR_TABLE_READONLY;
else
rc= HA_ERR_INITIALIZATION;
if ((rc= OpenTable(g)))
DBUG_RETURN(rc);
} // endif tdbp
} // endif isopened
......@@ -2378,6 +2377,7 @@ int ha_connect::index_next_same(uchar *buf, const uchar *key, uint keylen)
*/
int ha_connect::rnd_init(bool scan)
{
int rc;
PGLOBAL g= ((table && table->in_use) ? GetPlug(table->in_use, xp) :
(xp) ? xp->g : NULL);
DBUG_ENTER("ha_connect::rnd_init");
......@@ -2398,8 +2398,8 @@ int ha_connect::rnd_init(bool scan)
if (xmod == MODE_UPDATE)
bitmap_union(table->read_set, table->write_set);
if (OpenTable(g, xmod == MODE_DELETE))
DBUG_RETURN(HA_ERR_INITIALIZATION);
if ((rc= OpenTable(g, xmod == MODE_DELETE)))
DBUG_RETURN(rc);
xp->nrd= xp->fnd= xp->nfd= 0;
xp->tb1= my_interval_timer();
......@@ -2610,7 +2610,6 @@ int ha_connect::info(uint flag)
xp->CheckCleanup();
} // endif xmod
// tdbp= OpenTable(g, xmod == MODE_DELETE);
tdbp= GetTDB(g);
} // endif tdbp
......@@ -2705,18 +2704,19 @@ int ha_connect::delete_all_rows()
PGLOBAL g= xp->g;
DBUG_ENTER("ha_connect::delete_all_rows");
if (tdbp && tdbp->GetAmType() != TYPE_AM_XML)
if (tdbp && tdbp->GetUse() == USE_OPEN &&
tdbp->GetAmType() != TYPE_AM_XML &&
((PTDBASE)tdbp)->GetFtype() != RECFM_NAF)
// Close and reopen the table so it will be deleted
rc= CloseTable(g);
if (!(OpenTable(g))) {
if (!(rc= OpenTable(g))) {
if (CntDeleteRow(g, tdbp, true)) {
printf("%s\n", g->Message);
rc= HA_ERR_INTERNAL_ERROR;
} // endif
} else
rc= HA_ERR_INITIALIZATION;
} // endif rc
DBUG_RETURN(rc);
} // end of delete_all_rows
......
......@@ -174,7 +174,7 @@ class ha_connect: public handler
bool IsSameIndex(PIXDEF xp1, PIXDEF xp2);
PTDB GetTDB(PGLOBAL g);
bool OpenTable(PGLOBAL g, bool del= false);
int OpenTable(PGLOBAL g, bool del= false);
bool IsOpened(void);
int CloseTable(PGLOBAL g);
int MakeRecord(char *buf);
......
......@@ -48,7 +48,7 @@ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
dept INT(4) NOT NULL FIELD_FORMAT='S'
) ENGINE=CONNECT TABLE_TYPE=BIN READONLY=Yes FILE_NAME='Testbal.dat';
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=NO;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
......@@ -84,7 +84,7 @@ t1 CREATE TABLE `t1` (
`dept` int(4) NOT NULL `FIELD_FORMAT`='S'
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=BIN `FILE_NAME`='Testbal.dat' `READONLY`=YES
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
DROP TABLE t1;
#
# Testing that the underlying file is created
......
......@@ -50,13 +50,13 @@ children SMALLINT(2) NOT NULL
) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
HEADER=1 SEP_CHAR=';' QUOTED=1 READONLY=yes;
INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
UPDATE t1 SET children=6 WHERE name='BILL';
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE name='BILL';
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
SELECT * FROM t1;
name birth children
Archibald 2001-05-17 3
......@@ -90,7 +90,7 @@ t1 CREATE TABLE `t1` (
`children` smallint(2) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=CSV `FILE_NAME`='people.csv' `HEADER`=1 `SEP_CHAR`=';' `QUOTED`=1 `READONLY`=1
INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
SELECT * FROM t1;
name birth children
Archibald 2001-05-17 3
......
......@@ -77,13 +77,13 @@ t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1.dbf' `READONLY`=Yes
INSERT INTO t1 VALUES (30);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
UPDATE t1 SET a=30 WHERE a=10;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE a=10;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=NO;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
......
......@@ -30,13 +30,13 @@ t1 CREATE TABLE `t1` (
`id` int(11) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=FIX `FILE_NAME`='t1.txt' `READONLY`=1
INSERT INTO t1 VALUES (20);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
UPDATE t1 SET id=20 WHERE id=10;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE id=10;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=0;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
......
......@@ -194,13 +194,13 @@ t1 CREATE TABLE `t1` (
`c2` char(60) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=INI `FILE_NAME`='t1.ini' `READONLY`=1
INSERT INTO t1 VALUES ('US',40);
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
UPDATE t1 SET c2=20 WHERE c2=10;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE c2=10;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=0;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
......
......@@ -103,13 +103,13 @@ t1 CREATE TABLE `t1` (
`b` char(10) NOT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 MAX_ROWS=10 `TABLE_TYPE`=VEC `FILE_NAME`='t1vec' `READONLY`=yes
INSERT INTO t1 VALUES (4,'test04');
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
UPDATE t1 SET b='test04' WHERE a=3;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
DELETE FROM t1 WHERE a=3;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
TRUNCATE TABLE t1;
ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
ERROR HY000: Table 't1' is read only
ALTER TABLE t1 READONLY=no;
Warnings:
Warning 1105 The current version of CONNECT did not check what you changed in ALTER. Use at your own risk
......
......@@ -46,7 +46,7 @@ CREATE TABLE t1
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
dept INT(4) NOT NULL FIELD_FORMAT='S'
) ENGINE=CONNECT TABLE_TYPE=BIN READONLY=Yes FILE_NAME='Testbal.dat';
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
ALTER TABLE t1 READONLY=NO;
SHOW CREATE TABLE t1;
......@@ -54,7 +54,7 @@ INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
SELECT * FROM t1;
ALTER TABLE t1 READONLY=YES;
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
DROP TABLE t1;
......
......@@ -45,13 +45,13 @@ CREATE TABLE t1
children SMALLINT(2) NOT NULL
) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
HEADER=1 SEP_CHAR=';' QUOTED=1 READONLY=yes;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
UPDATE t1 SET children=6 WHERE name='BILL';
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
DELETE FROM t1 WHERE name='BILL';
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
TRUNCATE TABLE t1;
SELECT * FROM t1;
ALTER TABLE t1 READONLY=no;
......@@ -60,7 +60,7 @@ INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
SELECT * FROM t1;
ALTER TABLE t1 READONLY=1;
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
SELECT * FROM t1;
DROP TABLE t1;
......
......@@ -66,13 +66,13 @@ INSERT INTO t1 VALUES (10),(20);
SELECT * FROM t1;
ALTER TABLE t1 READONLY=Yes;
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (30);
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
UPDATE t1 SET a=30 WHERE a=10;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
DELETE FROM t1 WHERE a=10;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
TRUNCATE TABLE t1;
ALTER TABLE t1 READONLY=NO;
SHOW CREATE TABLE t1;
......
......@@ -28,13 +28,13 @@ INSERT INTO t1 VALUES (10);
SELECT * FROM t1;
ALTER TABLE t1 READONLY=1;
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (20);
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
UPDATE t1 SET id=20 WHERE id=10;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
DELETE FROM t1 WHERE id=10;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
TRUNCATE TABLE t1;
ALTER TABLE t1 READONLY=0;
SHOW CREATE TABLE t1;
......
......@@ -99,13 +99,13 @@ INSERT INTO t1 VALUES ('UK',10),('FR',20),('RU',30);
SELECT * FROM t1;
ALTER TABLE t1 READONLY=1;
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES ('US',40);
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
UPDATE t1 SET c2=20 WHERE c2=10;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
DELETE FROM t1 WHERE c2=10;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
TRUNCATE TABLE t1;
ALTER TABLE t1 READONLY=0;
SHOW CREATE TABLE t1;
......
......@@ -52,13 +52,13 @@ SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
--echo #
ALTER TABLE t1 READONLY=yes;
SHOW CREATE TABLE t1;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (4,'test04');
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
UPDATE t1 SET b='test04' WHERE a=3;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
DELETE FROM t1 WHERE a=3;
--error ER_GET_ERRMSG
--error ER_OPEN_AS_READONLY
TRUNCATE TABLE t1;
ALTER TABLE t1 READONLY=no;
SHOW CREATE TABLE t1;
......
......@@ -873,7 +873,8 @@ ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp)
m_Connect = NULL;
m_Updatable = true;
m_Transact = false;
m_IDQuoteChar = '\'';
m_IDQuoteChar[0] = '"';
m_IDQuoteChar[1] = 0;
//*m_ErrMsg = '\0';
} // end of ODBConn
......@@ -1232,16 +1233,9 @@ void ODBConn::GetConnectInfo()
SQL_MODE_READ_ONLY);
#endif // 0
// Cache the quote char to use when constructing SQL
char QuoteChar[2];
// Get the quote char to use when constructing SQL
rc = SQLGetInfo(m_hdbc, SQL_IDENTIFIER_QUOTE_CHAR,
QuoteChar, sizeof(QuoteChar), &nResult);
if (Check(rc) && nResult == 1)
m_IDQuoteChar = QuoteChar[0];
else
m_IDQuoteChar = ' ';
m_IDQuoteChar, sizeof(m_IDQuoteChar), &nResult);
if (trace)
htrc("DBMS: %s, Version: %s\n",
......
......@@ -127,7 +127,7 @@ class ODBConn : public BLOCK {
// Attributes
public:
char GetQuoteChar(void) {return m_IDQuoteChar;}
char *GetQuoteChar(void) {return m_IDQuoteChar;}
// Database successfully opened?
bool IsOpen(void) {return m_hdbc != SQL_NULL_HDBC;}
PSZ GetStringInfo(ushort infotype);
......@@ -184,9 +184,9 @@ class ODBConn : public BLOCK {
DWORD m_QueryTimeout;
DWORD m_UpdateOptions;
DWORD m_RowsetSize;
char m_IDQuoteChar[2];
int m_Catver;
PSZ m_Connect;
bool m_Updatable;
bool m_Transact;
char m_IDQuoteChar;
}; // end of ODBConn class definition
......@@ -593,4 +593,4 @@ int global_open(GLOBAL *g, int msgid, const char *filename, int flags, int mode)
DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir);
char *MakeEscape(PGLOBAL g, char* str, char q);
bool PushWarning(PGLOBAL, PTDBASE);
bool PushWarning(PGLOBAL, PTDBASE, int level = 1);
......@@ -524,6 +524,7 @@ bool TDBCAT::OpenDB(PGLOBAL g)
if (Initialize(g))
return true;
Use = USE_OPEN;
return InitCol(g);
} // end of OpenDB
......
......@@ -495,6 +495,7 @@ bool TDBOCCUR::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
Use = USE_OPEN;
return ViewColumnList(g);
} // end of OpenDB
......
......@@ -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)
if ((Query = MakeSQL(g, false))) {
for (PODBCCOL colp = (PODBCCOL)Columns;
colp; colp = (PODBCCOL)colp->GetNext())
for (PODBCCOL colp = (PODBCCOL)Columns; colp;
colp = (PODBCCOL)colp->GetNext())
if (!colp->IsSpecial())
colp->AllocateBuffers(g, Rows);
} else {
Ocp->Close();
return true;
} // endif Query
if (!rc)
rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0);
} // endif Query
} 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
} 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 (rc) {
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 ------------------------------- */
/***********************************************************************/
......
......@@ -34,7 +34,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ GetTabowner(void) {return Tabowner;}
PSZ GetTabqual(void) {return Tabqual;}
PSZ GetSrcdef(void) {return Srcdef;}
PSZ GetQchar(void) {return (Qchar && *Qchar) ? Qchar : NULL;}
int GetQuoted(void) {return Quoted;}
int GetCatver(void) {return Catver;}
int GetOptions(void) {return Options;}
......@@ -53,6 +53,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ Qrystr; /* The original query */
int Catver; /* ODBC version for catalog functions */
int Options; /* Open connection options */
int Quoted; /* Identifier quoting level */
int Mxr; /* Maxerr for an Exec table */
bool Xsrc; /* Execution type */
}; // end of ODBCDEF
......@@ -100,10 +101,11 @@ class TDBODBC : public TDBASE {
// Internal functions
int Decode(char *utf, char *buf, size_t n);
char *MakeSQL(PGLOBAL g, bool cnt);
bool MakeInsert(PGLOBAL g);
char *MakeInsert(PGLOBAL g);
//bool MakeFilter(PGLOBAL g, bool c);
bool BindParameters(PGLOBAL g);
char *MakeStmt(PGLOBAL g);
char *MakeUpdate(PGLOBAL g);
char *MakeDelete(PGLOBAL g);
// Members
ODBConn *Ocp; // Points to an ODBC connection class
......@@ -121,6 +123,7 @@ class TDBODBC : public TDBASE {
char *DBQ; // The address part of Connect string
char *Qrystr; // The original query
int Options; // Connect options
int Quoted; // The identifier quoting level
int Fpos; // Position of last read record
int AftRows; // The number of affected rows
int Rows; // Rowset size
......@@ -206,7 +209,7 @@ class TDBXDBC : public TDBODBC {
virtual bool OpenDB(PGLOBAL g);
virtual int ReadDB(PGLOBAL g);
virtual int WriteDB(PGLOBAL g);
//virtual int DeleteDB(PGLOBAL g, int irc);
virtual int DeleteDB(PGLOBAL g, int irc);
//virtual void CloseDB(PGLOBAL g);
protected:
......
......@@ -607,6 +607,8 @@ bool TDBPIVOT::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
Use = USE_OPEN; // Do it now in case we are recursively called
/*********************************************************************/
/* Make all required pivot columns for object views. */
/*********************************************************************/
......
......@@ -495,6 +495,7 @@ bool TDBPRX::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
Use = USE_OPEN;
return FALSE;
} // end of OpenDB
......
......@@ -667,6 +667,8 @@ bool TDBWMI::OpenDB(PGLOBAL g)
} else
DoubleSlash(g);
Use = USE_OPEN; // Do it now in case we are recursively called
/*********************************************************************/
/* Initialize the WMI processing. */
/*********************************************************************/
......
......@@ -193,6 +193,7 @@ bool TDBXCL::OpenDB(PGLOBAL g)
if (Tdbp->OpenDB(g))
return TRUE;
Use = USE_OPEN;
return FALSE;
} // end of OpenDB
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment