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() { ...@@ -257,6 +257,32 @@ int main() {
ENDIF(UNIX) ENDIF(UNIX)
ENDIF(CONNECT_WITH_ODBC) ENDIF(CONNECT_WITH_ODBC)
#
# JDBC
#
OPTION(CONNECT_WITH_JDBC "Compile CONNECT storage engine with JDBC support" ON)
IF(CONNECT_WITH_JDBC)
# TODO: detect Java SDK and the presence of JDBC connectors
# 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 # XMAP
...@@ -277,5 +303,5 @@ MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES} ...@@ -277,5 +303,5 @@ MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES}
COMPONENT connect-engine COMPONENT connect-engine
RECOMPILE_FOR_EMBEDDED RECOMPILE_FOR_EMBEDDED
LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY} LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY}
${ODBC_LIBRARY} ${IPHLPAPI_LIBRARY}) ${ODBC_LIBRARY} ${JDBC_LIBRARY} ${IPHLPAPI_LIBRARY})
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 @@ ...@@ -21,8 +21,8 @@
based on external data. Principally they are based on plain files of many based on external data. Principally they are based on plain files of many
different types, but also on collections of such files, collection of tables, different types, but also on collections of such files, collection of tables,
local or remote MySQL/MariaDB tables retrieved via MySQL API, local or remote MySQL/MariaDB tables retrieved via MySQL API,
ODBC tables retrieving data from other DBMS having an ODBC server, and even ODBC/JDBC tables retrieving data from other DBMS having an ODBC/JDBC server,
virtual tables. and even virtual tables.
@details @details
ha_connect will let you create/open/delete tables, the created table can be ha_connect will let you create/open/delete tables, the created table can be
...@@ -115,9 +115,6 @@ ...@@ -115,9 +115,6 @@
#include "sql_parse.h" #include "sql_parse.h"
#include "sql_base.h" #include "sql_base.h"
#include <sys/stat.h> #include <sys/stat.h>
#if defined(NEW_WAY)
#include "sql_table.h"
#endif // NEW_WAY
#include "sql_partition.h" #include "sql_partition.h"
#undef OFFSET #undef OFFSET
...@@ -130,6 +127,10 @@ ...@@ -130,6 +127,10 @@
#if defined(ODBC_SUPPORT) #if defined(ODBC_SUPPORT)
#include "odbccat.h" #include "odbccat.h"
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
#if defined(JDBC_SUPPORT)
#include "jdbccat.h"
#include "jdbconn.h"
#endif // JDBC_SUPPORT
#include "xtable.h" #include "xtable.h"
#include "tabmysql.h" #include "tabmysql.h"
#include "filamdbf.h" #include "filamdbf.h"
...@@ -169,7 +170,7 @@ ...@@ -169,7 +170,7 @@
#define JSONMAX 10 // JSON Default max grp size #define JSONMAX 10 // JSON Default max grp size
extern "C" { extern "C" {
char version[]= "Version 1.04.0006 March 12, 2016"; char version[]= "Version 1.04.0006 May 08, 2016";
#if defined(__WIN__) #if defined(__WIN__)
char compver[]= "Version 1.04.0006 " __DATE__ " " __TIME__; char compver[]= "Version 1.04.0006 " __DATE__ " " __TIME__;
char slash= '\\'; char slash= '\\';
...@@ -190,6 +191,17 @@ extern "C" { ...@@ -190,6 +191,17 @@ extern "C" {
} // extern "C" } // extern "C"
#endif // XMSG #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. */ /* Utility functions. */
/***********************************************************************/ /***********************************************************************/
...@@ -197,6 +209,7 @@ PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); ...@@ -197,6 +209,7 @@ PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info);
PQRYRES VirColumns(PGLOBAL g, bool info); PQRYRES VirColumns(PGLOBAL g, bool info);
PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info); PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info);
PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info); PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info);
int TranslateJDBCType(int stp, int prec, int& len, char& v);
void PushWarning(PGLOBAL g, THD *thd, int level); void PushWarning(PGLOBAL g, THD *thd, int level);
bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host, bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host,
const char *db, char *tab, const char *src, int port); const char *db, char *tab, const char *src, int port);
...@@ -633,6 +646,7 @@ static int connect_init_func(void *p) ...@@ -633,6 +646,7 @@ static int connect_init_func(void *p)
#if defined(__WIN__) #if defined(__WIN__)
sql_print_information("CONNECT: %s", compver); sql_print_information("CONNECT: %s", compver);
InitializeCriticalSection((LPCRITICAL_SECTION)&parsec);
#else // !__WIN__ #else // !__WIN__
sql_print_information("CONNECT: %s", version); sql_print_information("CONNECT: %s", version);
#endif // !__WIN__ #endif // !__WIN__
...@@ -659,6 +673,9 @@ static int connect_init_func(void *p) ...@@ -659,6 +673,9 @@ static int connect_init_func(void *p)
DTVAL::SetTimeShift(); // Initialize time zone shift once for all DTVAL::SetTimeShift(); // Initialize time zone shift once for all
BINCOL::SetEndian(); // Initialize host endian setting BINCOL::SetEndian(); // Initialize host endian setting
#if defined(JDBC_SUPPORT)
JDBConn::SetJVM();
#endif // JDBC_SUPPORT
DBUG_RETURN(0); DBUG_RETURN(0);
} // end of connect_init_func } // end of connect_init_func
...@@ -677,8 +694,14 @@ static int connect_done_func(void *) ...@@ -677,8 +694,14 @@ static int connect_done_func(void *)
XmlCleanupParserLib(); XmlCleanupParserLib();
#endif // LIBXML2_SUPPORT #endif // LIBXML2_SUPPORT
#if !defined(__WIN__) #ifdef JDBC_SUPPORT
//PROFILE_End(); Causes signal 11 JDBConn::ResetJVM();
#endif // JDBC_SUPPORT
#if defined(__WIN__)
DeleteCriticalSection((LPCRITICAL_SECTION)&parsec);
#else // !__WIN__
PROFILE_End();
#endif // !__WIN__ #endif // !__WIN__
for (pc= user_connect::to_users; pc; pc= pn) { for (pc= user_connect::to_users; pc; pc= pn) {
...@@ -1758,8 +1781,9 @@ int ha_connect::OpenTable(PGLOBAL g, bool del) ...@@ -1758,8 +1781,9 @@ int ha_connect::OpenTable(PGLOBAL g, bool del)
break; break;
} // endswitch xmode } // endswitch xmode
if (xmod != MODE_INSERT || tdbp->GetAmType() == TYPE_AM_ODBC if (xmod != MODE_INSERT || tdbp->GetAmType() == TYPE_AM_MYSQL
|| tdbp->GetAmType() == TYPE_AM_MYSQL) { || tdbp->GetAmType() == TYPE_AM_ODBC
|| tdbp->GetAmType() == TYPE_AM_JDBC) {
// Get the list of used fields (columns) // Get the list of used fields (columns)
char *p; char *p;
unsigned int k1, k2, n1, n2; unsigned int k1, k2, n1, n2;
...@@ -2077,7 +2101,8 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *) ...@@ -2077,7 +2101,8 @@ int ha_connect::ScanRecord(PGLOBAL g, uchar *)
continue; // Is a virtual column possible here ??? continue; // Is a virtual column possible here ???
if ((xmod == MODE_INSERT && tdbp->GetAmType() != TYPE_AM_MYSQL if ((xmod == MODE_INSERT && tdbp->GetAmType() != TYPE_AM_MYSQL
&& tdbp->GetAmType() != TYPE_AM_ODBC) || && tdbp->GetAmType() != TYPE_AM_ODBC
&& tdbp->GetAmType() != TYPE_AM_JDBC) ||
bitmap_is_set(table->write_set, fp->field_index)) { bitmap_is_set(table->write_set, fp->field_index)) {
for (colp= tp->GetSetCols(); colp; colp= colp->GetNext()) for (colp= tp->GetSetCols(); colp; colp= colp->GetNext())
if (!stricmp(colp->GetName(), fp->field_name)) if (!stricmp(colp->GetName(), fp->field_name))
...@@ -2627,7 +2652,7 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond) ...@@ -2627,7 +2652,7 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond)
} // end of CondFilter } // end of CondFilter
/***********************************************************************/ /***********************************************************************/
/* Check the WHERE condition and return a MYSQL/ODBC/WQL filter. */ /* Check the WHERE condition and return a MYSQL/ODBC/JDBC/WQL filter. */
/***********************************************************************/ /***********************************************************************/
PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
{ {
...@@ -2635,8 +2660,8 @@ 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; char *body= filp->Body;
unsigned int i; unsigned int i;
bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC); bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
bool nonul= (tty == TYPE_AM_ODBC && (tdbp->GetMode() == MODE_INSERT || bool nonul= ((tty == TYPE_AM_ODBC || tty == TYPE_AM_JDBC) &&
tdbp->GetMode() == MODE_DELETE)); (tdbp->GetMode() == MODE_INSERT || tdbp->GetMode() == MODE_DELETE));
OPVAL vop= OP_XX; OPVAL vop= OP_XX;
if (!cond) if (!cond)
...@@ -2958,7 +2983,7 @@ const COND *ha_connect::cond_push(const COND *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 x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
bool b= (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC || bool b= (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC ||
tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL || tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL ||
tty == TYPE_AM_PLG || x); tty == TYPE_AM_PLG || tty == TYPE_AM_JDBC || x);
// Save stack and allocation environment and prepare error return // Save stack and allocation environment and prepare error return
if (g->jump_level == MAX_JUMP) { if (g->jump_level == MAX_JUMP) {
...@@ -4108,6 +4133,7 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn) ...@@ -4108,6 +4133,7 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn)
/* Fall through to check FILE_ACL */ /* Fall through to check FILE_ACL */
case TAB_ODBC: case TAB_ODBC:
case TAB_JDBC:
case TAB_MYSQL: case TAB_MYSQL:
case TAB_DIR: case TAB_DIR:
case TAB_MAC: case TAB_MAC:
...@@ -5124,11 +5150,17 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5124,11 +5150,17 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
int port= 0, hdr= 0, mxr= 0, mxe= 0, rc= 0; int port= 0, hdr= 0, mxr= 0, mxe= 0, rc= 0;
int cop __attribute__((unused))= 0, lrecl= 0; int cop __attribute__((unused))= 0, lrecl= 0;
#if defined(ODBC_SUPPORT) #if defined(ODBC_SUPPORT)
POPARM sop = NULL; POPARM sop= NULL;
char *ucnc = NULL; char *ucnc= NULL;
bool cnc= false; bool cnc= false;
int cto= -1, qto= -1; int cto= -1, qto= -1;
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
#if defined(JDBC_SUPPORT)
PJPARM sjp= NULL;
char *driver= NULL;
char *url= NULL;
char *tabtyp = NULL;
#endif // JDBC_SUPPORT
uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL); uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL);
bool bif, ok= false, dbf= false; bool bif, ok= false, dbf= false;
TABTYPE ttp= TAB_UNDEF; TABTYPE ttp= TAB_UNDEF;
...@@ -5139,15 +5171,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5139,15 +5171,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
PDBUSER dup= PlgGetUser(g); PDBUSER dup= PlgGetUser(g);
PCATLG cat= (dup) ? dup->Catalog : NULL; PCATLG cat= (dup) ? dup->Catalog : NULL;
PTOS topt= table_s->option_struct; PTOS topt= table_s->option_struct;
#if defined(NEW_WAY)
//CHARSET_INFO *cs;
Alter_info alter_info;
#else // !NEW_WAY
char buf[1024]; char buf[1024];
String sql(buf, sizeof(buf), system_charset_info); String sql(buf, sizeof(buf), system_charset_info);
sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info); sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info);
#endif // !NEW_WAY
if (!g) if (!g)
return HA_ERR_INTERNAL_ERROR; return HA_ERR_INTERNAL_ERROR;
...@@ -5195,6 +5222,11 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5195,6 +5222,11 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
if ((ucnc= GetListOption(g, "UseDSN", topt->oplist))) if ((ucnc= GetListOption(g, "UseDSN", topt->oplist)))
cnc= (!*ucnc || *ucnc == 'y' || *ucnc == 'Y' || atoi(ucnc) != 0); cnc= (!*ucnc || *ucnc == 'y' || *ucnc == 'Y' || atoi(ucnc) != 0);
#endif #endif
#if defined(JDBC_SUPPORT)
driver= GetListOption(g, "Driver", topt->oplist, NULL);
url= GetListOption(g, "URL", topt->oplist, NULL);
tabtyp = GetListOption(g, "Tabtype", topt->oplist, NULL);
#endif // JDBC_SUPPORT
mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0")); mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0"));
#if defined(PROMPT_OK) #if defined(PROMPT_OK)
cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0")); cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0"));
...@@ -5255,9 +5287,6 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5255,9 +5287,6 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
} else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL))) } else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL)))
tab= table_s->table_name.str; // Default value tab= table_s->table_name.str; // Default value
#if defined(NEW_WAY)
// add_option(thd, create_info, "tabname", tab);
#endif // NEW_WAY
} // endif tab } // endif tab
switch (ttp) { switch (ttp) {
...@@ -5292,6 +5321,27 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5292,6 +5321,27 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER); supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER);
break; break;
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
#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: case TAB_DBF:
dbf= true; dbf= true;
// Passthru // Passthru
...@@ -5411,7 +5461,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5411,7 +5461,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
dpath= SetPath(g, table_s->db.str); dpath= SetPath(g, table_s->db.str);
if (src && ttp != TAB_PIVOT && ttp != TAB_ODBC) { if (src && ttp != TAB_PIVOT && ttp != TAB_ODBC && ttp != TAB_JDBC) {
qrp= SrcColumns(g, host, db, user, pwd, src, port); qrp= SrcColumns(g, host, db, user, pwd, src, port);
if (qrp && ttp == TAB_OCCUR) if (qrp && ttp == TAB_OCCUR)
...@@ -5453,6 +5503,36 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5453,6 +5503,36 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
break; break;
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
#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: case TAB_MYSQL:
qrp= MyColumns(g, thd, host, db, user, pwd, tab, qrp= MyColumns(g, thd, host, db, user, pwd, tab,
NULL, port, fnc == FNC_COL); NULL, port, fnc == FNC_COL);
...@@ -5526,14 +5606,9 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5526,14 +5606,9 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
len= 256; // STRBLK's have 0 length len= 256; // STRBLK's have 0 length
// Now add the field // Now add the field
#if defined(NEW_WAY)
rc= add_fields(g, thd, &alter_info, cnm, typ, len, dec,
tm, "", flg, dbf, v);
#else // !NEW_WAY
if (add_field(&sql, cnm, typ, len, dec, NULL, tm, if (add_field(&sql, cnm, typ, len, dec, NULL, tm,
NULL, NULL, NULL, NULL, flg, dbf, v)) NULL, NULL, NULL, NULL, flg, dbf, v))
rc= HA_ERR_OUT_OF_MEM; rc= HA_ERR_OUT_OF_MEM;
#endif // !NEW_WAY
} // endfor crp } // endfor crp
} else { } else {
...@@ -5556,12 +5631,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5556,12 +5631,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
cnm= (char*)"noname"; cnm= (char*)"noname";
dft= xtra= key= fmt= NULL; dft= xtra= key= fmt= NULL;
v= ' '; v= ' ';
#if defined(NEW_WAY)
rem= "";
// cs= NULL;
#else // !NEW_WAY
rem= NULL; rem= NULL;
#endif // !NEW_WAY
for (crp= qrp->Colresp; crp; crp= crp->Next) for (crp= qrp->Colresp; crp; crp= crp->Next)
switch (crp->Fld) { switch (crp->Fld) {
...@@ -5680,6 +5750,41 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5680,6 +5750,41 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
dec= 0; dec= 0;
} // endswitch typ } // endswitch typ
} else
#endif // ODBC_SUPPORT
#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 } else
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
// Make the arguments as required by add_fields // Make the arguments as required by add_fields
...@@ -5690,25 +5795,15 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5690,25 +5795,15 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
prec= 0; prec= 0;
// Now add the field // Now add the field
#if defined(NEW_WAY)
rc= add_fields(g, thd, &alter_info, cnm, typ, prec, dec,
tm, rem, 0, dbf, v);
#else // !NEW_WAY
if (add_field(&sql, cnm, typ, prec, dec, key, tm, rem, dft, xtra, if (add_field(&sql, cnm, typ, prec, dec, key, tm, rem, dft, xtra,
fmt, 0, dbf, v)) fmt, 0, dbf, v))
rc= HA_ERR_OUT_OF_MEM; rc= HA_ERR_OUT_OF_MEM;
#endif // !NEW_WAY
} // endfor i } // endfor i
} // endif fnc } // endif fnc
#if defined(NEW_WAY)
rc= init_table_share(thd, table_s, create_info, &alter_info);
#else // !NEW_WAY
if (!rc) if (!rc)
rc= init_table_share(thd, table_s, create_info, &sql); rc= init_table_share(thd, table_s, create_info, &sql);
// rc= init_table_share(thd, table_s, create_info, dsn, &sql);
#endif // !NEW_WAY
g->jump_level--; g->jump_level--;
return rc; return rc;
...@@ -6750,6 +6845,21 @@ static MYSQL_SYSVAR_STR(errmsg_dir_path, msg_path, ...@@ -6750,6 +6845,21 @@ static MYSQL_SYSVAR_STR(errmsg_dir_path, msg_path,
"../../../../storage/connect/"); // for testing "../../../../storage/connect/"); // for testing
#endif // XMSG #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[]= { static struct st_mysql_sys_var* connect_system_variables[]= {
MYSQL_SYSVAR(xtrace), MYSQL_SYSVAR(xtrace),
MYSQL_SYSVAR(conv_size), MYSQL_SYSVAR(conv_size),
...@@ -6767,6 +6877,10 @@ static struct st_mysql_sys_var* connect_system_variables[]= { ...@@ -6767,6 +6877,10 @@ static struct st_mysql_sys_var* connect_system_variables[]= {
MYSQL_SYSVAR(errmsg_dir_path), MYSQL_SYSVAR(errmsg_dir_path),
#endif // XMSG #endif // XMSG
MYSQL_SYSVAR(json_grp_size), MYSQL_SYSVAR(json_grp_size),
#if defined(JDBC_SUPPORT)
MYSQL_SYSVAR(jvm_path),
MYSQL_SYSVAR(class_path),
#endif // JDBC_SUPPORT
NULL NULL
}; };
......
...@@ -622,13 +622,16 @@ void PROFILE_End(void) ...@@ -622,13 +622,16 @@ void PROFILE_End(void)
if (trace) if (trace)
htrc("PROFILE_End: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES); 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 */ /* Close all opened files and free the cache structure */
for (i = 0; i < N_CACHED_PROFILES; i++) { for (i = 0; i < N_CACHED_PROFILES; i++) {
if (trace) if (trace)
htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i); htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i);
CurProfile = MRUProfile[i]; // CurProfile = MRUProfile[i]; Sergey Vojtovich
PROFILE_ReleaseFile(); // PROFILE_ReleaseFile(); see MDEV-9997
free(MRUProfile[i]); free(MRUProfile[i]);
} // endfor 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) ...@@ -3538,37 +3538,9 @@ void jsoncontains_path_deinit(UDF_INIT* initid)
} // end of jsoncontains_path_deinit } // 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) char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
{
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 *error) unsigned long *res_length, char *is_null, char *error)
{ {
char *p, *path, *str = NULL; char *p, *path, *str = NULL;
...@@ -3586,12 +3558,16 @@ char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -3586,12 +3558,16 @@ char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
} else if (initid->const_item) } else if (initid->const_item)
g->N = 1; g->N = 1;
if (!strcmp(result, "$insert")) if (!strcmp(result, "$set"))
w = 0;
else if (!strcmp(result, "$insert"))
w = 1; w = 1;
else if (!strcmp(result, "$update")) else if (!strcmp(result, "$update"))
w = 2; w = 2;
else else {
w = 0; PUSH_WARNING("Logical error, please contact CONNECT developer");
goto err;
} // endelse
// Save stack and allocation environment and prepare error return // Save stack and allocation environment and prepare error return
if (g->jump_level == MAX_JUMP) { if (g->jump_level == MAX_JUMP) {
...@@ -3660,10 +3636,10 @@ char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -3660,10 +3636,10 @@ char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
// Keep result of constant function // Keep result of constant function
g->Activityp = (PACTIVITY)str; g->Activityp = (PACTIVITY)str;
err: err:
g->jump_level--; g->jump_level--;
fin: fin:
if (!str) { if (!str) {
*is_null = 1; *is_null = 1;
*res_length = 0; *res_length = 0;
...@@ -3671,6 +3647,44 @@ char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -3671,6 +3647,44 @@ char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
*res_length = strlen(str); *res_length = strlen(str);
return 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 } // end of json_set_item
void json_set_item_deinit(UDF_INIT* initid) void json_set_item_deinit(UDF_INIT* initid)
...@@ -3690,7 +3704,7 @@ char *json_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -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) unsigned long *res_length, char *is_null, char *p)
{ {
strcpy(result, "$insert"); 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 } // end of json_insert_item
void json_insert_item_deinit(UDF_INIT* initid) void json_insert_item_deinit(UDF_INIT* initid)
...@@ -3710,7 +3724,7 @@ char *json_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -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) unsigned long *res_length, char *is_null, char *p)
{ {
strcpy(result, "$update"); 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 } // end of json_update_item
void json_update_item_deinit(UDF_INIT* initid) void json_update_item_deinit(UDF_INIT* initid)
...@@ -4706,14 +4720,9 @@ void jbin_item_merge_deinit(UDF_INIT* initid) ...@@ -4706,14 +4720,9 @@ void jbin_item_merge_deinit(UDF_INIT* initid)
} // end of jbin_item_merge_deinit } // 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) char *bin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
{
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 *error) unsigned long *res_length, char *is_null, char *error)
{ {
char *p, *path; char *p, *path;
...@@ -4732,12 +4741,16 @@ char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -4732,12 +4741,16 @@ char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
} else if (initid->const_item) } else if (initid->const_item)
g->N = 1; g->N = 1;
if (!strcmp(result, "$insert")) if (!strcmp(result, "$set"))
w = 0;
else if (!strcmp(result, "$insert"))
w = 1; w = 1;
else if (!strcmp(result, "$update")) else if (!strcmp(result, "$update"))
w = 2; w = 2;
else else {
w = 0; PUSH_WARNING("Logical error, please contact CONNECT developer");
goto fin;
} // endelse
if (!g->Xchk) { if (!g->Xchk) {
if (CheckMemory(g, initid, args, 1, true, false, true)) { 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, ...@@ -4791,7 +4804,7 @@ char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
// Keep result of constant function // Keep result of constant function
g->Activityp = (PACTIVITY)bsp; g->Activityp = (PACTIVITY)bsp;
fin: fin:
if (!bsp) { if (!bsp) {
*is_null = 1; *is_null = 1;
*res_length = 0; *res_length = 0;
...@@ -4799,6 +4812,21 @@ char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -4799,6 +4812,21 @@ char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
*res_length = sizeof(BSON); *res_length = sizeof(BSON);
return (char*)bsp; 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 } // end of jbin_set_item
void jbin_set_item_deinit(UDF_INIT* initid) void jbin_set_item_deinit(UDF_INIT* initid)
...@@ -4818,7 +4846,7 @@ char *jbin_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -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) unsigned long *res_length, char *is_null, char *p)
{ {
strcpy(result, "$insert"); 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 } // end of jbin_insert_item
void jbin_insert_item_deinit(UDF_INIT* initid) void jbin_insert_item_deinit(UDF_INIT* initid)
...@@ -4838,7 +4866,7 @@ char *jbin_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -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) unsigned long *res_length, char *is_null, char *p)
{ {
strcpy(result, "$update"); 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 } // end of jbin_update_item
void jbin_update_item_deinit(UDF_INIT* initid) void jbin_update_item_deinit(UDF_INIT* initid)
...@@ -4999,3 +5027,30 @@ void json_serialize_deinit(UDF_INIT* initid) ...@@ -4999,3 +5027,30 @@ void json_serialize_deinit(UDF_INIT* initid)
{ {
JsonFreeMem((PGLOBAL)initid->ptr); JsonFreeMem((PGLOBAL)initid->ptr);
} // end of json_serialize_deinit } // 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" { ...@@ -218,8 +218,12 @@ extern "C" {
DllExport my_bool json_serialize_init(UDF_INIT*, UDF_ARGS*, char*); DllExport my_bool json_serialize_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *json_serialize(UDF_EXEC_ARGS); DllExport char *json_serialize(UDF_EXEC_ARGS);
DllExport void json_serialize_deinit(UDF_INIT*); 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" } // extern "C"
/*********************************************************************************/ /*********************************************************************************/
/* Structure JPN. Used to make the locate path. */ /* Structure JPN. Used to make the locate path. */
/*********************************************************************************/ /*********************************************************************************/
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
/* */ /* */
/* COPYRIGHT: */ /* COPYRIGHT: */
/* ---------- */ /* ---------- */
/* (C) Copyright to the author Olivier BERTRAND 1998-2015 */ /* (C) Copyright to the author Olivier BERTRAND 1998-2016 */
/* */ /* */
/* WHAT THIS PROGRAM DOES: */ /* WHAT THIS PROGRAM DOES: */
/* ----------------------- */ /* ----------------------- */
...@@ -46,9 +46,9 @@ ...@@ -46,9 +46,9 @@
#else // !__WIN__ #else // !__WIN__
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#if defined(THREAD) //#if defined(THREAD)
#include <pthread.h> #include <pthread.h>
#endif // THREAD //#endif // THREAD
#include <stdarg.h> #include <stdarg.h>
#define BIGMEM 2147483647 // Max int value #define BIGMEM 2147483647 // Max int value
#endif // !__WIN__ #endif // !__WIN__
...@@ -69,17 +69,6 @@ ...@@ -69,17 +69,6 @@
#include "valblk.h" #include "valblk.h"
#include "rcmsg.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. */ /* DB static variables. */
/***********************************************************************/ /***********************************************************************/
...@@ -90,6 +79,12 @@ extern "C" { ...@@ -90,6 +79,12 @@ extern "C" {
extern char version[]; extern char version[];
} // extern "C" } // 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 // The debug trace used by the main thread
FILE *pfile = NULL; FILE *pfile = NULL;
...@@ -702,21 +697,21 @@ PDTP MakeDateFormat(PGLOBAL g, PSZ dfmt, bool in, bool out, int flag) ...@@ -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 */ /* Call the FLEX generated parser. In multi-threading mode the next */
/* instruction is included in an Enter/LeaveCriticalSection bracket. */ /* instruction is included in an Enter/LeaveCriticalSection bracket. */
/*********************************************************************/ /*********************************************************************/
#if defined(THREAD) //#if defined(THREAD)
#if defined(__WIN__) #if defined(__WIN__)
EnterCriticalSection((LPCRITICAL_SECTION)&parsec); EnterCriticalSection((LPCRITICAL_SECTION)&parsec);
#else // !__WIN__ #else // !__WIN__
pthread_mutex_lock(&parmut); pthread_mutex_lock(&parmut);
#endif // !__WIN__ #endif // !__WIN__
#endif // THREAD //#endif // THREAD
rc = fmdflex(pdp); rc = fmdflex(pdp);
#if defined(THREAD) //#if defined(THREAD)
#if defined(__WIN__) #if defined(__WIN__)
LeaveCriticalSection((LPCRITICAL_SECTION)&parsec); LeaveCriticalSection((LPCRITICAL_SECTION)&parsec);
#else // !__WIN__ #else // !__WIN__
pthread_mutex_unlock(&parmut); pthread_mutex_unlock(&parmut);
#endif // !__WIN__ #endif // !__WIN__
#endif // THREAD //#endif // THREAD
if (trace) if (trace)
htrc("Done: in=%s out=%s rc=%d\n", SVP(pdp->InFmt), SVP(pdp->OutFmt), rc); htrc("Done: in=%s out=%s rc=%d\n", SVP(pdp->InFmt), SVP(pdp->OutFmt), rc);
...@@ -1102,6 +1097,7 @@ char *GetAmName(PGLOBAL g, AMT am, void *memp) ...@@ -1102,6 +1097,7 @@ char *GetAmName(PGLOBAL g, AMT am, void *memp)
case TYPE_AM_DOM: strcpy(amn, "DOM"); break; case TYPE_AM_DOM: strcpy(amn, "DOM"); break;
case TYPE_AM_DIR: strcpy(amn, "DIR"); break; case TYPE_AM_DIR: strcpy(amn, "DIR"); break;
case TYPE_AM_ODBC: strcpy(amn, "ODBC"); break; case TYPE_AM_ODBC: strcpy(amn, "ODBC"); break;
case TYPE_AM_JDBC: strcpy(amn, "JDBC"); break;
case TYPE_AM_MAC: strcpy(amn, "MAC"); break; case TYPE_AM_MAC: strcpy(amn, "MAC"); break;
case TYPE_AM_OEM: strcpy(amn, "OEM"); break; case TYPE_AM_OEM: strcpy(amn, "OEM"); break;
case TYPE_AM_OUT: strcpy(amn, "OUT"); break; case TYPE_AM_OUT: strcpy(amn, "OUT"); break;
......
...@@ -305,7 +305,7 @@ int TABDEF::GetColCatInfo(PGLOBAL g) ...@@ -305,7 +305,7 @@ int TABDEF::GetColCatInfo(PGLOBAL g)
case TAB_OEM: case TAB_OEM:
poff = 0; // Offset represents an independant flag poff = 0; // Offset represents an independant flag
break; break;
default: // VCT PLG ODBC MYSQL WMI... default: // VCT PLG ODBC JDBC MYSQL WMI...
poff = 0; // NA poff = 0; // NA
break; break;
} // endswitch tc } // endswitch tc
...@@ -514,9 +514,10 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g) ...@@ -514,9 +514,10 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g)
} // endif getdef } // endif getdef
#else // !__WIN__ #else // !__WIN__
const char *error = NULL; const char *error = NULL;
Dl_info dl_info;
#if 0 // Don't know what all this stuff does #if 0 // Don't know what all this stuff does
Dl_info dl_info;
// The OEM lib must retrieve exported CONNECT variables // The OEM lib must retrieve exported CONNECT variables
if (dladdr(&connect_hton, &dl_info)) { if (dladdr(&connect_hton, &dl_info)) {
if (dlopen(dl_info.dli_fname, RTLD_NOLOAD | RTLD_NOW | RTLD_GLOBAL) == 0) { if (dlopen(dl_info.dli_fname, RTLD_NOLOAD | RTLD_NOW | RTLD_GLOBAL) == 0) {
......
/************* 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