2014-03-12 2 views
0

JNI를 사용하여 Java 기능을 호출하는 MySQL UDF를 만들었습니다. MS Visual Studio가 문제없이 내 코드를 컴파일하고 내 64 비트 MySQL 서버 (v.5.5) 용 DLL을 생성합니다. 내가 MySQL의 플러그인 폴더로 MySQLJavaUDF.dll 파일을 삭제 한
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 */ 

: 여기 는 같은 C는/C++ 코드를 보이는 것입니다. 파일이 64 비트 OS 용으로 컴파일되었는지 확인하기 위해 PE Deconstructor을 stackoverflow 멤버 (How can I test a Windows DLL file to determine if it is 32 bit or 64 bit?)가 프로그래밍했습니다.

그럼 Visual Studio dumpbin/EXPORTS 명령을 실행하여 DLL에 필요한 모든 기능이 포함되어 있는지 확인했습니다. 설치가 실패

CREATE FUNCTION call_java_method 
RETURNS STRING 
SONAME 'MySQLJavaUDF.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를 설치하는 최초의 시도를 한 다음과 올바른 것 같다로 출력 본다 오류 1126에 :
공유 라이브러리를 열 수 없습니다 'MySQLJavaUDF.dll':
그래서 나는 DLL을 설치할 때 어떻게되는지 볼 수있는 프로세스 모니터를 다운로드 한 (errno를 126 지정된 모듈을 찾을 수 없습니다.) ~으로 파일하다 게시물에서 제안했습니다 Monitoring application calls to DLL
jvm.dll 찾을 수 없습니다. OK, Java 1.6.45 64 비트 설치 폴더에서 MySQL Server/bin 폴더로 파일을 복사하고 SQL 명령을 다시 실행 한 후 WINMM.dll 파일과 관련하여 Procmon에서 "NAME NOT FOUND"라는 결과를 다시 얻었습니다. 아무런 문제도없고 문제가되는 파일을 복사하여 내 Windows/System32 디렉토리에서 bin 폴더에 붙여 넣습니다. 이번에는 Procmon이 "SUCCESS"결과 만보고했으나 MySQL은 오류 1127을 표시하여이를 알려줍니다.

라이브러리에서 'call_java_method'심볼을 찾을 수 없습니다. 여기 내가 붙어서 포기한 곳입니다. 어쩌면 당신 중 한 전문가가 잘못 될 것에 대한 아이디어를 가지고있을 것입니다. 나는 DLL이 어떤 이유로 JVM을로드 할 수 없다고 생각합니다. 나는 또한 jvm.dll을 bin 폴더에 복사하는 것이 올바른 방법이 아니라고 생각한다.

내 시스템 :
윈도우 7 64 비트
MySQL 서버 5.5 64 비트
자바 1.6.45 64 비트
MS 비주얼 스튜디오 2012 (사용의 x64 솔루션 플랫폼)

+0

확인 해결. 이 코드 블록 내의 함수를 캡슐화해야했습니다 ** extern "C"{...} ** C++가 아닌 C를 사용하고 있기 때문에 ** [MySQL 참조 설명서] (https://dev.mysql.com 참조) /doc/refman/5.0/en/adding-udf.html)). 그리고 이제 그것은 "상징을 발견합니다" – user46726

답변

0

mysql을 함수의 C와 같은 이름 만 이해합니다. 당신은 분명 같은 이름으로 내 보내야합니다 :

#if defined(_WIN32) || defined(_WIN64) 
#define DLLEXP extern "C" __declspec(dllexport) 

그리고 만약을

이 MySQL을이 플랫폼에 컴파일있는 플래그 당신의 DLL을 컴파일하려고합니다.문제는이 같은 MySQL의 분포 mysql_config 유틸리티를 사용하십시오 :
mysql_config --cxxflags 

그래서 당신은 필요한 컴파일 플래그를 정의 할 수 있습니다.