1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

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
This commit is contained in:
Tom Lane
2020-09-17 19:38:05 -04:00
parent 76f412ab31
commit 1ed6b89563
32 changed files with 279 additions and 339 deletions

View File

@ -52,7 +52,7 @@ typedef struct OprCacheKey
{
char oprname[NAMEDATALEN];
Oid left_arg; /* Left input OID, or 0 if prefix op */
Oid right_arg; /* Right input OID, or 0 if postfix op */
Oid right_arg; /* Right input OID */
Oid search_path[MAX_CACHED_PATH_LEN];
} OprCacheKey;
@ -88,8 +88,7 @@ static void InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
* Given a possibly-qualified operator name and exact input datatypes,
* look up the operator.
*
* Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
* a postfix op.
* Pass oprleft = InvalidOid for a prefix op.
*
* If the operator name is not schema-qualified, it is sought in the current
* namespace search path.
@ -115,10 +114,16 @@ LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
if (!OidIsValid(oprleft))
oprkind = 'l';
else if (!OidIsValid(oprright))
oprkind = 'r';
else
else if (OidIsValid(oprright))
oprkind = 'b';
else
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("postfix operators are not supported"),
parser_errposition(pstate, location)));
oprkind = 0; /* keep compiler quiet */
}
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
@ -507,85 +512,6 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
}
/* right_oper() -- search for a unary right operator (postfix operator)
* Given operator name and type of arg, return oper struct.
*
* IMPORTANT: the returned operator (if any) is only promised to be
* coercion-compatible with the input datatype. Do not use this if
* you need an exact- or binary-compatible match.
*
* If no matching operator found, return NULL if noError is true,
* raise an error if it is false. pstate and location are used only to report
* the error position; pass NULL/-1 if not available.
*
* NOTE: on success, the returned object is a syscache entry. The caller
* must ReleaseSysCache() the entry when done with it.
*/
Operator
right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
{
Oid operOid;
OprCacheKey key;
bool key_ok;
FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
HeapTuple tup = NULL;
/*
* Try to find the mapping in the lookaside cache.
*/
key_ok = make_oper_cache_key(pstate, &key, op, arg, InvalidOid, location);
if (key_ok)
{
operOid = find_oper_cache_entry(&key);
if (OidIsValid(operOid))
{
tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
if (HeapTupleIsValid(tup))
return (Operator) tup;
}
}
/*
* First try for an "exact" match.
*/
operOid = OpernameGetOprid(op, arg, InvalidOid);
if (!OidIsValid(operOid))
{
/*
* Otherwise, search for the most suitable candidate.
*/
FuncCandidateList clist;
/* Get postfix operators of given name */
clist = OpernameGetCandidates(op, 'r', false);
/* No operators found? Then fail... */
if (clist != NULL)
{
/*
* We must run oper_select_candidate even if only one candidate,
* otherwise we may falsely return a non-type-compatible operator.
*/
fdresult = oper_select_candidate(1, &arg, clist, &operOid);
}
}
if (OidIsValid(operOid))
tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
if (HeapTupleIsValid(tup))
{
if (key_ok)
make_oper_cache_entry(&key, operOid);
}
else if (!noError)
op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location);
return (Operator) tup;
}
/* left_oper() -- search for a unary left operator (prefix operator)
* Given operator name and type of arg, return oper struct.
*
@ -696,8 +622,7 @@ op_signature_string(List *op, char oprkind, Oid arg1, Oid arg2)
appendStringInfoString(&argbuf, NameListToString(op));
if (oprkind != 'r')
appendStringInfo(&argbuf, " %s", format_type_be(arg2));
appendStringInfo(&argbuf, " %s", format_type_be(arg2));
return argbuf.data; /* return palloc'd string buffer */
}
@ -758,17 +683,16 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
Oid rettype;
OpExpr *result;
/* Select the operator */
/* Check it's not a postfix operator */
if (rtree == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("postfix operators are not supported")));
/* Select the operator */
if (ltree == NULL)
{
/* right operator */
ltypeId = exprType(ltree);
rtypeId = InvalidOid;
tup = right_oper(pstate, opname, ltypeId, false, location);
}
else if (ltree == NULL)
{
/* left operator */
/* prefix operator */
rtypeId = exprType(rtree);
ltypeId = InvalidOid;
tup = left_oper(pstate, opname, rtypeId, false, location);
@ -795,17 +719,9 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
parser_errposition(pstate, location)));
/* Do typecasting and build the expression tree */
if (rtree == NULL)
if (ltree == NULL)
{
/* right operator */
args = list_make1(ltree);
actual_arg_types[0] = ltypeId;
declared_arg_types[0] = opform->oprleft;
nargs = 1;
}
else if (ltree == NULL)
{
/* left operator */
/* prefix operator */
args = list_make1(rtree);
actual_arg_types[0] = rtypeId;
declared_arg_types[0] = opform->oprright;