当前位置: 首页 > news >正文

达梦数据库-学习-21-C 外部函数

目录

一、环境信息

二、说点什么

三、介绍

四、参数介绍

五、语法树

六、标量类型参数

七、DM 结构化参数

1、结构体

(1)de_data

(2)de_args

2、函数介绍

(1)de_get_int

(2)de_get_double

(3)de_get_str

(4)de_get_str_with_len

(5)de_set_int

(6)de_get_int

(7)de_set_double

(8)de_set_str

(9)de_set_str_with_len

(10)de_return_int

(11)de_return_double

(12)de_return_str

(13)de_return_str_with_len

(14)de_return_null

(15)de_str_free

(16)de_is_null

八、实验

1、测试数据

2、PLSQL自定义函数

3、C外部函数源码

4、C外部函数编译

5、C外部函数动态库拷贝

6、调整参数

7、重启数据库

8、C外部函数创建

9、验证正确性

10、效率对比


一、环境信息

名称
CPU12th Gen Intel(R) Core(TM) i7-12700H
操作系统CentOS Linux release 7.9.2009 (Core)
内存4G
逻辑核数4
DM版本1          DM Database Server 64 V8
2          DB Version: 0x7000c
3          03134284194-20240703-234060-20108
4          Msg Version: 12
5          Gsu level(5) cnt: 0

二、说点什么

工作中我们有时会遇到一个简单的查询,上面嵌套了一个用户自定义的PLSQL编写的函数,去掉此函数非常快,加上就效率堪忧,需要我们去优化,这时C外部函数就是一个好的选择,或者做ORACLE到信创数据库的迁移,有些函数用户是用C外部函数实现的,需要我们去改写成信创数据库的C外部函数,今天我们就来介绍一下达梦C外部函数如何编写。

三、介绍

C 外部函数是使用 C、C++语言编写,在数据库外编译并保存在.dll、.so 共享库文件 中,被用户通过 DMSQL 程序调用的函数。

C 外部函数的执行一般通过代理 dmap 工具进行,此时为了执行 C 外部函数,需要先 启动 dmap 服务。dmap 执行程序在 DM8 安装目录的 bin 子目录下,直接执行即可启动 dmap 服务。

同时,结构化的 C 外部函数支持结合 INI 参数 EFC_USE_AP 进行性能优化,当指定参 数值为 0 时,结构化的 C 外部函数会在 dmserver 内部调用,不再和 dmap 进行通信,可以提高函数的执行效率。

当用户调用 C 外部函数时,服务器操作步骤如下:首先,确定调用的(外部函数使用的)共享库及函数;然后,通知代理进程工作。代理进程装载指定的共享库,并在函数执行后将结果返回给服务器。

C外部函数分为标量类型参数和DM 结构化参数两种。

四、参数介绍

参数名描述
ENABLE_EXTERNAL_CALL是否允许创建或执行外部函数。
0:不允许;
1:允许;
EFC_USE_AP是否允许结构化的C外部函数在DMSERVER内部执行。
1:表示使用常规DMAP方式通信;
0:表示不使用DMAP,直接在DMSERVER内部调用执行,可以提高函数的执行效率;

五、语法树

CREATE [OR REPLACE] FUNCTION [IF NOT EXISTS] [<模式名>.]<函数名>[(<参数列表>)] 
RETURN <返回值类型> 
EXTERNAL '<动态库路径>' [<引用的函数名>] USING < C | CS >; 
参数名描述
函数名指明被创建的 C 外部函数的名字;
模式名指明被创建的 C 外部函数所属模式的名字,缺省为当前模式名;
参数列表指明 C 外部函数参数信息,如果是使用 DM 结构化参数编写的 C 函 数,参数模式可设置为 IN、OUT 或 IN OUT(OUT IN),缺省为 IN 类型;
使用标量类型参数编写的 C 函数则参数模式只能是 IN 类型。参数类型、个数都应和动态库里定义的一致;
返回值类型必须和动态库里定义的一致;
动态库路径用户按照 DM 规定的 C 语言函数格式编写的 DLL 文件生成的动态库所在的路径;
动态库分为 64 位和 32 位两种,使用的时候要和操作系统一一对应。例如, 64 位的操作系统要用 64 位的动态库;
引用函数名指明函数名>在动态库路径>中对应的函数名;
USINGUSING 子句指明函数的类型,如果是 DM 结构化参数的 C 函数,类型为 C;
标量 类型参数的 C 函数,类型为 CS;

六、标量类型参数

该方案中,用户不必引用 DM 提供的外部函数接口,可以按照标准的 C 风格编码,使 用 C 标量类型作为参数类型。使用该方案编写的 C 函数,只能在使用 X86 CPU 的 64 位非 Windows 系统中,被数据库引用作为外部函数。

例子可以参考之前写的博客《达梦数据库-学习-07-C外部函数创建,及与Plsql自定义函数效率对比》。

七、DM 结构化参数

该方案中,C 用户必须使用 DM8 提供的编写 C 外部函数动态库的接口,严格按照要求格式书写外部函数的 C 代码。

优点在于效率高且适用于各个平台。

1、结构体

(1)de_data

返回值结构体。

typedef struct de_data_struct de_data;
struct de_data_struct
{udint4 null_flag; /*whether is null, 1:not null 0: null*/union	          {sdint4   v_int;ddouble  v_double;de_str   v_str;}data;
};
//只支持 int、double、float、binary_float、char 类型。其中 float 类型在系统内部被转化为 double 类型执行,相关接口请使用 double 类型的接口 

(2)de_args

传入参数结构体。

typedef struct de_args_struct de_args;
struct de_args_struct
{udint4        n_args;       de_data*      args;         
};

2、函数介绍

(1)de_get_int

/*** <p>Function: return the arg_id para as int</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> args: not null</li><li> arg_id: get the id para value, start with 0, not null</li>
* </ul></p>* <p>return val : the arg_id para as int</p>*/
sdint4 
de_get_int(de_args* args, udint4   arg_id
);

第 arg_id 参数的数据类型为整型,从参数列表args中取出第arg_id参数的值。

(2)de_get_double

/*** <p>Function: return the arg_id para as double</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> args: not null</li><li> arg_id: get the id para value,start with 0,not null</li>
* </ul></p>* <p>return val : the arg_id para as double</p>*/
ddouble 
de_get_double(de_args*  args, udint4    arg_id
);

第 arg_id 参数的数据类型为 double 类型,从参数列表 args 中取出第 arg_id 参数的值。

(3)de_get_str

/*** <p>Function: return the arg_id para as string</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> args: not null</li><li> arg_id: get the id para value,start with 0,not null</li>
* </ul></p>* <p>return val : the arg_id para as string</p>*/
udbyte* 
de_get_str(de_args* args, udint4   arg_id
);

第 arg_id 参数的数据类型为字符串类型,从参数列表 args 中取出第 arg_id 参数的值。

(4)de_get_str_with_len

/*** <p>Function: return the arg_id para as string</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> args: not null</li><li> arg_id: get the id para value,start with 0,not null</li><li> alen: return the length of string</li>
* </ul></p>* <p>return val : the arg_id para as string</p>*/
udbyte* 
de_get_str_with_len(de_args*    args, udint4      arg_id, udint4*     alen
);

第 arg_id 参数的数据类型为字符串类型,从参数列表 args 中取出第 arg_id 参数的值以及字符串长度。

(5)de_set_int

/*** <p>Function: set the arg_id para as int</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> args: not null</li><li> arg_id: set the id para value,start with 0,not null</li> 
* </ul></p>* <p>return val: the arg_id para as int</p>*/
void 
de_set_int(de_args*    args, udint4      arg_id, sdint4      ret
);

第 arg_id 参数的数据类型为整型,设置参数列表args的第arg_id参数的值 为 ret。

(6)de_get_int

/*** <p>Function: return the arg_id para as int</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> args: not null</li><li> arg_id: get the id para value, start with 0, not null</li>
* </ul></p>* <p>return val : the arg_id para as int</p>*/
sdint4 
de_get_int(de_args* args, udint4   arg_id
);

第 arg_id 参数的数据类型为整型,从参数列表args中取出第arg_id参数的值。

(7)de_set_double

/*** <p>Function: set the arg_id para as double</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> args: not null</li><li> arg_id: set the id para value,start with 0,not null</li> 
* </ul></p>* <p>return val: the arg_id para as double</p>*/
void 
de_set_double(de_args* args, udint4   arg_id, ddouble  ret
);

第 arg_id 参数的数据类型为 double 类型,设置参数列表 args 的第 arg_id 参数的值为 ret。

(8)de_set_str

/*** <p>Function: set the arg_id para as string</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> args: not null</li><li> arg_id: set the id para value,start with 0,not null</li> <li> ret: the new arg_id para as string,end with '\0'</li>
* </ul></p>* <p>return val: nothing</p>*/
void de_set_str(de_args*    args, udint4      arg_id, udbyte*     ret
);

第 arg_id 参数的数据类型为字符串类 型,设置第 arg_id 参数的值为 ret。

(9)de_set_str_with_len

/*** <p>Function: set the arg_id para as string</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> args: not null</li><li> arg_id: set the id para value,start with 0,not null</li> <li> alen: length of the new string</li><li> ret: the new arg_id para as string,not end with '\0'</li>
* </ul></p>* <p>return val: nothing</p>*/
void 
de_set_str_with_len(de_args*    args, udint4      arg_id, udbyte*     ret, udint4      alen
);

第 arg_id 参数的数据类型为字符串类 型,将字符串 ret 的前 len 个字符赋值给参数列表 args 的第 arg_id 参数。

(10)de_return_int

/*** <p>Function: return the arg_id para as int</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> ret: return the int value</li>
* </ul></p>* <p>return val: int</p>*/
de_data 
de_return_int(sdint4 ret
);

返回值类型为整型。

(11)de_return_double

/*** <p>Function: return the arg_id para as double</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> ret: return the double value</li>
* </ul></p>* <p>return val: double</p>*/
de_data 
de_return_double(ddouble ret
);

返回值类型为 double 型。

(12)de_return_str

/*** <p>Function: return the arg_id para as string</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> ret: return the string value, end with '\0'</li>
* </ul></p>* <p>return val: string</p>*/
de_data
de_return_str(udbyte* ret
);

返回值为字符串类型。

(13)de_return_str_with_len

/*** <p>Function: return the arg_id para as string</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> ret: return the string value, not end with '\0'</li><li> alen: the length of string</li>
* </ul></p>* <p>return val: string</p>*/
de_data 
de_return_str_with_len(udbyte*    ret, udint4     alen
);

返回字符串 ret 的前 len 个字符。

(14)de_return_null

/*** <p>Function: return null</p>* <p>Arthimetic: none</p>* <p>arg list: none<br><ul>
* </ul></p>* <p>return val: none</p>*/
de_data 
de_return_null(); 

返回空值。

(15)de_str_free

/*** <p>Function: free space</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li>str: return the point to the space of the string need free</li> 
* </ul></p>* <p>return val: nothing</p>*/
void 
de_str_free(sdbyte* str
);

调用 de_get_str 函数后,需要调用此 函数释放字符串空间。

(16)de_is_null

/*** <p>Function: whether the args are null</p>* <p>Arthimetic: none</p>* <p>arg list: <br><ul><li> args: not null</li><li> arg_id: set the id para value,start with 0,not null</li>
* </ul></p>* <p>return val: bool</p>*/
udint4 
de_is_null(de_args*  args, udint4    arg_id
);

判断参数列表args的第arg_id个参数 是否为空。

八、实验

我们使用PLSQL自定义函数和C外部函数分别实现16进制字符串转换成ASCII可见字符。

1、测试数据

CREATE USER LZL IDENTIFIED BY qwer1234S;
GRANT DBA TO LZL;
DROP TABLE LZL.TEST_HEX_TO_ASCII;
CREATE TABLE LZL.TEST_HEX_TO_ASCII(HEX VARCHAR2(100));
INSERT INTO LZL.TEST_HEX_TO_ASCII VALUES('4142'),('48656C6C6F'),('434445'),('41427E'),('53554e'),('434445'),('464748');
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
INSERT INTO LZL.TEST_HEX_TO_ASCII SELECT * FROM LZL.TEST_HEX_TO_ASCII;
COMMIT;
SELECT COUNT(*) FROM LZL.TEST_HEX_TO_ASCII; -- 229376

2、PLSQL自定义函数

CREATE OR REPLACE FUNCTION LZL.Hex2AsciiPlSql(Hex in varchar2)
return varchar2
as
DECLARE HexLen   int;TmpStr   char(2);i        int;j        int      := -1;Res      varchar2(4000);StartIdx int      := 1;
BEGINHexLen := lengthb(Hex);-- 数据长度为0if HexLen == 0 then return NULL;end if;-- 因为十六进制数由两个字符组成,判断是否能整除2if HexLen % 2 != 0 then return NULL;end if;   Hex := upper(Hex);HexLen := HexLen / 2;-- 跳过头部的\XSELECT substr(Hex,1,2) INTO TmpStr;if TmpStr = '\X' then StartIdx := 2;j        := 1;end if;for i in StartIdx..HexLen loop j := j + 2;SELECT substr(Hex,j,2) INTO TmpStr;case when TmpStr = '20' then Res := Res || ' ';when TmpStr = '21' then Res := Res || '!';when TmpStr = '22' then Res := Res || '"';when TmpStr = '23' then Res := Res || '#';when TmpStr = '24' then Res := Res || '$';when TmpStr = '25' then Res := Res || '%';when TmpStr = '26' then Res := Res || '&';when TmpStr = '27' then Res := Res || '''';when TmpStr = '28' then Res := Res || '(';when TmpStr = '29' then Res := Res || ')';when TmpStr = '2A' then Res := Res || '*';when TmpStr = '2B' then Res := Res || '+';when TmpStr = '2C' then Res := Res || ',';when TmpStr = '2D' then Res := Res || '-';when TmpStr = '2E' then Res := Res || '.';when TmpStr = '2F' then Res := Res || '/';when TmpStr = '30' then Res := Res || '0';when TmpStr = '31' then Res := Res || '1';when TmpStr = '32' then Res := Res || '2';when TmpStr = '33' then Res := Res || '3';when TmpStr = '34' then Res := Res || '4';when TmpStr = '35' then Res := Res || '5';when TmpStr = '36' then Res := Res || '6';when TmpStr = '37' then Res := Res || '7';when TmpStr = '38' then Res := Res || '8';when TmpStr = '39' then Res := Res || '9';when TmpStr = '3A' then Res := Res || ':';when TmpStr = '3B' then Res := Res || ';';when TmpStr = '3C' then Res := Res || '<';when TmpStr = '3D' then Res := Res || '=';when TmpStr = '3E' then Res := Res || '>';when TmpStr = '3F' then Res := Res || '?';when TmpStr = '40' then Res := Res || '@';when TmpStr = '41' then Res := Res || 'A';when TmpStr = '42' then Res := Res || 'B';when TmpStr = '43' then Res := Res || 'C';when TmpStr = '44' then Res := Res || 'D';when TmpStr = '45' then Res := Res || 'E';when TmpStr = '46' then Res := Res || 'F';when TmpStr = '47' then Res := Res || 'G';when TmpStr = '48' then Res := Res || 'H';when TmpStr = '49' then Res := Res || 'I';when TmpStr = '4A' then Res := Res || 'J';when TmpStr = '4B' then Res := Res || 'K';when TmpStr = '4C' then Res := Res || 'L';when TmpStr = '4D' then Res := Res || 'M';when TmpStr = '4E' then Res := Res || 'N';when TmpStr = '4F' then Res := Res || 'O';when TmpStr = '50' then Res := Res || 'P';when TmpStr = '51' then Res := Res || 'Q';when TmpStr = '52' then Res := Res || 'R';when TmpStr = '53' then Res := Res || 'S';when TmpStr = '54' then Res := Res || 'T';when TmpStr = '55' then Res := Res || 'U';when TmpStr = '56' then Res := Res || 'V';when TmpStr = '57' then Res := Res || 'W';when TmpStr = '58' then Res := Res || 'X';when TmpStr = '59' then Res := Res || 'Y';when TmpStr = '5A' then Res := Res || 'Z';when TmpStr = '5B' then Res := Res || '[';when TmpStr = '5C' then Res := Res || '\\';when TmpStr = '5D' then Res := Res || ']';when TmpStr = '5E' then Res := Res || '^';when TmpStr = '5F' then Res := Res || '_';when TmpStr = '60' then Res := Res || '`';when TmpStr = '61' then Res := Res || 'a';when TmpStr = '62' then Res := Res || 'b';when TmpStr = '63' then Res := Res || 'c';when TmpStr = '64' then Res := Res || 'd';when TmpStr = '65' then Res := Res || 'e';when TmpStr = '66' then Res := Res || 'f';when TmpStr = '67' then Res := Res || 'g';when TmpStr = '68' then Res := Res || 'h';when TmpStr = '69' then Res := Res || 'i';when TmpStr = '6A' then Res := Res || 'j';when TmpStr = '6B' then Res := Res || 'k';when TmpStr = '6C' then Res := Res || 'l';when TmpStr = '6D' then Res := Res || 'm';when TmpStr = '6E' then Res := Res || 'n';when TmpStr = '6F' then Res := Res || 'o';when TmpStr = '70' then Res := Res || 'p';when TmpStr = '71' then Res := Res || 'q';when TmpStr = '72' then Res := Res || 'r';when TmpStr = '73' then Res := Res || 's';when TmpStr = '74' then Res := Res || 't';when TmpStr = '75' then Res := Res || 'u';when TmpStr = '76' then Res := Res || 'v';when TmpStr = '77' then Res := Res || 'w';when TmpStr = '78' then Res := Res || 'x';when TmpStr = '79' then Res := Res || 'y';when TmpStr = '7A' then Res := Res || 'z';when TmpStr = '7B' then Res := Res || '{';when TmpStr = '7C' then Res := Res || '|';when TmpStr = '7D' then Res := Res || '}';when TmpStr = '7E' then Res := Res || '~'; else return NULL;end case;end loop;return Res;
END;

3、C外部函数源码

#include <stdio.h>
#include "de_pub.h"
#include "stdlib.h"de_data Hex2Ascii(de_args *args) 
{ de_data Ret; char    *Hex     = NULL; udint4  HexLen   = 0; char    *Ascii   = NULL; udint4  AsciiLen = 0;udint4  Val      = 0;size_t  HexIdx   = 0;size_t  AsciiIdx = 0;int     RetVal   = 0;if(!de_is_null(args, 0)) { /*从参数列表中取第 0 个参数的值以及长度*/ Hex = (char*)de_get_str_with_len(args, 0, (udint4*)&HexLen); } /*设置返回值的参数为空,为错误情况做准备。*/Ret.null_flag = 0;/*16进制字符串长度为0的情况*/if (HexLen == 0 || Hex == NULL){goto END_PHASE;}/*因为十六进制数由两个字符组成,判断是否能整除2*/if (HexLen % 2 != 0){goto END_PHASE;}/*如果包含\x或0x跳过*/if ((Hex[0] == '\\' || Hex[0] == '0') && (Hex[1] == 'x' || Hex[1] == 'X')){HexIdx    = 1;HexLen   -= 2;/*Ascii只需要存储Hex的一半,因为十六进制数由两个字符组成,对应一个字符。*/HexLen   /= 2;AsciiLen  = HexLen;}else{HexIdx    = 0;HexLen   /= 2;AsciiLen  = HexLen;HexLen--;}Ascii = (char*)malloc(sizeof(char) * AsciiLen); /*内存是否分配成功*/if (Ascii == NULL){goto END_PHASE;}for (; HexIdx <= HexLen; HexIdx++,AsciiIdx++) {/*将两个十六进制字符转换为对应的整数值*/Val = 0;/*需要检查一下是否为合格的十六进制数,两位,第一位0-7、第二位0-9 A-F a-f*/if(Hex[HexIdx * 2] >= '0' && Hex[HexIdx * 2] <= '7'){if((Hex[HexIdx * 2 + 1] >= '0' && Hex[HexIdx * 2 + 1] <= '9') ||(Hex[HexIdx * 2 + 1] >= 'A' && Hex[HexIdx * 2 + 1] <= 'F') ||(Hex[HexIdx * 2 + 1] >= 'a' && Hex[HexIdx * 2 + 1] <= 'f')){}else{goto FREE_MEM_PHASE;}}else{goto FREE_MEM_PHASE;}RetVal = sscanf(&(Hex[HexIdx * 2]), "%2x", &Val);if (RetVal == 0 || RetVal == EOF){goto FREE_MEM_PHASE;}/*将整数值转换为 ASCII 字符并存储在 Ascii 字符串中*/ Ascii[AsciiIdx] = (char)Val;}/*返回字符串*/Ret = de_return_str_with_len((udbyte*)Ascii, AsciiLen); FREE_MEM_PHASE:free(Ascii);Ascii = NULL;END_PHASE:/*调用 get 函数得到字符串之后,需要调用此函数释放字符串空间*/ if(!de_is_null(args, 0)) { de_str_free((sdbyte*)Hex); }return Ret; 
} 

4、C外部函数编译

[root@localhost DmExternalFuncC]# gcc -O3 -Wall -Wextra -Werror -o /opt/Developer/DmExternalFuncC/Libs/libHex2Ascii.so -fPIC -shared /opt/Developer/DmExternalFuncC/Src/Hex2Ascii.c -I /opt/Developer/DmExternalFuncC/Include

5、C外部函数动态库拷贝

[root@localhost DmExternalFuncC]# cp /opt/Developer/DmExternalFuncC/Libs/libHex2Ascii.so /opt/Dm8/ExternalFuncLibs/[root@localhost DmExternalFuncC]# chown -R dmdba:dmdba /opt/Dm8/ExternalFuncLibs/libHex2Ascii.so

6、调整参数

SP_SET_PARA_VALUE(2,'ENABLE_EXTERNAL_CALL',1);
SP_SET_PARA_VALUE(2,'EFC_USE_AP',0);

7、重启数据库

[root@localhost DmExternalFuncC]# systemctl restart DmServiceSingleDb.service

8、C外部函数创建

CREATE OR REPLACE FUNCTION LZL.Hex2Ascii(Hex VARCHAR) 
RETURN VARCHAR 
EXTERNAL '/opt/Dm8/ExternalFuncLibs/libHex2Ascii.so' "Hex2Ascii" USING C; 

9、验证正确性

名称描述
UTL_RAW.CAST_TO_VARCHAR2达梦自带的转换函数。
Hex2AsciiPlSqlPLSQL自定义函数。
Hex2AsciiC外部函数。
SQL> SELECT HEX,UTL_RAW.CAST_TO_VARCHAR2(HEX),LZL.Hex2AsciiPlSql(HEX),LZL.Hex2Ascii(HEX) FROM LZL.TEST_HEX_TO_ASCII LIMIT 7;行号     HEX        UTL_RAW.CAST_TO_VARCHAR2(HEX) LZL.HEX2ASCIIPLSQL(HEX) LZL.HEX2ASCII(HEX)
---------- ---------- ----------------------------- ----------------------- ------------------
1          4142       AB                            AB                      AB
2          48656C6C6F Hello                         Hello                   Hello
3          434445     CDE                           CDE                     CDE
4          41427E     AB~                           AB~                     AB~
5          53554e     SUN                           SUN                     SUN
6          434445     CDE                           CDE                     CDE
7          464748     FGH                           FGH                     FGH7 rows got

10、效率对比

[dmdba@localhost Dm8]$ time disql SYSDBA/qwer1234S@localhost:5236 -e "SELECT LZL.Hex2Ascii(HEX) FROM LZL.TEST_HEX_TO_ASCII;" > /opt/Hex2Ascii.txt
real    0m0.235s
user    0m0.074s
sys     0m0.009s
[dmdba@localhost Dm8]$ time disql SYSDBA/qwer1234S@localhost:5236 -e "SELECT UTL_RAW.CAST_TO_VARCHAR2(HEX) FROM LZL.TEST_HEX_TO_ASCII;" > /opt/Hex2Ascii.txtreal    0m0.575s
user    0m0.087s
sys     0m0.018s
[dmdba@localhost Dm8]$ time disql SYSDBA/qwer1234S@localhost:5236 -e "SELECT LZL.Hex2AsciiPlSql(HEX) FROM LZL.TEST_HEX_TO_ASCII;" > /opt/Hex2Ascii.txtreal    0m6.345s
user    0m0.078s
sys     0m0.015s
[dmdba@localhost Dm8]$ 

相关文章:

  • 怎么判断一个Android APP使用了Cordova这个跨端框架
  • ubuntu设置开机不输密码笔记
  • 《STL--- vector的使用及其底层实现》
  • 会话管理有哪些
  • 【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之3D高斯椭球
  • 【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之协方差矩阵控制椭球
  • JavaScript篇:解密ES6的“藏宝图“:Set和Map的奇妙冒险
  • 基于注解的Sentinel限流熔断
  • Sentinel+OpenFeign实现服务熔断与降级:构建弹性微服务架构的核心实践
  • PET,Prompt Tuning,P Tuning,Lora,Qlora 大模型微调的简介
  • PyQt5安装,在Pycharm上配置以及使用教程
  • spring注解旁路问题讨论
  • Wkhtmltopdf使用
  • 端到端大语言模型微调技术 Demo 全流程详解(附完整模块说明)
  • 飞书知识问答产品测评:让企业玩转AI
  • C# TCP协议全面指南:从可靠传输到企业级高并发的深度实践​
  • 职业规划:动态迭代的系统化路径
  • C# Windows Forms应用程序-001
  • Win/Linux安装flash attention2
  • 医学人工智能中的分层处理与跨模态融合:深度架构设计研究(基础教程.下)
  • 苏州响应式网站建设/2023最火的十大新闻
  • 淮南今日头条新闻/河南平价的seo整站优化定制
  • 专门做选择题的网站/seo舆情优化
  • 网站推广营销策划方案/seo快速排名软件品牌
  • 吴江建设局网站打不开了/动态网站建设
  • 在政务网站建设与管理上的讲话/整合营销传播方案案例