From 2b5154beab794eae6e624c162d497df927ec9d27 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Fri, 20 Oct 2023 12:28:38 -0400
Subject: Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
---
doc/src/sgml/ref/alter_operator.sgml | 86 +++++++++++++++++++++++++++++++++--
doc/src/sgml/ref/create_operator.sgml | 66 +++++++++++++++++++++++++--
doc/src/sgml/xoper.sgml | 44 ------------------
3 files changed, 144 insertions(+), 52 deletions(-)
(limited to 'doc/src')
diff --git a/doc/src/sgml/ref/alter_operator.sgml b/doc/src/sgml/ref/alter_operator.sgml
index a4a1af564ff..673dcce2f50 100644
--- a/doc/src/sgml/ref/alter_operator.sgml
+++ b/doc/src/sgml/ref/alter_operator.sgml
@@ -30,7 +30,11 @@ ALTER OPERATOR name ( { left_typename ( { left_type | NONE } , right_type )
SET ( { RESTRICT = { res_proc | NONE }
| JOIN = { join_proc | NONE }
- } [, ... ] )
+ | COMMUTATOR = com_op
+ | NEGATOR = neg_op
+ | HASHES
+ | MERGES
+ } [, ... ] )
@@ -121,9 +125,69 @@ ALTER OPERATOR name ( { left_type
+
+ com_op
+
+
+ The commutator of this operator. Can only be changed if the operator
+ does not have an existing commutator.
+
+
+
+
+
+ neg_op
+
+
+ The negator of this operator. Can only be changed if the operator does
+ not have an existing negator.
+
+
+
+
+
+ HASHES
+
+
+ Indicates this operator can support a hash join. Can only be enabled and
+ not disabled.
+
+
+
+
+
+ MERGES
+
+
+ Indicates this operator can support a merge join. Can only be enabled
+ and not disabled.
+
+
+
+
+
+ Notes
+
+
+ Refer to and
+ for further information.
+
+
+
+ Since commutators come in pairs that are commutators of each other,
+ ALTER OPERATOR SET COMMUTATOR will also set the
+ commutator of the com_op
+ to be the target operator. Likewise, ALTER OPERATOR SET
+ NEGATOR will also set the negator of
+ the neg_op to be the
+ target operator. Therefore, you must own the commutator or negator
+ operator as well as the target operator.
+
+
+
Examples
@@ -131,13 +195,25 @@ ALTER OPERATOR name ( { left_typea @@ b for type text:
ALTER OPERATOR @@ (text, text) OWNER TO joe;
-
+
+
- Change the restriction and join selectivity estimator functions of a custom operator a && b for type int[]:
+ Change the restriction and join selectivity estimator functions of a
+ custom operator a && b for
+ type int[]:
-ALTER OPERATOR && (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
-
+ALTER OPERATOR && (int[], int[]) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
+
+
+
+
+ Mark the && operator as being its own
+ commutator:
+
+ALTER OPERATOR && (int[], int[]) SET (COMMUTATOR = &&);
+
+
diff --git a/doc/src/sgml/ref/create_operator.sgml b/doc/src/sgml/ref/create_operator.sgml
index e27512ff391..c421fd21e9d 100644
--- a/doc/src/sgml/ref/create_operator.sgml
+++ b/doc/src/sgml/ref/create_operator.sgml
@@ -104,7 +104,7 @@ CREATE OPERATOR name (
- The other clauses specify optional operator optimization clauses.
+ The other clauses specify optional operator optimization attributes.
Their meaning is detailed in .
@@ -112,7 +112,7 @@ CREATE OPERATOR name (
To be able to create an operator, you must have USAGE
privilege on the argument types and the return type, as well
as EXECUTE privilege on the underlying function. If a
- commutator or negator operator is specified, you must own these operators.
+ commutator or negator operator is specified, you must own those operators.
@@ -231,7 +231,67 @@ COMMUTATOR = OPERATOR(myschema.===) ,
Notes
- Refer to for further information.
+ Refer to and
+ for further information.
+
+
+
+ When you are defining a self-commutative operator, you just do it.
+ When you are defining a pair of commutative operators, things are
+ a little trickier: how can the first one to be defined refer to the
+ other one, which you haven't defined yet? There are three solutions
+ to this problem:
+
+
+
+
+ One way is to omit the COMMUTATOR clause in the
+ first operator that you define, and then provide one in the second
+ operator's definition. Since PostgreSQL
+ knows that commutative operators come in pairs, when it sees the
+ second definition it will automatically go back and fill in the
+ missing COMMUTATOR clause in the first
+ definition.
+
+
+
+
+
+ Another, more straightforward way is just to
+ include COMMUTATOR clauses in both definitions.
+ When PostgreSQL processes the first
+ definition and realizes that COMMUTATOR refers to
+ a nonexistent operator, the system will make a dummy entry for that
+ operator in the system catalog. This dummy entry will have valid
+ data only for the operator name, left and right operand types, and
+ owner, since that's all that PostgreSQL
+ can deduce at this point. The first operator's catalog entry will
+ link to this dummy entry. Later, when you define the second
+ operator, the system updates the dummy entry with the additional
+ information from the second definition. If you try to use the dummy
+ operator before it's been filled in, you'll just get an error
+ message.
+
+
+
+
+
+ Alternatively, both operators can be defined
+ without COMMUTATOR clauses
+ and then ALTER OPERATOR can be used to set their
+ commutator links. It's sufficient to ALTER
+ either one of the pair.
+
+
+
+
+ In all three cases, you must own both operators in order to mark
+ them as commutators.
+
+
+
+ Pairs of negator operators can be defined using the same methods
+ as for commutator pairs.
diff --git a/doc/src/sgml/xoper.sgml b/doc/src/sgml/xoper.sgml
index a929ced07d7..954a90d77d0 100644
--- a/doc/src/sgml/xoper.sgml
+++ b/doc/src/sgml/xoper.sgml
@@ -146,44 +146,6 @@ SELECT (a + b) AS c FROM test_complex;
= operator must specify that it is valid, by marking the
operator with commutator information.
-
-
- When you are defining a self-commutative operator, you just do it.
- When you are defining a pair of commutative operators, things are
- a little trickier: how can the first one to be defined refer to the
- other one, which you haven't defined yet? There are two solutions
- to this problem:
-
-
-
-
- One way is to omit the COMMUTATOR clause in the first operator that
- you define, and then provide one in the second operator's definition.
- Since PostgreSQL knows that commutative
- operators come in pairs, when it sees the second definition it will
- automatically go back and fill in the missing COMMUTATOR clause in
- the first definition.
-
-
-
-
-
- The other, more straightforward way is just to include COMMUTATOR clauses
- in both definitions. When PostgreSQL processes
- the first definition and realizes that COMMUTATOR refers to a nonexistent
- operator, the system will make a dummy entry for that operator in the
- system catalog. This dummy entry will have valid data only
- for the operator name, left and right operand types, and result type,
- since that's all that PostgreSQL can deduce
- at this point. The first operator's catalog entry will link to this
- dummy entry. Later, when you define the second operator, the system
- updates the dummy entry with the additional information from the second
- definition. If you try to use the dummy operator before it's been filled
- in, you'll just get an error message.
-
-
-
-
@@ -217,12 +179,6 @@ SELECT (a + b) AS c FROM test_complex;
x <> y. This comes up more often than you might think, because
NOT operations can be inserted as a consequence of other rearrangements.
-
-
- Pairs of negator operators can be defined using the same methods
- explained above for commutator pairs.
-
-
--
cgit v1.2.3