Commit 4a624807 authored by Olivier Bertrand's avatar Olivier Bertrand

- Add the use of prepared statement in the JDBC table type.

  modified:   storage/connect/jdbconn.cpp
  modified:   storage/connect/jdbconn.h
  modified:   storage/connect/tabjdbc.cpp
  modified:   storage/connect/tabjdbc.h
parent c086a96b
......@@ -708,15 +708,10 @@ JDBConn::JDBConn(PGLOBAL g, TDBJDBC *tdbp)
m_Tdb = tdbp;
jvm = nullptr; // Pointer to the JVM (Java Virtual Machine)
env= nullptr; // Pointer to native interface
jdi = nullptr;
job = nullptr;
xqid = nullptr;
xuid = nullptr;
xid = nullptr;
grs = nullptr;
readid = nullptr;
fetchid = nullptr;
typid = nullptr;
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;
......@@ -1245,7 +1240,7 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val)
fldid = env->GetMethodID(jdi, "DoubleField", "(ILjava/lang/String;)D");
if (fldid != nullptr)
val->SetValue((double)env->CallDoubleMethod(job, fldid, rank,jn));
val->SetValue((double)env->CallDoubleMethod(job, fldid, rank, jn));
else
val->Reset();
......@@ -1318,10 +1313,23 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val)
/***********************************************************************/
/* Prepare an SQL statement for insert. */
/***********************************************************************/
int JDBConn::PrepareSQL(char *sql)
bool JDBConn::PrepareSQL(char *sql)
{
// TODO: implement prepared statement
return 0;
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
/***********************************************************************/
......@@ -1416,112 +1424,165 @@ int JDBConn::GetResultSize(char *sql, JDBCCOL *colp)
return colp->GetIntValue();
} // end of GetResultSize
#if 0
/***********************************************************************/
/* Execute a prepared statement. */
/***********************************************************************/
int JDBConn::ExecuteSQL(void)
{
int rc = RC_FX;
PGLOBAL& g = m_G;
SWORD ncol = 0;
RETCODE rc;
SQLLEN afrw = -1;
try {
do {
rc = SQLExecute(m_hstmt);
} while (rc == SQL_STILL_EXECUTING);
if (!Check(rc))
ThrowDJX(rc, "SQLExecute", m_hstmt);
if (!Check(rc = SQLNumResultCols(m_hstmt, &ncol)))
ThrowDJX(rc, "SQLNumResultCols", m_hstmt);
if (xpid == nullptr) {
// Get the methods used to execute a prepared statement
xpid = env->GetMethodID(jdi, "ExecutePrep", "()I");
if (ncol) {
// This should never happen while inserting
strcpy(g->Message, "Logical error while inserting");
} else {
// Insert, Update or Delete statement
if (!Check(rc = SQLRowCount(m_hstmt, &afrw)))
ThrowDJX(rc, "SQLRowCount", m_hstmt);
if (xpid == nullptr) {
strcpy(g->Message, "Cannot find method ExecutePrep");
return rc;
} // endif xpid
} // endif ncol
} // endif xpid
}
catch (DJX *x) {
sprintf(m_G->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
SQLCancel(m_hstmt);
rc = SQLFreeStmt(m_hstmt, SQL_DROP);
m_hstmt = NULL;
jint n = env->CallIntMethod(job, xpid);
if (m_Transact) {
rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_ROLLBACK);
m_Transact = false;
} // endif m_Transact
afrw = -1;
} // end try/catch
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 (int)afrw;
return rc;
} // end of ExecuteSQL
/***********************************************************************/
/* Bind a parameter for inserting. */
/* Set a parameter for inserting. */
/***********************************************************************/
bool JDBConn::BindParam(JDBCCOL *colp)
bool JDBConn::SetParam(JDBCCOL *colp)
{
void *buf;
int buftype = colp->GetResultType();
SQLUSMALLINT n = colp->GetRank();
SQLSMALLINT ct, sqlt, dec, nul;
SQLULEN colsize;
SQLLEN len;
SQLLEN *strlen = colp->GetStrLen();
SQLRETURN rc;
PGLOBAL& g = m_G;
int rc = false;
PVAL val = colp->GetValue();
jint n, i = (jint)colp->GetRank();
jshort s;
jlong lg;
//jfloat f;
jdouble d;
jclass dat;
jobject datobj;
jstring jst = nullptr;
jthrowable exc;
jmethodID dtc, setid = nullptr;
#if 0
try {
// This function is often not or badly implemented by data sources
rc = SQLDescribeParam(m_hstmt, n, &sqlt, &colsize, &dec, &nul);
switch (val->GetType()) {
case TYPE_STRING:
setid = env->GetMethodID(jdi, "SetStringParm", "(ILjava/lang/String;)V");
if (!Check(rc))
ThrowDJX(rc, "SQLDescribeParam", m_hstmt);
if (setid == nullptr) {
strcpy(g->Message, "Cannot fing method SetStringParm");
return true;
} // endif setid
}
catch (DJX *x) {
sprintf(m_G->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
#endif // 0
colsize = colp->GetPrecision();
sqlt = GetJDBCType(buftype);
dec = IsTypeNum(buftype) ? colp->GetScale() : 0;
nul = colp->IsNullable() ? SQL_NULLABLE : SQL_NO_NULLS;
//} // end try/catch
jst = env->NewStringUTF(val->GetCharValue());
env->CallVoidMethod(job, setid, i, jst);
break;
case TYPE_INT:
setid = env->GetMethodID(jdi, "SetIntParm", "(II)V");
buf = colp->GetBuffer(0);
len = IsTypeChar(buftype) ? colp->GetBuflen() : 0;
ct = GetJDBCCType(buftype);
*strlen = IsTypeChar(buftype) ? SQL_NTS : 0;
if (setid == nullptr) {
strcpy(g->Message, "Cannot fing method SetIntParm");
return true;
} // endif setid
try {
rc = SQLBindParameter(m_hstmt, n, SQL_PARAM_INPUT, ct, sqlt,
colsize, dec, buf, len, strlen);
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 (!Check(rc))
ThrowDJX(rc, "SQLBindParameter", m_hstmt);
if (setid == nullptr) {
strcpy(g->Message, "Cannot fing method SetShortParm");
return true;
} // endif setid
}
catch (DJX *x) {
strcpy(m_G->Message, x->GetErrorMessage(0));
SQLCancel(m_hstmt);
rc = SQLFreeStmt(m_hstmt, SQL_DROP);
m_hstmt = NULL;
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;
} // end try/catch
} // endif setid
return false;
} // end of BindParam
lg = (jlong)val->GetBigintValue();
env->CallVoidMethod(job, setid, i, lg);
break;
case TYPE_DOUBLE:
case TYPE_DECIM:
setid = env->GetMethodID(jdi, "SetDoubleParm", "(ID)V");
if (setid == nullptr) {
strcpy(g->Message, "Cannot fing method SetDoubleParm");
return true;
} // endif setid
d = (jdouble)val->GetFloatValue();
env->CallVoidMethod(job, setid, i, d);
break;
case TYPE_DATE:
if ((dat = env->FindClass("java/sql/Timestamp")) == nullptr) {
strcpy(g->Message, "Cannot find Timestamp class");
return true;
} else if (!(dtc = env->GetMethodID(dat, "<init>", "(J)V"))) {
strcpy(g->Message, "Cannot find Timestamp class constructor");
return true;
} // endif's
lg = (jlong)val->GetBigintValue() * 1000;
if ((datobj = env->NewObject(dat, dtc, lg)) == nullptr) {
strcpy(g->Message, "Cannot make Timestamp object");
return true;
} else if ((setid = env->GetMethodID(jdi, "SetTimestampParm",
"(ILjava/sql/Timestamp;)V")) == nullptr) {
strcpy(g->Message, "Cannot find method SetTimestampParm");
return true;
} // endif setid
env->CallVoidMethod(job, setid, i, datobj);
break;
default:
sprintf(g->Message, "Parm type %d not supported", val->GetType());
return true;
} // endswitch Type
if ((exc = env->ExceptionOccurred()) != nullptr) {
jboolean isCopy = false;
jmethodID tid = env->GetMethodID(env->FindClass("java/lang/Object"), "toString", "()Ljava/lang/String;");
jstring s = (jstring)env->CallObjectMethod(exc, tid);
const char* utf = env->GetStringUTFChars(s, &isCopy);
sprintf(g->Message, "SetParam: %s", utf);
env->DeleteLocalRef(s);
env->ExceptionClear();
rc = true;
} // endif exc
if (jst)
env->DeleteLocalRef(jst);
return rc;
} // end of SetParam
#if 0
/***********************************************************************/
/* Get the list of Data Sources and set it in qrp. */
/***********************************************************************/
......
......@@ -103,9 +103,9 @@ public:
int ExecuteQuery(char *sql);
int ExecuteUpdate(char *sql);
int Fetch(int pos = 0);
int PrepareSQL(char *sql);
//int ExecuteSQL(void);
//bool BindParam(JDBCCOL *colp);
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);
......@@ -134,10 +134,6 @@ protected:
//void Free(void);
protected:
// Static members
//static HENV m_henv;
//static int m_nAlloc; // per-Appl reference to HENV above
// Members
PGLOBAL m_G;
TDBJDBC *m_Tdb;
......@@ -152,7 +148,10 @@ protected:
jmethodID readid; // The ReadNext method ID
jmethodID fetchid; // The Fetch method ID
jmethodID typid; // The ColumnType method ID
//DWORD m_LoginTimeout;
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];
......
......@@ -468,6 +468,7 @@ 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;
......@@ -546,40 +547,44 @@ bool TDBJDBC::MakeInsert(PGLOBAL g)
} // endfor colp
oom |= Query->Append(") VALUES (");
if ((oom |= Query->Append(") VALUES ("))) {
strcpy(g->Message, "MakeInsert: Out of memory");
return true;
} else // in case prepared statement fails
pos = Query->GetLength();
// Currently not using prepared statement
//for (int i = 0; i < Nparm; i++)
// oom |= Query->Append("?,");
// Make prepared statement
for (int i = 0; i < Nparm; i++)
oom |= Query->Append("?,");
if (oom)
if (oom) {
strcpy(g->Message, "MakeInsert: Out of memory");
//else
// Query->RepLast(')');
return true;
} else
Query->RepLast(')');
return oom;
// 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 Bind Parameter function. */
/* JDBC Set Parameter function. */
/***********************************************************************/
bool TDBJDBC::BindParameters(PGLOBAL g)
bool TDBJDBC::SetParameters(PGLOBAL g)
{
#if 0
PJDBCCOL colp;
for (colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->Next) {
colp->AllocateBuffers(g, 0);
if (Jcp->BindParam(colp))
for (colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->Next)
if (Jcp->SetParam(colp))
return true;
} // endfor colp
return false;
#endif // 0
return true;
} // end of BindParameters
} // end of SetParameters
/***********************************************************************/
/* MakeCommand: make the Update or Delete statement to send to the */
......@@ -1042,20 +1047,22 @@ int TDBJDBC::ReadDB(PGLOBAL g)
/***********************************************************************/
int TDBJDBC::WriteDB(PGLOBAL g)
{
#if 0
int n = Jcp->ExecuteSQL();
int rc;
if (n < 0) {
AftRows = n;
return RC_FX;
} else
AftRows += n;
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
return RC_OK;
#endif // 0
// Statement was not prepared, we must construct and execute
// an insert query for each line to insert
int rc;
uint len = Query->GetLength();
char buf[64];
bool oom = false;
......@@ -1154,6 +1161,7 @@ void TDBJDBC::CloseDB(PGLOBAL g)
PushWarning(g, this, 0); // 0 means a Note
} // endif Mode
Prepared = false;
} // end of CloseDB
/* --------------------------- JDBCCOL ------------------------------- */
......
......@@ -121,7 +121,7 @@ protected:
bool MakeInsert(PGLOBAL g);
bool MakeCommand(PGLOBAL g);
//bool MakeFilter(PGLOBAL g, bool c);
bool BindParameters(PGLOBAL g);
bool SetParameters(PGLOBAL g);
//char *MakeUpdate(PGLOBAL g);
//char *MakeDelete(PGLOBAL g);
......@@ -160,6 +160,7 @@ protected:
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
......
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