TYPCONV GetTypeConv(); int GetConvSize(); void OdbcClose(PGLOBAL g, PFBLOCK fp);
/***********************************************************************/ /* Some macro's (should be defined elsewhere to be more accessible) */ /***********************************************************************/ #ifdefined(_DEBUG) #define ASSERT(f) assert(f) #define DEBUG_ONLY(f) (f) #else// !_DEBUG #define ASSERT(f) ((void)0) #define DEBUG_ONLY(f) ((void)0) #endif// !_DEBUG
/***********************************************************************/ /* GetSQLType: returns the SQL_TYPE corresponding to a PLG type. */ /***********************************************************************/ staticshort GetSQLType(int type)
{ short tp = SQL_TYPE_NULL;
switch (type) { case TYPE_STRING: tp = SQL_CHAR; break; case TYPE_SHORT: tp = SQL_SMALLINT; break; case TYPE_INT: tp = SQL_INTEGER; break; case TYPE_DATE: tp = SQL_TIMESTAMP; break; case TYPE_BIGINT: tp = SQL_BIGINT; break; // (-5) case TYPE_DOUBLE: tp = SQL_DOUBLE; break; case TYPE_TINY: tp = SQL_TINYINT; break; case TYPE_DECIM: tp = SQL_DECIMAL; break;
} // endswitch type
return tp;
} // end of GetSQLType
/***********************************************************************/ /* GetSQLCType: returns the SQL_C_TYPE corresponding to a PLG type. */ /***********************************************************************/ staticint GetSQLCType(int type)
{ int tp = SQL_TYPE_NULL;
switch (type) { case TYPE_STRING: tp = SQL_C_CHAR; break; case TYPE_SHORT: tp = SQL_C_SHORT; break; case TYPE_INT: tp = SQL_C_LONG; break; case TYPE_DATE: tp = SQL_C_TIMESTAMP; break; case TYPE_BIGINT: tp = SQL_C_SBIGINT; break; case TYPE_DOUBLE: tp = SQL_C_DOUBLE; break; case TYPE_TINY : tp = SQL_C_TINYINT; break; //#if (ODBCVER >= 0x0300) // case TYPE_DECIM: tp = SQL_C_NUMERIC; break; (CRASH!!!) //#else case TYPE_DECIM: tp = SQL_C_CHAR; break; //#endif
} // endswitch type
return tp;
} // end of GetSQLCType
/***********************************************************************/ /* TranslateSQLType: translate a SQL Type to a PLG type. */ /***********************************************************************/ int TranslateSQLType(int stp, int prec, int& len, char& v, bool& w)
{ int type;
switch (stp) { case SQL_WVARCHAR: // (-9)
w = true; /* fall through */ case SQL_VARCHAR: // 12
v = 'V';
type = TYPE_STRING; break; case SQL_WCHAR: // (-8)
w = true; /* fall through */ case SQL_CHAR: // 1
type = TYPE_STRING; break; case SQL_WLONGVARCHAR: // (-10)
w = true; /* fall through */ case SQL_LONGVARCHAR: // (-1) if (GetTypeConv() == TPC_YES || GetTypeConv() == TPC_FORCE) {
v = 'V';
type = TYPE_STRING;
len = (len) ? MY_MIN(abs(len), GetConvSize()) : GetConvSize();
} else
type = TYPE_ERROR;
break; case SQL_NUMERIC: // 2 case SQL_DECIMAL: // 3 // type = (prec || len > 20) ? TYPE_DOUBLE // : (len > 10) ? TYPE_BIGINT : TYPE_INT;
type = TYPE_DECIM; break; case SQL_INTEGER: // 4
type = TYPE_INT; break; case SQL_SMALLINT: // 5
type = TYPE_SHORT; break; case SQL_TINYINT: // (-6) case SQL_BIT: // (-7)
type = TYPE_TINY; break; case SQL_FLOAT: // 6 case SQL_REAL: // 7 case SQL_DOUBLE: // 8
type = TYPE_DOUBLE; break; case SQL_DATETIME: // 9
type = TYPE_DATE;
len = 19; break; case SQL_TYPE_DATE: // 91
type = TYPE_DATE;
len = 10;
v = 'D'; break; case SQL_INTERVAL: // 10 case SQL_TYPE_TIME: // 92
type = TYPE_STRING;
len = 8 + ((prec) ? (prec+1) : 0);
v = 'T'; break; case SQL_TIMESTAMP: // 11 case SQL_TYPE_TIMESTAMP: // 93
type = TYPE_DATE;
len = 19 + ((prec) ? (prec+1) : 0);
v = 'S'; break; case SQL_BIGINT: // (-5)
type = TYPE_BIGINT; break; case SQL_BINARY: // (-2) case SQL_VARBINARY: // (-3) case SQL_LONGVARBINARY: // (-4) if (GetTypeConv() == TPC_FORCE) {
v = 'V';
type = TYPE_STRING;
len = (len) ? MY_MIN(abs(len), GetConvSize()) : GetConvSize();
} else
type = TYPE_ERROR;
break; case SQL_GUID: // (-11)
type = TYPE_STRING;
len = 36; break; case SQL_UNKNOWN_TYPE: // 0 default:
type = TYPE_ERROR;
len = 0;
} // endswitch type
// Some data sources change the current directory if (strcmp(dir, buf))
rc = chdir(dir);
ocp->Close(); return newdsn; // Return complete connection string
} // end of ODBCCheckConnection #endif// PROMPT_OK
/***********************************************************************/ /* Allocate the structure used to refer to the result set. */ /***********************************************************************/ static CATPARM *AllocCatInfo(PGLOBAL g, CATINFO fid, PCSZ db,
PCSZ tab, PQRYRES qrp)
{
size_t i, m, n;
CATPARM *cap;
#ifdefined(_DEBUG)
assert(qrp); #endif
try {
m = (size_t)qrp->Maxres;
n = (size_t)qrp->Nbcol;
cap = (CATPARM *)PlugSubAlloc(g, NULL, sizeof(CATPARM));
memset(cap, 0, sizeof(CATPARM));
cap->Id = fid;
cap->Qrp = qrp;
cap->DB = db;
cap->Tab = tab;
cap->Vlen = (SQLLEN* *)PlugSubAlloc(g, NULL, n * sizeof(SQLLEN *));
for (i = 0; i < n; i++)
cap->Vlen[i] = (SQLLEN *)PlugSubAlloc(g, NULL, m * sizeof(SQLLEN));
cap->Status = (UWORD *)PlugSubAlloc(g, NULL, m * sizeof(UWORD));
} catch (int n) {
htrc("Exception %d: %s\n", n, g->Message);
cap = NULL;
} catch (constchar *msg) {
htrc(g->Message, msg);
printf("%s\n", g->Message);
cap = NULL;
} // end catch
return cap;
} // end of AllocCatInfo
#if0 /***********************************************************************/ /* Check for nulls and reset them to Null (?) values. */ /***********************************************************************/ staticvoid ResetNullValues(CATPARM *cap)
{ int i, n, ncol;
PCOLRES crp;
PQRYRES qrp = cap->Qrp;
#ifdefined(_DEBUG)
assert(qrp); #endif
ncol = qrp->Nbcol;
for (i = 0, crp = qrp->Colresp; i < ncol && crp; i++, crp = crp->Next) for (n = 0; n < qrp->Nblin; n++) if (cap->Vlen[i][n] == SQL_NULL_DATA)
crp->Kdata->Reset(n);
} // end of ResetNullValues #endif
/***********************************************************************/ /* Close an ODBC table after a thrown error (called by PlugCloseFile) */ /***********************************************************************/ void OdbcClose(PGLOBAL g, PFBLOCK fp) {
((ODBConn*)fp->File)->Close();
} // end of OdbcClose
/***********************************************************************/ /* ODBCColumns: constructs the result blocks containing all columns */ /* of an ODBC table that will be retrieved by GetData commands. */ /***********************************************************************/
PQRYRES ODBCColumns(PGLOBAL g, PCSZ dsn, PCSZ db, PCSZ table,
PCSZ colpat, int maxres, bool info, POPARM sop)
{ int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT,
TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
XFLD fldtyp[] = {FLD_CAT, FLD_SCHEM, FLD_TABNAME, FLD_NAME,
FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH,
FLD_SCALE, FLD_RADIX, FLD_NULL, FLD_REM}; unsignedint length[] = {0, 0, 0, 0, 6, 0, 10, 10, 6, 6, 6, 0}; bool b[] = {true,true,false,false,false,false,false,false,true,true,false,true}; int i, n, ncol = 12;
PCOLRES crp;
PQRYRES qrp;
CATPARM *cap;
ODBConn *ocp = NULL;
/************************************************************************/ /* Do an evaluation of the result size. */ /************************************************************************/ if (!info) {
ocp = new(g) ODBConn(g, NULL);
if (table && !strchr(table, '%')) { // We fix a MySQL limit because some data sources return 32767
n = ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_TABLE);
maxres = (n) ? MY_MIN(n, 4096) : 4096;
} elseif (!maxres)
maxres = 20000;
if (trace(1))
htrc("ODBCColumns: max=%d len=%d,%d,%d,%d\n",
maxres, length[0], length[1], length[2], length[3]);
/************************************************************************/ /* Allocate the structures used to refer to the result set. */ /************************************************************************/
qrp = PlgAllocResult(g, ncol, maxres, IDS_COLUMNS,
buftyp, fldtyp, length, false, true);
for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next) if (b[i])
crp->Kdata->SetNullable(true);
if (info || !qrp) // Info table return qrp;
if (trace(1))
htrc("Getting col results ncol=%d\n", qrp->Nbcol);
if (!(cap = AllocCatInfo(g, CAT_COL, db, table, qrp))) return NULL;
cap->Pat = colpat;
/************************************************************************/ /* Now get the results into blocks. */ /************************************************************************/ if ((n = ocp->GetCatInfo(cap)) >= 0) {
qrp->Nblin = n; // ResetNullValues(cap);
if (trace(1))
htrc("Columns: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
} else
qrp = NULL;
/* Cleanup */
ocp->Close();
/************************************************************************/ /* Return the result pointer for use by GetData routines. */ /************************************************************************/ 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, POPARM sop)
{ char *sqry;
ODBConn *ocp = new(g) ODBConn(g, NULL);
if (char *p = strstr(src, "%s")) { // Place holder for an eventual where clause
size_t sqry_size = strlen(src) + 3;
sqry = (char*)PlugSubAlloc(g, NULL, sqry_size);
snprintf(sqry, sqry_size, "%.*s1=1%s", (int) (p - src), src, p + 2); // dummy where clause
} else
sqry = src;
return ocp->GetMetaData(g, dsn, sqry);
} // end of ODBCSrcCols
#if0 /**************************************************************************/ /* MyODBCCols: returns column info as required by ha_connect::pre_create. */ /**************************************************************************/
PQRYRES MyODBCCols(PGLOBAL g, char *dsn, char *tab, bool info)
{ // int i, type, len, prec; bool w = false; // PCOLRES crp, crpt, crpl, crpp;
PQRYRES qrp;
ODBConn *ocp;
/**********************************************************************/ /* Open the connection with the ODBC data source. */ /**********************************************************************/ if (!info) {
ocp = new(g) ODBConn(g, NULL);
if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly return NULL;
} else
ocp = NULL;
/**********************************************************************/ /* Get the information about the ODBC table columns. */ /**********************************************************************/ if ((qrp = ODBCColumns(g, ocp, dsn, NULL, tab, 0, NULL)) && ocp)
dsn = ocp->GetConnect(); // Complete connect string
/************************************************************************/ /* Close the local connection. */ /************************************************************************/ if (ocp)
ocp->Close();
if (!qrp) return NULL; // Error in ODBCColumns
/************************************************************************/ /* Keep only the info used by ha_connect::pre_create. */ /************************************************************************/
qrp->Colresp = qrp->Colresp->Next->Next; // Skip Schema and Table names
for (int i = 0; i < qrp->Nblin; i++) { // Types must be PLG types, not SQL types
type = crpt->Kdata->GetIntValue(i);
len = crpl->Kdata->GetIntValue(i);
prec = crpp->Kdata->GetIntValue(i);
type = TranslateSQLType(type, prec, len, w);
crpt->Kdata->SetValue(type, i);
// Some data sources do not count prec in length if (type == TYPE_DOUBLE)
len += (prec + 2); // To be safe
// Could have been changed for blobs or numeric
crpl->Kdata->SetValue(len, i);
} // endfor i
crpp->Next = crpp->Next->Next->Next; // Should be Remark
// Renumber crp's for flag comparison for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
crp->Ncol = ++i;
qrp->Nbcol = i; // Should be 7; was 11, skipped 4 return qrp;
} // end of MyODBCCols #endif// 0
/*************************************************************************/ /* ODBCDrivers: constructs the result blocks containing all ODBC */ /* drivers available on the local host. */ /* Called with info=true to have result column names. */ /*************************************************************************/
PQRYRES ODBCDrivers(PGLOBAL g, int maxres, bool info)
{ int buftyp[] = {TYPE_STRING, TYPE_STRING};
XFLD fldtyp[] = {FLD_NAME, FLD_REM}; unsignedint length[] = {128, 256}; bool b[] = {false, true}; int i, ncol = 2;
PCOLRES crp;
PQRYRES qrp;
ODBConn *ocp = NULL;
/************************************************************************/ /* Do an evaluation of the result size. */ /************************************************************************/ if (!info) {
ocp = new(g) ODBConn(g, NULL);
if (!maxres)
maxres = 256; // Estimated max number of drivers
} else
maxres = 0;
if (trace(1))
htrc("ODBCDrivers: max=%d len=%d\n", maxres, length[0]);
/************************************************************************/ /* Allocate the structures used to refer to the result set. */ /************************************************************************/
qrp = PlgAllocResult(g, ncol, maxres, IDS_DRIVER,
buftyp, fldtyp, length, false, true);
for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next) if (b[i])
crp->Kdata->SetNullable(true);
/************************************************************************/ /* Now get the results into blocks. */ /************************************************************************/ if (!info && qrp && ocp->GetDrivers(qrp))
qrp = NULL;
/************************************************************************/ /* Return the result pointer for use by GetData routines. */ /************************************************************************/ return qrp;
} // end of ODBCDrivers
/*************************************************************************/ /* ODBCDataSources: constructs the result blocks containing all ODBC */ /* data sources available on the local host. */ /* Called with info=true to have result column names. */ /*************************************************************************/
PQRYRES ODBCDataSources(PGLOBAL g, int maxres, bool info)
{ int buftyp[] = {TYPE_STRING, TYPE_STRING};
XFLD fldtyp[] = {FLD_NAME, FLD_REM}; unsignedint length[] = {0, 256}; bool b[] = {false, true}; int i, n = 0, ncol = 2;
PCOLRES crp;
PQRYRES qrp;
ODBConn *ocp = NULL;
/************************************************************************/ /* Do an evaluation of the result size. */ /************************************************************************/ if (!info) {
ocp = new(g) ODBConn(g, NULL);
n = ocp->GetMaxValue(SQL_MAX_DSN_LENGTH);
length[0] = (n) ? (n + 1) : 256;
if (!maxres)
maxres = 512; // Estimated max number of data sources
if (trace(1))
htrc("ODBCDataSources: max=%d len=%d\n", maxres, length[0]);
/************************************************************************/ /* Allocate the structures used to refer to the result set. */ /************************************************************************/
qrp = PlgAllocResult(g, ncol, maxres, IDS_DSRC,
buftyp, fldtyp, length, false, true);
for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next) if (b[i])
crp->Kdata->SetNullable(true);
/************************************************************************/ /* Now get the results into blocks. */ /************************************************************************/ if (!info && qrp && ocp->GetDataSources(qrp))
qrp = NULL;
/************************************************************************/ /* Return the result pointer for use by GetData routines. */ /************************************************************************/ return qrp;
} // end of ODBCDataSources
/**************************************************************************/ /* ODBCTables: constructs the result blocks containing all tables in */ /* an ODBC database that will be retrieved by GetData commands. */ /**************************************************************************/
PQRYRES ODBCTables(PGLOBAL g, PCSZ dsn, PCSZ db, PCSZ tabpat, PCSZ tabtyp, int maxres, bool info, POPARM sop)
{ int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING, TYPE_STRING};
XFLD fldtyp[] = {FLD_CAT, FLD_SCHEM, FLD_NAME,
FLD_TYPE, FLD_REM}; unsignedint length[] = {0, 0, 0, 16, 0}; bool b[] ={ true, true, false, false, true }; int i, n, ncol = 5;
PCOLRES crp;
PQRYRES qrp;
CATPARM *cap;
ODBConn *ocp = NULL;
/************************************************************************/ /* Do an evaluation of the result size. */ /************************************************************************/ if (!info) { /**********************************************************************/ /* Open the connection with the ODBC data source. */ /**********************************************************************/
ocp = new(g) ODBConn(g, NULL);
if (ocp->Open(dsn, sop, 2) < 1) // 2 is openReadOnly return NULL;
if (!maxres)
maxres = 10000; // This is completely arbitrary
if (trace(1))
htrc("ODBCTables: max=%d len=%d,%d\n", maxres, length[0], length[1]);
/************************************************************************/ /* Allocate the structures used to refer to the result set. */ /************************************************************************/
qrp = PlgAllocResult(g, ncol, maxres, IDS_TABLES, buftyp,
fldtyp, length, false, true);
for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next) if (b[i])
crp->Kdata->SetNullable(true);
if (info || !qrp) return qrp;
if (!(cap = AllocCatInfo(g, CAT_TAB, db, tabpat, qrp))) return NULL;
cap->Pat = tabtyp;
if (trace(1))
htrc("Getting table results ncol=%d\n", cap->Qrp->Nbcol);
/************************************************************************/ /* Now get the results into blocks. */ /************************************************************************/ if ((n = ocp->GetCatInfo(cap)) >= 0) {
qrp->Nblin = n; // ResetNullValues(cap);
if (trace(1))
htrc("Tables: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
} else
qrp = NULL;
/************************************************************************/ /* Close any local connection. */ /************************************************************************/
ocp->Close();
/************************************************************************/ /* Return the result pointer for use by GetData routines. */ /************************************************************************/ return qrp;
} // end of ODBCTables
#if0// Currently not used by CONNECT /**************************************************************************/ /* PrimaryKeys: constructs the result blocks containing all the */ /* ODBC catalog information concerning primary keys. */ /**************************************************************************/
PQRYRES ODBCPrimaryKeys(PGLOBAL g, ODBConn *op, char *dsn, char *table)
{ staticint buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING, TYPE_SHORT, TYPE_STRING}; staticunsignedint length[] = {0, 0, 0, 0, 6, 128}; int n, ncol = 5; int maxres;
PQRYRES qrp;
CATPARM *cap;
ODBConn *ocp = op;
if (!op) { /**********************************************************************/ /* Open the connection with the ODBC data source. */ /**********************************************************************/
ocp = new(g) ODBConn(g, NULL);
if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly return NULL;
} // endif op
/************************************************************************/ /* Do an evaluation of the result size. */ /************************************************************************/
n = ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_TABLE);
maxres = (n) ? (int)n : 250;
n = ocp->GetMaxValue(SQL_MAX_CATALOG_NAME_LEN);
length[0] = (n) ? (n + 1) : 128;
n = ocp->GetMaxValue(SQL_MAX_SCHEMA_NAME_LEN);
length[1] = (n) ? (n + 1) : 128;
n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
length[2] = (n) ? (n + 1) : 128;
n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
length[3] = (n) ? (n + 1) : 128;
if (trace(1))
htrc("ODBCPrimaryKeys: max=%d len=%d,%d,%d\n",
maxres, length[0], length[1], length[2]);
/************************************************************************/ /* Allocate the structure used to refer to the result set. */ /************************************************************************/
qrp = PlgAllocResult(g, ncol, maxres, IDS_PKEY,
buftyp, NULL, length, false, true);
if (trace(1))
htrc("Getting pkey results ncol=%d\n", qrp->Nbcol);
cap = AllocCatInfo(g, CAT_KEY, NULL, table, qrp);
/************************************************************************/ /* Now get the results into blocks. */ /************************************************************************/ if ((n = ocp->GetCatInfo(cap)) >= 0) {
qrp->Nblin = n; // ResetNullValues(cap);
if (trace(1))
htrc("PrimaryKeys: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
} else
qrp = NULL;
/************************************************************************/ /* Close any local connection. */ /************************************************************************/ if (!op)
ocp->Close();
/************************************************************************/ /* Return the result pointer for use by GetData routines. */ /************************************************************************/ return qrp;
} // end of ODBCPrimaryKeys
/**************************************************************************/ /* Statistics: constructs the result blocks containing statistics */ /* about one or several tables to be retrieved by GetData commands. */ /**************************************************************************/
PQRYRES ODBCStatistics(PGLOBAL g, ODBConn *op, char *dsn, char *pat, int un, int acc)
{ staticint buftyp[] = {TYPE_STRING,
TYPE_STRING, TYPE_STRING, TYPE_SHORT, TYPE_STRING,
TYPE_STRING, TYPE_SHORT, TYPE_SHORT, TYPE_STRING,
TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_STRING}; staticunsignedint length[] = {0, 0, 0 ,6 ,0 ,0 ,6 ,6 ,0 ,2 ,10 ,10 ,128}; int n, ncol = 13; int maxres;
PQRYRES qrp;
CATPARM *cap;
ODBConn *ocp = op;
if (!op) { /**********************************************************************/ /* Open the connection with the ODBC data source. */ /**********************************************************************/
ocp = new(g) ODBConn(g, NULL);
if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly return NULL;
} // endif op
/************************************************************************/ /* Do an evaluation of the result size. */ /************************************************************************/
n = 1 + ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_INDEX);
maxres = (n) ? (int)n : 32;
n = ocp->GetMaxValue(SQL_MAX_SCHEMA_NAME_LEN);
length[1] = (n) ? (n + 1) : 128;
n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
length[2] = length[5] = (n) ? (n + 1) : 128;
n = ocp->GetMaxValue(SQL_MAX_CATALOG_NAME_LEN);
length[0] = length[4] = (n) ? (n + 1) : length[2];
n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
length[7] = (n) ? (n + 1) : 128;
if (trace(1))
htrc("SemStatistics: max=%d pat=%s\n", maxres, SVP(pat));
/************************************************************************/ /* Allocate the structure used to refer to the result set. */ /************************************************************************/
qrp = PlgAllocResult(g, ncol, maxres, IDS_STAT,
buftyp, NULL, length, false, true);
if (trace(1))
htrc("Getting stat results ncol=%d\n", qrp->Nbcol);
cap = AllocCatInfo(g, CAT_STAT, NULL, pat, qrp);
cap->Unique = (un < 0) ? SQL_INDEX_UNIQUE : (UWORD)un;
cap->Accuracy = (acc < 0) ? SQL_QUICK : (UWORD)acc;
/************************************************************************/ /* Now get the results into blocks. */ /************************************************************************/ if ((n = ocp->GetCatInfo(cap)) >= 0) {
qrp->Nblin = n; // ResetNullValues(cap);
if (trace(1))
htrc("Statistics: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
} else
qrp = NULL;
/************************************************************************/ /* Close any local connection. */ /************************************************************************/ if (!op)
ocp->Close();
/************************************************************************/ /* Return the result pointer for use by GetData routines. */ /************************************************************************/ return qrp;
} // end of Statistics #endif// 0
if ((signed)m_QueryTimeout != -1) { // Attempt to set query timeout. Ignore failure
rc = SQLSetStmtOption(hstmt, SQL_QUERY_TIMEOUT, m_QueryTimeout);
if (!Check(rc)) // don't attempt it again
m_QueryTimeout = (DWORD)-1;
} // endif m_QueryTimeout
if (m_RowsetSize > 0) { // Attempt to set rowset size. // In case of failure reset it to 0 to use Fetch.
rc = SQLSetStmtOption(hstmt, SQL_ROWSET_SIZE, m_RowsetSize);
if (!Check(rc)) // don't attempt it again
m_RowsetSize = 0;
} // endif m_RowsetSize
} // end of OnSetOptions
/***********************************************************************/ /* Open: connect to a data source. */ /***********************************************************************/ int ODBConn::Open(PCSZ ConnectString, POPARM sop, DWORD options)
{
PGLOBAL& g = m_G; //ASSERT_VALID(this); //ASSERT(ConnectString == NULL || AfxIsValidString(ConnectString));
ASSERT(!(options & noOdbcDialog && options & forceOdbcDialog));
if (!m_UseCnc) { if (DriverConnect(options)) {
snprintf(g->Message, sizeof(g->Message), MSG(CONNECT_CANCEL)); return0;
} // endif
} else// Connect using SQLConnect
Connect();
/*********************************************************************/ /* Link a Fblock. This make possible to automatically close it */ /* in case of error (throw). */ /*********************************************************************/
PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
/*ver = GetStringInfo(SQL_DRIVER_ODBC_VER);*/ // Verify support for required functionality and cache info // VerifyConnect(); Deprecated
GetConnectInfo(); // Still we want to use the set QChar
} catch(DBX *xp) {
snprintf(g->Message, sizeof(g->Message), "%s: %s", xp->m_Msg, xp->GetErrorMessage(0));
Close(); // Free(); return -1;
} // end try-catch
return1;
} // end of Open
/***********************************************************************/ /* Allocate an henv (first time called) and hdbc. */ /***********************************************************************/ void ODBConn::AllocConnect(DWORD Options)
{ if (m_hdbc != SQL_NULL_HDBC) return;
RETCODE rc; //AfxLockGlobals(CRIT_ODBC);
// Need to allocate an environment for first connection if (m_henv == SQL_NULL_HENV) { // ASSERT(m_nAlloc == 0);
if (trace(1))
htrc("Warning: data source is readonly\n");
} else// Make data source is !Updatable
rc = SQLSetConnectOption(m_hdbc, SQL_ACCESS_MODE,
SQL_MODE_READ_ONLY); #endif// 0
// Get the quote char to use when constructing SQL
rc = SQLGetInfo(m_hdbc, SQL_IDENTIFIER_QUOTE_CHAR,
m_IDQuoteChar, sizeof(m_IDQuoteChar), &nResult);
if (trace(1))
htrc("DBMS: %s, Version: %s, rc=%d\n",
GetStringInfo(SQL_DBMS_NAME), GetStringInfo(SQL_DBMS_VER), rc);
} // end of GetConnectInfo
/***********************************************************************/ /* Allocate record set and execute an SQL query. */ /***********************************************************************/ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols)
{
PGLOBAL& g = m_G; void *buffer; bool b;
UWORD n, k;
SWORD len, tp, ncol = 0;
ODBCCOL *colp;
RETCODE rc;
HSTMT hstmt;
try {
b = false;
if (m_hstmt) { // This is a Requery
rc = SQLFreeStmt(m_hstmt, SQL_CLOSE);
if (!Check(rc))
ThrowDBX(rc, "SQLFreeStmt", m_hstmt);
m_hstmt = NULL;
} // endif m_hstmt
rc = SQLAllocStmt(m_hdbc, &hstmt);
if (!Check(rc))
ThrowDBX(rc, "SQLAllocStmt");
if (m_Scrollable) {
rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_SCROLLABLE,
(void*)SQL_SCROLLABLE, 0);
if (!Check(rc))
ThrowDBX(rc, "Scrollable", hstmt);
} // endif m_Scrollable
OnSetOptions(hstmt);
b = true;
if (trace(1))
htrc("ExecDirect hstmt=%p %.256s\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) {
snprintf(g->Message, sizeof(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);
if (!Check(rc))
ThrowDBX(rc, "SQLExecDirect", hstmt);
do {
rc = SQLNumResultCols(hstmt, &ncol);
} while (rc == SQL_STILL_EXECUTING);
k = 0; // used for column number
} // endif Srcdef
for (n = 0, colp = tocols; colp; colp = (PODBCCOL)colp->GetNext()) if (!colp->IsSpecial())
n++;
// n can be 0 for query such as Select count(*) from table if (n && n > (UWORD)ncol)
ThrowDBX(MSG(COL_NUM_MISM));
// Now bind the column buffers for (colp = tocols; colp; colp = (PODBCCOL)colp->GetNext()) if (!colp->IsSpecial()) {
buffer = colp->GetBuffer(m_RowsetSize);
len = colp->GetBuflen();
tp = GetSQLCType(colp->GetResultType());
m_hstmt = hstmt; return (int)m_RowsetSize; // May have been reset in OnSetOptions
} // end of ExecDirectSQL
/***********************************************************************/ /* Get the number of lines of the result set. */ /***********************************************************************/ int ODBConn::GetResultSize(char *sql, ODBCCOL *colp)
{ int n = 0;
RETCODE rc;
if (ExecDirectSQL(sql, colp) < 0) return -1;
try { for (n = 0; ; n++) { do {
rc = SQLFetch(m_hstmt);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDBX(rc, "SQLFetch", m_hstmt);
m_hstmt = hstmt; return (int)nparm;
} // end of PrepareSQL
/***********************************************************************/ /* Execute a prepared statement. */ /***********************************************************************/ int ODBConn::ExecuteSQL(void)
{
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(rc = SQLNumResultCols(m_hstmt, &ncol)))
ThrowDBX(rc, "SQLNumResultCols", m_hstmt);
if (ncol) { // This should never happen while inserting
snprintf(g->Message, sizeof(g->Message), "Logical error while inserting");
} else { // Insert, Update or Delete statement if (!Check(rc = SQLRowCount(m_hstmt, &afrw)))
ThrowDBX(rc, "SQLRowCount", m_hstmt);
// Check whether we should use transaction if (sscanf(sql, " %15s ", cmd) == 1) { if (!stricmp(cmd, "INSERT") || !stricmp(cmd, "UPDATE") ||
!stricmp(cmd, "DELETE") || !stricmp(cmd, "REPLACE")) { // Does the data source support transactions
rc = SQLGetInfo(m_hdbc, SQL_TXN_CAPABLE, &txn, 0, NULL);
/************************************************************************/ /* Allocate the structures used to refer to the result set. */ /************************************************************************/ if (!(qrp = PlgAllocResult(g, qcol, ncol, IDS_COLUMNS + 3,
buftyp, fldtyp, length, false, true))) return NULL;
// Some columns must be renamed for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next) switch (++i) { case3: crp->Name = "Precision"; break; case4: crp->Name = "Scale"; break; case5: 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++;
/************************************************************************/ /* 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. */ /***********************************************************************/ bool ODBConn::GetDataSources(PQRYRES qrp)
{ bool rv = false;
UCHAR *dsn, *des;
UWORD dir = SQL_FETCH_FIRST;
SWORD n1, n2, p1, p2;
PCOLRES crp1 = qrp->Colresp, crp2 = qrp->Colresp->Next;
RETCODE rc;
n1 = crp1->Clen;
n2 = crp2->Clen;
try {
rc = SQLAllocEnv(&m_henv);
if (!Check(rc))
ThrowDBX(rc, "SQLAllocEnv"); // Fatal
for (int i = 0; i < qrp->Maxres; i++) {
dsn = (UCHAR*)crp1->Kdata->GetValPtr(i);
des = (UCHAR*)crp2->Kdata->GetValPtr(i);
rc = SQLDataSources(m_henv, dir, dsn, n1, &p1, des, n2, &p2);
if (rc == SQL_NO_DATA_FOUND) break; elseif (!Check(rc))
ThrowDBX(rc, "SQLDataSources");
/***********************************************************************/ /* Get the list of Drivers and set it in qrp. */ /***********************************************************************/ bool ODBConn::GetDrivers(PQRYRES qrp)
{ int i, n; bool rv = false;
UCHAR *des, *att;
UWORD dir = SQL_FETCH_FIRST;
SWORD n1, n2, p1, p2;
PCOLRES crp1 = qrp->Colresp, crp2 = qrp->Colresp->Next;
RETCODE rc;
n1 = crp1->Clen;
n2 = crp2->Clen;
try {
rc = SQLAllocEnv(&m_henv);
if (!Check(rc))
ThrowDBX(rc, "SQLAllocEnv"); // Fatal
for (n = 0; n < qrp->Maxres; n++) {
des = (UCHAR*)crp1->Kdata->GetValPtr(n);
att = (UCHAR*)crp2->Kdata->GetValPtr(n);
rc = SQLDrivers(m_henv, dir, des, n1, &p1, att, n2, &p2);
if (rc == SQL_NO_DATA_FOUND) break; elseif (!Check(rc))
ThrowDBX(rc, "SQLDrivers");
// The attributes being separated by '\0', set them to ';' for (i = 0; i < p2; i++) if (!att[i])
att[i] = ';';
/***********************************************************************/ /* A helper class to split an optionally qualified table name into */ /* components. */ /* These formats are understood: */ /* "CatalogName.SchemaName.TableName" */ /* "SchemaName.TableName" */ /* "TableName" */ /***********************************************************************/ class SQLQualifiedName
{ staticconst uint max_parts= 3; // Catalog.Schema.Table
MYSQL_LEX_STRING m_part[max_parts]; char m_buf[512];
void lex_string_set(MYSQL_LEX_STRING *S, char *str, size_t length)
{
S->str= str;
S->length= length;
} // end of lex_string_set
void lex_string_shorten_down(MYSQL_LEX_STRING *S, size_t offs)
{
DBUG_ASSERT(offs <= S->length);
S->str+= offs;
S->length-= offs;
} // end of lex_string_shorten_down
/*********************************************************************/ /* Find the rightmost '.' delimiter and return the length */ /* of the qualifier, including the rightmost '.' delimier. */ /* For example, for the string {"a.b.c",5} it will return 4, */ /* which is the length of the qualifier "a.b." */ /*********************************************************************/
size_t lex_string_find_qualifier(MYSQL_LEX_STRING *S)
{
size_t i; for (i= S->length; i > 0; i--)
{ if (S->str[i - 1] == '.')
{
S->str[i - 1]= '\0'; return i;
}
} return0;
} // end of lex_string_find_qualifier
public: /*********************************************************************/ /* Initialize to the given optionally qualified name. */ /* NULL pointer in "name" is supported. */ /* name qualifier has precedence over schema. */ /*********************************************************************/
SQLQualifiedName(CATPARM *cap)
{ constchar *name = (constchar *)cap->Tab; char *db = (char *)cap->DB;
size_t len, i;
// Initialize the parts for (i = 0 ; i < max_parts; i++)
lex_string_set(&m_part[i], NULL, 0);
if (name) { // Initialize the first (rightmost) part
lex_string_set(&m_part[0], m_buf,
strmake(m_buf, name, sizeof(m_buf) - 1) - m_buf);
// Initialize the other parts, if exist. for (i= 1; i < max_parts; i++) { if (!(len= lex_string_find_qualifier(&m_part[i - 1]))) break;
lex_string_set(&m_part[i], m_part[i - 1].str, len - 1);
lex_string_shorten_down(&m_part[i - 1], len);
} // endfor i
} // endif name
// If it was not specified, set schema as the passed db name if (db && !m_part[1].length)
lex_string_set(&m_part[1], db, strlen(db));
} // end of SQLQualifiedName
SQLCHAR *ptr(uint i)
{
DBUG_ASSERT(i < max_parts); return (SQLCHAR *) (m_part[i].length ? m_part[i].str : NULL);
} // end of ptr
SQLSMALLINT length(uint i)
{
DBUG_ASSERT(i < max_parts); return (SQLSMALLINT)m_part[i].length;
} // end of length
}; // end of class SQLQualifiedName
/***********************************************************************/ /* Allocate recset and call SQLTables, SQLColumns or SQLPrimaryKeys. */ /***********************************************************************/ int ODBConn::GetCatInfo(CATPARM *cap)
{
PGLOBAL& g = m_G; void *buffer; int i, irc; bool b;
PCSZ fnc = "Unknown";
UWORD n = 0;
SWORD ncol, len, tp;
SQLULEN crow = 0;
PQRYRES qrp = cap->Qrp;
PCOLRES crp;
RETCODE rc = 0;
HSTMT hstmt = NULL;
SQLLEN *vl, *vlen = NULL;
PVAL *pval = NULL; char* *pbuf = NULL;
try {
b = false;
if (!m_hstmt) {
rc = SQLAllocStmt(m_hdbc, &hstmt);
if (!Check(rc))
ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
} else
ThrowDBX(MSG(SEQUENCE_ERROR));
b = true;
// Currently m_Catver should be always 0 here
assert(!m_Catver); // This may be temporary
if (qrp->Maxres > 0)
m_RowsetSize = 1; else
ThrowDBX("0-sized result");
SQLQualifiedName name(cap);
// Now do call the proper ODBC API switch (cap->Id) { case CAT_TAB:
fnc = "SQLTables";
rc = SQLTables(hstmt, name.ptr(2), name.length(2),
name.ptr(1), name.length(1),
name.ptr(0), name.length(0),
(SQLCHAR *)cap->Pat,
cap->Pat ? SQL_NTS : 0); break; case CAT_COL:
fnc = "SQLColumns";
rc = SQLColumns(hstmt, name.ptr(2), name.length(2),
name.ptr(1), name.length(1),
name.ptr(0), name.length(0),
(SQLCHAR *)cap->Pat,
cap->Pat ? SQL_NTS : 0); break; case CAT_KEY:
fnc = "SQLPrimaryKeys";
rc = SQLPrimaryKeys(hstmt, name.ptr(2), name.length(2),
name.ptr(1), name.length(1),
name.ptr(0), name.length(0)); break; case CAT_STAT:
fnc = "SQLStatistics";
rc = SQLStatistics(hstmt, name.ptr(2), name.length(2),
name.ptr(1), name.length(1),
name.ptr(0), name.length(0),
cap->Unique, cap->Accuracy); break; case CAT_SPC:
ThrowDBX("SQLSpecialColumns not available yet"); break; default:
ThrowDBX("Invalid SQL function id");
} // endswitch infotype
if (!Check(rc))
ThrowDBX(rc, fnc, hstmt);
// Some data source do not implement SQLNumResultCols if (Check(SQLNumResultCols(hstmt, &ncol))) // n because we no more ignore the first column if ((n = (UWORD)qrp->Nbcol) > (UWORD)ncol)
ThrowDBX(MSG(COL_NUM_MISM));
// Unconditional to handle STRBLK's
pval = (PVAL *)PlugSubAlloc(g, NULL, n * sizeof(PVAL));
vlen = (SQLLEN *)PlugSubAlloc(g, NULL, n * sizeof(SQLLEN));
pbuf = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
// Now bind the column buffers for (n = 0, crp = qrp->Colresp; crp; crp = crp->Next) { if ((tp = GetSQLCType(crp->Type)) == SQL_TYPE_NULL) {
snprintf(g->Message, sizeof(g->Message), MSG(INV_COLUMN_TYPE), crp->Type, crp->Name);
ThrowDBX(g->Message);
} // endif tp
if (!(len = GetTypeSize(crp->Type, crp->Length))) {
len = 255; // for STRBLK's
((STRBLK*)crp->Kdata)->SetSorted(true);
} // endif len
// n + 1 because column numbers begin with 1
rc = SQLBindCol(hstmt, n + 1, tp, buffer, len, vl);
if (!Check(rc))
ThrowDBX(rc, "SQLBindCol", hstmt);
n++;
} // endfor crp
fnc = "SQLFetch";
// Now fetch the result // Extended fetch cannot be used because of STRBLK's for (i = 0; i < qrp->Maxres; i++) { if ((rc = SQLFetch(hstmt)) == SQL_NO_DATA_FOUND) break; elseif (rc != SQL_SUCCESS) { if (trace(2) || (trace(1) && rc != SQL_SUCCESS_WITH_INFO)) {
UCHAR msg[SQL_MAX_MESSAGE_LENGTH + 1];
UCHAR state[SQL_SQLSTATE_SIZE + 1];
RETCODE erc;
SDWORD native;
*pcrp = NULL; //qrp->Nblin = n; return qrp;
} // end of AllocateResult
/***********************************************************************/ /* Restart from beginning of result set */ /***********************************************************************/ int ODBConn::Rewind(char *sql, ODBCCOL *tocols)
{ int rc, rbuf = -1;
if (!m_hstmt)
rbuf = 0; elseif (m_Full)
rbuf = m_Rows; // No need to "rewind" elseif (m_Scrollable) {
SQLULEN crow;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.