찾다
데이터 베이스MySQL 튜토리얼MySQL:如何编写UDF_MySQL

bitsCN.com

 

1.什么是UDF

UDF顾名思义,就是User defined Function,用户定义函数。我们知道,MySQL本身支持很多内建的函数,此外还可以通过创建存储方法来定义函数。UDF为用户提供了一种更高效的方式来创建函数。

 

UDF与普通函数类似,有参数,也有输出。分为两种类型:单次调用型和聚集函数。前者能够针对每一行数据进行处理,后者则用于处理Group By这样的情况。

 

2.为什么用UDF

既然MySQL本身提供了大量的函数,并且也支持定义函数,为什么我们还需要UDF呢?这主要基于以下几点:

1)UDF的兼容性很好,这得益于MySQL的UDF基本上没有变动

2)比存储方法具有更高的执行效率,并支持聚集函数

3)相比修改代码增加函数,更加方便简单

 

当然UDF也是有缺点的,这是因为UDF也处于mysqld的内存空间中,不谨慎的内存使用很容易导致mysqld crash掉。

 

3.如何编写UDF

UDF的API包括

name_init():

在执行SQL之前会被调用,主要做一些初始化的工作,比如分配后续用到的内存、初始化变量、检查参数是否合法等。

 

name_deinit()

在执行完SQL后调用,大多用于内存清理等工作。init和deinit这两个函数都是可选的

 

name()

UDF的主要处理函数,当为单次调用型时,可以处理每一行的数据;当为聚集函数时,则返回Group by后的聚集结果。

 

name_add()

在每个分组中每行调用

 

name_clear()

在每个分组之后调用

 

为了便于理解,这里给出两种UDF类型的API调用图:

 

 /

下面将就上述几个API进行详细的讲解:

 

1). name_init

原型:

my_boolname_init(UDF_INIT *initid, UDF_ARGS *args, char *message)

UDF_INIT结构体如下:

 

字段

类型

描述

maybe_null

my_bool

如果为1表示该UDF可以返回NULL

decimals

unsigned int

返回值为实数时,表示精度,范围0~30

max_length

unsigned long

对于返回值为INTEGER类型值为21,对于REAL类型值为17,对于字符串类型,存储函数最长参数的长度

ptr

char*

额外的指针,我们可以在这里分配内存。通过initd传递给其他API

const_item

my_bool

为1表示函数总是返回相同的值

extension

void*

用于扩展?

 

UDF_ARGS结构体如下:

字段

类型

描述

arg_count

unsigned int

参数个数

arg_type

enum Item_result*

参数类型数组,记录每一个参数的类型,可以是STRING_RESULT、REAL_RESULT、INT_RESULT以及DECIMAL_RESULT

args

char **

同样是一个数组,用于存储实际数据。

STRING_RESULT与DECIMAL_RESULT类型为char*,INT_RESULT类型为long long*,REAL_RESULT类型为double*,或者一个NULL指针

lengths

unsigned long*

数组,用于存储每一个参数的长度

maybe_null

char *

该数组用于表明每个参数是否可以为NULL,例如

attributes

char **

每个参数的名字

attribute_lengths

unsigned long*

每个参数名字的长度

extension

void*

用于扩展?

 

Message:用于打印错误信息,该指针本身提供长度为MYSQL_ERRMSG_SIZE,来存储信息;

2).name_deinit

原型:

void name_deinit(UDF_INIT*initid)

该函数会进行一些内存释放和清理的工作,在之前我们提到initid->ptr,我们可以在该区域·进行内存的动态分配,这里就可以直接进行内存释放。

 

3).name()

原型:针对不同的返回值类型,有不同的函数原型:

返回值类型

函数原型

STRING or DECIMAL

char *name(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)

INTEGER

long long name(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)

REAL

double name(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error);

 

当返回值为STRING类型时,参数result开辟一个buffer来存储返回值,但不超过766字节,在length参数中存储了字符串的长度。

每个函数原型还包括了is_null和error参数,当*is_null被设置为1时,返回值为NULL,设置*error为1,表明发生了错误。

 

4).name_add()和name_clear()

原型:

void name_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null,char *error)

void name_clear(UDF_INIT *initid, char *is_null, char *error)

对于聚合类型的UDF,name_addd和name_clear会被反复调用。

 

 

4. 两个例子

下面将举两个简单的例子,一个单次调用型函数,一个聚集类型函数,来描述写一个UDF的过程。

 

1)接受一个参数,并返回该参数的值

//初始化

 

 

my_booludf_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message) 

    if (args->arg_count != 1){             //检查参数个数 

        strcpy(message, 

                "udf_intexample() can onlyaccept one argument"); 

        return 1; 

    }   

  

    if (args->arg_type[0] != INT_RESULT){   //检查参数类型 

        strcpy(message, 

                "udf_intexample() argumenthas to be an integer"); 

        return 1; 

    }   

    

    return 0; 

 

 

//清理操作

 

voidudf_int_deinit(UDF_INIT  *initid) 

  

 

 

//主函数

 

long long udf_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) 

    

    long long num = (*(long long *)args->args[0]);   //获取第一个参数值 

    

    return num; 

 

 

 

2)接受一个浮点数类型的参数,并对每个分组进行求和

 

 

//初始化 

my_booludf_floatsum_init(UDF_INIT *initid, UDF_ARGS *args, char *message) 

    double *total = (double *) malloc (sizeof(double)); 

  

    if (total == NULL){                  //内存分配失败 

        strcpy(message,"udf_floatsum:alloc mem failed!"); 

        return 1; 

    } 

  

    *total = 0; 

    initid->ptr = (char *)total; 

  

    if (args->arg_count != 1){            //检查参数个数 

        strcpy(message, "too moreargs,only one!"); 

        return 1; 

    } 

  

    if (args->arg_type[0] != REAL_RESULT){  //检查参数类型 

        strcpy(message, "wrongtype"); 

        return 1; 

    } 

  

    initid->decimals = 3;         //设置返回值精度 

    return 0; 

 

 

 

//清理、释放在init函数中分配的内存

 

voidudf_floatsum_deinit(UDF_INIT *initid) 

    free(initid->ptr); 

 

 

 

//每一行都会调用到该函数

 

voidudf_floatsum_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) 

    double* float_total; 

    float_total = (double*)initid->ptr; 

  

    if (args->args[0]) 

        *float_total += *(double*)args->args[0]; 

  

 

 

 

//每个分组完成后,返回结果

 

doubleudf_floatsum(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) 

    double* float_total; 

    float_total = (double *)initid->ptr; 

    return *float_total; 

 

 

 

//在进行下一个分组前调用,设置initid->ptr指向的值为0,以便下一次分组统计

 

voidudf_floatsum_clear(UDF_INIT *initid, char *is_null, char *error) 

    double *float_total; 

    float_total = (double *)initid->ptr; 

    *float_total = 0; 

  

 

 

3) Mysql-udf-http是一个开源的UDF,可以利用HTTP协议进行REST操作。什么是REST操作呢?REST是一种web service架构风格,其实现基于HTTP协议的四种方法:POST、GET、PUT以及DELETE操作,在mysql-udf-http里分别对应的函数是http_post、http_get()、http_put()、http_delete()。

源码下载:http://curl.haxx.se/download/curl-7.21.1.tar.gz

./configure–prefix={mysql安装目录} –with-mysql=/usr/local/webserver/mysql/bin/mysql_config

Make&& make install

该UDF的实现原理比较简单,主要使用libcurl库函数来实现http协议通信,总共三百多行代码。这里有使用和介绍http://blog.s135.com/mysql-udf-http/

有些比较有趣的功能:

例如,我们可以通过GET方法获取微博中的个人信息,其中1821798401为用户ID

selecthttp_get('http://api.t.sina.com.cn/statuses/user_timeline/1821798401.json?count=1&source=1561596835')

 

UDF具有非常高的自由度,你可以编写你任何想要实现的功能函数,甚至可以引用MySQL内核的代码和变量。

当然,UDF也有着局限性,如下:

a)        在mysql库下必须有func表,并且在‑‑skip‑grant‑tables开启的情况下,UDF会被禁止;

b)        当UDF挂掉时,有可能会导致mysqld crash掉;

c)        所有的UDF的函数必须是线程安全的,如果非要用全局变量,需要加互斥,尽量在name_init中分配资源,并在name_deinit中释放

d)        需要有insert权限

 

作者 zhaiwx1987

bitsCN.com
성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
华为明年将推创新 MED 存储产品:机架容量超过 10 PB,功耗低于 2 kW华为明年将推创新 MED 存储产品:机架容量超过 10 PB,功耗低于 2 kWMar 07, 2024 pm 10:43 PM

本站3月7日消息,华为数据存储产品线总裁周跃峰博士日前出席MWC2024大会,专门展示了为温数据(WarmData)和冷数据(ColdData)设计的新一代OceanStorArctic磁电存储解决方案。华为数据存储产品线总裁周跃峰发布系列创新解决方案图源:华为本站附上华为官方新闻稿内容如下:该方案的成本比磁带低20%,功耗比硬盘低90%。根据国外科技媒体blocksandfiles报道,华为发言人还透露了关于该磁电存储解决方案的信息:华为的磁电磁盘(MED)是对磁存储介质的重大创新。第一代ME

Vue3+TS+Vite开发技巧:如何进行数据加密和存储Vue3+TS+Vite开发技巧:如何进行数据加密和存储Sep 10, 2023 pm 04:51 PM

Vue3+TS+Vite开发技巧:如何进行数据加密和存储随着互联网技术的快速发展,数据的安全性和隐私保护变得越来越重要。在Vue3+TS+Vite开发环境下,如何进行数据加密和存储,是每个开发人员都需要面对的问题。本文将介绍一些常用的数据加密和存储的技巧,帮助开发人员提升应用的安全性和用户体验。一、数据加密前端数据加密前端加密是保护数据安全性的重要一环。常用

如何在 Windows 11 上清理缓存:详细的带图片教程如何在 Windows 11 上清理缓存:详细的带图片教程Apr 24, 2023 pm 09:37 PM

什么是缓存?缓存(发音为ka·shay)是一种专门的高速硬件或软件组件,用于存储经常请求的数据和指令,这些数据和指令又可用于更快地加载网站、应用程序、服务和系统的其他部分。缓存使最常访问的数据随时可用。缓存文件与缓存内存不同。缓存文件是指经常需要的文件,如PNG、图标、徽标、着色器等,多个程序可能需要这些文件。这些文件存储在您的物理驱动器空间中,通常是隐藏的。另一方面,高速缓存内存是一种比主内存和/或RAM更快的内存类型。它极大地减少了数据访问时间,因为与RAM相比,它更靠近CPU并且速度

正确利用sessionStorage保护敏感数据的方法正确利用sessionStorage保护敏感数据的方法Jan 13, 2024 am 11:54 AM

如何正确使用sessionStorage存储敏感信息,需要具体代码示例无论是在Web开发还是移动应用开发中,我们常常需要存储和处理敏感信息,如用户登录凭证、身份证号码等。在前端开发中,使用sessionStorage是一种常见的存储方案。然而,由于sessionStorage是基于浏览器的存储,需要注意一些安全性的问题,以确保存储的敏感信息不被恶意访问和利用

PHP和swoole如何实现高效的数据缓存和存储?PHP和swoole如何实现高效的数据缓存和存储?Jul 23, 2023 pm 04:03 PM

PHP和swoole如何实现高效的数据缓存和存储?概述:在Web应用开发中,数据的缓存和存储是非常重要的一部分。而PHP和swoole提供了一种高效的方法来实现数据的缓存与存储。本文将介绍如何使用PHP和swoole来实现高效的数据缓存和存储,并给出相应的代码示例。一、swoole简介:swoole是一个针对PHP语言开发的,高性能的异步网络通信引擎,它可以

一文读懂人工智能表:从MindsDB说起一文读懂人工智能表:从MindsDB说起Apr 12, 2023 pm 12:04 PM

本文转载自微信公众号「活在信息时代」,作者活在信息时代。转载本文请联系活在信息时代公众号。对于熟悉数据库操作的同学来说,编写优美的SQL语句,从数据库中想方设法找出自己需要的数据,是常规操作了。而对于熟悉机器学习的同学来说,获取数据,对数据进行预处理,建立模型,确定训练集和测试集,用训练好的模型对未来进行一系列的预测,也是一种常规操作了。那么,我们能否将两种技术结合起来呢?我们看到数据库里存储了数据,而进行预测需要基于以往的数据。如果我们通过数据库里现有的数据,对于未来的数据进行查询的话,那么是

使用PHP数组实现数据缓存和存储的方法和技巧使用PHP数组实现数据缓存和存储的方法和技巧Jul 16, 2023 pm 02:33 PM

使用PHP数组实现数据缓存和存储的方法和技巧随着互联网的发展和数据量的急剧增长,数据缓存和存储成为了我们在开发过程中必须要考虑的问题之一。PHP作为一门广泛应用的编程语言,也提供了丰富的方法和技巧来实现数据缓存和存储。其中,使用PHP数组进行数据缓存和存储是一种简单而高效的方法。一、数据缓存数据缓存的目的是为了减少对数据库或其他外部数据源的访问次数,从而提高

Java集合框架全解析:解剖数据结构,揭秘高效存储之道Java集合框架全解析:解剖数据结构,揭秘高效存储之道Feb 23, 2024 am 10:49 AM

Java集合框架概述Java集合框架是Java编程语言的重要组成部分,它提供了一系列可以存储和管理数据的容器类库。这些容器类库具有不同的数据结构,可以满足不同场景下的数据存储和处理需求。集合框架的优势在于它提供了统一的接口,使得开发人员可以使用相同的方式来操作不同的容器类库,从而降低了开发难度。Java集合框架的数据结构Java集合框架中包含多种数据结构,每种数据结构都有其独特的特性和适用场景。下面是几种常见的Java集合框架数据结构:1.List:List是一个有序的集合,它允许元素重复。Li

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

SublimeText3 영어 버전

SublimeText3 영어 버전

권장 사항: Win 버전, 코드 프롬프트 지원!

맨티스BT

맨티스BT

Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

mPDF

mPDF

mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

SublimeText3 Linux 새 버전

SublimeText3 Linux 새 버전

SublimeText3 Linux 최신 버전