Postgres 自定义运算符优先于内置?
Postgres custom operator priority over built in?
我最近写了一篇 blog post 关于为 PostgreSQL 的 JSONB 类型创建自定义减号运算符的文章。
基本上,一个运算符是这样创建的:
CREATE OPERATOR - (
PROCEDURE = jsonb_minus,
LEFTARG = jsonb,
RIGHTARG = jsonb )
但是,正如评论者正确指出的那样,在创建此运算符后,默认的 JSONB - TEXT 不再起作用。此查询导致错误:
SELECT '{"a":1, "b":{"c":123, "d":"test"}}'::jsonb - 'a'
结果 invalid input syntax for type json
。您必须明确地将第二个参数转换为 TEXT 才能使其工作。
删除自定义运算符后,恢复了正常行为,上面的查询给出了所需的结果:{"b": {"c": 123, "d": "test"}}
为什么在未指定显式类型时 Postgres 会尝试通过默认 TEXT 转换为 JSONB?我可以避免这种情况吗?
由于文档中描述的 operator type resolution rules,当您定义运算符时会出现问题。
在您给出的示例中,-
运算符的参数具有类型 jsonb
(左参数)和 unknown
(右参数)。 PostgreSQL 的类型 unknown
是分配给 string literals.
的类型
现在,如果定义了自定义运算符,运算符类型解析会在步骤 2.a 中选择您的运算符。:
Check for an operator accepting exactly the input argument types. If one exists (there can be only one exact match in the set of operators considered), use it.
a. If one argument of a binary operator invocation is of the unknown
type, then assume it is the same type as the other argument for this check. Invocations involving two unknown
inputs, or a unary operator with an unknown
input, will never find a match at this step.
因此,unknown
参数 'a'
将转换为 jsonb
,这会导致您观察到的错误。
我最近写了一篇 blog post 关于为 PostgreSQL 的 JSONB 类型创建自定义减号运算符的文章。
基本上,一个运算符是这样创建的:
CREATE OPERATOR - (
PROCEDURE = jsonb_minus,
LEFTARG = jsonb,
RIGHTARG = jsonb )
但是,正如评论者正确指出的那样,在创建此运算符后,默认的 JSONB - TEXT 不再起作用。此查询导致错误:
SELECT '{"a":1, "b":{"c":123, "d":"test"}}'::jsonb - 'a'
结果 invalid input syntax for type json
。您必须明确地将第二个参数转换为 TEXT 才能使其工作。
删除自定义运算符后,恢复了正常行为,上面的查询给出了所需的结果:{"b": {"c": 123, "d": "test"}}
为什么在未指定显式类型时 Postgres 会尝试通过默认 TEXT 转换为 JSONB?我可以避免这种情况吗?
由于文档中描述的 operator type resolution rules,当您定义运算符时会出现问题。
在您给出的示例中,-
运算符的参数具有类型 jsonb
(左参数)和 unknown
(右参数)。 PostgreSQL 的类型 unknown
是分配给 string literals.
现在,如果定义了自定义运算符,运算符类型解析会在步骤 2.a 中选择您的运算符。:
Check for an operator accepting exactly the input argument types. If one exists (there can be only one exact match in the set of operators considered), use it.
a. If one argument of a binary operator invocation is of the
unknown
type, then assume it is the same type as the other argument for this check. Invocations involving twounknown
inputs, or a unary operator with anunknown
input, will never find a match at this step.
因此,unknown
参数 'a'
将转换为 jsonb
,这会导致您观察到的错误。