AntDB基于Oracle兼容下的DECODE函数适配

在去'O'大背景下,为了减轻用户去'O'成本以及加快去'O'速度,很多国产数据库厂商都会在数据库产品上做Oracle兼容性适配。AntDB作为一款成熟、稳定的国产数据库,自然也兼容Oracle,并且兼容程度高达95%以上。本文将从Oracle的DECODE函数着手,分析一下AntDB的适配方案。

01

Oracle的DECODE函数简介

  • 语法

图1-1Oracle的DECODE函数语法

  • 功能

DECODE将expr依次与search比较,如果expr与某个search相等,则返回对应的result,如果没有找到相等的search则返回default。如果没有指定default,则返回NULL。

函数含义相当于:

AntDB基于Oracle兼容下的DECODE函数适配

图1-2Oracle的DECODE函数语义

示例如下

AntDB基于Oracle兼容下的DECODE函数适配

图1-3 Oracle的DECODE函数使用例

02

AntDB适配方案

Oracle的DECODE函数功能和AntDB的CASE表达式的功能非常相似,而AntDB也确实利用CASE表达式适配了DECODE函数的功能。

AntDB的CASE表达式

  • 语法1

AntDB基于Oracle兼容下的DECODE函数适配

图2-1 AntDB的CASE表达式语法1

  • 功能1

CASE子句可以用于任何表达式可以出现的地方。每一个condition是一个返回boolean结果的表达式。如果结果为真,那么CASE表达式的结果就是符合条件的result,并且剩下的CASE表达式不会被处理。如果条件的结果不为真,那么以相同方式搜寻任何随后的WHEN子句。如果没有WHEN condition为真,那么CASE表达式的结果就是ELSE子句里的result。如果省略了ELSE子句而且没有条件为真,则CASE表达式结果为空。

  • 示例1

AntDB基于Oracle兼容下的DECODE函数适配

图2-2 AntDB的CASE表达式使用例1

  • 语法2

AntDB基于Oracle兼容下的DECODE函数适配

图2-3 AntDB的CASE表达式语法2

  • 功能2

第一个expression会被计算,然后与所有在WHEN子句中的每一个value对比,直到找到一个相等的。如果没有找到匹配的,则返回在ELSE子句中的result(或者空值)。这类似于 C 里的switch语句。

  • 示例2

AntDB基于Oracle兼容下的DECODE函数适配

图2-4 AntDB的CASE表达式使用例2

AntDB利用CASE表达式的语法2,对DECODE函数进行了适配。

03

DECODE函数适配概要

3.1 语法分析阶段

AntDB利用CASE表达式的语法2,对DECODE函数进行了适配,在语法分析时将DECODE函数转换成了CASE表达式。

转换前:

AntDB基于Oracle兼容下的DECODE函数适配

图3-1 语法转换前的DECODE语法

转换后:

AntDB基于Oracle兼容下的DECODE函数适配

图3-2 语法转换后CASE表达式语法

3.2 语义解析阶段

AntDB在对CASE表达式的语义解析阶段,添加了对DECODE函数的一些细节处理。

主要添加了以下2个处理:

1.DECODE函数的expr参数与search参数比较时,选择合适的比较类型

AntDB的CASE表达式选择了expr参数的类型作为与各个search参数比较时使用的类型。

为了与ORACLE的行为一致,AntDB在适配DECODE函数时,选择了第一个search参数的类型作为比较时使用的类型。

2.search参数为空字符串时作为NULL处理

这个是ORACLE的另一个兼容性适配,这里不做详细说明。

04

DECODE函数适配详细

4.1语法分析阶段

语法分析时,将DECODE函数转成CASE表达式。详细请参考以下代码。

代码文件:src/backend/parser/ora_gram.y

AntDB基于Oracle兼容下的DECODE函数适配

图4-1 语法规则中的适配

在函数的语法规则里追加了对decode函数的特殊处理(参考上述代码中的第一个if块):

  • 对decode函数的参数个数进行检查

由于decode函数的最后一个参数可以省略,则参数个数至少为3。少于3个参数则报语法错误。

  • 通过reparsedecodefunc函数将decode函数转成CaseExpr

在说明reparsedecodefunc函数的转换处理之前,先了解下CASE表达式相关的结构体

CASE表达式结构体CaseExpr

AntDB基于Oracle兼容下的DECODE函数适配

图4-2 CaseExpr结构体

CaseExpr结构体成员的说明如下。

-casetype

CASE表达式结果类型,在语义解析时才能知道,语法分析时赋值为InvalidOid。

-casecollid

排序规则的OID,语法层不做处理。

-arg

CASE关键字后面的参数,即DECODE函数的第一个参数expr。

-args

WHEN语句列表。

每个WHEN语句包含对应的search和result参数。

WHEN语句对应的结构体参考如下。

AntDB基于Oracle兼容下的DECODE函数适配

图4-3 CaseWhen结构体

CaseWhen结构体的成员说明如下。

  • expr

条件表达式。

CASE关键字后的参数(expr)与WHEN关键字后的参数(search)是否相等的表达式。

  • result

WHEN语句中search对应的result。

  • location

token的位置信息

-defresult

ELSE关键字后参数,即CASE表达式的默认结果。

-isdecode

标记是否是ORACLE的DECODE函数。

-location

token的位置信息

reparse_decode_func函数的转换处理

先看下该函数的代码:

AntDB基于Oracle兼容下的DECODE函数适配

图4-4 reparse_decode_func函数实现

reparsedecodefunc()函数的参数args是DECODE函数的参数列表,该函数的主要处理逻辑如下:

1.新作成一个CaseExpr节点

2.利用DECODE函数的参数列表,设置CaseExpr的主要成员casetype

语法层赋值为InvalidOid。

  • isdecode

只有ORACLE的DECODE函数才会进reparsedecodefunc(),因此设置为true。

  • arg

设置为DECODE函数的第一个参数expr。

  • args

1)将DECODE函数的每一对search/result参数作成CaseWhen节点设置CaseWhen主要成员:

  • expr

设置为DECODE函数的search参数。

注意:

语法层并没有作成DECODE函数的第一个参数与search参数的等号表达式,后面的语义解析阶段会做这件事。

search参数为NULL时,利用DECODE函数的第一个参数作成IS_NULL表达式,并赋值给CaseWhen的expr成员。

  • result

设置为search参数对应的result参数。

2)将CaseWhen节点追加到args列表

defresult

设置为DECODE函数的最后一个参数。

3.返回CaseExpr节点

4.2 语义解析阶段

AntDB的CASE表达式是通过transformCaseExpr()函数进行解析的。语法分析时ORACLE的DECODE函数被转换成了CASE表达式,因此DECODE函数的语义解析也将通过transformCaseExpr()函数进行解析。

transformCaseExpr函数的主要处理流程(红色部分为DECODE函数适配追加)请参考图4-5。

图4-5 语义解析阶段的处理流程

如图所示,语义解析时,为了与ORACLE的行为一致,AntDB为DECODE函数做了一些细节上的处理。

05

DECODE函数适配详细

经过AntDB适配后的DECODE函数,演示结果如下

AntDB基于Oracle兼容下的DECODE函数适配

图5-1 适配后的结果演示

06

总结

Oracle功能适配时,利用AntDB既有的功能,可能起到事半功倍的效果。当然,熟悉和理解AntDB既有的功能,也是必不可少的技能。

DECODE函数的适配只是Oracle兼容性开发的冰山一角,AntDB在Oracle兼容上有着深厚的积累和独特的优势,想要去'O'的同学,可以试试AntDB。

关于AntDB数据库

AntDB数据库始于2008年,在运营商的核心系统上,为全国24个省份的10亿多用户提供在线服务,具备高性能、弹性扩展、高可靠等产品特性,峰值每秒可处理百万笔通信核心交易,保障系统持续稳定运行近十年,并在通信、金融、交通、能源、物联网等行业成功商用落地。