如 表 38.9 中所示,btree 定义了一个必需的支持函数和四个可选的支持函数。五个用户定义的方法是
order对于 btree 算子族提供比较算子的每种数据类型组合,它必须提供一个比较支持函数,在 pg_amproc 中注册,支持函数编号为 1,amproclefttype/amprocrighttype 等于比较的左右数据类型(即与匹配算子在 pg_amop 中注册的相同数据类型)。比较函数必须采用两个非空值 A 和 B,并返回一个 int32 值,该值分别在 A < B、A = B 或 A > B 时为 < 0、0 或 > 0。不允许出现空结果:数据类型的所有值都必须可比较。有关示例,请参见 src/backend/access/nbtree/nbtcompare.c。
如果比较值是可整理的数据类型,则使用标准 PG_GET_COLLATION() 机制将适当的整理 OID 传递给比较支持函数。
sortsupportB 树运算符族可以选择提供在支持函数编号 2 下注册的排序支持函数。这些函数允许以比简单调用比较支持函数更有效的方式实现排序目的的比较。涉及的 API 在 src/include/utils/sortsupport.h 中定义。
in_rangeB 树运算符族可以选择提供在支持函数编号 3 下注册的in_range 支持函数。这些函数在 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 函数,该函数具有类型为 interval 的offset。一个族可以为其任何支持的类型提供 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),错误文本类似于 “窗口函数中无效的前置或后置大小”。(SQL 标准要求这样做,尽管非标准运算符系列可能会选择忽略此限制,因为似乎没有太大的语义必要性。)此要求委托给 in_range 函数,以便核心代码不必理解 “小于零” 对特定数据类型意味着什么。
另一个期望是,如果可行,in_range 函数应避免在 base + offset 或 base - offset 溢出时引发错误。即使该值超出数据类型的范围,也可以确定正确的比较结果。请注意,如果数据类型包含 “无穷大” 或 “NaN” 等概念,则可能需要格外小心以确保 in_range 的结果与运算符系列的正常排序顺序一致。
in_range 函数的结果必须与运算符系列施加的排序顺序一致。确切地说,给定 offset 和 sub 的任何固定值,则
如果 less = true 的 in_range 对某些 val1 和 base 为真,则它必须对具有相同 base 的每个 val2 <= val1 为真。
如果 in_range 与 less = true 对于某些 val1 和 base 为 false,则对于具有相同 base 的每个 val2 >= val1,它都必须为 false。
如果 in_range 与 less = true 对于某些 val 和 base1 为 true,则对于具有相同 val 的每个 base2 >= base1,它都必须为 true。
如果 in_range 与 less = true 对于某些 val 和 base1 为 false,则对于具有相同 val 的每个 base2 <= base1,它都必须为 false。
当 less = false 时,具有反向条件的类似陈述成立。
如果正在排序的类型 (type1) 是可整理的,则将使用标准 PG_GET_COLLATION() 机制将适当的整理 OID 传递给 in_range 函数。
in_range 函数不需要处理 NULL 输入,通常会标记为严格。
equalimageBtree 运算符族可以选择提供 equalimage (“相等暗示图像相等”) 支持函数,在支持函数编号 4 下注册。这些函数允许核心代码确定何时可以安全地应用 btree 重复数据删除优化。目前,仅在构建或重建索引时才调用 equalimage 函数。
equalimage 函数必须具有以下签名
equalimage(opcintypeoid) returns bool
返回值是关于运算符类和排序规则的静态信息。返回 true 指示运算符类的 order 函数仅在 A 和 B 参数在不丢失任何语义信息的情况下可互换时才保证返回 0(“参数相等”)。未注册 equalimage 函数或返回 false 指示不能假设此条件成立。
opcintype 参数是运算符类索引的数据类型的 。这是一种便利,允许在运算符类中重复使用相同的底层 pg_type.oidequalimage 函数。如果 opcintype 是可排序数据类型,则使用标准 PG_GET_COLLATION() 机制将适当的排序规则 OID 传递给 equalimage 函数。
就运算符类而言,返回 true 指示重复数据删除是安全的(或对其 equalimage 函数传递 OID 的排序规则是安全的)。但是,核心代码仅在 每个 索引列都使用注册 equalimage 函数的运算符类,并且每个函数在调用时实际上都返回 true 时才将重复数据删除视为对索引是安全的。
图像相等与简单的按位相等条件 几乎 相同。有一个细微差别:在索引 varlena 数据类型时,由于输入上 TOAST 压缩的不一致应用,两个图像相等数据项的磁盘表示可能不是按位相等的。正式地说,当运算符类的 equalimage 函数返回 true 时,可以安全地假设 datum_image_eq() C 函数将始终与运算符类的 order 函数一致(前提是将相同的排序规则 OID 传递给 equalimage 和 order 函数)。
核心代码从根本上无法根据同一系列中其他运算符类的详细信息推断出多数据类型系列中运算符类的 “相等暗示图像相等” 状态。此外,运算符系列注册跨类型 equalimage 函数是不明智的,尝试这样做会导致错误。这是因为 “相等暗示图像相等” 状态不仅取决于排序/相等语义,而这些语义或多或少是在运算符系列级别定义的。通常,必须单独考虑一个特定数据类型实现的语义。
核心 PostgreSQL 发行版中包含的运算符类遵循的约定是注册一个现成的通用 equalimage 函数。大多数运算符类注册 btequalimage(),它指示重复数据删除无条件安全。可排序数据类型(如 text)的运算符类注册 btvarstrequalimage(),它指示重复数据删除在确定性排序规则下是安全的。第三方扩展的最佳做法是注册自己的自定义函数以保持控制权。
选项B 树运算符系列可以选择提供 options(“运算符类特定选项”)支持函数,在支持函数编号 5 下注册。这些函数定义了一组用户可见的参数,用于控制运算符类的行为。
options 支持函数必须具有签名
options(reloptslocal_relopts *) returns void
该函数传递给 local_relopts 结构的指针,该结构需要使用一组运算符类特定选项填充。可以使用 PG_HAS_OPCLASS_OPTIONS() 和 PG_GET_OPCLASS_OPTIONS() 宏从其他支持函数访问这些选项。
目前,没有 B 树运算符类具有 options 支持函数。B 树不允许像 GiST、SP-GiST、GIN 和 BRIN 那样灵活地表示键。因此,options 在当前 B 树索引访问方法中可能没有太多应用。不过,此支持函数已添加到 B 树中以实现统一性,并且可能会在 PostgreSQL 中 B 树的进一步演变中找到用途。
如果您在文档中看到任何不正确、与您对特定功能的体验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。