无法安装 MySQL UDF
Posted
技术标签:
【中文标题】无法安装 MySQL UDF【英文标题】:Cannot install MySQL UDF 【发布时间】:2014-03-12 20:07:01 【问题描述】:我创建了一个使用 JNI 调用 Java 函数的 mysql UDF。 MS Visual Studio 编译我的代码没有任何问题,并为我的 64 位 MySQL 服务器 (v.5.5) 生成一个 DLL。 下面是 C/C++ 代码的样子:
#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 位操作系统编译的,我使用了由 *** 成员 (How can I test a Windows DLL file to determine if it is 32 bit or 64 bit?) 编程的 PE 解构器。然后我还检查了通过执行 Visual Studios dumpbin /EXPORTS 命令,DLL 包含所有必需的功能。输出如下所示,似乎是正确的:
文件类型:DLL 部分包含 MySQLJavaUDF.dll 的以下导出 00000000 个特征 531F74A1 时间日期戳 Tue Mar 11 21:40:01 2014 0.00 版本 1 个序数基数 3个功能 3个名字 序号提示 RVA 名称 1 0 00001150 ?call_java_method@@YAPEADPEAUst_udf_init@@PEAUst_udf_a rgs@@PEAD2@Z = ?call_java_method@@YAPEADPEAUst_udf_init@@PEAUst_udf_args@@PEAD2@ Z (char * __cdecl call_java_method(struct st_udf_init *,struct st_udf_args *,cha r *,char *)) 2 1 00001140 ?call_java_method_deinit@@YAXPEAUst_udf_init@@@Z = ?ca ll_java_method_deinit@@YAXPEAUst_udf_init@@@Z (void __cdecl call_java_method_dei 尼特(结构st_udf_init *)) 3 2 000010B0 ?call_java_method_init@@YADPEAUst_udf_init@@PEAUst_udf _args@@PEAD@Z = ?call_java_method_init@@YADPEAUst_udf_init@@PEAUst_udf_args@@PEA D@Z (char __cdecl call_java_method_init(struct st_udf_init *,struct st_udf_args *,字符 *)) 概括 4000 .数据 2000 .pdata 9000 .rdata 1000 .重新定位 5000 .rsrc 22000.文本然后我第一次尝试通过在 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 Server/bin 文件夹中,再次执行 SQL 命令并再次从 Procmon 获得关于 WINMM.dll的“NAME NOT FOUND”结果> 文件。没问题,将有问题的文件从我的 Windows/System32 目录复制并粘贴到 bin 文件夹中。这次 Procmon 只报告了“SUCCESS”结果,但现在 MySQL 报错 1127,告诉我它Can't find symbol 'call_java_method' in library。 这就是我被卡住并放弃的地方。也许你们中的一位专家对出了什么问题有任何想法。我怀疑 DLL 由于某种原因无法加载 JVM。我也认为将jvm.dll复制到bin文件夹中不是正确的方法。
我的系统:Windows 7 64bitMySQL Server 5.5 64bitJava 1.6.45 64bitMS Visual Studio 2012(使用 x64 解决方案平台)
【问题讨论】:
OK 解决了。由于我使用的是 C++ 而不是 C(另请参见 MySQL Reference Manual),因此我必须将函数封装在此代码块 extern "C" ... 中。现在它“找到了符号” 【参考方案1】:mysql 只能理解类似 C 的函数名称。您显然需要导出此类名称:
#if defined(_WIN32) || defined(_WIN64)
#define DLLEXP extern "C" __declspec(dllexport)
并且以防万一尝试使用标志编译您的 dll,在您的平台上编译 mysql。为此,请使用 mysql 发行版中的 mysql_config
实用程序,如下所示:
mysql_config --cxxflags
因此您将能够定义必要的编译标志。
【讨论】:
以上是关于无法安装 MySQL UDF的主要内容,如果未能解决你的问题,请参考以下文章