63.3. B-树支持函数 #
如表 38.8 所示,B-树定义了一个必需支持函数和两个可选支持函数。
对于 B-树操作符族为其提供比较操作符的每一种数据类型组合,都必须提供一个比较支持函数。该函数在
pg_amproc 中注册,支持函数编号为 1,并且
amproclefttype/amprocrighttype
要等于该比较的左右数据类型(也就是与匹配操作符在
pg_amop 中注册时相同的数据类型)。比较函数必须接受两个非 null 值
A 和 B,并返回一个
int32 值,其值为
< 0、0 或 >
0,分别对应 A
< B、A =
B 或 A
> B。不允许返回 null:该数据类型的所有值都必须可比较。示例见
src/backend/access/nbtree/nbtcompare.c。
如果参与比较的值属于支持排序规则的数据类型,则会通过标准的
PG_GET_COLLATION() 机制,把适当的排序规则 OID
传递给比较支持函数。
可选地,B-树操作符族可以提供排序支持函数,注册为支持函数编号
2。这些函数允许以比朴素地直接调用比较支持函数更高效的方式,实现用于排序的比较。相关
API 定义在
src/include/utils/sortsupport.h 中。
可选地,B-树操作符族可以提供
in_range 支持函数,注册为支持函数编号 3。这些函数不会在 B-树索引操作期间使用;相反,它们会扩展操作符族的语义,使其能够支持包含
RANGE offset
PRECEDING 和 RANGE
offset FOLLOWING
这两种帧边界类型的窗口子句(见第 4.2.8 节)。本质上,它额外提供的信息是:如何以与该族数据排序兼容的方式,对
offset 值进行加减。
in_range 函数必须具有如下签名:
in_range(valtype1,basetype1,offsettype2,subbool,lessbool) returns bool
val 和
base 必须具有相同类型,并且该类型必须是操作符族支持的类型之一(也就是该族为其提供排序的一种类型)。不过,offset
可以是另一种类型,而该类型甚至可能不被该族以其他方式支持。例如,内置的
time_ops 族就提供了一个 in_range
函数,其 offset 的类型为
interval。一个族可以提供 in_range
函数,分别对应其支持的任意类型以及一个或多个
offset 类型。每个
in_range 函数都应在
pg_amproc 中登记,其中
amproclefttype 等于
type1,而
amprocrighttype 等于
type2。
in_range 函数的核心语义取决于这两个布尔标志参数。它应当先对 base 与
offset 做加法或减法,再把
val 与结果比较,具体如下:
如果
!sub且!less,返回val>=(base+offset)如果
!sub且less,返回val<=(base+offset)如果
sub且!less,返回val>=(base-offset)如果
sub且less,返回val<=(base-offset)
在此之前,函数应检查 offset 的符号:如果它小于零,就引发错误
ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE
(22013),错误文本类似于“invalid preceding or following size in window function”。(这是 SQL 标准的要求,尽管非标准操作符族或许会选择忽略这一限制,因为从语义上看似乎并没有太大必要。)把这个要求委托给 in_range
函数,是为了让核心代码无需理解对于某个特定数据类型来说“小于零”究竟意味着什么。
另外还希望 in_range 函数在可行时避免因为
base +
offset 或
base -
offset 会溢出而抛出错误。即便该值会超出该数据类型的取值范围,仍然可以判定正确的比较结果。注意,如果该数据类型包含诸如“infinity”或“NaN”之类的概念,就可能需要格外小心,以确保
in_range 的结果与该操作符族的正常排序顺序一致。
in_range 函数的结果必须与操作符族施加的排序顺序保持一致。更精确地说,给定任意固定的
offset 和
sub 值,则:
如果
in_range在less= true 时,对某个val1和base返回真,那么对于每一个val2<=val1,只要其base相同,它也必须返回真。如果
in_range在less= true 时,对某个val1和base返回假,那么对于每一个val2>=val1,只要其base相同,它也必须返回假。如果
in_range在less= true 时,对某个val和base1返回真,那么对于每一个base2>=base1,只要其val相同,它也必须返回真。如果
in_range在less= true 时,对某个val和base1返回假,那么对于每一个base2<=base1,只要其val相同,它也必须返回假。
当 less = false
时,也有条件相反的对应陈述成立。
如果被排序的类型(type1)属于支持排序规则的数据类型,则会通过标准的
PG_GET_COLLATION() 机制,把适当的排序规则 OID 传递给
in_range 函数。
in_range 函数不必处理 NULL
输入,并且通常会被标记为 strict。