1997-11-25 23:07:18 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
2000-02-27 03:48:15 +01:00
|
|
|
* parse_oper.c
|
1997-11-25 23:07:18 +01:00
|
|
|
* handle operator things for parser
|
|
|
|
*
|
2023-01-02 21:00:37 +01:00
|
|
|
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1997-11-25 23:07:18 +01:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/parser/parse_oper.c
|
1997-11-25 23:07:18 +01:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1997-11-26 02:14:33 +01:00
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
#include "postgres.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.h"
|
1997-11-25 23:07:18 +01:00
|
|
|
#include "catalog/pg_operator.h"
|
2006-07-13 18:49:20 +02:00
|
|
|
#include "catalog/pg_type.h"
|
2003-07-04 04:51:34 +02:00
|
|
|
#include "lib/stringinfo.h"
|
2008-08-26 00:42:34 +02:00
|
|
|
#include "nodes/nodeFuncs.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "parser/parse_coerce.h"
|
|
|
|
#include "parser/parse_func.h"
|
1997-11-26 02:14:33 +01:00
|
|
|
#include "parser/parse_oper.h"
|
|
|
|
#include "parser/parse_type.h"
|
2001-08-09 20:28:18 +02:00
|
|
|
#include "utils/builtins.h"
|
2007-11-28 19:47:56 +01:00
|
|
|
#include "utils/inval.h"
|
2003-04-09 01:20:04 +02:00
|
|
|
#include "utils/lsyscache.h"
|
1997-11-26 02:14:33 +01:00
|
|
|
#include "utils/syscache.h"
|
2003-08-17 21:58:06 +02:00
|
|
|
#include "utils/typcache.h"
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2003-04-09 01:20:04 +02:00
|
|
|
|
2007-11-28 19:47:56 +01:00
|
|
|
/*
|
|
|
|
* The lookup key for the operator lookaside hash table. Unused bits must be
|
|
|
|
* zeroes to ensure hashing works consistently --- in particular, oprname
|
|
|
|
* must be zero-padded and any unused entries in search_path must be zero.
|
|
|
|
*
|
|
|
|
* search_path contains the actual search_path with which the entry was
|
|
|
|
* derived (minus temp namespace if any), or else the single specified
|
|
|
|
* schema OID if we are looking up an explicitly-qualified operator name.
|
|
|
|
*
|
|
|
|
* search_path has to be fixed-length since the hashtable code insists on
|
|
|
|
* fixed-size keys. If your search path is longer than that, we just punt
|
|
|
|
* and don't cache anything.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* If your search_path is longer than this, sucks to be you ... */
|
|
|
|
#define MAX_CACHED_PATH_LEN 16
|
|
|
|
|
|
|
|
typedef struct OprCacheKey
|
|
|
|
{
|
|
|
|
char oprname[NAMEDATALEN];
|
|
|
|
Oid left_arg; /* Left input OID, or 0 if prefix op */
|
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
2020-09-18 01:38:05 +02:00
|
|
|
Oid right_arg; /* Right input OID */
|
2007-11-28 19:47:56 +01:00
|
|
|
Oid search_path[MAX_CACHED_PATH_LEN];
|
|
|
|
} OprCacheKey;
|
|
|
|
|
|
|
|
typedef struct OprCacheEntry
|
|
|
|
{
|
|
|
|
/* the hash lookup key MUST BE FIRST */
|
|
|
|
OprCacheKey key;
|
|
|
|
|
|
|
|
Oid opr_oid; /* OID of the resolved operator */
|
|
|
|
} OprCacheEntry;
|
|
|
|
|
|
|
|
|
2006-05-02 01:22:43 +02:00
|
|
|
static Oid binary_oper_exact(List *opname, Oid arg1, Oid arg2);
|
2003-07-04 04:51:34 +02:00
|
|
|
static FuncDetailCode oper_select_candidate(int nargs,
|
|
|
|
Oid *input_typeids,
|
|
|
|
FuncCandidateList candidates,
|
|
|
|
Oid *operOid);
|
|
|
|
static const char *op_signature_string(List *op, char oprkind,
|
|
|
|
Oid arg1, Oid arg2);
|
2006-03-14 23:48:25 +01:00
|
|
|
static void op_error(ParseState *pstate, List *op, char oprkind,
|
|
|
|
Oid arg1, Oid arg2,
|
|
|
|
FuncDetailCode fdresult, int location);
|
2015-03-18 18:48:02 +01:00
|
|
|
static bool make_oper_cache_key(ParseState *pstate, OprCacheKey *key,
|
|
|
|
List *opname, Oid ltypeId, Oid rtypeId,
|
|
|
|
int location);
|
2007-11-28 19:47:56 +01:00
|
|
|
static Oid find_oper_cache_entry(OprCacheKey *key);
|
|
|
|
static void make_oper_cache_entry(OprCacheKey *key, Oid opr_oid);
|
2011-08-17 01:27:46 +02:00
|
|
|
static void InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue);
|
2002-04-17 01:08:12 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* LookupOperName
|
|
|
|
* Given a possibly-qualified operator name and exact input datatypes,
|
2003-07-04 04:51:34 +02:00
|
|
|
* look up the operator.
|
2002-04-17 01:08:12 +02: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
2020-09-18 01:38:05 +02:00
|
|
|
* Pass oprleft = InvalidOid for a prefix op.
|
2002-04-17 01:08:12 +02:00
|
|
|
*
|
|
|
|
* If the operator name is not schema-qualified, it is sought in the current
|
|
|
|
* namespace search path.
|
2003-07-04 04:51:34 +02:00
|
|
|
*
|
|
|
|
* If the operator is not found, we return InvalidOid if noError is true,
|
2006-03-14 23:48:25 +01:00
|
|
|
* else raise an error. pstate and location are used only to report the
|
|
|
|
* error position; pass NULL/-1 if not available.
|
2002-04-17 01:08:12 +02:00
|
|
|
*/
|
|
|
|
Oid
|
2006-03-14 23:48:25 +01:00
|
|
|
LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
|
|
|
|
bool noError, int location)
|
2002-04-17 01:08:12 +02:00
|
|
|
{
|
2006-05-02 01:22:43 +02:00
|
|
|
Oid result;
|
2002-04-17 01:08:12 +02:00
|
|
|
|
2006-05-02 01:22:43 +02:00
|
|
|
result = OpernameGetOprid(opername, oprleft, oprright);
|
|
|
|
if (OidIsValid(result))
|
|
|
|
return result;
|
2002-04-17 01:08:12 +02:00
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
/* we don't use op_error here because only an exact match is wanted */
|
|
|
|
if (!noError)
|
2006-05-02 01:22:43 +02:00
|
|
|
{
|
|
|
|
char oprkind;
|
|
|
|
|
|
|
|
if (!OidIsValid(oprleft))
|
|
|
|
oprkind = 'l';
|
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
2020-09-18 01:38:05 +02:00
|
|
|
else if (OidIsValid(oprright))
|
2006-05-02 01:22:43 +02:00
|
|
|
oprkind = 'b';
|
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
2020-09-18 01:38:05 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("postfix operators are not supported"),
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
oprkind = 0; /* keep compiler quiet */
|
|
|
|
}
|
2006-05-02 01:22:43 +02:00
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("operator does not exist: %s",
|
|
|
|
op_signature_string(opername, oprkind,
|
2006-03-14 23:48:25 +01:00
|
|
|
oprleft, oprright)),
|
|
|
|
parser_errposition(pstate, location)));
|
2006-05-02 01:22:43 +02:00
|
|
|
}
|
2003-07-04 04:51:34 +02:00
|
|
|
|
2002-04-17 01:08:12 +02:00
|
|
|
return InvalidOid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2016-12-28 18:00:00 +01:00
|
|
|
* LookupOperWithArgs
|
2002-04-17 01:08:12 +02:00
|
|
|
* Like LookupOperName, but the argument types are specified by
|
2019-08-05 05:14:58 +02:00
|
|
|
* a ObjectWithArgs node.
|
2002-04-17 01:08:12 +02:00
|
|
|
*/
|
|
|
|
Oid
|
2016-12-28 18:00:00 +01:00
|
|
|
LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
|
2002-04-17 01:08:12 +02:00
|
|
|
{
|
2016-12-28 18:00:00 +01:00
|
|
|
TypeName *oprleft,
|
|
|
|
*oprright;
|
2002-04-17 01:08:12 +02:00
|
|
|
Oid leftoid,
|
|
|
|
rightoid;
|
|
|
|
|
2016-12-28 18:00:00 +01:00
|
|
|
Assert(list_length(oper->objargs) == 2);
|
Reconsider the handling of procedure OUT parameters.
Commit 2453ea142 redefined pg_proc.proargtypes to include the types of
OUT parameters, for procedures only. While that had some advantages
for implementing the SQL-spec behavior of DROP PROCEDURE, it was pretty
disastrous from a number of other perspectives. Notably, since the
primary key of pg_proc is name + proargtypes, this made it possible to
have multiple procedures with identical names + input arguments and
differing output argument types. That would make it impossible to call
any one of the procedures by writing just NULL (or "?", or any other
data-type-free notation) for the output argument(s). The change also
seems likely to cause grave confusion for client applications that
examine pg_proc and expect the traditional definition of proargtypes.
Hence, revert the definition of proargtypes to what it was, and
undo a number of complications that had been added to support that.
To support the SQL-spec behavior of DROP PROCEDURE, when there are
no argmode markers in the command's parameter list, we perform the
lookup both ways (that is, matching against both proargtypes and
proallargtypes), succeeding if we get just one unique match.
In principle this could result in ambiguous-function failures
that would not happen when using only one of the two rules.
However, overloading of procedure names is thought to be a pretty
rare usage, so this shouldn't cause many problems in practice.
Postgres-specific code such as pg_dump can defend against any
possibility of such failures by being careful to specify argmodes
for all procedure arguments.
This also fixes a few other bugs in the area of CALL statements
with named parameters, and improves the documentation a little.
catversion bump forced because the representation of procedures
with OUT arguments changes.
Discussion: https://postgr.es/m/3742981.1621533210@sss.pgh.pa.us
2021-06-10 23:11:36 +02:00
|
|
|
oprleft = linitial_node(TypeName, oper->objargs);
|
|
|
|
oprright = lsecond_node(TypeName, oper->objargs);
|
2016-12-28 18:00:00 +01:00
|
|
|
|
2002-04-17 01:08:12 +02:00
|
|
|
if (oprleft == NULL)
|
|
|
|
leftoid = InvalidOid;
|
|
|
|
else
|
2016-12-28 18:00:00 +01:00
|
|
|
leftoid = LookupTypeNameOid(NULL, oprleft, noError);
|
2006-03-14 23:48:25 +01:00
|
|
|
|
2002-04-17 01:08:12 +02:00
|
|
|
if (oprright == NULL)
|
|
|
|
rightoid = InvalidOid;
|
|
|
|
else
|
2016-12-28 18:00:00 +01:00
|
|
|
rightoid = LookupTypeNameOid(NULL, oprright, noError);
|
2002-04-17 01:08:12 +02:00
|
|
|
|
2016-12-28 18:00:00 +01:00
|
|
|
return LookupOperName(NULL, oper->objname, leftoid, rightoid,
|
|
|
|
noError, -1);
|
2002-04-17 01:08:12 +02:00
|
|
|
}
|
2000-02-27 03:48:15 +01:00
|
|
|
|
2002-11-29 22:39:12 +01:00
|
|
|
/*
|
2008-08-02 23:32:01 +02:00
|
|
|
* get_sort_group_operators - get default sorting/grouping operators for type
|
2002-11-29 22:39:12 +01:00
|
|
|
*
|
2008-08-02 23:32:01 +02:00
|
|
|
* We fetch the "<", "=", and ">" operators all at once to reduce lookup
|
|
|
|
* overhead (knowing that most callers will be interested in at least two).
|
|
|
|
* However, a given datatype might have only an "=" operator, if it is
|
|
|
|
* hashable but not sortable. (Other combinations of present and missing
|
|
|
|
* operators shouldn't happen, unless the system catalogs are messed up.)
|
2002-11-29 22:39:12 +01:00
|
|
|
*
|
2008-08-02 23:32:01 +02:00
|
|
|
* If an operator is missing and the corresponding needXX flag is true,
|
|
|
|
* throw a standard error message, else return InvalidOid.
|
|
|
|
*
|
2010-10-31 02:55:20 +01:00
|
|
|
* In addition to the operator OIDs themselves, this function can identify
|
|
|
|
* whether the "=" operator is hashable.
|
|
|
|
*
|
2008-08-02 23:32:01 +02:00
|
|
|
* Callers can pass NULL pointers for any results they don't care to get.
|
|
|
|
*
|
|
|
|
* Note: the results are guaranteed to be exact or binary-compatible matches,
|
|
|
|
* since most callers are not prepared to cope with adding any run-time type
|
|
|
|
* coercion steps.
|
2002-11-29 22:39:12 +01:00
|
|
|
*/
|
2008-08-02 23:32:01 +02:00
|
|
|
void
|
|
|
|
get_sort_group_operators(Oid argtype,
|
|
|
|
bool needLT, bool needEQ, bool needGT,
|
2010-10-31 02:55:20 +01:00
|
|
|
Oid *ltOpr, Oid *eqOpr, Oid *gtOpr,
|
|
|
|
bool *isHashable)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2003-08-17 21:58:06 +02:00
|
|
|
TypeCacheEntry *typentry;
|
2010-10-31 02:55:20 +01:00
|
|
|
int cache_flags;
|
2008-08-02 23:32:01 +02:00
|
|
|
Oid lt_opr;
|
|
|
|
Oid eq_opr;
|
|
|
|
Oid gt_opr;
|
2010-10-31 02:55:20 +01:00
|
|
|
bool hashable;
|
2003-08-17 21:58:06 +02:00
|
|
|
|
|
|
|
/*
|
2008-08-02 23:32:01 +02:00
|
|
|
* Look up the operators using the type cache.
|
2003-08-17 21:58:06 +02:00
|
|
|
*
|
2008-08-02 23:32:01 +02:00
|
|
|
* Note: the search algorithm used by typcache.c ensures that the results
|
2010-10-31 02:55:20 +01:00
|
|
|
* are consistent, ie all from matching opclasses.
|
2003-08-17 21:58:06 +02:00
|
|
|
*/
|
2010-10-31 02:55:20 +01:00
|
|
|
if (isHashable != NULL)
|
|
|
|
cache_flags = TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR |
|
|
|
|
TYPECACHE_HASH_PROC;
|
|
|
|
else
|
|
|
|
cache_flags = TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR;
|
|
|
|
|
|
|
|
typentry = lookup_type_cache(argtype, cache_flags);
|
2008-08-02 23:32:01 +02:00
|
|
|
lt_opr = typentry->lt_opr;
|
|
|
|
eq_opr = typentry->eq_opr;
|
|
|
|
gt_opr = typentry->gt_opr;
|
2010-10-31 02:55:20 +01:00
|
|
|
hashable = OidIsValid(typentry->hash_proc);
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2008-08-02 23:32:01 +02:00
|
|
|
/* Report errors if needed */
|
|
|
|
if ((needLT && !OidIsValid(lt_opr)) ||
|
|
|
|
(needGT && !OidIsValid(gt_opr)))
|
2003-08-17 21:58:06 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("could not identify an ordering operator for type %s",
|
|
|
|
format_type_be(argtype)),
|
|
|
|
errhint("Use an explicit ordering operator or modify the query.")));
|
2008-08-02 23:32:01 +02:00
|
|
|
if (needEQ && !OidIsValid(eq_opr))
|
2003-07-19 01:20:33 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
2008-08-02 23:32:01 +02:00
|
|
|
errmsg("could not identify an equality operator for type %s",
|
|
|
|
format_type_be(argtype))));
|
2003-06-27 02:33:26 +02:00
|
|
|
|
2008-08-02 23:32:01 +02:00
|
|
|
/* Return results as needed */
|
|
|
|
if (ltOpr)
|
|
|
|
*ltOpr = lt_opr;
|
|
|
|
if (eqOpr)
|
|
|
|
*eqOpr = eq_opr;
|
|
|
|
if (gtOpr)
|
|
|
|
*gtOpr = gt_opr;
|
2010-10-31 02:55:20 +01:00
|
|
|
if (isHashable)
|
|
|
|
*isHashable = hashable;
|
2003-06-27 02:33:26 +02:00
|
|
|
}
|
|
|
|
|
2002-11-29 22:39:12 +01:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
/* given operator tuple, return the operator OID */
|
1997-11-25 23:07:18 +01:00
|
|
|
Oid
|
|
|
|
oprid(Operator op)
|
|
|
|
{
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
return ((Form_pg_operator) GETSTRUCT(op))->oid;
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
|
Clean up two rather nasty bugs in operator selection code.
1. If there is exactly one pg_operator entry of the right name and oprkind,
oper() and related routines would return that entry whether its input type
had anything to do with the request or not. This is just premature
optimization: we shouldn't return the single candidate until after we verify
that it really is a valid candidate, ie, is at least coercion-compatible
with the given types.
2. oper() and related routines only promise a coercion-compatible result.
Unfortunately, there were quite a few callers that assumed the returned
operator is binary-compatible with the given datatype; they would proceed
to call it without making any datatype coercions. These callers include
sorting, grouping, aggregation, and VACUUM ANALYZE. In general I think
it is appropriate for these callers to require an exact or binary-compatible
match, so I've added a new routine compatible_oper() that only succeeds if
it can find an operator that doesn't require any run-time conversions.
Callers now call oper() or compatible_oper() depending on whether they are
prepared to deal with type conversion or not.
The upshot of these bugs is revealed by the following silliness in PL/Tcl's
selftest: it creates an operator @< on int4, and then tries to use it to
sort a char(N) column. The system would let it do that :-( (and evidently
has done so since 6.3 :-( :-(). The result in this case was just a silly
sort order, but the reverse combination would've provoked coredump from
trying to dereference integers. With this fix you get more reasonable
behavior:
pltcl_test=# select * from T_pkey1 order by key1, key2 using @<;
ERROR: Unable to identify an operator '@<' for types 'bpchar' and 'bpchar'
You will have to retype this query using an explicit cast
2001-02-16 04:16:58 +01:00
|
|
|
/* given operator tuple, return the underlying function's OID */
|
|
|
|
Oid
|
|
|
|
oprfuncid(Operator op)
|
|
|
|
{
|
|
|
|
Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(op);
|
|
|
|
|
|
|
|
return pgopform->oprcode;
|
|
|
|
}
|
|
|
|
|
1998-05-10 01:31:34 +02:00
|
|
|
|
2002-04-17 01:08:12 +02:00
|
|
|
/* binary_oper_exact()
|
|
|
|
* Check for an "exact" match to the specified operand types.
|
|
|
|
*
|
|
|
|
* If one operand is an unknown literal, assume it should be taken to be
|
2003-10-06 22:09:47 +02:00
|
|
|
* the same type as the other operand for this purpose. Also, consider
|
|
|
|
* the possibility that the other operand is a domain type that needs to
|
|
|
|
* be reduced to its base type to find an "exact" match.
|
1997-11-25 23:07:18 +01:00
|
|
|
*/
|
2002-04-17 01:08:12 +02:00
|
|
|
static Oid
|
2006-05-02 01:22:43 +02:00
|
|
|
binary_oper_exact(List *opname, Oid arg1, Oid arg2)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2006-05-02 01:22:43 +02:00
|
|
|
Oid result;
|
2003-10-06 22:09:47 +02:00
|
|
|
bool was_unknown = false;
|
|
|
|
|
2002-04-17 01:08:12 +02:00
|
|
|
/* Unspecified type for one of the arguments? then use the other */
|
|
|
|
if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid))
|
2003-10-06 22:09:47 +02:00
|
|
|
{
|
2002-04-17 01:08:12 +02:00
|
|
|
arg1 = arg2;
|
2003-10-06 22:09:47 +02:00
|
|
|
was_unknown = true;
|
|
|
|
}
|
2002-04-17 01:08:12 +02:00
|
|
|
else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))
|
2003-10-06 22:09:47 +02:00
|
|
|
{
|
2002-04-17 01:08:12 +02:00
|
|
|
arg2 = arg1;
|
2003-10-06 22:09:47 +02:00
|
|
|
was_unknown = true;
|
|
|
|
}
|
1998-05-10 01:31:34 +02:00
|
|
|
|
2006-05-02 01:22:43 +02:00
|
|
|
result = OpernameGetOprid(opname, arg1, arg2);
|
|
|
|
if (OidIsValid(result))
|
|
|
|
return result;
|
2003-10-06 22:09:47 +02:00
|
|
|
|
|
|
|
if (was_unknown)
|
|
|
|
{
|
|
|
|
/* arg1 and arg2 are the same here, need only look at arg1 */
|
|
|
|
Oid basetype = getBaseType(arg1);
|
|
|
|
|
|
|
|
if (basetype != arg1)
|
|
|
|
{
|
2006-05-02 01:22:43 +02:00
|
|
|
result = OpernameGetOprid(opname, basetype, basetype);
|
|
|
|
if (OidIsValid(result))
|
|
|
|
return result;
|
2003-10-06 22:09:47 +02:00
|
|
|
}
|
2002-02-19 21:11:20 +01:00
|
|
|
}
|
|
|
|
|
2002-04-17 01:08:12 +02:00
|
|
|
return InvalidOid;
|
|
|
|
}
|
2002-02-19 21:11:20 +01:00
|
|
|
|
1998-05-10 01:31:34 +02:00
|
|
|
|
1998-05-29 16:00:24 +02:00
|
|
|
/* oper_select_candidate()
|
2003-05-26 02:11:29 +02:00
|
|
|
* Given the input argtype array and one or more candidates
|
|
|
|
* for the operator, attempt to resolve the conflict.
|
1998-05-29 16:00:24 +02:00
|
|
|
*
|
2003-07-04 04:51:34 +02:00
|
|
|
* Returns FUNCDETAIL_NOTFOUND, FUNCDETAIL_MULTIPLE, or FUNCDETAIL_NORMAL.
|
|
|
|
* In the success case the Oid of the best candidate is stored in *operOid.
|
2000-03-19 01:19:39 +01:00
|
|
|
*
|
2003-05-26 02:11:29 +02:00
|
|
|
* Note that the caller has already determined that there is no candidate
|
|
|
|
* exactly matching the input argtype(s). Incompatible candidates are not yet
|
|
|
|
* pruned away, however.
|
1998-05-10 01:31:34 +02:00
|
|
|
*/
|
2003-07-04 04:51:34 +02:00
|
|
|
static FuncDetailCode
|
1998-05-29 16:00:24 +02:00
|
|
|
oper_select_candidate(int nargs,
|
|
|
|
Oid *input_typeids,
|
2003-07-04 04:51:34 +02:00
|
|
|
FuncCandidateList candidates,
|
|
|
|
Oid *operOid) /* output argument */
|
1998-05-10 01:31:34 +02:00
|
|
|
{
|
1998-05-29 16:00:24 +02:00
|
|
|
int ncandidates;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2000-03-19 01:19:39 +01:00
|
|
|
/*
|
2003-05-26 02:11:29 +02:00
|
|
|
* Delete any candidates that cannot actually accept the given input
|
|
|
|
* types, whether directly or by coercion.
|
2000-03-19 01:19:39 +01:00
|
|
|
*/
|
2003-05-26 02:11:29 +02:00
|
|
|
ncandidates = func_match_argtypes(nargs, input_typeids,
|
|
|
|
candidates, &candidates);
|
2000-03-19 01:19:39 +01:00
|
|
|
|
|
|
|
/* Done if no candidate or only one candidate survives */
|
|
|
|
if (ncandidates == 0)
|
2003-07-04 04:51:34 +02:00
|
|
|
{
|
|
|
|
*operOid = InvalidOid;
|
|
|
|
return FUNCDETAIL_NOTFOUND;
|
|
|
|
}
|
2000-03-19 01:19:39 +01:00
|
|
|
if (ncandidates == 1)
|
2003-07-04 04:51:34 +02:00
|
|
|
{
|
|
|
|
*operOid = candidates->oid;
|
|
|
|
return FUNCDETAIL_NORMAL;
|
|
|
|
}
|
2000-03-19 01:19:39 +01:00
|
|
|
|
|
|
|
/*
|
2003-05-26 02:11:29 +02:00
|
|
|
* Use the same heuristics as for ambiguous functions to resolve the
|
|
|
|
* conflict.
|
2000-03-19 01:19:39 +01:00
|
|
|
*/
|
2003-05-26 02:11:29 +02:00
|
|
|
candidates = func_select_candidate(nargs, input_typeids, candidates);
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2003-05-26 02:11:29 +02:00
|
|
|
if (candidates)
|
2003-07-04 04:51:34 +02:00
|
|
|
{
|
|
|
|
*operOid = candidates->oid;
|
|
|
|
return FUNCDETAIL_NORMAL;
|
|
|
|
}
|
2000-12-15 20:22:03 +01:00
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
*operOid = InvalidOid;
|
|
|
|
return FUNCDETAIL_MULTIPLE; /* failed to select a best candidate */
|
|
|
|
}
|
1997-11-25 23:07:18 +01:00
|
|
|
|
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
/* oper() -- search for a binary operator
|
|
|
|
* Given operator name, types of arg1 and arg2, return oper struct.
|
|
|
|
*
|
Clean up two rather nasty bugs in operator selection code.
1. If there is exactly one pg_operator entry of the right name and oprkind,
oper() and related routines would return that entry whether its input type
had anything to do with the request or not. This is just premature
optimization: we shouldn't return the single candidate until after we verify
that it really is a valid candidate, ie, is at least coercion-compatible
with the given types.
2. oper() and related routines only promise a coercion-compatible result.
Unfortunately, there were quite a few callers that assumed the returned
operator is binary-compatible with the given datatype; they would proceed
to call it without making any datatype coercions. These callers include
sorting, grouping, aggregation, and VACUUM ANALYZE. In general I think
it is appropriate for these callers to require an exact or binary-compatible
match, so I've added a new routine compatible_oper() that only succeeds if
it can find an operator that doesn't require any run-time conversions.
Callers now call oper() or compatible_oper() depending on whether they are
prepared to deal with type conversion or not.
The upshot of these bugs is revealed by the following silliness in PL/Tcl's
selftest: it creates an operator @< on int4, and then tries to use it to
sort a char(N) column. The system would let it do that :-( (and evidently
has done so since 6.3 :-( :-(). The result in this case was just a silly
sort order, but the reverse combination would've provoked coredump from
trying to dereference integers. With this fix you get more reasonable
behavior:
pltcl_test=# select * from T_pkey1 order by key1, key2 using @<;
ERROR: Unable to identify an operator '@<' for types 'bpchar' and 'bpchar'
You will have to retype this query using an explicit cast
2001-02-16 04:16:58 +01:00
|
|
|
* IMPORTANT: the returned operator (if any) is only promised to be
|
|
|
|
* coercion-compatible with the input datatypes. Do not use this if
|
|
|
|
* you need an exact- or binary-compatible match; see compatible_oper.
|
|
|
|
*
|
2000-11-16 23:30:52 +01:00
|
|
|
* If no matching operator found, return NULL if noError is true,
|
2006-03-14 23:48:25 +01:00
|
|
|
* raise an error if it is false. pstate and location are used only to report
|
|
|
|
* the error position; pass NULL/-1 if not available.
|
2000-11-16 23:30:52 +01:00
|
|
|
*
|
|
|
|
* NOTE: on success, the returned object is a syscache entry. The caller
|
|
|
|
* must ReleaseSysCache() the entry when done with it.
|
1998-05-29 16:00:24 +02:00
|
|
|
*/
|
|
|
|
Operator
|
2006-03-14 23:48:25 +01:00
|
|
|
oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
|
|
|
|
bool noError, int location)
|
1998-05-29 16:00:24 +02:00
|
|
|
{
|
2003-07-04 04:51:34 +02:00
|
|
|
Oid operOid;
|
2007-11-28 19:47:56 +01:00
|
|
|
OprCacheKey key;
|
|
|
|
bool key_ok;
|
2003-07-04 04:51:34 +02:00
|
|
|
FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
|
2002-04-17 01:08:12 +02:00
|
|
|
HeapTuple tup = NULL;
|
1998-05-29 16:00:24 +02:00
|
|
|
|
2007-11-28 19:47:56 +01:00
|
|
|
/*
|
|
|
|
* Try to find the mapping in the lookaside cache.
|
|
|
|
*/
|
2015-03-18 18:48:02 +01:00
|
|
|
key_ok = make_oper_cache_key(pstate, &key, opname, ltypeId, rtypeId, location);
|
|
|
|
|
2007-11-28 19:47:56 +01:00
|
|
|
if (key_ok)
|
|
|
|
{
|
|
|
|
operOid = find_oper_cache_entry(&key);
|
|
|
|
if (OidIsValid(operOid))
|
|
|
|
{
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
|
2007-11-28 19:47:56 +01:00
|
|
|
if (HeapTupleIsValid(tup))
|
|
|
|
return (Operator) tup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-02 01:22:43 +02:00
|
|
|
/*
|
|
|
|
* First try for an "exact" match.
|
|
|
|
*/
|
|
|
|
operOid = binary_oper_exact(opname, ltypeId, rtypeId);
|
|
|
|
if (!OidIsValid(operOid))
|
2002-04-17 01:08:12 +02:00
|
|
|
{
|
|
|
|
/*
|
2006-05-02 01:22:43 +02:00
|
|
|
* Otherwise, search for the most suitable candidate.
|
2002-04-17 01:08:12 +02:00
|
|
|
*/
|
2006-05-02 01:22:43 +02:00
|
|
|
FuncCandidateList clist;
|
2000-11-16 23:30:52 +01:00
|
|
|
|
2006-05-02 01:22:43 +02:00
|
|
|
/* Get binary operators of given name */
|
2014-04-08 16:27:56 +02:00
|
|
|
clist = OpernameGetCandidates(opname, 'b', false);
|
2006-05-02 01:22:43 +02:00
|
|
|
|
|
|
|
/* No operators found? Then fail... */
|
|
|
|
if (clist != NULL)
|
|
|
|
{
|
2002-04-17 01:08:12 +02:00
|
|
|
/*
|
|
|
|
* Unspecified type for one of the arguments? then use the other
|
2003-05-26 02:11:29 +02:00
|
|
|
* (XXX this is probably dead code?)
|
2002-04-17 01:08:12 +02:00
|
|
|
*/
|
2006-05-02 01:22:43 +02:00
|
|
|
Oid inputOids[2];
|
|
|
|
|
2002-04-17 01:08:12 +02:00
|
|
|
if (rtypeId == InvalidOid)
|
|
|
|
rtypeId = ltypeId;
|
|
|
|
else if (ltypeId == InvalidOid)
|
|
|
|
ltypeId = rtypeId;
|
|
|
|
inputOids[0] = ltypeId;
|
|
|
|
inputOids[1] = rtypeId;
|
2003-07-04 04:51:34 +02:00
|
|
|
fdresult = oper_select_candidate(2, inputOids, clist, &operOid);
|
2002-04-17 01:08:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-02 01:22:43 +02:00
|
|
|
if (OidIsValid(operOid))
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
|
2006-05-02 01:22:43 +02:00
|
|
|
|
2007-11-28 19:47:56 +01:00
|
|
|
if (HeapTupleIsValid(tup))
|
|
|
|
{
|
|
|
|
if (key_ok)
|
|
|
|
make_oper_cache_entry(&key, operOid);
|
|
|
|
}
|
|
|
|
else if (!noError)
|
2006-03-14 23:48:25 +01:00
|
|
|
op_error(pstate, opname, 'b', ltypeId, rtypeId, fdresult, location);
|
1998-05-29 16:00:24 +02:00
|
|
|
|
2002-04-17 01:08:12 +02:00
|
|
|
return (Operator) tup;
|
2000-11-16 23:30:52 +01:00
|
|
|
}
|
|
|
|
|
Clean up two rather nasty bugs in operator selection code.
1. If there is exactly one pg_operator entry of the right name and oprkind,
oper() and related routines would return that entry whether its input type
had anything to do with the request or not. This is just premature
optimization: we shouldn't return the single candidate until after we verify
that it really is a valid candidate, ie, is at least coercion-compatible
with the given types.
2. oper() and related routines only promise a coercion-compatible result.
Unfortunately, there were quite a few callers that assumed the returned
operator is binary-compatible with the given datatype; they would proceed
to call it without making any datatype coercions. These callers include
sorting, grouping, aggregation, and VACUUM ANALYZE. In general I think
it is appropriate for these callers to require an exact or binary-compatible
match, so I've added a new routine compatible_oper() that only succeeds if
it can find an operator that doesn't require any run-time conversions.
Callers now call oper() or compatible_oper() depending on whether they are
prepared to deal with type conversion or not.
The upshot of these bugs is revealed by the following silliness in PL/Tcl's
selftest: it creates an operator @< on int4, and then tries to use it to
sort a char(N) column. The system would let it do that :-( (and evidently
has done so since 6.3 :-( :-(). The result in this case was just a silly
sort order, but the reverse combination would've provoked coredump from
trying to dereference integers. With this fix you get more reasonable
behavior:
pltcl_test=# select * from T_pkey1 order by key1, key2 using @<;
ERROR: Unable to identify an operator '@<' for types 'bpchar' and 'bpchar'
You will have to retype this query using an explicit cast
2001-02-16 04:16:58 +01:00
|
|
|
/* compatible_oper()
|
|
|
|
* given an opname and input datatypes, find a compatible binary operator
|
|
|
|
*
|
|
|
|
* This is tighter than oper() because it will not return an operator that
|
|
|
|
* requires coercion of the input datatypes (but binary-compatible operators
|
|
|
|
* are accepted). Otherwise, the semantics are the same.
|
|
|
|
*/
|
|
|
|
Operator
|
2006-03-14 23:48:25 +01:00
|
|
|
compatible_oper(ParseState *pstate, List *op, Oid arg1, Oid arg2,
|
|
|
|
bool noError, int location)
|
Clean up two rather nasty bugs in operator selection code.
1. If there is exactly one pg_operator entry of the right name and oprkind,
oper() and related routines would return that entry whether its input type
had anything to do with the request or not. This is just premature
optimization: we shouldn't return the single candidate until after we verify
that it really is a valid candidate, ie, is at least coercion-compatible
with the given types.
2. oper() and related routines only promise a coercion-compatible result.
Unfortunately, there were quite a few callers that assumed the returned
operator is binary-compatible with the given datatype; they would proceed
to call it without making any datatype coercions. These callers include
sorting, grouping, aggregation, and VACUUM ANALYZE. In general I think
it is appropriate for these callers to require an exact or binary-compatible
match, so I've added a new routine compatible_oper() that only succeeds if
it can find an operator that doesn't require any run-time conversions.
Callers now call oper() or compatible_oper() depending on whether they are
prepared to deal with type conversion or not.
The upshot of these bugs is revealed by the following silliness in PL/Tcl's
selftest: it creates an operator @< on int4, and then tries to use it to
sort a char(N) column. The system would let it do that :-( (and evidently
has done so since 6.3 :-( :-(). The result in this case was just a silly
sort order, but the reverse combination would've provoked coredump from
trying to dereference integers. With this fix you get more reasonable
behavior:
pltcl_test=# select * from T_pkey1 order by key1, key2 using @<;
ERROR: Unable to identify an operator '@<' for types 'bpchar' and 'bpchar'
You will have to retype this query using an explicit cast
2001-02-16 04:16:58 +01:00
|
|
|
{
|
|
|
|
Operator optup;
|
|
|
|
Form_pg_operator opform;
|
|
|
|
|
|
|
|
/* oper() will find the best available match */
|
2006-03-14 23:48:25 +01:00
|
|
|
optup = oper(pstate, op, arg1, arg2, noError, location);
|
Clean up two rather nasty bugs in operator selection code.
1. If there is exactly one pg_operator entry of the right name and oprkind,
oper() and related routines would return that entry whether its input type
had anything to do with the request or not. This is just premature
optimization: we shouldn't return the single candidate until after we verify
that it really is a valid candidate, ie, is at least coercion-compatible
with the given types.
2. oper() and related routines only promise a coercion-compatible result.
Unfortunately, there were quite a few callers that assumed the returned
operator is binary-compatible with the given datatype; they would proceed
to call it without making any datatype coercions. These callers include
sorting, grouping, aggregation, and VACUUM ANALYZE. In general I think
it is appropriate for these callers to require an exact or binary-compatible
match, so I've added a new routine compatible_oper() that only succeeds if
it can find an operator that doesn't require any run-time conversions.
Callers now call oper() or compatible_oper() depending on whether they are
prepared to deal with type conversion or not.
The upshot of these bugs is revealed by the following silliness in PL/Tcl's
selftest: it creates an operator @< on int4, and then tries to use it to
sort a char(N) column. The system would let it do that :-( (and evidently
has done so since 6.3 :-( :-(). The result in this case was just a silly
sort order, but the reverse combination would've provoked coredump from
trying to dereference integers. With this fix you get more reasonable
behavior:
pltcl_test=# select * from T_pkey1 order by key1, key2 using @<;
ERROR: Unable to identify an operator '@<' for types 'bpchar' and 'bpchar'
You will have to retype this query using an explicit cast
2001-02-16 04:16:58 +01:00
|
|
|
if (optup == (Operator) NULL)
|
|
|
|
return (Operator) NULL; /* must be noError case */
|
|
|
|
|
|
|
|
/* but is it good enough? */
|
|
|
|
opform = (Form_pg_operator) GETSTRUCT(optup);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
if (IsBinaryCoercible(arg1, opform->oprleft) &&
|
|
|
|
IsBinaryCoercible(arg2, opform->oprright))
|
Clean up two rather nasty bugs in operator selection code.
1. If there is exactly one pg_operator entry of the right name and oprkind,
oper() and related routines would return that entry whether its input type
had anything to do with the request or not. This is just premature
optimization: we shouldn't return the single candidate until after we verify
that it really is a valid candidate, ie, is at least coercion-compatible
with the given types.
2. oper() and related routines only promise a coercion-compatible result.
Unfortunately, there were quite a few callers that assumed the returned
operator is binary-compatible with the given datatype; they would proceed
to call it without making any datatype coercions. These callers include
sorting, grouping, aggregation, and VACUUM ANALYZE. In general I think
it is appropriate for these callers to require an exact or binary-compatible
match, so I've added a new routine compatible_oper() that only succeeds if
it can find an operator that doesn't require any run-time conversions.
Callers now call oper() or compatible_oper() depending on whether they are
prepared to deal with type conversion or not.
The upshot of these bugs is revealed by the following silliness in PL/Tcl's
selftest: it creates an operator @< on int4, and then tries to use it to
sort a char(N) column. The system would let it do that :-( (and evidently
has done so since 6.3 :-( :-(). The result in this case was just a silly
sort order, but the reverse combination would've provoked coredump from
trying to dereference integers. With this fix you get more reasonable
behavior:
pltcl_test=# select * from T_pkey1 order by key1, key2 using @<;
ERROR: Unable to identify an operator '@<' for types 'bpchar' and 'bpchar'
You will have to retype this query using an explicit cast
2001-02-16 04:16:58 +01:00
|
|
|
return optup;
|
|
|
|
|
2001-04-23 06:32:30 +02:00
|
|
|
/* nope... */
|
|
|
|
ReleaseSysCache(optup);
|
|
|
|
|
Clean up two rather nasty bugs in operator selection code.
1. If there is exactly one pg_operator entry of the right name and oprkind,
oper() and related routines would return that entry whether its input type
had anything to do with the request or not. This is just premature
optimization: we shouldn't return the single candidate until after we verify
that it really is a valid candidate, ie, is at least coercion-compatible
with the given types.
2. oper() and related routines only promise a coercion-compatible result.
Unfortunately, there were quite a few callers that assumed the returned
operator is binary-compatible with the given datatype; they would proceed
to call it without making any datatype coercions. These callers include
sorting, grouping, aggregation, and VACUUM ANALYZE. In general I think
it is appropriate for these callers to require an exact or binary-compatible
match, so I've added a new routine compatible_oper() that only succeeds if
it can find an operator that doesn't require any run-time conversions.
Callers now call oper() or compatible_oper() depending on whether they are
prepared to deal with type conversion or not.
The upshot of these bugs is revealed by the following silliness in PL/Tcl's
selftest: it creates an operator @< on int4, and then tries to use it to
sort a char(N) column. The system would let it do that :-( (and evidently
has done so since 6.3 :-( :-(). The result in this case was just a silly
sort order, but the reverse combination would've provoked coredump from
trying to dereference integers. With this fix you get more reasonable
behavior:
pltcl_test=# select * from T_pkey1 order by key1, key2 using @<;
ERROR: Unable to identify an operator '@<' for types 'bpchar' and 'bpchar'
You will have to retype this query using an explicit cast
2001-02-16 04:16:58 +01:00
|
|
|
if (!noError)
|
2003-07-19 01:20:33 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("operator requires run-time type coercion: %s",
|
2006-03-14 23:48:25 +01:00
|
|
|
op_signature_string(op, 'b', arg1, arg2)),
|
|
|
|
parser_errposition(pstate, location)));
|
Clean up two rather nasty bugs in operator selection code.
1. If there is exactly one pg_operator entry of the right name and oprkind,
oper() and related routines would return that entry whether its input type
had anything to do with the request or not. This is just premature
optimization: we shouldn't return the single candidate until after we verify
that it really is a valid candidate, ie, is at least coercion-compatible
with the given types.
2. oper() and related routines only promise a coercion-compatible result.
Unfortunately, there were quite a few callers that assumed the returned
operator is binary-compatible with the given datatype; they would proceed
to call it without making any datatype coercions. These callers include
sorting, grouping, aggregation, and VACUUM ANALYZE. In general I think
it is appropriate for these callers to require an exact or binary-compatible
match, so I've added a new routine compatible_oper() that only succeeds if
it can find an operator that doesn't require any run-time conversions.
Callers now call oper() or compatible_oper() depending on whether they are
prepared to deal with type conversion or not.
The upshot of these bugs is revealed by the following silliness in PL/Tcl's
selftest: it creates an operator @< on int4, and then tries to use it to
sort a char(N) column. The system would let it do that :-( (and evidently
has done so since 6.3 :-( :-(). The result in this case was just a silly
sort order, but the reverse combination would've provoked coredump from
trying to dereference integers. With this fix you get more reasonable
behavior:
pltcl_test=# select * from T_pkey1 order by key1, key2 using @<;
ERROR: Unable to identify an operator '@<' for types 'bpchar' and 'bpchar'
You will have to retype this query using an explicit cast
2001-02-16 04:16:58 +01:00
|
|
|
|
|
|
|
return (Operator) NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compatible_oper_opid() -- get OID of a binary operator
|
2000-11-16 23:30:52 +01:00
|
|
|
*
|
|
|
|
* This is a convenience routine that extracts only the operator OID
|
Clean up two rather nasty bugs in operator selection code.
1. If there is exactly one pg_operator entry of the right name and oprkind,
oper() and related routines would return that entry whether its input type
had anything to do with the request or not. This is just premature
optimization: we shouldn't return the single candidate until after we verify
that it really is a valid candidate, ie, is at least coercion-compatible
with the given types.
2. oper() and related routines only promise a coercion-compatible result.
Unfortunately, there were quite a few callers that assumed the returned
operator is binary-compatible with the given datatype; they would proceed
to call it without making any datatype coercions. These callers include
sorting, grouping, aggregation, and VACUUM ANALYZE. In general I think
it is appropriate for these callers to require an exact or binary-compatible
match, so I've added a new routine compatible_oper() that only succeeds if
it can find an operator that doesn't require any run-time conversions.
Callers now call oper() or compatible_oper() depending on whether they are
prepared to deal with type conversion or not.
The upshot of these bugs is revealed by the following silliness in PL/Tcl's
selftest: it creates an operator @< on int4, and then tries to use it to
sort a char(N) column. The system would let it do that :-( (and evidently
has done so since 6.3 :-( :-(). The result in this case was just a silly
sort order, but the reverse combination would've provoked coredump from
trying to dereference integers. With this fix you get more reasonable
behavior:
pltcl_test=# select * from T_pkey1 order by key1, key2 using @<;
ERROR: Unable to identify an operator '@<' for types 'bpchar' and 'bpchar'
You will have to retype this query using an explicit cast
2001-02-16 04:16:58 +01:00
|
|
|
* from the result of compatible_oper(). InvalidOid is returned if the
|
|
|
|
* lookup fails and noError is true.
|
2000-11-16 23:30:52 +01:00
|
|
|
*/
|
|
|
|
Oid
|
2002-04-17 01:08:12 +02:00
|
|
|
compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
|
2000-11-16 23:30:52 +01:00
|
|
|
{
|
|
|
|
Operator optup;
|
|
|
|
Oid result;
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2006-03-14 23:48:25 +01:00
|
|
|
optup = compatible_oper(NULL, op, arg1, arg2, noError, -1);
|
2000-11-16 23:30:52 +01:00
|
|
|
if (optup != NULL)
|
|
|
|
{
|
|
|
|
result = oprid(optup);
|
|
|
|
ReleaseSysCache(optup);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return InvalidOid;
|
|
|
|
}
|
1998-05-10 01:31:34 +02:00
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
/* left_oper() -- search for a unary left operator (prefix operator)
|
2002-05-01 21:26:08 +02:00
|
|
|
* Given operator name and type of arg, return oper struct.
|
Clean up two rather nasty bugs in operator selection code.
1. If there is exactly one pg_operator entry of the right name and oprkind,
oper() and related routines would return that entry whether its input type
had anything to do with the request or not. This is just premature
optimization: we shouldn't return the single candidate until after we verify
that it really is a valid candidate, ie, is at least coercion-compatible
with the given types.
2. oper() and related routines only promise a coercion-compatible result.
Unfortunately, there were quite a few callers that assumed the returned
operator is binary-compatible with the given datatype; they would proceed
to call it without making any datatype coercions. These callers include
sorting, grouping, aggregation, and VACUUM ANALYZE. In general I think
it is appropriate for these callers to require an exact or binary-compatible
match, so I've added a new routine compatible_oper() that only succeeds if
it can find an operator that doesn't require any run-time conversions.
Callers now call oper() or compatible_oper() depending on whether they are
prepared to deal with type conversion or not.
The upshot of these bugs is revealed by the following silliness in PL/Tcl's
selftest: it creates an operator @< on int4, and then tries to use it to
sort a char(N) column. The system would let it do that :-( (and evidently
has done so since 6.3 :-( :-(). The result in this case was just a silly
sort order, but the reverse combination would've provoked coredump from
trying to dereference integers. With this fix you get more reasonable
behavior:
pltcl_test=# select * from T_pkey1 order by key1, key2 using @<;
ERROR: Unable to identify an operator '@<' for types 'bpchar' and 'bpchar'
You will have to retype this query using an explicit cast
2001-02-16 04:16:58 +01:00
|
|
|
*
|
|
|
|
* 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.
|
2000-11-16 23:30:52 +01:00
|
|
|
*
|
2002-05-01 21:26:08 +02:00
|
|
|
* If no matching operator found, return NULL if noError is true,
|
2006-03-14 23:48:25 +01:00
|
|
|
* raise an error if it is false. pstate and location are used only to report
|
|
|
|
* the error position; pass NULL/-1 if not available.
|
2000-11-16 23:30:52 +01:00
|
|
|
*
|
|
|
|
* NOTE: on success, the returned object is a syscache entry. The caller
|
|
|
|
* must ReleaseSysCache() the entry when done with it.
|
|
|
|
*/
|
1997-11-25 23:07:18 +01:00
|
|
|
Operator
|
2006-03-14 23:48:25 +01:00
|
|
|
left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2006-05-02 01:22:43 +02:00
|
|
|
Oid operOid;
|
2007-11-28 19:47:56 +01:00
|
|
|
OprCacheKey key;
|
|
|
|
bool key_ok;
|
2003-07-04 04:51:34 +02:00
|
|
|
FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
|
2002-04-17 01:08:12 +02:00
|
|
|
HeapTuple tup = NULL;
|
1998-05-10 01:31:34 +02:00
|
|
|
|
2007-11-28 19:47:56 +01:00
|
|
|
/*
|
|
|
|
* Try to find the mapping in the lookaside cache.
|
|
|
|
*/
|
2015-03-18 18:48:02 +01:00
|
|
|
key_ok = make_oper_cache_key(pstate, &key, op, InvalidOid, arg, location);
|
|
|
|
|
2007-11-28 19:47:56 +01:00
|
|
|
if (key_ok)
|
|
|
|
{
|
|
|
|
operOid = find_oper_cache_entry(&key);
|
|
|
|
if (OidIsValid(operOid))
|
|
|
|
{
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
|
2007-11-28 19:47:56 +01:00
|
|
|
if (HeapTupleIsValid(tup))
|
|
|
|
return (Operator) tup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-02 01:22:43 +02:00
|
|
|
/*
|
|
|
|
* First try for an "exact" match.
|
|
|
|
*/
|
|
|
|
operOid = OpernameGetOprid(op, InvalidOid, arg);
|
|
|
|
if (!OidIsValid(operOid))
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2002-04-17 01:08:12 +02:00
|
|
|
/*
|
2006-05-02 01:22:43 +02:00
|
|
|
* Otherwise, search for the most suitable candidate.
|
2002-04-17 01:08:12 +02:00
|
|
|
*/
|
2006-05-02 01:22:43 +02:00
|
|
|
FuncCandidateList clist;
|
|
|
|
|
|
|
|
/* Get prefix operators of given name */
|
2014-04-08 16:27:56 +02:00
|
|
|
clist = OpernameGetCandidates(op, 'l', false);
|
2002-04-17 01:08:12 +02:00
|
|
|
|
2006-05-02 01:22:43 +02:00
|
|
|
/* No operators found? Then fail... */
|
|
|
|
if (clist != NULL)
|
2002-04-17 01:08:12 +02:00
|
|
|
{
|
2006-05-02 01:22:43 +02:00
|
|
|
/*
|
|
|
|
* The returned list has args in the form (0, oprright). Move the
|
|
|
|
* useful data into args[0] to keep oper_select_candidate simple.
|
|
|
|
* XXX we are assuming here that we may scribble on the list!
|
|
|
|
*/
|
|
|
|
FuncCandidateList clisti;
|
|
|
|
|
|
|
|
for (clisti = clist; clisti != NULL; clisti = clisti->next)
|
2002-04-17 01:08:12 +02:00
|
|
|
{
|
2006-05-02 01:22:43 +02:00
|
|
|
clisti->args[0] = clisti->args[1];
|
2002-04-17 01:08:12 +02:00
|
|
|
}
|
|
|
|
|
Clean up two rather nasty bugs in operator selection code.
1. If there is exactly one pg_operator entry of the right name and oprkind,
oper() and related routines would return that entry whether its input type
had anything to do with the request or not. This is just premature
optimization: we shouldn't return the single candidate until after we verify
that it really is a valid candidate, ie, is at least coercion-compatible
with the given types.
2. oper() and related routines only promise a coercion-compatible result.
Unfortunately, there were quite a few callers that assumed the returned
operator is binary-compatible with the given datatype; they would proceed
to call it without making any datatype coercions. These callers include
sorting, grouping, aggregation, and VACUUM ANALYZE. In general I think
it is appropriate for these callers to require an exact or binary-compatible
match, so I've added a new routine compatible_oper() that only succeeds if
it can find an operator that doesn't require any run-time conversions.
Callers now call oper() or compatible_oper() depending on whether they are
prepared to deal with type conversion or not.
The upshot of these bugs is revealed by the following silliness in PL/Tcl's
selftest: it creates an operator @< on int4, and then tries to use it to
sort a char(N) column. The system would let it do that :-( (and evidently
has done so since 6.3 :-( :-(). The result in this case was just a silly
sort order, but the reverse combination would've provoked coredump from
trying to dereference integers. With this fix you get more reasonable
behavior:
pltcl_test=# select * from T_pkey1 order by key1, key2 using @<;
ERROR: Unable to identify an operator '@<' for types 'bpchar' and 'bpchar'
You will have to retype this query using an explicit cast
2001-02-16 04:16:58 +01:00
|
|
|
/*
|
|
|
|
* We must run oper_select_candidate even if only one candidate,
|
|
|
|
* otherwise we may falsely return a non-type-compatible operator.
|
|
|
|
*/
|
2003-07-04 04:51:34 +02:00
|
|
|
fdresult = oper_select_candidate(1, &arg, clist, &operOid);
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
|
|
|
}
|
2000-02-27 03:48:15 +01:00
|
|
|
|
2006-05-02 01:22:43 +02:00
|
|
|
if (OidIsValid(operOid))
|
2010-02-14 19:42:19 +01:00
|
|
|
tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
|
2006-05-02 01:22:43 +02:00
|
|
|
|
2007-11-28 19:47:56 +01:00
|
|
|
if (HeapTupleIsValid(tup))
|
|
|
|
{
|
|
|
|
if (key_ok)
|
|
|
|
make_oper_cache_entry(&key, operOid);
|
|
|
|
}
|
|
|
|
else if (!noError)
|
2006-03-14 23:48:25 +01:00
|
|
|
op_error(pstate, op, 'l', InvalidOid, arg, fdresult, location);
|
2002-04-17 01:08:12 +02:00
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
return (Operator) tup;
|
2002-05-01 21:26:08 +02:00
|
|
|
}
|
1997-11-25 23:07:18 +01:00
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
/*
|
|
|
|
* op_signature_string
|
|
|
|
* Build a string representing an operator name, including arg type(s).
|
|
|
|
* The result is something like "integer + integer".
|
|
|
|
*
|
|
|
|
* This is typically used in the construction of operator-not-found error
|
|
|
|
* messages.
|
1997-11-25 23:07:18 +01:00
|
|
|
*/
|
2003-07-04 04:51:34 +02:00
|
|
|
static const char *
|
|
|
|
op_signature_string(List *op, char oprkind, Oid arg1, Oid arg2)
|
1997-11-25 23:07:18 +01:00
|
|
|
{
|
2003-07-04 04:51:34 +02:00
|
|
|
StringInfoData argbuf;
|
|
|
|
|
|
|
|
initStringInfo(&argbuf);
|
|
|
|
|
|
|
|
if (oprkind != 'l')
|
|
|
|
appendStringInfo(&argbuf, "%s ", format_type_be(arg1));
|
|
|
|
|
|
|
|
appendStringInfoString(&argbuf, NameListToString(op));
|
|
|
|
|
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
2020-09-18 01:38:05 +02:00
|
|
|
appendStringInfo(&argbuf, " %s", format_type_be(arg2));
|
2003-07-04 04:51:34 +02:00
|
|
|
|
|
|
|
return argbuf.data; /* return palloc'd string buffer */
|
1997-11-25 23:07:18 +01:00
|
|
|
}
|
2000-02-27 03:48:15 +01:00
|
|
|
|
2003-07-04 04:51:34 +02:00
|
|
|
/*
|
|
|
|
* op_error - utility routine to complain about an unresolvable operator
|
2000-02-27 03:48:15 +01:00
|
|
|
*/
|
|
|
|
static void
|
2006-03-14 23:48:25 +01:00
|
|
|
op_error(ParseState *pstate, List *op, char oprkind,
|
|
|
|
Oid arg1, Oid arg2,
|
|
|
|
FuncDetailCode fdresult, int location)
|
2000-02-27 03:48:15 +01:00
|
|
|
{
|
2003-07-04 04:51:34 +02:00
|
|
|
if (fdresult == FUNCDETAIL_MULTIPLE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
|
|
|
|
errmsg("operator is not unique: %s",
|
|
|
|
op_signature_string(op, oprkind, arg1, arg2)),
|
2003-07-28 02:09:16 +02:00
|
|
|
errhint("Could not choose a best candidate operator. "
|
Wording cleanup for error messages. Also change can't -> cannot.
Standard English uses "may", "can", and "might" in different ways:
may - permission, "You may borrow my rake."
can - ability, "I can lift that log."
might - possibility, "It might rain today."
Unfortunately, in conversational English, their use is often mixed, as
in, "You may use this variable to do X", when in fact, "can" is a better
choice. Similarly, "It may crash" is better stated, "It might crash".
2007-02-01 20:10:30 +01:00
|
|
|
"You might need to add explicit type casts."),
|
2006-03-14 23:48:25 +01:00
|
|
|
parser_errposition(pstate, location)));
|
2001-08-09 20:28:18 +02:00
|
|
|
else
|
2003-07-04 04:51:34 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("operator does not exist: %s",
|
|
|
|
op_signature_string(op, oprkind, arg1, arg2)),
|
2017-08-23 19:56:59 +02:00
|
|
|
(!arg1 || !arg2) ?
|
|
|
|
errhint("No operator matches the given name and argument type. "
|
|
|
|
"You might need to add an explicit type cast.") :
|
|
|
|
errhint("No operator matches the given name and argument types. "
|
Wording cleanup for error messages. Also change can't -> cannot.
Standard English uses "may", "can", and "might" in different ways:
may - permission, "You may borrow my rake."
can - ability, "I can lift that log."
might - possibility, "It might rain today."
Unfortunately, in conversational English, their use is often mixed, as
in, "You may use this variable to do X", when in fact, "can" is a better
choice. Similarly, "It may crash" is better stated, "It might crash".
2007-02-01 20:10:30 +01:00
|
|
|
"You might need to add explicit type casts."),
|
2006-03-14 23:48:25 +01:00
|
|
|
parser_errposition(pstate, location)));
|
2000-02-27 03:48:15 +01:00
|
|
|
}
|
2003-04-09 01:20:04 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* make_op()
|
|
|
|
* Operator expression construction.
|
|
|
|
*
|
|
|
|
* Transform operator expression ensuring type compatibility.
|
|
|
|
* This is where some type conversion happens.
|
2003-04-30 00:13:11 +02:00
|
|
|
*
|
Disallow set-returning functions inside CASE or COALESCE.
When we reimplemented SRFs in commit 69f4b9c85, our initial choice was
to allow the behavior to vary from historical practice in cases where a
SRF call appeared within a conditional-execution construct (currently,
only CASE or COALESCE). But that was controversial to begin with, and
subsequent discussion has resulted in a consensus that it's better to
throw an error instead of executing the query differently from before,
so long as we can provide a reasonably clear error message and a way to
rewrite the query.
Hence, add a parser mechanism to allow detection of such cases during
parse analysis. The mechanism just requires storing, in the ParseState,
a pointer to the set-returning FuncExpr or OpExpr most recently emitted
by parse analysis. Then the parsing functions for CASE and COALESCE can
detect the presence of a SRF in their arguments by noting whether this
pointer changes while analyzing their arguments. Furthermore, if it does,
it provides a suitable error cursor location for the complaint. (This
means that if there's more than one SRF in the arguments, the error will
point at the last one to be analyzed not the first. While connoisseurs of
parsing behavior might find that odd, it's unlikely the average user would
ever notice.)
While at it, we can also provide more specific error messages than before
about some pre-existing restrictions, such as no-SRFs-within-aggregates.
Also, reject at parse time cases where a NULLIF or IS DISTINCT FROM
construct would need to return a set. We've never supported that, but the
restriction is depended on in more subtle ways now, so it seems wise to
detect it at the start.
Also, provide some documentation about how to rewrite a SRF-within-CASE
query using a custom wrapper SRF.
It turns out that the information_schema.user_mapping_options view
contained an instance of exactly the behavior we're now forbidding; but
rewriting it makes it more clear and safer too.
initdb forced because of user_mapping_options change.
Patch by me, with error message suggestions from Alvaro Herrera and
Andres Freund, pursuant to a complaint from Regina Obe.
Discussion: https://postgr.es/m/000001d2d5de$d8d66170$8a832450$@pcorp.us
2017-06-14 05:46:39 +02:00
|
|
|
* last_srf should be a copy of pstate->p_last_srf from just before we
|
|
|
|
* started transforming the operator's arguments; this is used for nested-SRF
|
|
|
|
* detection. If the caller will throw an error anyway for a set-returning
|
|
|
|
* expression, it's okay to cheat and just pass pstate->p_last_srf.
|
2003-04-09 01:20:04 +02:00
|
|
|
*/
|
|
|
|
Expr *
|
2006-03-14 23:48:25 +01:00
|
|
|
make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
|
Disallow set-returning functions inside CASE or COALESCE.
When we reimplemented SRFs in commit 69f4b9c85, our initial choice was
to allow the behavior to vary from historical practice in cases where a
SRF call appeared within a conditional-execution construct (currently,
only CASE or COALESCE). But that was controversial to begin with, and
subsequent discussion has resulted in a consensus that it's better to
throw an error instead of executing the query differently from before,
so long as we can provide a reasonably clear error message and a way to
rewrite the query.
Hence, add a parser mechanism to allow detection of such cases during
parse analysis. The mechanism just requires storing, in the ParseState,
a pointer to the set-returning FuncExpr or OpExpr most recently emitted
by parse analysis. Then the parsing functions for CASE and COALESCE can
detect the presence of a SRF in their arguments by noting whether this
pointer changes while analyzing their arguments. Furthermore, if it does,
it provides a suitable error cursor location for the complaint. (This
means that if there's more than one SRF in the arguments, the error will
point at the last one to be analyzed not the first. While connoisseurs of
parsing behavior might find that odd, it's unlikely the average user would
ever notice.)
While at it, we can also provide more specific error messages than before
about some pre-existing restrictions, such as no-SRFs-within-aggregates.
Also, reject at parse time cases where a NULLIF or IS DISTINCT FROM
construct would need to return a set. We've never supported that, but the
restriction is depended on in more subtle ways now, so it seems wise to
detect it at the start.
Also, provide some documentation about how to rewrite a SRF-within-CASE
query using a custom wrapper SRF.
It turns out that the information_schema.user_mapping_options view
contained an instance of exactly the behavior we're now forbidding; but
rewriting it makes it more clear and safer too.
initdb forced because of user_mapping_options change.
Patch by me, with error message suggestions from Alvaro Herrera and
Andres Freund, pursuant to a complaint from Regina Obe.
Discussion: https://postgr.es/m/000001d2d5de$d8d66170$8a832450$@pcorp.us
2017-06-14 05:46:39 +02:00
|
|
|
Node *last_srf, int location)
|
2003-04-09 01:20:04 +02:00
|
|
|
{
|
|
|
|
Oid ltypeId,
|
|
|
|
rtypeId;
|
|
|
|
Operator tup;
|
2008-04-22 03:34:34 +02:00
|
|
|
Form_pg_operator opform;
|
|
|
|
Oid actual_arg_types[2];
|
|
|
|
Oid declared_arg_types[2];
|
|
|
|
int nargs;
|
|
|
|
List *args;
|
|
|
|
Oid rettype;
|
|
|
|
OpExpr *result;
|
2003-04-09 01:20:04 +02: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
2020-09-18 01:38:05 +02:00
|
|
|
/* Check it's not a postfix operator */
|
2003-04-09 01:20:04 +02:00
|
|
|
if (rtree == NULL)
|
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
2020-09-18 01:38:05 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("postfix operators are not supported")));
|
|
|
|
|
|
|
|
/* Select the operator */
|
|
|
|
if (ltree == NULL)
|
2003-04-09 01:20:04 +02: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
2020-09-18 01:38:05 +02:00
|
|
|
/* prefix operator */
|
2003-04-09 01:20:04 +02:00
|
|
|
rtypeId = exprType(rtree);
|
|
|
|
ltypeId = InvalidOid;
|
2006-03-14 23:48:25 +01:00
|
|
|
tup = left_oper(pstate, opname, rtypeId, false, location);
|
2003-04-09 01:20:04 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* otherwise, binary operator */
|
|
|
|
ltypeId = exprType(ltree);
|
|
|
|
rtypeId = exprType(rtree);
|
2006-03-14 23:48:25 +01:00
|
|
|
tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
|
2003-04-09 01:20:04 +02:00
|
|
|
}
|
|
|
|
|
2008-04-22 03:34:34 +02:00
|
|
|
opform = (Form_pg_operator) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
/* Check it's not a shell */
|
|
|
|
if (!RegProcedureIsValid(opform->oprcode))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("operator is only a shell: %s",
|
|
|
|
op_signature_string(opname,
|
|
|
|
opform->oprkind,
|
|
|
|
opform->oprleft,
|
|
|
|
opform->oprright)),
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
|
2003-04-09 01:20:04 +02:00
|
|
|
/* Do typecasting and build the expression tree */
|
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
2020-09-18 01:38:05 +02:00
|
|
|
if (ltree == NULL)
|
2008-04-22 03:34:34 +02: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
2020-09-18 01:38:05 +02:00
|
|
|
/* prefix operator */
|
2008-04-22 03:34:34 +02:00
|
|
|
args = list_make1(rtree);
|
|
|
|
actual_arg_types[0] = rtypeId;
|
|
|
|
declared_arg_types[0] = opform->oprright;
|
|
|
|
nargs = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* otherwise, binary operator */
|
|
|
|
args = list_make2(ltree, rtree);
|
|
|
|
actual_arg_types[0] = ltypeId;
|
|
|
|
actual_arg_types[1] = rtypeId;
|
|
|
|
declared_arg_types[0] = opform->oprleft;
|
|
|
|
declared_arg_types[1] = opform->oprright;
|
|
|
|
nargs = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* enforce consistency with polymorphic argument and return types,
|
|
|
|
* possibly adjusting return type or declared_arg_types (which will be
|
|
|
|
* used as the cast destination by make_fn_arguments)
|
|
|
|
*/
|
|
|
|
rettype = enforce_generic_type_consistency(actual_arg_types,
|
|
|
|
declared_arg_types,
|
|
|
|
nargs,
|
|
|
|
opform->oprresult,
|
|
|
|
false);
|
|
|
|
|
|
|
|
/* perform the necessary typecasting of arguments */
|
|
|
|
make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types);
|
|
|
|
|
|
|
|
/* and build the expression node */
|
|
|
|
result = makeNode(OpExpr);
|
|
|
|
result->opno = oprid(tup);
|
|
|
|
result->opfuncid = opform->oprcode;
|
|
|
|
result->opresulttype = rettype;
|
|
|
|
result->opretset = get_func_retset(opform->oprcode);
|
2011-03-20 01:29:08 +01:00
|
|
|
/* opcollid and inputcollid will be set by parse_collate.c */
|
2008-04-22 03:34:34 +02:00
|
|
|
result->args = args;
|
2008-08-29 01:09:48 +02:00
|
|
|
result->location = location;
|
2003-04-09 01:20:04 +02:00
|
|
|
|
2016-09-13 19:54:24 +02:00
|
|
|
/* if it returns a set, check that's OK */
|
|
|
|
if (result->opretset)
|
Disallow set-returning functions inside CASE or COALESCE.
When we reimplemented SRFs in commit 69f4b9c85, our initial choice was
to allow the behavior to vary from historical practice in cases where a
SRF call appeared within a conditional-execution construct (currently,
only CASE or COALESCE). But that was controversial to begin with, and
subsequent discussion has resulted in a consensus that it's better to
throw an error instead of executing the query differently from before,
so long as we can provide a reasonably clear error message and a way to
rewrite the query.
Hence, add a parser mechanism to allow detection of such cases during
parse analysis. The mechanism just requires storing, in the ParseState,
a pointer to the set-returning FuncExpr or OpExpr most recently emitted
by parse analysis. Then the parsing functions for CASE and COALESCE can
detect the presence of a SRF in their arguments by noting whether this
pointer changes while analyzing their arguments. Furthermore, if it does,
it provides a suitable error cursor location for the complaint. (This
means that if there's more than one SRF in the arguments, the error will
point at the last one to be analyzed not the first. While connoisseurs of
parsing behavior might find that odd, it's unlikely the average user would
ever notice.)
While at it, we can also provide more specific error messages than before
about some pre-existing restrictions, such as no-SRFs-within-aggregates.
Also, reject at parse time cases where a NULLIF or IS DISTINCT FROM
construct would need to return a set. We've never supported that, but the
restriction is depended on in more subtle ways now, so it seems wise to
detect it at the start.
Also, provide some documentation about how to rewrite a SRF-within-CASE
query using a custom wrapper SRF.
It turns out that the information_schema.user_mapping_options view
contained an instance of exactly the behavior we're now forbidding; but
rewriting it makes it more clear and safer too.
initdb forced because of user_mapping_options change.
Patch by me, with error message suggestions from Alvaro Herrera and
Andres Freund, pursuant to a complaint from Regina Obe.
Discussion: https://postgr.es/m/000001d2d5de$d8d66170$8a832450$@pcorp.us
2017-06-14 05:46:39 +02:00
|
|
|
{
|
|
|
|
check_srf_call_placement(pstate, last_srf, location);
|
|
|
|
/* ... and remember it for error checks at higher levels */
|
|
|
|
pstate->p_last_srf = (Node *) result;
|
|
|
|
}
|
2016-09-13 19:54:24 +02:00
|
|
|
|
2003-04-09 01:20:04 +02:00
|
|
|
ReleaseSysCache(tup);
|
|
|
|
|
2008-04-22 03:34:34 +02:00
|
|
|
return (Expr *) result;
|
2003-04-09 01:20:04 +02:00
|
|
|
}
|
|
|
|
|
2003-06-29 02:33:44 +02:00
|
|
|
/*
|
|
|
|
* make_scalar_array_op()
|
|
|
|
* Build expression tree for "scalar op ANY/ALL (array)" construct.
|
|
|
|
*/
|
|
|
|
Expr *
|
|
|
|
make_scalar_array_op(ParseState *pstate, List *opname,
|
|
|
|
bool useOr,
|
2006-03-14 23:48:25 +01:00
|
|
|
Node *ltree, Node *rtree,
|
|
|
|
int location)
|
2003-06-29 02:33:44 +02:00
|
|
|
{
|
|
|
|
Oid ltypeId,
|
|
|
|
rtypeId,
|
|
|
|
atypeId,
|
|
|
|
res_atypeId;
|
|
|
|
Operator tup;
|
|
|
|
Form_pg_operator opform;
|
|
|
|
Oid actual_arg_types[2];
|
|
|
|
Oid declared_arg_types[2];
|
|
|
|
List *args;
|
|
|
|
Oid rettype;
|
|
|
|
ScalarArrayOpExpr *result;
|
|
|
|
|
|
|
|
ltypeId = exprType(ltree);
|
|
|
|
atypeId = exprType(rtree);
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2003-06-29 02:33:44 +02:00
|
|
|
/*
|
|
|
|
* The right-hand input of the operator will be the element type of the
|
|
|
|
* array. However, if we currently have just an untyped literal on the
|
|
|
|
* right, stay with that and hope we can resolve the operator.
|
|
|
|
*/
|
|
|
|
if (atypeId == UNKNOWNOID)
|
|
|
|
rtypeId = UNKNOWNOID;
|
|
|
|
else
|
|
|
|
{
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
rtypeId = get_base_element_type(atypeId);
|
2003-06-29 02:33:44 +02:00
|
|
|
if (!OidIsValid(rtypeId))
|
2003-07-19 01:20:33 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
2006-03-14 23:48:25 +01:00
|
|
|
errmsg("op ANY/ALL (array) requires array on right side"),
|
|
|
|
parser_errposition(pstate, location)));
|
2003-06-29 02:33:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Now resolve the operator */
|
2006-03-14 23:48:25 +01:00
|
|
|
tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
|
2003-06-29 02:33:44 +02:00
|
|
|
opform = (Form_pg_operator) GETSTRUCT(tup);
|
|
|
|
|
2008-04-22 03:34:34 +02:00
|
|
|
/* Check it's not a shell */
|
|
|
|
if (!RegProcedureIsValid(opform->oprcode))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("operator is only a shell: %s",
|
|
|
|
op_signature_string(opname,
|
|
|
|
opform->oprkind,
|
|
|
|
opform->oprleft,
|
|
|
|
opform->oprright)),
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
|
2004-05-31 01:40:41 +02:00
|
|
|
args = list_make2(ltree, rtree);
|
2003-06-29 02:33:44 +02:00
|
|
|
actual_arg_types[0] = ltypeId;
|
|
|
|
actual_arg_types[1] = rtypeId;
|
|
|
|
declared_arg_types[0] = opform->oprleft;
|
|
|
|
declared_arg_types[1] = opform->oprright;
|
|
|
|
|
|
|
|
/*
|
2007-04-02 05:49:42 +02:00
|
|
|
* enforce consistency with polymorphic argument and return types,
|
|
|
|
* possibly adjusting return type or declared_arg_types (which will be
|
2003-06-29 02:33:44 +02:00
|
|
|
* used as the cast destination by make_fn_arguments)
|
|
|
|
*/
|
|
|
|
rettype = enforce_generic_type_consistency(actual_arg_types,
|
|
|
|
declared_arg_types,
|
|
|
|
2,
|
2008-01-11 19:39:41 +01:00
|
|
|
opform->oprresult,
|
|
|
|
false);
|
2003-06-29 02:33:44 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that operator result is boolean
|
|
|
|
*/
|
|
|
|
if (rettype != BOOLOID)
|
2003-07-19 01:20:33 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
2006-03-14 23:48:25 +01:00
|
|
|
errmsg("op ANY/ALL (array) requires operator to yield boolean"),
|
|
|
|
parser_errposition(pstate, location)));
|
2003-06-29 02:33:44 +02:00
|
|
|
if (get_func_retset(opform->oprcode))
|
2003-07-19 01:20:33 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
2006-03-14 23:48:25 +01:00
|
|
|
errmsg("op ANY/ALL (array) requires operator not to return a set"),
|
|
|
|
parser_errposition(pstate, location)));
|
2003-06-29 02:33:44 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now switch back to the array type on the right, arranging for any
|
2007-04-02 05:49:42 +02:00
|
|
|
* needed cast to be applied. Beware of polymorphic operators here;
|
|
|
|
* enforce_generic_type_consistency may or may not have replaced a
|
|
|
|
* polymorphic type with a real one.
|
2003-06-29 02:33:44 +02:00
|
|
|
*/
|
2007-04-02 05:49:42 +02:00
|
|
|
if (IsPolymorphicType(declared_arg_types[1]))
|
|
|
|
{
|
|
|
|
/* assume the actual array type is OK */
|
|
|
|
res_atypeId = atypeId;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
res_atypeId = get_array_type(declared_arg_types[1]);
|
|
|
|
if (!OidIsValid(res_atypeId))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
errmsg("could not find array type for data type %s",
|
|
|
|
format_type_be(declared_arg_types[1])),
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
}
|
2003-06-29 02:33:44 +02:00
|
|
|
actual_arg_types[1] = atypeId;
|
|
|
|
declared_arg_types[1] = res_atypeId;
|
|
|
|
|
|
|
|
/* perform the necessary typecasting of arguments */
|
|
|
|
make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types);
|
|
|
|
|
|
|
|
/* and build the expression node */
|
|
|
|
result = makeNode(ScalarArrayOpExpr);
|
|
|
|
result->opno = oprid(tup);
|
2007-11-22 20:40:25 +01:00
|
|
|
result->opfuncid = opform->oprcode;
|
2021-04-08 13:51:22 +02:00
|
|
|
result->hashfuncid = InvalidOid;
|
2021-07-07 06:29:17 +02:00
|
|
|
result->negfuncid = InvalidOid;
|
2003-06-29 02:33:44 +02:00
|
|
|
result->useOr = useOr;
|
2011-03-20 01:29:08 +01:00
|
|
|
/* inputcollid will be set by parse_collate.c */
|
2003-06-29 02:33:44 +02:00
|
|
|
result->args = args;
|
2008-08-29 01:09:48 +02:00
|
|
|
result->location = location;
|
2003-06-29 02:33:44 +02:00
|
|
|
|
|
|
|
ReleaseSysCache(tup);
|
|
|
|
|
|
|
|
return (Expr *) result;
|
|
|
|
}
|
2003-04-09 01:20:04 +02:00
|
|
|
|
2007-11-28 19:47:56 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Lookaside cache to speed operator lookup. Possibly this should be in
|
|
|
|
* a separate module under utils/cache/ ?
|
|
|
|
*
|
|
|
|
* The idea here is that the mapping from operator name and given argument
|
|
|
|
* types is constant for a given search path (or single specified schema OID)
|
|
|
|
* so long as the contents of pg_operator and pg_cast don't change. And that
|
|
|
|
* mapping is pretty expensive to compute, especially for ambiguous operators;
|
|
|
|
* this is mainly because there are a *lot* of instances of popular operator
|
|
|
|
* names such as "=", and we have to check each one to see which is the
|
|
|
|
* best match. So once we have identified the correct mapping, we save it
|
|
|
|
* in a cache that need only be flushed on pg_operator or pg_cast change.
|
|
|
|
* (pg_cast must be considered because changes in the set of implicit casts
|
|
|
|
* affect the set of applicable operators for any given input datatype.)
|
|
|
|
*
|
|
|
|
* XXX in principle, ALTER TABLE ... INHERIT could affect the mapping as
|
|
|
|
* well, but we disregard that since there's no convenient way to find out
|
|
|
|
* about it, and it seems a pretty far-fetched corner-case anyway.
|
|
|
|
*
|
|
|
|
* Note: at some point it might be worth doing a similar cache for function
|
|
|
|
* lookups. However, the potential gain is a lot less since (a) function
|
|
|
|
* names are generally not overloaded as heavily as operator names, and
|
|
|
|
* (b) we'd have to flush on pg_proc updates, which are probably a good
|
|
|
|
* deal more common than pg_operator updates.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* The operator cache hashtable */
|
|
|
|
static HTAB *OprCacheHash = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* make_oper_cache_key
|
|
|
|
* Fill the lookup key struct given operator name and arg types.
|
|
|
|
*
|
2017-08-16 06:22:32 +02:00
|
|
|
* Returns true if successful, false if the search_path overflowed
|
2007-11-28 19:47:56 +01:00
|
|
|
* (hence no caching is possible).
|
2015-03-18 18:48:02 +01:00
|
|
|
*
|
|
|
|
* pstate/location are used only to report the error position; pass NULL/-1
|
|
|
|
* if not available.
|
2007-11-28 19:47:56 +01:00
|
|
|
*/
|
|
|
|
static bool
|
2015-03-18 18:48:02 +01:00
|
|
|
make_oper_cache_key(ParseState *pstate, OprCacheKey *key, List *opname,
|
|
|
|
Oid ltypeId, Oid rtypeId, int location)
|
2007-11-28 19:47:56 +01:00
|
|
|
{
|
|
|
|
char *schemaname;
|
|
|
|
char *opername;
|
|
|
|
|
|
|
|
/* deconstruct the name list */
|
|
|
|
DeconstructQualifiedName(opname, &schemaname, &opername);
|
|
|
|
|
|
|
|
/* ensure zero-fill for stable hashing */
|
|
|
|
MemSet(key, 0, sizeof(OprCacheKey));
|
|
|
|
|
|
|
|
/* save operator name and input types into key */
|
|
|
|
strlcpy(key->oprname, opername, NAMEDATALEN);
|
|
|
|
key->left_arg = ltypeId;
|
|
|
|
key->right_arg = rtypeId;
|
|
|
|
|
|
|
|
if (schemaname)
|
|
|
|
{
|
2015-03-18 18:48:02 +01:00
|
|
|
ParseCallbackState pcbstate;
|
|
|
|
|
2007-11-28 19:47:56 +01:00
|
|
|
/* search only in exact schema given */
|
2015-03-18 18:48:02 +01:00
|
|
|
setup_parser_errposition_callback(&pcbstate, pstate, location);
|
2013-01-26 19:24:50 +01:00
|
|
|
key->search_path[0] = LookupExplicitNamespace(schemaname, false);
|
2015-03-18 18:48:02 +01:00
|
|
|
cancel_parser_errposition_callback(&pcbstate);
|
2007-11-28 19:47:56 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* get the active search path */
|
|
|
|
if (fetch_search_path_array(key->search_path,
|
|
|
|
MAX_CACHED_PATH_LEN) > MAX_CACHED_PATH_LEN)
|
|
|
|
return false; /* oops, didn't fit */
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* find_oper_cache_entry
|
|
|
|
*
|
|
|
|
* Look for a cache entry matching the given key. If found, return the
|
|
|
|
* contained operator OID, else return InvalidOid.
|
|
|
|
*/
|
|
|
|
static Oid
|
|
|
|
find_oper_cache_entry(OprCacheKey *key)
|
|
|
|
{
|
|
|
|
OprCacheEntry *oprentry;
|
|
|
|
|
|
|
|
if (OprCacheHash == NULL)
|
|
|
|
{
|
|
|
|
/* First time through: initialize the hash table */
|
|
|
|
HASHCTL ctl;
|
|
|
|
|
|
|
|
ctl.keysize = sizeof(OprCacheKey);
|
|
|
|
ctl.entrysize = sizeof(OprCacheEntry);
|
|
|
|
OprCacheHash = hash_create("Operator lookup cache", 256,
|
Improve hash_create's API for selecting simple-binary-key hash functions.
Previously, if you wanted anything besides C-string hash keys, you had to
specify a custom hashing function to hash_create(). Nearly all such
callers were specifying tag_hash or oid_hash; which is tedious, and rather
error-prone, since a caller could easily miss the opportunity to optimize
by using hash_uint32 when appropriate. Replace this with a design whereby
callers using simple binary-data keys just specify HASH_BLOBS and don't
need to mess with specific support functions. hash_create() itself will
take care of optimizing when the key size is four bytes.
This nets out saving a few hundred bytes of code space, and offers
a measurable performance improvement in tidbitmap.c (which was not
exploiting the opportunity to use hash_uint32 for its 4-byte keys).
There might be some wins elsewhere too, I didn't analyze closely.
In future we could look into offering a similar optimized hashing function
for 8-byte keys. Under this design that could be done in a centralized
and machine-independent fashion, whereas getting it right for keys of
platform-dependent sizes would've been notationally painful before.
For the moment, the old way still works fine, so as not to break source
code compatibility for loadable modules. Eventually we might want to
remove tag_hash and friends from the exported API altogether, since there's
no real need for them to be explicitly referenced from outside dynahash.c.
Teodor Sigaev and Tom Lane
2014-12-18 19:36:29 +01:00
|
|
|
&ctl, HASH_ELEM | HASH_BLOBS);
|
2007-11-28 19:47:56 +01:00
|
|
|
|
|
|
|
/* Arrange to flush cache on pg_operator and pg_cast changes */
|
|
|
|
CacheRegisterSyscacheCallback(OPERNAMENSP,
|
|
|
|
InvalidateOprCacheCallBack,
|
|
|
|
(Datum) 0);
|
|
|
|
CacheRegisterSyscacheCallback(CASTSOURCETARGET,
|
|
|
|
InvalidateOprCacheCallBack,
|
|
|
|
(Datum) 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Look for an existing entry */
|
|
|
|
oprentry = (OprCacheEntry *) hash_search(OprCacheHash,
|
2023-02-06 09:05:20 +01:00
|
|
|
key,
|
2007-11-28 19:47:56 +01:00
|
|
|
HASH_FIND, NULL);
|
|
|
|
if (oprentry == NULL)
|
|
|
|
return InvalidOid;
|
|
|
|
|
|
|
|
return oprentry->opr_oid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* make_oper_cache_entry
|
|
|
|
*
|
|
|
|
* Insert a cache entry for the given key.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
make_oper_cache_entry(OprCacheKey *key, Oid opr_oid)
|
|
|
|
{
|
|
|
|
OprCacheEntry *oprentry;
|
|
|
|
|
|
|
|
Assert(OprCacheHash != NULL);
|
|
|
|
|
|
|
|
oprentry = (OprCacheEntry *) hash_search(OprCacheHash,
|
2023-02-06 09:05:20 +01:00
|
|
|
key,
|
2007-11-28 19:47:56 +01:00
|
|
|
HASH_ENTER, NULL);
|
|
|
|
oprentry->opr_oid = opr_oid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Callback for pg_operator and pg_cast inval events
|
|
|
|
*/
|
|
|
|
static void
|
2011-08-17 01:27:46 +02:00
|
|
|
InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
|
2007-11-28 19:47:56 +01:00
|
|
|
{
|
|
|
|
HASH_SEQ_STATUS status;
|
|
|
|
OprCacheEntry *hentry;
|
|
|
|
|
|
|
|
Assert(OprCacheHash != NULL);
|
|
|
|
|
|
|
|
/* Currently we just flush all entries; hard to be smarter ... */
|
|
|
|
hash_seq_init(&status, OprCacheHash);
|
|
|
|
|
|
|
|
while ((hentry = (OprCacheEntry *) hash_seq_search(&status)) != NULL)
|
|
|
|
{
|
|
|
|
if (hash_search(OprCacheHash,
|
2023-02-06 09:05:20 +01:00
|
|
|
&hentry->key,
|
2007-11-28 19:47:56 +01:00
|
|
|
HASH_REMOVE, NULL) == NULL)
|
|
|
|
elog(ERROR, "hash table corrupted");
|
|
|
|
}
|
|
|
|
}
|