南大通用数据库-Gbase-8a-学习-41-获取当前日期的季初日期(CUDF、自带函数嵌套等实现)

目录

一、环境信息

二、C-UDF实现

1、C源码

2、编译成动态库

3、拷贝动态库

4、创建函数

5、查看函数

6、测试验证

三、86版本自带函数嵌套实现

四、95版本自带函数实现

五、二三效率比对

1、测试数据条数

2、对比结果


一、环境信息

名称
CPU Intel(R) Core(TM) i5-1035G1 CPU @ 1.00GHz
操作系统 CentOS Linux release 7.9.2009 (Core)
内存 3G
逻辑核数 2
Gbase8a版本 8.6.2-R43.34.27468a27

二、C-UDF实现

UDF相关知识点可以参考之前的博客:

《南大通用数据库-Gbase-8a-学习-26-UDF自定义函数(C、python外部函数)》

1、C源码

#include 
#include 
#include 
#include 

#define YMD_SPLIT_CHAR    '-'
#define TMS_SPLIT_CHAR    ':'
#define ERROR_STR         "N"
#define MIN_STR_LEN       10
#define MONTH_STR_MAX_LEN 3
#define DAY_STR_MAX_LEN   MONTH_STR_MAX_LEN 
#define MONTH_NUM         12
#define STR_END_CHAR      '\0'
#define LEAP_YEAR_FALG    0
#define N_LEAP_YEAR_FALG  1
#define MAX_RES_LEN       255

gs_bool GetQuarterBegin_init(GB_UDF_INIT *initid, GB_UDF_ARGS *args, char *message)
{
    if (args->arg_count != 1) 
    {
        strcpy(message, "GetQuarterBegin Function Accepts Only One Argument.");
        return 1;
    }
    if (args->arg_type[0] != GB_STRING_RESULT) 
    {
        strcpy(message, "GetQuarterBegin Function Input Parameter Data Type Need String.");
        return 1;
    }
    initid->maybe_null = 1;
    initid->decimals   = 0;
    initid->max_length = MAX_RES_LEN;
    initid->extension  = NULL;
    return 0;
}

char* GetQuarterBegin(GB_UDF_INIT   *initid, 
                      GB_UDF_ARGS   *args,
                      char          *result, 
                      unsigned long *length,
                      char          *is_null, 
                      char          *error)
{
	int  YmVal;                                                              //年、月。
	char TmpStr[MONTH_STR_MAX_LEN];                                          //年、月。
	int  TmpVal;                                                             //日、余数。
	int  LeapYearFlag;                                                       // 0:闰年。1:非闰年。复用。
	int  DayArray[MONTH_NUM]         = {31,28,31,30,31,30,31,31,30,31,30,31};//12个月每月的天数。
	
	if(args->lengths[0] < MIN_STR_LEN)//2023-09-27,最小十个字符。
	{
        strcpy(result, "ErrorLen");
        *length= strlen(result);
        return result;		
	}
	
	if(args->args[0] == NULL)//判断传入参数是否是空值,防止上面的length不准,保险。
	{
        strcpy(result, "ErrorNull");
        *length= strlen(result);
        return result;		
	}
	
	if(args->args[0][4] != YMD_SPLIT_CHAR || args->args[0][7] != YMD_SPLIT_CHAR)//判断年月日分割符是否合法
	{
        strcpy(result, "ErrorSplitChar");
        *length= strlen(result);
        return result;	
	}
	
	//闰年判断合法
    for (LeapYearFlag = 0; LeapYearFlag < 4; LeapYearFlag++)
    {
        if (args->args[0][LeapYearFlag] < '0' || args->args[0][LeapYearFlag] > '9')
        {
            strcpy(result, "ErrorYear");
            *length= strlen(result);
            return result;	
        }
        result[LeapYearFlag] = args->args[0][LeapYearFlag];
    }

	result[4] = STR_END_CHAR;
	YmVal     = atoi(result);//表示年

	if(result[2] == '0' && result[3] == '0')//整百年判断
	{
		TmpVal = YmVal % 400;
		if(TmpVal == 0)//整百年的年份中,能被400整除的是闰年,不能被400整除的是平年。如2000年是闰年,1900年是平年。
		{
			LeapYearFlag = LEAP_YEAR_FALG;
		}
		else
		{
			LeapYearFlag = N_LEAP_YEAR_FALG;
		}
	}
	else//非整百年判断
	{
		TmpVal = YmVal % 4;
		if(TmpVal == 0)//非整百年的年份中,能被4整除的为闰年,不能被4整除的为平年。如2004年就是闰年,2001年平年。
		{
			LeapYearFlag = LEAP_YEAR_FALG;
		}
		else
		{
			LeapYearFlag = N_LEAP_YEAR_FALG;
		}	
	}
	
	//月判断合法
	TmpStr[0] = args->args[0][5];
	TmpStr[1] = args->args[0][6];
	TmpStr[2] = STR_END_CHAR;
	YmVal     = atoi(TmpStr);//表示月

    if(YmVal >= 1 && YmVal <= 12)//1-12
	{
        TmpStr[0] = args->args[0][8];
        TmpStr[1] = args->args[0][9];
        TmpVal    = atoi(TmpStr);//表示日
        //日判断合法
        if (YmVal == 2)
        {
            if (LeapYearFlag == LEAP_YEAR_FALG)
            {
                if (TmpVal != 29)
                {
                    goto DAY_ERROR_FLAG;
                }
            }
            else
            {
                if (TmpVal != 28)
                {
                    goto DAY_ERROR_FLAG;
                }
            }
        }
        else if (TmpVal > DayArray[YmVal - 1] || TmpVal < 1)
        {
            DAY_ERROR_FLAG:
            strcpy(result, "ErrorDay");
            *length= strlen(result);
            return result;	
        }
	}
	else
	{
        strcpy(result, "ErrorMonth");
        *length= strlen(result);
        return result;	
	}

    //拼接返回数据-年
    result[4] = YMD_SPLIT_CHAR;

    //拼接返回数据-月
    if (YmVal <= 3)
    {
        result[5] = '0';
        result[6] = '1';
    }
    else if (YmVal <= 6)
    {
        result[5] = '0';
        result[6] = '4';
    }
    else if (YmVal <= 9)
    {
        result[5] = '0';
        result[6] = '7';
    }
    else
    {
        result[5] = '1';
        result[6] = '0';
    }

    //拼接返回数据-日
    result[7]  = YMD_SPLIT_CHAR;
    result[8]  = '0';
    result[9]  = '1';
    result[10] = STR_END_CHAR;

    *length = MIN_STR_LEN;
    return result;
}

void GetQuarterBegin_deinit(GB_UDF_INIT *initid)
{

}

2、编译成动态库

[gbase@czg2 GetQuarterBegin]$ gcc GetQuarterBegin.c -shared -Wall -Wextra -fpic -O3 -o GetQuarterBegin.so -I /opt/Developer/ComputerLanguageStudy/C/DataStructureTestSrc/PublicFunction/Gbase8a/include/
GetQuarterBegin.c: 在函数‘GetQuarterBegin’中:
GetQuarterBegin.c:37:38: 警告:未使用的参数‘initid’ [-Wunused-parameter]
 char* GetQuarterBegin(GB_UDF_INIT   *initid, 
                                      ^
GetQuarterBegin.c:41:38: 警告:未使用的参数‘is_null’ [-Wunused-parameter]
                       char          *is_null, 
                                      ^
GetQuarterBegin.c:42:38: 警告:未使用的参数‘error’ [-Wunused-parameter]
                       char          *error)
                                      ^
GetQuarterBegin.c: 在函数‘GetQuarterBegin_deinit’中:
GetQuarterBegin.c:188:42: 警告:未使用的参数‘initid’ [-Wunused-parameter]
 void GetQuarterBegin_deinit(GB_UDF_INIT *initid)
                      
                                          ^

未使用参数这个警告不用理会。

3、拷贝动态库

[gbase@czg2 GetQuarterBegin]$ cp GetQuarterBegin.so /opt/gnode/server/lib/gbase/plugin/
[gbase@czg2 GetQuarterBegin]$ cp GetQuarterBegin.so /opt/gcluster/server/lib/gbase/plugin/

我只有一个节点所以只拷贝了两次,一次是gcluster,一次是gnode。如果有多个节点,记得都拷贝一遍。

4、创建函数

gbase> drop function GetQuarterBegin;
Query OK, 0 rows affected (Elapsed: 00:00:00.01)

gbase> create function GetQuarterBegin returns string soname 'GetQuarterBegin.so';
Query OK, 0 rows affected (Elapsed: 00:00:00.02)

5、查看函数

gbase> select * from gbase.func where name = 'GetQuarterBegin'\G;
*************************** 1. row ***************************
    name: GetQuarterBegin                                                 
     ret: 0
      dl: 1fda52aedbef1a748661661895f2f3c71695799660GetQuarterBegin.so                                                                    
    type: function
  engine:                                                                                                                                 
instance:                                                                                                                                 
1 row in set (Elapsed: 00:00:00.01)

ERROR: 
No query specified

6、测试验证

gbase> desc czg.test_udf_2023_09_27;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| data  | varchar(30) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
1 row in set (Elapsed: 00:00:00.00)

gbase> select data,GetQuarterBegin(data) from czg.test_udf_2023_09_27;
+---------------------+-----------------------+
| data                | GetQuarterBegin(data) |
+---------------------+-----------------------+
| 2023-09-27 15:21:00 | 2023-07-01            |
| 2023-09-28          | 2023-07-01            |
| 2023-09-56          | ErrorDay              |
| 2023/09/56          | ErrorSplitChar        |
| 2023-13-56          | ErrorMonth            |
| 99999-12-01         | ErrorSplitChar        |
| 202b-13-56          | ErrorYear             |
+---------------------+-----------------------+
7 rows in set (Elapsed: 00:00:00.00)

三、86版本自带函数嵌套实现

gbase> select data,concat(date_format(LAST_DAY(MAKEDATE(EXTRACT(YEAR FROM data),1) + interval QUARTER(data)*3-3 month),'%Y-%m-'),'01') from czg.test_udf_2023_09_27;
+---------------------+---------------------------------------------------------------------------------------------------------------------+
| data                | concat(date_format(LAST_DAY(MAKEDATE(EXTRACT(YEAR FROM data),1) + interval QUARTER(data)*3-3 month),'%Y-%m-'),'01') |
+---------------------+---------------------------------------------------------------------------------------------------------------------+
| 2023-09-27 15:21:00 | 2023-07-01                                                                                                          |
| 2023-09-28          | 2023-07-01                                                                                                          |
| 2023-09-56          | NULL                                                                                                                |
| 2023/09/56          | NULL                                                                                                                |
| 2023-13-56          | NULL                                                                                                                |
| 99999-12-01         | NULL                                                                                                                |
| 202b-13-56          | NULL                                                                                                                |
+---------------------+---------------------------------------------------------------------------------------------------------------------+
7 rows in set, 5 warnings (Elapsed: 00:00:00.00)

四、95版本自带函数实现

gbase> select date_trunc(quarter,'2023-09-27 16:21:18.52389');
+-------------------------------------------------+
| date_trunc(quarter,'2023-09-27 16:21:18.52389') |
+-------------------------------------------------+
| 2023-07-01 00:00:00                             |
+-------------------------------------------------+
1 row in set (Elapsed: 00:00:00.00)

五、二三效率比对

1、测试数据条数

gbase> select count(*) from czg.test_udf_2023_09_27;
+----------+
| count(*) |
+----------+
|  7340032 |
+----------+
1 row in set (Elapsed: 00:00:00.00)

2、对比结果

[gbase@czg2 ~]$ time gccli -e 'select data,GetQuarterBegin(data) from czg.test_udf_2023_09_27' > 2023_09_27.txt

real    0m5.804s
user    0m2.706s
sys     0m0.477s
[gbase@czg2 ~]$ time gccli -e 'select data,GetQuarterBegin(data) from czg.test_udf_2023_09_27' > 2023_09_27.txt

real    0m5.584s
user    0m2.667s
sys     0m0.489s
[gbase@czg2 ~]$ time gccli -e 'select data,GetQuarterBegin(data) from czg.test_udf_2023_09_27' > 2023_09_27.txt

real    0m5.681s
user    0m2.735s
sys     0m0.479s
[gbase@czg2 ~]$ time gccli -e "select data,concat(date_format(LAST_DAY(MAKEDATE(EXTRACT(YEAR FROM data),1) + interval QUARTER(data)*3-3 month),'%Y-%m-'),'01') from czg.test_udf_2023_09_27" > 2023_09_27.txt

real    0m7.080s
user    0m2.113s
sys     0m0.416s
[gbase@czg2 ~]$ time gccli -e "select data,concat(date_format(LAST_DAY(MAKEDATE(EXTRACT(YEAR FROM data),1) + interval QUARTER(data)*3-3 month),'%Y-%m-'),'01') from czg.test_udf_2023_09_27" > 2023_09_27.txt

real    0m7.023s
user    0m2.156s
sys     0m0.414s
[gbase@czg2 ~]$ time gccli -e "select data,concat(date_format(LAST_DAY(MAKEDATE(EXTRACT(YEAR FROM data),1) + interval QUARTER(data)*3-3 month),'%Y-%m-'),'01') from czg.test_udf_2023_09_27" > 2023_09_27.txt

real    0m7.489s
user    0m2.280s
sys     0m0.443s

此UDF函数大家如果要在生产环境使用,记得多测试测试,如果什么问题,可以留言沟通。

你可能感兴趣的:(#,Gbase-8a-学习,学习,数据库,sql,c语言,dba)