mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
- Fix bug when closing some table types
modified: storage/connect/tabmul.cpp storage/connect/tabmysql.cpp storage/connect/tabodbc.cpp - Add Insert support for ODBC table Add the send command feature to ODBC tables (not documented yet) modified: storage/connect/ha_connect.cc storage/connect/myconn.cpp storage/connect/odbccat.h storage/connect/odbconn.cpp storage/connect/odbconn.h storage/connect/tabodbc.cpp storage/connect/tabodbc.h
This commit is contained in:
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/************ 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,6 +1264,32 @@ 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 = SQLPrepare(hstmt, (PUCHAR)sql, SQL_NTS);
|
||||
} while (rc == SQL_STILL_EXECUTING);
|
||||
|
||||
if (!Check(rc))
|
||||
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 = SQLExecute(hstmt);
|
||||
} while (rc == SQL_STILL_EXECUTING);
|
||||
|
||||
if (!Check(rc))
|
||||
ThrowDBX(rc, "SQLExecute", hstmt);
|
||||
|
||||
} else {
|
||||
do {
|
||||
rc = SQLExecDirect(hstmt, (PUCHAR)sql, SQL_NTS);
|
||||
} while (rc == SQL_STILL_EXECUTING);
|
||||
@@ -1255,15 +1301,7 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols)
|
||||
rc = SQLNumResultCols(hstmt, &ncol);
|
||||
} while (rc == SQL_STILL_EXECUTING);
|
||||
|
||||
if (ncol == 0) {
|
||||
// Update or Delete statement
|
||||
rc = SQLRowCount(hstmt, &afrw);
|
||||
|
||||
if (!Check(rc))
|
||||
ThrowDBX(rc, "SQLRowCount", hstmt);
|
||||
|
||||
return afrw;
|
||||
} // endif ncol
|
||||
} // 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
|
||||
|
@@ -1043,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;
|
||||
@@ -1055,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);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/************* 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,242 @@ 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 = sscanf(To_Filter, "%s = '%[^\0]", 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 --------------------------- */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*************** 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. */
|
||||
/***********************************************************************/
|
||||
|
Reference in New Issue
Block a user