
导读:
在新一代信息技术创新应用的大背景下,为了降低用户使用成本、加快改造速度,很多数据库产品都在做Oracle兼容性适配。AntDB作为一款成熟、稳定的国产数据库,高度兼容Oracle语法。本文将主要介绍AntDB数据库基于操作符的隐式转换及其设计原理,包括Oracle兼容模式下基于操作符的隐式转换。
一、AntDB的类型转换概述
AntDB的类型转换主要分为显示转换和隐式转换。
1. 显示转换
显示转换是指明确地使用类型转换函数将一个数据类型转换成另一个数据类型。在AntDB中使用CAST函数或者使用类型强转(::)进行显示转换。
2. 隐式转换
隐式转换是指数据库在执行查询时(SQL解析阶段)自动进行的类型转换,而不需要显示指定类型转换函数。在AntDB的SQL解析器中,主要有以下情形需要做隐式类型转换。
函数调用
AntDB的大部分类型建立在一套丰富的函数上,函数可以有一个或多个。由于AntDB允许函数重载,所以函数名自身并不唯一地标识需要被调用的函数,解析器必须根据提供的参数类型选择正确的函数。
操作符
AntDB支持带有前缀或后缀的一元(单目)操作符表达式,也支持二元(两个参数)操作符。与函数类似,操作符也可以被重载,因此操作符的选择也跟参数类型息息相关。
值存储
INSERT和UPDATE语句可以将表达式的结果存放到表中,而表达式结果的类型必须和目标列的类型一致(或者可以被转换成一致)。
UNION、CASE和相关结构
因为来自一个联合(UNION)的各个SELECT语句中的查询结果需要汇总到一个列中集中显示,所以每个SELECT子句的结果类型必须能相互匹配并被转换成一个统一的集合。
类似的,一个CASE结构包含多个条件表达式,但是输出结果只能是一种类型,因此多个条件表达式必须被转换成一种公共的类型,这样CASE语句作为整体才有一种已知的输出类型。同样的要求也存在于ARRAY[]结构以及GREATEST和LEAST函数中。
二、操作符
AntDB中操作符可以分为一元操作符和二元操作符。一元操作符只操作一个操作数,例如正负号、按位取反等。
以下是一元操作符的一些示例:
正号(+):返回操作数的正值。
符号(-):返回操作符的负值。
按位取反(~):对操作符的二进制进行按位取反。
二元操作符操作两个操作数,列如加、减、乘、除法,比较操作符等。以下是二元操作符的一些示例:
加法(+):返回两个操作数的和。
减法(-):返回两个操作数的差。
大于(>):比较两个操作数,如果第一个操作数大于第二个操作数,则返回true,否则返回false。
小于(<):比较两个操作数,如果第一个操作数小于第二个操作数,则返回true,否则返回false。
在SQL中操作符的使用是非常常见和重要的,很多数据的计算和筛选都依赖操作符的使用,尤其是二元操作符。
1. 基于操作符的隐式转换
在SQL解析阶段会对操作符表达式进行解析,并选择操作数的类型。因为操作符的功能最终是通过函数实现的,操作数则是函数对应的参数,那么在SQL解析阶段对操作符表达式的解析,最根本的目的是根据操作符名称和操作数类型。选择最正确最合适的函数,并将操作数类型,转换成函数可以接收的参数类型。
(一)操作符类型选择
解析操作符的左右表达式(左右输入参数)
分别解析操作符的左右表达式,解析完成后将获得左右操作数的类型。
从系统表pg_operator中选出要考虑的操作符(模糊匹配)
如果使用了一个不带模式限定的操作符名(常见情况),则操作符被认为是那些在当前search_path中可见并有匹配的名字和参数个数的操作符。
如果指定了模式限定的操作符名,则只考虑指定模式中的操作符。
如果search_path中不同模式下找到多个有相同参数类型的操作符,则只考虑最早出现在search_path中的那一个。
精确找出一个正好接收输入参数(左右操作数)类型的操作符
如果找到,则使用之;否则,进行下一步寻找最优匹配。
处理未知类型(unknown)输入参数的情况
如果一个二元操作符中的一个输入参数是unknown类型,则在精确查找时假设其与另一个参数类型相同。
对于涉及两个unknown类型的输入参数或者一个unknown类型的一元操作符,在这一步将永远找不到一个精确匹配。
如果一个二元操作符中的一个输入参数是unknown类型且另一个是一种域(domain)类型,查找匹配时会看看是否有一个操作符正好在左右两边都接收该域的基类型,如果有则匹配成功。
寻找最优匹配的操作符
如果未找到精确匹配的操作符,将根据以下原则选择最优匹配: ①. 排除不匹配且无法转换的候选操作符,unknown类型视为可转换。 ②. 将域类型视为其基类型。 ③. 选择左右参数类型最匹配的操作符。 ④. 优先考虑首选转换类型。
处理未知类型(unknown)输入参数
尝试为unknown类型找到合适的类型分类,若候选操作符参数类型相同,则假定unknown类型也相同。
最终筛选
若unknown参数与已知参数类型一致,选择能接受该类型的操作符。
3.2 Oracle兼容模式下的操作符类型选择
Oracle兼容模式下的操作符类型选择整体上套用了非兼容模式下的选择框架,只不过针对Oracle特有的数据类型和操作符追加了一些特殊处理。这里有以下几个重要前提:
Oralce兼容模式下的操作符实现函数已实现,且相关元数据追加到pg_operator系统表
Oracle兼容模式下特有的数据类型已经实现,且能和非兼容模式下的某个或某些类型可以相互转换。
上述两个前提条件的实现方法和实现原理本文不会详细讨论。接下来本文重点说明实现Oracle兼容模式下的操作符类型选择的实现原理。
增加系统表ora_convert,用来存放oracle操作符的参数类型转换规则。
在“3.1操作符类型选择“章节的步骤2之前,追加以下处理
如果开启了Oracle兼容模式,那么在ora_convert系统表检索匹配的操作符(根据cvtname和cvtfrom进行匹配检索)。如果找到匹配的记录,则将左右表达式类型转换成cvtto列中对应的类型。
接下来的处理与3.1操作符类型选择“章节的步骤基本相同。
4 总结
隐式转换对用户是透明的,但在数据库内部确是非常重要的,因为这会涉及到SQL的执行效率(例如:不恰当的类型隐转可能使索引失效)。在实现Oracle兼容模式时,最好基于现有的框架进行设计,而不是单独设计一套框架。
配置autocommit=1时,隐式开启事务,每执行一条DML的SQL语句,数据库系统会隐式的自动执行commit逻辑提交事务,不需要用户输入commit执行提交。 配置autocommit=0时,隐式开启事务,随后执行的DML的SQL语句都在同一个事务内,直到用户输入commit执行提交。 用户输入BEGIN/START TRANSACTION,显式开启事务,随后执行的DML的SQL语句都在同一个事务内,直到用户输入commit执行提交。
超时时间配置值不好评估,如果确实有个别应用处理产生的长事务会超过空闲事务超时时间,会影响正常应用流程; 副本数据同步实时性不足,数据丢失风险,如果在在备副本上空闲事务超时时间范围内发生的DDL等待失败,副本数据同步中断;如果在DDL等待成功(DDL等锁时间大于空闲事务超时时间),但备副本同步落后。
如果事务前序的只读查询操作的DML,每执行一条只读查询操作的DML后,系统自动提交; 如果事务执行过写操作的DML,之后的再执行只读查询或写操作的DML,不执行自动提交;






