这里写目录标题
数据库环境
类型 | 版本 | 官网下载地址 |
---|---|---|
基础环境 | 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; // 创建, msbd为模式 CREATE OR REPLACE FUNCTION "msbd"."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 语言)外部函数:yearWeek_s 用于求当年第几周
windows 环境2.1 第一步,使用 idea 创建新项目 dm_udr_java
2.2 第二步,在 dm_udr_java 项目中,添加包 casic.dm 。
2.3 第三步,在 casic.dm 路径下 创建 App类,内容如下:
public class App { public int yearWeek_s(String date){ try { DateFormat format =new SimpleDateFormat("yyyy-MM-dd"); Date parseDate = format.parse(date); Instant instant = parseDate.toInstant(); ZoneId zoneId = ZoneId.systemDefault(); LocalDate currentDate = instant.atZone(zoneId).toLocalDate(); WeekFields weekFields = WeekFields.of(Locale.getDefault()); int weekNumber = currentDate.get(weekFields.weekOfWeekBasedYear()); String ns = currentDate.getYear()+""+weekNumber; return Integer.parseInt(ns); } catch (ParseException e) { throw new RuntimeException(e); } } }
2.4 第四步,生成 jar 包,如上图 maven 项目生成 jar 包在 target 下
2.5 第五步,在安装目录的 …\bin 中创建一个 external_jar 文件夹,将 dm_udr_java-1.0-SNAPSHOT.jar 拷入其中。
2.6 部署 agent 服务
(1)下载 tomcat 链接: link
(2)修改 tomcat 参数在conf/server.xml中 <Connector port="8080" protocol="HTTP/1.1"... 追加属性字段 maxPostSize="-1"; 修改jvm启动参数, Linux:bin/catalina.sh -> JAVA_OPTS="-server -Djava.library.path=/opt/dmdbms/bin" Windows:bin/catalina.bat -> set java_opts= -server -Djava.library.path=c:\dmdbms\bin 需要配置JAVA 1.8及以上版本的运行时环境
(3)在数据库安装目录下找到 web 文件夹,将 dem_init.sql 导入数据库
(4)在数据库安装目录下找到 web 文件夹,将 dem.war 拷贝到 tomcat 的 webapps 文件夹下,解压后修改 \dem/WEB-INF/db.xml :ip、port、用户名、密码、连接池大小,SSL登录信息等
(5)启动 tomcat
(6)进入数据库安装目录下 tool\dmagent 文件夹,修改 agent.ini 参数 center_url 为 tomcat 的 IP和 端口,然后执行 ./start.bat agent.ini 启动# 注册服务,使用root用户 cd /xxx/tool\dmagent ./service.sh install ......一直回车即可 # 启动服务 systemctl start DmAgentService.service
2.7 创建并使用外部函数。
(1)启动数据库服务器 dmserver,启动 DM 管理工具。
(2)在 DM 管理工具中,创建外部函数 YEARWEEK ,语句如下:
CREATE OR REPLACE FUNCTION yearWeek(a varchar) RETURN int EXTERNAL 'xxx\bin\external_jar\dm_udr_java-1.0-SNAPSHOT.jar' "casic.dm.App.yearWeek_s" USING java;
(3)调用 JAVA 外部函数,语句如下:
select yearWeek('2023-09-12 12'); select yearWeek(NOW());
(4)查看结果,分别为:
202336 202336