我已經創建了一個使用JNI調用Java函數的MySQL UDF。 MS Visual Studio編譯我的代碼沒有任何問題,併爲我的64位MySQL服務器(v.5.5)生成一個DLL。 這裏是C/C++代碼如下所示:
無法安裝MySQL UDF
#ifdef STANDARD
/* STANDARD is defined, don't use any mysql functions */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef __WIN__
typedef unsigned __int64 ulonglong;/* Microsofts 64 bit types */
typedef __int64 longlong;
#else
typedef unsigned long long ulonglong;
typedef long long longlong;
#endif /*__WIN__*/
#else
#include <my_global.h>
#include <my_sys.h>
#if defined(MYSQL_SERVER)
#include <m_string.h>/* To get strmov() */
#else
/* when compiled as standalone */
#include <string.h>
#define strmov(a,b) stpcpy(a,b)
#define bzero(a,b) memset(a,0,b)
#define memcpy_fixed(a,b,c) memcpy(a,b,c)
#endif
#endif
#include <mysql.h>
#include <ctype.h>
#ifdef _WIN32
/* inet_aton needs winsock library */
#pragma comment(lib, "ws2_32")
#endif
#ifdef HAVE_DLOPEN
#if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
static pthread_mutex_t LOCK_hostname;
#endif
#if defined(_WIN32) || defined(_WIN64)
#define DLLEXP __declspec(dllexport)
#else
#define DLLEXP
#endif
#include <jni.h>
DLLEXP my_bool call_java_method_init(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args, char *message);
DLLEXP void call_java_method_deinit(UDF_INIT *initid __attribute__((unused)));
DLLEXP char* call_java_method(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
char* is_null __attribute__((unused)), char* error __attribute__((unused)));
static JNIEnv *env;
static JavaVM *jvm;
JNIEnv* create_vm(JavaVM **jvm) {
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options;
options.optionString = "-Djava.class.path=C:\\JavaApps\\CallJavaFromC++\\bin"; //Path to the java source code
vm_args.version = JNI_VERSION_1_6; //JDK version. This indicates version 1.6
vm_args.nOptions = 1;
vm_args.options = &options;
vm_args.ignoreUnrecognized = 0;
int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);
if(ret < 0)
printf("\nUnable to Launch JVM\n");
return env;
}
my_bool call_java_method_init(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args, char *message)
{
if(!(args->arg_count == 3)) {
char *m = "Expected 3 arguments. Function usage: call_java_method('classPath', 'className', 'methodName(methodArguments)') ";
strcpy_s(message, strlen(m)+1, m);
return 1;
}
env = create_vm(&jvm);
if (env == NULL){
char *m = "Could not load JVM!";
strcpy_s(message, strlen(m)+1, m);
return 1;
}
args->arg_type[0] = STRING_RESULT;
args->arg_type[1] = STRING_RESULT;
args->arg_type[2] = STRING_RESULT;
return 0;
}
void call_java_method_deinit(UDF_INIT *initid __attribute__((unused)))
{
int n = jvm->DestroyJavaVM();
}
char* call_java_method(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
char* is_null __attribute__((unused)), char* error __attribute__((unused)))
{
char* retResult = "";
jclass clsLEC = NULL;
jmethodID callJavaClass = NULL;
jstring jstrcalljava = NULL;
const char *pResult = NULL;
clsLEC = env->FindClass("LoadExternalClass");
if(clsLEC != NULL)
{
callJavaClass = env->GetStaticMethodID(clsLEC,"callJavaClass","([Ljava/lang/String;)Ljava/lang/String;");
}
else
{
printf("\nUnable to find the requested class\n");
}
if(clsLEC != NULL && callJavaClass != NULL)
{
jobjectArray ret= (jobjectArray)env->NewObjectArray(3, env->FindClass("java/lang/String"), env->NewStringUTF(""));
env->SetObjectArrayElement(ret,0,env->NewStringUTF(args->args[0]));
env->SetObjectArrayElement(ret,1,env->NewStringUTF(args->args[1]));
env->SetObjectArrayElement(ret,2,env->NewStringUTF(args->args[2]));
jstrcalljava = (jstring)env->CallStaticObjectMethod(clsLEC,callJavaClass,ret);
pResult = env->GetStringUTFChars(jstrcalljava,0);
retResult = _strdup(pResult);
env->ReleaseStringUTFChars(jstrcalljava,pResult);
}
//Release resources.
return retResult;
}
#endif /* HAVE_DLOPEN */
我已經放棄了MySQLJavaUDF.dll文件到MySQL的插件文件夾。爲了驗證文件是爲64位操作系統編譯的,我使用了一個由stackoverflow成員(How can I test a Windows DLL file to determine if it is 32 bit or 64 bit?)編程的PE Deconstructor。
然後我還通過執行Visual Studios dumpbin/EXPORTS命令來檢查DLL是否包含所有必需的功能。輸出看起來如下,似乎是正確的:
File Type: DLL Section contains the following exports for MySQLJavaUDF.dll 00000000 characteristics 531F74A1 time date stamp Tue Mar 11 21:40:01 2014 0.00 version 1 ordinal base 3 number of functions 3 number of names ordinal hint RVA name 1 0 00001150 [email protected]@[email protected]@PEAUst_udf_a [email protected]@[email protected] = [email protected]@[email protected]@[email protected]@[email protected] Z (char * __cdecl call_java_method(struct st_udf_init *,struct st_udf_args *,cha r *,char *)) 2 1 00001140 [email protected]@[email protected]@@Z = ?ca [email protected]@[email protected]@@Z (void __cdecl call_java_method_dei nit(struct st_udf_init *)) 3 2 000010B0 [email protected]@[email protected]@PEAUst_udf [email protected]@[email protected] = [email protected]@[email protected]@[email protected]@PEA [email protected] (char __cdecl call_java_method_init(struct st_udf_init *,struct st_udf_args *,char *)) Summary 4000 .data 2000 .pdata 9000 .rdata 1000 .reloc 5000 .rsrc 22000 .text
於是我做了通過在MySQL的瀏覽器中鍵入以下命令來安裝UDF的第一次嘗試:
CREATE FUNCTION call_java_method
RETURNS STRING
SONAME 'MySQLJavaUDF.dll';
安裝失敗錯誤1126:
無法打開共享庫「MySQLJavaUDF.dll」(錯誤:126指定的模塊找不到)
所以我已經下載進程監視器,看看安裝DLL時會發生什麼文件爲建議在Monitoring application calls to DLL
原來,找不到jvm.dll。好的,將文件從我的Java 1.6.45 64位安裝文件夾複製到MySQL服務器/ bin文件夾中,再次執行SQL命令並再次得到Procmon有關WINMM.dll文件的「NAME NOT FOUND」結果。沒問題,將有問題的文件從我的Windows/System32目錄複製並粘貼到bin文件夾中。這一次Procmon只報告了「SUCCESS」結果,但現在MySQL抱怨錯誤1127,告訴我它
找不到符號'call_java_method'庫
。 這裏是我卡住,放棄的地方。也許你們中的一位專家對發生了什麼問題有任何想法。我懷疑由於某種原因DLL無法加載JVM。我也認爲將jvm.dll複製到bin文件夾不是正確的方法。
我的系統:
64位Windows 7
MySQL服務器5.5的64位
的Java 45年6月1日64
MS的Visual Studio 2012(使用64位解決方案平臺)
好的解決了它。由於我使用的是C++而不是C,所以我不得不封裝這個代碼塊中的函數** extern「C」{...} **(另請參見[MySQL參考手冊](https://dev.mysql.com) /doc/refman/5.0/en/adding-udf.html))。現在它「發現符號」 – user46726