PostgreSQL7.0手册-程序员手册 -43. 扩展索引接口
省索引.如果不是这样,只需要向 opcdeftype 插入零,而不是插入该数据类型的 oid:
INSERT INTO pg_opclass (opcname, opcdeftype) VALUES ('complex_abs_ops', 0);
因此,现在我们有了一个访问方式和一个操作符表.我们还需要一套操作符;用于定义操作符的过程已经在这份手册的早先部分讨论过了.对这个用于 Btrees 的 complex_abs_ops 操作符表,我们需要的操作符是:
absolute value less-than
absolute value less-than-or-equal
absolute value equal
absolute value greater-than-or-equal
absolute value greater-than
假设实现函数册代码放在文件 PGROOT/src/tutorial/complex.c 里
有一部分代码看起来象:(注意我们在余下的例子中将只展示等号操作符.其他四种操作符都非常相似,请参考 complex.c 或 complex.sql 获取详细信息.)
#define Mag(c) ((c)->x*(c)->x + (c)->y*(c)->y)
bool
complex_abs_eq(Complex *a, Complex *b)
{
double amag = Mag(a), bmag = Mag(b);
return (amag==bmag);
}
我们用下面语句让 Postgres 这样识别这个函数:
CREATE FUNCTION complex_abs_eq(complex, complex)
RETURNS bool
AS 'PGROOT/tutorial/obj/complex.so'
LANGUAGE 'c';
有几个很重要的问题要在这里指出.
首先,请注意定义了用于 complex 的小于,小于或等于,等于,大于或等于和大于操作符.我们可以只有一个命名了的操作符名,(比如 =)并把类型 complex 做为其两个操作数.这种情况下我们没有其它用于 complex 的 = 操作符,但是如果我们要制作一个实用的数据类型,我们可能需要 = 做为用于复数的通用等于操作的操作符.这种情况,我们可能需要使用一些其他操作符名称来命名 complex_abs_eq.
第二,尽管 Postgres 可以处理同名操作符,只要它们的输入数据类型不同.C 只能处理一个具有给出名称的全局过程.因此我们不能把 C 函数命名为象 abs_eq 这样简单的名字.通常在 C 函数名里面包含数据类型名称是一个好习惯,这样就不会和用于其它数据类型的函数冲突.
第三,我们可以制作函数 abs_eq 的 Postgres 名称,依靠 Postgres 通过输入数据类型来与任何其他同名 Postgres 函数区分开.为了令例子简单,我们做的函数在 C 层次和 Postgres 层次都有相同的名称,
最后,请注意这些操作符函数返回布尔值.访问模式依靠这个特性.(令一方面,支持函数返回特定的访问模式的希望值--在这种情况下是一个符号整数.)文件里最终的过程是我们在讨论表 pg_am 里amsupport 字段时提到过的"支持过程".我们稍后将用到这个东西.目前我们暂时忽略它.
现在定义使用它们的操作符:
CREATE OPERATOR = (
leftarg = complex, rightarg = complex,
procedure = complex_abs_eq,
restrict = eqsel, join = eqjoinsel
)
这里的重要问题是过程名称(就是上面定义的 C 函数)和这个关系和联合选择性函数.你应该只使用例子里(参阅 complex.source)的选择性函数.请注意还要有这样的用于小于,等于和大于情况的函数.必须提供这些(函数),否则优化器将无法有效地使用该索引.
下一步是为这些操作符向 pg_amop 关系里面增加条目.要做这些,我们将需要我们刚定义的这些操作符的 oid.我们将从所有操作符中找出接受两个复数的操作符名称,并把它们选出来:
SELECT o.oid AS opoid, o.oprname
INTO TABLE complex_ops_tmp
FROM pg_operator o, pg_type t
WHERE o.oprleft = t.oid and o.oprright = t.oid
and t.typname = 'complex';
opoid | oprname
--------+---------
277963 | +
277970 | <
277971 | <=
277972 | =
277973 | >=
277974 | >
(6 rows)
(同样,一些你的 oid (对象标识)将可以肯定是不同的.)我们感兴趣的操作符是那些 oid(对象标识)在 277970 到 277974 之间的.你得到的值将可能不同,你应该用你得到的值代替上面的数值.我们通过一条 select 语句实现这个目的。
现在我们已经准备好用我们新的操作符表更新 pg_amop 表.在整个讨论中最重要的是在 pg_amop 里操作符是顺序排列的,从小于等于到大于等于.我们用下面方法增加我们需要的实例:
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy)
SELECT am.oid, opcl.oid, c.opoid, 1
FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
WHERE amname = 'btree' AND
opcname = 'complex_abs_ops' AND
c.oprname = '<';
然后添加其他操作符,相应地替换上面第三行的 "1" 和最后一行的 "<"。注意顺序:"小于" 是 1,"小于或等于" 是 2,"等于" 是 3,"大于或等于" 是 4,而 "大于" 是 5。
下一步是注册我们前面在讨论 pg_am 时描述过的"支持过程".支持过程的 oid(对象标识)存放在表 pg_amproc 里,用访问模式的 oid(对象标识)和操作符表 oid(对象标识)做关键字.首先,我们需要在 Postgres 注册函数(还记得我们把实现这个过程的C 代码放在了我们实现操作符过程的文件的底部吗?):
CREATE FUNCTION complex_abs_cmp(complex, complex)
RETURNS int4
AS 'PGROOT/tutorial/obj/complex.so'
LANGUAGE 'c';
SELECT oid, proname FROM pg_proc
WHERE proname = 'complex_abs_cmp';
oid | proname
--------+---
INSERT INTO pg_opclass (opcname, opcdeftype) VALUES ('complex_abs_ops', 0);
因此,现在我们有了一个访问方式和一个操作符表.我们还需要一套操作符;用于定义操作符的过程已经在这份手册的早先部分讨论过了.对这个用于 Btrees 的 complex_abs_ops 操作符表,我们需要的操作符是:
absolute value less-than
absolute value less-than-or-equal
absolute value equal
absolute value greater-than-or-equal
absolute value greater-than
假设实现函数册代码放在文件 PGROOT/src/tutorial/complex.c 里
有一部分代码看起来象:(注意我们在余下的例子中将只展示等号操作符.其他四种操作符都非常相似,请参考 complex.c 或 complex.sql 获取详细信息.)
#define Mag(c) ((c)->x*(c)->x + (c)->y*(c)->y)
bool
complex_abs_eq(Complex *a, Complex *b)
{
double amag = Mag(a), bmag = Mag(b);
return (amag==bmag);
}
我们用下面语句让 Postgres 这样识别这个函数:
CREATE FUNCTION complex_abs_eq(complex, complex)
RETURNS bool
AS 'PGROOT/tutorial/obj/complex.so'
LANGUAGE 'c';
有几个很重要的问题要在这里指出.
首先,请注意定义了用于 complex 的小于,小于或等于,等于,大于或等于和大于操作符.我们可以只有一个命名了的操作符名,(比如 =)并把类型 complex 做为其两个操作数.这种情况下我们没有其它用于 complex 的 = 操作符,但是如果我们要制作一个实用的数据类型,我们可能需要 = 做为用于复数的通用等于操作的操作符.这种情况,我们可能需要使用一些其他操作符名称来命名 complex_abs_eq.
第二,尽管 Postgres 可以处理同名操作符,只要它们的输入数据类型不同.C 只能处理一个具有给出名称的全局过程.因此我们不能把 C 函数命名为象 abs_eq 这样简单的名字.通常在 C 函数名里面包含数据类型名称是一个好习惯,这样就不会和用于其它数据类型的函数冲突.
第三,我们可以制作函数 abs_eq 的 Postgres 名称,依靠 Postgres 通过输入数据类型来与任何其他同名 Postgres 函数区分开.为了令例子简单,我们做的函数在 C 层次和 Postgres 层次都有相同的名称,
最后,请注意这些操作符函数返回布尔值.访问模式依靠这个特性.(令一方面,支持函数返回特定的访问模式的希望值--在这种情况下是一个符号整数.)文件里最终的过程是我们在讨论表 pg_am 里amsupport 字段时提到过的"支持过程".我们稍后将用到这个东西.目前我们暂时忽略它.
现在定义使用它们的操作符:
CREATE OPERATOR = (
leftarg = complex, rightarg = complex,
procedure = complex_abs_eq,
restrict = eqsel, join = eqjoinsel
)
这里的重要问题是过程名称(就是上面定义的 C 函数)和这个关系和联合选择性函数.你应该只使用例子里(参阅 complex.source)的选择性函数.请注意还要有这样的用于小于,等于和大于情况的函数.必须提供这些(函数),否则优化器将无法有效地使用该索引.
下一步是为这些操作符向 pg_amop 关系里面增加条目.要做这些,我们将需要我们刚定义的这些操作符的 oid.我们将从所有操作符中找出接受两个复数的操作符名称,并把它们选出来:
SELECT o.oid AS opoid, o.oprname
INTO TABLE complex_ops_tmp
FROM pg_operator o, pg_type t
WHERE o.oprleft = t.oid and o.oprright = t.oid
and t.typname = 'complex';
opoid | oprname
--------+---------
277963 | +
277970 | <
277971 | <=
277972 | =
277973 | >=
277974 | >
(6 rows)
(同样,一些你的 oid (对象标识)将可以肯定是不同的.)我们感兴趣的操作符是那些 oid(对象标识)在 277970 到 277974 之间的.你得到的值将可能不同,你应该用你得到的值代替上面的数值.我们通过一条 select 语句实现这个目的。
现在我们已经准备好用我们新的操作符表更新 pg_amop 表.在整个讨论中最重要的是在 pg_amop 里操作符是顺序排列的,从小于等于到大于等于.我们用下面方法增加我们需要的实例:
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy)
SELECT am.oid, opcl.oid, c.opoid, 1
FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
WHERE amname = 'btree' AND
opcname = 'complex_abs_ops' AND
c.oprname = '<';
然后添加其他操作符,相应地替换上面第三行的 "1" 和最后一行的 "<"。注意顺序:"小于" 是 1,"小于或等于" 是 2,"等于" 是 3,"大于或等于" 是 4,而 "大于" 是 5。
下一步是注册我们前面在讨论 pg_am 时描述过的"支持过程".支持过程的 oid(对象标识)存放在表 pg_amproc 里,用访问模式的 oid(对象标识)和操作符表 oid(对象标识)做关键字.首先,我们需要在 Postgres 注册函数(还记得我们把实现这个过程的C 代码放在了我们实现操作符过程的文件的底部吗?):
CREATE FUNCTION complex_abs_cmp(complex, complex)
RETURNS int4
AS 'PGROOT/tutorial/obj/complex.so'
LANGUAGE 'c';
SELECT oid, proname FROM pg_proc
WHERE proname = 'complex_abs_cmp';
oid | proname
--------+---

