亚信安慧AntDB基于操作符的隐式转换

背景

在新一代信息技术创新应用的大背景下,为了降低用户使用成本、加快改造速度,很多数据库产品都在做Oracle兼容性适配。AntDB作为一款成熟、稳定的国产数据库,高度兼容Oracle语法。本文将主要介绍AntDB数据库基于操作符的隐式转换及其设计原理,包括Oracle兼容模式下基于操作符。

AntDB的类型转换概述

AntDB的类型转换主要分为显示转换和隐式转换。

1、 显示转换

显示转换是指明确地使用类型转换函数将一个数据类型转换成另一个数据类型。在AntDB中使用CAST函数或者使用类型强转(::)进行显示转换。

以下是显示转换地示例:

=# create table tb1(c1 int,c2 varchar,c3 text); CREATE TABLE =# insert into tb1 values (1,‘12’,‘aaaa’); INSERT 0 1 --使用CAST显示转换 =# select CAST(c2 as int) from tb1; c2 ---- 12 (1 row) =# select CAST(c3 as int) from tb1; ERROR: invalid input syntax for type integer: “aaaa” --使用类型强转 =# select c2::int from tb1; c2 ---- 12 (1 row) =# select c3::int from tb1; ERROR: invalid input syntax for type integer: “aaaa”

图1:显示类型转换使用例

2、 隐式转换

隐式转换是指数据库在执行查询时(SQL解析阶段)自动进行的类型转换,而不需要显示指定类型转换函数。在AntDB的SQL解析器中,主要有以下情形需要做隐式类型转换。

1)函数调用

AntDB的大部分类型建立在一套丰富的函数上,函数可以有一个或多个。由于AntDB允许函数重载,所以函数名自身并不唯一地标识需要被调用的函数,解析器必须根据提供的参数类型选择正确的函数。

2)操作符

AntDB支持带有前缀或后缀的一元(单目)操作符表达式,也支持二元(两个参数)操作符。与函数类似,操作符也可以被重载,因此操作符的选择也跟参数类型息息相关。

3)值存储

INSERT和UPDATE语句可以将表达式的结果存放到表中,而表达式结果的类型必须和目标列的类型一致(或者可以被转换成一致)。

4)UNION、CASE和相关结构

因为来自一个联合(UNION)的各个SELECT语句中的查询结果需要汇总到一个列中集中显示,所以每个SELECT子句的结果类型必须能相互匹配并被转换成一个统一的集合。类似的,一个CASE结构包含多个条件表达式,但是输出结果只能是一种类型,因此多个条件表达式必须被转换成一种公共的类型,这样CASE语句作为整体才有一种已知的输出类型。同样的要求也存在于ARRAY[]结构以及GREATEST和LEAST函数中。

AntDB的操作符

AntDB中操作符可以分为一元操作符二元操作符

一元操作符只操作一个操作数,例如正负号、按位取反等。以下是一元操作符的一些示例:

  • 正号(+):返回操作数的正值。
  • 符号(-):返回操作符的负值。
  • 按位取反(~):对操作符的二进制进行按位取反。

二元操作符操作两个操作数,列如加、减、乘、除法,比较操作符等。以下是二元操作符的一些示例:

  • 加法(+):返回两个操作数的和。
  • 减法(-):返回两个操作数的差。
  • 大于(>):比较两个操作数,如果第一个操作数大于第二个操作数,则返回true,否则返回false。
  • 小于(<):比较两个操作数,如果第一个操作数小于第二个操作数,则返回true,否则返回false。

在SQL中操作符的使用是非常常见和重要的,很多数据的计算和筛选都依赖操作符的使用,尤其是二元操作符。

1、 基于操作符的隐式转换

在SQL解析阶段会对操作符表达式进行解析,并选择操作数的类型(如果和原始的操作数类型不一致,就涉及到类型的隐式转换)。因为操作符的功能最终是通过函数实现的,操作数则是函数对应的参数,那么在SQL解析阶段对操作符表达式的解析最根本的目的是根据操作符名称和操作数类型,选择最正确最合适的函数,并将操作数类型转换成函数可以接收的参数类型。

操作符类型选择

1)分别解析操作符的左右表达式(左右输入参数)

解析完将获得左右操作数的类型。

2)从系统表pg_operator中选出要考虑的操作符(模糊匹配)

如果使用了一个不带模式限定的操作符名(常见情况),那么操作符被认为是那些在当前search_path中可见并有匹配的名字和参数个数的操作符;如果指定了模式限定的操作符名,那么只考虑指定模式中的操作符;

如果search_path中不同模式下找到多个有相同参数类型的操作符,那么只考虑最早出现在search_path中的那一个。

3)精确找出一个正好接收输入参数(左右操作数)类型的操作符

如果找到则使用之,否则进行下个步骤寻找最优匹配。

  • 如果一个二元操作符中的一个输入参数是unknown类型,则在精确查找时假设其与另一个参数类型相同。对于涉及两个unknown类型的输入参数或者一个unknwon类型的一元操作符,在这一步将永远找不到一个精确匹配。
  • 如果一个二元操作符中的一个输入参数是unknown类型且另一个是一种域(domain)类型,查找匹配时会看看是否有一个操作符正好在左右两边都接收该域的基类型,如果有则匹配成功。
  • 寻找最优匹配的操作符

如果上面的步骤没有找出一个精确匹配,那么将在候选操作符中选择一个最优匹配的操作符。最优匹配的算法或者原则介绍如下。

  • 抛弃那些输入类型不匹配并且也不能被转换的候选操作符。Unknown类型被假定为可以转换成任何类型。这一步筛选过后如果只剩一个候选操作符,则使用之,否则继续下一步。
  • 如果任何输入参数是一种域(domain)类型,后续所有步骤都将其当做是该域的基类型来处理。这确保在做有歧义的操作符解析时,域的行为与其基类型一致。
  • 遍历所有候选操作符,保留那些输入类型上匹配度最高的作为候选者。匹配度的计算很简单,初始匹配度为0,如果操作符左输入参数类型一致则匹配度+1,如果右输入参数一致则匹配度+1。如果筛选完只剩下一个候选操作符,则使用之,否则继续下一步。
  • 遍历所有候选操作符,根据类型所属分类中首选转换类型找出匹配度最高的候选者。

所谓“类型所属分类中首选转换类型“,其实就是一种类型在进行隐式转换时首选的转换类型。例如,字符串分类(varchar,char,text,name等)中首选的转换类型为text。详细信息可以参考系统表pg_type。

  • 如果左输入参数类型与操作符的左操作数类型一致,或者操作符的左操作数类型是左输入参数类型所属分类中的首选转换类型,匹配度+1;右输入参数匹配度也是如此计算。
  • 如果没有接收首选转换类型的操作符,则保留所有候选操作符。
  • 如果经过本轮筛选只剩下一个候选操作符,则使用之,否则继续下一步。

4)如果有任一输入类型为unknown,尝试为其找到一个类型分类。

如果有任一个候选者对应的参数分类为字符串类别(S),则使用字符串类别(因为unknown类型的文本看上去确实像字符串)。没有候选者接收参数类型属于字符串类别时,检查所有候选操作符接收的参数类型分类是否相同,若相同则选择该类别作为unknwon类型的分类,若不同,就会抛错(因为在没有更多线索的条件下无法做出正确的选择)。

接着找出参数类型是该分类中的首选转换类型的候选操作符,如果没找到则保留所有候选者。

经过本轮筛选,如果只剩下一个候选操作符,则使用之;否则继续下一步。

  • 如果既有unknown输入参数也有已知类型的输入参数,并且所有已知类型的参数类型相同,则假定该unknown参数也是那种类型,并找出哪些候选操作符可以在该unknown参数的位置上接收那种类型。

经过本轮筛选,如果正好只剩一个候选者,则使用之;否则失败。

2、 Oracle兼容模式下的操作符类型选择

Oracle兼容模式下的操作符类型选择整体上套用了非兼容模式下的选择框架,只不过针对Oracle特有的数据类型和操作符追加了一些特殊处理。这里有以下几个重要前提:

  • Oralce兼容模式下的操作符实现函数已实现,且相关元数据追加到pg_operator系统表
  • Oracle兼容模式下特有的数据类型已经实现,且能和非兼容模式下的某个或某些类型可以相互转换。

上述两个前提条件的实现方法和实现原理本文不会详细讨论。接下来本文重点说明实现Oracle兼容模式下的操作符类型选择的实现原理。

1)增加系统表ora_convert,用来存放oracle操作符的参数类型转换规则。

2)在“3.1操作符类型选择“章节的步骤2之前,追加以下处理

如果开启了Oracle兼容模式,那么在ora_convert系统表检索匹配的操作符(根据cvtname和cvtfrom进行匹配检索)。如果找到匹配的记录,则将左右表达式类型转换成cvtto列中对应的类型。

1)接下来的处理与3.1操作符类型选择“章节的步骤基本相同。

总结

隐式转换对用户是透明的,但在数据库内部确是非常重要的,因为这会涉及到SQL的执行效率(例如:不恰当的类型隐转可能使索引失效)。在实现Oracle兼容模式时,最好基于现有的框架进行设计,而不是单独设计一套框架。

关于AntDB数据库

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值