Skip to content

Commit 1ed6b89

Browse files
committed
Remove support for postfix (right-unary) operators.
This feature has been a thorn in our sides for a long time, causing many grammatical ambiguity problems. It doesn't seem worth the pain to continue to support it, so remove it. There are some follow-on improvements we can make in the grammar, but this commit only removes the bare minimum number of productions, plus assorted backend support code. Note that pg_dump and psql continue to have full support, since they may be used against older servers. However, pg_dump warns about postfix operators. There is also a check in pg_upgrade. Documentation-wise, I (tgl) largely removed the "left unary" terminology in favor of saying "prefix operator", which is a more standard and IMO less confusing term. I included a catversion bump, although no initial catalog data changes here, to mark the boundary at which oprkind = 'r' stopped being valid in pg_operator. Mark Dilger, based on work by myself and Robert Haas; review by John Naylor Discussion: https://postgr.es/m/38ca86db-42ab-9b48-2902-337a0d6b8311@2ndquadrant.com
1 parent 76f412a commit 1ed6b89

32 files changed

+280
-340
lines changed

contrib/postgres_fdw/deparse.c

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2706,7 +2706,6 @@ deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
27062706
HeapTuple tuple;
27072707
Form_pg_operator form;
27082708
char oprkind;
2709-
ListCell *arg;
27102709

27112710
/* Retrieve information about the operator from system catalog. */
27122711
tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(node->opno));
@@ -2716,31 +2715,25 @@ deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
27162715
oprkind = form->oprkind;
27172716

27182717
/* Sanity check. */
2719-
Assert((oprkind == 'r' && list_length(node->args) == 1) ||
2720-
(oprkind == 'l' && list_length(node->args) == 1) ||
2718+
Assert((oprkind == 'l' && list_length(node->args) == 1) ||
27212719
(oprkind == 'b' && list_length(node->args) == 2));
27222720

27232721
/* Always parenthesize the expression. */
27242722
appendStringInfoChar(buf, '(');
27252723

2726-
/* Deparse left operand. */
2727-
if (oprkind == 'r' || oprkind == 'b')
2724+
/* Deparse left operand, if any. */
2725+
if (oprkind == 'b')
27282726
{
2729-
arg = list_head(node->args);
2730-
deparseExpr(lfirst(arg), context);
2727+
deparseExpr(linitial(node->args), context);
27312728
appendStringInfoChar(buf, ' ');
27322729
}
27332730

27342731
/* Deparse operator name. */
27352732
deparseOperatorName(buf, form);
27362733

27372734
/* Deparse right operand. */
2738-
if (oprkind == 'l' || oprkind == 'b')
2739-
{
2740-
arg = list_tail(node->args);
2741-
appendStringInfoChar(buf, ' ');
2742-
deparseExpr(lfirst(arg), context);
2743-
}
2735+
appendStringInfoChar(buf, ' ');
2736+
deparseExpr(llast(node->args), context);
27442737

27452738
appendStringInfoChar(buf, ')');
27462739

doc/src/sgml/catalogs.sgml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5159,8 +5159,8 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
51595159
<structfield>oprkind</structfield> <type>char</type>
51605160
</para>
51615161
<para>
5162-
<literal>b</literal> = infix (<quote>both</quote>), <literal>l</literal> = prefix
5163-
(<quote>left</quote>), <literal>r</literal> = postfix (<quote>right</quote>)
5162+
<literal>b</literal> = infix operator (<quote>both</quote>),
5163+
or <literal>l</literal> = prefix operator (<quote>left</quote>)
51645164
</para></entry>
51655165
</row>
51665166

@@ -5188,7 +5188,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
51885188
(references <link linkend="catalog-pg-type"><structname>pg_type</structname></link>.<structfield>oid</structfield>)
51895189
</para>
51905190
<para>
5191-
Type of the left operand
5191+
Type of the left operand (0 if none)
51925192
</para></entry>
51935193
</row>
51945194

@@ -5266,7 +5266,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
52665266
</table>
52675267

52685268
<para>
5269-
Unused column contain zeroes. For example, <structfield>oprleft</structfield>
5269+
Unused columns contain zeroes. For example, <structfield>oprleft</structfield>
52705270
is zero for a prefix operator.
52715271
</para>
52725272

doc/src/sgml/ref/alter_extension.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ ALTER EXTENSION <replaceable class="parameter">name</replaceable> DROP <replacea
251251
<para>
252252
The data type(s) of the operator's arguments (optionally
253253
schema-qualified). Write <literal>NONE</literal> for the missing argument
254-
of a prefix or postfix operator.
254+
of a prefix operator.
255255
</para>
256256
</listitem>
257257
</varlistentry>

doc/src/sgml/ref/alter_operator.sgml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ PostgreSQL documentation
2121

2222
<refsynopsisdiv>
2323
<synopsis>
24-
ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } )
24+
ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , <replaceable>right_type</replaceable> )
2525
OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
2626

27-
ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } )
27+
ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , <replaceable>right_type</replaceable> )
2828
SET SCHEMA <replaceable>new_schema</replaceable>
2929

30-
ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } )
30+
ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , <replaceable>right_type</replaceable> )
3131
SET ( { RESTRICT = { <replaceable class="parameter">res_proc</replaceable> | NONE }
3232
| JOIN = { <replaceable class="parameter">join_proc</replaceable> | NONE }
3333
} [, ... ] )
@@ -79,8 +79,7 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
7979
<term><replaceable class="parameter">right_type</replaceable></term>
8080
<listitem>
8181
<para>
82-
The data type of the operator's right operand; write
83-
<literal>NONE</literal> if the operator has no right operand.
82+
The data type of the operator's right operand.
8483
</para>
8584
</listitem>
8685
</varlistentry>

doc/src/sgml/ref/alter_opfamily.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="
141141
<para>
142142
In an <literal>OPERATOR</literal> clause,
143143
the operand data type(s) of the operator, or <literal>NONE</literal> to
144-
signify a left-unary or right-unary operator. Unlike the comparable
144+
signify a prefix operator. Unlike the comparable
145145
syntax in <command>CREATE OPERATOR CLASS</command>, the operand data types
146146
must always be specified.
147147
</para>

doc/src/sgml/ref/comment.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ COMMENT ON
224224
<para>
225225
The data type(s) of the operator's arguments (optionally
226226
schema-qualified). Write <literal>NONE</literal> for the missing argument
227-
of a prefix or postfix operator.
227+
of a prefix operator.
228228
</para>
229229
</listitem>
230230
</varlistentry>

doc/src/sgml/ref/create_opclass.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
161161
<para>
162162
In an <literal>OPERATOR</literal> clause,
163163
the operand data type(s) of the operator, or <literal>NONE</literal> to
164-
signify a left-unary or right-unary operator. The operand data
164+
signify a prefix operator. The operand data
165165
types can be omitted in the normal case where they are the same
166166
as the operator class's data type.
167167
</para>

doc/src/sgml/ref/create_operator.sgml

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -86,20 +86,9 @@ CREATE OPERATOR <replaceable>name</replaceable> (
8686
</para>
8787

8888
<para>
89-
At least one of <literal>LEFTARG</literal> and <literal>RIGHTARG</literal> must be defined. For
90-
binary operators, both must be defined. For right unary
91-
operators, only <literal>LEFTARG</literal> should be defined, while for left
92-
unary operators only <literal>RIGHTARG</literal> should be defined.
93-
</para>
94-
95-
<note>
96-
<para>
97-
Right unary, also called postfix, operators are deprecated and will be
98-
removed in <productname>PostgreSQL</productname> version 14.
99-
</para>
100-
</note>
101-
102-
<para>
89+
For binary operators, both <literal>LEFTARG</literal> and
90+
<literal>RIGHTARG</literal> must be defined. For prefix operators only
91+
<literal>RIGHTARG</literal> should be defined.
10392
The <replaceable class="parameter">function_name</replaceable>
10493
function must have been previously defined using <command>CREATE
10594
FUNCTION</command> and must be defined to accept the correct number
@@ -160,7 +149,7 @@ CREATE OPERATOR <replaceable>name</replaceable> (
160149
<listitem>
161150
<para>
162151
The data type of the operator's left operand, if any.
163-
This option would be omitted for a left-unary operator.
152+
This option would be omitted for a prefix operator.
164153
</para>
165154
</listitem>
166155
</varlistentry>
@@ -169,8 +158,7 @@ CREATE OPERATOR <replaceable>name</replaceable> (
169158
<term><replaceable class="parameter">right_type</replaceable></term>
170159
<listitem>
171160
<para>
172-
The data type of the operator's right operand, if any.
173-
This option would be omitted for a right-unary operator.
161+
The data type of the operator's right operand.
174162
</para>
175163
</listitem>
176164
</varlistentry>

doc/src/sgml/ref/drop_operator.sgml

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ PostgreSQL documentation
2121

2222
<refsynopsisdiv>
2323
<synopsis>
24-
DROP OPERATOR [ IF EXISTS ] <replaceable class="parameter">name</replaceable> ( { <replaceable class="parameter">left_type</replaceable> | NONE } , { <replaceable class="parameter">right_type</replaceable> | NONE } ) [, ...] [ CASCADE | RESTRICT ]
24+
DROP OPERATOR [ IF EXISTS ] <replaceable class="parameter">name</replaceable> ( { <replaceable class="parameter">left_type</replaceable> | NONE } , <replaceable class="parameter">right_type</replaceable> ) [, ...] [ CASCADE | RESTRICT ]
2525
</synopsis>
2626
</refsynopsisdiv>
2727

@@ -73,8 +73,7 @@ DROP OPERATOR [ IF EXISTS ] <replaceable class="parameter">name</replaceable> (
7373
<term><replaceable class="parameter">right_type</replaceable></term>
7474
<listitem>
7575
<para>
76-
The data type of the operator's right operand; write
77-
<literal>NONE</literal> if the operator has no right operand.
76+
The data type of the operator's right operand.
7877
</para>
7978
</listitem>
8079
</varlistentry>
@@ -113,24 +112,17 @@ DROP OPERATOR ^ (integer, integer);
113112
</para>
114113

115114
<para>
116-
Remove the left unary bitwise complement operator
115+
Remove the bitwise-complement prefix operator
117116
<literal>~b</literal> for type <type>bit</type>:
118117
<programlisting>
119118
DROP OPERATOR ~ (none, bit);
120119
</programlisting>
121120
</para>
122121

123-
<para>
124-
Remove the right unary factorial operator <literal>x!</literal>
125-
for type <type>bigint</type>:
126-
<programlisting>
127-
DROP OPERATOR ! (bigint, none);
128-
</programlisting></para>
129-
130122
<para>
131123
Remove multiple operators in one command:
132124
<programlisting>
133-
DROP OPERATOR ~ (none, bit), ! (bigint, none);
125+
DROP OPERATOR ~ (none, bit), ^ (integer, integer);
134126
</programlisting></para>
135127
</refsect1>
136128

doc/src/sgml/syntax.sgml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,7 @@ CAST ( '<replaceable>string</replaceable>' AS <replaceable>type</replaceable> )
836836
<para>
837837
When working with non-SQL-standard operator names, you will usually
838838
need to separate adjacent operators with spaces to avoid ambiguity.
839-
For example, if you have defined a left unary operator named <literal>@</literal>,
839+
For example, if you have defined a prefix operator named <literal>@</literal>,
840840
you cannot write <literal>X*@Y</literal>; you must write
841841
<literal>X* @Y</literal> to ensure that
842842
<productname>PostgreSQL</productname> reads it as two operator names
@@ -1444,11 +1444,10 @@ $1.somecolumn
14441444
</indexterm>
14451445

14461446
<para>
1447-
There are three possible syntaxes for an operator invocation:
1447+
There are two possible syntaxes for an operator invocation:
14481448
<simplelist>
14491449
<member><replaceable>expression</replaceable> <replaceable>operator</replaceable> <replaceable>expression</replaceable> (binary infix operator)</member>
14501450
<member><replaceable>operator</replaceable> <replaceable>expression</replaceable> (unary prefix operator)</member>
1451-
<member><replaceable>expression</replaceable> <replaceable>operator</replaceable> (unary postfix operator)</member>
14521451
</simplelist>
14531452
where the <replaceable>operator</replaceable> token follows the syntax
14541453
rules of <xref linkend="sql-syntax-operators"/>, or is one of the

doc/src/sgml/typeconv.sgml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ Operators
9797
<listitem>
9898
<para>
9999
<productname>PostgreSQL</productname> allows expressions with
100-
prefix and postfix unary (one-argument) operators,
101-
as well as binary (two-argument) operators. Like functions, operators can
100+
prefix (one-argument) operators,
101+
as well as infix (two-argument) operators. Like functions, operators can
102102
be overloaded, so the same problem of selecting the right operator
103103
exists.
104104
</para>
@@ -266,7 +266,7 @@ create objects. In such situations, cast arguments to force an exact match.
266266
<para>
267267
If one argument of a binary operator invocation is of the <type>unknown</type> type,
268268
then assume it is the same type as the other argument for this check.
269-
Invocations involving two <type>unknown</type> inputs, or a unary operator
269+
Invocations involving two <type>unknown</type> inputs, or a prefix operator
270270
with an <type>unknown</type> input, will never find a match at this step.
271271
</para>
272272
</step>

doc/src/sgml/xoper.sgml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
</para>
2121

2222
<para>
23-
<productname>PostgreSQL</productname> supports left unary, right
24-
unary, and binary operators. Operators can be
23+
<productname>PostgreSQL</productname> supports prefix
24+
and infix operators. Operators can be
2525
overloaded;<indexterm><primary>overloading</primary><secondary>operators</secondary></indexterm>
2626
that is, the same operator name can be used for different operators
2727
that have different numbers and types of operands. When a query is
@@ -64,9 +64,9 @@ SELECT (a + b) AS c FROM test_complex;
6464
</para>
6565

6666
<para>
67-
We've shown how to create a binary operator here. To create unary
68-
operators, just omit one of <literal>leftarg</literal> (for left unary) or
69-
<literal>rightarg</literal> (for right unary). The <literal>function</literal>
67+
We've shown how to create a binary operator here. To create a prefix
68+
operator, just omit the <literal>leftarg</literal>.
69+
The <literal>function</literal>
7070
clause and the argument clauses are the only required items in
7171
<command>CREATE OPERATOR</command>. The <literal>commutator</literal>
7272
clause shown in the example is an optional hint to the query
@@ -202,7 +202,7 @@ SELECT (a + b) AS c FROM test_complex;
202202
<para>
203203
Unlike commutators, a pair of unary operators could validly be marked
204204
as each other's negators; that would mean (A x) equals NOT (B x)
205-
for all x, or the equivalent for right unary operators.
205+
for all x.
206206
</para>
207207

208208
<para>

src/backend/catalog/namespace.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,8 +1473,7 @@ FunctionIsVisible(Oid funcid)
14731473
* Given a possibly-qualified operator name and exact input datatypes,
14741474
* look up the operator. Returns InvalidOid if not found.
14751475
*
1476-
* Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
1477-
* a postfix op.
1476+
* Pass oprleft = InvalidOid for a prefix op.
14781477
*
14791478
* If the operator name is not schema-qualified, it is sought in the current
14801479
* namespace search path. If the name is schema-qualified and the given
@@ -1580,8 +1579,8 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
15801579
* namespace case, we arrange for entries in earlier namespaces to mask
15811580
* identical entries in later namespaces.
15821581
*
1583-
* The returned items always have two args[] entries --- one or the other
1584-
* will be InvalidOid for a prefix or postfix oprkind. nargs is 2, too.
1582+
* The returned items always have two args[] entries --- the first will be
1583+
* InvalidOid for a prefix oprkind. nargs is always 2, too.
15851584
*/
15861585
FuncCandidateList
15871586
OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)

src/backend/catalog/pg_operator.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ OperatorShellMake(const char *operatorName,
245245
values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
246246
values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
247247
values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
248-
values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
248+
values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
249249
values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
250250
values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
251251
values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
@@ -494,7 +494,7 @@ OperatorCreate(const char *operatorName,
494494
values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
495495
values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
496496
values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
497-
values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
497+
values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
498498
values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
499499
values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
500500
values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);

src/backend/commands/operatorcmds.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,22 @@ DefineOperator(List *names, List *parameters)
168168
if (typeName2)
169169
typeId2 = typenameTypeId(NULL, typeName2);
170170

171+
/*
172+
* If only the right argument is missing, the user is likely trying to
173+
* create a postfix operator, so give them a hint about why that does not
174+
* work. But if both arguments are missing, do not mention postfix
175+
* operators, as the user most likely simply neglected to mention the
176+
* arguments.
177+
*/
171178
if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
172179
ereport(ERROR,
173180
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
174-
errmsg("at least one of leftarg or rightarg must be specified")));
181+
errmsg("operator argument types must be specified")));
182+
if (!OidIsValid(typeId2))
183+
ereport(ERROR,
184+
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
185+
errmsg("operator right argument type must be specified"),
186+
errdetail("Postfix operators are not supported.")));
175187

176188
if (typeName1)
177189
{

src/backend/nodes/print.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,6 @@ print_expr(const Node *expr, const List *rtable)
394394
}
395395
else
396396
{
397-
/* we print prefix and postfix ops the same... */
398397
printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
399398
print_expr(get_leftop((const Expr *) e), rtable);
400399
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy