summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Bertrand <bertrandop@gmail.com>2016-04-26 11:22:30 +0200
committerOlivier Bertrand <bertrandop@gmail.com>2016-04-26 11:22:30 +0200
commit4a6248079904498825c0b03b727b9e7486ed8867 (patch)
tree0bdd21002bc77fe724f47278abfaada523da65b2
parentc086a96b94322de173921ff5d15edc6a2ca82509 (diff)
downloadmariadb-git-4a6248079904498825c0b03b727b9e7486ed8867.tar.gz
- 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
-rw-r--r--storage/connect/jdbconn.cpp245
-rw-r--r--storage/connect/jdbconn.h15
-rw-r--r--storage/connect/tabjdbc.cpp68
-rw-r--r--storage/connect/tabjdbc.h3
4 files changed, 200 insertions, 131 deletions
diff --git a/storage/connect/jdbconn.cpp b/storage/connect/jdbconn.cpp
index 0c06e12b2f0..cf744971c9e 100644
--- a/storage/connect/jdbconn.cpp
+++ b/storage/connect/jdbconn.cpp
@@ -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. */
/***********************************************************************/
diff --git a/storage/connect/jdbconn.h b/storage/connect/jdbconn.h
index f84b8355443..0646fee845b 100644
--- a/storage/connect/jdbconn.h
+++ b/storage/connect/jdbconn.h
@@ -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];
diff --git a/storage/connect/tabjdbc.cpp b/storage/connect/tabjdbc.cpp
index 0dd15fe5c7d..97168646ba0 100644
--- a/storage/connect/tabjdbc.cpp
+++ b/storage/connect/tabjdbc.cpp
@@ -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 ------------------------------- */
diff --git a/storage/connect/tabjdbc.h b/storage/connect/tabjdbc.h
index 4163d051a30..b6cf91e28b8 100644
--- a/storage/connect/tabjdbc.h
+++ b/storage/connect/tabjdbc.h
@@ -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