这里写目录标题
- 数据库环境
- 创建方式
- 一、C 外部函数
- 二、JAVA 外部函数
数据库环境
类型 | 版本 | 官网下载地址 |
---|---|---|
基础环境 | Windows 11 | – |
Dm8 | dm8_20230418_x86_win_64.zip | 链接: 官网 |
创建方式
一、C 外部函数
(1)C 外部函数是使用 C、C++ 语言编写,在数据库外编译并保存在.dll、.so 共享库文件中,被用户通过 DMSQL 程序调用的函数。
(2)C 外部函数的执行一般通过代理 dmap 工具进行,此时为了执行 C 外部函数,需要先启动 dmap 服务。dmap 执行程序在 DM8
(3) 安装目录的 bin 子目录下,直接执行即可启动 dmap 服务。 同时,结构化的 C 外部函数支持结合 INI 参数 EFC_USE_AP 进行性能优化,当指定参数值为 0 时,结构化的 C 外部函数会在 dmserver 内部调用,不再和 dmap 进行通信,可以提高函数的执行效率。
(4)当用户调用 C 外部函数时,服务器操作步骤如下:首先,确定调用的(外部函数使用的)共享库及函数;然后,通知代理进程工作。代理进程装载指定的共享库,并在函数执行后将结果返回给服务器。
DM8 C 外部函数 提供以下两种方案编写:
-
方式一:DM 结构化参数
de_data 函数名(de_args *args) { C语言函数实现体; }
(1) <de_data> 返回值类型。de_data 结构体类型如下:
struct de_data{ int null_flag; //参数是否为空,1表示非空,0表示空 union //只支持int、double(或精度大于24的float)、char类型。其中float类型在系统内部被转化为double类型执行,相关接口请使用double类型的接口 { int v_int; double v_double; char v_str[]; }data; };
(2) <de_args> 参数信类型。de_args 结构体类型如下:
struct de_args { int n_args; //参数个数 de_data* args; //参数列表 };
(3) < C 语言函数实现体 > C 语言函数对应的函数实现体。
-
方式二:标量类型参数
(1) 该方案中,用户不必引用 DM 提供的外部函数接口,可以按照标准的 C 风格编码,使用 C 标量类型作为参数类型。使用该方案编写的 C 函数,只能在使用 X86 CPU 的 64 位非 Windows 系统中,被数据库引用作为外部函数。
(2) 结构体返回类型函数名(参数列表) { C语言函数实现体; }
(3) 参数说明
· 返回类型及参数列表中参数的数据类型只支持 int、double(或精度大于 24 的 float)以及 char类型。其中 float 的用法和 double 完全一样;
参数列表中不支持 out 型参数;
· 如果参数列表中有 char* 的参数,不必在函数中对其进行释放;为了安全考虑,最好只对其进行只读操作;
· 如果返回 char类型,返回值必须使用 malloc 申请空间,且必须有结尾 0,不允许直接返回常量或返回参数列表中传入的字符类型参数 -
举例创建 YEARWEEK 函数
3.1 语法格式
CREATE [OR REPLACE] FUNCTION [IF NOT EXISTS] [<模式名>.]<函数名>[(<参数列表>)] RETURN <返回值类型> EXTERNAL '<动态库路径>' [<引用的函数名>] USING < C | CS >;
3.2 新建项目
使用 Microsoft Visual Studio 2010 新建空项目 dm_udr,新建完毕后,若本机操作系统为 x64,因为 VS 默认的解决方案平台不是 x64,需要在解决方案平台下拉框选择“配置管理器-活动方案解决平台-新建-键入或选择新平台-x64”。在 d:\xx\dm_udr\newp 文件夹中,直接拷入 dmde.lib 动态库和 de_pub.h 头文件。dmde.lib 和 de_pub.h 位于dm安装目录 x:…\dmdbms\include 中。3.3 创建函数文件
在源文件创建 dm_main.c 文件,写入以下代码(C 水平有限,大家可自行优化,嘿):#include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #define _CRT_SECURE_NO_WARNINGS #include "newp/de_pub.h" /*! @brief 计算今天是今年的第几周 @param [in] nYear 年 @return uint16_t */ de_data C_YEARWEEK(de_args* args) { de_data de_ret; char* strDate; strDate = de_get_str(args, 0); //提取年月日 /*struct tm stm; strptime(strDate, "%Y-%m-%d %H:%M:%S", &stm);*/ //由于windows下没有strptime函数,可以使用scanf来格式化时间,但是报错 int nYear, nMonth, nday, hour, minute, second; //sscanf(strDate, "%d-%d-%d %d:%d:%d", &nYear, &nMonth, &nday, &hour, &minute, &second); //使用间隔符提取 char blank[2] = " ",yi[2] = "-"; char strDateNew[20]; strcpy(strDateNew, strDate); char* str1 = strtok(strDateNew, blank); char* str2 = strtok(str1, yi); char* str3 = strtok(NULL, yi); char* str4 = strtok(NULL, yi); nYear = atoi(str2); nMonth = atoi(str3); nday = atoi(str4); //free(str1); free(str2); free(str3); free(str4); //计算 int nWeekCnt = 0, nWeekRemain = 0, nCount = 0; switch (nMonth - 1) { case 11: nCount += 30; case 10: nCount += 31; case 9: nCount += 30; case 8: nCount += 31; case 7: nCount += 31; case 6: nCount += 30; case 5: nCount += 31; case 4: nCount += 30; case 3: nCount += 31; case 2: if ((nYear % 4 == 0 && nYear % 100 != 0) || nYear % 400 == 0){ nCount += 29; } else{ nCount += 28; } case 1: nCount += 31; default: break; } //蔡勒公式,周几 int c, y, nWeek; if (nYear == 1 || nMonth == 2){ nYear--; nMonth += 12; } c = nYear / 100; y = nYear - c * 100; nWeek = (c / 4) - 2 * c + (y + y / 4) + (13 * (nMonth + 1) / 5) + nday - 1; while (nWeek < 0) { nWeek += 7; } nWeek %= 7; // 根据当前天数计算属于一年的第几周 nCount += nday; nWeekCnt = (nCount + (7 - nWeek)) / 7; //nWeekRemain = (nCount + (7 - nWeek))%7; //uYearWeek = nWeekCnt + ((nWeekRemain == 0) ? 0 : 1); //uYearWeek = nWeekCnt ; int uYearWeek = nYear * 100 + nWeekCnt; de_ret = de_return_int(uYearWeek); de_str_free(strDate); return de_ret; }
创建 tt.def 文件,写入以下代码(C_YEARWEEK 为函数名):
LIBRARY "tt.dll" EXPORTS C_YEARWEEK
3.4 配置项目属性
右击 dm_udr 项目-属性,点击打开。
在 配置属性—链接器—输入,添加附加依赖项-编辑增加:newp\dmde.lib
在 配置属性—链接器—输入,模块定义文件-编辑增加:tt.def
在 配置属性—高级—字符集:选择使用多字节字符集。
在 配置属性—常规—输出目录:设为 D:\xx\dm_udr
在 配置属性—常规—配置类型:选择动态库(.dll)3.5 生成 dm_udr 项目
右击 dm_udr 项目-生成。得到 D:\xx\dm_udr \dm_udr .dll 文件。
至此,外部函数的使用环境准备完毕。3.6 在达梦创建并使用外部函数
第一步,启动数据库服务器 dmserver、启动 DMAP、启动 DIsql 等服务。
需要先开启系统允许创建外部函数的开关。通过设置 DM.INI 参数 ENABLE_EXTERNAL_CALL=1 开启。打开DM管理工具执行语句如下:SF_SET_SYSTEM_PARA_VALUE('ENABLE_EXTERNAL_CALL',1,0,2); //设置完毕后需重启数据库服务器,参数才能生效
第二步,创建外部函数 YEARWEEK
// 先删除存在的 YEARWEEK 函数 drop function YEARWEEK; // 创建 CREATE OR REPLACE FUNCTION YEARWEEK(A VARCHAR) RETURN int EXTERNAL 'D:\xx\dm_udr\dm_udr.dll' C_YEARWEEK USING C;
第三步,调用 C YEARWEEK 外部函数。语句如下:
select YEARWEEK('2023-08-18 10:03:50'); select YEARWEEK(now());
第四步,查看结果,至此 YEARWEEK 实现完毕,等同于 MySQL 的YEARWEEK 函数
二、JAVA 外部函数
(1)JAVA 外部函数是使用 JAVA 语言编写,在数据库外编译生成的 jar 包,被用户通过 DMSQL 程序调用的函数。
(2)JAVA 外部函数的执行都通过代理 dmagent 工具进行,为了执行 JAVA 外部函数,需要先启动 dmagent 服务。dmagent 执行程序在 DM8 安装目录的 tool/dmagent 子目录下,其使用说明文档可参看该目录下的《readme》文档。
(3)当用户调用 JAVA 外部函数时,服务器操作步骤如下:首先,确定调用(外部函数使用的)jar 包及函数;然后,通知代理进程工作。代理进程装载指定的 jar 包,并在函数执行后将结果返回给服务器。
(4)需要注意的是,进行 JAVA 外部函数调用应 保证当前用户可以运行 JAVA 命令,否则会导致调用失败。
-
JAVA 外部函数创建
1.1 语法格式CREATE [OR REPLACE] FUNCTION [IF NOT EXISTS] [<模式名>.]<函数名>[(<参数列表>)] RETURN <返回值类型> EXTERNAL '<jar包路径>' <引用函数名> USING JAVA;
-
举例说明
例如,写(JAVA 语言)外部函数:testAdd 用于求两个数之和,testStr 用于在一个字符串后面加上 hello。
首先,生成 jar 包。2.1 第一步,使用 eclipse 创建新项目 newp,位于 F:\workspace 文件夹中。
2.2 第二步,在 newp 项目中,添加包。右击 newp,新建(new)一个 package,命名(name)为 com.test.package1。
2.3 第三步,在 package1 包中,添加类文件。右击 src,新建(new)一个 class,命名(name)为 test。Modifiers 选择 public。class 文件内容如下:
package com.test.package1; public class test { public static int testAdd(int a, int b) { return a + b; } public static String testStr(String str) { return str + " hello"; } }
2.4 第四步,生成 jar 包。在 newp 项目中,右击,选中 EXPORT,选择 Java\JAR file,取消.classpath 和.project 的勾选。目标路径 JAR file 设置为:E:\test.jar,然后 finish
2.5 第五步,查看 E 盘中 test.jar。已经存在。
2.6 第六步,在安装目录的…\dmdbms\bin 中创建一个 external_jar 文件夹,将 test.jar 拷入其中。至此,外部函数的使用环境准备完毕。
2.7 创建并使用外部函数。
(1)启动数据库服务器 dmserver,启动 DM 管理工具。
(2)在 DM 管理工具中,创建外部函数 MY_INT 和 MY_chr,语句如下:
CREATE OR REPLACE FUNCTION MY_INT(a int, b int) RETURN int EXTERNAL '..\dmdbms\bin\external_jar\test.jar' "com.test.package1.test.testAdd" USING java; CREATE OR REPLACE FUNCTION MY_chr(s varchar) RETURN varchar EXTERNAL '..\dmdbms\bin\external_jar\test.jar' "com.test.package1.test.testStr" USING java;
(3)调用 JAVA 外部函数,语句如下:
select MY_INT(1,2); select MY_chr('abc');
(4)查看结果,分别为:
3 abc hello