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) ...@@ -708,15 +708,10 @@ JDBConn::JDBConn(PGLOBAL g, TDBJDBC *tdbp)
m_Tdb = tdbp; m_Tdb = tdbp;
jvm = nullptr; // Pointer to the JVM (Java Virtual Machine) jvm = nullptr; // Pointer to the JVM (Java Virtual Machine)
env= nullptr; // Pointer to native interface env= nullptr; // Pointer to native interface
jdi = nullptr; jdi = nullptr; // Pointer to the JdbcInterface class
job = nullptr; job = nullptr; // The JdbcInterface class object
xqid = nullptr; xqid = xuid = xid = grs = readid = fetchid = typid = nullptr;
xuid = nullptr; prepid = xpid = pcid = nullptr;
xid = nullptr;
grs = nullptr;
readid = nullptr;
fetchid = nullptr;
typid = nullptr;
//m_LoginTimeout = DEFAULT_LOGIN_TIMEOUT; //m_LoginTimeout = DEFAULT_LOGIN_TIMEOUT;
//m_QueryTimeout = DEFAULT_QUERY_TIMEOUT; //m_QueryTimeout = DEFAULT_QUERY_TIMEOUT;
//m_UpdateOptions = 0; //m_UpdateOptions = 0;
...@@ -1245,7 +1240,7 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val) ...@@ -1245,7 +1240,7 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val)
fldid = env->GetMethodID(jdi, "DoubleField", "(ILjava/lang/String;)D"); fldid = env->GetMethodID(jdi, "DoubleField", "(ILjava/lang/String;)D");
if (fldid != nullptr) if (fldid != nullptr)
val->SetValue((double)env->CallDoubleMethod(job, fldid, rank,jn)); val->SetValue((double)env->CallDoubleMethod(job, fldid, rank, jn));
else else
val->Reset(); val->Reset();
...@@ -1318,10 +1313,23 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val) ...@@ -1318,10 +1313,23 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val)
/***********************************************************************/ /***********************************************************************/
/* Prepare an SQL statement for insert. */ /* Prepare an SQL statement for insert. */
/***********************************************************************/ /***********************************************************************/
int JDBConn::PrepareSQL(char *sql) bool JDBConn::PrepareSQL(char *sql)
{ {
// TODO: implement prepared statement if (prepid == nullptr) {
return 0; 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 } // end of PrepareSQL
/***********************************************************************/ /***********************************************************************/
...@@ -1416,112 +1424,165 @@ int JDBConn::GetResultSize(char *sql, JDBCCOL *colp) ...@@ -1416,112 +1424,165 @@ int JDBConn::GetResultSize(char *sql, JDBCCOL *colp)
return colp->GetIntValue(); return colp->GetIntValue();
} // end of GetResultSize } // end of GetResultSize
#if 0
/***********************************************************************/ /***********************************************************************/
/* Execute a prepared statement. */ /* Execute a prepared statement. */
/***********************************************************************/ /***********************************************************************/
int JDBConn::ExecuteSQL(void) int JDBConn::ExecuteSQL(void)
{ {
int rc = RC_FX;
PGLOBAL& g = m_G; 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))) if (xpid == nullptr) {
ThrowDJX(rc, "SQLNumResultCols", m_hstmt); // Get the methods used to execute a prepared statement
xpid = env->GetMethodID(jdi, "ExecutePrep", "()I");
if (ncol) { if (xpid == nullptr) {
// This should never happen while inserting strcpy(g->Message, "Cannot find method ExecutePrep");
strcpy(g->Message, "Logical error while inserting"); return rc;
} else { } // endif xpid
// Insert, Update or Delete statement
if (!Check(rc = SQLRowCount(m_hstmt, &afrw)))
ThrowDJX(rc, "SQLRowCount", m_hstmt);
} // endif ncol } // endif xpid
} jint n = env->CallIntMethod(job, 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;
if (m_Transact) { switch ((int)n) {
rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_ROLLBACK); case -1:
m_Transact = false; case -2:
} // endif m_Transact strcpy(g->Message, "Exception error thrown while executing SQL");
break;
afrw = -1; case -3:
} // end try/catch 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 } // 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; PGLOBAL& g = m_G;
int buftype = colp->GetResultType(); int rc = false;
SQLUSMALLINT n = colp->GetRank(); PVAL val = colp->GetValue();
SQLSMALLINT ct, sqlt, dec, nul; jint n, i = (jint)colp->GetRank();
SQLULEN colsize; jshort s;
SQLLEN len; jlong lg;
SQLLEN *strlen = colp->GetStrLen(); //jfloat f;
SQLRETURN rc; jdouble d;
jclass dat;
jobject datobj;
jstring jst = nullptr;
jthrowable exc;
jmethodID dtc, setid = nullptr;
#if 0 switch (val->GetType()) {
try { case TYPE_STRING:
// This function is often not or badly implemented by data sources setid = env->GetMethodID(jdi, "SetStringParm", "(ILjava/lang/String;)V");
rc = SQLDescribeParam(m_hstmt, n, &sqlt, &colsize, &dec, &nul);
if (!Check(rc)) if (setid == nullptr) {
ThrowDJX(rc, "SQLDescribeParam", m_hstmt); strcpy(g->Message, "Cannot fing method SetStringParm");
return true;
} // endif setid
} jst = env->NewStringUTF(val->GetCharValue());
catch (DJX *x) { env->CallVoidMethod(job, setid, i, jst);
sprintf(m_G->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0)); break;
#endif // 0 case TYPE_INT:
colsize = colp->GetPrecision(); setid = env->GetMethodID(jdi, "SetIntParm", "(II)V");
sqlt = GetJDBCType(buftype);
dec = IsTypeNum(buftype) ? colp->GetScale() : 0;
nul = colp->IsNullable() ? SQL_NULLABLE : SQL_NO_NULLS;
//} // end try/catch
buf = colp->GetBuffer(0); if (setid == nullptr) {
len = IsTypeChar(buftype) ? colp->GetBuflen() : 0; strcpy(g->Message, "Cannot fing method SetIntParm");
ct = GetJDBCCType(buftype); return true;
*strlen = IsTypeChar(buftype) ? SQL_NTS : 0; } // endif setid
try { n = (jint)val->GetIntValue();
rc = SQLBindParameter(m_hstmt, n, SQL_PARAM_INPUT, ct, sqlt, env->CallVoidMethod(job, setid, i, n);
colsize, dec, buf, len, strlen); break;
case TYPE_TINY:
case TYPE_SHORT:
setid = env->GetMethodID(jdi, "SetShortParm", "(IS)V");
if (!Check(rc)) if (setid == nullptr) {
ThrowDJX(rc, "SQLBindParameter", m_hstmt); strcpy(g->Message, "Cannot fing method SetShortParm");
return true;
} // endif setid
} s = (jshort)val->GetShortValue();
catch (DJX *x) { env->CallVoidMethod(job, setid, i, s);
strcpy(m_G->Message, x->GetErrorMessage(0)); break;
SQLCancel(m_hstmt); case TYPE_BIGINT:
rc = SQLFreeStmt(m_hstmt, SQL_DROP); setid = env->GetMethodID(jdi, "SetBigintParm", "(IJ)V");
m_hstmt = NULL;
if (setid == nullptr) {
strcpy(g->Message, "Cannot fing method SetBigintParm");
return true; return true;
} // end try/catch } // endif setid
return false; lg = (jlong)val->GetBigintValue();
} // end of BindParam 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. */ /* Get the list of Data Sources and set it in qrp. */
/***********************************************************************/ /***********************************************************************/
......
...@@ -103,9 +103,9 @@ public: ...@@ -103,9 +103,9 @@ public:
int ExecuteQuery(char *sql); int ExecuteQuery(char *sql);
int ExecuteUpdate(char *sql); int ExecuteUpdate(char *sql);
int Fetch(int pos = 0); int Fetch(int pos = 0);
int PrepareSQL(char *sql); bool PrepareSQL(char *sql);
//int ExecuteSQL(void); int ExecuteSQL(void);
//bool BindParam(JDBCCOL *colp); bool SetParam(JDBCCOL *colp);
int ExecSQLcommand(char *sql); int ExecSQLcommand(char *sql);
void SetColumnValue(int rank, PSZ name, PVAL val); void SetColumnValue(int rank, PSZ name, PVAL val);
int GetCatInfo(JCATPARM *cap); int GetCatInfo(JCATPARM *cap);
...@@ -134,10 +134,6 @@ protected: ...@@ -134,10 +134,6 @@ protected:
//void Free(void); //void Free(void);
protected: protected:
// Static members
//static HENV m_henv;
//static int m_nAlloc; // per-Appl reference to HENV above
// Members // Members
PGLOBAL m_G; PGLOBAL m_G;
TDBJDBC *m_Tdb; TDBJDBC *m_Tdb;
...@@ -152,7 +148,10 @@ protected: ...@@ -152,7 +148,10 @@ protected:
jmethodID readid; // The ReadNext method ID jmethodID readid; // The ReadNext method ID
jmethodID fetchid; // The Fetch method ID jmethodID fetchid; // The Fetch method ID
jmethodID typid; // The ColumnType 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_QueryTimeout;
//DWORD m_UpdateOptions; //DWORD m_UpdateOptions;
char m_IDQuoteChar[2]; char m_IDQuoteChar[2];
......
...@@ -468,6 +468,7 @@ bool TDBJDBC::MakeInsert(PGLOBAL g) ...@@ -468,6 +468,7 @@ bool TDBJDBC::MakeInsert(PGLOBAL g)
{ {
char *schmp = NULL, *catp = NULL, buf[NAM_LEN * 3]; char *schmp = NULL, *catp = NULL, buf[NAM_LEN * 3];
int len = 0; int len = 0;
uint pos;
bool b = false, oom = false; bool b = false, oom = false;
PTABLE tablep = To_Table; PTABLE tablep = To_Table;
PCOL colp; PCOL colp;
...@@ -546,40 +547,44 @@ bool TDBJDBC::MakeInsert(PGLOBAL g) ...@@ -546,40 +547,44 @@ bool TDBJDBC::MakeInsert(PGLOBAL g)
} // endfor colp } // 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 // Make prepared statement
//for (int i = 0; i < Nparm; i++) for (int i = 0; i < Nparm; i++)
// oom |= Query->Append("?,"); oom |= Query->Append("?,");
if (oom) if (oom) {
strcpy(g->Message, "MakeInsert: Out of memory"); strcpy(g->Message, "MakeInsert: Out of memory");
//else return true;
// Query->RepLast(')'); } 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 } // 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; PJDBCCOL colp;
for (colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->Next) { for (colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->Next)
colp->AllocateBuffers(g, 0); if (Jcp->SetParam(colp))
if (Jcp->BindParam(colp))
return true; return true;
} // endfor colp
return false; return false;
#endif // 0 } // end of SetParameters
return true;
} // end of BindParameters
/***********************************************************************/ /***********************************************************************/
/* MakeCommand: make the Update or Delete statement to send to the */ /* MakeCommand: make the Update or Delete statement to send to the */
...@@ -1042,20 +1047,22 @@ int TDBJDBC::ReadDB(PGLOBAL g) ...@@ -1042,20 +1047,22 @@ int TDBJDBC::ReadDB(PGLOBAL g)
/***********************************************************************/ /***********************************************************************/
int TDBJDBC::WriteDB(PGLOBAL g) int TDBJDBC::WriteDB(PGLOBAL g)
{ {
#if 0 int rc;
int n = Jcp->ExecuteSQL();
if (n < 0) { if (Prepared) {
AftRows = n; if (SetParameters(g)) {
return RC_FX; Werr = true;
} else rc = RC_FX;
AftRows += n; } 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 // Statement was not prepared, we must construct and execute
// an insert query for each line to insert // an insert query for each line to insert
int rc;
uint len = Query->GetLength(); uint len = Query->GetLength();
char buf[64]; char buf[64];
bool oom = false; bool oom = false;
...@@ -1154,6 +1161,7 @@ void TDBJDBC::CloseDB(PGLOBAL g) ...@@ -1154,6 +1161,7 @@ void TDBJDBC::CloseDB(PGLOBAL g)
PushWarning(g, this, 0); // 0 means a Note PushWarning(g, this, 0); // 0 means a Note
} // endif Mode } // endif Mode
Prepared = false;
} // end of CloseDB } // end of CloseDB
/* --------------------------- JDBCCOL ------------------------------- */ /* --------------------------- JDBCCOL ------------------------------- */
......
...@@ -121,7 +121,7 @@ protected: ...@@ -121,7 +121,7 @@ protected:
bool MakeInsert(PGLOBAL g); bool MakeInsert(PGLOBAL g);
bool MakeCommand(PGLOBAL g); bool MakeCommand(PGLOBAL g);
//bool MakeFilter(PGLOBAL g, bool c); //bool MakeFilter(PGLOBAL g, bool c);
bool BindParameters(PGLOBAL g); bool SetParameters(PGLOBAL g);
//char *MakeUpdate(PGLOBAL g); //char *MakeUpdate(PGLOBAL g);
//char *MakeDelete(PGLOBAL g); //char *MakeDelete(PGLOBAL g);
...@@ -160,6 +160,7 @@ protected: ...@@ -160,6 +160,7 @@ protected:
int Memory; // 0: No 1: Alloc 2: Put 3: Get int Memory; // 0: No 1: Alloc 2: Put 3: Get
//bool Scrollable; // Use scrollable cursor --> in Ops //bool Scrollable; // Use scrollable cursor --> in Ops
bool Placed; // True for position reading bool Placed; // True for position reading
bool Prepared; // True when using prepared statement
bool Werr; // Write error bool Werr; // Write error
bool Rerr; // Rewind error bool Rerr; // Rewind error
PQRYRES Qrp; // Points to storage result 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