目录
一、环境信息
二、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 |
UDF相关知识点可以参考之前的博客:
《南大通用数据库-Gbase-8a-学习-26-UDF自定义函数(C、python外部函数)》
#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)
{
}
[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)
^
未使用参数这个警告不用理会。
[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。如果有多个节点,记得都拷贝一遍。
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)
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
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)
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)
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)
gbase> select count(*) from czg.test_udf_2023_09_27;
+----------+
| count(*) |
+----------+
| 7340032 |
+----------+
1 row in set (Elapsed: 00:00:00.00)
[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函数大家如果要在生产环境使用,记得多测试测试,如果什么问题,可以留言沟通。