dm达梦数据库 创建 YEARWEEK 外部函数

这里写目录标题

  • 数据库环境
  • 创建方式
    • 一、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 外部函数 提供以下两种方案编写:
  1. 方式一:DM 结构化参数

       de_data 函数名(de_args *args)
       {
       	C语言函数实现体;
       }
    

    (1) 返回值类型。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 结构体类型如下:

    struct de_args
    {
    	int        n_args;      //参数个数
        de_data*      args;        //参数列表
    };
    

    (3) < C 语言函数实现体 > C 语言函数对应的函数实现体。

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

      返回类型函数名(参数列表)
      {
      	C语言函数实现体;
      }
    

    (3) 参数说明
    · 返回类型及参数列表中参数的数据类型只支持 int、double(或精度大于 24 的 float)以及 char类型。其中 float 的用法和 double 完全一样;
    参数列表中不支持 out 型参数;
    · 如果参数列表中有 char* 的参数,不必在函数中对其进行释放;为了安全考虑,最好只对其进行只读操作;
    · 如果返回 char类型,返回值必须使用 malloc 申请空间,且必须有结尾 0,不允许直接返回常量或返回参数列表中传入的字符类型参数

  3. 举例创建 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 函数
    dm达梦数据库 创建 YEARWEEK 外部函数_第1张图片

二、JAVA 外部函数

(1)JAVA 外部函数是使用 JAVA 语言编写,在数据库外编译生成的 jar 包,被用户通过 DMSQL 程序调用的函数。
(2)JAVA 外部函数的执行都通过代理 dmagent 工具进行,为了执行 JAVA 外部函数,需要先启动 dmagent 服务。dmagent 执行程序在 DM8 安装目录的 tool/dmagent 子目录下,其使用说明文档可参看该目录下的《readme》文档。
(3)当用户调用 JAVA 外部函数时,服务器操作步骤如下:首先,确定调用(外部函数使用的)jar 包及函数;然后,通知代理进程工作。代理进程装载指定的 jar 包,并在函数执行后将结果返回给服务器。
(4)需要注意的是,进行 JAVA 外部函数调用应 保证当前用户可以运行 JAVA 命令,否则会导致调用失败。

  1. JAVA 外部函数创建
    1.1 语法格式

    CREATE [OR REPLACE] FUNCTION [IF NOT EXISTS] [<模式名>.]<函数名>[(<参数列表>)] 
    RETURN <返回值类型>
    EXTERNAL '' <引用函数名> USING JAVA;
    
  2. 举例说明
    例如,写(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
    

你可能感兴趣的:(#,达梦数据库,DM,数据库,数据库,达梦,dm,外部函数)