如何为基本类型(int、real...)重载相等运算符?

How to overload the equality operator for primitive types (int, real...)?

是否可以重载 PostgreSQL 中现有的相等运算符,以给出 intreal 类型的两个值之间相等的新定义?我认为这违反了超载规则,但我想知道是否有办法做到这一点。我试过这个:

CREATE OPERATOR = ( LEFTARG = real ,
                    RIGHTARG = real,
                    PROCEDURE = new_equality,
                    COMMUTATOR = = ,
                    NEGATOR = !=
                  );

CREATE OR REPLACE FUNCTION new_equality (real, real) RETURNS BOOLEAN AS 
$$
SELECT abs ( - ) < 0,2 ;
$$ LANGUAGE PL/PGSQL

但是当我在查询中使用相等运算符时,我没有得到任何结果。
我还尝试将 new_equality() 函数参数定义为我的属性类型,如下所示:

CREATE OR REPLACE FUNCTION new_equality (Student.age%TYPE, Student.age%TYPE) RETURNS BOOLEAN 
AS
$$
SELECT abs ( - ) < 0,2;
$$ lANGUAGE PL/PGSQL

但我收到一条通知,说 Postgres 将它们转换为 real,当我在查询中使用相等运算符时,我仍然没有得到任何结果。

您的代码无效(应该是 LANGUAGE sql),但是您的运算符不会被使用,因为 pg_catalogsearch_path.[=17= 上隐含地排在第一位]

您可以将 search_path 更改为将 pg_catalog 放在其他地方:

SET search_path = public, pg_catalog;

或者您可以显式引用运算符:

SELECT 1::real OPERATOR(public.=) 1.1::real;

Laurenz 指出了眼前的问题 search_path。还有更多。

假设 Postgres 14,这会起作用:

CREATE OR REPLACE FUNCTION public.new_equality (real, real)  -- be explicit about the schema!
  RETURNS bool
  LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE COST 10
BEGIN ATOMIC
SELECT abs( - ) < 0.2;
END;

CREATE OR REPLACE FUNCTION public.new_inequality (real, real)  -- be explicit about the schema!
  RETURNS bool
  LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE COST 10
BEGIN ATOMIC
SELECT abs( - ) >= 0.2;
END;

CREATE OPERATOR public.= (             -- be explicit about the schema!
  LEFTARG    = real
, RIGHTARG   = real
, FUNCTION   = public.new_equality
, COMMUTATOR = OPERATOR(public.=)      -- be explicit about the schema!
, NEGATOR    = OPERATOR(public.!=)     -- must also exist
);

CREATE OPERATOR public.!= (
  LEFTARG    = real
, RIGHTARG   = real
, FUNCTION   = public.new_inequality
, COMMUTATOR = OPERATOR(public.!=)
, NEGATOR    = OPERATOR(public.=)
);

使用 OPERATOR() 构造来调用它:

SELECT id, real '0.1' OPERATOR(public.=) real '0.2';
SELECT id, real '0.1' OPERATOR(public.!=) real '0.2';
SELECT id, real '0.1' OPERATOR(public.<>) real '0.2';

db<>fiddle here - 更多示例

注意 higher operator precedence,可能会在普通运算符不会强制使用括号!

您还必须定义您在声明中提到的NEGATOR。使用 built-in != 将是自相矛盾的废话。创建一个匹配运算符,您必须使用 schema-qualified 语法引用它。 The manual:

To give a schema-qualified operator name in com_op or the other optional arguments, use the OPERATOR() syntax [...]

相关:

  • How to use % operator from the extension pg_trgm?

注意 <>!= 的自动别名,<> 是 SQL.

中的默认不等式运算符

不合格的 = 将是标准的相等运算符 (OPERATOR(pg_catalog.=)),而您不会乱用 search_path 来降级 pg_catalog - 您应该吨!降级 pg_catalog 为各种严重问题打开了大门,因为系统对象现在隐藏在一个或多个其他模式之后。 不要 这样做,除非您确切地知道自己在做什么。关于 search_path:

  • How does the search_path influence identifier resolution and the "current schema"

这假设至少是 Postgres 14。关于 BEGIN ATOMIC:

  • How to implement `BEGIN ATOMIC` in PostgreSQL

使用关键字 FUNCTION 而不是误导性的 PROCEDURE,这对于向后兼容仍然有效。参见:

一样,使用与现有运算符不同的运算符符号可能更方便,以避免冲突。仍将具有比默认比较运算符标准(= 更高)的运算符优先级,并且不能轻易更改。