Commit 4ab970ab authored by Olivier Bertrand's avatar Olivier Bertrand

- Commit merged file (on Linux)

modified:
  storage/connect/ha_connect.cc
  storage/connect/myconn.cpp
  storage/connect/odbccat.h
  storage/connect/odbconn.cpp
  storage/connect/odbconn.h
  storage/connect/tabmul.cpp
  storage/connect/tabmysql.cpp
  storage/connect/tabodbc.cpp
  storage/connect/tabodbc.h
  
- Fix typo error in TDBDIR::CloseDB

modified:
  storage/connect/tabmul.cpp

- Fix format in TDBXDBC::MakeCMD (was not accepted on Linux)

modified:
  storage/connect/tabodbc.cpp
parents b8422f63 ca4c54aa
......@@ -1133,13 +1133,14 @@ bool ha_connect::OpenTable(PGLOBAL g, bool del)
break;
} // endswitch xmode
if (xmod != MODE_INSERT) {
if (xmod != MODE_INSERT || tdbp->GetAmType() == TYPE_AM_ODBC
|| tdbp->GetAmType() == TYPE_AM_MYSQL) {
// Get the list of used fields (columns)
char *p;
unsigned int k1, k2, n1, n2;
Field* *field;
Field* fp;
MY_BITMAP *map= table->read_set;
MY_BITMAP *map= (xmod == MODE_INSERT) ? table->write_set : table->read_set;
MY_BITMAP *ump= (xmod == MODE_UPDATE) ? table->write_set : NULL;
k1= k2= 0;
......@@ -1374,7 +1375,8 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *buf)
fp->option_struct->special)
continue; // Is a virtual column possible here ???
if (xmod == MODE_INSERT ||
if ((xmod == MODE_INSERT && tdbp->GetAmType() != TYPE_AM_MYSQL
&& tdbp->GetAmType() != TYPE_AM_ODBC) ||
bitmap_is_set(table->write_set, fp->field_index)) {
for (colp= tp->GetSetCols(); colp; colp= colp->GetNext())
if (!stricmp(colp->GetName(), fp->field_name))
......@@ -3464,7 +3466,7 @@ static bool add_field(String *sql, const char *field_name, int typ, int len,
{
bool error= false;
const char *type= PLGtoMYSQLtype(typ, dbf);
type= PLGtoMYSQLtype(typ, true);
// type= PLGtoMYSQLtype(typ, true); ?????
error|= sql->append('`');
error|= sql->append(field_name);
......@@ -3948,7 +3950,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
else
return HA_ERR_INTERNAL_ERROR; // Should never happen
if (src && ttp != TAB_PIVOT) {
if (src && ttp != TAB_PIVOT && ttp != TAB_ODBC) {
qrp= SrcColumns(g, host, db, user, pwd, src, port);
if (qrp && ttp == TAB_OCCUR)
......@@ -3966,7 +3968,12 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
switch (fnc) {
case FNC_NO:
case FNC_COL:
if (src) {
qrp= ODBCSrcCols(g, dsn, (char*)src);
src= NULL; // for next tests
} else
qrp= ODBCColumns(g, dsn, (char *) tab, NULL, fnc == FNC_COL);
break;
case FNC_TABLE:
qrp= ODBCTables(g, dsn, (char *) tab, true);
......
......@@ -166,7 +166,7 @@ PQRYRES MyColumns(PGLOBAL g, const char *host, const char *db,
// Get type, type name, and precision
fld = myc.GetCharField(1);
prec = 0;
len = 256; // Default for text or blob
len = 255; // Default for text or blob
if ((nf = sscanf(fld, "%[^(](%d,%d", cmd, &len, &prec)) < 1) {
sprintf(g->Message, MSG(BAD_FIELD_TYPE), fld);
......
......@@ -4,5 +4,6 @@
PQRYRES ODBCDataSources(PGLOBAL g, bool info);
PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
char *colpat, bool info);
PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src);
PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *tabpat, bool info);
PQRYRES ODBCDrivers(PGLOBAL g, bool info);
/************ Odbconn C++ Functions Source Code File (.CPP) ************/
/* Name: ODBCONN.CPP Version 1.6 */
/* Name: ODBCONN.CPP Version 1.7 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 1998-2013 */
/* */
......@@ -229,7 +229,6 @@ static void ResetNullValues(CATPARM *cap)
/***********************************************************************/
/* ODBCColumns: constructs the result blocks containing all columns */
/* of an ODBC table that will be retrieved by GetData commands. */
/* Note: The first two columns (Qualifier, Owner) are ignored. */
/***********************************************************************/
PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
char *colpat, bool info)
......@@ -318,6 +317,17 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *table,
return qrp;
} // end of ODBCColumns
/**************************************************************************/
/* ODBCSrcCols: constructs the result blocks containing the */
/* description of all the columns of a Srcdef option. */
/**************************************************************************/
PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src)
{
ODBConn *ocp = new(g) ODBConn(g, NULL);
return ocp->GetMetaData(g, dsn, src);
} // end of ODBCSrcCols
#if 0
/**************************************************************************/
/* MyODBCCols: returns column info as required by ha_connect::pre_create. */
......@@ -804,6 +814,17 @@ void DBX::BuildErrorMessage(ODBConn* pdb, HSTMT hstmt)
} // end of BuildErrorMessage
const char *DBX::GetErrorMessage(int i)
{
if (i < 0 || i >= MAX_NUM_OF_MSG)
return "No ODBC error";
else if (m_ErrMsg[i])
return m_ErrMsg[i];
else
return (m_Msg) ? m_Msg : "Unknown error";
} // end of GetErrorMessage
/***********************************************************************/
/* ODBConn construction/destruction. */
/***********************************************************************/
......@@ -822,7 +843,7 @@ ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp)
m_Catver = (tdbp) ? tdbp->Catver : 0;
m_Connect = NULL;
m_Updatable = true;
//m_Transactions = false;
m_Transact = false;
m_IDQuoteChar = '\'';
//*m_ErrMsg = '\0';
} // end of ODBConn
......@@ -1208,8 +1229,7 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols)
void *buffer;
bool b;
UWORD n;
SWORD ncol, len, tp;
SQLLEN afrw;
SWORD len, tp, ncol = 0;
ODBCCOL *colp;
RETCODE rc;
HSTMT hstmt;
......@@ -1244,26 +1264,44 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols)
if (trace)
htrc("ExecDirect hstmt=%p %.64s\n", hstmt, sql);
if (m_Tdb->Srcdef) {
// Be sure this is a query returning a result set
do {
rc = SQLExecDirect(hstmt, (PUCHAR)sql, SQL_NTS);
rc = SQLPrepare(hstmt, (PUCHAR)sql, SQL_NTS);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLExecDirect", hstmt);
ThrowDBX(rc, "SQLPrepare", hstmt);
if (!Check(rc = SQLNumResultCols(hstmt, &ncol)))
ThrowDBX(rc, "SQLNumResultCols", hstmt);
if (ncol == 0) {
strcpy(g->Message, "This Srcdef does not return a result set");
return -1;
} // endif ncol
// Ok, now we can proceed
do {
rc = SQLNumResultCols(hstmt, &ncol);
rc = SQLExecute(hstmt);
} while (rc == SQL_STILL_EXECUTING);
if (ncol == 0) {
// Update or Delete statement
rc = SQLRowCount(hstmt, &afrw);
if (!Check(rc))
ThrowDBX(rc, "SQLExecute", hstmt);
} else {
do {
rc = SQLExecDirect(hstmt, (PUCHAR)sql, SQL_NTS);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLRowCount", hstmt);
ThrowDBX(rc, "SQLExecDirect", hstmt);
return afrw;
} // endif ncol
do {
rc = SQLNumResultCols(hstmt, &ncol);
} while (rc == SQL_STILL_EXECUTING);
} // endif Srcdef
for (n = 0, colp = tocols; colp; colp = (PODBCCOL)colp->GetNext())
if (!colp->IsSpecial())
......@@ -1411,10 +1449,33 @@ int ODBConn::PrepareSQL(char *sql)
{
PGLOBAL& g = m_G;
bool b;
UINT txn = 0;
SWORD nparm;
RETCODE rc;
HSTMT hstmt;
if (m_Tdb->GetMode() != MODE_READ) {
// Does the data source support transactions
rc = SQLGetInfo(m_hdbc, SQL_TXN_CAPABLE, &txn, 0, NULL);
if (Check(rc) && txn != SQL_TC_NONE) try {
rc = SQLSetConnectAttr(m_hdbc, SQL_ATTR_AUTOCOMMIT,
SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER);
if (!Check(rc))
ThrowDBX(SQL_INVALID_HANDLE, "SQLSetConnectAttr");
m_Transact = true;
} catch(DBX *x) {
if (trace)
for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
htrc(x->m_ErrMsg[i]);
strcpy(g->Message, x->GetErrorMessage(0));
} // end try/catch
} // endif Mode
try {
b = false;
......@@ -1454,13 +1515,19 @@ int ODBConn::PrepareSQL(char *sql)
for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
htrc(x->m_ErrMsg[i]);
strcpy(m_G->Message, x->GetErrorMessage(0));
strcpy(g->Message, x->GetErrorMessage(0));
if (b)
SQLCancel(hstmt);
rc = SQLFreeStmt(hstmt, SQL_DROP);
m_hstmt = NULL;
if (m_Transact) {
rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_ROLLBACK);
m_Transact = false;
} // endif m_Transact
return -1;
} // end try/catch
......@@ -1469,27 +1536,59 @@ int ODBConn::PrepareSQL(char *sql)
} // end of PrepareSQL
/***********************************************************************/
/* Bind a parameter for inserting. */
/* Execute a prepared statement. */
/***********************************************************************/
bool ODBConn::ExecuteSQL(void)
int ODBConn::ExecuteSQL(bool x)
{
PGLOBAL& g = m_G;
SWORD ncol = 0;
RETCODE rc;
SQLLEN afrw = -1;
try {
do {
rc = SQLExecute(m_hstmt);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLExecute", m_hstmt);
if (!Check(SQLNumResultCols(m_hstmt, &ncol)))
ThrowDBX(rc, "SQLNumResultCols", m_hstmt);
if (ncol) {
if (x) {
afrw = ncol;
strcpy(g->Message, "Result set column number");
} else {
// This should never happen while inserting
strcpy(g->Message, "Logical error while inserting");
} // endif ncol
} else {
// Insert, Update or Delete statement
if (!Check(SQLRowCount(m_hstmt, &afrw)))
ThrowDBX(rc, "SQLRowCount", m_hstmt);
if (x)
strcpy(g->Message, "Affected rows");
} // endif ncol
} catch(DBX *x) {
strcpy(m_G->Message, x->GetErrorMessage(0));
SQLCancel(m_hstmt);
rc = SQLFreeStmt(m_hstmt, SQL_DROP);
m_hstmt = NULL;
return true;
if (m_Transact) {
rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_ROLLBACK);
m_Transact = false;
} // endif m_Transact
} // end try/catch
return false;
return (int)afrw;
} // end of ExecuteSQL
/***********************************************************************/
......@@ -1541,6 +1640,132 @@ bool ODBConn::BindParam(ODBCCOL *colp)
return false;
} // end of BindParam
/**************************************************************************/
/* GetMetaData: constructs the result blocks containing the */
/* description of all the columns of an SQL command. */
/**************************************************************************/
PQRYRES ODBConn::GetMetaData(PGLOBAL g, char *dsn, char *src)
{
static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_INT,
TYPE_SHORT, TYPE_SHORT};
static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_PREC,
FLD_SCALE, FLD_NULL};
static unsigned int length[] = {0, 6, 10, 6, 6};
unsigned char cn[60];
int qcol = 5;
short nl, type, prec, nul, cns = (short)sizeof(cn);
PQRYRES qrp = NULL;
PCOLRES crp;
USHORT i;
ULONG n;
SWORD ncol;
RETCODE rc;
HSTMT hstmt;
if (Open(dsn, 2) < 1) // 2 is openReadOnly
return NULL;
try {
rc = SQLAllocStmt(m_hdbc, &hstmt);
if (!Check(rc))
ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
OnSetOptions(hstmt);
do {
rc = SQLPrepare(hstmt, (PUCHAR)src, SQL_NTS);
// rc = SQLExecDirect(hstmt, (PUCHAR)src, SQL_NTS);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLExecDirect", hstmt);
do {
rc = SQLNumResultCols(hstmt, &ncol);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLNumResultCols", hstmt);
if (ncol) for (i = 1; i <= ncol; i++) {
do {
rc = SQLDescribeCol(hstmt, i, NULL, 0, &nl, NULL, NULL, NULL, NULL);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLDescribeCol", hstmt);
length[0] = max(length[0], (UINT)nl);
} // endfor i
} catch(DBX *x) {
strcpy(g->Message, x->GetErrorMessage(0));
goto err;
} // end try/catch
if (!ncol) {
strcpy(g->Message, "Invalid Srcdef");
goto err;
} // endif ncol
/************************************************************************/
/* Allocate the structures used to refer to the result set. */
/************************************************************************/
qrp = PlgAllocResult(g, qcol, ncol, IDS_COLUMNS + 3,
buftyp, fldtyp, length, false, true);
// Some columns must be renamed
for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
switch (++i) {
case 3: crp->Name = "Precision"; break;
case 4: crp->Name = "Scale"; break;
case 5: crp->Name = "Nullable"; break;
} // endswitch i
/************************************************************************/
/* Now get the results into blocks. */
/************************************************************************/
try {
for (i = 0; i < ncol; i++) {
do {
rc = SQLDescribeCol(hstmt, i+1, cn, cns, &nl, &type, &n, &prec, &nul);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLDescribeCol", hstmt);
else
qrp->Nblin++;
crp = qrp->Colresp; // Column_Name
crp->Kdata->SetValue((char*)cn, i);
crp = crp->Next; // Data_Type
crp->Kdata->SetValue(type, i);
crp = crp->Next; // Precision (length)
crp->Kdata->SetValue((int)n, i);
crp = crp->Next; // Scale
crp->Kdata->SetValue(prec, i);
crp = crp->Next; // Nullable
crp->Kdata->SetValue(nul, i);
} // endfor i
} catch(DBX *x) {
strcpy(g->Message, x->GetErrorMessage(0));
qrp = NULL;
} // end try/catch
/* Cleanup */
err:
SQLCancel(hstmt);
rc = SQLFreeStmt(hstmt, SQL_DROP);
Close();
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of GetMetaData
/***********************************************************************/
/* Get the list of Data Sources and set it in qrp. */
/***********************************************************************/
......@@ -1844,6 +2069,11 @@ void ODBConn::Close()
} // endif m_hstmt
if (m_hdbc != SQL_NULL_HDBC) {
if (m_Transact) {
rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_COMMIT);
m_Transact = false;
} // endif m_Transact
rc = SQLDisconnect(m_hdbc);
if (trace && rc != SQL_SUCCESS)
......
......@@ -91,8 +91,7 @@ class DBX : public BLOCK {
// Implementation (use ThrowDBX to create)
RETCODE GetRC(void) {return m_RC;}
PSZ GetMsg(void) {return m_Msg;}
const char *GetErrorMessage(int i)
{return (i >=0 && i < MAX_NUM_OF_MSG) ? m_ErrMsg[i] : "No ODBC error";}
const char *GetErrorMessage(int i);
protected:
void BuildErrorMessage(ODBConn* pdb, HSTMT hstmt = SQL_NULL_HSTMT);
......@@ -107,6 +106,7 @@ class DBX : public BLOCK {
/* ODBConn class. */
/***********************************************************************/
class ODBConn : public BLOCK {
friend class TDBODBC;
friend class DBX;
friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&);
private:
......@@ -142,11 +142,12 @@ class ODBConn : public BLOCK {
int ExecDirectSQL(char *sql, ODBCCOL *tocols);
int Fetch(void);
int PrepareSQL(char *sql);
bool ExecuteSQL(void);
int ExecuteSQL(bool x);
bool BindParam(ODBCCOL *colp);
int GetCatInfo(CATPARM *cap);
bool GetDataSources(PQRYRES qrp);
bool GetDrivers(PQRYRES qrp);
PQRYRES GetMetaData(PGLOBAL g, char *dsn, char *src);
public:
// Set special options
......@@ -185,5 +186,6 @@ class ODBConn : public BLOCK {
int m_Catver;
PSZ m_Connect;
bool m_Updatable;
bool m_Transact;
char m_IDQuoteChar;
}; // end of ODBConn class definition
......@@ -884,9 +884,11 @@ void TDBDIR::CloseDB(PGLOBAL g)
_findclose(Hsearch);
Hsearch = -1;
#else // !WIN32
// Close the DIR handle.
// Close the DIR handle
if (Dir) {
closedir(Dir);
Dir = NULL;
} // endif dir
#endif // !WIN32
iFile = 0;
} // end of CloseDB
......
......@@ -507,6 +507,9 @@ bool TDBMYSQL::MakeSelect(PGLOBAL g)
if (To_Filter)
strcat(strcat(Query, " WHERE "), To_Filter);
if (trace)
htrc("Query=%s\n", Query);
// Now we know how much to suballocate
PlugSubAlloc(g, NULL, strlen(Query) + 1);
return FALSE;
......@@ -1040,6 +1043,7 @@ int TDBMYSQL::DeleteDB(PGLOBAL g, int irc)
/***********************************************************************/
void TDBMYSQL::CloseDB(PGLOBAL g)
{
if (Myc.Connected()) {
if (Mode == MODE_INSERT) {
char cmd[64];
int w;
......@@ -1052,6 +1056,7 @@ void TDBMYSQL::CloseDB(PGLOBAL g)
} // endif m_Rc
Myc.Close();
} // endif Myc
if (trace)
htrc("MySQL CloseDB: closing %s rc=%d\n", Name, m_Rc);
......
/************* Tabodbc C++ Program Source Code File (.CPP) *************/
/* PROGRAM NAME: TABODBC */
/* ------------- */
/* Version 2.5 */
/* Version 2.6 */
/* */
/* COPYRIGHT: */
/* ---------- */
......@@ -90,8 +90,9 @@ extern int num_read, num_there, num_eq[2]; // Statistics
/***********************************************************************/
ODBCDEF::ODBCDEF(void)
{
Connect = Tabname = Tabowner = Tabqual = Qchar = NULL;
Connect = Tabname = Tabowner = Tabqual = Srcdef = Qchar = NULL;
Catver = Options = 0;
Xsrc = false;
} // end of ODBCDEF constructor
/***********************************************************************/
......@@ -107,9 +108,11 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Tabname = Cat->GetStringCatInfo(g, "Tabname", Tabname);
Tabowner = Cat->GetStringCatInfo(g, "Owner", "");
Tabqual = Cat->GetStringCatInfo(g, "Qualifier", "");
Srcdef = Cat->GetStringCatInfo(g, "Srcdef", NULL);
Qchar = Cat->GetStringCatInfo(g, "Qchar", "");
Catver = Cat->GetIntCatInfo("Catver", 2);
Options = Cat->GetIntCatInfo("Options", dop);
Xsrc = Cat->GetBoolCatInfo("Execsrc", FALSE);
Pseudo = 2; // FILID is Ok but not ROWID
return false;
} // end of DefineAM
......@@ -125,7 +128,9 @@ PTDB ODBCDEF::GetTable(PGLOBAL g, MODE m)
/* Allocate a TDB of the proper type. */
/* Column blocks will be allocated only when needed. */
/*********************************************************************/
switch (Catfunc) {
if (Xsrc)
tdbp = new(g) TDBXDBC(this);
else switch (Catfunc) {
case FNC_COL:
tdbp = new(g) TDBOCL(this);
break;
......@@ -161,19 +166,21 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
Cnp = NULL;
if (tdp) {
Connect = tdp->GetConnect();
TableName = tdp->GetTabname();
Owner = tdp->GetTabowner();
Qualifier = tdp->GetTabqual();
Connect = tdp->Connect;
TableName = tdp->Tabname;
Owner = tdp->Tabowner;
Qualifier = tdp->Tabqual;
Srcdef = tdp->Srcdef;
Quote = tdp->GetQchar();
Options = tdp->GetOptions();
Options = tdp->Options;
Rows = tdp->GetElemt();
Catver = tdp->GetCatver();
Catver = tdp->Catver;
} else {
Connect = NULL;
TableName = NULL;
Owner = NULL;
Qualifier = NULL;
Srcdef = NULL;
Quote = NULL;
Options = 0;
Rows = 0;
......@@ -201,6 +208,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
TableName = tdbp->TableName;
Owner = tdbp->Owner;
Qualifier = tdbp->Qualifier;
Srcdef = tdbp->Srcdef;
Quote = tdbp->Quote;
Query = tdbp->Query;
Count = tdbp->Count;
......@@ -299,7 +307,6 @@ void TDBODBC::SetFile(PGLOBAL g, PSZ fn)
DBQ = fn;
} // end of SetFile
/******************************************************************/
/* Convert an UTF-8 string to latin characters. */
/******************************************************************/
......@@ -314,7 +321,6 @@ int TDBODBC::Decode(char *txt, char *buf, size_t n)
return 0;
} // end of Decode
/***********************************************************************/
/* MakeSQL: make the SQL statement use with ODBC connection. */
/* Note: when implementing EOM filtering, column only used in local */
......@@ -329,6 +335,9 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
PTABLE tablep = To_Table;
PCOL colp;
if (Srcdef)
return Srcdef;
if (!cnt) {
// Normal SQL statement to retrieve results
for (colp = Columns; colp; colp = colp->GetNext())
......@@ -430,6 +439,83 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
return sql;
} // end of MakeSQL
/***********************************************************************/
/* MakeInsert: make the Insert statement used with ODBC connection. */
/***********************************************************************/
bool TDBODBC::MakeInsert(PGLOBAL g)
{
char *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;
} else {
len += (strlen(colp->GetName()) + 4);
((PODBCCOL)colp)->Rank = ++Nparm;
} // endif colp
colist = (char*)PlugSubAlloc(g, NULL, len);
*colist = '\0';
valist = (char*)PlugSubAlloc(g, NULL, 2 * Nparm);
*valist = '\0';
for (colp = Columns; colp; colp = colp->GetNext()) {
if (b) {
strcat(colist, ", ");
strcat(valist, ",");
} else
b = true;
if (Quote)
strcat(strcat(strcat(colist, Quote), colp->GetName()), Quote);
else
strcat(colist, colp->GetName());
strcat(valist, "?"); // Parameter marker
} // endfor colp
// 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 ");
if (Quote)
strcat(strcat(strcat(Query, Quote), TableName), Quote);
else
strcat(Query, TableName);
strcat(strcat(strcat(Query, " ("), colist), ") VALUES (");
strcat(strcat(Query, valist), ")");
return false;
} // end of MakeInsert
/***********************************************************************/
/* ODBC Bind Parameter function. */
/***********************************************************************/
bool TDBODBC::BindParameters(PGLOBAL g)
{
PODBCCOL colp;
for (colp = (PODBCCOL)Columns; colp; colp = (PODBCCOL)colp->Next) {
colp->AllocateBuffers(g, 0);
if (Ocp->BindParam(colp))
return true;
} // endfor colp
return false;
} // end of BindParameters
/***********************************************************************/
/* ResetSize: call by TDBMUL when calculating size estimate. */
/***********************************************************************/
......@@ -448,6 +534,12 @@ void TDBODBC::ResetSize(void)
int TDBODBC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
if (Srcdef) {
// Give a reasonable guess
MaxSize = 100;
return MaxSize;
} // endif Srcdef
if (!Ocp)
Ocp = new(g) ODBConn(g, this);
......@@ -473,12 +565,11 @@ int TDBODBC::GetMaxSize(PGLOBAL g)
} // end of GetMaxSize
/***********************************************************************/
/* Return 0 in mode DELETE or UPDATE to tell that it is done. */
/* Return max size value. */
/***********************************************************************/
int TDBODBC::GetProgMax(PGLOBAL g)
{
return (Mode == MODE_DELETE || Mode == MODE_UPDATE) ? 0
: GetMaxSize(g);
return GetMaxSize(g);
} // end of GetProgMax
/***********************************************************************/
......@@ -546,14 +637,24 @@ bool TDBODBC::OpenDB(PGLOBAL g)
if (!colp->IsSpecial())
colp->AllocateBuffers(g, Rows);
} else
rc = true;
} else {
Ocp->Close();
return true;
} // endif Query
if (!rc)
rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0);
} else if (Mode == MODE_INSERT) {
if (!(rc = MakeInsert(g)))
if (Nparm != Ocp->PrepareSQL(Query)) {
strcpy(g->Message, MSG(PARM_CNT_MISS));
rc = true;
} else
rc = BindParameters(g);
} else {
strcpy(g->Message, "ODBC tables are read only in this version");
strcpy(g->Message, "No DELETE/UPDATE of ODBC tablesd");
return true;
} // endelse
......@@ -592,30 +693,6 @@ int TDBODBC::ReadDB(PGLOBAL g)
// Direct access of ODBC tables is not implemented yet
strcpy(g->Message, MSG(NO_ODBC_DIRECT));
longjmp(g->jumper[g->jump_level], GetAmType());
#if 0
/*******************************************************************/
/* Reading is by an index table. */
/*******************************************************************/
int recpos = To_Kindex->Fetch(g);
switch (recpos) {
case -1: // End of file reached
return RC_EF;
case -2: // No match for join
return RC_NF;
case -3: // Same record as current one
num_there++;
return RC_OK;
default:
/***************************************************************/
/* Set the cursor position according to record to read. */
/***************************************************************/
//--------------------------------- TODO --------------------------------
break;
} // endswitch recpos
#endif // 0
} // endif To_Kindex
/*********************************************************************/
......@@ -641,8 +718,15 @@ int TDBODBC::ReadDB(PGLOBAL g)
/***********************************************************************/
int TDBODBC::WriteDB(PGLOBAL g)
{
strcpy(g->Message, "ODBC tables are read only");
int n = Ocp->ExecuteSQL(false);
if (n < 0) {
AftRows = n;
return RC_FX;
} else
AftRows += n;
return RC_OK;
} // end of WriteDB
/***********************************************************************/
......@@ -664,6 +748,7 @@ void TDBODBC::CloseDB(PGLOBAL g)
// To_Kindex = NULL;
// } // endif
if (Ocp)
Ocp->Close();
if (trace)
......@@ -892,7 +977,7 @@ void ODBCCOL::WriteColumn(PGLOBAL g)
/* Do convert the column value if necessary. */
/*********************************************************************/
if (Value != To_Val)
Value->SetValue_pval(To_Val, false); // Convert the inserted value
Value->SetValue_pval(To_Val, FALSE); // Convert the inserted value
if (Buf_Type == TYPE_DATE) {
struct tm tm, *dbtime = ((DTVAL*)Value)->GetGmTime(&tm);
......@@ -903,8 +988,245 @@ void ODBCCOL::WriteColumn(PGLOBAL g)
Sqlbuf->day = dbtime->tm_mday;
Sqlbuf->month = dbtime->tm_mon + 1;
Sqlbuf->year = dbtime->tm_year + 1900;
Sqlbuf->fraction = 0;
} // endif Buf_Type
if (Nullable)
*StrLen = (Value->IsNull()) ? SQL_NULL_DATA :
(IsTypeNum(Buf_Type)) ? 0 : SQL_NTS;
} // end of WriteColumn
/* -------------------------- Class TDBXDBC -------------------------- */
/***********************************************************************/
/* Implementation of the TDBODBC class. */
/***********************************************************************/
PTDB TDBXDBC::CopyOne(PTABS t)
{
PTDB tp;
PXSRCCOL cp1, cp2;
PGLOBAL g = t->G; // Is this really useful ???
tp = new(g) TDBXDBC(this);
for (cp1 = (PXSRCCOL)Columns; cp1; cp1 = (PXSRCCOL)cp1->GetNext()) {
cp2 = new(g) XSRCCOL(cp1, tp); // Make a copy
NewPointer(t, cp1, cp2);
} // endfor cp1
return tp;
} // end of CopyOne
/***********************************************************************/
/* Allocate XSRC column description block. */
/***********************************************************************/
PCOL TDBXDBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{
PXSRCCOL colp = new(g) XSRCCOL(cdp, this, cprec, n);
if (!colp->Flag)
Cmdcol = colp->GetName();
return colp;
} // end of MakeCol
/***********************************************************************/
/* MakeCMD: make the SQL statement to send to ODBC connection. */
/***********************************************************************/
char *TDBXDBC::MakeCMD(PGLOBAL g)
{
char *xcmd = NULL;
if (To_Filter) {
if (Cmdcol) {
char col[128], cmd[1024];
int n;
memset(cmd, 0, sizeof(cmd));
n = sscanf(To_Filter, "%s = '%1023c", col, cmd);
if (n == 2 && !stricmp(col, Cmdcol)) {
xcmd = (char*)PlugSubAlloc(g, NULL, strlen(cmd) + 1);
strcpy(xcmd, cmd);
xcmd[strlen(xcmd) - 1] = 0;
} else
strcpy(g->Message, "Invalid command specification filter");
} else
strcpy(g->Message, "No command column in select list");
} else if (!Srcdef)
strcpy(g->Message, "No Srcdef default command");
else
xcmd = Srcdef;
return xcmd;
} // end of MakeCMD
#if 0
/***********************************************************************/
/* ODBC Bind Parameter function. */
/***********************************************************************/
bool TDBXDBC::BindParameters(PGLOBAL g)
{
PODBCCOL colp;
for (colp = (PODBCCOL)Columns; colp; colp = (PODBCCOL)colp->Next) {
colp->AllocateBuffers(g, 0);
if (Ocp->BindParam(colp))
return true;
} // endfor colp
return false;
} // end of BindParameters
#endif // 0
/***********************************************************************/
/* XDBC GetMaxSize: returns table size (always one row). */
/***********************************************************************/
int TDBXDBC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0)
MaxSize = 1;
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/
/* ODBC Access Method opening routine. */
/* New method now that this routine is called recursively (last table */
/* first in reverse order): index blocks are immediately linked to */
/* join block of next table if it exists or else are discarted. */
/***********************************************************************/
bool TDBXDBC::OpenDB(PGLOBAL g)
{
bool rc = false;
if (g->Trace)
htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n",
this, Tdb_No, Use, Mode);
if (Use == USE_OPEN) {
strcpy(g->Message, "Multiple execution is not allowed");
return true;
} // endif use
/*********************************************************************/
/* Open an ODBC connection for this table. */
/* Note: this may not be the proper way to do. Perhaps it is better */
/* to test whether a connection is already open for this datasource */
/* and if so to allocate just a new result set. But this only for */
/* drivers allowing concurency in getting results ??? */
/*********************************************************************/
if (!Ocp)
Ocp = new(g) ODBConn(g, this);
else if (Ocp->IsOpen())
Ocp->Close();
if (Ocp->Open(Connect, Options) < 1)
return true;
Use = USE_OPEN; // Do it now in case we are recursively called
if (Mode != MODE_READ) {
strcpy(g->Message, "No INSERT/DELETE/UPDATE of XDBC tables");
return true;
} // endif Mode
/*********************************************************************/
/* Get the command to execute. */
/*********************************************************************/
if (!(Query = MakeCMD(g))) {
Ocp->Close();
return true;
} // endif Query
Rows = 1;
if (Ocp->PrepareSQL(Query)) {
strcpy(g->Message, "Parameters not supported");
AftRows = -1;
} else
AftRows = 0;
return false;
} // end of OpenDB
/***********************************************************************/
/* ReadDB: Data Base read routine for xdbc access method. */
/***********************************************************************/
int TDBXDBC::ReadDB(PGLOBAL g)
{
if (trace)
htrc("XDBC ReadDB: query=%s\n", SVP(Query));
if (Rows--) {
if (!AftRows)
AftRows = Ocp->ExecuteSQL(true);
} else
return RC_EF;
Fpos++; // Used for progress info
return RC_OK;
} // end of ReadDB
/***********************************************************************/
/* Data Base delete line routine for ODBC access method. */
/***********************************************************************/
int TDBXDBC::WriteDB(PGLOBAL g)
{
strcpy(g->Message, "Execsrc tables are read only");
return RC_FX;
} // end of DeleteDB
/* --------------------------- XSRCCOL ------------------------------- */
/***********************************************************************/
/* XSRCCOL public constructor. */
/***********************************************************************/
XSRCCOL::XSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
: ODBCCOL(cdp, tdbp, cprec, i, am)
{
// Set additional ODBC access method information for column.
Flag = cdp->GetOffset();
} // end of XSRCCOL constructor
/***********************************************************************/
/* XSRCCOL constructor used for copying columns. */
/* tdbp is the pointer to the new table descriptor. */
/***********************************************************************/
XSRCCOL::XSRCCOL(XSRCCOL *col1, PTDB tdbp) : ODBCCOL(col1, tdbp)
{
Flag = col1->Flag;
} // end of XSRCCOL copy constructor
/***********************************************************************/
/* ReadColumn: set column value according to Flag. */
/***********************************************************************/
void XSRCCOL::ReadColumn(PGLOBAL g)
{
PTDBXDBC tdbp = (PTDBXDBC)To_Tdb;
switch (Flag) {
case 0: Value->SetValue_psz(tdbp->Query); break;
case 1: Value->SetValue(tdbp->AftRows); break;
case 2: Value->SetValue_psz(g->Message); break;
default: Value->SetValue_psz("Invalid Flag"); break;
} // endswitch Flag
} // end of ReadColumn
/***********************************************************************/
/* WriteColumn: Should never be called. */
/***********************************************************************/
void XSRCCOL::WriteColumn(PGLOBAL g)
{
// Should never be called
} // end of WriteColumn
/* ---------------------------TDBSRC class --------------------------- */
......
/*************** Tabodbc H Declares Source Code File (.H) **************/
/* Name: TABODBC.H Version 1.5 */
/* Name: TABODBC.H Version 1.6 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2000-2013 */
/* */
......@@ -11,6 +11,8 @@
typedef class ODBCDEF *PODEF;
typedef class TDBODBC *PTDBODBC;
typedef class ODBCCOL *PODBCCOL;
typedef class TDBXDBC *PTDBXDBC;
typedef class XSRCCOL *PXSRCCOL;
typedef class TDBOIF *PTDBOIF;
typedef class OIFCOL *POIFCOL;
typedef class TDBSRC *PTDBSRC;
......@@ -19,6 +21,8 @@ typedef class TDBSRC *PTDBSRC;
/* ODBC table. */
/***********************************************************************/
class DllExport ODBCDEF : public TABDEF { /* Logical table description */
friend class TDBODBC;
friend class TDBXDBC;
public:
// Constructor
ODBCDEF(void);
......@@ -29,6 +33,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ GetTabname(void) {return Tabname;}
PSZ GetTabowner(void) {return Tabowner;}
PSZ GetTabqual(void) {return Tabqual;}
PSZ GetSrcdef(void) {return Srcdef;}
PSZ GetQchar(void) {return (Qchar && *Qchar) ? Qchar : NULL;}
int GetCatver(void) {return Catver;}
int GetOptions(void) {return Options;}
......@@ -43,9 +48,11 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ Tabname; /* External table name */
PSZ Tabowner; /* External table owner */
PSZ Tabqual; /* External table qualifier */
PSZ Srcdef; /* The source table SQL definition */
PSZ Qchar; /* Identifier quoting character */
int Catver; /* ODBC version for catalog functions */
int Options; /* Open connection options */
bool Xsrc; /* Execution type */
}; // end of ODBCDEF
#if !defined(NODBC)
......@@ -92,10 +99,10 @@ class TDBODBC : public TDBASE {
int Decode(char *utf, char *buf, size_t n);
char *MakeSQL(PGLOBAL g, bool cnt);
//bool MakeUpdate(PGLOBAL g, PSELECT selist);
//bool MakeInsert(PGLOBAL g);
bool MakeInsert(PGLOBAL g);
//bool MakeDelete(PGLOBAL g);
//bool MakeFilter(PGLOBAL g, bool c);
//bool BindParameters(PGLOBAL g);
bool BindParameters(PGLOBAL g);
// Members
ODBConn *Ocp; // Points to an ODBC connection class
......@@ -104,6 +111,7 @@ class TDBODBC : public TDBASE {
char *TableName; // Points to ODBC table name
char *Owner; // Points to ODBC table Owner
char *Qualifier; // Points to ODBC table Qualifier
char *Srcdef; // The source table SQL definition
char *Query; // Points to SQL statement
char *Count; // Points to count(*) SQL statement
//char *Where; // Points to local where clause
......@@ -122,7 +130,7 @@ class TDBODBC : public TDBASE {
}; // end of class TDBODBC
/***********************************************************************/
/* Class ODBCCOL: DOS access method column descriptor. */
/* Class ODBCCOL: ODBC access method column descriptor. */
/* This A.M. is used for ODBC tables. */
/***********************************************************************/
class ODBCCOL : public COLBLK {
......@@ -163,6 +171,75 @@ class ODBCCOL : public COLBLK {
int Rank; // Rank (position) number in the query
}; // end of class ODBCCOL
/***********************************************************************/
/* This is the ODBC Access Method class declaration that send */
/* commands to be executed by other DB ODBC drivers. */
/***********************************************************************/
class TDBXDBC : public TDBODBC {
friend class XSRCCOL;
friend class ODBConn;
public:
// Constructor
TDBXDBC(PODEF tdp = NULL) : TDBODBC(tdp) {Cmdcol = NULL;}
TDBXDBC(PTDBXDBC tdbp) : TDBODBC(tdbp) {Cmdcol = tdbp->Cmdcol;}
// Implementation
//virtual AMT GetAmType(void) {return TYPE_AM_ODBC;}
virtual PTDB Duplicate(PGLOBAL g)
{return (PTDB)new(g) TDBXDBC(this);}
// Methods
virtual PTDB CopyOne(PTABS t);
//virtual int GetRecpos(void);
//virtual PSZ GetFile(PGLOBAL g);
//virtual void SetFile(PGLOBAL g, PSZ fn);
//virtual void ResetSize(void);
//virtual int GetAffectedRows(void) {return AftRows;}
//virtual PSZ GetServer(void) {return "ODBC";}
// Database routines
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
//virtual int GetProgMax(PGLOBAL g);
virtual int GetMaxSize(PGLOBAL g);
virtual bool OpenDB(PGLOBAL g);
virtual int ReadDB(PGLOBAL g);
virtual int WriteDB(PGLOBAL g);
//virtual int DeleteDB(PGLOBAL g, int irc);
//virtual void CloseDB(PGLOBAL g);
protected:
// Internal functions
char *MakeCMD(PGLOBAL g);
//bool BindParameters(PGLOBAL g);
// Members
char *Cmdcol; // The name of the Xsrc command column
}; // end of class TDBXDBC
/***********************************************************************/
/* Used by table in source execute mode. */
/***********************************************************************/
class XSRCCOL : public ODBCCOL {
friend class TDBXDBC;
public:
// Constructors
XSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "ODBC");
XSRCCOL(XSRCCOL *colp, PTDB tdbp); // Constructor used in copy process
// Implementation
//virtual int GetAmType(void) {return TYPE_AM_ODBC;}
// Methods
virtual void ReadColumn(PGLOBAL g);
virtual void WriteColumn(PGLOBAL g);
// void Print(PGLOBAL g, FILE *, uint);
protected:
// Members
char *Buffer; // To get returned message
int Flag; // Column content desc
}; // end of class XSRCCOL
/***********************************************************************/
/* This is the class declaration for the Data Sources catalog table. */
/***********************************************************************/
......
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