Commit 5af076e5 authored by Olivier Bertrand's avatar Olivier Bertrand

Add all changes made on 10.1

parent 26adbb2d
......@@ -257,6 +257,32 @@ int main() {
ENDIF(UNIX)
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
# TODO: Find how to compile and install the JdbcInterface.java class
# Find required libraries and include directories
FIND_PACKAGE(Java)
FIND_PACKAGE(JNI)
IF (JAVA_FOUND AND JNI_FOUND)
INCLUDE_DIRECTORIES(${JAVA_INCLUDE_PATH})
INCLUDE_DIRECTORIES(${JAVA_INCLUDE_PATH2})
# SET(JDBC_LIBRARY ${JAVA_JVM_LIBRARY})
SET(CONNECT_SOURCES ${CONNECT_SOURCES}
JdbcInterface.java JdbcInterface.class
jdbconn.cpp tabjdbc.cpp jdbconn.h tabjdbc.h jdbccat.h)
add_definitions(-DJDBC_SUPPORT)
ELSE()
SET(JDBC_LIBRARY "")
ENDIF()
ENDIF(CONNECT_WITH_JDBC)
#
# XMAP
......@@ -277,5 +303,5 @@ MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES}
COMPONENT connect-engine
RECOMPILE_FOR_EMBEDDED
LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY}
${ODBC_LIBRARY} ${IPHLPAPI_LIBRARY})
${ODBC_LIBRARY} ${JDBC_LIBRARY} ${IPHLPAPI_LIBRARY})
This diff was suppressed by a .gitattributes entry.
import java.math.*;
import java.sql.*;
import java.util.Collections;
import java.util.List;
public class JdbcInterface {
boolean DEBUG = false;
Connection conn = null;
DatabaseMetaData dbmd = null;
Statement stmt = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
ResultSetMetaData rsmd = null;
// === Constructors/finalize =========================================
public JdbcInterface() {
this(true);
} // end of default constructor
public JdbcInterface(boolean b) {
DEBUG = b;
} // end of constructor
public int JdbcConnect(String[] parms, int fsize, boolean scrollable) {
int rc = 0;
if (DEBUG)
System.out.println("In JdbcInterface: driver=" + parms[0]);
try {
if (DEBUG)
System.out.println("In try block");
if (parms[0] != null && !parms[0].isEmpty()) {
System.out.println("b is true!");
Class.forName(parms[0]); //loads the driver
} // endif driver
if (DEBUG)
System.out.println("URL=" + parms[1]);
if (parms[2] != null && !parms[2].isEmpty()) {
if (DEBUG)
System.out.println("user=" + parms[2] + " pwd=" + parms[3]);
conn = DriverManager.getConnection(parms[1], parms[2], parms[3]);
} else
conn = DriverManager.getConnection(parms[1]);
if (DEBUG)
System.out.println("Connection " + conn.toString() + " established");
// Get the data base meta data object
dbmd = conn.getMetaData();
// Get a statement from the connection
if (scrollable)
stmt = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY);
else
stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY);
if (DEBUG)
System.out.println("Statement type = " + stmt.getResultSetType()
+ " concurrency = " + stmt.getResultSetConcurrency());
if (DEBUG) // Get the fetch size of a statement
System.out.println("Default fetch size = " + stmt.getFetchSize());
if (fsize != 0) {
// Set the fetch size
stmt.setFetchSize(fsize);
if (DEBUG)
System.out.println("New fetch size = " + stmt.getFetchSize());
} // endif fsize
} catch(ClassNotFoundException e) {
System.err.println("ClassNotFoundException: " + e.getMessage());
rc = 1;
} catch (SQLException se) {
System.out.println("SQL Exception:");
// Loop through the SQL Exceptions
while (se != null) {
System.out.println("State : " + se.getSQLState());
System.out.println("Message: " + se.getMessage());
System.out.println("Error : " + se.getErrorCode());
se = se.getNextException();
} // end while se
rc = 2;
} catch( Exception e ) {
System.out.println(e);
rc = 3;
} // end try/catch
return rc;
} // end of JdbcConnect
public boolean CreatePrepStmt(String sql) {
boolean b = false;
try {
pstmt = conn.prepareStatement(sql);
} catch (SQLException se) {
System.out.println(se);
b = true;
} catch (Exception e) {
System.out.println(e);
b = true;
} // end try/catch
return b;
} // end of CreatePrepStmt
public void SetStringParm(int i, String s) {
try {
pstmt.setString(i, s);
} catch (Exception e) {
System.out.println(e);
} // end try/catch
} // end of SetStringParm
public void SetIntParm(int i, int n) {
try {
pstmt.setInt(i, n);
} catch (Exception e) {
System.out.println(e);
} // end try/catch
} // end of SetIntParm
public void SetShortParm(int i, short n) {
try {
pstmt.setShort(i, n);
} catch (Exception e) {
System.out.println(e);
} // end try/catch
} // end of SetShortParm
public void SetBigintParm(int i, long n) {
try {
pstmt.setLong(i, n);
} catch (Exception e) {
System.out.println(e);
} // end try/catch
} // end of SetBigintParm
public void SetFloatParm(int i, float f) {
try {
pstmt.setFloat(i, f);
} catch (Exception e) {
System.out.println(e);
} // end try/catch
} // end of SetFloatParm
public void SetDoubleParm(int i, double d) {
try {
pstmt.setDouble(i, d);
} catch (Exception e) {
System.out.println(e);
} // end try/catch
} // end of SetDoubleParm
public void SetTimestampParm(int i, Timestamp t) {
try {
pstmt.setTimestamp(i, t);
} catch (Exception e) {
System.out.println(e);
} // end try/catch
} // end of SetTimestampParm
public int ExecutePrep() {
int n = -3;
if (pstmt != null) try {
n = pstmt.executeUpdate();
} catch (SQLException se) {
System.out.println(se);
n = -1;
} catch (Exception e) {
System.out.println(e);
n = -2;
} //end try/catch
return n;
} // end of ExecutePrep
public boolean ClosePrepStmt() {
boolean b = false;
if (pstmt != null) try {
pstmt.close();
pstmt = null;
} catch (SQLException se) {
System.out.println(se);
b = true;
} catch (Exception e) {
System.out.println(e);
b = true;
} // end try/catch
return b;
} // end of ClosePrepStmt
public int JdbcDisconnect() {
int rc = 0;
// Cancel pending statement
if (stmt != null)
try {
System.out.println("Cancelling statement");
stmt.cancel();
} catch(SQLException se) {
System.out.println(se);
rc += 1;
} // nothing more we can do
// Close the statement and the connection
if (rs != null)
try {
System.out.println("Closing result set");
rs.close();
} catch(SQLException se) {
System.out.println(se);
rc = 2;
} // nothing more we can do
if (stmt != null)
try {
System.out.println("Closing statement");
stmt.close();
} catch(SQLException se) {
System.out.println(se);
rc += 4;
} // nothing more we can do
ClosePrepStmt();
if (conn != null)
try {
System.out.println("Closing connection");
conn.close();
} catch (SQLException se) {
System.out.println(se);
rc += 8;
} //end try/catch
System.out.println("All closed");
return rc;
} // end of JdbcDisconnect
public int GetMaxValue(int n) {
int m = 0;
try {
switch (n) {
case 1: // Max columns in table
m = dbmd.getMaxColumnsInTable();
break;
case 2: // Max catalog name length
m = dbmd.getMaxCatalogNameLength();
break;
case 3: // Max schema name length
m = dbmd.getMaxSchemaNameLength();
break;
case 4: // Max table name length
m = dbmd.getMaxTableNameLength();
break;
case 5: // Max column name length
m = dbmd.getMaxColumnNameLength();
break;
} // endswitch n
} catch(Exception e) {
System.out.println(e);
} // end try/catch
return m;
} // end of GetMaxValue
public int GetColumns(String[] parms) {
int ncol = 0;
try {
if (rs != null) rs.close();
rs = dbmd.getColumns(parms[0], parms[1], parms[2], parms[3]);
if (rs != null) {
rsmd = rs.getMetaData();
ncol = rsmd.getColumnCount();
} // endif rs
} catch(SQLException se) {
System.out.println(se);
} // end try/catch
return ncol;
} // end of GetColumns
public int GetTables(String[] parms) {
int ncol = 0;
String[] typ = null;
if (parms[3] != null) {
typ = new String[1];
typ[0] = parms[3];
} // endif parms
try {
if (rs != null) rs.close();
rs = dbmd.getTables(parms[0], parms[1], parms[2], typ);
if (rs != null) {
rsmd = rs.getMetaData();
ncol = rsmd.getColumnCount();
} // endif rs
} catch(SQLException se) {
System.out.println(se);
} // end try/catch
return ncol;
} // end of GetColumns
public int Execute(String query) {
int n = 0;
if (DEBUG)
System.out.println("Executing '" + query + "'");
try {
boolean b = stmt.execute(query);
if (b == false) {
n = stmt.getUpdateCount();
if (rs != null) rs.close();
} // endif b
if (DEBUG)
System.out.println("Query '" + query + "' executed: n = " + n);
} catch (SQLException se) {
System.out.println(se);
n = -1;
} catch (Exception e) {
System.out.println(e);
n = -2;
} //end try/catch
return n;
} // end of Execute
public int GetResult() {
int ncol = 0;
try {
rs = stmt.getResultSet();
if (rs != null) {
rsmd = rs.getMetaData();
ncol = rsmd.getColumnCount();
if (DEBUG)
System.out.println("Result set has " + rsmd.getColumnCount() + " column(s)");
} // endif rs
} catch (SQLException se) {
System.out.println(se);
ncol = -1;
} catch (Exception e) {
System.out.println(e);
ncol = -2;
} //end try/catch
return ncol;
} // end of GetResult
public int ExecuteQuery(String query) {
int ncol = 0;
if (DEBUG)
System.out.println("Executing query '" + query + "'");
try {
rs = stmt.executeQuery(query);
rsmd = rs.getMetaData();
ncol = rsmd.getColumnCount();
if (DEBUG) {
System.out.println("Query '" + query + "' executed successfully");
System.out.println("Result set has " + rsmd.getColumnCount() + " column(s)");
} // endif DEBUG
} catch (SQLException se) {
System.out.println(se);
ncol = -1;
} catch (Exception e) {
System.out.println(e);
ncol = -2;
} //end try/catch
return ncol;
} // end of ExecuteQuery
public int ExecuteUpdate(String query) {
int n = 0;
if (DEBUG)
System.out.println("Executing update query '" + query + "'");
try {
n = stmt.executeUpdate(query);
if (DEBUG)
System.out.println("Update Query '" + query + "' executed: n = " + n);
} catch (SQLException se) {
System.out.println(se);
n = -1;
} catch (Exception e) {
System.out.println(e);
n = -2;
} //end try/catch
return n;
} // end of ExecuteQuery
public int ReadNext() {
if (rs != null) {
try {
return rs.next() ? 1 : 0;
} catch (SQLException se) {
System.out.println(se);
return -1;
} //end try/catch
} else
return 0;
} // end of ReadNext
public boolean Fetch(int row) {
if (rs != null) {
try {
return rs.absolute(row);
} catch (SQLException se) {
System.out.println(se);
return false;
} //end try/catch
} else
return false;
} // end of Fetch
public String ColumnName(int n) {
if (rsmd == null) {
System.out.println("No result metadata");
} else try {
return rsmd.getColumnLabel(n);
} catch (SQLException se) {
System.out.println(se);
} //end try/catch
return null;
} // end of ColumnName
public int ColumnType(int n, String name) {
if (rsmd == null) {
System.out.println("No result metadata");
} else try {
if (n == 0)
n = rs.findColumn(name);
return rsmd.getColumnType(n);
} catch (SQLException se) {
System.out.println("ColumnType: " + se);
} //end try/catch
return 0;
} // end of ColumnType
public String ColumnDesc(int n, int[] val) {
if (rsmd == null) {
System.out.println("No result metadata");
return null;
} else try {
val[0] = rsmd.getColumnType(n);
val[1] = rsmd.getPrecision(n);
val[2] = rsmd.getScale(n);
val[3] = rsmd.isNullable(n);
return rsmd.getColumnLabel(n);
} catch (SQLException se) {
System.out.println(se);
} //end try/catch
return null;
} // end of ColumnType
public String StringField(int n, String name) {
if (rs == null) {
System.out.println("No result set");
} else try {
return (n > 0) ? rs.getString(n) : rs.getString(name);
} catch (SQLException se) {
System.out.println(se);
} //end try/catch
return null;
} // end of StringField
public int IntField(int n, String name) {
if (rs == null) {
System.out.println("No result set");
} else try {
return (n > 0) ? rs.getInt(n) : rs.getInt(name);
} catch (SQLException se) {
System.out.println(se);
} //end try/catch
return 0;
} // end of IntField
public long BigintField(int n, String name) {
if (rs == null) {
System.out.println("No result set");
} else try {
BigDecimal bigDecimal = (n > 0) ? rs.getBigDecimal(n) : rs.getBigDecimal(name);
return bigDecimal != null ? bigDecimal.longValue() : 0;
} catch (SQLException se) {
System.out.println(se);
} //end try/catch
return 0;
} // end of BiginttField
public double DoubleField(int n, String name) {
if (rs == null) {
System.out.println("No result set");
} else try {
return (n > 0) ? rs.getDouble(n) : rs.getDouble(name);
} catch (SQLException se) {
System.out.println(se);
} //end try/catch
return 0.;
} // end of DoubleField
public float FloatField(int n, String name) {
if (rs == null) {
System.out.println("No result set");
} else try {
return (n > 0) ? rs.getFloat(n) : rs.getFloat(name);
} catch (SQLException se) {
System.out.println(se);
} //end try/catch
return 0;
} // end of FloatField
public boolean BooleanField(int n, String name) {
if (rs == null) {
System.out.println("No result set");
} else try {
return (n > 0) ? rs.getBoolean(n) : rs.getBoolean(name);
} catch (SQLException se) {
System.out.println(se);
} //end try/catch
return false;
} // end of BooleanField
public Date DateField(int n, String name) {
if (rs == null) {
System.out.println("No result set");
} else try {
return (n > 0) ? rs.getDate(n) : rs.getDate(name);
} catch (SQLException se) {
System.out.println(se);
} //end try/catch
return null;
} // end of DateField
public Time TimeField(int n, String name) {
if (rs == null) {
System.out.println("No result set");
} else try {
return (n > 0) ? rs.getTime(n) : rs.getTime(name);
} catch (SQLException se) {
System.out.println(se);
} //end try/catch
return null;
} // end of TimeField
public Timestamp TimestampField(int n, String name) {
if (rs == null) {
System.out.println("No result set");
} else try {
return (n > 0) ? rs.getTimestamp(n) : rs.getTimestamp(name);
} catch (SQLException se) {
System.out.println(se);
} //end try/catch
return null;
} // end of TimestampField
public int GetDrivers(String[] s, int mxs) {
int n = 0;
List<Driver> drivers = Collections.list(DriverManager.getDrivers());
int size = Math.min(mxs, drivers.size());
for (int i = 0; i < size; i++) {
Driver driver = (Driver)drivers.get(i);
// Get name of driver
s[n++] = driver.getClass().getName();
// Get version info
s[n++] = driver.getMajorVersion() + "." + driver.getMinorVersion();
s[n++] = driver.jdbcCompliant() ? "Yes" : "No";
s[n++] = driver.toString();
} // endfor i
return size;
} // end of GetDrivers
} // end of class JdbcInterface
......@@ -21,8 +21,8 @@
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,
local or remote MySQL/MariaDB tables retrieved via MySQL API,
ODBC tables retrieving data from other DBMS having an ODBC server, and even
virtual tables.
ODBC/JDBC tables retrieving data from other DBMS having an ODBC/JDBC server,
and even virtual tables.
@details
ha_connect will let you create/open/delete tables, the created table can be
......@@ -115,9 +115,6 @@
#include "sql_parse.h"
#include "sql_base.h"
#include <sys/stat.h>
#if defined(NEW_WAY)
#include "sql_table.h"
#endif // NEW_WAY
#include "sql_partition.h"
#undef OFFSET
......@@ -130,6 +127,10 @@
#if defined(ODBC_SUPPORT)
#include "odbccat.h"
#endif // ODBC_SUPPORT
#if defined(JDBC_SUPPORT)
#include "jdbccat.h"
#include "jdbconn.h"
#endif // JDBC_SUPPORT
#include "xtable.h"
#include "tabmysql.h"
#include "filamdbf.h"
......@@ -169,7 +170,7 @@
#define JSONMAX 10 // JSON Default max grp size
extern "C" {
char version[]= "Version 1.04.0006 March 12, 2016";
char version[]= "Version 1.04.0006 May 08, 2016";
#if defined(__WIN__)
char compver[]= "Version 1.04.0006 " __DATE__ " " __TIME__;
char slash= '\\';
......@@ -190,6 +191,17 @@ extern "C" {
} // extern "C"
#endif // XMSG
#if defined(JDBC_SUPPORT)
char *JvmPath;
char *ClassPath;
#endif // JDBC_SUPPORT
#if defined(__WIN__)
CRITICAL_SECTION parsec; // Used calling the Flex parser
#else // !__WIN__
pthread_mutex_t parmut = PTHREAD_MUTEX_INITIALIZER;
#endif // !__WIN__
/***********************************************************************/
/* Utility functions. */
/***********************************************************************/
......@@ -197,6 +209,7 @@ PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info);
PQRYRES VirColumns(PGLOBAL g, bool info);
PQRYRES JSONColumns(PGLOBAL g, char *db, 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);
bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host,
const char *db, char *tab, const char *src, int port);
......@@ -633,6 +646,7 @@ static int connect_init_func(void *p)
#if defined(__WIN__)
sql_print_information("CONNECT: %s", compver);
InitializeCriticalSection((LPCRITICAL_SECTION)&parsec);
#else // !__WIN__
sql_print_information("CONNECT: %s", version);
#endif // !__WIN__
......@@ -659,6 +673,9 @@ static int connect_init_func(void *p)
DTVAL::SetTimeShift(); // Initialize time zone shift once for all
BINCOL::SetEndian(); // Initialize host endian setting
#if defined(JDBC_SUPPORT)
JDBConn::SetJVM();
#endif // JDBC_SUPPORT
DBUG_RETURN(0);
} // end of connect_init_func
......@@ -675,11 +692,17 @@ static int connect_done_func(void *)
#ifdef LIBXML2_SUPPORT
XmlCleanupParserLib();
#endif // LIBXML2_SUPPORT
#endif // LIBXML2_SUPPORT
#ifdef JDBC_SUPPORT
JDBConn::ResetJVM();
#endif // JDBC_SUPPORT
#if !defined(__WIN__)
//PROFILE_End(); Causes signal 11
#endif // !__WIN__
#if defined(__WIN__)
DeleteCriticalSection((LPCRITICAL_SECTION)&parsec);
#else // !__WIN__
PROFILE_End();
#endif // !__WIN__
for (pc= user_connect::to_users; pc; pc= pn) {
if (pc->g)
......@@ -1758,9 +1781,10 @@ int ha_connect::OpenTable(PGLOBAL g, bool del)
break;
} // endswitch xmode
if (xmod != MODE_INSERT || tdbp->GetAmType() == TYPE_AM_ODBC
|| tdbp->GetAmType() == TYPE_AM_MYSQL) {
// Get the list of used fields (columns)
if (xmod != MODE_INSERT || tdbp->GetAmType() == TYPE_AM_MYSQL
|| tdbp->GetAmType() == TYPE_AM_ODBC
|| tdbp->GetAmType() == TYPE_AM_JDBC) {
// Get the list of used fields (columns)
char *p;
unsigned int k1, k2, n1, n2;
Field* *field;
......@@ -2077,8 +2101,9 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *)
continue; // Is a virtual column possible here ???
if ((xmod == MODE_INSERT && tdbp->GetAmType() != TYPE_AM_MYSQL
&& tdbp->GetAmType() != TYPE_AM_ODBC) ||
bitmap_is_set(table->write_set, fp->field_index)) {
&& tdbp->GetAmType() != TYPE_AM_ODBC
&& tdbp->GetAmType() != TYPE_AM_JDBC) ||
bitmap_is_set(table->write_set, fp->field_index)) {
for (colp= tp->GetSetCols(); colp; colp= colp->GetNext())
if (!stricmp(colp->GetName(), fp->field_name))
break;
......@@ -2627,7 +2652,7 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond)
} // 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)
{
......@@ -2635,8 +2660,8 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
char *body= filp->Body;
unsigned int i;
bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
bool nonul= (tty == TYPE_AM_ODBC && (tdbp->GetMode() == MODE_INSERT ||
tdbp->GetMode() == MODE_DELETE));
bool nonul= ((tty == TYPE_AM_ODBC || tty == TYPE_AM_JDBC) &&
(tdbp->GetMode() == MODE_INSERT || tdbp->GetMode() == MODE_DELETE));
OPVAL vop= OP_XX;
if (!cond)
......@@ -2958,7 +2983,7 @@ const COND *ha_connect::cond_push(const COND *cond)
bool x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
bool b= (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC ||
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
if (g->jump_level == MAX_JUMP) {
......@@ -4108,7 +4133,8 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn)
/* Fall through to check FILE_ACL */
case TAB_ODBC:
case TAB_MYSQL:
case TAB_JDBC:
case TAB_MYSQL:
case TAB_DIR:
case TAB_MAC:
case TAB_WMI:
......@@ -5124,11 +5150,17 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
int port= 0, hdr= 0, mxr= 0, mxe= 0, rc= 0;
int cop __attribute__((unused))= 0, lrecl= 0;
#if defined(ODBC_SUPPORT)
POPARM sop = NULL;
char *ucnc = NULL;
POPARM sop= NULL;
char *ucnc= NULL;
bool cnc= false;
int cto= -1, qto= -1;
#endif // ODBC_SUPPORT
#if defined(JDBC_SUPPORT)
PJPARM sjp= NULL;
char *driver= NULL;
char *url= NULL;
char *tabtyp = NULL;
#endif // JDBC_SUPPORT
uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL);
bool bif, ok= false, dbf= false;
TABTYPE ttp= TAB_UNDEF;
......@@ -5139,15 +5171,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
PDBUSER dup= PlgGetUser(g);
PCATLG cat= (dup) ? dup->Catalog : NULL;
PTOS topt= table_s->option_struct;
#if defined(NEW_WAY)
//CHARSET_INFO *cs;
Alter_info alter_info;
#else // !NEW_WAY
char buf[1024];
String sql(buf, sizeof(buf), system_charset_info);
sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info);
#endif // !NEW_WAY
if (!g)
return HA_ERR_INTERNAL_ERROR;
......@@ -5166,7 +5193,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
spc= (!sep) ? ',' : *sep;
qch= topt->qchar ? *topt->qchar : (signed)topt->quoted >= 0 ? '"' : 0;
hdr= (int)topt->header;
tbl= topt->tablist;
tbl= topt->tablist;
col= topt->colist;
if (topt->oplist) {
......@@ -5195,6 +5222,11 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
if ((ucnc= GetListOption(g, "UseDSN", topt->oplist)))
cnc= (!*ucnc || *ucnc == 'y' || *ucnc == 'Y' || atoi(ucnc) != 0);
#endif
#if defined(JDBC_SUPPORT)
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"));
#if defined(PROMPT_OK)
cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0"));
......@@ -5255,44 +5287,62 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
} else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL)))
tab= table_s->table_name.str; // Default value
#if defined(NEW_WAY)
// add_option(thd, create_info, "tabname", tab);
#endif // NEW_WAY
} // endif tab
switch (ttp) {
switch (ttp) {
#if defined(ODBC_SUPPORT)
case TAB_ODBC:
dsn= strz(g, create_info->connect_string);
case TAB_ODBC:
dsn= strz(g, create_info->connect_string);
if (fnc & (FNC_DSN | FNC_DRIVER)) {
ok= true;
if (fnc & (FNC_DSN | FNC_DRIVER)) {
ok= true;
#if defined(PROMPT_OK)
} else if (!stricmp(thd->main_security_ctx.host, "localhost")
&& cop == 1) {
if ((dsn = ODBCCheckConnection(g, dsn, cop)) != NULL) {
thd->make_lex_string(&create_info->connect_string, dsn, strlen(dsn));
ok= true;
} // endif dsn
} else if (!stricmp(thd->main_security_ctx.host, "localhost")
&& cop == 1) {
if ((dsn = ODBCCheckConnection(g, dsn, cop)) != NULL) {
thd->make_lex_string(&create_info->connect_string, dsn, strlen(dsn));
ok= true;
} // endif dsn
#endif // PROMPT_OK
} else if (!dsn) {
sprintf(g->Message, "Missing %s connection string", topt->type);
} else {
// Store ODBC additional parameters
sop= (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM));
sop->User= (char*)user;
sop->Pwd= (char*)pwd;
sop->Cto= cto;
sop->Qto= qto;
sop->UseCnc= cnc;
ok= true;
} // endif's
supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER);
break;
} else if (!dsn) {
sprintf(g->Message, "Missing %s connection string", topt->type);
} else {
// Store ODBC additional parameters
sop= (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM));
sop->User= (char*)user;
sop->Pwd= (char*)pwd;
sop->Cto= cto;
sop->Qto= qto;
sop->UseCnc= cnc;
ok= true;
} // endif's
supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER);
break;
#endif // ODBC_SUPPORT
case TAB_DBF:
#if defined(JDBC_SUPPORT)
case TAB_JDBC:
if (fnc & FNC_DRIVER) {
ok= true;
} else if (!url && !(url= strz(g, create_info->connect_string))) {
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;
// Passthru
case TAB_CSV:
......@@ -5411,7 +5461,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
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);
if (qrp && ttp == TAB_OCCUR)
......@@ -5453,7 +5503,37 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
break;
#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, (char*)src, sjp);
src= NULL; // for next tests
} else
qrp= JDBCColumns(g, shm, tab, NULL, mxr, fnc == FNC_COL, sjp);
break;
case FNC_TABLE:
qrp= JDBCTables(g, 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, 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,
NULL, port, fnc == FNC_COL);
break;
......@@ -5526,14 +5606,9 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
len= 256; // STRBLK's have 0 length
// 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,
NULL, NULL, NULL, NULL, flg, dbf, v))
rc= HA_ERR_OUT_OF_MEM;
#endif // !NEW_WAY
} // endfor crp
} else {
......@@ -5556,12 +5631,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
cnm= (char*)"noname";
dft= xtra= key= fmt= NULL;
v= ' ';
#if defined(NEW_WAY)
rem= "";
// cs= NULL;
#else // !NEW_WAY
rem= NULL;
#endif // !NEW_WAY
for (crp= qrp->Colresp; crp; crp= crp->Next)
switch (crp->Fld) {
......@@ -5630,10 +5700,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
"Several %s tables found, specify DBNAME", tab);
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
goto err;
} else if (!schem)
} else if (!schem)
schem= crp->Kdata->GetCharValue(i);
} // endif ttp
} // endif ttp
#endif // ODBC_SUPPORT
default:
break; // Ignore
......@@ -5682,7 +5752,42 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
} else
#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)
prec= len;
......@@ -5690,25 +5795,15 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
prec= 0;
// 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,
fmt, 0, dbf, v))
rc= HA_ERR_OUT_OF_MEM;
#endif // !NEW_WAY
} // endfor i
} // endif fnc
#if defined(NEW_WAY)
rc= init_table_share(thd, table_s, create_info, &alter_info);
#else // !NEW_WAY
if (!rc)
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--;
return rc;
......@@ -6750,6 +6845,21 @@ static MYSQL_SYSVAR_STR(errmsg_dir_path, msg_path,
"../../../../storage/connect/"); // for testing
#endif // XMSG
#if defined(JDBC_SUPPORT)
static MYSQL_SYSVAR_STR(jvm_path, JvmPath,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
"Path to the directory where is the JVM lib",
// check_jvm_path, update_jvm_path,
NULL, NULL, NULL);
static MYSQL_SYSVAR_STR(class_path, ClassPath,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
"Java class path",
// check_class_path, update_class_path,
NULL, NULL, NULL);
#endif // JDBC_SUPPORT
static struct st_mysql_sys_var* connect_system_variables[]= {
MYSQL_SYSVAR(xtrace),
MYSQL_SYSVAR(conv_size),
......@@ -6767,7 +6877,11 @@ static struct st_mysql_sys_var* connect_system_variables[]= {
MYSQL_SYSVAR(errmsg_dir_path),
#endif // XMSG
MYSQL_SYSVAR(json_grp_size),
NULL
#if defined(JDBC_SUPPORT)
MYSQL_SYSVAR(jvm_path),
MYSQL_SYSVAR(class_path),
#endif // JDBC_SUPPORT
NULL
};
maria_declare_plugin(connect)
......
......@@ -622,13 +622,16 @@ void PROFILE_End(void)
if (trace)
htrc("PROFILE_End: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES);
if (!CurProfile) // Sergey Vojtovich
return;
/* Close all opened files and free the cache structure */
for (i = 0; i < N_CACHED_PROFILES; i++) {
if (trace)
htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i);
CurProfile = MRUProfile[i];
PROFILE_ReleaseFile();
// CurProfile = MRUProfile[i]; Sergey Vojtovich
// PROFILE_ReleaseFile(); see MDEV-9997
free(MRUProfile[i]);
} // endfor i
......
// 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 *db, char *table,
char *colpat, int maxres, bool info, PJPARM sop);
PQRYRES JDBCSrcCols(PGLOBAL g, char *src, PJPARM sop);
PQRYRES JDBCTables(PGLOBAL g, char *db, char *tabpat,
char *tabtyp, int maxres, bool info, PJPARM sop);
PQRYRES JDBCDrivers(PGLOBAL g, 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 // __BORLANDC__
//#include <windows.h>
#else // !__WIN__
#if defined(UNIX)
#include <errno.h>
#else // !UNIX
//nclude <io.h>
#endif // !UNIX
#include <stdio.h>
#include <stdlib.h> // for getenv
//nclude <fcntl.h>
#define NODW
#endif // !__WIN__
/***********************************************************************/
/* 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
#else // !__WIN__
#define nullptr 0
#endif // !__WIN__
int GetConvSize();
extern char *JvmPath; // The connect_jvm_path global variable value
extern char *ClassPath; // The connect_class_path global variable value
/***********************************************************************/
/* Static JDBConn objects. */
/***********************************************************************/
void *JDBConn::LibJvm = NULL;
CRTJVM JDBConn::CreateJavaVM = NULL;
GETJVM JDBConn::GetCreatedJavaVMs = NULL;
/***********************************************************************/
/* 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
// To avoid gcc warning
int TranslateJDBCType(int stp, int prec, int& len, char& v);
/***********************************************************************/
/* 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 *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(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 *src, PJPARM sjp)
{
JDBConn *jcp = new(g)JDBConn(g, NULL);
if (jcp->Open(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 *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(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, 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(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
#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
/***********************************************************************/
/* Screen for errors. */
/***********************************************************************/
char *JDBConn::Check(void)
{
if (env->ExceptionCheck()) {
char *msg;
jthrowable exc = env->ExceptionOccurred();
jmethodID tid = env->GetMethodID(env->FindClass("java/lang/Object"),
"toString", "()Ljava/lang/String;");
if (exc != nullptr && tid != nullptr) {
jstring s = (jstring)env->CallObjectMethod(exc, tid);
const char *utf = env->GetStringUTFChars(s, (jboolean)false);
env->DeleteLocalRef(s);
msg = PlugDup(m_G, utf);
} else
msg = "Exception occured";
env->ExceptionClear();
return msg;
} // endif Check
return NULL;
} // end of Check
#if 0
/***********************************************************************/
/* 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
/***********************************************************************/
/* Reset the JVM library. */
/***********************************************************************/
void JDBConn::ResetJVM(void)
{
if (LibJvm) {
#if defined(__WIN__)
FreeLibrary((HMODULE)LibJvm);
#else // !__WIN__
dlclose(LibJvm);
#endif // !__WIN__
LibJvm = NULL;
CreateJavaVM = NULL;
GetCreatedJavaVMs = NULL;
} // endif LibJvm
} // end of ResetJVM
/***********************************************************************/
/* Dynamically link the JVM library. */
/* The purpose of this function is to allow using the CONNECT plugin */
/* for other table types when the Java JDK is not installed. */
/***********************************************************************/
bool JDBConn::GetJVM(PGLOBAL g)
{
if (!LibJvm) {
char soname[512];
#if defined(__WIN__)
if (JvmPath)
strcat(strcpy(soname, JvmPath), "\\jvm.dll");
else
strcpy(soname, "jvm.dll");
// Load the desired shared library
if (!(LibJvm = LoadLibrary(soname))) {
char buf[256];
DWORD rc = GetLastError();
sprintf(g->Message, MSG(DLL_LOAD_ERROR), rc, soname);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
(LPTSTR)buf, sizeof(buf), NULL);
strcat(strcat(g->Message, ": "), buf);
} else if (!(CreateJavaVM = (CRTJVM)GetProcAddress((HINSTANCE)LibJvm,
"JNI_CreateJavaVM"))) {
sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), "JNI_CreateJavaVM");
FreeLibrary((HMODULE)LibJvm);
LibJvm = NULL;
} else if (!(GetCreatedJavaVMs = (GETJVM)GetProcAddress((HINSTANCE)LibJvm,
"JNI_GetCreatedJavaVMs"))) {
sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), "JNI_GetCreatedJavaVMs");
FreeLibrary((HMODULE)LibJvm);
LibJvm = NULL;
} // endif LibJvm
#else // !__WIN__
const char *error = NULL;
if (JvmPath)
strcat(strcpy(soname, JvmPath), "/libjvm.so");
else
strcpy(soname, "libjvm.so");
// Load the desired shared library
if (!(LibJvm = dlopen(soname, RTLD_LAZY))) {
error = dlerror();
sprintf(g->Message, MSG(SHARED_LIB_ERR), soname, SVP(error));
} else if (!(CreateJavaVM = (CRTJVM)dlsym(LibJvm, "JNI_CreateJavaVM"))) {
error = dlerror();
sprintf(g->Message, MSG(GET_FUNC_ERR), "JNI_CreateJavaVM", SVP(error));
dlclose(LibJvm);
LibJvm = NULL;
} else if (!(GetCreatedJavaVMs = (GETJVM)dlsym(LibJvm, "JNI_GetCreatedJavaVMs"))) {
error = dlerror();
sprintf(g->Message, MSG(GET_FUNC_ERR), "JNI_GetCreatedJavaVMs", SVP(error));
dlclose(LibJvm);
LibJvm = NULL;
} // endif LibJvm
#endif // !__WIN__
} // endif LibJvm
return LibJvm == NULL;
} // end of GetJVM
/***********************************************************************/
/* Open: connect to a data source. */
/***********************************************************************/
int JDBConn::Open(PJPARM sop)
{
PGLOBAL& g = m_G;
// Link or check whether jvm library was linked
if (GetJVM(g))
return RC_FX;
// Firstly check whether the jvm was already created
JavaVM* jvms[1];
jsize jsz;
jint rc = GetCreatedJavaVMs(jvms, 1, &jsz);
if (rc == JNI_OK && jsz == 1) {
// jvm already existing
jvm = jvms[0];
rc = jvm->AttachCurrentThread((void**)&env, nullptr);
if (rc != JNI_OK) {
strcpy(g->Message, "Cannot attach jvm to the current thread");
return RC_FX;
} // endif rc
} else {
// Create a new jvm
PSTRG jpop = new(g)STRING(g, 512, "-Djava.class.path=");
char *cp = NULL;
char sep;
#if defined(__WIN__)
sep = ';';
#else
sep = ':';
#endif
//================== prepare loading of Java VM ============================
JavaVMInitArgs vm_args; // Initialization arguments
JavaVMOption* options = new JavaVMOption[1]; // JVM invocation options
// where to find java .class
if ((cp = PlugDup(m_G, getenv("CLASSPATH"))))
jpop->Append(cp);
if (trace) {
htrc("CLASSPATH=%s\n", getenv("CLASSPATH"));
htrc("ClassPath=%s\n", ClassPath);
} // endif trace
if (ClassPath && *ClassPath) {
if (cp)
jpop->Append(sep);
jpop->Append(ClassPath);
} // endif ClassPath
if (trace)
htrc("%s\n", jpop->GetStr());
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 =============
rc = 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");
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
} // endif 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 0 // Suppressed because it does not make any usable change
if (b && jpath && *jpath) {
// Try to add that path the the jvm class path
jmethodID alp = env->GetStaticMethodID(jdi, "addLibraryPath",
"(Ljava/lang/String;)I");
if (alp == nullptr) {
env->ExceptionDescribe();
env->ExceptionClear();
} else {
char *msg;
jstring path = env->NewStringUTF(jpath);
rc = env->CallStaticIntMethod(jdi, alp, path);
if ((msg = Check())) {
strcpy(g->Message, msg);
env->DeleteLocalRef(path);
return RC_FX;
} else switch (rc) {
case JNI_OK:
printf("jpath added\n");
break;
case JNI_EEXIST:
printf("jpath already exist\n");
break;
case JNI_ERR:
default:
strcpy(g->Message, "Error adding jpath");
env->DeleteLocalRef(path);
return RC_FX;
} // endswitch rc
env->DeleteLocalRef(path);
} // endif alp
} // endif jpath
#endif // 0
// 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
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
// 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 if ((rc = env->CallIntMethod(job, did)))
printf("jdbcDisconnect: rc=%d", (int)rc);
if ((rc = jvm->DetachCurrentThread()))
printf("DetachCurrentThread: rc = %d", (int)rc);
//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;
char *msg;
jint ctyp;
jlong dtv;
jstring cn, jn = nullptr;
jobject dob;
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 ((msg = Check())) {
sprintf(g->Message, "Getting ctyp: %s", msg);
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 ((msg = Check())) {
if (rank == 0)
env->DeleteLocalRef(jn);
sprintf(g->Message, "SetColumnValue: %s rank=%d ctyp=%d", msg, rank, (int)ctyp);
longjmp(g->jumper[g->jump_level], TYPE_AM_JDBC);
} // endif Check
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;
char *msg;
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;
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 find 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 ((msg = Check())) {
sprintf(g->Message, "SetParam: col=%s msg=%s", colp->GetName(), msg);
rc = true;
} // endif msg
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 = nullptr;
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);
if (trace)
htrc("Method %s returned %d columns\n", fnc, ncol);
// n because we no more ignore the first column
if ((n = qrp->Nbcol) > (uint)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];
} // endif Type
// } else
// buffer = pval[n]->GetTo_Val();
n++;
} // endfor n
// Now fetch the result
for (i = 0; i < qrp->Maxres; i++) {
if ((rc = Fetch(0)) == 0) {
if (trace)
htrc("End of fetches i=%d\n", i);
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 > 0)
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__
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;
typedef jint(JNICALL *CRTJVM) (JavaVM **, void **, void *);
typedef jint(JNICALL *GETJVM) (JavaVM **, jsize, jsize *);
// 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(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 static variables
static void SetJVM(void)
{ LibJvm = NULL; CreateJavaVM = NULL; GetCreatedJavaVMs = NULL; }
static void ResetJVM(void);
static bool GetJVM(PGLOBAL g);
// Implementation
public:
//virtual ~JDBConn();
// JDBC operations
protected:
char *Check(void);
//void ThrowDJX(int rc, PSZ msg/*, HSTMT hstmt = SQL_NULL_HSTMT*/);
//void ThrowDJX(PSZ msg);
//void Free(void);
protected:
// Members
#if defined(__WIN__)
static HANDLE LibJvm; // Handle to the jvm DLL
#else // !__WIN__
static void *LibJvm; // Handle for the jvm shared library
#endif // !__WIN__
static CRTJVM CreateJavaVM;
static GETJVM GetCreatedJavaVMs;
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
......@@ -3538,37 +3538,9 @@ void jsoncontains_path_deinit(UDF_INIT* initid)
} // end of jsoncontains_path_deinit
/*********************************************************************************/
/* Set Json items of a Json document according to path. */
/* This function is used by the json_set/insert/update_item functions. */
/*********************************************************************************/
my_bool json_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
int n = IsJson(args, 0);
if (!(args->arg_count % 2)) {
strcpy(message, "This function must have an odd number of arguments");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else
CalcLen(args, false, reslen, memlen);
if (n == 2 && args->args[0]) {
char fn[_MAX_PATH];
long fl;
memcpy(fn, args->args[0], args->lengths[0]);
fn[args->lengths[0]] = 0;
fl = GetFileLength(fn);
memlen += fl * 3;
} else if (n != 3)
memlen += args->lengths[0] * 3;
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of json_set_item_init
char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *p, *path, *str = NULL;
......@@ -3586,12 +3558,16 @@ char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
} else if (initid->const_item)
g->N = 1;
if (!strcmp(result, "$insert"))
if (!strcmp(result, "$set"))
w = 0;
else if (!strcmp(result, "$insert"))
w = 1;
else if (!strcmp(result, "$update"))
w = 2;
else
w = 0;
else {
PUSH_WARNING("Logical error, please contact CONNECT developer");
goto err;
} // endelse
// Save stack and allocation environment and prepare error return
if (g->jump_level == MAX_JUMP) {
......@@ -3660,10 +3636,10 @@ char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
// Keep result of constant function
g->Activityp = (PACTIVITY)str;
err:
err:
g->jump_level--;
fin:
fin:
if (!str) {
*is_null = 1;
*res_length = 0;
......@@ -3671,6 +3647,44 @@ char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
*res_length = strlen(str);
return str;
} // end of handle_item
/*********************************************************************************/
/* Set Json items of a Json document according to path. */
/*********************************************************************************/
my_bool json_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
int n = IsJson(args, 0);
if (!(args->arg_count % 2)) {
strcpy(message, "This function must have an odd number of arguments");
return true;
} else if (!n && args->arg_type[0] != STRING_RESULT) {
strcpy(message, "First argument must be a json item");
return true;
} else
CalcLen(args, false, reslen, memlen);
if (n == 2 && args->args[0]) {
char fn[_MAX_PATH];
long fl;
memcpy(fn, args->args[0], args->lengths[0]);
fn[args->lengths[0]] = 0;
fl = GetFileLength(fn);
memlen += fl * 3;
} else if (n != 3)
memlen += args->lengths[0] * 3;
return JsonInit(initid, args, message, true, reslen, memlen);
} // end of json_set_item_init
char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$set");
return handle_item(initid, args, result, res_length, is_null, p);
} // end of json_set_item
void json_set_item_deinit(UDF_INIT* initid)
......@@ -3690,7 +3704,7 @@ char *json_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$insert");
return json_set_item(initid, args, result, res_length, is_null, p);
return handle_item(initid, args, result, res_length, is_null, p);
} // end of json_insert_item
void json_insert_item_deinit(UDF_INIT* initid)
......@@ -3710,7 +3724,7 @@ char *json_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$update");
return json_set_item(initid, args, result, res_length, is_null, p);
return handle_item(initid, args, result, res_length, is_null, p);
} // end of json_update_item
void json_update_item_deinit(UDF_INIT* initid)
......@@ -4706,14 +4720,9 @@ void jbin_item_merge_deinit(UDF_INIT* initid)
} // end of jbin_item_merge_deinit
/*********************************************************************************/
/* Set Json items of a Json document according to path. */
/* This function is used by the jbin_set/insert/update functions. */
/*********************************************************************************/
my_bool jbin_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return json_set_item_init(initid, args, message);
} // end of jbin_set_item_init
char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
char *bin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *p, *path;
......@@ -4732,12 +4741,16 @@ char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
} else if (initid->const_item)
g->N = 1;
if (!strcmp(result, "$insert"))
if (!strcmp(result, "$set"))
w = 0;
else if (!strcmp(result, "$insert"))
w = 1;
else if (!strcmp(result, "$update"))
w = 2;
else
w = 0;
else {
PUSH_WARNING("Logical error, please contact CONNECT developer");
goto fin;
} // endelse
if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true, false, true)) {
......@@ -4791,7 +4804,7 @@ char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
// Keep result of constant function
g->Activityp = (PACTIVITY)bsp;
fin:
fin:
if (!bsp) {
*is_null = 1;
*res_length = 0;
......@@ -4799,6 +4812,21 @@ char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
*res_length = sizeof(BSON);
return (char*)bsp;
} // end of bin_handle_item
/*********************************************************************************/
/* Set Json items of a Json document according to path. */
/*********************************************************************************/
my_bool jbin_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
return json_set_item_init(initid, args, message);
} // end of jbin_set_item_init
char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$set");
return bin_handle_item(initid, args, result, res_length, is_null, p);
} // end of jbin_set_item
void jbin_set_item_deinit(UDF_INIT* initid)
......@@ -4818,7 +4846,7 @@ char *jbin_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$insert");
return jbin_set_item(initid, args, result, res_length, is_null, p);
return bin_handle_item(initid, args, result, res_length, is_null, p);
} // end of jbin_insert_item
void jbin_insert_item_deinit(UDF_INIT* initid)
......@@ -4838,7 +4866,7 @@ char *jbin_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *p)
{
strcpy(result, "$update");
return jbin_set_item(initid, args, result, res_length, is_null, p);
return bin_handle_item(initid, args, result, res_length, is_null, p);
} // end of jbin_update_item
void jbin_update_item_deinit(UDF_INIT* initid)
......@@ -4999,3 +5027,30 @@ void json_serialize_deinit(UDF_INIT* initid)
{
JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_serialize_deinit
/*********************************************************************************/
/* Utility function returning an environment variable value. */
/*********************************************************************************/
my_bool envar_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
if (args->arg_count != 1) {
strcpy(message, "Unique argument must be an environment variable name");
return true;
} else
return false;
} // end of envar_init
char *envar(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *, char *)
{
char *str, name[256];
int n = MY_MIN(args->lengths[0], sizeof(name) - 1);
memcpy(name, args->args[0], n);
name[n] = 0;
str = getenv(name);
*res_length = (str) ? strlen(str) : 0;
return str;
} // end of envar
......@@ -218,8 +218,12 @@ extern "C" {
DllExport my_bool json_serialize_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *json_serialize(UDF_EXEC_ARGS);
DllExport void json_serialize_deinit(UDF_INIT*);
DllExport my_bool envar_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *envar(UDF_EXEC_ARGS);
} // extern "C"
/*********************************************************************************/
/* Structure JPN. Used to make the locate path. */
/*********************************************************************************/
......
......@@ -5,7 +5,7 @@
/* */
/* COPYRIGHT: */
/* ---------- */
/* (C) Copyright to the author Olivier BERTRAND 1998-2015 */
/* (C) Copyright to the author Olivier BERTRAND 1998-2016 */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
......@@ -46,9 +46,9 @@
#else // !__WIN__
#include <unistd.h>
#include <fcntl.h>
#if defined(THREAD)
//#if defined(THREAD)
#include <pthread.h>
#endif // THREAD
//#endif // THREAD
#include <stdarg.h>
#define BIGMEM 2147483647 // Max int value
#endif // !__WIN__
......@@ -69,17 +69,6 @@
#include "valblk.h"
#include "rcmsg.h"
/***********************************************************************/
/* Macro or external routine definition */
/***********************************************************************/
#if defined(THREAD)
#if defined(__WIN__)
extern CRITICAL_SECTION parsec; // Used calling the Flex parser
#else // !__WIN__
extern pthread_mutex_t parmut;
#endif // !__WIN__
#endif // THREAD
/***********************************************************************/
/* DB static variables. */
/***********************************************************************/
......@@ -90,6 +79,12 @@ extern "C" {
extern char version[];
} // extern "C"
#if defined(__WIN__)
extern CRITICAL_SECTION parsec; // Used calling the Flex parser
#else // !__WIN__
extern pthread_mutex_t parmut;
#endif // !__WIN__
// The debug trace used by the main thread
FILE *pfile = NULL;
......@@ -702,21 +697,21 @@ PDTP MakeDateFormat(PGLOBAL g, PSZ dfmt, bool in, bool out, int flag)
/* Call the FLEX generated parser. In multi-threading mode the next */
/* instruction is included in an Enter/LeaveCriticalSection bracket. */
/*********************************************************************/
#if defined(THREAD)
//#if defined(THREAD)
#if defined(__WIN__)
EnterCriticalSection((LPCRITICAL_SECTION)&parsec);
#else // !__WIN__
pthread_mutex_lock(&parmut);
#endif // !__WIN__
#endif // THREAD
//#endif // THREAD
rc = fmdflex(pdp);
#if defined(THREAD)
//#if defined(THREAD)
#if defined(__WIN__)
LeaveCriticalSection((LPCRITICAL_SECTION)&parsec);
#else // !__WIN__
pthread_mutex_unlock(&parmut);
#endif // !__WIN__
#endif // THREAD
//#endif // THREAD
if (trace)
htrc("Done: in=%s out=%s rc=%d\n", SVP(pdp->InFmt), SVP(pdp->OutFmt), rc);
......@@ -1102,7 +1097,8 @@ char *GetAmName(PGLOBAL g, AMT am, void *memp)
case TYPE_AM_DOM: strcpy(amn, "DOM"); break;
case TYPE_AM_DIR: strcpy(amn, "DIR"); 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_OUT: strcpy(amn, "OUT"); break;
default: sprintf(amn, "OEM(%d)", am);
......
......@@ -305,7 +305,7 @@ int TABDEF::GetColCatInfo(PGLOBAL g)
case TAB_OEM:
poff = 0; // Offset represents an independant flag
break;
default: // VCT PLG ODBC MYSQL WMI...
default: // VCT PLG ODBC JDBC MYSQL WMI...
poff = 0; // NA
break;
} // endswitch tc
......@@ -514,10 +514,11 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g)
} // endif getdef
#else // !__WIN__
const char *error = NULL;
Dl_info dl_info;
#if 0 // Don't know what all this stuff does
// The OEM lib must retrieve exported CONNECT variables
Dl_info dl_info;
// The OEM lib must retrieve exported CONNECT variables
if (dladdr(&connect_hton, &dl_info)) {
if (dlopen(dl_info.dli_fname, RTLD_NOLOAD | RTLD_NOW | RTLD_GLOBAL) == 0) {
error = dlerror();
......
/************* 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)
{
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)
{
Driver = GetStringCatInfo(g, "Driver", NULL);
Desc = Url = GetStringCatInfo(g, "Connect", NULL);
if (!Url && !Catfunc) {
// Look in the option list (deprecated)
Url = GetStringCatInfo(g, "Url", NULL);
if (!Url) {
sprintf(g->Message, "Missing URL for JDBC table %s", Name);
return true;
} // endif Url
} // 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) {
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 {
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;
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(&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(&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(&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, Maxres, false);
} // end of GetResult
/* ---------------------------TDBJTB class --------------------------- */
/***********************************************************************/
/* TDBJTB class constructor. */
/***********************************************************************/
TDBJTB::TDBJTB(PJDBCDEF tdp) : TDBJDRV(tdp)
{
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;
Ops.Fsize = 0;
Ops.Scrollable = false;
} // end of TDBJTB constructor
/***********************************************************************/
/* GetResult: Get the list of JDBC tables. */
/***********************************************************************/
PQRYRES TDBJTB::GetResult(PGLOBAL g)
{
return JDBCTables(g, 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, 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 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 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 *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;}
protected:
// Specific routines
virtual PQRYRES GetResult(PGLOBAL g);
// Members
int Maxres; // Returned lines limit
}; // 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 *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
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