mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
- Add the possibility to establish an ODBC connection via SQLConnect (the
default being still to use SQLDriverConnect) modified: storage/connect/ha_connect.cc storage/connect/odbccat.h storage/connect/odbconn.cpp storage/connect/odbconn.h storage/connect/tabodbc.cpp storage/connect/tabodbc.h - Cardinality testing not possible for TBL tables modified: storage/connect/tabtbl.cpp - Make all line ending LF instead of CRLF modified: storage/connect/tabjson.cpp
This commit is contained in:
parent
fd1ca70bb3
commit
180b2be63c
8 changed files with 356 additions and 284 deletions
|
@ -934,6 +934,9 @@ ulonglong ha_connect::table_flags() const
|
|||
char *GetListOption(PGLOBAL g, const char *opname,
|
||||
const char *oplist, const char *def)
|
||||
{
|
||||
if (!oplist)
|
||||
return (char*)def;
|
||||
|
||||
char key[16], val[256];
|
||||
char *pk, *pv, *pn;
|
||||
char *opval= (char*) def;
|
||||
|
@ -4847,10 +4850,12 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
|||
int port= 0, hdr= 0, mxr __attribute__((unused))= 0, mxe= 0, rc= 0;
|
||||
int cop __attribute__((unused)) = 0;
|
||||
#if defined(ODBC_SUPPORT)
|
||||
POPARM sop;
|
||||
char *ucnc;
|
||||
int cto= -1, qto= -1;
|
||||
#endif // ODBC_SUPPORT
|
||||
uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL);
|
||||
bool bif, ok= false, dbf= false;
|
||||
bool bif, ok= false, dbf= false, cnc= false;;
|
||||
TABTYPE ttp= TAB_UNDEF;
|
||||
PQRYRES qrp= NULL;
|
||||
PCOLRES crp;
|
||||
|
@ -4891,7 +4896,8 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
|||
|
||||
if (topt->oplist) {
|
||||
host= GetListOption(g, "host", topt->oplist, "localhost");
|
||||
user= GetListOption(g, "user", topt->oplist, "root");
|
||||
user= GetListOption(g, "user", topt->oplist,
|
||||
(ttp == TAB_ODBC ? NULL : "root"));
|
||||
// Default value db can come from the DBNAME=xxx option.
|
||||
db= GetListOption(g, "database", topt->oplist, db);
|
||||
col= GetListOption(g, "colist", topt->oplist, col);
|
||||
|
@ -4910,6 +4916,8 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
|||
mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0"));
|
||||
cto= atoi(GetListOption(g,"ConnectTimeout", topt->oplist, "-1"));
|
||||
qto= atoi(GetListOption(g,"QueryTimeout", topt->oplist, "-1"));
|
||||
if ((ucnc= GetListOption(g, "UseDSN", topt->oplist)))
|
||||
cnc= (!*ucnc || *ucnc == 'y' || *ucnc == 'Y' || atoi(ucnc) != 0);
|
||||
#endif
|
||||
mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0"));
|
||||
#if defined(PROMPT_OK)
|
||||
|
@ -4994,10 +5002,18 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
|||
} // endif dsn
|
||||
#endif // PROMPT_OK
|
||||
|
||||
} else if (!dsn)
|
||||
} else if (!dsn) {
|
||||
sprintf(g->Message, "Missing %s connection string", topt->type);
|
||||
else
|
||||
} else {
|
||||
// Store ODBC additional parameters
|
||||
sop= (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM));
|
||||
sop->User= (char*)user;
|
||||
sop->Pwd= (char*)pwd;
|
||||
sop->Cto= cto;
|
||||
sop->Qto= qto;
|
||||
sop->UseCnc=cnc;
|
||||
ok= true;
|
||||
} // endif's
|
||||
|
||||
supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER);
|
||||
break;
|
||||
|
@ -5128,15 +5144,15 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
|
|||
case FNC_NO:
|
||||
case FNC_COL:
|
||||
if (src) {
|
||||
qrp= ODBCSrcCols(g, dsn, (char*)src, cto, qto);
|
||||
qrp= ODBCSrcCols(g, dsn, (char*)src, sop);
|
||||
src= NULL; // for next tests
|
||||
} else
|
||||
qrp= ODBCColumns(g, dsn, shm, tab, NULL,
|
||||
mxr, cto, qto, fnc == FNC_COL);
|
||||
qrp= ODBCColumns(g, dsn, shm, tab, NULL,
|
||||
mxr, fnc == FNC_COL, sop);
|
||||
|
||||
break;
|
||||
case FNC_TABLE:
|
||||
qrp= ODBCTables(g, dsn, shm, tab, mxr, cto, qto, true);
|
||||
qrp= ODBCTables(g, dsn, shm, tab, mxr, true, sop);
|
||||
break;
|
||||
case FNC_DSN:
|
||||
qrp= ODBCDataSources(g, mxr, true);
|
||||
|
|
|
@ -2,6 +2,14 @@
|
|||
#define DEFAULT_LOGIN_TIMEOUT -1 // means do not set
|
||||
#define DEFAULT_QUERY_TIMEOUT -1 // means do not set
|
||||
|
||||
typedef struct odbc_parms {
|
||||
char *User; // User connect info
|
||||
char *Pwd; // Password connect info
|
||||
int Cto; // Connect timeout
|
||||
int Qto; // Query timeout
|
||||
bool UseCnc; // Use SQLConnect (!SQLDriverConnect)
|
||||
} ODBCPARM, *POPARM;
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBC catalog function prototypes. */
|
||||
/***********************************************************************/
|
||||
|
@ -10,8 +18,8 @@ char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop);
|
|||
#endif // PROMPT_OK
|
||||
PQRYRES ODBCDataSources(PGLOBAL g, int maxres, bool info);
|
||||
PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
|
||||
char *colpat, int maxres, int cto, int qto, bool info);
|
||||
PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, int cto, int qto);
|
||||
char *colpat, int maxres, bool info, POPARM sop);
|
||||
PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, POPARM sop);
|
||||
PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *db, char *tabpat,
|
||||
int maxres, int cto, int qto, bool info);
|
||||
int maxres, bool info, POPARM sop);
|
||||
PQRYRES ODBCDrivers(PGLOBAL g, int maxres, bool info);
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
#include "xobject.h"
|
||||
//#include "kindex.h"
|
||||
#include "xtable.h"
|
||||
#include "tabodbc.h"
|
||||
#include "odbccat.h"
|
||||
#include "tabodbc.h"
|
||||
#include "plgcnx.h" // For DB types
|
||||
#include "resource.h"
|
||||
#include "valblk.h"
|
||||
|
@ -291,7 +291,7 @@ static void ResetNullValues(CATPARM *cap)
|
|||
/* of an ODBC table that will be retrieved by GetData commands. */
|
||||
/***********************************************************************/
|
||||
PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
|
||||
char *colpat, int maxres, int cto, int qto, bool info)
|
||||
char *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,
|
||||
|
@ -310,10 +310,8 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
|
|||
/************************************************************************/
|
||||
if (!info) {
|
||||
ocp = new(g) ODBConn(g, NULL);
|
||||
ocp->SetLoginTimeout((DWORD)cto);
|
||||
ocp->SetQueryTimeout((DWORD)qto);
|
||||
|
||||
if (ocp->Open(dsn, 10) < 1) // openReadOnly + noODBCdialog
|
||||
if (ocp->Open(dsn, sop, 10) < 1) // openReadOnly + noODBCdialog
|
||||
return NULL;
|
||||
|
||||
if (table && !strchr(table, '%')) {
|
||||
|
@ -388,12 +386,13 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
|
|||
/* ODBCSrcCols: constructs the result blocks containing the */
|
||||
/* description of all the columns of a Srcdef option. */
|
||||
/**************************************************************************/
|
||||
PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, int cto, int qto)
|
||||
PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, POPARM sop)
|
||||
{
|
||||
ODBConn *ocp = new(g) ODBConn(g, NULL);
|
||||
|
||||
ocp->SetLoginTimeout((DWORD)cto);
|
||||
ocp->SetQueryTimeout((DWORD)qto);
|
||||
if (ocp->Open(dsn, sop, 10) < 1) // openReadOnly + noOdbcDialog
|
||||
return NULL;
|
||||
|
||||
return ocp->GetMetaData(g, dsn, src);
|
||||
} // end of ODBCSrcCols
|
||||
|
||||
|
@ -574,7 +573,7 @@ PQRYRES ODBCDataSources(PGLOBAL g, int maxres, bool info)
|
|||
/* an ODBC database that will be retrieved by GetData commands. */
|
||||
/**************************************************************************/
|
||||
PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *db, char *tabpat,
|
||||
int maxres, int cto, int qto, bool info)
|
||||
int maxres, bool info, POPARM sop)
|
||||
{
|
||||
int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
|
||||
TYPE_STRING, TYPE_STRING};
|
||||
|
@ -594,10 +593,8 @@ PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *db, char *tabpat,
|
|||
/* Open the connection with the ODBC data source. */
|
||||
/**********************************************************************/
|
||||
ocp = new(g) ODBConn(g, NULL);
|
||||
ocp->SetLoginTimeout((DWORD)cto);
|
||||
ocp->SetQueryTimeout((DWORD)qto);
|
||||
|
||||
if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
|
||||
if (ocp->Open(dsn, sop, 2) < 1) // 2 is openReadOnly
|
||||
return NULL;
|
||||
|
||||
if (!maxres)
|
||||
|
@ -925,6 +922,8 @@ ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp)
|
|||
m_Catver = (tdbp) ? tdbp->Catver : 0;
|
||||
m_Rows = 0;
|
||||
m_Connect = NULL;
|
||||
m_User = NULL;
|
||||
m_Pwd = NULL;
|
||||
m_Updatable = true;
|
||||
m_Transact = false;
|
||||
m_Scrollable = (tdbp) ? tdbp->Scrollable : false;
|
||||
|
@ -1061,7 +1060,7 @@ void ODBConn::OnSetOptions(HSTMT hstmt)
|
|||
/***********************************************************************/
|
||||
/* Open: connect to a data source. */
|
||||
/***********************************************************************/
|
||||
int ODBConn::Open(PSZ ConnectString, DWORD options)
|
||||
int ODBConn::Open(PSZ ConnectString, POPARM sop, DWORD options)
|
||||
{
|
||||
PGLOBAL& g = m_G;
|
||||
//ASSERT_VALID(this);
|
||||
|
@ -1070,6 +1069,11 @@ int ODBConn::Open(PSZ ConnectString, DWORD options)
|
|||
|
||||
m_Updatable = !(options & openReadOnly);
|
||||
m_Connect = ConnectString;
|
||||
m_User = sop->User;
|
||||
m_Pwd = sop->Pwd;
|
||||
m_LoginTimeout = sop->Cto;
|
||||
m_QueryTimeout = sop->Qto;
|
||||
m_UseCnc = sop->UseCnc;
|
||||
|
||||
// Allocate the HDBC and make connection
|
||||
try {
|
||||
|
@ -1078,10 +1082,22 @@ int ODBConn::Open(PSZ ConnectString, DWORD options)
|
|||
AllocConnect(options);
|
||||
/*ver = GetStringInfo(SQL_ODBC_VER);*/
|
||||
|
||||
if (Connect(options)) {
|
||||
#if 0
|
||||
// Connect using SQLDriverConnect
|
||||
if (DriverConnect(options)) {
|
||||
strcpy(g->Message, MSG(CONNECT_CANCEL));
|
||||
return 0;
|
||||
} // endif
|
||||
#endif // 0
|
||||
|
||||
if (!m_UseCnc) {
|
||||
if (DriverConnect(options)) {
|
||||
strcpy(g->Message, MSG(CONNECT_CANCEL));
|
||||
return 0;
|
||||
} // endif
|
||||
|
||||
} else // Connect using SQLConnect
|
||||
Connect();
|
||||
|
||||
/*ver = GetStringInfo(SQL_DRIVER_ODBC_VER);*/
|
||||
// Verify support for required functionality and cache info
|
||||
|
@ -1163,10 +1179,27 @@ void ODBConn::AllocConnect(DWORD Options)
|
|||
return;
|
||||
} // end of AllocConnect
|
||||
|
||||
/***********************************************************************/
|
||||
/* Connect to data source using SQLConnect. */
|
||||
/***********************************************************************/
|
||||
void ODBConn::Connect(void)
|
||||
{
|
||||
SQLRETURN rc;
|
||||
SQLSMALLINT ul = (m_User ? SQL_NTS : 0);
|
||||
SQLSMALLINT pl = (m_Pwd ? SQL_NTS : 0);
|
||||
|
||||
rc = SQLConnect(m_hdbc, (SQLCHAR*)m_Connect, SQL_NTS,
|
||||
(SQLCHAR*)m_User, ul, (SQLCHAR*)m_Pwd, pl);
|
||||
|
||||
if (!Check(rc))
|
||||
ThrowDBX(rc, "SQLConnect");
|
||||
|
||||
} // end of Connect
|
||||
|
||||
/***********************************************************************/
|
||||
/* Connect to data source using SQLDriverConnect. */
|
||||
/***********************************************************************/
|
||||
bool ODBConn::Connect(DWORD Options)
|
||||
bool ODBConn::DriverConnect(DWORD Options)
|
||||
{
|
||||
RETCODE rc;
|
||||
SWORD nResult;
|
||||
|
@ -1213,7 +1246,7 @@ bool ODBConn::Connect(DWORD Options)
|
|||
|
||||
// All done
|
||||
return false;
|
||||
} // end of Connect
|
||||
} // end of DriverConnect
|
||||
|
||||
void ODBConn::VerifyConnect()
|
||||
{
|
||||
|
@ -1865,9 +1898,6 @@ PQRYRES ODBConn::GetMetaData(PGLOBAL g, char *dsn, char *src)
|
|||
RETCODE rc;
|
||||
HSTMT hstmt;
|
||||
|
||||
if (Open(dsn, 10) < 1) // openReadOnly + noOdbcDialog
|
||||
return NULL;
|
||||
|
||||
try {
|
||||
rc = SQLAllocStmt(m_hdbc, &hstmt);
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ class ODBConn : public BLOCK {
|
|||
noOdbcDialog = 0x0008, // Don't display ODBC Connect dialog
|
||||
forceOdbcDialog = 0x0010}; // Always display ODBC connect dialog
|
||||
|
||||
int Open(PSZ ConnectString, DWORD Options = 0);
|
||||
int Open(PSZ ConnectString, POPARM sop, DWORD Options = 0);
|
||||
int Rewind(char *sql, ODBCCOL *tocols);
|
||||
void Close(void);
|
||||
PQRYRES AllocateResult(PGLOBAL g);
|
||||
|
@ -135,8 +135,10 @@ class ODBConn : public BLOCK {
|
|||
|
||||
public:
|
||||
// Operations
|
||||
void SetLoginTimeout(DWORD sec) {m_LoginTimeout = sec;}
|
||||
void SetQueryTimeout(DWORD sec) {m_QueryTimeout = sec;}
|
||||
//void SetLoginTimeout(DWORD sec) {m_LoginTimeout = sec;}
|
||||
//void SetQueryTimeout(DWORD sec) {m_QueryTimeout = sec;}
|
||||
//void SetUserName(PSZ user) {m_User = user;}
|
||||
//void SetUserPwd(PSZ pwd) {m_Pwd = pwd;}
|
||||
int GetResultSize(char *sql, ODBCCOL *colp);
|
||||
int ExecDirectSQL(char *sql, ODBCCOL *tocols);
|
||||
int Fetch(void);
|
||||
|
@ -155,7 +157,7 @@ class ODBConn : public BLOCK {
|
|||
|
||||
// Implementation
|
||||
public:
|
||||
// virtual ~ODBConn();
|
||||
//virtual ~ODBConn();
|
||||
|
||||
// ODBC operations
|
||||
protected:
|
||||
|
@ -163,7 +165,8 @@ class ODBConn : public BLOCK {
|
|||
void ThrowDBX(RETCODE rc, PSZ msg, HSTMT hstmt = SQL_NULL_HSTMT);
|
||||
void ThrowDBX(PSZ msg);
|
||||
void AllocConnect(DWORD dwOptions);
|
||||
bool Connect(DWORD Options);
|
||||
void Connect(void);
|
||||
bool DriverConnect(DWORD Options);
|
||||
void VerifyConnect(void);
|
||||
void GetConnectInfo(void);
|
||||
void Free(void);
|
||||
|
@ -185,11 +188,14 @@ class ODBConn : public BLOCK {
|
|||
DWORD m_RowsetSize;
|
||||
char m_IDQuoteChar[2];
|
||||
PSZ m_Connect;
|
||||
PSZ m_User;
|
||||
PSZ m_Pwd;
|
||||
int m_Catver;
|
||||
int m_Rows;
|
||||
bool m_Updatable;
|
||||
bool m_Transact;
|
||||
bool m_Scrollable;
|
||||
bool m_UseCnc;
|
||||
bool m_First;
|
||||
bool m_Full;
|
||||
}; // end of ODBConn class definition
|
||||
|
|
|
@ -482,38 +482,38 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
|
|||
return true;
|
||||
} // endif's
|
||||
|
||||
// For calculated arrays, a local Value must be used
|
||||
switch (jnp->Op) {
|
||||
case OP_NUM:
|
||||
jnp->Valp = AllocateValue(g, TYPE_INT);
|
||||
break;
|
||||
case OP_ADD:
|
||||
case OP_MULT:
|
||||
case OP_SEP:
|
||||
if (!IsTypeChar(Buf_Type))
|
||||
jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
|
||||
else
|
||||
jnp->Valp = AllocateValue(g, TYPE_DOUBLE);
|
||||
|
||||
break;
|
||||
case OP_MIN:
|
||||
case OP_MAX:
|
||||
jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
|
||||
break;
|
||||
case OP_CNC:
|
||||
if (IsTypeChar(Buf_Type))
|
||||
jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
|
||||
else
|
||||
jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
} // endswitch Op
|
||||
|
||||
if (jnp->Valp)
|
||||
MulVal = AllocateValue(g, jnp->Valp);
|
||||
|
||||
// For calculated arrays, a local Value must be used
|
||||
switch (jnp->Op) {
|
||||
case OP_NUM:
|
||||
jnp->Valp = AllocateValue(g, TYPE_INT);
|
||||
break;
|
||||
case OP_ADD:
|
||||
case OP_MULT:
|
||||
case OP_SEP:
|
||||
if (!IsTypeChar(Buf_Type))
|
||||
jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
|
||||
else
|
||||
jnp->Valp = AllocateValue(g, TYPE_DOUBLE);
|
||||
|
||||
break;
|
||||
case OP_MIN:
|
||||
case OP_MAX:
|
||||
jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
|
||||
break;
|
||||
case OP_CNC:
|
||||
if (IsTypeChar(Buf_Type))
|
||||
jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
|
||||
else
|
||||
jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
} // endswitch Op
|
||||
|
||||
if (jnp->Valp)
|
||||
MulVal = AllocateValue(g, jnp->Valp);
|
||||
|
||||
return false;
|
||||
} // end of SetArrayOptions
|
||||
|
||||
|
@ -606,188 +606,188 @@ void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n)
|
|||
|
||||
} // end of SetJsonValue
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: */
|
||||
/***********************************************************************/
|
||||
void JSONCOL::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
if (!Tjp->SameRow || Xnod >= Tjp->SameRow)
|
||||
Value->SetValue_pval(GetColumnValue(g, Tjp->Row, 0));
|
||||
|
||||
} // end of ReadColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetColumnValue: */
|
||||
/***********************************************************************/
|
||||
PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i)
|
||||
{
|
||||
int n = Nod - 1;
|
||||
int nextsame = 0;
|
||||
bool expd = false;
|
||||
PJAR arp;
|
||||
PJVAL val = NULL;
|
||||
|
||||
//for (; i < Nod-1 && row; i++) {
|
||||
for (; i < Nod && row; i++) {
|
||||
if (Nodes[i].Op == OP_NUM) {
|
||||
Value->SetValue(row->GetType() == TYPE_JAR ? row->size() : 1);
|
||||
return(Value);
|
||||
} else switch (row->GetType()) {
|
||||
case TYPE_JOB:
|
||||
if (!Nodes[i].Key) {
|
||||
// Expected Array was not there
|
||||
if (i < Nod-1)
|
||||
continue;
|
||||
else
|
||||
val = new(g) JVALUE(row);
|
||||
|
||||
} else
|
||||
val = ((PJOB)row)->GetValue(Nodes[i].Key);
|
||||
|
||||
break;
|
||||
case TYPE_JAR:
|
||||
arp = (PJAR)row;
|
||||
|
||||
if (!Nodes[i].Key) {
|
||||
if (Nodes[i].Op != OP_NULL) {
|
||||
if (Nodes[i].Rank) {
|
||||
val = arp->GetValue(Nodes[i].Rank - 1);
|
||||
} else if (Nodes[i].Op == OP_XX) {
|
||||
return ExpandArray(g, arp, i);
|
||||
} else
|
||||
return CalculateArray(g, arp, i);
|
||||
|
||||
} else
|
||||
val = NULL;
|
||||
|
||||
} else if (i < Nod-1) {
|
||||
strcpy(g->Message, "Unexpected array");
|
||||
val = NULL; // Not an expected array
|
||||
} else
|
||||
val = arp->GetValue(0);
|
||||
|
||||
break;
|
||||
case TYPE_JVAL:
|
||||
val = (PJVAL)row;
|
||||
break;
|
||||
default:
|
||||
sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
|
||||
val = NULL;
|
||||
} // endswitch Type
|
||||
|
||||
if (i < Nod-1)
|
||||
row = (val) ? val->GetJson() : NULL;
|
||||
|
||||
} // endfor i
|
||||
|
||||
SetJsonValue(g, Value, val, n);
|
||||
return Value;
|
||||
} // end of GetColumnValue
|
||||
|
||||
/***********************************************************************/
|
||||
/* ExpandArray: */
|
||||
/***********************************************************************/
|
||||
PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n)
|
||||
{
|
||||
int ars;
|
||||
PJVAL jvp;
|
||||
JVALUE jval;
|
||||
|
||||
ars = MY_MIN(Tjp->Limit, arp->size());
|
||||
jvp = arp->GetValue(Nodes[n].Nx);
|
||||
|
||||
if (n < Nod - 1 && jvp->GetJson()) {
|
||||
jval.SetValue(GetColumnValue(g, jvp->GetJson(), n + 1));
|
||||
jvp = &jval;
|
||||
} // endif n
|
||||
|
||||
if (n >= Tjp->NextSame) {
|
||||
if (++Nodes[n].Nx == ars) {
|
||||
Nodes[n].Nx = 0;
|
||||
Xnod = 0;
|
||||
} else
|
||||
Xnod = n;
|
||||
|
||||
Tjp->NextSame = Xnod;
|
||||
} // endif NextSame
|
||||
|
||||
SetJsonValue(g, Value, jvp, n);
|
||||
return Value;
|
||||
} // end of ExpandArray
|
||||
|
||||
/***********************************************************************/
|
||||
/* CalculateArray: */
|
||||
/***********************************************************************/
|
||||
PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n)
|
||||
{
|
||||
int i, ars;
|
||||
bool err;
|
||||
OPVAL op = Nodes[n].Op;
|
||||
PVAL val[2], vp = Nodes[n].Valp;
|
||||
PJVAL jvp;
|
||||
JVALUE jval;
|
||||
|
||||
vp->Reset();
|
||||
ars = MY_MIN(Tjp->Limit, arp->size());
|
||||
|
||||
for (i = 0; i < ars; i++) {
|
||||
jvp = arp->GetValue(i);
|
||||
|
||||
if (n < Nod - 1 && jvp->GetJson()) {
|
||||
jval.SetValue(GetColumnValue(g, jvp->GetJson(), n + 1));
|
||||
jvp = &jval;
|
||||
} // endif n
|
||||
|
||||
if (!i) {
|
||||
SetJsonValue(g, vp, jvp, n);
|
||||
continue;
|
||||
} else
|
||||
SetJsonValue(g, MulVal, jvp, n);
|
||||
|
||||
if (!MulVal->IsZero()) {
|
||||
switch (op) {
|
||||
case OP_CNC:
|
||||
if (Nodes[n].CncVal) {
|
||||
val[0] = Nodes[n].CncVal;
|
||||
err = vp->Compute(g, val, 1, op);
|
||||
} // endif CncVal
|
||||
|
||||
val[0] = MulVal;
|
||||
err = vp->Compute(g, val, 1, op);
|
||||
break;
|
||||
case OP_NUM:
|
||||
case OP_SEP:
|
||||
val[0] = Nodes[n].Valp;
|
||||
val[1] = MulVal;
|
||||
err = vp->Compute(g, val, 2, OP_ADD);
|
||||
break;
|
||||
default:
|
||||
val[0] = Nodes[n].Valp;
|
||||
val[1] = MulVal;
|
||||
err = vp->Compute(g, val, 2, op);
|
||||
} // endswitch Op
|
||||
|
||||
if (err)
|
||||
vp->Reset();
|
||||
|
||||
} // endif Zero
|
||||
|
||||
} // endfor i
|
||||
|
||||
if (op == OP_SEP) {
|
||||
// Calculate average
|
||||
MulVal->SetValue(ars);
|
||||
val[0] = vp;
|
||||
val[1] = MulVal;
|
||||
|
||||
if (vp->Compute(g, val, 2, OP_DIV))
|
||||
vp->Reset();
|
||||
|
||||
} // endif Op
|
||||
|
||||
return vp;
|
||||
} // end of CalculateArray
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: */
|
||||
/***********************************************************************/
|
||||
void JSONCOL::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
if (!Tjp->SameRow || Xnod >= Tjp->SameRow)
|
||||
Value->SetValue_pval(GetColumnValue(g, Tjp->Row, 0));
|
||||
|
||||
} // end of ReadColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetColumnValue: */
|
||||
/***********************************************************************/
|
||||
PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i)
|
||||
{
|
||||
int n = Nod - 1;
|
||||
int nextsame = 0;
|
||||
bool expd = false;
|
||||
PJAR arp;
|
||||
PJVAL val = NULL;
|
||||
|
||||
//for (; i < Nod-1 && row; i++) {
|
||||
for (; i < Nod && row; i++) {
|
||||
if (Nodes[i].Op == OP_NUM) {
|
||||
Value->SetValue(row->GetType() == TYPE_JAR ? row->size() : 1);
|
||||
return(Value);
|
||||
} else switch (row->GetType()) {
|
||||
case TYPE_JOB:
|
||||
if (!Nodes[i].Key) {
|
||||
// Expected Array was not there
|
||||
if (i < Nod-1)
|
||||
continue;
|
||||
else
|
||||
val = new(g) JVALUE(row);
|
||||
|
||||
} else
|
||||
val = ((PJOB)row)->GetValue(Nodes[i].Key);
|
||||
|
||||
break;
|
||||
case TYPE_JAR:
|
||||
arp = (PJAR)row;
|
||||
|
||||
if (!Nodes[i].Key) {
|
||||
if (Nodes[i].Op != OP_NULL) {
|
||||
if (Nodes[i].Rank) {
|
||||
val = arp->GetValue(Nodes[i].Rank - 1);
|
||||
} else if (Nodes[i].Op == OP_XX) {
|
||||
return ExpandArray(g, arp, i);
|
||||
} else
|
||||
return CalculateArray(g, arp, i);
|
||||
|
||||
} else
|
||||
val = NULL;
|
||||
|
||||
} else if (i < Nod-1) {
|
||||
strcpy(g->Message, "Unexpected array");
|
||||
val = NULL; // Not an expected array
|
||||
} else
|
||||
val = arp->GetValue(0);
|
||||
|
||||
break;
|
||||
case TYPE_JVAL:
|
||||
val = (PJVAL)row;
|
||||
break;
|
||||
default:
|
||||
sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
|
||||
val = NULL;
|
||||
} // endswitch Type
|
||||
|
||||
if (i < Nod-1)
|
||||
row = (val) ? val->GetJson() : NULL;
|
||||
|
||||
} // endfor i
|
||||
|
||||
SetJsonValue(g, Value, val, n);
|
||||
return Value;
|
||||
} // end of GetColumnValue
|
||||
|
||||
/***********************************************************************/
|
||||
/* ExpandArray: */
|
||||
/***********************************************************************/
|
||||
PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n)
|
||||
{
|
||||
int ars;
|
||||
PJVAL jvp;
|
||||
JVALUE jval;
|
||||
|
||||
ars = MY_MIN(Tjp->Limit, arp->size());
|
||||
jvp = arp->GetValue(Nodes[n].Nx);
|
||||
|
||||
if (n < Nod - 1 && jvp->GetJson()) {
|
||||
jval.SetValue(GetColumnValue(g, jvp->GetJson(), n + 1));
|
||||
jvp = &jval;
|
||||
} // endif n
|
||||
|
||||
if (n >= Tjp->NextSame) {
|
||||
if (++Nodes[n].Nx == ars) {
|
||||
Nodes[n].Nx = 0;
|
||||
Xnod = 0;
|
||||
} else
|
||||
Xnod = n;
|
||||
|
||||
Tjp->NextSame = Xnod;
|
||||
} // endif NextSame
|
||||
|
||||
SetJsonValue(g, Value, jvp, n);
|
||||
return Value;
|
||||
} // end of ExpandArray
|
||||
|
||||
/***********************************************************************/
|
||||
/* CalculateArray: */
|
||||
/***********************************************************************/
|
||||
PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n)
|
||||
{
|
||||
int i, ars;
|
||||
bool err;
|
||||
OPVAL op = Nodes[n].Op;
|
||||
PVAL val[2], vp = Nodes[n].Valp;
|
||||
PJVAL jvp;
|
||||
JVALUE jval;
|
||||
|
||||
vp->Reset();
|
||||
ars = MY_MIN(Tjp->Limit, arp->size());
|
||||
|
||||
for (i = 0; i < ars; i++) {
|
||||
jvp = arp->GetValue(i);
|
||||
|
||||
if (n < Nod - 1 && jvp->GetJson()) {
|
||||
jval.SetValue(GetColumnValue(g, jvp->GetJson(), n + 1));
|
||||
jvp = &jval;
|
||||
} // endif n
|
||||
|
||||
if (!i) {
|
||||
SetJsonValue(g, vp, jvp, n);
|
||||
continue;
|
||||
} else
|
||||
SetJsonValue(g, MulVal, jvp, n);
|
||||
|
||||
if (!MulVal->IsZero()) {
|
||||
switch (op) {
|
||||
case OP_CNC:
|
||||
if (Nodes[n].CncVal) {
|
||||
val[0] = Nodes[n].CncVal;
|
||||
err = vp->Compute(g, val, 1, op);
|
||||
} // endif CncVal
|
||||
|
||||
val[0] = MulVal;
|
||||
err = vp->Compute(g, val, 1, op);
|
||||
break;
|
||||
case OP_NUM:
|
||||
case OP_SEP:
|
||||
val[0] = Nodes[n].Valp;
|
||||
val[1] = MulVal;
|
||||
err = vp->Compute(g, val, 2, OP_ADD);
|
||||
break;
|
||||
default:
|
||||
val[0] = Nodes[n].Valp;
|
||||
val[1] = MulVal;
|
||||
err = vp->Compute(g, val, 2, op);
|
||||
} // endswitch Op
|
||||
|
||||
if (err)
|
||||
vp->Reset();
|
||||
|
||||
} // endif Zero
|
||||
|
||||
} // endfor i
|
||||
|
||||
if (op == OP_SEP) {
|
||||
// Calculate average
|
||||
MulVal->SetValue(ars);
|
||||
val[0] = vp;
|
||||
val[1] = MulVal;
|
||||
|
||||
if (vp->Compute(g, val, 2, OP_DIV))
|
||||
vp->Reset();
|
||||
|
||||
} // endif Op
|
||||
|
||||
return vp;
|
||||
} // end of CalculateArray
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetRow: Get the object containing this column. */
|
||||
/***********************************************************************/
|
||||
|
@ -811,13 +811,13 @@ PJSON JSONCOL::GetRow(PGLOBAL g)
|
|||
if (Nodes[i].Op != OP_NULL) {
|
||||
arp = (PJAR)row;
|
||||
|
||||
if (Nodes[i].Rank)
|
||||
val = arp->GetValue(Nodes[i].Rank - 1);
|
||||
else
|
||||
val = arp->GetValue(Nodes[i].Nx);
|
||||
|
||||
} else
|
||||
val = NULL;
|
||||
if (Nodes[i].Rank)
|
||||
val = arp->GetValue(Nodes[i].Rank - 1);
|
||||
else
|
||||
val = arp->GetValue(Nodes[i].Nx);
|
||||
|
||||
} else
|
||||
val = NULL;
|
||||
|
||||
} else {
|
||||
strcpy(g->Message, "Unexpected array");
|
||||
|
|
|
@ -66,8 +66,8 @@
|
|||
#include "plgdbsem.h"
|
||||
#include "mycat.h"
|
||||
#include "xtable.h"
|
||||
#include "tabodbc.h"
|
||||
#include "odbccat.h"
|
||||
#include "tabodbc.h"
|
||||
#include "tabmul.h"
|
||||
#include "reldef.h"
|
||||
#include "tabcol.h"
|
||||
|
@ -93,9 +93,10 @@ bool ExactInfo(void);
|
|||
/***********************************************************************/
|
||||
ODBCDEF::ODBCDEF(void)
|
||||
{
|
||||
Connect= Tabname= Tabschema= Tabcat= Srcdef= Qchar= Qrystr= Sep= NULL;
|
||||
Connect = Tabname = Tabschema = Username = Password = NULL;
|
||||
Tabcat = Srcdef = Qchar = Qrystr = Sep = NULL;
|
||||
Catver = Options = Cto = Qto = Quoted = Maxerr = Maxres = 0;
|
||||
Scrollable = Memory = Xsrc = false;
|
||||
Scrollable = Memory = Xsrc = UseCnc = false;
|
||||
} // end of ODBCDEF constructor
|
||||
|
||||
/***********************************************************************/
|
||||
|
@ -117,6 +118,8 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
|||
Tabschema = GetStringCatInfo(g, "Schema", Tabschema);
|
||||
Tabcat = GetStringCatInfo(g, "Qualifier", NULL);
|
||||
Tabcat = GetStringCatInfo(g, "Catalog", Tabcat);
|
||||
Username = GetStringCatInfo(g, "User", NULL);
|
||||
Password = GetStringCatInfo(g, "Password", NULL);
|
||||
|
||||
if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL)))
|
||||
Read_Only = true;
|
||||
|
@ -133,6 +136,7 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
|||
Cto= GetIntCatInfo("ConnectTimeout", DEFAULT_LOGIN_TIMEOUT);
|
||||
Qto= GetIntCatInfo("QueryTimeout", DEFAULT_QUERY_TIMEOUT);
|
||||
Scrollable = GetBoolCatInfo("Scrollable", false);
|
||||
UseCnc = GetBoolCatInfo("UseDSN", false);
|
||||
Memory = GetBoolCatInfo("Memory", false);
|
||||
Pseudo = 2; // FILID is Ok but not ROWID
|
||||
return false;
|
||||
|
@ -190,34 +194,40 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
|
|||
Connect = tdp->Connect;
|
||||
TableName = tdp->Tabname;
|
||||
Schema = tdp->Tabschema;
|
||||
Ops.User = tdp->Username;
|
||||
Ops.Pwd = tdp->Password;
|
||||
Catalog = tdp->Tabcat;
|
||||
Srcdef = tdp->Srcdef;
|
||||
Qrystr = tdp->Qrystr;
|
||||
Sep = tdp->GetSep();
|
||||
Options = tdp->Options;
|
||||
Cto = tdp->Cto;
|
||||
Qto = tdp->Qto;
|
||||
Ops.Cto = tdp->Cto;
|
||||
Ops.Qto = tdp->Qto;
|
||||
Quoted = MY_MAX(0, tdp->GetQuoted());
|
||||
Rows = tdp->GetElemt();
|
||||
Catver = tdp->Catver;
|
||||
Memory = (tdp->Memory) ? 1 : 0;
|
||||
Scrollable = tdp->Scrollable;
|
||||
Ops.UseCnc = tdp->UseCnc;
|
||||
} else {
|
||||
Connect = NULL;
|
||||
TableName = NULL;
|
||||
Schema = NULL;
|
||||
Ops.User = NULL;
|
||||
Ops.Pwd = NULL;
|
||||
Catalog = NULL;
|
||||
Srcdef = NULL;
|
||||
Qrystr = NULL;
|
||||
Sep = 0;
|
||||
Options = 0;
|
||||
Cto = DEFAULT_LOGIN_TIMEOUT;
|
||||
Qto = DEFAULT_QUERY_TIMEOUT;
|
||||
Ops.Cto = DEFAULT_LOGIN_TIMEOUT;
|
||||
Ops.Qto = DEFAULT_QUERY_TIMEOUT;
|
||||
Quoted = 0;
|
||||
Rows = 0;
|
||||
Catver = 0;
|
||||
Memory = 0;
|
||||
Scrollable = false;
|
||||
Ops.UseCnc = false;
|
||||
} // endif tdp
|
||||
|
||||
Quote = NULL;
|
||||
|
@ -242,6 +252,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
|
|||
Connect = tdbp->Connect;
|
||||
TableName = tdbp->TableName;
|
||||
Schema = tdbp->Schema;
|
||||
Ops = tdbp->Ops;
|
||||
Catalog = tdbp->Catalog;
|
||||
Srcdef = tdbp->Srcdef;
|
||||
Qrystr = tdbp->Qrystr;
|
||||
|
@ -254,8 +265,6 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
|
|||
MulConn = tdbp->MulConn;
|
||||
DBQ = tdbp->DBQ;
|
||||
Options = tdbp->Options;
|
||||
Cto = tdbp->Cto;
|
||||
Qto = tdbp->Qto;
|
||||
Quoted = tdbp->Quoted;
|
||||
Rows = tdbp->Rows;
|
||||
Fpos = tdbp->Fpos;
|
||||
|
@ -698,10 +707,7 @@ int TDBODBC::Cardinality(PGLOBAL g)
|
|||
char qry[96], tbn[64];
|
||||
ODBConn *ocp = new(g) ODBConn(g, this);
|
||||
|
||||
ocp->SetLoginTimeout((DWORD)Cto);
|
||||
ocp->SetQueryTimeout((DWORD)Qto);
|
||||
|
||||
if (ocp->Open(Connect, Options) < 1)
|
||||
if (ocp->Open(Connect, &Ops, Options) < 1)
|
||||
return -1;
|
||||
|
||||
// Table name can be encoded in UTF-8
|
||||
|
@ -802,14 +808,12 @@ bool TDBODBC::OpenDB(PGLOBAL g)
|
|||
/* and if so to allocate just a new result set. But this only for */
|
||||
/* drivers allowing concurency in getting results ??? */
|
||||
/*********************************************************************/
|
||||
if (!Ocp) {
|
||||
if (!Ocp)
|
||||
Ocp = new(g) ODBConn(g, this);
|
||||
Ocp->SetLoginTimeout((DWORD)Cto);
|
||||
Ocp->SetQueryTimeout((DWORD)Qto);
|
||||
} else if (Ocp->IsOpen())
|
||||
else if (Ocp->IsOpen())
|
||||
Ocp->Close();
|
||||
|
||||
if (Ocp->Open(Connect, Options) < 1)
|
||||
if (Ocp->Open(Connect, &Ops, Options) < 1)
|
||||
return true;
|
||||
else if (Quoted)
|
||||
Quote = Ocp->GetQuoteChar();
|
||||
|
@ -1415,12 +1419,10 @@ bool TDBXDBC::OpenDB(PGLOBAL g)
|
|||
/*********************************************************************/
|
||||
if (!Ocp) {
|
||||
Ocp = new(g) ODBConn(g, this);
|
||||
Ocp->SetLoginTimeout((DWORD)Cto);
|
||||
Ocp->SetQueryTimeout((DWORD)Qto);
|
||||
} else if (Ocp->IsOpen())
|
||||
Ocp->Close();
|
||||
|
||||
if (Ocp->Open(Connect, Options) < 1)
|
||||
if (Ocp->Open(Connect, &Ops, Options) < 1)
|
||||
return true;
|
||||
|
||||
Use = USE_OPEN; // Do it now in case we are recursively called
|
||||
|
@ -1554,8 +1556,10 @@ TDBOTB::TDBOTB(PODEF tdp) : TDBDRV(tdp)
|
|||
Dsn = tdp->GetConnect();
|
||||
Schema = tdp->GetTabschema();
|
||||
Tab = tdp->GetTabname();
|
||||
Cto = tdp->Cto;
|
||||
Qto = tdp->Qto;
|
||||
Ops.User = tdp->Username;
|
||||
Ops.Pwd = tdp->Password;
|
||||
Ops.Cto = tdp->Cto;
|
||||
Ops.Qto = tdp->Qto;
|
||||
} // end of TDBOTB constructor
|
||||
|
||||
/***********************************************************************/
|
||||
|
@ -1563,7 +1567,7 @@ TDBOTB::TDBOTB(PODEF tdp) : TDBDRV(tdp)
|
|||
/***********************************************************************/
|
||||
PQRYRES TDBOTB::GetResult(PGLOBAL g)
|
||||
{
|
||||
return ODBCTables(g, Dsn, Schema, Tab, Maxres, Cto, Qto, false);
|
||||
return ODBCTables(g, Dsn, Schema, Tab, Maxres, false, &Ops);
|
||||
} // end of GetResult
|
||||
|
||||
/* ---------------------------TDBOCL class --------------------------- */
|
||||
|
@ -1573,7 +1577,7 @@ PQRYRES TDBOTB::GetResult(PGLOBAL g)
|
|||
/***********************************************************************/
|
||||
PQRYRES TDBOCL::GetResult(PGLOBAL g)
|
||||
{
|
||||
return ODBCColumns(g, Dsn, Schema, Tab, NULL, Maxres, Cto, Qto, false);
|
||||
return ODBCColumns(g, Dsn, Schema, Tab, NULL, Maxres, false, &Ops);
|
||||
} // end of GetResult
|
||||
|
||||
/* ------------------------ End of Tabodbc --------------------------- */
|
||||
|
|
|
@ -50,6 +50,8 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
|
|||
PSZ Connect; /* ODBC connection string */
|
||||
PSZ Tabname; /* External table name */
|
||||
PSZ Tabschema; /* External table schema */
|
||||
PSZ Username; /* User connect name */
|
||||
PSZ Password; /* Password connect info */
|
||||
PSZ Tabcat; /* External table catalog */
|
||||
PSZ Srcdef; /* The source table SQL definition */
|
||||
PSZ Qchar; /* Identifier quoting character */
|
||||
|
@ -65,6 +67,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
|
|||
bool Scrollable; /* Use scrollable cursor */
|
||||
bool Memory; /* Put result set in memory */
|
||||
bool Xsrc; /* Execution type */
|
||||
bool UseCnc; /* Use SQLConnect (!SQLDriverConnect) */
|
||||
}; // end of ODBCDEF
|
||||
|
||||
#if !defined(NODBC)
|
||||
|
@ -124,9 +127,12 @@ class TDBODBC : public TDBASE {
|
|||
// Members
|
||||
ODBConn *Ocp; // Points to an ODBC connection class
|
||||
ODBCCOL *Cnp; // Points to count(*) column
|
||||
ODBCPARM Ops; // Additional parameters
|
||||
char *Connect; // Points to connection string
|
||||
char *TableName; // Points to ODBC table name
|
||||
char *Schema; // Points to ODBC table Schema
|
||||
char *User; // User connect info
|
||||
char *Pwd; // Password connect info
|
||||
char *Catalog; // Points to ODBC table Catalog
|
||||
char *Srcdef; // The source table SQL definition
|
||||
char *Query; // Points to SQL statement
|
||||
|
@ -151,6 +157,7 @@ class TDBODBC : public TDBASE {
|
|||
int Nparm; // The number of statement parameters
|
||||
int Memory; // 0: No 1: Alloc 2: Put 3: Get
|
||||
bool Scrollable; // Use scrollable cursor
|
||||
bool UseCnc; // Use SQLConnect (!SQLDriverConnect)
|
||||
PQRYRES Qrp; // Points to storage result
|
||||
}; // end of class TDBODBC
|
||||
|
||||
|
@ -316,8 +323,7 @@ class TDBOTB : public TDBDRV {
|
|||
char *Dsn; // Points to connection string
|
||||
char *Schema; // Points to schema name or NULL
|
||||
char *Tab; // Points to ODBC table name or pattern
|
||||
int Cto; // Connect timeout
|
||||
int Qto; // Query timeout
|
||||
ODBCPARM Ops; // Additional parameters
|
||||
}; // end of class TDBOTB
|
||||
|
||||
/***********************************************************************/
|
||||
|
|
|
@ -352,7 +352,9 @@ bool TDBTBL::TestFil(PGLOBAL g, PCFIL filp, PTABLE tabp)
|
|||
/***********************************************************************/
|
||||
int TDBTBL::Cardinality(PGLOBAL g)
|
||||
{
|
||||
if (Cardinal < 0) {
|
||||
if (!g)
|
||||
return 0; // Cannot make the table list
|
||||
else if (Cardinal < 0) {
|
||||
int tsz;
|
||||
|
||||
if (!Tablist && InitTableList(g))
|
||||
|
|
Loading…
Add table
Reference in a new issue