diff options
author | Olivier Bertrand <bertrandop@gmail.com> | 2016-04-26 11:22:30 +0200 |
---|---|---|
committer | Olivier Bertrand <bertrandop@gmail.com> | 2016-04-26 11:22:30 +0200 |
commit | 4a6248079904498825c0b03b727b9e7486ed8867 (patch) | |
tree | 0bdd21002bc77fe724f47278abfaada523da65b2 | |
parent | c086a96b94322de173921ff5d15edc6a2ca82509 (diff) | |
download | mariadb-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.cpp | 245 | ||||
-rw-r--r-- | storage/connect/jdbconn.h | 15 | ||||
-rw-r--r-- | storage/connect/tabjdbc.cpp | 68 | ||||
-rw-r--r-- | storage/connect/tabjdbc.h | 3 |
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 |