如Table 38.8所示,btree 定义了一个必需支持函数和两个可选支持函数。
对于 B-树 操作符族为其提供比较操作符的每一种数据类型组合,都必须提供一个比较支持函数。该函数在 pg_amproc 中注册,支持函数编号为 1,并且 amproclefttype/amprocrighttype 要等于该比较的左右数据类型(也就是与匹配操作符在 pg_amop 中注册时相同的数据类型)。比较函数必须接受两个非空值 A 和 B,并返回一个 int32 值,其值为 < 0、 0 或 > 0,分别对应 A < B、 A = B 或 A > B。不允许返回空值:该数据类型的所有值都必须可比较。示例见 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 这两种帧边界类型的窗口子句(见Section 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。