2002-04-15 05:22:04 +00:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* operatorcmds.c
|
|
|
|
*
|
|
|
|
* Routines for operator manipulation commands
|
|
|
|
*
|
2024-01-03 20:49:05 -05:00
|
|
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
2002-04-15 05:22:04 +00:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/commands/operatorcmds.c
|
2002-04-15 05:22:04 +00:00
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* The "DefineFoo" routines take the parse tree and pick out the
|
|
|
|
* appropriate arguments/flags, passing the results to the
|
|
|
|
* corresponding "FooDefine" routines (in src/catalog) that do
|
|
|
|
* the actual catalog-munging. These routines also verify permission
|
|
|
|
* of the user to execute the command.
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* These things must be defined and committed in the following order:
|
|
|
|
* "create function":
|
2018-08-15 18:05:46 +02:00
|
|
|
* input/output, recv/send functions
|
2002-04-15 05:22:04 +00:00
|
|
|
* "create type":
|
|
|
|
* type
|
|
|
|
* "create operator":
|
|
|
|
* operators
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2012-08-30 16:15:44 -04:00
|
|
|
#include "access/htup_details.h"
|
2019-01-21 10:18:20 -08:00
|
|
|
#include "access/table.h"
|
2004-06-25 21:55:59 +00:00
|
|
|
#include "catalog/indexing.h"
|
2015-07-14 19:50:18 +03:00
|
|
|
#include "catalog/objectaccess.h"
|
2022-11-13 08:11:17 +01:00
|
|
|
#include "catalog/pg_namespace.h"
|
2002-04-15 05:22:04 +00:00
|
|
|
#include "catalog/pg_operator.h"
|
2022-11-13 08:11:17 +01:00
|
|
|
#include "catalog/pg_proc.h"
|
2008-08-16 00:01:38 +00:00
|
|
|
#include "catalog/pg_type.h"
|
2002-04-15 05:22:04 +00:00
|
|
|
#include "commands/defrem.h"
|
|
|
|
#include "miscadmin.h"
|
2008-08-16 00:01:38 +00:00
|
|
|
#include "parser/parse_func.h"
|
2002-04-16 23:08:12 +00:00
|
|
|
#include "parser/parse_oper.h"
|
2002-04-15 05:22:04 +00:00
|
|
|
#include "parser/parse_type.h"
|
2020-03-10 10:22:52 +01:00
|
|
|
#include "utils/acl.h"
|
2002-04-27 03:45:03 +00:00
|
|
|
#include "utils/lsyscache.h"
|
2008-06-19 00:46:06 +00:00
|
|
|
#include "utils/rel.h"
|
2002-04-15 05:22:04 +00:00
|
|
|
#include "utils/syscache.h"
|
|
|
|
|
2015-07-14 18:17:55 +03:00
|
|
|
static Oid ValidateRestrictionEstimator(List *restrictionName);
|
|
|
|
static Oid ValidateJoinEstimator(List *joinName);
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
static Oid ValidateOperatorReference(List *name,
|
|
|
|
Oid leftTypeId,
|
|
|
|
Oid rightTypeId);
|
2015-07-14 18:17:55 +03:00
|
|
|
|
2002-04-15 05:22:04 +00:00
|
|
|
/*
|
|
|
|
* DefineOperator
|
|
|
|
* this function extracts all the information from the
|
|
|
|
* parameter list generated by the parser and then has
|
|
|
|
* OperatorCreate() do all the actual work.
|
|
|
|
*
|
|
|
|
* 'parameters' is a list of DefElem
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 14:10:50 -03:00
|
|
|
ObjectAddress
|
2002-04-15 05:22:04 +00:00
|
|
|
DefineOperator(List *names, List *parameters)
|
|
|
|
{
|
|
|
|
char *oprName;
|
|
|
|
Oid oprNamespace;
|
2002-04-27 03:45:03 +00:00
|
|
|
AclResult aclresult;
|
2002-04-16 23:08:12 +00:00
|
|
|
bool canMerge = false; /* operator merges */
|
2006-12-23 00:43:13 +00:00
|
|
|
bool canHash = false; /* operator hashes */
|
2002-04-16 23:08:12 +00:00
|
|
|
List *functionName = NIL; /* function for operator */
|
2002-04-15 05:22:04 +00:00
|
|
|
TypeName *typeName1 = NULL; /* first type name */
|
|
|
|
TypeName *typeName2 = NULL; /* second type name */
|
|
|
|
Oid typeId1 = InvalidOid; /* types converted to OID */
|
|
|
|
Oid typeId2 = InvalidOid;
|
2011-12-20 00:05:19 +02:00
|
|
|
Oid rettype;
|
2002-04-16 23:08:12 +00:00
|
|
|
List *commutatorName = NIL; /* optional commutator operator name */
|
|
|
|
List *negatorName = NIL; /* optional negator operator name */
|
2018-08-15 18:05:46 +02:00
|
|
|
List *restrictionName = NIL; /* optional restrict. sel. function */
|
|
|
|
List *joinName = NIL; /* optional join sel. function */
|
2008-08-16 00:01:38 +00:00
|
|
|
Oid functionOid; /* functions converted to OID */
|
|
|
|
Oid restrictionOid;
|
|
|
|
Oid joinOid;
|
2015-07-14 18:17:55 +03:00
|
|
|
Oid typeId[2]; /* to hold left and right arg */
|
2008-08-16 00:01:38 +00:00
|
|
|
int nargs;
|
2004-05-26 04:41:50 +00:00
|
|
|
ListCell *pl;
|
2002-04-15 05:22:04 +00:00
|
|
|
|
|
|
|
/* Convert list of names to a name and namespace */
|
|
|
|
oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
|
|
|
|
|
2002-04-27 03:45:03 +00:00
|
|
|
/* Check we have creation rights in target namespace */
|
2022-11-13 08:11:17 +01:00
|
|
|
aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE);
|
2002-04-27 03:45:03 +00:00
|
|
|
if (aclresult != ACLCHECK_OK)
|
2017-12-02 09:26:34 -05:00
|
|
|
aclcheck_error(aclresult, OBJECT_SCHEMA,
|
2003-08-01 00:15:26 +00:00
|
|
|
get_namespace_name(oprNamespace));
|
2002-04-27 03:45:03 +00:00
|
|
|
|
2002-04-15 05:22:04 +00:00
|
|
|
/*
|
|
|
|
* loop over the definition list and extract the information we need.
|
|
|
|
*/
|
|
|
|
foreach(pl, parameters)
|
|
|
|
{
|
|
|
|
DefElem *defel = (DefElem *) lfirst(pl);
|
|
|
|
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
if (strcmp(defel->defname, "leftarg") == 0)
|
2002-04-15 05:22:04 +00:00
|
|
|
{
|
|
|
|
typeName1 = defGetTypeName(defel);
|
|
|
|
if (typeName1->setof)
|
2003-07-20 21:56:35 +00:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
2007-06-02 23:36:35 +00:00
|
|
|
errmsg("SETOF type not allowed for operator argument")));
|
2002-04-15 05:22:04 +00:00
|
|
|
}
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "rightarg") == 0)
|
2002-04-15 05:22:04 +00:00
|
|
|
{
|
|
|
|
typeName2 = defGetTypeName(defel);
|
|
|
|
if (typeName2->setof)
|
2003-07-20 21:56:35 +00:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
2007-06-02 23:36:35 +00:00
|
|
|
errmsg("SETOF type not allowed for operator argument")));
|
2002-04-15 05:22:04 +00:00
|
|
|
}
|
2018-08-15 18:05:46 +02:00
|
|
|
/* "function" and "procedure" are equivalent here */
|
|
|
|
else if (strcmp(defel->defname, "function") == 0)
|
|
|
|
functionName = defGetQualifiedName(defel);
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "procedure") == 0)
|
2002-04-16 23:08:12 +00:00
|
|
|
functionName = defGetQualifiedName(defel);
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "commutator") == 0)
|
2002-04-16 23:08:12 +00:00
|
|
|
commutatorName = defGetQualifiedName(defel);
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "negator") == 0)
|
2002-04-16 23:08:12 +00:00
|
|
|
negatorName = defGetQualifiedName(defel);
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "restrict") == 0)
|
2002-04-16 23:08:12 +00:00
|
|
|
restrictionName = defGetQualifiedName(defel);
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "join") == 0)
|
2002-04-16 23:08:12 +00:00
|
|
|
joinName = defGetQualifiedName(defel);
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "hashes") == 0)
|
2004-05-14 16:11:25 +00:00
|
|
|
canHash = defGetBoolean(defel);
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "merges") == 0)
|
2004-05-14 16:11:25 +00:00
|
|
|
canMerge = defGetBoolean(defel);
|
2006-12-23 00:43:13 +00:00
|
|
|
/* These obsolete options are taken as meaning canMerge */
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "sort1") == 0)
|
2006-12-23 00:43:13 +00:00
|
|
|
canMerge = true;
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "sort2") == 0)
|
2006-12-23 00:43:13 +00:00
|
|
|
canMerge = true;
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "ltcmp") == 0)
|
2006-12-23 00:43:13 +00:00
|
|
|
canMerge = true;
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "gtcmp") == 0)
|
2006-12-23 00:43:13 +00:00
|
|
|
canMerge = true;
|
2002-04-15 05:22:04 +00:00
|
|
|
else
|
2015-07-14 18:17:55 +03:00
|
|
|
{
|
|
|
|
/* WARNING, not ERROR, for historical backwards-compatibility */
|
2003-07-20 21:56:35 +00:00
|
|
|
ereport(WARNING,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("operator attribute \"%s\" not recognized",
|
|
|
|
defel->defname)));
|
2015-07-14 18:17:55 +03:00
|
|
|
}
|
2002-04-15 05:22:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* make sure we have our required definitions
|
|
|
|
*/
|
2002-04-16 23:08:12 +00:00
|
|
|
if (functionName == NIL)
|
2003-07-20 21:56:35 +00:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
2018-08-15 18:05:46 +02:00
|
|
|
errmsg("operator function must be specified")));
|
2002-04-15 05:22:04 +00:00
|
|
|
|
|
|
|
/* Transform type names to type OIDs */
|
|
|
|
if (typeName1)
|
2010-10-25 21:40:46 +03:00
|
|
|
typeId1 = typenameTypeId(NULL, typeName1);
|
2002-04-15 05:22:04 +00:00
|
|
|
if (typeName2)
|
2010-10-25 21:40:46 +03:00
|
|
|
typeId2 = typenameTypeId(NULL, typeName2);
|
2002-04-15 05:22:04 +00: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-17 19:38:05 -04:00
|
|
|
/*
|
|
|
|
* If only the right argument is missing, the user is likely trying to
|
|
|
|
* create a postfix operator, so give them a hint about why that does not
|
|
|
|
* work. But if both arguments are missing, do not mention postfix
|
|
|
|
* operators, as the user most likely simply neglected to mention the
|
|
|
|
* arguments.
|
|
|
|
*/
|
2008-08-16 00:01:38 +00:00
|
|
|
if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
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-17 19:38:05 -04:00
|
|
|
errmsg("operator argument types must be specified")));
|
|
|
|
if (!OidIsValid(typeId2))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
|
|
|
errmsg("operator right argument type must be specified"),
|
|
|
|
errdetail("Postfix operators are not supported.")));
|
2008-08-16 00:01:38 +00:00
|
|
|
|
2011-12-20 00:05:19 +02:00
|
|
|
if (typeName1)
|
|
|
|
{
|
2022-11-13 08:11:17 +01:00
|
|
|
aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE);
|
2011-12-20 00:05:19 +02:00
|
|
|
if (aclresult != ACLCHECK_OK)
|
2012-06-15 22:55:03 +03:00
|
|
|
aclcheck_error_type(aclresult, typeId1);
|
2011-12-20 00:05:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (typeName2)
|
|
|
|
{
|
2022-11-13 08:11:17 +01:00
|
|
|
aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE);
|
2011-12-20 00:05:19 +02:00
|
|
|
if (aclresult != ACLCHECK_OK)
|
2012-06-15 22:55:03 +03:00
|
|
|
aclcheck_error_type(aclresult, typeId2);
|
2011-12-20 00:05:19 +02:00
|
|
|
}
|
|
|
|
|
2008-08-16 00:01:38 +00:00
|
|
|
/*
|
|
|
|
* Look up the operator's underlying function.
|
|
|
|
*/
|
|
|
|
if (!OidIsValid(typeId1))
|
|
|
|
{
|
|
|
|
typeId[0] = typeId2;
|
|
|
|
nargs = 1;
|
|
|
|
}
|
|
|
|
else if (!OidIsValid(typeId2))
|
|
|
|
{
|
|
|
|
typeId[0] = typeId1;
|
|
|
|
nargs = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
typeId[0] = typeId1;
|
|
|
|
typeId[1] = typeId2;
|
|
|
|
nargs = 2;
|
|
|
|
}
|
|
|
|
functionOid = LookupFuncName(functionName, nargs, typeId, false);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We require EXECUTE rights for the function. This isn't strictly
|
|
|
|
* necessary, since EXECUTE will be checked at any attempted use of the
|
|
|
|
* operator, but it seems like a good idea anyway.
|
|
|
|
*/
|
2022-11-13 08:11:17 +01:00
|
|
|
aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
|
2008-08-16 00:01:38 +00:00
|
|
|
if (aclresult != ACLCHECK_OK)
|
2017-12-02 09:26:34 -05:00
|
|
|
aclcheck_error(aclresult, OBJECT_FUNCTION,
|
2008-08-16 00:01:38 +00:00
|
|
|
NameListToString(functionName));
|
|
|
|
|
2011-12-20 00:05:19 +02:00
|
|
|
rettype = get_func_rettype(functionOid);
|
2022-11-13 08:11:17 +01:00
|
|
|
aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
|
2011-12-20 00:05:19 +02:00
|
|
|
if (aclresult != ACLCHECK_OK)
|
2012-06-15 22:55:03 +03:00
|
|
|
aclcheck_error_type(aclresult, rettype);
|
2011-12-20 00:05:19 +02:00
|
|
|
|
2008-08-16 00:01:38 +00:00
|
|
|
/*
|
2015-07-14 18:17:55 +03:00
|
|
|
* Look up restriction and join estimators if specified
|
2008-08-16 00:01:38 +00:00
|
|
|
*/
|
|
|
|
if (restrictionName)
|
2015-07-14 18:17:55 +03:00
|
|
|
restrictionOid = ValidateRestrictionEstimator(restrictionName);
|
2008-08-16 00:01:38 +00:00
|
|
|
else
|
|
|
|
restrictionOid = InvalidOid;
|
|
|
|
if (joinName)
|
2015-07-14 18:17:55 +03:00
|
|
|
joinOid = ValidateJoinEstimator(joinName);
|
2008-08-16 00:01:38 +00:00
|
|
|
else
|
|
|
|
joinOid = InvalidOid;
|
|
|
|
|
2002-04-15 05:22:04 +00:00
|
|
|
/*
|
|
|
|
* now have OperatorCreate do all the work..
|
|
|
|
*/
|
2012-12-23 18:25:03 -05:00
|
|
|
return
|
|
|
|
OperatorCreate(oprName, /* operator name */
|
|
|
|
oprNamespace, /* namespace */
|
|
|
|
typeId1, /* left type id */
|
|
|
|
typeId2, /* right type id */
|
|
|
|
functionOid, /* function for operator */
|
|
|
|
commutatorName, /* optional commutator operator name */
|
|
|
|
negatorName, /* optional negator operator name */
|
2018-08-15 18:05:46 +02:00
|
|
|
restrictionOid, /* optional restrict. sel. function */
|
|
|
|
joinOid, /* optional join sel. function name */
|
2012-12-23 18:25:03 -05:00
|
|
|
canMerge, /* operator merges */
|
|
|
|
canHash); /* operator hashes */
|
2002-04-15 05:22:04 +00:00
|
|
|
}
|
|
|
|
|
2015-07-14 18:17:55 +03:00
|
|
|
/*
|
2021-05-10 15:45:54 +09:00
|
|
|
* Look up a restriction estimator function by name, and verify that it has
|
2015-07-14 18:17:55 +03:00
|
|
|
* the correct signature and we have the permissions to attach it to an
|
|
|
|
* operator.
|
|
|
|
*/
|
|
|
|
static Oid
|
|
|
|
ValidateRestrictionEstimator(List *restrictionName)
|
|
|
|
{
|
|
|
|
Oid typeId[4];
|
|
|
|
Oid restrictionOid;
|
|
|
|
AclResult aclresult;
|
|
|
|
|
|
|
|
typeId[0] = INTERNALOID; /* PlannerInfo */
|
|
|
|
typeId[1] = OIDOID; /* operator OID */
|
|
|
|
typeId[2] = INTERNALOID; /* args list */
|
|
|
|
typeId[3] = INT4OID; /* varRelid */
|
|
|
|
|
|
|
|
restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
|
|
|
|
|
|
|
|
/* estimators must return float8 */
|
|
|
|
if (get_func_rettype(restrictionOid) != FLOAT8OID)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2016-04-01 13:35:48 -03:00
|
|
|
errmsg("restriction estimator function %s must return type %s",
|
2016-03-28 14:12:00 -03:00
|
|
|
NameListToString(restrictionName), "float8")));
|
2015-07-14 18:17:55 +03:00
|
|
|
|
|
|
|
/* Require EXECUTE rights for the estimator */
|
2022-11-13 08:11:17 +01:00
|
|
|
aclresult = object_aclcheck(ProcedureRelationId, restrictionOid, GetUserId(), ACL_EXECUTE);
|
2015-07-14 18:17:55 +03:00
|
|
|
if (aclresult != ACLCHECK_OK)
|
2017-12-02 09:26:34 -05:00
|
|
|
aclcheck_error(aclresult, OBJECT_FUNCTION,
|
2015-07-14 18:17:55 +03:00
|
|
|
NameListToString(restrictionName));
|
|
|
|
|
|
|
|
return restrictionOid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2021-05-10 15:45:54 +09:00
|
|
|
* Look up a join estimator function by name, and verify that it has the
|
2015-07-14 18:17:55 +03:00
|
|
|
* correct signature and we have the permissions to attach it to an
|
|
|
|
* operator.
|
|
|
|
*/
|
|
|
|
static Oid
|
|
|
|
ValidateJoinEstimator(List *joinName)
|
|
|
|
{
|
|
|
|
Oid typeId[5];
|
|
|
|
Oid joinOid;
|
Make contrib modules' installation scripts more secure.
Hostile objects located within the installation-time search_path could
capture references in an extension's installation or upgrade script.
If the extension is being installed with superuser privileges, this
opens the door to privilege escalation. While such hazards have existed
all along, their urgency increases with the v13 "trusted extensions"
feature, because that lets a non-superuser control the installation path
for a superuser-privileged script. Therefore, make a number of changes
to make such situations more secure:
* Tweak the construction of the installation-time search_path to ensure
that references to objects in pg_catalog can't be subverted; and
explicitly add pg_temp to the end of the path to prevent attacks using
temporary objects.
* Disable check_function_bodies within installation/upgrade scripts,
so that any security gaps in SQL-language or PL-language function bodies
cannot create a risk of unwanted installation-time code execution.
* Adjust lookup of type input/receive functions and join estimator
functions to complain if there are multiple candidate functions. This
prevents capture of references to functions whose signature is not the
first one checked; and it's arguably more user-friendly anyway.
* Modify various contrib upgrade scripts to ensure that catalog
modification queries are executed with secure search paths. (These
are in-place modifications with no extension version changes, since
it is the update process itself that is at issue, not the end result.)
Extensions that depend on other extensions cannot be made fully secure
by these methods alone; therefore, revert the "trusted" marking that
commit eb67623c9 applied to earthdistance and hstore_plperl, pending
some better solution to that set of issues.
Also add documentation around these issues, to help extension authors
write secure installation scripts.
Patch by me, following an observation by Andres Freund; thanks
to Noah Misch for review.
Security: CVE-2020-14350
2020-08-10 10:44:42 -04:00
|
|
|
Oid joinOid2;
|
2015-07-14 18:17:55 +03:00
|
|
|
AclResult aclresult;
|
|
|
|
|
|
|
|
typeId[0] = INTERNALOID; /* PlannerInfo */
|
|
|
|
typeId[1] = OIDOID; /* operator OID */
|
|
|
|
typeId[2] = INTERNALOID; /* args list */
|
|
|
|
typeId[3] = INT2OID; /* jointype */
|
|
|
|
typeId[4] = INTERNALOID; /* SpecialJoinInfo */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* As of Postgres 8.4, the preferred signature for join estimators has 5
|
Make contrib modules' installation scripts more secure.
Hostile objects located within the installation-time search_path could
capture references in an extension's installation or upgrade script.
If the extension is being installed with superuser privileges, this
opens the door to privilege escalation. While such hazards have existed
all along, their urgency increases with the v13 "trusted extensions"
feature, because that lets a non-superuser control the installation path
for a superuser-privileged script. Therefore, make a number of changes
to make such situations more secure:
* Tweak the construction of the installation-time search_path to ensure
that references to objects in pg_catalog can't be subverted; and
explicitly add pg_temp to the end of the path to prevent attacks using
temporary objects.
* Disable check_function_bodies within installation/upgrade scripts,
so that any security gaps in SQL-language or PL-language function bodies
cannot create a risk of unwanted installation-time code execution.
* Adjust lookup of type input/receive functions and join estimator
functions to complain if there are multiple candidate functions. This
prevents capture of references to functions whose signature is not the
first one checked; and it's arguably more user-friendly anyway.
* Modify various contrib upgrade scripts to ensure that catalog
modification queries are executed with secure search paths. (These
are in-place modifications with no extension version changes, since
it is the update process itself that is at issue, not the end result.)
Extensions that depend on other extensions cannot be made fully secure
by these methods alone; therefore, revert the "trusted" marking that
commit eb67623c9 applied to earthdistance and hstore_plperl, pending
some better solution to that set of issues.
Also add documentation around these issues, to help extension authors
write secure installation scripts.
Patch by me, following an observation by Andres Freund; thanks
to Noah Misch for review.
Security: CVE-2020-14350
2020-08-10 10:44:42 -04:00
|
|
|
* arguments, but we still allow the old 4-argument form. Whine about
|
|
|
|
* ambiguity if both forms exist.
|
2015-07-14 18:17:55 +03:00
|
|
|
*/
|
|
|
|
joinOid = LookupFuncName(joinName, 5, typeId, true);
|
Make contrib modules' installation scripts more secure.
Hostile objects located within the installation-time search_path could
capture references in an extension's installation or upgrade script.
If the extension is being installed with superuser privileges, this
opens the door to privilege escalation. While such hazards have existed
all along, their urgency increases with the v13 "trusted extensions"
feature, because that lets a non-superuser control the installation path
for a superuser-privileged script. Therefore, make a number of changes
to make such situations more secure:
* Tweak the construction of the installation-time search_path to ensure
that references to objects in pg_catalog can't be subverted; and
explicitly add pg_temp to the end of the path to prevent attacks using
temporary objects.
* Disable check_function_bodies within installation/upgrade scripts,
so that any security gaps in SQL-language or PL-language function bodies
cannot create a risk of unwanted installation-time code execution.
* Adjust lookup of type input/receive functions and join estimator
functions to complain if there are multiple candidate functions. This
prevents capture of references to functions whose signature is not the
first one checked; and it's arguably more user-friendly anyway.
* Modify various contrib upgrade scripts to ensure that catalog
modification queries are executed with secure search paths. (These
are in-place modifications with no extension version changes, since
it is the update process itself that is at issue, not the end result.)
Extensions that depend on other extensions cannot be made fully secure
by these methods alone; therefore, revert the "trusted" marking that
commit eb67623c9 applied to earthdistance and hstore_plperl, pending
some better solution to that set of issues.
Also add documentation around these issues, to help extension authors
write secure installation scripts.
Patch by me, following an observation by Andres Freund; thanks
to Noah Misch for review.
Security: CVE-2020-14350
2020-08-10 10:44:42 -04:00
|
|
|
joinOid2 = LookupFuncName(joinName, 4, typeId, true);
|
|
|
|
if (OidIsValid(joinOid))
|
|
|
|
{
|
|
|
|
if (OidIsValid(joinOid2))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
|
|
|
|
errmsg("join estimator function %s has multiple matches",
|
|
|
|
NameListToString(joinName))));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
joinOid = joinOid2;
|
|
|
|
/* If not found, reference the 5-argument signature in error msg */
|
|
|
|
if (!OidIsValid(joinOid))
|
|
|
|
joinOid = LookupFuncName(joinName, 5, typeId, false);
|
|
|
|
}
|
2015-07-14 18:17:55 +03:00
|
|
|
|
|
|
|
/* estimators must return float8 */
|
|
|
|
if (get_func_rettype(joinOid) != FLOAT8OID)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2016-04-01 13:35:48 -03:00
|
|
|
errmsg("join estimator function %s must return type %s",
|
2016-03-28 14:12:00 -03:00
|
|
|
NameListToString(joinName), "float8")));
|
2015-07-14 18:17:55 +03:00
|
|
|
|
|
|
|
/* Require EXECUTE rights for the estimator */
|
2022-11-13 08:11:17 +01:00
|
|
|
aclresult = object_aclcheck(ProcedureRelationId, joinOid, GetUserId(), ACL_EXECUTE);
|
2015-07-14 18:17:55 +03:00
|
|
|
if (aclresult != ACLCHECK_OK)
|
2017-12-02 09:26:34 -05:00
|
|
|
aclcheck_error(aclresult, OBJECT_FUNCTION,
|
2015-07-14 18:17:55 +03:00
|
|
|
NameListToString(joinName));
|
|
|
|
|
|
|
|
return joinOid;
|
|
|
|
}
|
|
|
|
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
/*
|
|
|
|
* Look up and return the OID of an operator,
|
|
|
|
* given a possibly-qualified name and left and right type IDs.
|
|
|
|
*
|
|
|
|
* Verifies that the operator is defined (not a shell) and owned by
|
|
|
|
* the current user, so that we have permission to associate it with
|
|
|
|
* the operator being altered. Rejecting shell operators is a policy
|
|
|
|
* choice to help catch mistakes, rather than something essential.
|
|
|
|
*/
|
|
|
|
static Oid
|
|
|
|
ValidateOperatorReference(List *name,
|
|
|
|
Oid leftTypeId,
|
|
|
|
Oid rightTypeId)
|
|
|
|
{
|
|
|
|
Oid oid;
|
|
|
|
bool defined;
|
|
|
|
|
|
|
|
oid = OperatorLookup(name,
|
|
|
|
leftTypeId,
|
|
|
|
rightTypeId,
|
|
|
|
&defined);
|
|
|
|
|
|
|
|
/* These message strings are chosen to match parse_oper.c */
|
|
|
|
if (!OidIsValid(oid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("operator does not exist: %s",
|
|
|
|
op_signature_string(name,
|
|
|
|
leftTypeId,
|
|
|
|
rightTypeId))));
|
|
|
|
|
|
|
|
if (!defined)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
|
|
|
errmsg("operator is only a shell: %s",
|
|
|
|
op_signature_string(name,
|
|
|
|
leftTypeId,
|
|
|
|
rightTypeId))));
|
|
|
|
|
|
|
|
if (!object_ownercheck(OperatorRelationId, oid, GetUserId()))
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
|
|
|
|
NameListToString(name));
|
|
|
|
|
|
|
|
return oid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-12 18:43:19 +00:00
|
|
|
/*
|
|
|
|
* Guts of operator deletion.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
RemoveOperatorById(Oid operOid)
|
|
|
|
{
|
|
|
|
Relation relation;
|
|
|
|
HeapTuple tup;
|
2016-03-25 12:33:16 -04:00
|
|
|
Form_pg_operator op;
|
2002-07-12 18:43:19 +00:00
|
|
|
|
2019-01-21 10:32:19 -08:00
|
|
|
relation = table_open(OperatorRelationId, RowExclusiveLock);
|
2002-07-12 18:43:19 +00:00
|
|
|
|
2010-02-14 18:42:19 +00:00
|
|
|
tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
|
2002-07-12 18:43:19 +00:00
|
|
|
if (!HeapTupleIsValid(tup)) /* should not happen */
|
2003-07-20 21:56:35 +00:00
|
|
|
elog(ERROR, "cache lookup failed for operator %u", operOid);
|
2016-03-25 12:33:16 -04:00
|
|
|
op = (Form_pg_operator) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset links from commutator and negator, if any. In case of a
|
|
|
|
* self-commutator or self-negator, this means we have to re-fetch the
|
|
|
|
* updated tuple. (We could optimize away updates on the tuple we're
|
|
|
|
* about to drop, but it doesn't seem worth convoluting the logic for.)
|
|
|
|
*/
|
|
|
|
if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
|
|
|
|
{
|
|
|
|
OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
|
|
|
|
if (operOid == op->oprcom || operOid == op->oprnegate)
|
|
|
|
{
|
|
|
|
ReleaseSysCache(tup);
|
|
|
|
tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
|
|
|
|
if (!HeapTupleIsValid(tup)) /* should not happen */
|
|
|
|
elog(ERROR, "cache lookup failed for operator %u", operOid);
|
|
|
|
}
|
|
|
|
}
|
2002-04-15 05:22:04 +00:00
|
|
|
|
2017-02-01 16:13:30 -05:00
|
|
|
CatalogTupleDelete(relation, &tup->t_self);
|
2002-04-15 05:22:04 +00:00
|
|
|
|
2002-07-12 18:43:19 +00:00
|
|
|
ReleaseSysCache(tup);
|
|
|
|
|
2019-01-21 10:32:19 -08:00
|
|
|
table_close(relation, RowExclusiveLock);
|
2002-04-15 05:22:04 +00:00
|
|
|
}
|
2015-07-14 18:17:55 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* AlterOperator
|
|
|
|
* routine implementing ALTER OPERATOR <operator> SET (option = ...).
|
|
|
|
*
|
|
|
|
* Currently, only RESTRICT and JOIN estimator functions can be changed.
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
* COMMUTATOR, NEGATOR, MERGES, and HASHES attributes can be set if they
|
|
|
|
* have not been set previously. (Changing or removing one of these
|
|
|
|
* attributes could invalidate existing plans, which seems more trouble
|
|
|
|
* than it's worth.)
|
2015-07-14 18:17:55 +03:00
|
|
|
*/
|
|
|
|
ObjectAddress
|
|
|
|
AlterOperator(AlterOperatorStmt *stmt)
|
|
|
|
{
|
|
|
|
ObjectAddress address;
|
|
|
|
Oid oprId;
|
|
|
|
Relation catalog;
|
|
|
|
HeapTuple tup;
|
|
|
|
Form_pg_operator oprForm;
|
|
|
|
int i;
|
|
|
|
ListCell *pl;
|
|
|
|
Datum values[Natts_pg_operator];
|
|
|
|
bool nulls[Natts_pg_operator];
|
|
|
|
bool replaces[Natts_pg_operator];
|
2018-08-15 18:05:46 +02:00
|
|
|
List *restrictionName = NIL; /* optional restrict. sel. function */
|
2015-07-14 18:17:55 +03:00
|
|
|
bool updateRestriction = false;
|
|
|
|
Oid restrictionOid;
|
2018-08-15 18:05:46 +02:00
|
|
|
List *joinName = NIL; /* optional join sel. function */
|
2015-07-14 18:17:55 +03:00
|
|
|
bool updateJoin = false;
|
|
|
|
Oid joinOid;
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
List *commutatorName = NIL; /* optional commutator operator name */
|
|
|
|
Oid commutatorOid;
|
|
|
|
List *negatorName = NIL; /* optional negator operator name */
|
|
|
|
Oid negatorOid;
|
|
|
|
bool canMerge = false;
|
|
|
|
bool updateMerges = false;
|
|
|
|
bool canHash = false;
|
|
|
|
bool updateHashes = false;
|
2015-07-14 18:17:55 +03:00
|
|
|
|
|
|
|
/* Look up the operator */
|
2016-12-28 12:00:00 -05:00
|
|
|
oprId = LookupOperWithArgs(stmt->opername, false);
|
2019-01-21 10:32:19 -08:00
|
|
|
catalog = table_open(OperatorRelationId, RowExclusiveLock);
|
2015-07-14 18:17:55 +03:00
|
|
|
tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
|
2019-05-05 13:10:07 -04:00
|
|
|
if (!HeapTupleIsValid(tup))
|
2015-07-14 18:17:55 +03:00
|
|
|
elog(ERROR, "cache lookup failed for operator %u", oprId);
|
|
|
|
oprForm = (Form_pg_operator) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
/* Process options */
|
|
|
|
foreach(pl, stmt->options)
|
|
|
|
{
|
|
|
|
DefElem *defel = (DefElem *) lfirst(pl);
|
|
|
|
List *param;
|
|
|
|
|
|
|
|
if (defel->arg == NULL)
|
|
|
|
param = NIL; /* NONE, removes the function */
|
|
|
|
else
|
|
|
|
param = defGetQualifiedName(defel);
|
|
|
|
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
if (strcmp(defel->defname, "restrict") == 0)
|
2015-07-14 18:17:55 +03:00
|
|
|
{
|
|
|
|
restrictionName = param;
|
|
|
|
updateRestriction = true;
|
|
|
|
}
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "join") == 0)
|
2015-07-14 18:17:55 +03:00
|
|
|
{
|
|
|
|
joinName = param;
|
|
|
|
updateJoin = true;
|
|
|
|
}
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
else if (strcmp(defel->defname, "commutator") == 0)
|
|
|
|
{
|
|
|
|
commutatorName = defGetQualifiedName(defel);
|
|
|
|
}
|
|
|
|
else if (strcmp(defel->defname, "negator") == 0)
|
|
|
|
{
|
|
|
|
negatorName = defGetQualifiedName(defel);
|
|
|
|
}
|
|
|
|
else if (strcmp(defel->defname, "merges") == 0)
|
|
|
|
{
|
|
|
|
canMerge = defGetBoolean(defel);
|
|
|
|
updateMerges = true;
|
|
|
|
}
|
|
|
|
else if (strcmp(defel->defname, "hashes") == 0)
|
|
|
|
{
|
|
|
|
canHash = defGetBoolean(defel);
|
|
|
|
updateHashes = true;
|
|
|
|
}
|
2015-07-14 18:17:55 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The rest of the options that CREATE accepts cannot be changed.
|
|
|
|
* Check for them so that we can give a meaningful error message.
|
|
|
|
*/
|
Avoid unnecessary use of pg_strcasecmp for already-downcased identifiers.
We have a lot of code in which option names, which from the user's
viewpoint are logically keywords, are passed through the grammar as plain
identifiers, and then matched to string literals during command execution.
This approach avoids making words into lexer keywords unnecessarily. Some
places matched these strings using plain strcmp, some using pg_strcasecmp.
But the latter should be unnecessary since identifiers would have been
downcased on their way through the parser. Aside from any efficiency
concerns (probably not a big factor), the lack of consistency in this area
creates a hazard of subtle bugs due to different places coming to different
conclusions about whether two option names are the same or different.
Hence, standardize on using strcmp() to match any option names that are
expected to have been fed through the parser.
This does create a user-visible behavioral change, which is that while
formerly all of these would work:
alter table foo set (fillfactor = 50);
alter table foo set (FillFactor = 50);
alter table foo set ("fillfactor" = 50);
alter table foo set ("FillFactor" = 50);
now the last case will fail because that double-quoted identifier is
different from the others. However, none of our documentation says that
you can use a quoted identifier in such contexts at all, and we should
discourage doing so since it would break if we ever decide to parse such
constructs as true lexer keywords rather than poor man's substitutes.
So this shouldn't create a significant compatibility issue for users.
Daniel Gustafsson, reviewed by Michael Paquier, small changes by me
Discussion: https://postgr.es/m/29405B24-564E-476B-98C0-677A29805B84@yesql.se
2018-01-26 18:25:02 -05:00
|
|
|
else if (strcmp(defel->defname, "leftarg") == 0 ||
|
|
|
|
strcmp(defel->defname, "rightarg") == 0 ||
|
2018-08-15 18:05:46 +02:00
|
|
|
strcmp(defel->defname, "function") == 0 ||
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
strcmp(defel->defname, "procedure") == 0)
|
2015-07-14 18:17:55 +03:00
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2016-06-07 14:18:08 -04:00
|
|
|
errmsg("operator attribute \"%s\" cannot be changed",
|
2015-07-14 18:17:55 +03:00
|
|
|
defel->defname)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("operator attribute \"%s\" not recognized",
|
|
|
|
defel->defname)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check permissions. Must be owner. */
|
2022-11-13 08:11:17 +01:00
|
|
|
if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
|
2017-12-02 09:26:34 -05:00
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
|
2015-07-14 18:17:55 +03:00
|
|
|
NameStr(oprForm->oprname));
|
|
|
|
|
|
|
|
/*
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
* Look up OIDs for any parameters specified
|
2015-07-14 18:17:55 +03:00
|
|
|
*/
|
|
|
|
if (restrictionName)
|
|
|
|
restrictionOid = ValidateRestrictionEstimator(restrictionName);
|
|
|
|
else
|
|
|
|
restrictionOid = InvalidOid;
|
|
|
|
if (joinName)
|
|
|
|
joinOid = ValidateJoinEstimator(joinName);
|
|
|
|
else
|
|
|
|
joinOid = InvalidOid;
|
|
|
|
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
if (commutatorName)
|
2015-07-14 18:17:55 +03:00
|
|
|
{
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
/* commutator has reversed arg types */
|
|
|
|
commutatorOid = ValidateOperatorReference(commutatorName,
|
|
|
|
oprForm->oprright,
|
|
|
|
oprForm->oprleft);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We don't need to do anything extra for a self commutator as in
|
|
|
|
* OperatorCreate, since the operator surely exists already.
|
|
|
|
*/
|
2015-07-14 18:17:55 +03:00
|
|
|
}
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
else
|
|
|
|
commutatorOid = InvalidOid;
|
2015-07-14 18:17:55 +03:00
|
|
|
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
if (negatorName)
|
2015-07-14 18:17:55 +03:00
|
|
|
{
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
negatorOid = ValidateOperatorReference(negatorName,
|
|
|
|
oprForm->oprleft,
|
|
|
|
oprForm->oprright);
|
|
|
|
|
|
|
|
/* Must reject self-negation */
|
|
|
|
if (negatorOid == oprForm->oid)
|
2015-07-14 18:17:55 +03:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
errmsg("operator cannot be its own negator")));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
negatorOid = InvalidOid;
|
2015-07-14 18:17:55 +03:00
|
|
|
}
|
|
|
|
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
/*
|
|
|
|
* Check that we're not changing any attributes that might be depended on
|
|
|
|
* by plans, while allowing no-op updates.
|
|
|
|
*/
|
|
|
|
if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
|
|
|
|
commutatorOid != oprForm->oprcom)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
|
|
|
errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
|
|
|
|
"commutator")));
|
|
|
|
|
|
|
|
if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
|
|
|
|
negatorOid != oprForm->oprnegate)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
|
|
|
errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
|
|
|
|
"negator")));
|
|
|
|
|
|
|
|
if (updateMerges && oprForm->oprcanmerge && !canMerge)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
|
|
|
errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
|
|
|
|
"merges")));
|
|
|
|
|
|
|
|
if (updateHashes && oprForm->oprcanhash && !canHash)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
|
|
|
errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
|
|
|
|
"hashes")));
|
|
|
|
|
|
|
|
/* Perform additional checks, like OperatorCreate does */
|
|
|
|
OperatorValidateParams(oprForm->oprleft,
|
|
|
|
oprForm->oprright,
|
|
|
|
oprForm->oprresult,
|
|
|
|
OidIsValid(commutatorOid),
|
|
|
|
OidIsValid(negatorOid),
|
|
|
|
OidIsValid(restrictionOid),
|
|
|
|
OidIsValid(joinOid),
|
|
|
|
canMerge,
|
|
|
|
canHash);
|
|
|
|
|
2015-07-14 18:17:55 +03:00
|
|
|
/* Update the tuple */
|
|
|
|
for (i = 0; i < Natts_pg_operator; ++i)
|
|
|
|
{
|
|
|
|
values[i] = (Datum) 0;
|
|
|
|
replaces[i] = false;
|
|
|
|
nulls[i] = false;
|
|
|
|
}
|
|
|
|
if (updateRestriction)
|
|
|
|
{
|
|
|
|
replaces[Anum_pg_operator_oprrest - 1] = true;
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionOid);
|
2015-07-14 18:17:55 +03:00
|
|
|
}
|
|
|
|
if (updateJoin)
|
|
|
|
{
|
|
|
|
replaces[Anum_pg_operator_oprjoin - 1] = true;
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
|
|
|
|
}
|
|
|
|
if (OidIsValid(commutatorOid))
|
|
|
|
{
|
|
|
|
replaces[Anum_pg_operator_oprcom - 1] = true;
|
|
|
|
values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorOid);
|
|
|
|
}
|
|
|
|
if (OidIsValid(negatorOid))
|
|
|
|
{
|
|
|
|
replaces[Anum_pg_operator_oprnegate - 1] = true;
|
|
|
|
values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorOid);
|
|
|
|
}
|
|
|
|
if (updateMerges)
|
|
|
|
{
|
|
|
|
replaces[Anum_pg_operator_oprcanmerge - 1] = true;
|
|
|
|
values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
|
|
|
|
}
|
|
|
|
if (updateHashes)
|
|
|
|
{
|
|
|
|
replaces[Anum_pg_operator_oprcanhash - 1] = true;
|
|
|
|
values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
|
2015-07-14 18:17:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
|
|
|
|
values, nulls, replaces);
|
|
|
|
|
2017-01-31 18:42:24 -03:00
|
|
|
CatalogTupleUpdate(catalog, &tup->t_self, tup);
|
2015-07-14 18:17:55 +03:00
|
|
|
|
Prevent ALTER TYPE/DOMAIN/OPERATOR from changing extension membership.
If recordDependencyOnCurrentExtension is invoked on a pre-existing,
free-standing object during an extension update script, that object
will become owned by the extension. In our current code this is
possible in three cases:
* Replacing a "shell" type or operator.
* CREATE OR REPLACE overwriting an existing object.
* ALTER TYPE SET, ALTER DOMAIN SET, and ALTER OPERATOR SET.
The first of these cases is intentional behavior, as noted by the
existing comments for GenerateTypeDependencies. It seems like
appropriate behavior for CREATE OR REPLACE too; at least, the obvious
alternatives are not better. However, the fact that it happens during
ALTER is an artifact of trying to share code (GenerateTypeDependencies
and makeOperatorDependencies) between the CREATE and ALTER cases.
Since an extension script would be unlikely to ALTER an object that
didn't already belong to the extension, this behavior is not very
troubling for the direct target object ... but ALTER TYPE SET will
recurse to dependent domains, and it is very uncool for those to
become owned by the extension if they were not already.
Let's fix this by redefining the ALTER cases to never change extension
membership, full stop. We could minimize the behavioral change by
only changing the behavior when ALTER TYPE SET is recursing to a
domain, but that would complicate the code and it does not seem like
a better definition.
Per bug #17144 from Alex Kozhemyakin. Back-patch to v13 where ALTER
TYPE SET was added. (The other cases are older, but since they only
affect the directly-named object, there's not enough of a problem to
justify changing the behavior further back.)
Discussion: https://postgr.es/m/17144-e67d7a8f049de9af@postgresql.org
2021-08-17 14:29:22 -04:00
|
|
|
address = makeOperatorDependencies(tup, false, true);
|
2015-07-14 19:50:18 +03:00
|
|
|
|
Extend ALTER OPERATOR to allow setting more optimization attributes.
Allow the COMMUTATOR, NEGATOR, MERGES, and HASHES attributes to be set
by ALTER OPERATOR. However, we don't allow COMMUTATOR/NEGATOR to be
changed once set, nor allow the MERGES/HASHES flags to be unset once
set. Changes like that might invalidate plans already made, and
dealing with the consequences seems like more trouble than it's worth.
The main use-case we foresee for this is to allow addition of missed
properties in extension update scripts, such as extending an existing
operator to support hashing. So only transitions from not-set to set
states seem very useful.
This patch also causes us to reject some incorrect cases that formerly
resulted in inconsistent catalog state, such as trying to set the
commutator of an operator to be some other operator that already has a
(different) commutator.
While at it, move the InvokeObjectPostCreateHook call for CREATE
OPERATOR to not occur until after we've fixed up commutator or negator
links as needed. The previous ordering could only be justified by
thinking of the OperatorUpd call as a kind of ALTER OPERATOR step;
but we don't call InvokeObjectPostAlterHook therein. It seems better
to let the hook see the final state of the operator object.
In the documentation, move the discussion of how to establish
commutator pairs from xoper.sgml to the CREATE OPERATOR ref page.
Tommy Pavlicek, reviewed and editorialized a bit by me
Discussion: https://postgr.es/m/CAEhP-W-vGVzf4udhR5M8Bdv88UYnPrhoSkj3ieR3QNrsGQoqdg@mail.gmail.com
2023-10-20 12:28:38 -04:00
|
|
|
if (OidIsValid(commutatorOid) || OidIsValid(negatorOid))
|
|
|
|
OperatorUpd(oprId, commutatorOid, negatorOid, false);
|
|
|
|
|
2015-12-31 17:37:31 -05:00
|
|
|
InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
|
2015-07-14 19:50:18 +03:00
|
|
|
|
2019-01-21 10:32:19 -08:00
|
|
|
table_close(catalog, NoLock);
|
2015-07-14 18:17:55 +03:00
|
|
|
|
|
|
|
return address;
|
|
|
|
}
|