SQL是一种强类型语言。也就是说,每个数据项都有一个相关的数据类型,数据类型决定其行为和允许的用法。 LightDB有一个可扩展的类型系统,该系统比其它SQL实现更具通用和灵活。因而,LightDB中大多数类型转换行为是由通用规则来管理的,而不是特定的启发式规则。这种做法允许使用混合类型表达式,即便是其中包含用户定义的类型。
LightDB扫描器/解析器只将词法元素分解成五个基本种类:整数、非整数数字、字符串、标识符、关键字。大多数非数字类型常量首先被分类为字符串。SQL语言定义允许将类型名指定为字符串, 这个机制被LightDB用于保证解析器沿着正确的方向运行。例如,查询:
SELECT text 'Origin' AS "label", point '(0,0)' AS "value"; label | value --------+------- Origin | (0,0) (1 row)
有两个文字常量,类型分别为text
和point
。如果一个串文字没有指定类型,初始将被分配一个占位符类型unknown
,该类型将在下文描述的后续阶段被解析。
在SQL解析器里,有四种基本的SQL结构要求独立的类型转换规则:
LightDB类型系统的大部分建立在一套丰富的函数上。 函数可以有一个或多个参数。由于LightDB允许函数重载, 所以函数名自身并不唯一地标识将要被调用的函数,解析器必须根据提供的参数类型选择正确的函数。
LightDB允许带有前缀(单目)操作符的表达式,也允许中缀(两个参数)操作符。像函数一样,操作符也可以被重载,因此操作符的选择也有同样的问题。
SQL INSERT
和UPDATE
语句将表达式的结果放 入表中。语句中的表达式类型必须和目标列的类型一致(或者可以被转换为一致)。
UNION
、CASE
和相关结构
因为来自一个联合的SELECT
语句中的所有查询结果必须在一个列集中显示,所以每个 SELECT
子句的结果类型必须能相互匹配并被转换成一个统一的集合。类似地,一个 CASE
结构的结果表达式必须被转换成一种公共的类型,这样CASE
表达式作为整体才 有一种已知的输出类型。其他一些结构,例如 ARRAY[]
和 GREATEST
和 LEAST
函数,同样需要确定几个子表达式的公共类型。
系统目录存储有关哪些数据类型之间存在哪种转换(或造型)以及如何执行这些转换的相关信息。额外的造型可以由用户通过CREATE CAST命令增加(这个通常和定义一种新的数据类型一起完成。 内建的类型转换集已经经过了仔细的雕琢,最好不要去更改它们)。
解析器提供了一种额外的启发式规则,它允许在具有隐式造型的类型组中恰当造型行为的改进决定。 数据类型被分为几个基本的类型分类,包括boolean
、numeric
、string
、bitstring
、datetime
、timespan
、geometric
、network
和用户自定义(可参阅Table 50.74中的列表;但需要注意的是 也可以创建自定义的类型分类)。在每个分类中,可以有一个或多个首选类型, 当存在类型选择时,这个是更好的选择。利用精心选择的首选类型和可用的隐式造型, 我们可以确保有歧义的表达式(那些有多个候选解析方案的表达式)可以用一种有用的方式来处理。
所有类型转换规则都是建立在下面几个基本原则上的:
隐式转换决不能有意外的或不可预见的输出。
如果一个查询不需要隐式类型转换,解析器或执行器不应该有额外的开销。也就是说,如果一个查询是结构良好的并且类型已经匹配,则查询不应该在解析器里耗费额外的时间执行,也不会在查询中引入不必要的隐式类型转换调用。
另外,如果一个查询通常要求为某个函数进行隐式类型转换,而用户定义了一个有正确参数类型的新函数, 解析器应该使用新函数并不再做隐式转换来使用旧函数。