Commit 357f4d83 authored by Sergei Golubchik's avatar Sergei Golubchik

Merge branch 'connect/10.1' into 10.1

parents 40405656 4a624807
...@@ -232,6 +232,27 @@ int main() { ...@@ -232,6 +232,27 @@ int main() {
ENDIF(UNIX) ENDIF(UNIX)
ENDIF(CONNECT_WITH_ODBC) ENDIF(CONNECT_WITH_ODBC)
#
# JDBC
#
OPTION(CONNECT_WITH_JDBC "Compile CONNECT storage engine with JDBC support" ON)
IF(CONNECT_WITH_JDBC)
# TODO: detect Java SDK and the presence of JDBC connectors
# Find required libraries and include directories
# Find how to compile and install the JdbcInterface.java class
IF(JDBC_OK)
INCLUDE_DIRECTORIES(${JDBC_INCLUDE_DIR})
add_definitions(-DJDBC_SUPPORT)
SET(CONNECT_SOURCES ${CONNECT_SOURCES}
JdbcInterface.java tabjdbc.cpp jdbconn.cpp jdbccat.h jdbconn.h tabjdbc.h)
ELSE()
SET(JDBC_LIBRARY "")
ENDIF()
ENDIF(CONNECT_WITH_JDBC)
# #
# XMAP # XMAP
...@@ -252,5 +273,5 @@ MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES} ...@@ -252,5 +273,5 @@ MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES}
COMPONENT connect-engine COMPONENT connect-engine
RECOMPILE_FOR_EMBEDDED RECOMPILE_FOR_EMBEDDED
LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY} LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY}
${ODBC_LIBRARY} ${IPHLPAPI_LIBRARY}) ${ODBC_LIBRARY} ${JDBC_LIBRARY} ${IPHLPAPI_LIBRARY})
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
based on external data. Principally they are based on plain files of many based on external data. Principally they are based on plain files of many
different types, but also on collections of such files, collection of tables, different types, but also on collections of such files, collection of tables,
local or remote MySQL/MariaDB tables retrieved via MySQL API, local or remote MySQL/MariaDB tables retrieved via MySQL API,
ODBC tables retrieving data from other DBMS having an ODBC server, and even ODBC/JDBC tables retrieving data from other DBMS having an ODBC/JDBC server,
virtual tables. and even virtual tables.
@details @details
ha_connect will let you create/open/delete tables, the created table can be ha_connect will let you create/open/delete tables, the created table can be
...@@ -115,9 +115,6 @@ ...@@ -115,9 +115,6 @@
#include "sql_parse.h" #include "sql_parse.h"
#include "sql_base.h" #include "sql_base.h"
#include <sys/stat.h> #include <sys/stat.h>
#if defined(NEW_WAY)
#include "sql_table.h"
#endif // NEW_WAY
#include "sql_partition.h" #include "sql_partition.h"
#undef OFFSET #undef OFFSET
...@@ -130,6 +127,9 @@ ...@@ -130,6 +127,9 @@
#if defined(ODBC_SUPPORT) #if defined(ODBC_SUPPORT)
#include "odbccat.h" #include "odbccat.h"
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
#if defined(JDBC_SUPPORT)
#include "jdbccat.h"
#endif // JDBC_SUPPORT
#include "xtable.h" #include "xtable.h"
#include "tabmysql.h" #include "tabmysql.h"
#include "filamdbf.h" #include "filamdbf.h"
...@@ -197,6 +197,7 @@ PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); ...@@ -197,6 +197,7 @@ PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info);
PQRYRES VirColumns(PGLOBAL g, bool info); PQRYRES VirColumns(PGLOBAL g, bool info);
PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info); PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info);
PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info); PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info);
int TranslateJDBCType(int stp, int prec, int& len, char& v);
void PushWarning(PGLOBAL g, THD *thd, int level); void PushWarning(PGLOBAL g, THD *thd, int level);
bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host, bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host,
const char *db, char *tab, const char *src, int port); const char *db, char *tab, const char *src, int port);
...@@ -1758,9 +1759,10 @@ int ha_connect::OpenTable(PGLOBAL g, bool del) ...@@ -1758,9 +1759,10 @@ int ha_connect::OpenTable(PGLOBAL g, bool del)
break; break;
} // endswitch xmode } // endswitch xmode
if (xmod != MODE_INSERT || tdbp->GetAmType() == TYPE_AM_ODBC if (xmod != MODE_INSERT || tdbp->GetAmType() == TYPE_AM_MYSQL
|| tdbp->GetAmType() == TYPE_AM_MYSQL) { || tdbp->GetAmType() == TYPE_AM_ODBC
// Get the list of used fields (columns) || tdbp->GetAmType() == TYPE_AM_JDBC) {
// Get the list of used fields (columns)
char *p; char *p;
unsigned int k1, k2, n1, n2; unsigned int k1, k2, n1, n2;
Field* *field; Field* *field;
...@@ -2077,8 +2079,9 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *) ...@@ -2077,8 +2079,9 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *)
continue; // Is a virtual column possible here ??? continue; // Is a virtual column possible here ???
if ((xmod == MODE_INSERT && tdbp->GetAmType() != TYPE_AM_MYSQL if ((xmod == MODE_INSERT && tdbp->GetAmType() != TYPE_AM_MYSQL
&& tdbp->GetAmType() != TYPE_AM_ODBC) || && tdbp->GetAmType() != TYPE_AM_ODBC
bitmap_is_set(table->write_set, fp->field_index)) { && tdbp->GetAmType() != TYPE_AM_JDBC) ||
bitmap_is_set(table->write_set, fp->field_index)) {
for (colp= tp->GetSetCols(); colp; colp= colp->GetNext()) for (colp= tp->GetSetCols(); colp; colp= colp->GetNext())
if (!stricmp(colp->GetName(), fp->field_name)) if (!stricmp(colp->GetName(), fp->field_name))
break; break;
...@@ -2627,7 +2630,7 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond) ...@@ -2627,7 +2630,7 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond)
} // end of CondFilter } // end of CondFilter
/***********************************************************************/ /***********************************************************************/
/* Check the WHERE condition and return a MYSQL/ODBC/WQL filter. */ /* Check the WHERE condition and return a MYSQL/ODBC/JDBC/WQL filter. */
/***********************************************************************/ /***********************************************************************/
PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
{ {
...@@ -2635,8 +2638,8 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) ...@@ -2635,8 +2638,8 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
char *body= filp->Body; char *body= filp->Body;
unsigned int i; unsigned int i;
bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC); bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
bool nonul= (tty == TYPE_AM_ODBC && (tdbp->GetMode() == MODE_INSERT || bool nonul= ((tty == TYPE_AM_ODBC || tty == TYPE_AM_JDBC) &&
tdbp->GetMode() == MODE_DELETE)); (tdbp->GetMode() == MODE_INSERT || tdbp->GetMode() == MODE_DELETE));
OPVAL vop= OP_XX; OPVAL vop= OP_XX;
if (!cond) if (!cond)
...@@ -2958,7 +2961,7 @@ const COND *ha_connect::cond_push(const COND *cond) ...@@ -2958,7 +2961,7 @@ const COND *ha_connect::cond_push(const COND *cond)
bool x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC); bool x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
bool b= (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC || bool b= (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC ||
tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL || tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL ||
tty == TYPE_AM_PLG || x); tty == TYPE_AM_PLG || tty == TYPE_AM_JDBC || x);
// Save stack and allocation environment and prepare error return // Save stack and allocation environment and prepare error return
if (g->jump_level == MAX_JUMP) { if (g->jump_level == MAX_JUMP) {
...@@ -4109,7 +4112,8 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn, bool quick) ...@@ -4109,7 +4112,8 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn, bool quick)
/* Fall through to check FILE_ACL */ /* Fall through to check FILE_ACL */
case TAB_ODBC: case TAB_ODBC:
case TAB_MYSQL: case TAB_JDBC:
case TAB_MYSQL:
case TAB_DIR: case TAB_DIR:
case TAB_MAC: case TAB_MAC:
case TAB_WMI: case TAB_WMI:
...@@ -5131,11 +5135,18 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5131,11 +5135,18 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
int port= 0, hdr= 0, mxr= 0, mxe= 0, rc= 0; int port= 0, hdr= 0, mxr= 0, mxe= 0, rc= 0;
int cop __attribute__((unused))= 0, lrecl= 0; int cop __attribute__((unused))= 0, lrecl= 0;
#if defined(ODBC_SUPPORT) #if defined(ODBC_SUPPORT)
POPARM sop = NULL; POPARM sop= NULL;
char *ucnc = NULL; char *ucnc= NULL;
bool cnc= false; bool cnc= false;
int cto= -1, qto= -1; int cto= -1, qto= -1;
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
#if defined(JDBC_SUPPORT)
PJPARM sjp= NULL;
char *jpath= NULL;
char *driver= NULL;
char *url= NULL;
char *tabtyp = NULL;
#endif // JDBC_SUPPORT
uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL); uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL);
bool bif, ok= false, dbf= false; bool bif, ok= false, dbf= false;
TABTYPE ttp= TAB_UNDEF; TABTYPE ttp= TAB_UNDEF;
...@@ -5146,15 +5157,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5146,15 +5157,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
PDBUSER dup= PlgGetUser(g); PDBUSER dup= PlgGetUser(g);
PCATLG cat= (dup) ? dup->Catalog : NULL; PCATLG cat= (dup) ? dup->Catalog : NULL;
PTOS topt= table_s->option_struct; PTOS topt= table_s->option_struct;
#if defined(NEW_WAY)
//CHARSET_INFO *cs;
Alter_info alter_info;
#else // !NEW_WAY
char buf[1024]; char buf[1024];
String sql(buf, sizeof(buf), system_charset_info); String sql(buf, sizeof(buf), system_charset_info);
sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info); sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info);
#endif // !NEW_WAY
if (!g) if (!g)
return HA_ERR_INTERNAL_ERROR; return HA_ERR_INTERNAL_ERROR;
...@@ -5202,6 +5208,12 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5202,6 +5208,12 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
if ((ucnc= GetListOption(g, "UseDSN", topt->oplist))) if ((ucnc= GetListOption(g, "UseDSN", topt->oplist)))
cnc= (!*ucnc || *ucnc == 'y' || *ucnc == 'Y' || atoi(ucnc) != 0); cnc= (!*ucnc || *ucnc == 'y' || *ucnc == 'Y' || atoi(ucnc) != 0);
#endif #endif
#if defined(JDBC_SUPPORT)
jpath= GetListOption(g, "Jpath", topt->oplist, NULL);
driver= GetListOption(g, "Driver", topt->oplist, NULL);
url= GetListOption(g, "URL", topt->oplist, NULL);
tabtyp = GetListOption(g, "Tabtype", topt->oplist, NULL);
#endif // JDBC_SUPPORT
mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0")); mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0"));
#if defined(PROMPT_OK) #if defined(PROMPT_OK)
cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0")); cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0"));
...@@ -5262,44 +5274,62 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5262,44 +5274,62 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
} else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL))) } else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL)))
tab= table_s->table_name.str; // Default value tab= table_s->table_name.str; // Default value
#if defined(NEW_WAY)
// add_option(thd, create_info, "tabname", tab);
#endif // NEW_WAY
} // endif tab } // endif tab
switch (ttp) { switch (ttp) {
#if defined(ODBC_SUPPORT) #if defined(ODBC_SUPPORT)
case TAB_ODBC: case TAB_ODBC:
dsn= strz(g, create_info->connect_string); dsn= strz(g, create_info->connect_string);
if (fnc & (FNC_DSN | FNC_DRIVER)) { if (fnc & (FNC_DSN | FNC_DRIVER)) {
ok= true; ok= true;
#if defined(PROMPT_OK) #if defined(PROMPT_OK)
} else if (!stricmp(thd->main_security_ctx.host, "localhost") } else if (!stricmp(thd->main_security_ctx.host, "localhost")
&& cop == 1) { && cop == 1) {
if ((dsn = ODBCCheckConnection(g, dsn, cop)) != NULL) { if ((dsn = ODBCCheckConnection(g, dsn, cop)) != NULL) {
thd->make_lex_string(&create_info->connect_string, dsn, strlen(dsn)); thd->make_lex_string(&create_info->connect_string, dsn, strlen(dsn));
ok= true; ok= true;
} // endif dsn } // endif dsn
#endif // PROMPT_OK #endif // PROMPT_OK
} else if (!dsn) { } else if (!dsn) {
sprintf(g->Message, "Missing %s connection string", topt->type); sprintf(g->Message, "Missing %s connection string", topt->type);
} else { } else {
// Store ODBC additional parameters // Store ODBC additional parameters
sop= (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM)); sop= (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM));
sop->User= (char*)user; sop->User= (char*)user;
sop->Pwd= (char*)pwd; sop->Pwd= (char*)pwd;
sop->Cto= cto; sop->Cto= cto;
sop->Qto= qto; sop->Qto= qto;
sop->UseCnc= cnc; sop->UseCnc= cnc;
ok= true; ok= true;
} // endif's } // endif's
supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER); supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER);
break; break;
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
case TAB_DBF: #if defined(JDBC_SUPPORT)
case TAB_JDBC:
if (fnc & FNC_DRIVER) {
ok= true;
} else if (!url) {
strcpy(g->Message, "Missing URL");
} else {
// Store ODBC additional parameters
sjp= (PJPARM)PlugSubAlloc(g, NULL, sizeof(JDBCPARM));
sjp->Driver= driver;
sjp->Url= url;
sjp->User= (char*)user;
sjp->Pwd= (char*)pwd;
sjp->Fsize= 0;
sjp->Scrollable= false;
ok= true;
} // endif's
supfnc |= (FNC_DRIVER | FNC_TABLE);
break;
#endif // JDBC_SUPPORT
case TAB_DBF:
dbf= true; dbf= true;
// Passthru // Passthru
case TAB_CSV: case TAB_CSV:
...@@ -5418,7 +5448,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5418,7 +5448,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
dpath= SetPath(g, table_s->db.str); dpath= SetPath(g, table_s->db.str);
if (src && ttp != TAB_PIVOT && ttp != TAB_ODBC) { if (src && ttp != TAB_PIVOT && ttp != TAB_ODBC && ttp != TAB_JDBC) {
qrp= SrcColumns(g, host, db, user, pwd, src, port); qrp= SrcColumns(g, host, db, user, pwd, src, port);
if (qrp && ttp == TAB_OCCUR) if (qrp && ttp == TAB_OCCUR)
...@@ -5460,7 +5490,38 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5460,7 +5490,38 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
break; break;
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
case TAB_MYSQL: #if defined(JDBC_SUPPORT)
case TAB_JDBC:
switch (fnc) {
case FNC_NO:
case FNC_COL:
if (src) {
qrp= JDBCSrcCols(g, jpath, (char*)src, sjp);
src= NULL; // for next tests
} else
qrp= JDBCColumns(g, jpath, shm, tab, NULL,
mxr, fnc == FNC_COL, sjp);
break;
case FNC_TABLE:
qrp= JDBCTables(g, dsn, shm, tab, tabtyp, mxr, true, sjp);
break;
#if 0
case FNC_DSN:
qrp= JDBCDataSources(g, mxr, true);
break;
#endif // 0
case FNC_DRIVER:
qrp= JDBCDrivers(g, jpath, mxr, true);
break;
default:
sprintf(g->Message, "invalid catfunc %s", fncn);
break;
} // endswitch info
break;
#endif // JDBC_SUPPORT
case TAB_MYSQL:
qrp= MyColumns(g, thd, host, db, user, pwd, tab, qrp= MyColumns(g, thd, host, db, user, pwd, tab,
NULL, port, fnc == FNC_COL); NULL, port, fnc == FNC_COL);
break; break;
...@@ -5533,14 +5594,9 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5533,14 +5594,9 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
len= 256; // STRBLK's have 0 length len= 256; // STRBLK's have 0 length
// Now add the field // Now add the field
#if defined(NEW_WAY)
rc= add_fields(g, thd, &alter_info, cnm, typ, len, dec,
tm, "", flg, dbf, v);
#else // !NEW_WAY
if (add_field(&sql, cnm, typ, len, dec, NULL, tm, if (add_field(&sql, cnm, typ, len, dec, NULL, tm,
NULL, NULL, NULL, NULL, flg, dbf, v)) NULL, NULL, NULL, NULL, flg, dbf, v))
rc= HA_ERR_OUT_OF_MEM; rc= HA_ERR_OUT_OF_MEM;
#endif // !NEW_WAY
} // endfor crp } // endfor crp
} else { } else {
...@@ -5563,12 +5619,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5563,12 +5619,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
cnm= (char*)"noname"; cnm= (char*)"noname";
dft= xtra= key= fmt= NULL; dft= xtra= key= fmt= NULL;
v= ' '; v= ' ';
#if defined(NEW_WAY)
rem= "";
// cs= NULL;
#else // !NEW_WAY
rem= NULL; rem= NULL;
#endif // !NEW_WAY
for (crp= qrp->Colresp; crp; crp= crp->Next) for (crp= qrp->Colresp; crp; crp= crp->Next)
switch (crp->Fld) { switch (crp->Fld) {
...@@ -5637,10 +5688,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5637,10 +5688,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
"Several %s tables found, specify DBNAME", tab); "Several %s tables found, specify DBNAME", tab);
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
goto err; goto err;
} else if (!schem) } else if (!schem)
schem= crp->Kdata->GetCharValue(i); schem= crp->Kdata->GetCharValue(i);
} // endif ttp } // endif ttp
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
default: default:
break; // Ignore break; // Ignore
...@@ -5689,7 +5740,42 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5689,7 +5740,42 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
} else } else
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
// Make the arguments as required by add_fields #if defined(JDBC_SUPPORT)
if (ttp == TAB_JDBC) {
int plgtyp;
// typ must be PLG type, not SQL type
if (!(plgtyp= TranslateJDBCType(typ, dec, prec, v))) {
if (GetTypeConv() == TPC_SKIP) {
// Skip this column
sprintf(g->Message, "Column %s skipped (unsupported type %d)",
cnm, typ);
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
continue;
} else {
sprintf(g->Message, "Unsupported SQL type %d", typ);
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
goto err;
} // endif type_conv
} else
typ= plgtyp;
switch (typ) {
case TYPE_DOUBLE:
// Some data sources do not count dec in length (prec)
prec += (dec + 2); // To be safe
break;
case TYPE_DECIM:
prec= len;
break;
default:
dec= 0;
} // endswitch typ
} else
#endif // ODBC_SUPPORT
// Make the arguments as required by add_fields
if (typ == TYPE_DOUBLE) if (typ == TYPE_DOUBLE)
prec= len; prec= len;
...@@ -5697,25 +5783,15 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5697,25 +5783,15 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
prec= 0; prec= 0;
// Now add the field // Now add the field
#if defined(NEW_WAY)
rc= add_fields(g, thd, &alter_info, cnm, typ, prec, dec,
tm, rem, 0, dbf, v);
#else // !NEW_WAY
if (add_field(&sql, cnm, typ, prec, dec, key, tm, rem, dft, xtra, if (add_field(&sql, cnm, typ, prec, dec, key, tm, rem, dft, xtra,
fmt, 0, dbf, v)) fmt, 0, dbf, v))
rc= HA_ERR_OUT_OF_MEM; rc= HA_ERR_OUT_OF_MEM;
#endif // !NEW_WAY
} // endfor i } // endfor i
} // endif fnc } // endif fnc
#if defined(NEW_WAY)
rc= init_table_share(thd, table_s, create_info, &alter_info);
#else // !NEW_WAY
if (!rc) if (!rc)
rc= init_table_share(thd, table_s, create_info, &sql); rc= init_table_share(thd, table_s, create_info, &sql);
// rc= init_table_share(thd, table_s, create_info, dsn, &sql);
#endif // !NEW_WAY
g->jump_level--; g->jump_level--;
return rc; return rc;
......
// Timeout and net wait defaults
#define DEFAULT_LOGIN_TIMEOUT -1 // means do not set
#define DEFAULT_QUERY_TIMEOUT -1 // means do not set
typedef struct jdbc_parms {
int CheckSize(int rows);
char *Driver; // JDBC driver
char *Url; // Driver URL
char *User; // User connect info
char *Pwd; // Password connect info
//int Cto; // Connect timeout
//int Qto; // Query timeout
int Fsize; // Fetch size
bool Scrollable; // Scrollable cursor
} JDBCPARM, *PJPARM;
/***********************************************************************/
/* JDBC catalog function prototypes. */
/***********************************************************************/
#if defined(PROMPT_OK)
char *JDBCCheckConnection(PGLOBAL g, char *dsn, int cop);
#endif // PROMPT_OK
//PQRYRES JDBCDataSources(PGLOBAL g, int maxres, bool info);
PQRYRES JDBCColumns(PGLOBAL g, char *jpath, char *db, char *table,
char *colpat, int maxres, bool info, PJPARM sop);
PQRYRES JDBCSrcCols(PGLOBAL g, char *jpath, char *src, PJPARM sop);
PQRYRES JDBCTables(PGLOBAL g, char *jpath, char *db, char *tabpat,
char *tabtyp, int maxres, bool info, PJPARM sop);
PQRYRES JDBCDrivers(PGLOBAL g, char *jpath, int maxres, bool info);
/************ Jdbconn C++ Functions Source Code File (.CPP) ************/
/* Name: JDBCONN.CPP Version 1.0 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2016 */
/* */
/* This file contains the JDBC connection classes functions. */
/***********************************************************************/
/***********************************************************************/
/* Include relevant MariaDB header file. */
/***********************************************************************/
#include <my_global.h>
#include <m_string.h>
#if defined(__WIN__)
//nclude <io.h>
//nclude <fcntl.h>
#include <direct.h> // for getcwd
#if defined(__BORLANDC__)
#define __MFC_COMPAT__ // To define min/max as macro
#endif
//#include <windows.h>
#else
#if defined(UNIX)
#include <errno.h>
#else
//nclude <io.h>
#endif
//nclude <fcntl.h>
#define NODW
#endif
/***********************************************************************/
/* Required objects includes. */
/***********************************************************************/
#include "global.h"
#include "plgdbsem.h"
#include "xobject.h"
#include "xtable.h"
#include "jdbccat.h"
#include "tabjdbc.h"
//#include "jdbconn.h"
//#include "plgcnx.h" // For DB types
#include "resource.h"
#include "valblk.h"
#include "osutil.h"
#if defined(__WIN__)
extern "C" HINSTANCE s_hModule; // Saved module handle
#endif // __WIN__
int GetConvSize();
/***********************************************************************/
/* Some macro's (should be defined elsewhere to be more accessible) */
/***********************************************************************/
#if defined(_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
/***********************************************************************/
/* GetJDBCType: returns the SQL_TYPE corresponding to a PLG type. */
/***********************************************************************/
static short GetJDBCType(int type)
{
short tp = 0; // NULL
switch (type) {
case TYPE_STRING: tp = 12; break; // VARCHAR
case TYPE_SHORT: tp = 5; break; // SMALLINT
case TYPE_INT: tp = 4; break; // INTEGER
case TYPE_DATE: tp = 93; break; // DATE
//case TYPE_TIME: tp = 92; break; // TIME
//case TYPE_TIMESTAMP: tp = 93; break; // TIMESTAMP
case TYPE_BIGINT: tp = -5; break; // BIGINT
case TYPE_DOUBLE: tp = 8; break; // DOUBLE
case TYPE_TINY: tp = -6; break; // TINYINT
case TYPE_DECIM: tp = 3; break; // DECIMAL
} // endswitch type
return tp;
} // end of GetJDBCType
/***********************************************************************/
/* TranslateJDBCType: translate a JDBC Type to a PLG type. */
/***********************************************************************/
int TranslateJDBCType(int stp, int prec, int& len, char& v)
{
int type;
switch (stp) {
case -1: // LONGVARCHAR
len = MY_MIN(abs(len), GetConvSize());
case 12: // VARCHAR
v = 'V';
case 1: // CHAR
type = TYPE_STRING;
break;
case 2: // NUMERIC
case 3: // DECIMAL
type = TYPE_DECIM;
break;
case 4: // INTEGER
type = TYPE_INT;
break;
case 5: // SMALLINT
type = TYPE_SHORT;
break;
case -6: // TINYINT
case -7: // BIT
type = TYPE_TINY;
break;
case 6: // FLOAT
case 7: // REAL
case 8: // DOUBLE
type = TYPE_DOUBLE;
break;
case 93: // TIMESTAMP
type = TYPE_DATE;
len = 19 + ((prec) ? (prec+1) : 0);
v = 'S';
break;
case 91: // TYPE_DATE
type = TYPE_DATE;
len = 10;
v = 'D';
break;
case 92: // TYPE_TIME
type = TYPE_DATE;
len = 8 + ((prec) ? (prec+1) : 0);
v = 'T';
break;
case -5: // BIGINT
type = TYPE_BIGINT;
break;
case 0: // NULL
case -2: // BINARY
case -3: // VARBINARY
case -4: // LONGVARBINARY
default:
type = TYPE_ERROR;
len = 0;
} // endswitch type
return type;
} // end of TranslateJDBCType
/***********************************************************************/
/* Allocate the structure used to refer to the result set. */
/***********************************************************************/
static JCATPARM *AllocCatInfo(PGLOBAL g, JCATINFO fid, char *db,
char *tab, PQRYRES qrp)
{
size_t m, n;
JCATPARM *cap;
#if defined(_DEBUG)
assert(qrp);
#endif
// Save stack and allocation environment and prepare error return
if (g->jump_level == MAX_JUMP) {
strcpy(g->Message, MSG(TOO_MANY_JUMPS));
return NULL;
} // endif jump_level
if (setjmp(g->jumper[++g->jump_level]) != 0) {
printf("%s\n", g->Message);
cap = NULL;
goto fin;
} // endif rc
m = (size_t)qrp->Maxres;
n = (size_t)qrp->Nbcol;
cap = (JCATPARM *)PlugSubAlloc(g, NULL, sizeof(JCATPARM));
memset(cap, 0, sizeof(JCATPARM));
cap->Id = fid;
cap->Qrp = qrp;
cap->DB = (PUCHAR)db;
cap->Tab = (PUCHAR)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));
fin:
g->jump_level--;
return cap;
} // end of AllocCatInfo
/***********************************************************************/
/* JDBCColumns: constructs the result blocks containing all columns */
/* of a JDBC table that will be retrieved by GetData commands. */
/***********************************************************************/
PQRYRES JDBCColumns(PGLOBAL g, char *jpath, char *db, char *table,
char *colpat, int maxres, bool info, PJPARM sjp)
{
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};
unsigned int 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;
JCATPARM *cap;
JDBConn *jcp = NULL;
/************************************************************************/
/* Do an evaluation of the result size. */
/************************************************************************/
if (!info) {
jcp = new(g)JDBConn(g, NULL);
if (jcp->Open(jpath, sjp) != RC_OK) // openReadOnly + noJDBCdialog
return NULL;
if (table && !strchr(table, '%')) {
// We fix a MySQL limit because some data sources return 32767
n = jcp->GetMaxValue(1); // MAX_COLUMNS_IN_TABLE)
maxres = (n > 0) ? MY_MIN(n, 4096) : 4096;
} else if (!maxres)
maxres = 20000;
// n = jcp->GetMaxValue(2); MAX_CATALOG_NAME_LEN
// length[0] = (n) ? (n + 1) : 0;
// n = jcp->GetMaxValue(3); MAX_SCHEMA_NAME_LEN
// length[1] = (n) ? (n + 1) : 0;
// n = jcp->GetMaxValue(4); MAX_TABLE_NAME_LEN
// length[2] = (n) ? (n + 1) : 0;
n = jcp->GetMaxValue(5); // MAX_COLUMN_NAME_LEN
length[3] = (n > 0) ? (n + 1) : 128;
} else { // Info table
maxres = 0;
length[0] = 128;
length[1] = 128;
length[2] = 128;
length[3] = 128;
length[5] = 30;
length[11] = 255;
} // endif jcp
if (trace)
htrc("JDBCColumns: 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)
htrc("Getting col results ncol=%d\n", qrp->Nbcol);
if (!(cap = AllocCatInfo(g, CAT_COL, db, table, qrp)))
return NULL;
cap->Pat = (PUCHAR)colpat;
/************************************************************************/
/* Now get the results into blocks. */
/************************************************************************/
if ((n = jcp->GetCatInfo(cap)) >= 0) {
qrp->Nblin = n;
// ResetNullValues(cap);
if (trace)
htrc("Columns: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
} else
qrp = NULL;
/* Cleanup */
jcp->Close();
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of JDBCColumns
/**************************************************************************/
/* JDBCSrcCols: constructs the result blocks containing the */
/* description of all the columns of a Srcdef option. */
/**************************************************************************/
PQRYRES JDBCSrcCols(PGLOBAL g, char *jpath, char *src, PJPARM sjp)
{
JDBConn *jcp = new(g)JDBConn(g, NULL);
if (jcp->Open(jpath, sjp))
return NULL;
return jcp->GetMetaData(g, src);
} // end of JDBCSrcCols
/**************************************************************************/
/* JDBCTables: constructs the result blocks containing all tables in */
/* an JDBC database that will be retrieved by GetData commands. */
/**************************************************************************/
PQRYRES JDBCTables(PGLOBAL g, char *jpath, char *db, char *tabpat,
char *tabtyp, int maxres, bool info, PJPARM sjp)
{
int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING, TYPE_STRING};
XFLD fldtyp[] = {FLD_CAT, FLD_SCHEM, FLD_NAME, FLD_TYPE, FLD_REM};
unsigned int length[] = {0, 0, 0, 16, 0};
bool b[] = {true, true, false, false, true};
int i, n, ncol = 5;
PCOLRES crp;
PQRYRES qrp;
JCATPARM *cap;
JDBConn *jcp = NULL;
/************************************************************************/
/* Do an evaluation of the result size. */
/************************************************************************/
if (!info) {
/**********************************************************************/
/* Open the connection with the JDBC data source. */
/**********************************************************************/
jcp = new(g)JDBConn(g, NULL);
if (jcp->Open(jpath, sjp) == RC_FX)
return NULL;
if (!maxres)
maxres = 10000; // This is completely arbitrary
n = jcp->GetMaxValue(2); // Max catalog name length
if (n < 0)
return NULL;
length[0] = (n) ? (n + 1) : 0;
n = jcp->GetMaxValue(3); // Max schema name length
length[1] = (n) ? (n + 1) : 0;
n = jcp->GetMaxValue(4); // Max table name length
length[2] = (n) ? (n + 1) : 128;
} else {
maxres = 0;
length[0] = 128;
length[1] = 128;
length[2] = 128;
length[4] = 255;
} // endif info
if (trace)
htrc("JDBCTables: 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 = (PUCHAR)tabtyp;
if (trace)
htrc("Getting table results ncol=%d\n", cap->Qrp->Nbcol);
/************************************************************************/
/* Now get the results into blocks. */
/************************************************************************/
if ((n = jcp->GetCatInfo(cap)) >= 0) {
qrp->Nblin = n;
// ResetNullValues(cap);
if (trace)
htrc("Tables: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
} else
qrp = NULL;
/************************************************************************/
/* Close any local connection. */
/************************************************************************/
jcp->Close();
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of JDBCTables
/*************************************************************************/
/* JDBCDrivers: constructs the result blocks containing all JDBC */
/* drivers available on the local host. */
/* Called with info=true to have result column names. */
/*************************************************************************/
PQRYRES JDBCDrivers(PGLOBAL g, char *jpath, int maxres, bool info)
{
int buftyp[] ={TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING};
XFLD fldtyp[] ={FLD_NAME, FLD_EXTRA, FLD_DEFAULT, FLD_REM };
unsigned int length[] ={ 128, 32, 4, 256 };
bool b[] ={ false, false, false, true };
int i, ncol = 4;
PCOLRES crp;
PQRYRES qrp;
JDBConn *jcp = NULL;
/************************************************************************/
/* Do an evaluation of the result size. */
/************************************************************************/
if (!info) {
jcp = new(g) JDBConn(g, NULL);
if (jcp->Open(jpath, NULL) != RC_OK)
return NULL;
if (!maxres)
maxres = 256; // Estimated max number of drivers
} else
maxres = 0;
if (trace)
htrc("JDBCDrivers: max=%d len=%d\n", maxres, length[0]);
/************************************************************************/
/* Allocate the structures used to refer to the result set. */
/************************************************************************/
qrp = PlgAllocResult(g, ncol, maxres, 0, buftyp, fldtyp, length, false, true);
for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next) {
if (b[i])
crp->Kdata->SetNullable(true);
switch (i) {
case 0: crp->Name = "Name"; break;
case 1: crp->Name = "Version"; break;
case 2: crp->Name = "Compliant"; break;
case 3: crp->Name = "Description"; break;
} // endswitch
} // endfor i
/************************************************************************/
/* Now get the results into blocks. */
/************************************************************************/
if (!info && qrp && jcp->GetDrivers(qrp))
qrp = NULL;
if (!info)
jcp->Close();
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of JDBCDrivers
#if 0
/*************************************************************************/
/* JDBCDataSources: constructs the result blocks containing all JDBC */
/* data sources available on the local host. */
/* Called with info=true to have result column names. */
/*************************************************************************/
PQRYRES JDBCDataSources(PGLOBAL g, int maxres, bool info)
{
int buftyp[] ={ TYPE_STRING, TYPE_STRING };
XFLD fldtyp[] ={ FLD_NAME, FLD_REM };
unsigned int length[] ={ 0, 256 };
bool b[] ={ false, true };
int i, n = 0, ncol = 2;
PCOLRES crp;
PQRYRES qrp;
JDBConn *jcp = NULL;
/************************************************************************/
/* Do an evaluation of the result size. */
/************************************************************************/
if (!info) {
jcp = new(g)JDBConn(g, NULL);
n = jcp->GetMaxValue(SQL_MAX_DSN_LENGTH);
length[0] = (n) ? (n + 1) : 256;
if (!maxres)
maxres = 512; // Estimated max number of data sources
} else {
length[0] = 256;
maxres = 0;
} // endif info
if (trace)
htrc("JDBCDataSources: 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 && jcp->GetDataSources(qrp))
qrp = NULL;
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of JDBCDataSources
/**************************************************************************/
/* PrimaryKeys: constructs the result blocks containing all the */
/* JDBC catalog information concerning primary keys. */
/**************************************************************************/
PQRYRES JDBCPrimaryKeys(PGLOBAL g, JDBConn *op, char *dsn, char *table)
{
static int buftyp[] ={ TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING, TYPE_SHORT, TYPE_STRING };
static unsigned int length[] ={ 0, 0, 0, 0, 6, 128 };
int n, ncol = 5;
int maxres;
PQRYRES qrp;
JCATPARM *cap;
JDBConn *jcp = op;
if (!op) {
/**********************************************************************/
/* Open the connection with the JDBC data source. */
/**********************************************************************/
jcp = new(g)JDBConn(g, NULL);
if (jcp->Open(dsn, 2) < 1) // 2 is openReadOnly
return NULL;
} // endif op
/************************************************************************/
/* Do an evaluation of the result size. */
/************************************************************************/
n = jcp->GetMaxValue(SQL_MAX_COLUMNS_IN_TABLE);
maxres = (n) ? (int)n : 250;
n = jcp->GetMaxValue(SQL_MAX_CATALOG_NAME_LEN);
length[0] = (n) ? (n + 1) : 128;
n = jcp->GetMaxValue(SQL_MAX_SCHEMA_NAME_LEN);
length[1] = (n) ? (n + 1) : 128;
n = jcp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
length[2] = (n) ? (n + 1) : 128;
n = jcp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
length[3] = (n) ? (n + 1) : 128;
if (trace)
htrc("JDBCPrimaryKeys: 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)
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 = jcp->GetCatInfo(cap)) >= 0) {
qrp->Nblin = n;
// ResetNullValues(cap);
if (trace)
htrc("PrimaryKeys: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
} else
qrp = NULL;
/************************************************************************/
/* Close any local connection. */
/************************************************************************/
if (!op)
jcp->Close();
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of JDBCPrimaryKeys
/**************************************************************************/
/* Statistics: constructs the result blocks containing statistics */
/* about one or several tables to be retrieved by GetData commands. */
/**************************************************************************/
PQRYRES JDBCStatistics(PGLOBAL g, JDBConn *op, char *dsn, char *pat,
int un, int acc)
{
static int 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 };
static unsigned int length[] ={ 0, 0, 0, 6, 0, 0, 6, 6, 0, 2, 10, 10, 128 };
int n, ncol = 13;
int maxres;
PQRYRES qrp;
JCATPARM *cap;
JDBConn *jcp = op;
if (!op) {
/**********************************************************************/
/* Open the connection with the JDBC data source. */
/**********************************************************************/
jcp = new(g)JDBConn(g, NULL);
if (jcp->Open(dsn, 2) < 1) // 2 is openReadOnly
return NULL;
} // endif op
/************************************************************************/
/* Do an evaluation of the result size. */
/************************************************************************/
n = 1 + jcp->GetMaxValue(SQL_MAX_COLUMNS_IN_INDEX);
maxres = (n) ? (int)n : 32;
n = jcp->GetMaxValue(SQL_MAX_SCHEMA_NAME_LEN);
length[1] = (n) ? (n + 1) : 128;
n = jcp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
length[2] = length[5] = (n) ? (n + 1) : 128;
n = jcp->GetMaxValue(SQL_MAX_CATALOG_NAME_LEN);
length[0] = length[4] = (n) ? (n + 1) : length[2];
n = jcp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
length[7] = (n) ? (n + 1) : 128;
if (trace)
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)
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 = jcp->GetCatInfo(cap)) >= 0) {
qrp->Nblin = n;
// ResetNullValues(cap);
if (trace)
htrc("Statistics: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
} else
qrp = NULL;
/************************************************************************/
/* Close any local connection. */
/************************************************************************/
if (!op)
jcp->Close();
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of Statistics
#endif // 0
/***********************************************************************/
/* JDBConn construction/destruction. */
/***********************************************************************/
JDBConn::JDBConn(PGLOBAL g, TDBJDBC *tdbp)
{
m_G = g;
m_Tdb = tdbp;
jvm = nullptr; // Pointer to the JVM (Java Virtual Machine)
env= nullptr; // Pointer to native interface
jdi = nullptr; // Pointer to the JdbcInterface class
job = nullptr; // The JdbcInterface class object
xqid = xuid = xid = grs = readid = fetchid = typid = nullptr;
prepid = xpid = pcid = nullptr;
//m_LoginTimeout = DEFAULT_LOGIN_TIMEOUT;
//m_QueryTimeout = DEFAULT_QUERY_TIMEOUT;
//m_UpdateOptions = 0;
m_Driver = NULL;
m_Url = NULL;
m_User = NULL;
m_Pwd = NULL;
m_Ncol = 0;
m_Aff = 0;
m_Rows = 0;
m_Fetch = 0;
m_RowsetSize = 0;
m_Updatable = true;
m_Transact = false;
m_Scrollable = false;
m_Full = false;
m_Opened = false;
m_IDQuoteChar[0] = '"';
m_IDQuoteChar[1] = 0;
//*m_ErrMsg = '\0';
} // end of JDBConn
//JDBConn::~JDBConn()
// {
//if (Connected())
// EndCom();
// } // end of ~JDBConn
#if 0
/***********************************************************************/
/* Screen for errors. */
/***********************************************************************/
bool JDBConn::Check(RETCODE rc)
{
switch (rc) {
case SQL_SUCCESS_WITH_INFO:
if (trace) {
DJX x(rc);
if (x.BuildErrorMessage(this, m_hstmt))
htrc("JDBC Success With Info, hstmt=%p %s\n",
m_hstmt, x.GetErrorMessage(0));
} // endif trace
// Fall through
case SQL_SUCCESS:
case SQL_NO_DATA_FOUND:
return true;
} // endswitch rc
return false;
} // end of Check
/***********************************************************************/
/* Utility routine. */
/***********************************************************************/
PSZ JDBConn::GetStringInfo(ushort infotype)
{
//ASSERT(m_hdbc != SQL_NULL_HDBC);
char *p, buffer[MAX_STRING_INFO];
SWORD result;
RETCODE rc;
rc = SQLGetInfo(m_hdbc, infotype, buffer, sizeof(buffer), &result);
if (!Check(rc)) {
ThrowDJX(rc, "SQLGetInfo"); // Temporary
// *buffer = '\0';
} // endif rc
p = PlugDup(m_G, buffer);
return p;
} // end of GetStringInfo
/***********************************************************************/
/* Utility routines. */
/***********************************************************************/
void JDBConn::OnSetOptions(HSTMT hstmt)
{
RETCODE rc;
ASSERT(m_hdbc != SQL_NULL_HDBC);
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
#endif // 0
/***********************************************************************/
/* Utility routine. */
/***********************************************************************/
int JDBConn::GetMaxValue(int n)
{
jmethodID maxid = env->GetMethodID(jdi, "GetMaxValue", "(I)I");
if (maxid == nullptr) {
strcpy(m_G->Message, "ERROR: method GetMaxValue not found !");
return -1;
} // endif maxid
// call method
return (int)env->CallIntMethod(job, maxid, n);
} // end of GetMaxValue
/***********************************************************************/
/* Open: connect to a data source. */
/***********************************************************************/
int JDBConn::Open(PSZ jpath, PJPARM sop)
{
PGLOBAL& g = m_G;
PSTRG jpop = new(g) STRING(g, 512, "-Djava.class.path=");
char sep;
#if defined(__WIN__)
sep = ';';
#else
sep = ':';
#endif
if (sop) {
m_Driver = sop->Driver;
m_Url = sop->Url;
m_User = sop->User;
m_Pwd = sop->Pwd;
m_Scrollable = sop->Scrollable;
m_RowsetSize = sop->Fsize;
//m_LoginTimeout = sop->Cto;
//m_QueryTimeout = sop->Qto;
//m_UseCnc = sop->UseCnc;
} // endif sop
//================== prepare loading of Java VM ============================
JavaVMInitArgs vm_args; // Initialization arguments
JavaVMOption* options = new JavaVMOption[1]; // JVM invocation options
// where to find java .class
jpop->Append(getenv("CLASSPATH"));
if (jpath) {
jpop->Append(sep);
jpop->Append(jpath);
} // endif jpath
options[0].optionString = jpop->GetStr();
//options[1].optionString = "-verbose:jni";
vm_args.version = JNI_VERSION_1_6; // minimum Java version
vm_args.nOptions = 1; // number of options
vm_args.options = options;
vm_args.ignoreUnrecognized = false; // invalid options make the JVM init fail
//=============== load and initialize Java VM and JNI interface =============
jint rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); // YES !!
delete options; // we then no longer need the initialisation options.
switch (rc) {
case JNI_OK:
strcpy(g->Message, "VM successfully created");
break;
case JNI_ERR:
strcpy(g->Message, "Initialising JVM failed: unknown error");
return RC_FX;
case JNI_EDETACHED:
strcpy(g->Message, "Thread detached from the VM");
return RC_FX;
case JNI_EVERSION:
strcpy(g->Message, "JNI version error");
return RC_FX;
case JNI_ENOMEM:
strcpy(g->Message, "Not enough memory");
return RC_FX;
case JNI_EEXIST:
strcpy(g->Message, "VM already created");
{
JavaVM* jvms[1];
jsize jsz;
rc = JNI_GetCreatedJavaVMs(jvms, 1, &jsz);
if (rc == JNI_OK && jsz == 1) {
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_6;
args.name = NULL;
args.group = NULL;
jvm = jvms[0];
rc = jvm->AttachCurrentThread((void**)&env, &args);
} // endif rc
} // end of block
if (rc == JNI_OK)
break;
else
return RC_FX;
case JNI_EINVAL:
strcpy(g->Message, "Invalid arguments");
return RC_FX;
default:
sprintf(g->Message, "Unknown return code %d", rc);
return RC_FX;
} // endswitch rc
//=============== Display JVM version =======================================
//jint ver = env->GetVersion();
//cout << ((ver>>16)&0x0f) << "."<<(ver&0x0f) << endl;
// try to find the JdbcInterface class
jdi = env->FindClass("JdbcInterface");
if (jdi == nullptr) {
strcpy(g->Message, "ERROR: class JdbcInterface not found !");
return RC_FX;
} // endif jdi
// if class found, continue
jmethodID ctor = env->GetMethodID(jdi, "<init>", "()V");
if (ctor == nullptr) {
strcpy(g->Message, "ERROR: JdbcInterface constructor not found !");
return RC_FX;
} else
job = env->NewObject(jdi, ctor);
// If the object is successfully constructed,
// we can then search for the method we want to call,
// and invoke it for the object:
if (job == nullptr) {
strcpy(g->Message, "JdbcInterface class object not constructed !");
return RC_FX;
} // endif job
if (!sop) // DRIVER catalog table
return RC_OK;
jmethodID cid = env->GetMethodID(jdi, "JdbcConnect", "([Ljava/lang/String;IZ)I");
if (env->ExceptionCheck()) {
strcpy(g->Message, "ERROR: method JdbcConnect() not found!");
env->ExceptionDescribe();
env->ExceptionClear();
return RC_FX;
} // endif Check
// Build the java string array
jobjectArray parms = env->NewObjectArray(4, // constructs java array of 4
env->FindClass("java/lang/String"), NULL); // Strings
// change some elements
if (m_Driver)
env->SetObjectArrayElement(parms, 0, env->NewStringUTF(m_Driver));
if (m_Url)
env->SetObjectArrayElement(parms, 1, env->NewStringUTF(m_Url));
if (m_User)
env->SetObjectArrayElement(parms, 2, env->NewStringUTF(m_User));
if (m_Pwd)
env->SetObjectArrayElement(parms, 3, env->NewStringUTF(m_Pwd));
// call method
rc = env->CallIntMethod(job, cid, parms, m_RowsetSize, m_Scrollable);
// Not used anymore
env->DeleteLocalRef(parms);
if (rc != (jint)0) {
strcpy(g->Message, "Connection failed");
return RC_FX;
} // endif rc
typid = env->GetMethodID(jdi, "ColumnType", "(ILjava/lang/String;)I");
if (env->ExceptionCheck()) {
strcpy(g->Message, "ERROR: method ColumnType() not found!");
env->ExceptionDescribe();
env->ExceptionClear();
return RC_FX;
} else
m_Opened = true;
return RC_OK;
} // end of Open
/***********************************************************************/
/* Execute an SQL command. */
/***********************************************************************/
int JDBConn::ExecSQLcommand(char *sql)
{
int rc = RC_NF;
jint n;
jstring qry;
PGLOBAL& g = m_G;
if (xid == nullptr) {
// Get the methods used to execute a query and get the result
xid = env->GetMethodID(jdi, "Execute", "(Ljava/lang/String;)I");
if (xid == nullptr) {
strcpy(g->Message, "Cannot find method Execute");
return RC_FX;
} else
grs = env->GetMethodID(jdi, "GetResult", "()I");
if (grs == nullptr) {
strcpy(g->Message, "Cannot find method GetResult");
return RC_FX;
} // endif grs
} // endif xid
qry = env->NewStringUTF(sql);
n = env->CallIntMethod(job, xid, qry);
env->DeleteLocalRef(qry);
if (n < 0) {
sprintf(g->Message, "Error executing %s", sql);
return RC_FX;
} // endif n
if ((m_Ncol = env->CallIntMethod(job, grs))) {
strcpy(g->Message, "Result set column number");
rc = RC_OK; // A result set was returned
} else {
m_Aff = (int)n; // Affected rows
strcpy(g->Message, "Affected rows");
} // endif ncol
return rc;
} // end of ExecSQLcommand
/***********************************************************************/
/* Fetch next row. */
/***********************************************************************/
int JDBConn::Fetch(int pos)
{
jint rc;
if (m_Full) // Result set has one row
return 1;
if (pos) {
if (!m_Scrollable) {
strcpy(m_G->Message, "Cannot fetch(pos) if FORWARD ONLY");
return -1;
} else if (fetchid == nullptr) {
fetchid = env->GetMethodID(jdi, "Fetch", "(I)Z");
if (fetchid == nullptr) {
strcpy(m_G->Message, "Cannot find method Fetch");
return -1;
} // endif fetchid
} // endif's
if (env->CallBooleanMethod(job, fetchid, pos))
rc = m_Rows;
else
rc = -1;
} else {
if (readid == nullptr) {
readid = env->GetMethodID(jdi, "ReadNext", "()I");
if (readid == nullptr) {
strcpy(m_G->Message, "Cannot find method ReadNext");
return -1;
} // endif readid
} // endif readid
rc = env->CallBooleanMethod(job, readid);
if (rc >= 0) {
if (rc == 0)
m_Full = (m_Fetch == 1);
else
m_Fetch++;
m_Rows += (int)rc;
} else
strcpy(m_G->Message, "Error fetching next row");
} // endif pos
return (int)rc;
} // end of Fetch
/***********************************************************************/
/* Restart from beginning of result set */
/***********************************************************************/
int JDBConn::Rewind(char *sql)
{
int rbuf = -1;
if (m_Full)
rbuf = m_Rows; // No need to "rewind"
else if (m_Scrollable) {
if (fetchid == nullptr) {
fetchid = env->GetMethodID(jdi, "Fetch", "(I)Z");
if (fetchid == nullptr) {
strcpy(m_G->Message, "Cannot find method Fetch");
return -1;
} // endif readid
} // endif readid
jboolean b = env->CallBooleanMethod(job, fetchid, 0);
rbuf = m_Rows;
} else if (ExecSQLcommand(sql) != RC_FX)
rbuf = 0;
return rbuf;
} // end of Rewind
/***********************************************************************/
/* Disconnect connection */
/***********************************************************************/
void JDBConn::Close()
{
if (m_Opened) {
jint rc;
jmethodID did = env->GetMethodID(jdi, "JdbcDisconnect", "()I");
if (did == nullptr)
printf("ERROR: method JdbcDisconnect() not found !");
else
rc = env->CallIntMethod(job, did);
rc = jvm->DetachCurrentThread();
//rc = jvm->DestroyJavaVM();
m_Opened = false;
} // endif m_Opened
} // end of Close
/***********************************************************************/
/* Retrieve and set the column value from the result set. */
/***********************************************************************/
void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val)
{
PGLOBAL& g = m_G;
jint ctyp;
jlong dtv;
jstring cn, jn = nullptr;
jobject dob;
jthrowable exc;
jmethodID fldid = nullptr;
if (rank == 0)
if (!name || (jn = env->NewStringUTF(name)) == nullptr) {
sprintf(g->Message, "Fail to allocate jstring %s", SVP(name));
longjmp(g->jumper[g->jump_level], TYPE_AM_JDBC);
} // endif name
ctyp = env->CallIntMethod(job, typid, rank, jn);
if ((exc = env->ExceptionOccurred()) != nullptr) {
jboolean isCopy = false;
jmethodID tid = env->GetMethodID(env->FindClass("java/lang/Object"), "toString", "()Ljava/lang/String;");
jstring s = (jstring)env->CallObjectMethod(exc, tid);
const char* utf = env->GetStringUTFChars(s, &isCopy);
sprintf(g->Message, "SetColumnValue: %s", utf);
env->DeleteLocalRef(s);
env->ExceptionClear();
longjmp(g->jumper[g->jump_level], TYPE_AM_JDBC);
} // endif Check
switch (ctyp) {
case 12: // VARCHAR
case -1: // LONGVARCHAR
case 1: // CHAR
fldid = env->GetMethodID(jdi, "StringField",
"(ILjava/lang/String;)Ljava/lang/String;");
if (fldid != nullptr) {
cn = (jstring)env->CallObjectMethod(job, fldid, (jint)rank, jn);
if (cn) {
const char *field = env->GetStringUTFChars(cn, (jboolean)false);
val->SetValue_psz((PSZ)field);
} else {
val->Reset();
val->SetNull(true);
} // endif cn
} else
val->Reset();
break;
case 4: // INTEGER
case 5: // SMALLINT
case -6: // TINYINT
fldid = env->GetMethodID(jdi, "IntField", "(ILjava/lang/String;)I");
if (fldid != nullptr)
val->SetValue((int)env->CallIntMethod(job, fldid, rank, jn));
else
val->Reset();
break;
case 8: // DOUBLE
case 3: // DECIMAL
fldid = env->GetMethodID(jdi, "DoubleField", "(ILjava/lang/String;)D");
if (fldid != nullptr)
val->SetValue((double)env->CallDoubleMethod(job, fldid, rank, jn));
else
val->Reset();
break;
case 7: // REAL
case 6: // FLOAT
fldid = env->GetMethodID(jdi, "FloatField", "(ILjava/lang/String;)F");
if (fldid != nullptr)
val->SetValue((float)env->CallFloatMethod(job, fldid, rank, jn));
else
val->Reset();
break;
case 91: // DATE
case 92: // TIME
case 93: // TIMESTAMP
fldid = env->GetMethodID(jdi, "TimestampField",
"(ILjava/lang/String;)Ljava/sql/Timestamp;");
if (fldid != nullptr) {
dob = env->CallObjectMethod(job, fldid, (jint)rank, jn);
if (dob) {
jclass jts = env->FindClass("java/sql/Timestamp");
if (env->ExceptionCheck()) {
val->Reset();
} else {
jmethodID getTime = env->GetMethodID(jts, "getTime", "()J");
if (getTime != nullptr) {
dtv = env->CallLongMethod(dob, getTime);
val->SetValue((int)(dtv / 1000));
} else
val->Reset();
} // endif check
} else
val->Reset();
} else
val->Reset();
break;
case -5: // BIGINT
fldid = env->GetMethodID(jdi, "BigintField", "(ILjava/lang/String;)J");
if (fldid != nullptr)
val->SetValue((long long)env->CallLongMethod(job, fldid, (jint)rank, jn));
else
val->Reset();
break;
/* case java.sql.Types.SMALLINT:
System.out.print(jdi.IntField(i));
break;
case java.sql.Types.BOOLEAN:
System.out.print(jdi.BooleanField(i)); */
default:
val->Reset();
} // endswitch Type
if (rank == 0)
env->DeleteLocalRef(jn);
} // end of SetColumnValue
/***********************************************************************/
/* Prepare an SQL statement for insert. */
/***********************************************************************/
bool JDBConn::PrepareSQL(char *sql)
{
if (prepid == nullptr) {
prepid = env->GetMethodID(jdi, "CreatePrepStmt", "(Ljava/lang/String;)Z");
if (prepid == nullptr) {
strcpy(m_G->Message, "Cannot find method CreatePrepStmt");
return true;
} // endif prepid
} // endif prepid
// Create the prepared statement
jstring qry = env->NewStringUTF(sql);
jboolean b = env->CallBooleanMethod(job, prepid, qry);
env->DeleteLocalRef(qry);
return (bool)b;
} // end of PrepareSQL
/***********************************************************************/
/* Execute an SQL query that returns a result set. */
/***********************************************************************/
int JDBConn::ExecuteQuery(char *sql)
{
jint ncol;
jstring qry;
PGLOBAL& g = m_G;
if (xqid == nullptr) {
// Get the methods used to execute a query and get the result
xqid = env->GetMethodID(jdi, "ExecuteQuery", "(Ljava/lang/String;)I");
if (xqid == nullptr) {
strcpy(g->Message, "Cannot find method ExecuteQuery");
return RC_FX;
} // endif !xqid
} // endif xqid
qry = env->NewStringUTF(sql);
ncol = env->CallIntMethod(job, xqid, qry);
env->DeleteLocalRef(qry);
if (ncol < 0) {
sprintf(g->Message, "Error executing %s: ncol = %d", sql, ncol);
return RC_FX;
} else {
m_Ncol = (int)ncol;
m_Aff = 0; // Affected rows
} // endif ncol
return RC_OK;
} // end of ExecuteQuery
/***********************************************************************/
/* Execute an SQL query and get the affected rows. */
/***********************************************************************/
int JDBConn::ExecuteUpdate(char *sql)
{
jint n;
jstring qry;
PGLOBAL& g = m_G;
if (xuid == nullptr) {
// Get the methods used to execute a query and get the affected rows
xuid = env->GetMethodID(jdi, "ExecuteUpdate", "(Ljava/lang/String;)I");
if (xuid == nullptr) {
strcpy(g->Message, "Cannot find method ExecuteUpdate");
return RC_FX;
} // endif !xuid
} // endif xuid
qry = env->NewStringUTF(sql);
n = env->CallIntMethod(job, xuid, qry);
env->DeleteLocalRef(qry);
if (n < 0) {
sprintf(g->Message, "Error executing %s: n = %d", sql, n);
return RC_FX;
} else {
m_Ncol = 0;
m_Aff = (int)n; // Affected rows
} // endif n
return RC_OK;
} // end of ExecuteUpdate
/***********************************************************************/
/* Get the number of lines of the result set. */
/***********************************************************************/
int JDBConn::GetResultSize(char *sql, JDBCCOL *colp)
{
int rc, n = 0;
if ((rc = ExecuteQuery(sql)) != RC_OK)
return -1;
if ((rc = Fetch()) > 0)
SetColumnValue(1, NULL, colp->GetValue());
else
return -2;
if ((rc = Fetch()) != 0)
return -3;
m_Full = false;
return colp->GetIntValue();
} // end of GetResultSize
/***********************************************************************/
/* Execute a prepared statement. */
/***********************************************************************/
int JDBConn::ExecuteSQL(void)
{
int rc = RC_FX;
PGLOBAL& g = m_G;
if (xpid == nullptr) {
// Get the methods used to execute a prepared statement
xpid = env->GetMethodID(jdi, "ExecutePrep", "()I");
if (xpid == nullptr) {
strcpy(g->Message, "Cannot find method ExecutePrep");
return rc;
} // endif xpid
} // endif xpid
jint n = env->CallIntMethod(job, xpid);
switch ((int)n) {
case -1:
case -2:
strcpy(g->Message, "Exception error thrown while executing SQL");
break;
case -3:
strcpy(g->Message, "SQL statement is not prepared");
break;
default:
m_Aff = (int)n;
rc = RC_OK;
} // endswitch n
return rc;
} // end of ExecuteSQL
/***********************************************************************/
/* Set a parameter for inserting. */
/***********************************************************************/
bool JDBConn::SetParam(JDBCCOL *colp)
{
PGLOBAL& g = m_G;
int rc = false;
PVAL val = colp->GetValue();
jint n, i = (jint)colp->GetRank();
jshort s;
jlong lg;
//jfloat f;
jdouble d;
jclass dat;
jobject datobj;
jstring jst = nullptr;
jthrowable exc;
jmethodID dtc, setid = nullptr;
switch (val->GetType()) {
case TYPE_STRING:
setid = env->GetMethodID(jdi, "SetStringParm", "(ILjava/lang/String;)V");
if (setid == nullptr) {
strcpy(g->Message, "Cannot fing method SetStringParm");
return true;
} // endif setid
jst = env->NewStringUTF(val->GetCharValue());
env->CallVoidMethod(job, setid, i, jst);
break;
case TYPE_INT:
setid = env->GetMethodID(jdi, "SetIntParm", "(II)V");
if (setid == nullptr) {
strcpy(g->Message, "Cannot fing method SetIntParm");
return true;
} // endif setid
n = (jint)val->GetIntValue();
env->CallVoidMethod(job, setid, i, n);
break;
case TYPE_TINY:
case TYPE_SHORT:
setid = env->GetMethodID(jdi, "SetShortParm", "(IS)V");
if (setid == nullptr) {
strcpy(g->Message, "Cannot fing method SetShortParm");
return true;
} // endif setid
s = (jshort)val->GetShortValue();
env->CallVoidMethod(job, setid, i, s);
break;
case TYPE_BIGINT:
setid = env->GetMethodID(jdi, "SetBigintParm", "(IJ)V");
if (setid == nullptr) {
strcpy(g->Message, "Cannot fing method SetBigintParm");
return true;
} // endif setid
lg = (jlong)val->GetBigintValue();
env->CallVoidMethod(job, setid, i, lg);
break;
case TYPE_DOUBLE:
case TYPE_DECIM:
setid = env->GetMethodID(jdi, "SetDoubleParm", "(ID)V");
if (setid == nullptr) {
strcpy(g->Message, "Cannot fing method SetDoubleParm");
return true;
} // endif setid
d = (jdouble)val->GetFloatValue();
env->CallVoidMethod(job, setid, i, d);
break;
case TYPE_DATE:
if ((dat = env->FindClass("java/sql/Timestamp")) == nullptr) {
strcpy(g->Message, "Cannot find Timestamp class");
return true;
} else if (!(dtc = env->GetMethodID(dat, "<init>", "(J)V"))) {
strcpy(g->Message, "Cannot find Timestamp class constructor");
return true;
} // endif's
lg = (jlong)val->GetBigintValue() * 1000;
if ((datobj = env->NewObject(dat, dtc, lg)) == nullptr) {
strcpy(g->Message, "Cannot make Timestamp object");
return true;
} else if ((setid = env->GetMethodID(jdi, "SetTimestampParm",
"(ILjava/sql/Timestamp;)V")) == nullptr) {
strcpy(g->Message, "Cannot find method SetTimestampParm");
return true;
} // endif setid
env->CallVoidMethod(job, setid, i, datobj);
break;
default:
sprintf(g->Message, "Parm type %d not supported", val->GetType());
return true;
} // endswitch Type
if ((exc = env->ExceptionOccurred()) != nullptr) {
jboolean isCopy = false;
jmethodID tid = env->GetMethodID(env->FindClass("java/lang/Object"), "toString", "()Ljava/lang/String;");
jstring s = (jstring)env->CallObjectMethod(exc, tid);
const char* utf = env->GetStringUTFChars(s, &isCopy);
sprintf(g->Message, "SetParam: %s", utf);
env->DeleteLocalRef(s);
env->ExceptionClear();
rc = true;
} // endif exc
if (jst)
env->DeleteLocalRef(jst);
return rc;
} // end of SetParam
#if 0
/***********************************************************************/
/* Get the list of Data Sources and set it in qrp. */
/***********************************************************************/
bool JDBConn::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))
ThrowDJX(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;
else if (!Check(rc))
ThrowDJX(rc, "SQLDataSources");
qrp->Nblin++;
dir = SQL_FETCH_NEXT;
} // endfor i
}
catch (DJX *x) {
sprintf(m_G->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
rv = true;
} // end try/catch
Close();
return rv;
} // end of GetDataSources
#endif // 0
/***********************************************************************/
/* Get the list of Drivers and set it in qrp. */
/***********************************************************************/
bool JDBConn::GetDrivers(PQRYRES qrp)
{
PSZ sval;
int i, n, size;
PCOLRES crp;
jstring js;
jmethodID gdid = env->GetMethodID(jdi, "GetDrivers", "([Ljava/lang/String;I)I");
if (env->ExceptionCheck()) {
strcpy(m_G->Message, "ERROR: method GetDrivers() not found!");
env->ExceptionDescribe();
env->ExceptionClear();
return true;
} // endif Check
// Build the java string array
jobjectArray s = env->NewObjectArray(4 * qrp->Maxres,
env->FindClass("java/lang/String"), NULL);
size = env->CallIntMethod(job, gdid, s, qrp->Maxres);
for (i = 0, n = 0; i < size; i++) {
crp = qrp->Colresp;
js = (jstring)env->GetObjectArrayElement(s, n++);
sval = (PSZ)env->GetStringUTFChars(js, 0);
crp->Kdata->SetValue(sval, i);
crp = crp->Next;
js = (jstring)env->GetObjectArrayElement(s, n++);
sval = (PSZ)env->GetStringUTFChars(js, 0);
crp->Kdata->SetValue(sval, i);
crp = crp->Next;
js = (jstring)env->GetObjectArrayElement(s, n++);
sval = (PSZ)env->GetStringUTFChars(js, 0);
crp->Kdata->SetValue(sval, i);
crp = crp->Next;
js = (jstring)env->GetObjectArrayElement(s, n++);
sval = (PSZ)env->GetStringUTFChars(js, 0);
crp->Kdata->SetValue(sval, i);
} // endfor i
// Not used anymore
env->DeleteLocalRef(s);
qrp->Nblin = size;
return false;
} // end of GetDrivers
/**************************************************************************/
/* GetMetaData: constructs the result blocks containing the */
/* description of all the columns of an SQL command. */
/**************************************************************************/
PQRYRES JDBConn::GetMetaData(PGLOBAL g, char *src)
{
static int buftyp[] = {TYPE_STRING, TYPE_INT, TYPE_INT,
TYPE_INT, TYPE_INT};
static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_PREC,
FLD_SCALE, FLD_NULL };
static unsigned int length[] = {0, 6, 10, 6, 6};
const char *name;
int len, qcol = 5;
PQRYRES qrp = NULL;
PCOLRES crp;
USHORT i;
jint *n;
jstring label;
jmethodID colid;
int rc = ExecSQLcommand(src);
if (rc == RC_NF) {
strcpy(g->Message, "Srcdef is not returning a result set");
return NULL;
} else if ((rc) == RC_FX) {
return NULL;
} else if (m_Ncol == 0) {
strcpy(g->Message, "Invalid Srcdef");
return NULL;
} // endif's
colid = env->GetMethodID(jdi, "ColumnDesc", "(I[I)Ljava/lang/String;");
if (colid == nullptr) {
strcpy(m_G->Message, "ERROR: method ColumnDesc() not found!");
return NULL;
} // endif colid
// Build the java string array
jintArray val = env->NewIntArray(4);
if (val == nullptr) {
strcpy(m_G->Message, "Cannot allocate jint array");
return NULL;
} // endif colid
// Get max column name length
len = GetMaxValue(5);
length[0] = (len > 0) ? len + 1 : 128;
/************************************************************************/
/* Allocate the structures used to refer to the result set. */
/************************************************************************/
if (!(qrp = PlgAllocResult(g, qcol, m_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) {
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. */
/************************************************************************/
for (i = 0; i < m_Ncol; i++) {
label = (jstring)env->CallObjectMethod(job, colid, i + 1, val);
name = env->GetStringUTFChars(label, (jboolean)false);
crp = qrp->Colresp; // Column_Name
crp->Kdata->SetValue((char*)name, i);
n = env->GetIntArrayElements(val, 0);
crp = crp->Next; // Data_Type
crp->Kdata->SetValue((int)n[0], i);
crp = crp->Next; // Precision (length)
crp->Kdata->SetValue((int)n[1], i);
crp = crp->Next; // Scale
crp->Kdata->SetValue((int)n[2], i);
crp = crp->Next; // Nullable
crp->Kdata->SetValue((int)n[3], i);
qrp->Nblin++;
} // endfor i
/* Cleanup */
env->ReleaseIntArrayElements(val, n, 0);
Close();
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of GetMetaData
/***********************************************************************/
/* A helper class to split an optionally qualified table name into */
/* components. */
/* These formats are understood: */
/* "CatalogName.SchemaName.TableName" */
/* "SchemaName.TableName" */
/* "TableName" */
/***********************************************************************/
class SQLQualifiedName
{
static const 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;
}
}
return 0;
} // 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(JCATPARM *cap)
{
const char *name = (const char *)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
char *ptr(uint i)
{
DBUG_ASSERT(i < max_parts);
return (char *)(m_part[i].length ? m_part[i].str : NULL);
} // end of ptr
size_t length(uint i)
{
DBUG_ASSERT(i < max_parts);
return m_part[i].length;
} // end of length
}; // end of class SQLQualifiedName
/***********************************************************************/
/* Allocate recset and call SQLTables, SQLColumns or SQLPrimaryKeys. */
/***********************************************************************/
int JDBConn::GetCatInfo(JCATPARM *cap)
{
PGLOBAL& g = m_G;
void *buffer;
int i;
PSZ fnc = "Unknown";
uint n, ncol;
short len, tp;
int crow = 0;
PQRYRES qrp = cap->Qrp;
PCOLRES crp;
jboolean rc = false;
// HSTMT hstmt = NULL;
// SQLLEN *vl, *vlen = NULL;
PVAL *pval = NULL;
char* *pbuf = NULL;
jobjectArray parms;
jmethodID catid;
if (qrp->Maxres <= 0)
return 0; // 0-sized result"
SQLQualifiedName name(cap);
// Build the java string array
parms = env->NewObjectArray(4, env->FindClass("java/lang/String"), NULL);
env->SetObjectArrayElement(parms, 0, env->NewStringUTF(name.ptr(2)));
env->SetObjectArrayElement(parms, 1, env->NewStringUTF(name.ptr(1)));
env->SetObjectArrayElement(parms, 2, env->NewStringUTF(name.ptr(0)));
if (cap->Pat)
env->SetObjectArrayElement(parms, 3, env->NewStringUTF((const char*)cap->Pat));
// Now do call the proper JDBC API
switch (cap->Id) {
case CAT_COL:
fnc = "GetColumns";
break;
case CAT_TAB:
fnc = "GetTables";
break;
#if 0
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:
ThrowDJX("SQLSpecialColumns not available yet");
#endif // 0
default:
sprintf(g->Message, "Invalid SQL function id");
return -1;
} // endswitch infotype
catid = env->GetMethodID(jdi, fnc, "([Ljava/lang/String;)I");
if (catid == nullptr) {
sprintf(g->Message, "ERROR: method %s not found !", fnc);
return -1;
} // endif maxid
// call method
ncol = env->CallIntMethod(job, catid, parms);
// Not used anymore
env->DeleteLocalRef(parms);
// n because we no more ignore the first column
if ((n = qrp->Nbcol) > (int)ncol) {
strcpy(g->Message, MSG(COL_NUM_MISM));
return -1;
} // endif n
// 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*));
// Prepare retrieving column values
for (n = 0, crp = qrp->Colresp; crp; crp = crp->Next) {
if (!(tp = GetJDBCType(crp->Type))) {
sprintf(g->Message, MSG(INV_COLUMN_TYPE), crp->Type, crp->Name);
return -1;
} // endif tp
if (!(len = GetTypeSize(crp->Type, crp->Length))) {
len = 255; // for STRBLK's
((STRBLK*)crp->Kdata)->SetSorted(true);
} // endif len
pval[n] = AllocateValue(g, crp->Type, len);
if (crp->Type == TYPE_STRING) {
pbuf[n] = (char*)PlugSubAlloc(g, NULL, len);
buffer = pbuf[n];
} else
buffer = pval[n]->GetTo_Val();
n++;
} // endfor n
// Now fetch the result
// Extended fetch cannot be used because of STRBLK's
for (i = 0; i < qrp->Maxres; i++) {
if ((rc = Fetch(0)) == 0)
break;
else if (rc < 0)
return -1;
for (n = 0, crp = qrp->Colresp; crp; n++, crp = crp->Next) {
SetColumnValue(n + 1, nullptr, pval[n]);
crp->Kdata->SetValue(pval[n], i);
} // endfor n
} // endfor i
if (rc == RC_OK)
qrp->Truncated = true;
return i;
} // end of GetCatInfo
/***********************************************************************/
/* Allocate a CONNECT result structure from the JDBC result. */
/***********************************************************************/
PQRYRES JDBConn::AllocateResult(PGLOBAL g)
{
bool uns;
PJDBCCOL colp;
PCOLRES *pcrp, crp;
PQRYRES qrp;
if (!m_Rows) {
strcpy(g->Message, "Void result");
return NULL;
} // endif m_Res
/*********************************************************************/
/* Allocate the result storage for future retrieval. */
/*********************************************************************/
qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
pcrp = &qrp->Colresp;
qrp->Continued = FALSE;
qrp->Truncated = FALSE;
qrp->Info = FALSE;
qrp->Suball = TRUE;
qrp->BadLines = 0;
qrp->Maxsize = m_Rows;
qrp->Maxres = m_Rows;
qrp->Nbcol = 0;
qrp->Nblin = 0;
qrp->Cursor = 0;
for (colp = (PJDBCCOL)m_Tdb->Columns; colp;
colp = (PJDBCCOL)colp->GetNext())
if (!colp->IsSpecial()) {
*pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
crp = *pcrp;
pcrp = &crp->Next;
memset(crp, 0, sizeof(COLRES));
crp->Ncol = ++qrp->Nbcol;
crp->Name = colp->GetName();
crp->Type = colp->GetResultType();
crp->Prec = colp->GetScale();
crp->Length = colp->GetLength();
crp->Clen = colp->GetValue()->GetClen();
uns = colp->IsUnsigned();
if (!(crp->Kdata = AllocValBlock(g, NULL, crp->Type, m_Rows,
crp->Clen, 0, FALSE, TRUE, uns))) {
sprintf(g->Message, MSG(INV_RESULT_TYPE),
GetFormatType(crp->Type));
return NULL;
} // endif Kdata
if (!colp->IsNullable())
crp->Nulls = NULL;
else {
crp->Nulls = (char*)PlugSubAlloc(g, NULL, m_Rows);
memset(crp->Nulls, ' ', m_Rows);
} // endelse Nullable
colp->SetCrp(crp);
} // endif colp
*pcrp = NULL;
//qrp->Nblin = n;
return qrp;
} // end of AllocateResult
/***********************************************************************/
/* JDBConn.h : header file for the JDBC connection classes. */
/***********************************************************************/
//nclude <windows.h> /* Windows include file */
//nclude <windowsx.h> /* Message crackers */
/***********************************************************************/
/* Included C-definition files required by the interface. */
/***********************************************************************/
#include "block.h"
/***********************************************************************/
/* JDBC interface. */
/***********************************************************************/
#include <jni.h>
/***********************************************************************/
/* Constants and defines. */
/***********************************************************************/
// Miscellaneous sizing info
#define MAX_NUM_OF_MSG 10 // Max number of error messages
//efine MAX_CURRENCY 30 // Max size of Currency($) string
#define MAX_TNAME_LEN 32 // Max size of table names
//efine MAX_FNAME_LEN 256 // Max size of field names
//efine MAX_STRING_INFO 256 // Max size of string from SQLGetInfo
//efine MAX_DNAME_LEN 256 // Max size of Recordset names
#define MAX_CONNECT_LEN 512 // Max size of Connect string
//efine MAX_CURSOR_NAME 18 // Max size of a cursor name
#define DEFAULT_FIELD_TYPE 0 // TYPE_NULL
#if !defined(__WIN__)
typedef unsigned char *PUCHAR;
#endif // !__WIN__
// Field Flags, used to indicate status of fields
//efine SQL_FIELD_FLAG_DIRTY 0x1
//efine SQL_FIELD_FLAG_NULL 0x2
// Update options flags
//efine SQL_SETPOSUPDATES 0x0001
//efine SQL_POSITIONEDSQL 0x0002
//efine SQL_GDBOUND 0x0004
enum JCATINFO {
CAT_TAB = 1, // JDBC Tables
CAT_COL = 2, // JDBC Columns
CAT_KEY = 3, // JDBC PrimaryKeys
//CAT_STAT = 4, // SQLStatistics
//CAT_SPC = 5 // SQLSpecialColumns
};
/***********************************************************************/
/* This structure is used to control the catalog functions. */
/***********************************************************************/
typedef struct tagJCATPARM {
JCATINFO Id; // Id to indicate function
PQRYRES Qrp; // Result set pointer
PUCHAR DB; // Database (Schema)
PUCHAR Tab; // Table name or pattern
PUCHAR Pat; // Table type or column pattern
} JCATPARM;
// JDBC connection to a data source
class TDBJDBC;
class JDBCCOL;
class JDBConn;
class TDBXJDC;
/***********************************************************************/
/* JDBConn class. */
/***********************************************************************/
class JDBConn : public BLOCK {
friend class TDBJDBC;
friend class TDBXJDC;
//friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&);
private:
JDBConn(); // Standard (unused) constructor
public:
JDBConn(PGLOBAL g, TDBJDBC *tdbp);
int Open(PSZ jpath, PJPARM sop);
int Rewind(char *sql);
void Close(void);
PQRYRES AllocateResult(PGLOBAL g);
// Attributes
public:
char *GetQuoteChar(void) { return m_IDQuoteChar; }
// Database successfully opened?
bool IsOpen(void) { return m_Opened; }
//PSZ GetStringInfo(ushort infotype);
int GetMaxValue(int infotype);
//PSZ GetConnect(void) { return m_Connect; }
public:
// Operations
//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, JDBCCOL *colp);
int ExecuteQuery(char *sql);
int ExecuteUpdate(char *sql);
int Fetch(int pos = 0);
bool PrepareSQL(char *sql);
int ExecuteSQL(void);
bool SetParam(JDBCCOL *colp);
int ExecSQLcommand(char *sql);
void SetColumnValue(int rank, PSZ name, PVAL val);
int GetCatInfo(JCATPARM *cap);
//bool GetDataSources(PQRYRES qrp);
bool GetDrivers(PQRYRES qrp);
PQRYRES GetMetaData(PGLOBAL g, char *src);
public:
// Set special options
//void OnSetOptions(HSTMT hstmt);
// Implementation
public:
//virtual ~JDBConn();
// JDBC operations
protected:
//bool Check(RETCODE rc);
//void ThrowDJX(int rc, PSZ msg/*, HSTMT hstmt = SQL_NULL_HSTMT*/);
//void ThrowDJX(PSZ msg);
//void AllocConnect(DWORD dwOptions);
//void Connect(void);
//bool DriverConnect(DWORD Options);
//void VerifyConnect(void);
//void GetConnectInfo(void);
//void Free(void);
protected:
// Members
PGLOBAL m_G;
TDBJDBC *m_Tdb;
JavaVM *jvm; // Pointer to the JVM (Java Virtual Machine)
JNIEnv *env; // Pointer to native interface
jclass jdi; // Pointer to the JdbcInterface class
jobject job; // The JdbcInterface class object
jmethodID xqid; // The ExecuteQuery method ID
jmethodID xuid; // The ExecuteUpdate method ID
jmethodID xid; // The Execute method ID
jmethodID grs; // The GetResult method ID
jmethodID readid; // The ReadNext method ID
jmethodID fetchid; // The Fetch method ID
jmethodID typid; // The ColumnType method ID
jmethodID prepid; // The CreatePrepStmt method ID
jmethodID xpid; // The ExecutePrep method ID
jmethodID pcid; // The ClosePrepStmt method ID
//DWORD m_LoginTimeout;
//DWORD m_QueryTimeout;
//DWORD m_UpdateOptions;
char m_IDQuoteChar[2];
PSZ m_Driver;
PSZ m_Url;
PSZ m_User;
PSZ m_Pwd;
int m_Ncol;
int m_Aff;
int m_Rows;
int m_Fetch;
int m_RowsetSize;
jboolean m_Updatable;
jboolean m_Transact;
jboolean m_Scrollable;
bool m_Opened;
bool m_Full;
}; // end of JDBConn class definition
...@@ -80,6 +80,10 @@ ...@@ -80,6 +80,10 @@
#define NODBC #define NODBC
#include "tabodbc.h" #include "tabodbc.h"
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
#if defined(JDBC_SUPPORT)
#define NJDBC
#include "tabjdbc.h"
#endif // ODBC_SUPPORT
#if defined(PIVOT_SUPPORT) #if defined(PIVOT_SUPPORT)
#include "tabpivot.h" #include "tabpivot.h"
#endif // PIVOT_SUPPORT #endif // PIVOT_SUPPORT
...@@ -140,7 +144,10 @@ TABTYPE GetTypeID(const char *type) ...@@ -140,7 +144,10 @@ TABTYPE GetTypeID(const char *type)
#ifdef ODBC_SUPPORT #ifdef ODBC_SUPPORT
: (!stricmp(type, "ODBC")) ? TAB_ODBC : (!stricmp(type, "ODBC")) ? TAB_ODBC
#endif #endif
: (!stricmp(type, "MYSQL")) ? TAB_MYSQL #ifdef JDBC_SUPPORT
: (!stricmp(type, "JDBC")) ? TAB_JDBC
#endif
: (!stricmp(type, "MYSQL")) ? TAB_MYSQL
: (!stricmp(type, "MYPRX")) ? TAB_MYSQL : (!stricmp(type, "MYPRX")) ? TAB_MYSQL
: (!stricmp(type, "DIR")) ? TAB_DIR : (!stricmp(type, "DIR")) ? TAB_DIR
#ifdef __WIN__ #ifdef __WIN__
...@@ -301,12 +308,12 @@ int GetIndexType(TABTYPE type) ...@@ -301,12 +308,12 @@ int GetIndexType(TABTYPE type)
break; break;
case TAB_MYSQL: case TAB_MYSQL:
case TAB_ODBC: case TAB_ODBC:
xtyp= 2; case TAB_JDBC:
xtyp= 2;
break; break;
case TAB_VIR: case TAB_VIR:
xtyp= 3; xtyp= 3;
break; break;
// case TAB_ODBC:
default: default:
xtyp= 0; xtyp= 0;
break; break;
...@@ -558,6 +565,9 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) ...@@ -558,6 +565,9 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am)
#if defined(ODBC_SUPPORT) #if defined(ODBC_SUPPORT)
case TAB_ODBC: tdp= new(g) ODBCDEF; break; case TAB_ODBC: tdp= new(g) ODBCDEF; break;
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
#if defined(JDBC_SUPPORT)
case TAB_JDBC: tdp= new(g)JDBCDEF; break;
#endif // JDBC_SUPPORT
#if defined(__WIN__) #if defined(__WIN__)
case TAB_MAC: tdp= new(g) MACDEF; break; case TAB_MAC: tdp= new(g) MACDEF; break;
case TAB_WMI: tdp= new(g) WMIDEF; break; case TAB_WMI: tdp= new(g) WMIDEF; break;
......
SET NAMES utf8; SET NAMES utf8;
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Bad connection string'; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Bad connection string';
ERROR HY000: SQLDriverConnect: [unixODBC][Driver Manager]Data source name not found, and no default driver specified
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources;
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`Name` varchar(256) NOT NULL, `Name` varchar(256) NOT NULL,
`Description` varchar(256) NOT NULL `Description` varchar(256) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Sources' ) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Sources'
SELECT * FROM t1; SELECT * FROM t1;
Name Description Name Description
Firebird Firebird dBASE Files Microsoft Access dBASE Driver (*.dbf, *.ndx, *.mdx)
PLUGDB_DEBUG PLUGODBC_Driver
PLUGDB_ODBC PLUGODBC_Driver
SafeDB_ODBC SDB_ODBC_Driver
Firebird Firebird/InterBase(r) driver
ConnectEngineXLS Microsoft Excel Driver (*.xls)
Excel Files Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)
MariaODBC MySQL ODBC 5.2a Driver
MariaODBCbeta MariaDB ODBC 1.0 Driver
MyODBC MySQL ODBC 5.2a Driver
MS Access Database Microsoft Access Driver (*.mdb, *.accdb)
MS Access Db1 Microsoft Access Driver (*.mdb)
MySQL-ANSI MySQL ODBC 5.3 ANSI Driver
MySQL-Unicode MySQL ODBC 5.3 Unicode Driver
Xtreme Sample Database 2008 Microsoft Access Driver (*.mdb)
PlugDB test PLUGODBC_Driver
SQLite3 Datasource SQLite3 ODBC Driver
SQLite Datasource SQLite ODBC Driver
SQLite UTF-8 Datasource SQLite ODBC (UTF-8) Driver
ORACLE_TEST Oracle in XE
ConnectEnginePostgresql PostgreSQL ODBC Driver(ANSI)
ConnectEngineOracle Oracle in XE
ConnectEngineSQLServer SQL Server
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers;
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`Description` char(128) NOT NULL, `Description` char(128) NOT NULL,
`Attributes` varchar(256) NOT NULL `Attributes` varchar(256) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Drivers' ) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Drivers'
SELECT * FROM t1; SELECT * FROM t1;
Description Attributes Description Attributes
Firebird Description=Firebird ODBC Driver in usr;Driver=/usr/local/lib/libOdbcFb.so;Setup=/usr/local/lib/libOdbcFb.so;FileUsage=1; SQL Server UsageCount=1;SQLLevel=1;FileUsage=0;DriverODBCVer=03.50;ConnectFunctions=YYY;APILevel=2;CPTimeout=60;
Microsoft ODBC for Oracle UsageCount=1;SQLLevel=1;FileUsage=0;DriverODBCVer=02.50;ConnectFunctions=YYY;APILevel=1;CPTimeout=120;
Microsoft Access Driver (*.mdb) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=2;FileExtns=*.mdb;SQLLevel=0;
Microsoft Access-Treiber (*.mdb) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=2;FileExtns=*.mdb;SQLLevel=0;
Driver do Microsoft Access (*.mdb) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=2;FileExtns=*.mdb;SQLLevel=0;
Microsoft dBase Driver (*.dbf) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.dbf,*.ndx,*.mdx;SQLLevel=0;
Microsoft dBase-Treiber (*.dbf) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.dbf,*.ndx,*.mdx;SQLLevel=0;
Driver do Microsoft dBase (*.dbf) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.dbf,*.ndx,*.mdx;SQLLevel=0;
Microsoft Excel Driver (*.xls) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.xls;SQLLevel=0;
Microsoft Excel-Treiber (*.xls) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.xls;SQLLevel=0;
Driver do Microsoft Excel(*.xls) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.xls;SQLLevel=0;
Microsoft Paradox Driver (*.db ) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.db;SQLLevel=0;
Microsoft Paradox-Treiber (*.db ) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.db;SQLLevel=0;
Driver do Microsoft Paradox (*.db ) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.db;SQLLevel=0;
Microsoft Text Driver (*.txt; *.csv) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.,*.asc,*.csv,*.tab,*.txt,*.csv;SQLLevel=0;
Microsoft Text-Treiber (*.txt; *.csv) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.,*.asc,*.csv,*.tab,*.txt,*.csv;SQLLevel=0;
Driver da Microsoft para arquivos texto (*.txt; *.csv) UsageCount=1;APILevel=1;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.,*.asc,*.csv,*.tab,*.txt,*.csv;SQLLevel=0;
Microsoft Visual FoxPro Driver UsageCount=1;APILevel=0;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.dbf,*.cdx,*.idx,*.fpt;SQLLevel=0;
Microsoft FoxPro VFP Driver (*.dbf) UsageCount=1;APILevel=0;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.dbf,*.cdx,*.idx,*.fpt;SQLLevel=0;
Microsoft dBase VFP Driver (*.dbf) UsageCount=1;APILevel=0;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.dbf,*.cdx,*.idx,*.fpt;SQLLevel=0;
Microsoft Visual FoxPro-Treiber UsageCount=1;APILevel=0;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.dbf,*.cdx,*.idx,*.fpt;SQLLevel=0;
Driver para o Microsoft Visual FoxPro UsageCount=1;APILevel=0;ConnectFunctions=YYN;DriverODBCVer=02.50;FileUsage=1;FileExtns=*.dbf,*.cdx,*.idx,*.fpt;SQLLevel=0;
SQL Native Client UsageCount=1;APILevel=2;ConnectFunctions=YYY;CPTimeout=60;DriverODBCVer=09.00;FileUsage=0;SQLLevel=1;
CR Sybase Wire Protocol ODBC Driver 6.0 UsageCount=1;APILevel=1;ConnectFunctions=YYY;DriverODBCVer=3.52;FileUsage=0;SQLLevel=0;CPTimeout=60;HelpRootDirectory=C:\Program Files\SAP BusinessObjects\SAP BusinessObjects Enterprise XI 4.0\win32_x86\odbc\help;
CR SQL Server Native Wire Protocol ODBC Driver 6.0 UsageCount=1;APILevel=1;ConnectFunctions=YYY;DriverODBCVer=3.52;FileUsage=0;SQLLevel=1;CPTimeout=60;HelpRootDirectory=C:\Program Files\SAP BusinessObjects\SAP BusinessObjects Enterprise XI 4.0\win32_x86\odbc\help;
CR SQL Server Classic Wire Protocol ODBC Driver 6.0 UsageCount=1;APILevel=1;ConnectFunctions=YYY;DriverODBCVer=3.52;FileUsage=0;SQLLevel=1;CPTimeout=60;HelpRootDirectory=C:\Program Files\SAP BusinessObjects\SAP BusinessObjects Enterprise XI 4.0\win32_x86\odbc\help;
CR TextFile ODBC Driver 6.0 UsageCount=1;APILevel=1;ConnectFunctions=YYY;DriverODBCVer=3.52;FileUsage=1;FileExtns=*.*;SQLLevel=0;CPTimeout=60;HelpRootDirectory=C:\Program Files\SAP BusinessObjects\SAP BusinessObjects Enterprise XI 4.0\win32_x86\odbc\help;
PLUGODBC_Driver UsageCount=1;
SDB_ODBC_Driver UsageCount=2;
Microsoft Access Text Driver (*.txt, *.csv) SQLLevel=0;FileExtns=*.txt, *.csv;FileUsage=2;DriverODBCVer=02.50;ConnectFunctions=YYN;APILevel=1;UsageCount=3;
Microsoft Access dBASE Driver (*.dbf, *.ndx, *.mdx) SQLLevel=0;FileExtns=*.dbf, *.ndx, *.mdx;FileUsage=2;DriverODBCVer=02.50;ConnectFunctions=YYN;APILevel=1;UsageCount=3;
Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb) SQLLevel=0;FileExtns=*.xls,*.xlsx, *.xlsb;FileUsage=2;DriverODBCVer=02.50;ConnectFunctions=YYN;APILevel=1;UsageCount=3;
Microsoft Access Driver (*.mdb, *.accdb) SQLLevel=0;FileExtns=*.mdb,*.accdb;FileUsage=2;DriverODBCVer=02.50;ConnectFunctions=YYN;APILevel=1;UsageCount=3;
SQLite3 ODBC Driver UsageCount=1;
SQLite ODBC Driver UsageCount=1;
SQLite ODBC (UTF-8) Driver UsageCount=1;
Oracle in XE ConnectionFunctions=YYY;DriverODBCVer=03.51;CPTimeout=60;FileUsage=0;APILevel=1;SQLLevel=1;
Oracle in instantclient_12_1 APILevel=1;ConnectionFunctions=YYY;CPTimeout=60;DriverODBCVer=03.51;FileUsage=0;SQLLevel=1;
PostgreSQL ODBC Driver(ANSI) APILevel=1;ConnectFunctions=YYN;DriverODBCVer=09.02.0100;FileUsage=0;SQLLevel=1;
PostgreSQL ODBC Driver(UNICODE) APILevel=1;ConnectFunctions=YYN;DriverODBCVer=09.02.0100;FileUsage=0;SQLLevel=1;
SQL Server Native Client 11.0 UsageCount=1;APILevel=2;ConnectFunctions=YYY;CPTimeout=60;DriverODBCVer=03.80;FileUsage=0;SQLLevel=1;
MariaDB ODBC 1.0 Driver UsageCount=1;
Firebird/InterBase(r) driver UsageCount=1;FileExtns=*.fdb,*.gdb;APILevel=1;ConnectFunctions=YYY;FileUsage=0;DriverODBCVer=03.51;SQLLevel=1;
MySQL ODBC 5.3 ANSI Driver UsageCount=1;
MySQL ODBC 5.3 Unicode Driver UsageCount=1;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Tables CONNECTION='Not important'; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Tables CONNECTION='Not important';
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`Table_Cat` char(128) NOT NULL, `Table_Cat` char(128) DEFAULT NULL,
`Table_Schema` char(128) NOT NULL, `Table_Schema` char(128) DEFAULT NULL,
`Table_Name` char(128) NOT NULL, `Table_Name` char(128) NOT NULL,
`Table_Type` char(16) NOT NULL, `Table_Type` char(16) NOT NULL,
`Remark` char(255) NOT NULL `Remark` char(255) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='Not important' `TABLE_TYPE`='ODBC' `CATFUNC`='Tables' ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='Not important' `TABLE_TYPE`='ODBC' `CATFUNC`='Tables'
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Columns CONNECTION='Not important'; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Columns CONNECTION='Not important';
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`Table_Cat` char(128) NOT NULL, `Table_Cat` char(128) DEFAULT NULL,
`Table_Schema` char(128) NOT NULL, `Table_Schema` char(128) DEFAULT NULL,
`Table_Name` char(128) NOT NULL, `Table_Name` char(128) NOT NULL,
`Column_Name` char(128) NOT NULL, `Column_Name` char(128) NOT NULL,
`Data_Type` smallint(6) NOT NULL, `Data_Type` smallint(6) NOT NULL,
`Type_Name` char(30) NOT NULL, `Type_Name` char(30) NOT NULL,
`Column_Size` int(10) NOT NULL, `Column_Size` int(10) NOT NULL,
`Buffer_Length` int(10) NOT NULL, `Buffer_Length` int(10) NOT NULL,
`Decimal_Digits` smallint(6) NOT NULL, `Decimal_Digits` smallint(6) DEFAULT NULL,
`Radix` smallint(6) NOT NULL, `Radix` smallint(6) DEFAULT NULL,
`Nullable` smallint(6) NOT NULL, `Nullable` smallint(6) NOT NULL,
`Remarks` char(255) NOT NULL `Remarks` char(255) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='Not important' `TABLE_TYPE`='ODBC' `CATFUNC`='Columns' ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='Not important' `TABLE_TYPE`='ODBC' `CATFUNC`='Columns'
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC TABNAME='EMPLOYEE' CONNECTION='DSN=Firebird;UID=SYSDBA;PWD=manager'; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC TABNAME='EMPLOYEE' CONNECTION='DSN=Firebird;UID=SYSDBA;PWD=masterkey';
SELECT * FROM t1; SELECT * FROM t1;
EMP_NO FIRST_NAME LAST_NAME PHONE_EXT HIRE_DATE DEPT_NO JOB_CODE JOB_GRADE JOB_COUNTRY SALARY FULL_NAME EMP_NO FIRST_NAME LAST_NAME PHONE_EXT HIRE_DATE DEPT_NO JOB_CODE JOB_GRADE JOB_COUNTRY SALARY FULL_NAME
2 Robert Nelson 250 1988-12-28 00:00:00 600 VP 2 USA 105900.00 Nelson, Robert 2 Robert Nelson 250 1988-12-28 00:00:00 600 VP 2 USA 105900.00 Nelson, Robert
......
...@@ -4,7 +4,7 @@ SET NAMES utf8; ...@@ -4,7 +4,7 @@ SET NAMES utf8;
# MS ODBC and unixODBC return different error message text, # MS ODBC and unixODBC return different error message text,
# so disable displaying error messages # so disable displaying error messages
#--disable_result_log ONCE --disable_result_log ONCE
--error ER_UNKNOWN_ERROR --error ER_UNKNOWN_ERROR
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Bad connection string'; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Bad connection string';
...@@ -30,6 +30,6 @@ CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Columns CONNECTION='Not i ...@@ -30,6 +30,6 @@ CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Columns CONNECTION='Not i
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC TABNAME='EMPLOYEE' CONNECTION='DSN=Firebird;UID=SYSDBA;PWD=manager'; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC TABNAME='EMPLOYEE' CONNECTION='DSN=Firebird;UID=SYSDBA;PWD=masterkey';
SELECT * FROM t1; SELECT * FROM t1;
DROP TABLE t1; DROP TABLE t1;
...@@ -1458,7 +1458,7 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols) ...@@ -1458,7 +1458,7 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols)
n++; n++;
// n can be 0 for query such as Select count(*) from table // n can be 0 for query such as Select count(*) from table
if (n && n != (UWORD)ncol) if (n && n > (UWORD)ncol)
ThrowDBX(MSG(COL_NUM_MISM)); ThrowDBX(MSG(COL_NUM_MISM));
// Now bind the column buffers // Now bind the column buffers
......
...@@ -77,7 +77,8 @@ enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */ ...@@ -77,7 +77,8 @@ enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */
TAB_JSON = 23, /* JSON tables */ TAB_JSON = 23, /* JSON tables */
TAB_JCT = 24, /* Junction tables NIY */ TAB_JCT = 24, /* Junction tables NIY */
TAB_DMY = 25, /* DMY Dummy tables NIY */ TAB_DMY = 25, /* DMY Dummy tables NIY */
TAB_NIY = 26}; /* Table not implemented yet */ TAB_JDBC = 26, /* Table accessed via JDBC */
TAB_NIY = 27}; /* Table not implemented yet */
enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
TYPE_AM_ROWID = 1, /* ROWID type (special column) */ TYPE_AM_ROWID = 1, /* ROWID type (special column) */
...@@ -109,7 +110,9 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ ...@@ -109,7 +110,9 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
TYPE_AM_DIR = 90, /* DIR access method type no */ TYPE_AM_DIR = 90, /* DIR access method type no */
TYPE_AM_ODBC = 100, /* ODBC access method type no */ TYPE_AM_ODBC = 100, /* ODBC access method type no */
TYPE_AM_XDBC = 101, /* XDBC access method type no */ TYPE_AM_XDBC = 101, /* XDBC access method type no */
TYPE_AM_OEM = 110, /* OEM access method type no */ TYPE_AM_JDBC = 102, /* JDBC access method type no */
TYPE_AM_XJDC = 103, /* XJDC access method type no */
TYPE_AM_OEM = 110, /* OEM access method type no */
TYPE_AM_TBL = 115, /* TBL access method type no */ TYPE_AM_TBL = 115, /* TBL access method type no */
TYPE_AM_PIVOT = 120, /* PIVOT access method type no */ TYPE_AM_PIVOT = 120, /* PIVOT access method type no */
TYPE_AM_SRC = 121, /* PIVOT multiple column type no */ TYPE_AM_SRC = 121, /* PIVOT multiple column type no */
...@@ -146,8 +149,9 @@ enum RECFM {RECFM_NAF = -2, /* Not a file */ ...@@ -146,8 +149,9 @@ enum RECFM {RECFM_NAF = -2, /* Not a file */
RECFM_BIN = 2, /* Binary DOS files (also fixed) */ RECFM_BIN = 2, /* Binary DOS files (also fixed) */
RECFM_VCT = 3, /* VCT formatted files */ RECFM_VCT = 3, /* VCT formatted files */
RECFM_ODBC = 4, /* Table accessed via ODBC */ RECFM_ODBC = 4, /* Table accessed via ODBC */
RECFM_PLG = 5, /* Table accessed via PLGconn */ RECFM_JDBC = 5, /* Table accessed via JDBC */
RECFM_DBF = 6}; /* DBase formatted file */ RECFM_PLG = 6, /* Table accessed via PLGconn */
RECFM_DBF = 7}; /* DBase formatted file */
enum MISC {DB_TABNO = 1, /* DB routines in Utility Table */ enum MISC {DB_TABNO = 1, /* DB routines in Utility Table */
MAX_MULT_KEY = 10, /* Max multiple key number */ MAX_MULT_KEY = 10, /* Max multiple key number */
......
...@@ -1102,7 +1102,8 @@ char *GetAmName(PGLOBAL g, AMT am, void *memp) ...@@ -1102,7 +1102,8 @@ char *GetAmName(PGLOBAL g, AMT am, void *memp)
case TYPE_AM_DOM: strcpy(amn, "DOM"); break; case TYPE_AM_DOM: strcpy(amn, "DOM"); break;
case TYPE_AM_DIR: strcpy(amn, "DIR"); break; case TYPE_AM_DIR: strcpy(amn, "DIR"); break;
case TYPE_AM_ODBC: strcpy(amn, "ODBC"); break; case TYPE_AM_ODBC: strcpy(amn, "ODBC"); break;
case TYPE_AM_MAC: strcpy(amn, "MAC"); break; case TYPE_AM_JDBC: strcpy(amn, "JDBC"); break;
case TYPE_AM_MAC: strcpy(amn, "MAC"); break;
case TYPE_AM_OEM: strcpy(amn, "OEM"); break; case TYPE_AM_OEM: strcpy(amn, "OEM"); break;
case TYPE_AM_OUT: strcpy(amn, "OUT"); break; case TYPE_AM_OUT: strcpy(amn, "OUT"); break;
default: sprintf(amn, "OEM(%d)", am); default: sprintf(amn, "OEM(%d)", am);
......
...@@ -305,7 +305,7 @@ int TABDEF::GetColCatInfo(PGLOBAL g) ...@@ -305,7 +305,7 @@ int TABDEF::GetColCatInfo(PGLOBAL g)
case TAB_OEM: case TAB_OEM:
poff = 0; // Offset represents an independant flag poff = 0; // Offset represents an independant flag
break; break;
default: // VCT PLG ODBC MYSQL WMI... default: // VCT PLG ODBC JDBC MYSQL WMI...
poff = 0; // NA poff = 0; // NA
break; break;
} // endswitch tc } // endswitch tc
......
/************* TabJDBC C++ Program Source Code File (.CPP) *************/
/* PROGRAM NAME: TABJDBC */
/* ------------- */
/* Version 1.0 */
/* */
/* COPYRIGHT: */
/* ---------- */
/* (C) Copyright to the author Olivier BERTRAND 2016 */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
/* This program are the TABJDBC class DB execution routines. */
/* */
/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
/* -------------------------------------- */
/* */
/* REQUIRED FILES: */
/* --------------- */
/* TABJDBC.CPP - Source code */
/* PLGDBSEM.H - DB application declaration file */
/* TABJDBC.H - TABJDBC classes declaration file */
/* GLOBAL.H - Global declaration file */
/* */
/* REQUIRED LIBRARIES: */
/* ------------------- */
/* Large model C library */
/* */
/* REQUIRED PROGRAMS: */
/* ------------------ */
/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
/* */
/***********************************************************************/
/***********************************************************************/
/* Include relevant MariaDB header file. */
/***********************************************************************/
#include "my_global.h"
#include "sql_class.h"
#if defined(__WIN__)
#include <io.h>
#include <fcntl.h>
#if defined(__BORLANDC__)
#define __MFC_COMPAT__ // To define min/max as macro
#endif
//#include <windows.h>
#include <sqltypes.h>
#else
#if defined(UNIX)
#include <errno.h>
#define NODW
#include "osutil.h"
#else
#include <io.h>
#endif
#include <fcntl.h>
#endif
/***********************************************************************/
/* Include application header files: */
/* global.h is header containing all global declarations. */
/* plgdbsem.h is header containing the DB application declarations. */
/* kindex.h is kindex header that also includes tabdos.h. */
/* tabJDBC.h is header containing the TABJDBC class declarations. */
/* JDBConn.h is header containing JDBC connection declarations. */
/***********************************************************************/
#include "global.h"
#include "plgdbsem.h"
#include "mycat.h"
#include "xtable.h"
#include "jdbccat.h"
#include "tabjdbc.h"
#include "tabmul.h"
#include "reldef.h"
#include "tabcol.h"
#include "valblk.h"
#include "ha_connect.h"
#include "sql_string.h"
/***********************************************************************/
/* DB static variables. */
/***********************************************************************/
// int num_read, num_there, num_eq[2], num_nf; // Statistics
extern int num_read, num_there, num_eq[2]; // Statistics
/***********************************************************************/
/* External function. */
/***********************************************************************/
bool ExactInfo(void);
/* -------------------------- Class JDBCDEF -------------------------- */
/***********************************************************************/
/* Constructor. */
/***********************************************************************/
JDBCDEF::JDBCDEF(void)
{
Jpath = Driver = Url = Tabname = Tabschema = Username = NULL;
Password = Tabcat = Tabtype = Srcdef = Qchar = Qrystr = Sep = NULL;
Options = Quoted = Maxerr = Maxres = Memory = 0;
Scrollable = Xsrc = false;
} // end of JDBCDEF constructor
/***********************************************************************/
/* DefineAM: define specific AM block values from JDBC file. */
/***********************************************************************/
bool JDBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
{
Jpath = GetStringCatInfo(g, "Jpath", "");
Driver = GetStringCatInfo(g, "Driver", NULL);
Desc = Url = GetStringCatInfo(g, "Url", NULL);
if (!Url && !Catfunc) {
sprintf(g->Message, "Missing URL for JDBC table %s", Name);
return true;
} // endif Connect
Tabname = GetStringCatInfo(g, "Name",
(Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name);
Tabname = GetStringCatInfo(g, "Tabname", Tabname);
Tabschema = GetStringCatInfo(g, "Dbname", NULL);
Tabschema = GetStringCatInfo(g, "Schema", Tabschema);
Tabcat = GetStringCatInfo(g, "Qualifier", NULL);
Tabcat = GetStringCatInfo(g, "Catalog", Tabcat);
Tabtype = GetStringCatInfo(g, "Tabtype", NULL);
Username = GetStringCatInfo(g, "User", NULL);
Password = GetStringCatInfo(g, "Password", NULL);
if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL)))
Read_Only = true;
Qrystr = GetStringCatInfo(g, "Query_String", "?");
Sep = GetStringCatInfo(g, "Separator", NULL);
Xsrc = GetBoolCatInfo("Execsrc", FALSE);
Maxerr = GetIntCatInfo("Maxerr", 0);
Maxres = GetIntCatInfo("Maxres", 0);
Quoted = GetIntCatInfo("Quoted", 0);
//Options = JDBConn::noJDBCDialog;
//Options = JDBConn::noJDBCDialog | JDBConn::useCursorLib;
//Cto= GetIntCatInfo("ConnectTimeout", DEFAULT_LOGIN_TIMEOUT);
//Qto= GetIntCatInfo("QueryTimeout", DEFAULT_QUERY_TIMEOUT);
Scrollable = GetBoolCatInfo("Scrollable", false);
Memory = GetIntCatInfo("Memory", 0);
Pseudo = 2; // FILID is Ok but not ROWID
return false;
} // end of DefineAM
/***********************************************************************/
/* GetTable: makes a new Table Description Block. */
/***********************************************************************/
PTDB JDBCDEF::GetTable(PGLOBAL g, MODE m)
{
PTDBASE tdbp = NULL;
/*********************************************************************/
/* Allocate a TDB of the proper type. */
/* Column blocks will be allocated only when needed. */
/*********************************************************************/
if (Xsrc)
tdbp = new(g)TDBXJDC(this);
else switch (Catfunc) {
case FNC_COL:
tdbp = new(g)TDBJDBCL(this);
break;
#if 0
case FNC_DSN:
tdbp = new(g)TDBJSRC(this);
break;
#endif // 0
case FNC_TABLE:
tdbp = new(g)TDBJTB(this);
break;
case FNC_DRIVER:
tdbp = new(g)TDBJDRV(this);
break;
default:
tdbp = new(g)TDBJDBC(this);
if (Multiple == 1)
tdbp = new(g)TDBMUL(tdbp);
else if (Multiple == 2)
strcpy(g->Message, "NO_JDBC_MUL");
} // endswitch Catfunc
return tdbp;
} // end of GetTable
/***********************************************************************/
/* The MySQL and MariaDB JDBC drivers return by default a result set */
/* containing the entire result of the executed query. This can be an */
/* issue for big tables and memory error can occur. An alternative is */
/* to use streaming (reading one row at a time) but to specify this, */
/* a fech size of the integer min value must be send to the driver. */
/***********************************************************************/
int JDBCPARM::CheckSize(int rows)
{
if (Url && rows == 1) {
// Are we connected to a MySQL JDBC connector?
bool b = (!strncmp(Url, "jdbc:mysql:", 11) ||
!strncmp(Url, "jdbc:mariadb:", 13));
return b ? INT_MIN32 : rows;
} else
return rows;
} // end of CheckSize
/* -------------------------- Class TDBJDBC -------------------------- */
/***********************************************************************/
/* Implementation of the TDBJDBC class. */
/***********************************************************************/
TDBJDBC::TDBJDBC(PJDBCDEF tdp) : TDBASE(tdp)
{
Jcp = NULL;
Cnp = NULL;
if (tdp) {
Jpath = tdp->Jpath;
Ops.Driver = tdp->Driver;
Ops.Url = tdp->Url;
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;
// Ops.Cto = tdp->Cto;
// Ops.Qto = tdp->Qto;
Quoted = MY_MAX(0, tdp->GetQuoted());
Rows = tdp->GetElemt();
Memory = tdp->Memory;
Ops.Scrollable = tdp->Scrollable;
} else {
Jpath = NULL;
TableName = NULL;
Schema = NULL;
Ops.Driver = NULL;
Ops.Url = NULL;
Ops.User = NULL;
Ops.Pwd = NULL;
Catalog = NULL;
Srcdef = NULL;
Qrystr = NULL;
Sep = 0;
Options = 0;
// Ops.Cto = DEFAULT_LOGIN_TIMEOUT;
// Ops.Qto = DEFAULT_QUERY_TIMEOUT;
Quoted = 0;
Rows = 0;
Memory = 0;
Ops.Scrollable = false;
} // endif tdp
Quote = NULL;
Query = NULL;
Count = NULL;
//Where = NULL;
MulConn = NULL;
DBQ = NULL;
Qrp = NULL;
Fpos = 0;
Curpos = 0;
AftRows = 0;
CurNum = 0;
Rbuf = 0;
BufSize = 0;
Ncol = 0;
Nparm = 0;
Placed = false;
Werr = false;
Rerr = false;
Ops.Fsize = Ops.CheckSize(Rows);
} // end of TDBJDBC standard constructor
TDBJDBC::TDBJDBC(PTDBJDBC tdbp) : TDBASE(tdbp)
{
Jcp = tdbp->Jcp; // is that right ?
Cnp = tdbp->Cnp;
Jpath = tdbp->Jpath;
TableName = tdbp->TableName;
Schema = tdbp->Schema;
Ops = tdbp->Ops;
Catalog = tdbp->Catalog;
Srcdef = tdbp->Srcdef;
Qrystr = tdbp->Qrystr;
Memory = tdbp->Memory;
//Scrollable = tdbp->Scrollable;
Quote = tdbp->Quote;
Query = tdbp->Query;
Count = tdbp->Count;
//Where = tdbp->Where;
MulConn = tdbp->MulConn;
DBQ = tdbp->DBQ;
Options = tdbp->Options;
Quoted = tdbp->Quoted;
Rows = tdbp->Rows;
Fpos = 0;
Curpos = 0;
AftRows = 0;
CurNum = 0;
Rbuf = 0;
BufSize = tdbp->BufSize;
Nparm = tdbp->Nparm;
Qrp = tdbp->Qrp;
Placed = false;
} // end of TDBJDBC copy constructor
// Method
PTDB TDBJDBC::CopyOne(PTABS t)
{
PTDB tp;
PJDBCCOL cp1, cp2;
PGLOBAL g = t->G; // Is this really useful ???
tp = new(g)TDBJDBC(this);
for (cp1 = (PJDBCCOL)Columns; cp1; cp1 = (PJDBCCOL)cp1->GetNext()) {
cp2 = new(g)JDBCCOL(cp1, tp); // Make a copy
NewPointer(t, cp1, cp2);
} // endfor cp1
return tp;
} // end of CopyOne
/***********************************************************************/
/* Allocate JDBC column description block. */
/***********************************************************************/
PCOL TDBJDBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{
return new(g)JDBCCOL(cdp, this, cprec, n);
} // end of MakeCol
/******************************************************************/
/* Convert an UTF-8 string to latin characters. */
/******************************************************************/
int TDBJDBC::Decode(char *txt, char *buf, size_t n)
{
uint dummy_errors;
uint32 len= copy_and_convert(buf, n, &my_charset_latin1,
txt, strlen(txt),
&my_charset_utf8_general_ci,
&dummy_errors);
buf[len]= '\0';
return 0;
} // end of Decode
/***********************************************************************/
/* MakeSQL: make the SQL statement use with JDBC connection. */
/* TODO: when implementing EOM filtering, column only used in local */
/* filter should be removed from column list. */
/***********************************************************************/
bool TDBJDBC::MakeSQL(PGLOBAL g, bool cnt)
{
char *schmp = NULL, *catp = NULL, buf[NAM_LEN * 3];
int len;
bool oom = false, first = true;
PTABLE tablep = To_Table;
PCOL colp;
if (Srcdef) {
Query = new(g)STRING(g, 0, Srcdef);
return false;
} // endif Srcdef
// Allocate the string used to contain the Query
Query = new(g)STRING(g, 1023, "SELECT ");
if (!cnt) {
if (Columns) {
// Normal SQL statement to retrieve results
for (colp = Columns; colp; colp = colp->GetNext())
if (!colp->IsSpecial()) {
if (!first)
oom |= Query->Append(", ");
else
first = false;
// Column name can be encoded in UTF-8
Decode(colp->GetName(), buf, sizeof(buf));
if (Quote) {
// Put column name between identifier quotes in case in contains blanks
oom |= Query->Append(Quote);
oom |= Query->Append(buf);
oom |= Query->Append(Quote);
} else
oom |= Query->Append(buf);
((PJDBCCOL)colp)->Rank = ++Ncol;
} // endif colp
} else
// !Columns can occur for queries such that sql count(*) from...
// for which we will count the rows from sql * from...
oom |= Query->Append('*');
} else
// SQL statement used to retrieve the size of the result
oom |= Query->Append("count(*)");
oom |= Query->Append(" FROM ");
if (Catalog && *Catalog)
catp = Catalog;
if (tablep->GetSchema())
schmp = (char*)tablep->GetSchema();
else if (Schema && *Schema)
schmp = Schema;
if (catp) {
oom |= Query->Append(catp);
if (schmp) {
oom |= Query->Append('.');
oom |= Query->Append(schmp);
} // endif schmp
oom |= Query->Append('.');
} else if (schmp) {
oom |= Query->Append(schmp);
oom |= Query->Append('.');
} // endif schmp
// Table name can be encoded in UTF-8
Decode(TableName, buf, sizeof(buf));
if (Quote) {
// Put table name between identifier quotes in case in contains blanks
oom |= Query->Append(Quote);
oom |= Query->Append(buf);
oom |= Query->Append(Quote);
} else
oom |= Query->Append(buf);
len = Query->GetLength();
if (To_CondFil) {
if (Mode == MODE_READ) {
oom |= Query->Append(" WHERE ");
oom |= Query->Append(To_CondFil->Body);
len = Query->GetLength() + 1;
} else
len += (strlen(To_CondFil->Body) + 256);
} else
len += ((Mode == MODE_READX) ? 256 : 1);
if (oom || Query->Resize(len)) {
strcpy(g->Message, "MakeSQL: Out of memory");
return true;
} // endif oom
if (trace)
htrc("Query=%s\n", Query->GetStr());
return false;
} // end of MakeSQL
/***********************************************************************/
/* MakeInsert: make the Insert statement used with JDBC connection. */
/***********************************************************************/
bool TDBJDBC::MakeInsert(PGLOBAL g)
{
char *schmp = NULL, *catp = NULL, buf[NAM_LEN * 3];
int len = 0;
uint pos;
bool b = false, oom = false;
PTABLE tablep = To_Table;
PCOL colp;
for (colp = Columns; colp; colp = colp->GetNext())
if (colp->IsSpecial()) {
strcpy(g->Message, "No JDBC special columns");
return true;
} else {
// Column name can be encoded in UTF-8
Decode(colp->GetName(), buf, sizeof(buf));
len += (strlen(buf) + 6); // comma + quotes + valist
((PJDBCCOL)colp)->Rank = ++Nparm;
} // endif colp
// Below 32 is enough to contain the fixed part of the query
if (Catalog && *Catalog)
catp = Catalog;
if (catp)
len += strlen(catp) + 1;
if (tablep->GetSchema())
schmp = (char*)tablep->GetSchema();
else if (Schema && *Schema)
schmp = Schema;
if (schmp)
len += strlen(schmp) + 1;
// Table name can be encoded in UTF-8
Decode(TableName, buf, sizeof(buf));
len += (strlen(buf) + 32);
Query = new(g)STRING(g, len, "INSERT INTO ");
if (catp) {
oom |= Query->Append(catp);
if (schmp) {
oom |= Query->Append('.');
oom |= Query->Append(schmp);
} // endif schmp
oom |= Query->Append('.');
} else if (schmp) {
oom |= Query->Append(schmp);
oom |= Query->Append('.');
} // endif schmp
if (Quote) {
// Put table name between identifier quotes in case in contains blanks
oom |= Query->Append(Quote);
oom |= Query->Append(buf);
oom |= Query->Append(Quote);
} else
oom |= Query->Append(buf);
oom |= Query->Append('(');
for (colp = Columns; colp; colp = colp->GetNext()) {
if (b)
oom |= Query->Append(", ");
else
b = true;
// Column name can be in UTF-8 encoding
Decode(colp->GetName(), buf, sizeof(buf));
if (Quote) {
// Put column name between identifier quotes in case in contains blanks
oom |= Query->Append(Quote);
oom |= Query->Append(buf);
oom |= Query->Append(Quote);
} else
oom |= Query->Append(buf);
} // endfor colp
if ((oom |= Query->Append(") VALUES ("))) {
strcpy(g->Message, "MakeInsert: Out of memory");
return true;
} else // in case prepared statement fails
pos = Query->GetLength();
// Make prepared statement
for (int i = 0; i < Nparm; i++)
oom |= Query->Append("?,");
if (oom) {
strcpy(g->Message, "MakeInsert: Out of memory");
return true;
} else
Query->RepLast(')');
// Now see if we can use prepared statement
if (Jcp->PrepareSQL(Query->GetStr()))
Query->Truncate(pos); // Restore query to not prepared
else
Prepared = true;
return false;
} // end of MakeInsert
/***********************************************************************/
/* JDBC Set Parameter function. */
/***********************************************************************/
bool TDBJDBC::SetParameters(PGLOBAL g)
{
PJDBCCOL colp;
for (colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->Next)
if (Jcp->SetParam(colp))
return true;
return false;
} // end of SetParameters
/***********************************************************************/
/* MakeCommand: make the Update or Delete statement to send to the */
/* MySQL server. Limited to remote values and filtering. */
/***********************************************************************/
bool TDBJDBC::MakeCommand(PGLOBAL g)
{
char *p, *stmt, name[68], *body = NULL, *qc = Jcp->GetQuoteChar();
char *qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1);
bool qtd = Quoted > 0;
int i = 0, k = 0;
// Make a lower case copy of the originale query and change
// back ticks to the data source identifier quoting character
do {
qrystr[i] = (Qrystr[i] == '`') ? *qc : tolower(Qrystr[i]);
} while (Qrystr[i++]);
if (To_CondFil && (p = strstr(qrystr, " where "))) {
p[7] = 0; // Remove where clause
Qrystr[(p - qrystr) + 7] = 0;
body = To_CondFil->Body;
stmt = (char*)PlugSubAlloc(g, NULL, strlen(qrystr)
+ strlen(body) + 64);
} else
stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
// Check whether the table name is equal to a keyword
// If so, it must be quoted in the original query
strlwr(strcat(strcat(strcpy(name, " "), Name), " "));
if (!strstr(" update delete low_priority ignore quick from ", name))
strlwr(strcpy(name, Name)); // Not a keyword
else
strlwr(strcat(strcat(strcpy(name, qc), Name), qc));
if ((p = strstr(qrystr, name))) {
for (i = 0; i < p - qrystr; i++)
stmt[i] = (Qrystr[i] == '`') ? *qc : Qrystr[i];
stmt[i] = 0;
k = i + (int)strlen(Name);
if (qtd && *(p-1) == ' ')
strcat(strcat(strcat(stmt, qc), TableName), qc);
else
strcat(stmt, TableName);
i = (int)strlen(stmt);
do {
stmt[i++] = (Qrystr[k] == '`') ? *qc : Qrystr[k];
} while (Qrystr[k++]);
if (body)
strcat(stmt, body);
} else {
sprintf(g->Message, "Cannot use this %s command",
(Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
return NULL;
} // endif p
Query = new(g)STRING(g, 0, stmt);
return (!Query->GetSize());
} // end of MakeCommand
/***********************************************************************/
/* ResetSize: call by TDBMUL when calculating size estimate. */
/***********************************************************************/
void TDBJDBC::ResetSize(void)
{
MaxSize = -1;
if (Jcp && Jcp->IsOpen())
Jcp->Close();
} // end of ResetSize
/***********************************************************************/
/* JDBC Cardinality: returns table size in number of rows. */
/***********************************************************************/
int TDBJDBC::Cardinality(PGLOBAL g)
{
if (!g)
return (Mode == MODE_ANY && !Srcdef) ? 1 : 0;
#if 0
if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef && ExactInfo()) {
// Info command, we must return the exact table row number
char qry[96], tbn[64];
JDBConn *jcp = new(g)JDBConn(g, this);
if (jcp->Open(Jpath, &Ops) == RC_FX)
return -1;
// Table name can be encoded in UTF-8
Decode(TableName, tbn, sizeof(tbn));
strcpy(qry, "SELECT COUNT(*) FROM ");
if (Quote)
strcat(strcat(strcat(qry, Quote), tbn), Quote);
else
strcat(qry, tbn);
// Allocate a Count(*) column (must not use the default constructor)
Cnp = new(g)JDBCCOL;
Cnp->InitValue(g);
if ((Cardinal = jcp->GetResultSize(qry, Cnp)) < 0)
return -3;
jcp->Close();
} else
#endif // 0
Cardinal = 10; // To make MariaDB happy
return Cardinal;
} // end of Cardinality
/***********************************************************************/
/* JDBC GetMaxSize: returns table size estimate in number of lines. */
/***********************************************************************/
int TDBJDBC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
if (Mode == MODE_DELETE)
// Return 0 in mode DELETE in case of delete all.
MaxSize = 0;
else if (!Cardinality(NULL))
MaxSize = 10; // To make MySQL happy
else if ((MaxSize = Cardinality(g)) < 0)
MaxSize = 12; // So we can see an error occured
} // endif MaxSize
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/
/* Return max size value. */
/***********************************************************************/
int TDBJDBC::GetProgMax(PGLOBAL g)
{
return GetMaxSize(g);
} // end of GetProgMax
/***********************************************************************/
/* JDBC 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 TDBJDBC::OpenDB(PGLOBAL g)
{
bool rc = true;
if (trace)
htrc("JDBC OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
this, Tdb_No, Use, Mode);
if (Use == USE_OPEN) {
/*******************************************************************/
/* Table already open, just replace it at its beginning. */
/*******************************************************************/
if (Memory == 1) {
if ((Qrp = Jcp->AllocateResult(g)))
Memory = 2; // Must be filled
else
Memory = 0; // Allocation failed, don't use it
} else if (Memory == 2)
Memory = 3; // Ok to use memory result
if (Memory < 3) {
// Method will depend on cursor type
if ((Rbuf = Jcp->Rewind(Query->GetStr())) < 0)
if (Mode != MODE_READX) {
Jcp->Close();
return true;
} else
Rbuf = 0;
} else
Rbuf = Qrp->Nblin;
CurNum = 0;
Fpos = 0;
Curpos = 1;
return false;
} // endif use
/*********************************************************************/
/* Open an JDBC 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 (!Jcp)
Jcp = new(g)JDBConn(g, this);
else if (Jcp->IsOpen())
Jcp->Close();
if (Jcp->Open(Jpath, &Ops) == RC_FX)
return true;
else if (Quoted)
Quote = Jcp->GetQuoteChar();
Use = USE_OPEN; // Do it now in case we are recursively called
/*********************************************************************/
/* Make the command and allocate whatever is used for getting results. */
/*********************************************************************/
if (Mode == MODE_READ || Mode == MODE_READX) {
if (Memory > 1 && !Srcdef) {
int n;
if (!MakeSQL(g, true)) {
// Allocate a Count(*) column
Cnp = new(g)JDBCCOL;
Cnp->InitValue(g);
if ((n = Jcp->GetResultSize(Query->GetStr(), Cnp)) < 0) {
sprintf(g->Message, "Cannot get result size rc=%d", n);
return true;
} else if (n) {
Jcp->m_Rows = n;
if ((Qrp = Jcp->AllocateResult(g)))
Memory = 2; // Must be filled
else {
strcpy(g->Message, "Result set memory allocation failed");
return true;
} // endif n
} else // Void result
Memory = 0;
Jcp->m_Rows = 0;
} else
return true;
} // endif Memory
if (!(rc = MakeSQL(g, false))) {
// for (PJDBCCOL colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->GetNext())
// if (!colp->IsSpecial())
// colp->AllocateBuffers(g, Rows);
rc = (Mode == MODE_READ)
? (Jcp->ExecuteQuery(Query->GetStr()) != RC_OK)
: false;
} // endif rc
} else if (Mode == MODE_INSERT) {
#if 0
if (!(rc = MakeInsert(g))) {
if (Nparm != Jcp->PrepareSQL(Query->GetStr())) {
strcpy(g->Message, MSG(PARM_CNT_MISS));
rc = true;
} else
rc = BindParameters(g);
} // endif rc
#endif // 0
rc = MakeInsert(g);
} else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
rc = false; // wait for CheckCond before calling MakeCommand(g);
} else
sprintf(g->Message, "Invalid mode %d", Mode);
if (rc) {
Jcp->Close();
return true;
} // endif rc
/*********************************************************************/
/* Reset statistics values. */
/*********************************************************************/
num_read = num_there = num_eq[0] = num_eq[1] = 0;
return false;
} // end of OpenDB
/***********************************************************************/
/* GetRecpos: return the position of last read record. */
/***********************************************************************/
int TDBJDBC::GetRecpos(void)
{
return Fpos;
} // end of GetRecpos
/***********************************************************************/
/* SetRecpos: set the position of next read record. */
/***********************************************************************/
bool TDBJDBC::SetRecpos(PGLOBAL g, int recpos)
{
if (Jcp->m_Full) {
Fpos = 0;
// CurNum = 0;
CurNum = 1;
} else if (Memory == 3) {
// Fpos = recpos;
// CurNum = -1;
Fpos = 0;
CurNum = recpos;
} else if (Ops.Scrollable) {
// Is new position in the current row set?
// if (recpos >= Curpos && recpos < Curpos + Rbuf) {
// CurNum = recpos - Curpos;
// Fpos = 0;
if (recpos > 0 && recpos <= Rbuf) {
CurNum = recpos;
Fpos = recpos;
} else {
strcpy(g->Message, "Scrolling out of row set NIY");
return true;
} // endif recpos
} else {
strcpy(g->Message, "This action requires a scrollable cursor");
return true;
} // endif's
// Indicate the table position was externally set
Placed = true;
return false;
} // end of SetRecpos
/***********************************************************************/
/* Data Base indexed read routine for JDBC access method. */
/***********************************************************************/
bool TDBJDBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
{
char c = Quote ? *Quote : 0;
int rc, oldlen = Query->GetLength();
PHC hc = To_Def->GetHandler();
if (!(kr || hc->end_range) || op == OP_NEXT ||
Mode == MODE_UPDATE || Mode == MODE_DELETE) {
if (!kr && Mode == MODE_READX) {
// This is a false indexed read
rc = Jcp->ExecuteQuery((char*)Query->GetStr());
Mode = MODE_READ;
Rows = 1; // ???
return (rc != RC_OK);
} // endif key
return false;
} else {
if (hc->MakeKeyWhere(g, Query, op, c, kr))
return true;
if (To_CondFil) {
if (To_CondFil->Idx != hc->active_index) {
To_CondFil->Idx = hc->active_index;
To_CondFil->Body= (char*)PlugSubAlloc(g, NULL, 0);
*To_CondFil->Body= 0;
if ((To_CondFil = hc->CheckCond(g, To_CondFil, To_CondFil->Cond)))
PlugSubAlloc(g, NULL, strlen(To_CondFil->Body) + 1);
} // endif active_index
if (To_CondFil)
if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
strcpy(g->Message, "Readkey: Out of memory");
return true;
} // endif Append
} // endif To_Condfil
Mode = MODE_READ;
} // endif's op
if (trace)
htrc("JDBC ReadKey: Query=%s\n", Query->GetStr());
rc = Jcp->ExecuteQuery((char*)Query->GetStr());
Query->Truncate(oldlen);
Rows = 1; // ???
return (rc != RC_OK);
} // end of ReadKey
/***********************************************************************/
/* Data Base read routine for JDBC access method. */
/***********************************************************************/
int TDBJDBC::ReadDB(PGLOBAL g)
{
int rc;
if (trace > 1)
htrc("JDBC ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p\n",
GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex);
if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
if (!Query && MakeCommand(g))
return RC_FX;
// Send the UPDATE/DELETE command to the remote table
rc = Jcp->ExecuteUpdate(Query->GetStr());
if (rc == RC_OK) {
AftRows = Jcp->m_Aff;
return RC_EF; // Nothing else to do
} else {
Werr = true;
return RC_FX;
} // endif rc
} // endif Mode
if (To_Kindex) {
// Direct access of JDBC tables is not implemented
strcpy(g->Message, "No JDBC direct access");
return RC_FX;
} // endif To_Kindex
/*********************************************************************/
/* Now start the reading process. */
/* Here is the place to fetch the line(s). */
/*********************************************************************/
if (Placed) {
if (Fpos && CurNum >= 0)
Rbuf = Jcp->Fetch((Curpos = Fpos));
else
Fpos = CurNum;
rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
Placed = false;
} else {
if (Memory != 3) {
if (++CurNum >= Rbuf) {
Rbuf = Jcp->Fetch();
Curpos = Fpos + 1;
CurNum = 0;
} // endif CurNum
rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
} else // Getting result from memory
rc = (Fpos < Qrp->Nblin) ? RC_OK : RC_EF;
if (rc == RC_OK) {
if (Memory == 2)
Qrp->Nblin++;
Fpos++; // Used for memory and pos
} // endif rc
} // endif placed
if (trace > 1)
htrc(" Read: Rbuf=%d rc=%d\n", Rbuf, rc);
return rc;
} // end of ReadDB
/***********************************************************************/
/* Data Base Insert write routine for JDBC access method. */
/***********************************************************************/
int TDBJDBC::WriteDB(PGLOBAL g)
{
int rc;
if (Prepared) {
if (SetParameters(g)) {
Werr = true;
rc = RC_FX;
} else if ((rc = Jcp->ExecuteSQL()) == RC_OK)
AftRows += Jcp->m_Aff;
else
Werr = true;
return rc;
} // endif Prepared
// Statement was not prepared, we must construct and execute
// an insert query for each line to insert
uint len = Query->GetLength();
char buf[64];
bool oom = false;
// Make the Insert command value list
for (PCOL colp = Columns; colp; colp = colp->GetNext()) {
if (!colp->GetValue()->IsNull()) {
char *s = colp->GetValue()->GetCharString(buf);
if (colp->GetResultType() == TYPE_STRING)
oom |= Query->Append_quoted(s);
else if (colp->GetResultType() == TYPE_DATE) {
DTVAL *dtv = (DTVAL*)colp->GetValue();
if (dtv->IsFormatted())
oom |= Query->Append_quoted(s);
else
oom |= Query->Append(s);
} else
oom |= Query->Append(s);
} else
oom |= Query->Append("NULL");
oom |= Query->Append(',');
} // endfor colp
if (unlikely(oom)) {
strcpy(g->Message, "WriteDB: Out of memory");
return RC_FX;
} // endif oom
Query->RepLast(')');
rc = Jcp->ExecuteUpdate(Query->GetStr());
Query->Truncate(len); // Restore query
if (rc == RC_OK)
AftRows += Jcp->m_Aff;
else
Werr = true;
return rc;
} // end of WriteDB
/***********************************************************************/
/* Data Base delete line routine for JDBC access method. */
/***********************************************************************/
int TDBJDBC::DeleteDB(PGLOBAL g, int irc)
{
if (irc == RC_FX) {
if (!Query && MakeCommand(g))
return RC_FX;
// Send the DELETE (all) command to the remote table
if (Jcp->ExecuteUpdate(Query->GetStr()) == RC_OK) {
AftRows = Jcp->m_Aff;
sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
if (trace)
htrc("%s\n", g->Message);
PushWarning(g, this, 0); // 0 means a Note
return RC_OK; // This is a delete all
} else
return RC_FX; // Error
} else
return RC_OK; // Ignore
} // end of DeleteDB
/***********************************************************************/
/* Data Base close routine for JDBC access method. */
/***********************************************************************/
void TDBJDBC::CloseDB(PGLOBAL g)
{
//if (To_Kindex) {
// To_Kindex->Close();
// To_Kindex = NULL;
// } // endif
if (Jcp)
Jcp->Close();
if (trace)
htrc("JDBC CloseDB: closing %s\n", Name);
if (!Werr &&
(Mode == MODE_INSERT || Mode == MODE_UPDATE || Mode == MODE_DELETE)) {
sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
if (trace)
htrc("%s\n", g->Message);
PushWarning(g, this, 0); // 0 means a Note
} // endif Mode
Prepared = false;
} // end of CloseDB
/* --------------------------- JDBCCOL ------------------------------- */
/***********************************************************************/
/* JDBCCOL public constructor. */
/***********************************************************************/
JDBCCOL::JDBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
: COLBLK(cdp, tdbp, i)
{
if (cprec) {
Next = cprec->GetNext();
cprec->SetNext(this);
} else {
Next = tdbp->GetColumns();
tdbp->SetColumns(this);
} // endif cprec
// Set additional JDBC access method information for column.
Crp = NULL;
//Long = cdp->GetLong();
Long = Precision;
//strcpy(F_Date, cdp->F_Date);
To_Val = NULL;
//Slen = 0;
//StrLen = &Slen;
//Sqlbuf = NULL;
Bufp = NULL;
Blkp = NULL;
Rank = 0; // Not known yet
if (trace)
htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
} // end of JDBCCOL constructor
/***********************************************************************/
/* JDBCCOL private constructor. */
/***********************************************************************/
JDBCCOL::JDBCCOL(void) : COLBLK()
{
Crp = NULL;
Buf_Type = TYPE_INT; // This is a count(*) column
// Set additional Dos access method information for column.
Long = sizeof(int);
To_Val = NULL;
//Slen = 0;
//StrLen = &Slen;
//Sqlbuf = NULL;
Bufp = NULL;
Blkp = NULL;
Rank = 1;
} // end of JDBCCOL constructor
/***********************************************************************/
/* JDBCCOL constructor used for copying columns. */
/* tdbp is the pointer to the new table descriptor. */
/***********************************************************************/
JDBCCOL::JDBCCOL(JDBCCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
{
Crp = col1->Crp;
Long = col1->Long;
//strcpy(F_Date, col1->F_Date);
To_Val = col1->To_Val;
//Slen = col1->Slen;
//StrLen = col1->StrLen;
//Sqlbuf = col1->Sqlbuf;
Bufp = col1->Bufp;
Blkp = col1->Blkp;
Rank = col1->Rank;
} // end of JDBCCOL copy constructor
/***********************************************************************/
/* SetBuffer: prepare a column block for write operation. */
/***********************************************************************/
bool JDBCCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
{
if (!(To_Val = value)) {
sprintf(g->Message, MSG(VALUE_ERROR), Name);
return true;
} else if (Buf_Type == value->GetType()) {
// Values are of the (good) column type
if (Buf_Type == TYPE_DATE) {
// If any of the date values is formatted
// output format must be set for the receiving table
if (GetDomain() || ((DTVAL *)value)->IsFormatted())
goto newval; // This will make a new value;
} else if (Buf_Type == TYPE_DOUBLE)
// Float values must be written with the correct (column) precision
// Note: maybe this should be forced by ShowValue instead of this ?
value->SetPrec(GetScale());
Value = value; // Directly access the external value
} else {
// Values are not of the (good) column type
if (check) {
sprintf(g->Message, MSG(TYPE_VALUE_ERR), Name,
GetTypeName(Buf_Type), GetTypeName(value->GetType()));
return true;
} // endif check
newval:
if (InitValue(g)) // Allocate the matching value block
return true;
} // endif's Value, Buf_Type
// Because Colblk's have been made from a copy of the original TDB in
// case of Update, we must reset them to point to the original one.
if (To_Tdb->GetOrig())
To_Tdb = (PTDB)To_Tdb->GetOrig();
// Set the Column
Status = (ok) ? BUF_EMPTY : BUF_NO;
return false;
} // end of SetBuffer
/***********************************************************************/
/* ReadColumn: when SQLFetch is used there is nothing to do as the */
/* column buffer was bind to the record set. This is also the case */
/* when calculating MaxSize (Bufp is NULL even when Rows is not). */
/***********************************************************************/
void JDBCCOL::ReadColumn(PGLOBAL g)
{
PTDBJDBC tdbp = (PTDBJDBC)To_Tdb;
int i = tdbp->Fpos - 1, n = tdbp->CurNum;
if (tdbp->Memory == 3) {
// Get the value from the stored memory
if (Crp->Nulls && Crp->Nulls[i] == '*') {
Value->Reset();
Value->SetNull(true);
} else {
Value->SetValue_pvblk(Crp->Kdata, i);
Value->SetNull(false);
} // endif Nulls
return;
} // endif Memory
/*********************************************************************/
/* Get the column value. */
/*********************************************************************/
tdbp->Jcp->SetColumnValue(Rank, Name, Value);
if (tdbp->Memory != 2)
return;
/*********************************************************************/
/* Fill the allocated result structure. */
/*********************************************************************/
if (Value->IsNull()) {
if (Crp->Nulls)
Crp->Nulls[i] = '*'; // Null value
Crp->Kdata->Reset(i);
} else
Crp->Kdata->SetValue(Value, i);
} // end of ReadColumn
#if 0
/***********************************************************************/
/* AllocateBuffers: allocate the extended buffer for SQLExtendedFetch */
/* or Fetch. Note: we use Long+1 here because JDBC must have space */
/* for the ending null character. */
/***********************************************************************/
void JDBCCOL::AllocateBuffers(PGLOBAL g, int rows)
{
if (Buf_Type == TYPE_DATE)
Sqlbuf = (TIMESTAMP_STRUCT*)PlugSubAlloc(g, NULL,
sizeof(TIMESTAMP_STRUCT));
if (!rows)
return;
if (Buf_Type == TYPE_DATE)
Bufp = PlugSubAlloc(g, NULL, rows * sizeof(TIMESTAMP_STRUCT));
else {
Blkp = AllocValBlock(g, NULL, Buf_Type, rows, GetBuflen(),
GetScale(), true, false, false);
Bufp = Blkp->GetValPointer();
} // endelse
if (rows > 1)
StrLen = (SQLLEN *)PlugSubAlloc(g, NULL, rows * sizeof(SQLLEN));
} // end of AllocateBuffers
/***********************************************************************/
/* Returns the buffer to use for Fetch or Extended Fetch. */
/***********************************************************************/
void *JDBCCOL::GetBuffer(DWORD rows)
{
if (rows && To_Tdb) {
assert(rows == (DWORD)((TDBJDBC*)To_Tdb)->Rows);
return Bufp;
} else
return (Buf_Type == TYPE_DATE) ? Sqlbuf : Value->GetTo_Val();
} // end of GetBuffer
/***********************************************************************/
/* Returns the buffer length to use for Fetch or Extended Fetch. */
/***********************************************************************/
SWORD JDBCCOL::GetBuflen(void)
{
SWORD flen;
switch (Buf_Type) {
case TYPE_DATE:
flen = (SWORD)sizeof(TIMESTAMP_STRUCT);
break;
case TYPE_STRING:
case TYPE_DECIM:
flen = (SWORD)Value->GetClen() + 1;
break;
default:
flen = (SWORD)Value->GetClen();
} // endswitch Buf_Type
return flen;
} // end of GetBuflen
#endif // 0
/***********************************************************************/
/* WriteColumn: make sure the bind buffer is updated. */
/***********************************************************************/
void JDBCCOL::WriteColumn(PGLOBAL g)
{
/*********************************************************************/
/* Do convert the column value if necessary. */
/*********************************************************************/
if (Value != To_Val)
Value->SetValue_pval(To_Val, FALSE); // Convert the inserted value
#if 0
if (Buf_Type == TYPE_DATE) {
struct tm tm, *dbtime = ((DTVAL*)Value)->GetGmTime(&tm);
Sqlbuf->second = dbtime->tm_sec;
Sqlbuf->minute = dbtime->tm_min;
Sqlbuf->hour = dbtime->tm_hour;
Sqlbuf->day = dbtime->tm_mday;
Sqlbuf->month = dbtime->tm_mon + 1;
Sqlbuf->year = dbtime->tm_year + 1900;
Sqlbuf->fraction = 0;
} else if (Buf_Type == TYPE_DECIM) {
// Some data sources require local decimal separator
char *p, sep = ((PTDBJDBC)To_Tdb)->Sep;
if (sep && (p = strchr(Value->GetCharValue(), '.')))
*p = sep;
} // endif Buf_Type
if (Nullable)
*StrLen = (Value->IsNull()) ? SQL_NULL_DATA :
(IsTypeChar(Buf_Type)) ? SQL_NTS : 0;
#endif // 0
} // end of WriteColumn
/* -------------------------- Class TDBXJDC -------------------------- */
/***********************************************************************/
/* Implementation of the TDBXJDC class. */
/***********************************************************************/
TDBXJDC::TDBXJDC(PJDBCDEF tdp) : TDBJDBC(tdp)
{
Cmdlist = NULL;
Cmdcol = NULL;
Mxr = tdp->Maxerr;
Nerr = 0;
} // end of TDBXJDC constructor
/***********************************************************************/
/* Allocate XSRC column description block. */
/***********************************************************************/
PCOL TDBXJDC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{
PJSRCCOL colp = new(g)JSRCCOL(cdp, this, cprec, n);
if (!colp->Flag)
Cmdcol = colp->GetName();
return colp;
} // end of MakeCol
/***********************************************************************/
/* MakeCMD: make the SQL statement to send to JDBC connection. */
/***********************************************************************/
PCMD TDBXJDC::MakeCMD(PGLOBAL g)
{
PCMD xcmd = NULL;
if (To_CondFil) {
if (Cmdcol) {
if (!stricmp(Cmdcol, To_CondFil->Body) &&
(To_CondFil->Op == OP_EQ || To_CondFil->Op == OP_IN)) {
xcmd = To_CondFil->Cmds;
} 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 = new(g) CMD(g, Srcdef);
return xcmd;
} // end of MakeCMD
#if 0
/***********************************************************************/
/* JDBC Bind Parameter function. */
/***********************************************************************/
bool TDBXJDC::BindParameters(PGLOBAL g)
{
PJDBCCOL colp;
for (colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->Next) {
colp->AllocateBuffers(g, 0);
if (Jcp->BindParam(colp))
return true;
} // endfor colp
return false;
} // end of BindParameters
#endif // 0
/***********************************************************************/
/* XDBC GetMaxSize: returns table size (not always one row). */
/***********************************************************************/
int TDBXJDC::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0)
MaxSize = 2; // Just a guess
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/
/* JDBC 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 TDBXJDC::OpenDB(PGLOBAL g)
{
bool rc = false;
if (trace)
htrc("JDBC OpenDB: tdbp=%p tdb=R%d use=%d mode=%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 JDBC 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 (!Jcp) {
Jcp = new(g) JDBConn(g, this);
} else if (Jcp->IsOpen())
Jcp->Close();
if (Jcp->Open(Jpath, &Ops) == RC_FX)
return true;
Use = USE_OPEN; // Do it now in case we are recursively called
if (Mode != MODE_READ && Mode != MODE_READX) {
strcpy(g->Message, "No INSERT/DELETE/UPDATE of XJDBC tables");
return true;
} // endif Mode
/*********************************************************************/
/* Get the command to execute. */
/*********************************************************************/
if (!(Cmdlist = MakeCMD(g))) {
Jcp->Close();
return true;
} // endif Query
Rows = 1;
return false;
} // end of OpenDB
/***********************************************************************/
/* ReadDB: Data Base read routine for xdbc access method. */
/***********************************************************************/
int TDBXJDC::ReadDB(PGLOBAL g)
{
if (Cmdlist) {
int rc;
if (!Query)
Query = new(g) STRING(g, 0, Cmdlist->Cmd);
else
Query->Set(Cmdlist->Cmd);
if ((rc = Jcp->ExecSQLcommand(Query->GetStr())) == RC_FX)
Nerr++;
if (rc == RC_NF)
AftRows = Jcp->m_Aff;
else if (rc == RC_OK)
AftRows = Jcp->m_Ncol;
Fpos++; // Used for progress info
Cmdlist = (Nerr > Mxr) ? NULL : Cmdlist->Next;
return RC_OK;
} else
return RC_EF;
} // end of ReadDB
/***********************************************************************/
/* Data Base write line routine for JDBC access method. */
/***********************************************************************/
int TDBXJDC::WriteDB(PGLOBAL g)
{
strcpy(g->Message, "Execsrc tables are read only");
return RC_FX;
} // end of DeleteDB
/***********************************************************************/
/* Data Base delete line routine for JDBC access method. */
/***********************************************************************/
int TDBXJDC::DeleteDB(PGLOBAL g, int irc)
{
strcpy(g->Message, "NO_XJDBC_DELETE");
return RC_FX;
} // end of DeleteDB
/* --------------------------- JSRCCOL ------------------------------- */
/***********************************************************************/
/* JSRCCOL public constructor. */
/***********************************************************************/
JSRCCOL::JSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
: JDBCCOL(cdp, tdbp, cprec, i, am)
{
// Set additional JDBC access method information for column.
Flag = cdp->GetOffset();
} // end of JSRCCOL constructor
/***********************************************************************/
/* ReadColumn: set column value according to Flag. */
/***********************************************************************/
void JSRCCOL::ReadColumn(PGLOBAL g)
{
PTDBXJDC tdbp = (PTDBXJDC)To_Tdb;
switch (Flag) {
case 0: Value->SetValue_psz(tdbp->Query->GetStr()); 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 JSRCCOL::WriteColumn(PGLOBAL g)
{
// Should never be called
} // end of WriteColumn
/* ---------------------------TDBJDRV class -------------------------- */
/***********************************************************************/
/* GetResult: Get the list of JDBC drivers. */
/***********************************************************************/
PQRYRES TDBJDRV::GetResult(PGLOBAL g)
{
return JDBCDrivers(g, Jpath, Maxres, false);
} // end of GetResult
/* ---------------------------TDBJTB class --------------------------- */
/***********************************************************************/
/* TDBJTB class constructor. */
/***********************************************************************/
TDBJTB::TDBJTB(PJDBCDEF tdp) : TDBJDRV(tdp)
{
Jpath = tdp->Jpath;
Schema = tdp->Tabschema;
Tab = tdp->Tabname;
Tabtype = tdp->Tabtype;
Ops.Driver = tdp->Driver;
Ops.Url = tdp->Url;
Ops.User = tdp->Username;
Ops.Pwd = tdp->Password;
} // end of TDBJTB constructor
/***********************************************************************/
/* GetResult: Get the list of JDBC tables. */
/***********************************************************************/
PQRYRES TDBJTB::GetResult(PGLOBAL g)
{
return JDBCTables(g, Jpath, Schema, Tab, Tabtype, Maxres, false, &Ops);
} // end of GetResult
/* --------------------------TDBJDBCL class -------------------------- */
/***********************************************************************/
/* GetResult: Get the list of JDBC table columns. */
/***********************************************************************/
PQRYRES TDBJDBCL::GetResult(PGLOBAL g)
{
return JDBCColumns(g, Jpath, Schema, Tab, NULL, Maxres, false, &Ops);
} // end of GetResult
#if 0
/* ---------------------------TDBJSRC class -------------------------- */
/***********************************************************************/
/* GetResult: Get the list of JDBC data sources. */
/***********************************************************************/
PQRYRES TDBJSRC::GetResult(PGLOBAL g)
{
return JDBCDataSources(g, Maxres, false);
} // end of GetResult
/* ------------------------ End of TabJDBC --------------------------- */
#endif // 0
/*************** Tabjdbc H Declares Source Code File (.H) **************/
/* Name: TABJDBC.H Version 1.0 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2016 */
/* */
/* This file contains the TDBJDBC classes declares. */
/***********************************************************************/
#include "colblk.h"
#include "resource.h"
typedef class JDBCDEF *PJDBCDEF;
typedef class TDBJDBC *PTDBJDBC;
typedef class JDBCCOL *PJDBCCOL;
typedef class TDBXJDC *PTDBXJDC;
typedef class JSRCCOL *PJSRCCOL;
//typedef class TDBOIF *PTDBOIF;
//typedef class OIFCOL *POIFCOL;
//typedef class TDBJSRC *PTDBJSRC;
/***********************************************************************/
/* JDBC table. */
/***********************************************************************/
class DllExport JDBCDEF : public TABDEF { /* Logical table description */
friend class TDBJDBC;
friend class TDBXJDC;
friend class TDBJDRV;
friend class TDBJTB;
public:
// Constructor
JDBCDEF(void);
// Implementation
virtual const char *GetType(void) { return "JDBC"; }
PSZ GetJpath(void) { return Jpath; }
PSZ GetTabname(void) { return Tabname; }
PSZ GetTabschema(void) { return Tabschema; }
PSZ GetTabcat(void) { return Tabcat; }
PSZ GetSrcdef(void) { return Srcdef; }
char GetSep(void) { return (Sep) ? *Sep : 0; }
int GetQuoted(void) { return Quoted; }
//int GetCatver(void) { return Catver; }
int GetOptions(void) { return Options; }
// Methods
virtual int Indexable(void) { return 2; }
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
virtual PTDB GetTable(PGLOBAL g, MODE m);
protected:
// Members
PSZ Jpath; /* Java class path */
PSZ Driver; /* JDBC driver */
PSZ Url; /* JDBC driver URL */
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 Tabtype; /* External table type */
PSZ Srcdef; /* The source table SQL definition */
PSZ Qchar; /* Identifier quoting character */
PSZ Qrystr; /* The original query */
PSZ Sep; /* Decimal separator */
int Options; /* Open connection options */
//int Cto; /* Open connection timeout */
//int Qto; /* Query (command) timeout */
int Quoted; /* Identifier quoting level */
int Maxerr; /* Maxerr for an Exec table */
int Maxres; /* Maxres for a catalog table */
int Memory; /* Put result set in memory */
bool Scrollable; /* Use scrollable cursor */
bool Xsrc; /* Execution type */
}; // end of JDBCDEF
#if !defined(NJDBC)
#include "JDBConn.h"
/***********************************************************************/
/* This is the JDBC Access Method class declaration for files from */
/* other DB drivers to be accessed via JDBC. */
/***********************************************************************/
class TDBJDBC : public TDBASE {
friend class JDBCCOL;
friend class JDBConn;
public:
// Constructor
TDBJDBC(PJDBCDEF tdp = NULL);
TDBJDBC(PTDBJDBC tdbp);
// Implementation
virtual AMT GetAmType(void) { return TYPE_AM_JDBC; }
virtual PTDB Duplicate(PGLOBAL g) { return (PTDB)new(g)TDBJDBC(this); }
// Methods
virtual PTDB CopyOne(PTABS t);
virtual int GetRecpos(void);
virtual bool SetRecpos(PGLOBAL g, int recpos);
//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 "JDBC"; }
virtual int Indexable(void) { return 2; }
// Database routines
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
virtual int Cardinality(PGLOBAL g);
virtual int GetMaxSize(PGLOBAL g);
virtual int GetProgMax(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);
virtual bool ReadKey(PGLOBAL g, OPVAL op, const key_range *kr);
protected:
// Internal functions
int Decode(char *utf, char *buf, size_t n);
bool MakeSQL(PGLOBAL g, bool cnt);
bool MakeInsert(PGLOBAL g);
bool MakeCommand(PGLOBAL g);
//bool MakeFilter(PGLOBAL g, bool c);
bool SetParameters(PGLOBAL g);
//char *MakeUpdate(PGLOBAL g);
//char *MakeDelete(PGLOBAL g);
// Members
JDBConn *Jcp; // Points to a JDBC connection class
JDBCCOL *Cnp; // Points to count(*) column
JDBCPARM Ops; // Additional parameters
PSTRG Query; // Constructed SQL query
char *Jpath; // Java class path
char *TableName; // Points to JDBC table name
char *Schema; // Points to JDBC table Schema
char *User; // User connect info
char *Pwd; // Password connect info
char *Catalog; // Points to JDBC table Catalog
char *Srcdef; // The source table SQL definition
char *Count; // Points to count(*) SQL statement
//char *Where; // Points to local where clause
char *Quote; // The identifier quoting character
char *MulConn; // Used for multiple JDBC tables
char *DBQ; // The address part of Connect string
char *Qrystr; // The original query
char Sep; // The decimal separator
int Options; // Connect options
//int Cto; // Connect timeout
//int Qto; // Query timeout
int Quoted; // The identifier quoting level
int Fpos; // Position of last read record
int Curpos; // Cursor position of last fetch
int AftRows; // The number of affected rows
int Rows; // Rowset size
int CurNum; // Current buffer line number
int Rbuf; // Number of lines read in buffer
int BufSize; // Size of connect string buffer
int Ncol; // The column number
int Nparm; // The number of statement parameters
int Memory; // 0: No 1: Alloc 2: Put 3: Get
//bool Scrollable; // Use scrollable cursor --> in Ops
bool Placed; // True for position reading
bool Prepared; // True when using prepared statement
bool Werr; // Write error
bool Rerr; // Rewind error
PQRYRES Qrp; // Points to storage result
}; // end of class TDBJDBC
/***********************************************************************/
/* Class JDBCCOL: JDBC access method column descriptor. */
/* This A.M. is used for JDBC tables. */
/***********************************************************************/
class JDBCCOL : public COLBLK {
friend class TDBJDBC;
public:
// Constructors
JDBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "JDBC");
JDBCCOL(JDBCCOL *colp, PTDB tdbp); // Constructor used in copy process
// Implementation
virtual int GetAmType(void) { return TYPE_AM_JDBC; }
//SQLLEN *GetStrLen(void) { return StrLen; }
int GetRank(void) { return Rank; }
//PVBLK GetBlkp(void) {return Blkp;}
void SetCrp(PCOLRES crp) { Crp = crp; }
// Methods
virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
virtual void ReadColumn(PGLOBAL g);
virtual void WriteColumn(PGLOBAL g);
//void AllocateBuffers(PGLOBAL g, int rows);
//void *GetBuffer(DWORD rows);
//SWORD GetBuflen(void);
// void Print(PGLOBAL g, FILE *, uint);
protected:
// Constructor used by GetMaxSize
JDBCCOL(void);
// Members
//TIMESTAMP_STRUCT *Sqlbuf; // To get SQL_TIMESTAMP's
PCOLRES Crp; // To storage result
void *Bufp; // To extended buffer
PVBLK Blkp; // To Value Block
//char F_Date[12]; // Internal Date format
PVAL To_Val; // To value used for Insert
//SQLLEN *StrLen; // As returned by JDBC
//SQLLEN Slen; // Used with Fetch
int Rank; // Rank (position) number in the query
}; // end of class JDBCCOL
/***********************************************************************/
/* This is the JDBC Access Method class declaration that send */
/* commands to be executed by other DB JDBC drivers. */
/***********************************************************************/
class TDBXJDC : public TDBJDBC {
friend class JSRCCOL;
friend class JDBConn;
public:
// Constructors
TDBXJDC(PJDBCDEF tdp = NULL);
// Implementation
virtual AMT GetAmType(void) {return TYPE_AM_XDBC;}
// Methods
//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 "JDBC";}
// 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
PCMD MakeCMD(PGLOBAL g);
//bool BindParameters(PGLOBAL g);
// Members
PCMD Cmdlist; // The commands to execute
char *Cmdcol; // The name of the Xsrc command column
int Mxr; // Maximum errors before closing
int Nerr; // Number of errors so far
}; // end of class TDBXJDC
/***********************************************************************/
/* Used by table in source execute mode. */
/***********************************************************************/
class JSRCCOL : public JDBCCOL {
friend class TDBXJDC;
public:
// Constructors
JSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "JDBC");
// Implementation
//virtual int GetAmType(void) {return TYPE_AM_JDBC;}
// 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 JSRCCOL
/***********************************************************************/
/* This is the class declaration for the Drivers catalog table. */
/***********************************************************************/
class TDBJDRV : public TDBCAT {
public:
// Constructor
TDBJDRV(PJDBCDEF tdp) : TDBCAT(tdp) {Maxres = tdp->Maxres; Jpath = tdp->Jpath;}
protected:
// Specific routines
virtual PQRYRES GetResult(PGLOBAL g);
// Members
int Maxres; // Returned lines limit
char *Jpath; // Java class path
}; // end of class TDBJDRV
/***********************************************************************/
/* This is the class declaration for the tables catalog table. */
/***********************************************************************/
class TDBJTB : public TDBJDRV {
public:
// Constructor
TDBJTB(PJDBCDEF tdp);
protected:
// Specific routines
virtual PQRYRES GetResult(PGLOBAL g);
// Members
char *Jpath; // Points to Java classpath
char *Schema; // Points to schema name or NULL
char *Tab; // Points to JDBC table name or pattern
char *Tabtype; // Points to JDBC table type
JDBCPARM Ops; // Additional parameters
}; // end of class TDBJTB
/***********************************************************************/
/* This is the class declaration for the columns catalog table. */
/***********************************************************************/
class TDBJDBCL : public TDBJTB {
public:
// Constructor
TDBJDBCL(PJDBCDEF tdp) : TDBJTB(tdp) {}
protected:
// Specific routines
virtual PQRYRES GetResult(PGLOBAL g);
// No additional Members
}; // end of class TDBJCL
#if 0
/***********************************************************************/
/* This is the class declaration for the Data Sources catalog table. */
/***********************************************************************/
class TDBJSRC : public TDBJDRV {
public:
// Constructor
TDBJSRC(PJDBCDEF tdp) : TDBJDRV(tdp) {}
protected:
// Specific routines
virtual PQRYRES GetResult(PGLOBAL g);
// No additional Members
}; // end of class TDBJSRC
#endif // 0
#endif // !NJDBC
...@@ -97,8 +97,8 @@ ODBCDEF::ODBCDEF(void) ...@@ -97,8 +97,8 @@ ODBCDEF::ODBCDEF(void)
{ {
Connect = Tabname = Tabschema = Username = Password = NULL; Connect = Tabname = Tabschema = Username = Password = NULL;
Tabcat = Srcdef = Qchar = Qrystr = Sep = NULL; Tabcat = Srcdef = Qchar = Qrystr = Sep = NULL;
Catver = Options = Cto = Qto = Quoted = Maxerr = Maxres = 0; Catver = Options = Cto = Qto = Quoted = Maxerr = Maxres = Memory = 0;
Scrollable = Memory = Xsrc = UseCnc = false; Scrollable = Xsrc = UseCnc = false;
} // end of ODBCDEF constructor } // end of ODBCDEF constructor
/***********************************************************************/ /***********************************************************************/
...@@ -1009,7 +1009,7 @@ bool TDBODBC::SetRecpos(PGLOBAL g, int recpos) ...@@ -1009,7 +1009,7 @@ bool TDBODBC::SetRecpos(PGLOBAL g, int recpos)
} // end of SetRecpos } // end of SetRecpos
/***********************************************************************/ /***********************************************************************/
/* Data Base indexed read routine for MYSQL access method. */ /* Data Base indexed read routine for ODBC access method. */
/***********************************************************************/ /***********************************************************************/
bool TDBODBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr) bool TDBODBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
{ {
...@@ -1028,7 +1028,7 @@ bool TDBODBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr) ...@@ -1028,7 +1028,7 @@ bool TDBODBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
return false; return false;
} else { } else {
if (To_Def->GetHandler()->MakeKeyWhere(g, Query, op, c, kr)) if (hc->MakeKeyWhere(g, Query, op, c, kr))
return true; return true;
if (To_CondFil) { if (To_CondFil) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment