达梦数据库-学习-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、效率对比
一、环境信息
名称 | 值 |
CPU | 12th 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 位的动态库; |
引用函数名 | 指明函数名>在动态库路径>中对应的函数名; |
USING | USING 子句指明函数的类型,如果是 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 | 达梦自带的转换函数。 |
Hex2AsciiPlSql | PLSQL自定义函数。 |
Hex2Ascii | C外部函数。 |
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]$