Hello Hackers.
Because change the commutator and negator raised questions I suggest 3 version
of the patch without them. In addition, for us now is much more important
restrict and join (for "Selectivity estimation for intarray" patch).
What do you think?
Thanks!
--
Uriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 072f530..f7770fd 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -28,8 +28,10 @@
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
+#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse_oper.h"
+#include "parser/parse_func.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
@@ -53,7 +55,7 @@ static Oid OperatorShellMake(const char *operatorName,
Oid leftTypeId,
Oid rightTypeId);
-static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
+static void ShellOperatorUpd(Oid baseId, Oid commId, Oid negId);
static Oid get_other_operator(List *otherOp,
Oid otherLeftTypeId, Oid otherRightTypeId,
@@ -563,7 +565,7 @@ OperatorCreate(const char *operatorName,
commutatorId = operatorObjectId;
if (OidIsValid(commutatorId) || OidIsValid(negatorId))
- OperatorUpd(operatorObjectId, commutatorId, negatorId);
+ ShellOperatorUpd(operatorObjectId, commutatorId, negatorId);
return address;
}
@@ -633,7 +635,7 @@ get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
}
/*
- * OperatorUpd
+ * ShellOperatorUpd
*
* For a given operator, look up its negator and commutator operators.
* If they are defined, but their negator and commutator fields
@@ -642,7 +644,7 @@ get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
* which are the negator or commutator of each other.
*/
static void
-OperatorUpd(Oid baseId, Oid commId, Oid negId)
+ShellOperatorUpd(Oid baseId, Oid commId, Oid negId)
{
int i;
Relation pg_operator_desc;
@@ -864,3 +866,158 @@ makeOperatorDependencies(HeapTuple tuple)
return myself;
}
+
+/*
+ * Operator update aka ALTER OPERATOR for RESTRICT, JOIN
+ */
+void OperatorUpd(Oid classId,
+ Oid baseId,
+ List *operator_params)
+{
+ int i;
+ ListCell *pl;
+ Relation catalog;
+ HeapTuple tup;
+ Oid operator_param_id = 0;
+ bool nulls[Natts_pg_operator];
+ bool replaces[Natts_pg_operator];
+ Datum values[Natts_pg_operator];
+
+ for (i = 0; i < Natts_pg_operator; ++i)
+ {
+ values[i] = (Datum) 0;
+ replaces[i] = false;
+ nulls[i] = false;
+ }
+
+ catalog = heap_open(classId, RowExclusiveLock);
+ tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(baseId));
+ if (HeapTupleIsValid(tup))
+ {
+ /*
+ * loop over the definition list and extract the information we need.
+ */
+ foreach(pl, operator_params)
+ {
+ DefElem *defel = (DefElem *) lfirst(pl);
+ List *param = defGetQualifiedName(defel);
+ int param_type;
+
+ if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ param_type = Anum_pg_operator_oprrest;
+ else if (pg_strcasecmp(defel->defname, "join") == 0)
+ param_type = Anum_pg_operator_oprjoin;
+ else
+ {
+ ereport(WARNING,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("operator attribute \"%s\" not recognized",
+ defel->defname)));
+ continue;
+ }
+
+ /* Resets if written NULL */
+ if (pg_strcasecmp(NameListToString(param), "null") == 0)
+ {
+ values[param_type - 1] = ObjectIdGetDatum(InvalidOid);
+ replaces[param_type - 1] = true;
+ continue;
+ }
+
+ if (param_type == Anum_pg_operator_oprrest)
+ {
+ if (PointerIsValid(param))
+ {
+ Oid typeId[5];
+ AclResult aclresult;
+ typeId[0] = INTERNALOID; /* PlannerInfo */
+ typeId[1] = OIDOID; /* operator OID */
+ typeId[2] = INTERNALOID; /* args list */
+ typeId[3] = INT4OID; /* varRelid */
+
+ operator_param_id = LookupFuncName(param, 4, typeId, false);
+
+ /* estimators must return float8 */
+ if (get_func_rettype(operator_param_id) != FLOAT8OID)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("restriction estimator function %s must return type \"float8\"",
+ NameListToString(param))));
+
+ /* Require EXECUTE rights for the estimator */
+ aclresult = pg_proc_aclcheck(operator_param_id, GetUserId(), ACL_EXECUTE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_PROC,
+ NameListToString(param));
+ }
+ else
+ operator_param_id = 0;
+ }
+ else if (param_type == Anum_pg_operator_oprjoin)
+ {
+ if (PointerIsValid(param))
+ {
+ Oid typeId[5];
+ 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 arguments, but we still allow the old 4-argument form. Try the
+ * preferred form first.
+ */
+ operator_param_id = LookupFuncName(param, 5, typeId, true);
+ if (!OidIsValid(operator_param_id))
+ operator_param_id = LookupFuncName(param, 4, typeId, true);
+ /* If not found, reference the 5-argument signature in error msg */
+ if (!OidIsValid(operator_param_id))
+ operator_param_id = LookupFuncName(param, 5, typeId, false);
+
+ /* estimators must return float8 */
+ if (get_func_rettype(operator_param_id) != FLOAT8OID)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("restriction estimator function %s must return type \"float8\"",
+ NameListToString(param))));
+
+ /* Require EXECUTE rights for the estimator */
+ aclresult = pg_proc_aclcheck(operator_param_id, GetUserId(), ACL_EXECUTE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_PROC,
+ NameListToString(param));
+ }
+ else
+ operator_param_id = 0;
+ }
+
+ if (OidIsValid(operator_param_id))
+ {
+ values[param_type - 1] = ObjectIdGetDatum(operator_param_id);
+ replaces[param_type - 1] = true;
+ }
+ else
+ ereport(ERROR,
+ (errmsg_internal("Not found function or operator for alter operator")));
+ }
+
+ /* Update heap */
+ tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(baseId));
+ if (HeapTupleIsValid(tup))
+ {
+ tup = heap_modify_tuple(tup,
+ RelationGetDescr(catalog),
+ values,
+ nulls,
+ replaces);
+
+ simple_heap_update(catalog, &tup->t_self, tup);
+ CatalogUpdateIndexes(catalog, tup);
+ }
+ }
+
+ heap_close(catalog, RowExclusiveLock);
+}
\ No newline at end of file
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index b4a1aac..43e0d66 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -320,3 +320,74 @@ RemoveOperatorById(Oid operOid)
heap_close(relation, RowExclusiveLock);
}
+
+ObjectAddress
+ExecAlterOperatorStmt(AlterOperatorStmt *stmt)
+{
+ ObjectAddress address;
+ Relation catalog;
+ Relation relation;
+ Datum datum;
+ Oid ownerId;
+ bool isnull;
+ HeapTuple tup;
+
+ /* Address to be modified operator. */
+ address = get_object_address(OBJECT_OPERATOR,
+ stmt->object,
+ stmt->objarg,
+ &relation,
+ AccessExclusiveLock,
+ false);
+ Assert(relation == NULL);
+
+ /* Check user rights. */
+ if (!superuser())
+ {
+ AclObjectKind aclkind = get_object_aclkind(address.classId);
+ AttrNumber Anum_name = get_object_attnum_name(address.classId);
+ AttrNumber Anum_owner = get_object_attnum_owner(address.classId);;
+
+ catalog = heap_open(address.classId, RowExclusiveLock);
+
+ tup = get_catalog_object_by_oid(catalog, address.objectId);
+
+ if (tup == NULL)
+ elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
+ address.objectId, RelationGetRelationName(catalog));
+
+ datum = heap_getattr(tup, Anum_owner,
+ RelationGetDescr(catalog), &isnull);
+ Assert(!isnull);
+ ownerId = DatumGetObjectId(datum);
+
+ /* must be owner */
+ if (!has_privs_of_role(GetUserId(), ownerId))
+ {
+ char *objname;
+ char namebuf[NAMEDATALEN];
+
+ if (Anum_name != InvalidAttrNumber)
+ {
+ datum = heap_getattr(tup, Anum_name,
+ RelationGetDescr(catalog), &isnull);
+ Assert(!isnull);
+ objname = NameStr(*DatumGetName(datum));
+ }
+ else
+ {
+ snprintf(namebuf, sizeof(namebuf), "%u",
+ HeapTupleGetOid(tup));
+ objname = namebuf;
+ }
+ aclcheck_error(ACLCHECK_NOT_OWNER, aclkind, objname);
+ }
+ heap_close(catalog, RowExclusiveLock);
+ }
+
+ OperatorUpd(address.classId,
+ address.objectId,
+ stmt->defnames);
+
+ return address;
+}
\ No newline at end of file
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 4c363d3..09cbf88 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3212,6 +3212,19 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from)
return newnode;
}
+static AlterOperatorStmt *
+_copyAlterOperatorStmt(const AlterOperatorStmt *from)
+{
+ AlterOperatorStmt *newnode = makeNode(AlterOperatorStmt);
+
+ COPY_NODE_FIELD(relation);
+ COPY_NODE_FIELD(object);
+ COPY_NODE_FIELD(objarg);
+ COPY_NODE_FIELD(defnames);
+
+ return newnode;
+}
+
static RuleStmt *
_copyRuleStmt(const RuleStmt *from)
{
@@ -4615,6 +4628,9 @@ copyObject(const void *from)
case T_AlterOwnerStmt:
retval = _copyAlterOwnerStmt(from);
break;
+ case T_AlterOperatorStmt:
+ retval = _copyAlterOperatorStmt(from);
+ break;
case T_RuleStmt:
retval = _copyRuleStmt(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index f19251e..017891a 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1339,6 +1339,17 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
}
static bool
+_equalAlterOperatorStmt(const AlterOperatorStmt *a, const AlterOperatorStmt *b)
+{
+ COMPARE_NODE_FIELD(relation);
+ COMPARE_NODE_FIELD(object);
+ COMPARE_NODE_FIELD(objarg);
+ COMPARE_NODE_FIELD(defnames);
+
+ return true;
+}
+
+static bool
_equalRuleStmt(const RuleStmt *a, const RuleStmt *b)
{
COMPARE_NODE_FIELD(relation);
@@ -2980,6 +2991,9 @@ equal(const void *a, const void *b)
case T_AlterOwnerStmt:
retval = _equalAlterOwnerStmt(a, b);
break;
+ case T_AlterOperatorStmt:
+ retval = _equalAlterOperatorStmt(a, b);
+ break;
case T_RuleStmt:
retval = _equalRuleStmt(a, b);
break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e0ff6f1..d621b8d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -232,7 +232,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
AlterEventTrigStmt
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
- AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterSystemStmt AlterTableStmt
+ AlterObjectSchemaStmt AlterOwnerStmt AlterOperatorStmt AlterSeqStmt AlterSystemStmt AlterTableStmt
AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt
AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt
AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt
@@ -769,6 +769,7 @@ stmt :
| AlterGroupStmt
| AlterObjectSchemaStmt
| AlterOwnerStmt
+ | AlterOperatorStmt
| AlterPolicyStmt
| AlterSeqStmt
| AlterSystemStmt
@@ -8198,6 +8199,24 @@ AlterObjectSchemaStmt:
/*****************************************************************************
*
+ * ALTER OPERATOR name SET define
+ *
+ *****************************************************************************/
+
+AlterOperatorStmt:
+ ALTER OPERATOR any_operator oper_argtypes SET definition
+ {
+ AlterOperatorStmt *n = makeNode(AlterOperatorStmt);
+ n->object = $3;
+ n->objarg = $4;
+ n->defnames = $6;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
* ALTER THING name OWNER TO newname
*
*****************************************************************************/
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 7db9f96..5597901 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -149,6 +149,7 @@ check_xact_readonly(Node *parsetree)
case T_AlterRoleSetStmt:
case T_AlterObjectSchemaStmt:
case T_AlterOwnerStmt:
+ case T_AlterOperatorStmt:
case T_AlterSeqStmt:
case T_AlterTableMoveAllStmt:
case T_AlterTableStmt:
@@ -861,6 +862,19 @@ standard_ProcessUtility(Node *parsetree,
}
break;
+ case T_AlterOperatorStmt:
+ {
+ AlterOperatorStmt *stmt = (AlterOperatorStmt *) parsetree;
+ if (EventTriggerSupportsObjectType(OBJECT_OPERATOR)) {
+ ProcessUtilitySlow(parsetree, queryString,
+ context, params,
+ dest, completionTag);
+ }
+ else
+ ExecAlterOperatorStmt(stmt);
+ }
+ break;
+
case T_CommentStmt:
{
CommentStmt *stmt = (CommentStmt *) parsetree;
@@ -916,12 +930,14 @@ ProcessUtilitySlow(Node *parsetree,
ObjectAddress address;
ObjectAddress secondaryObject = InvalidObjectAddress;
+
/* All event trigger calls are done only when isCompleteQuery is true */
needCleanup = isCompleteQuery && EventTriggerBeginCompleteQuery();
/* PG_TRY block is to ensure we call EventTriggerEndCompleteQuery */
PG_TRY();
{
+
if (isCompleteQuery)
EventTriggerDDLCommandStart(parsetree);
@@ -1481,6 +1497,10 @@ ProcessUtilitySlow(Node *parsetree,
address = ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
break;
+ case T_AlterOperatorStmt:
+ address = ExecAlterOperatorStmt((AlterOperatorStmt *) parsetree);
+ break;
+
case T_CommentStmt:
address = CommentObject((CommentStmt *) parsetree);
break;
@@ -2494,6 +2514,10 @@ CreateCommandTag(Node *parsetree)
tag = "ALTER OPERATOR FAMILY";
break;
+ case T_AlterOperatorStmt:
+ tag = "ALTER OPERATOR";
+ break;
+
case T_AlterTSDictionaryStmt:
tag = "ALTER TEXT SEARCH DICTIONARY";
break;
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 26c9d4e..67420b1 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1837,4 +1837,8 @@ extern ObjectAddress OperatorCreate(const char *operatorName,
bool canMerge,
bool canHash);
+extern void OperatorUpd(Oid classId,
+ Oid baseId,
+ List *operator_params);
+
#endif /* PG_OPERATOR_H */
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index dcb6c08..8ab2207 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -73,6 +73,7 @@ extern void interpret_function_parameter_list(List *parameters,
/* commands/operatorcmds.c */
extern ObjectAddress DefineOperator(List *names, List *parameters);
extern void RemoveOperatorById(Oid operOid);
+extern ObjectAddress ExecAlterOperatorStmt(AlterOperatorStmt *stmt);
/* commands/aggregatecmds.c */
extern ObjectAddress DefineAggregate(List *name, List *args, bool oldstyle,
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 290cdb3..f8acda4 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -347,6 +347,7 @@ typedef enum NodeTag
T_DropTableSpaceStmt,
T_AlterObjectSchemaStmt,
T_AlterOwnerStmt,
+ T_AlterOperatorStmt,
T_DropOwnedStmt,
T_ReassignOwnedStmt,
T_CompositeTypeStmt,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 868905b..c20868f 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2543,6 +2543,20 @@ typedef struct AlterOwnerStmt
/* ----------------------
+ * Alter Operator Set Restrict, Join
+ * ----------------------
+ */
+typedef struct AlterOperatorStmt
+{
+ NodeTag type;
+ RangeVar *relation; /* in case it's a table */
+ List *object; /* in case it's some other object */
+ List *objarg; /* argument types, if applicable */
+ List *defnames; /* operator */
+} AlterOperatorStmt;
+
+
+/* ----------------------
* Create Rule Statement
* ----------------------
*/
diff --git a/src/test/regress/expected/alter_operator.out b/src/test/regress/expected/alter_operator.out
new file mode 100644
index 0000000..1dbb05e
--- /dev/null
+++ b/src/test/regress/expected/alter_operator.out
@@ -0,0 +1,78 @@
+CREATE OR REPLACE FUNCTION fn_op2(boolean, boolean)
+RETURNS boolean AS $$
+ SELECT NULL::BOOLEAN;
+$$ LANGUAGE sql IMMUTABLE;
+CREATE OPERATOR === (
+ LEFTARG = boolean,
+ RIGHTARG = boolean,
+ PROCEDURE = fn_op2,
+ COMMUTATOR = ===,
+ NEGATOR = !==,
+ RESTRICT = contsel,
+ JOIN = contjoinsel,
+ SORT1, SORT2, LTCMP, GTCMP, HASHES, MERGES
+);
+--
+-- Reset and set params
+--
+ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NULL);
+ALTER OPERATOR === (boolean, boolean) SET (JOIN = NULL);
+SELECT oprrest, oprjoin FROM pg_operator WHERE oprname = '===' AND oprleft = 16 AND oprright = 16;
+ oprrest | oprjoin
+---------+---------
+ - | -
+(1 row)
+
+ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = contsel);
+ALTER OPERATOR === (boolean, boolean) SET (JOIN = contjoinsel);
+SELECT oprrest, oprjoin FROM pg_operator WHERE oprname = '===' AND oprleft = 16 AND oprright = 16;
+ oprrest | oprjoin
+---------+-------------
+ contsel | contjoinsel
+(1 row)
+
+ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NULL,
+ JOIN = NULL);
+SELECT oprrest, oprjoin
+FROM pg_operator WHERE oprname = '===' AND oprleft = 16 AND oprright = 16;
+ oprrest | oprjoin
+---------+---------
+ - | -
+(1 row)
+
+ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = contsel,
+ JOIN = contjoinsel);
+SELECT oprrest, oprjoin
+FROM pg_operator WHERE oprname = '===' AND oprleft = 16 AND oprright = 16;
+ oprrest | oprjoin
+---------+-------------
+ contsel | contjoinsel
+(1 row)
+
+--
+-- Trying set the wrong parameters
+--
+ALTER OPERATOR === (boolean, boolean) SET (COMMUTATOR = ====);
+WARNING: operator attribute "commutator" not recognized
+ALTER OPERATOR === (boolean, boolean) SET (NEGATOR = ====);
+WARNING: operator attribute "negator" not recognized
+ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = blabla);
+ERROR: function blabla(internal, oid, internal, integer) does not exist
+ALTER OPERATOR === (boolean, boolean) SET (JOIN = blabla);
+ERROR: function blabla(internal, oid, internal, smallint, internal) does not exist
+ALTER OPERATOR === (boolean, boolean) SET (COMMUTATOR = !==);
+WARNING: operator attribute "commutator" not recognized
+ALTER OPERATOR === (boolean, boolean) SET (NEGATOR = !==);
+WARNING: operator attribute "negator" not recognized
+--
+-- Trying set params from wrong user
+--
+CREATE USER regression_user;
+SET SESSION AUTHORIZATION regression_user;
+ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NULL);
+ERROR: must be owner of operator ===
+ALTER OPERATOR === (boolean, boolean) SET (JOIN = NULL);
+ERROR: must be owner of operator ===
+RESET SESSION AUTHORIZATION;
+DROP USER regression_user;
+DROP OPERATOR === (boolean, boolean);
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 91780cd..836f9f9 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -103,7 +103,7 @@ test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combo
# NB: temp.sql does a reconnect which transiently uses 2 connections,
# so keep this parallel group to at most 19 tests
# ----------
-test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml
+test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml alter_operator
# event triggers cannot run concurrently with any test that runs DDL
test: event_trigger
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index a2e0ceb..fbec844 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -146,6 +146,7 @@ test: without_oid
test: conversion
test: truncate
test: alter_table
+test: alter_operator
test: sequence
test: polymorphism
test: rowtypes
diff --git a/src/test/regress/sql/alter_operator.sql b/src/test/regress/sql/alter_operator.sql
new file mode 100644
index 0000000..8365331
--- /dev/null
+++ b/src/test/regress/sql/alter_operator.sql
@@ -0,0 +1,68 @@
+CREATE OR REPLACE FUNCTION fn_op2(boolean, boolean)
+RETURNS boolean AS $$
+ SELECT NULL::BOOLEAN;
+$$ LANGUAGE sql IMMUTABLE;
+CREATE OPERATOR === (
+ LEFTARG = boolean,
+ RIGHTARG = boolean,
+ PROCEDURE = fn_op2,
+ COMMUTATOR = ===,
+ NEGATOR = !==,
+ RESTRICT = contsel,
+ JOIN = contjoinsel,
+ SORT1, SORT2, LTCMP, GTCMP, HASHES, MERGES
+);
+
+
+--
+-- Reset and set params
+--
+
+ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NULL);
+ALTER OPERATOR === (boolean, boolean) SET (JOIN = NULL);
+
+SELECT oprrest, oprjoin FROM pg_operator WHERE oprname = '===' AND oprleft = 16 AND oprright = 16;
+
+ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = contsel);
+ALTER OPERATOR === (boolean, boolean) SET (JOIN = contjoinsel);
+
+SELECT oprrest, oprjoin FROM pg_operator WHERE oprname = '===' AND oprleft = 16 AND oprright = 16;
+
+ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NULL,
+ JOIN = NULL);
+
+SELECT oprrest, oprjoin
+FROM pg_operator WHERE oprname = '===' AND oprleft = 16 AND oprright = 16;
+
+ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = contsel,
+ JOIN = contjoinsel);
+
+SELECT oprrest, oprjoin
+FROM pg_operator WHERE oprname = '===' AND oprleft = 16 AND oprright = 16;
+
+--
+-- Trying set the wrong parameters
+--
+
+ALTER OPERATOR === (boolean, boolean) SET (COMMUTATOR = ====);
+ALTER OPERATOR === (boolean, boolean) SET (NEGATOR = ====);
+ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = blabla);
+ALTER OPERATOR === (boolean, boolean) SET (JOIN = blabla);
+ALTER OPERATOR === (boolean, boolean) SET (COMMUTATOR = !==);
+ALTER OPERATOR === (boolean, boolean) SET (NEGATOR = !==);
+
+
+--
+-- Trying set params from wrong user
+--
+
+CREATE USER regression_user;
+SET SESSION AUTHORIZATION regression_user;
+
+ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NULL);
+ALTER OPERATOR === (boolean, boolean) SET (JOIN = NULL);
+
+RESET SESSION AUTHORIZATION;
+DROP USER regression_user;
+
+DROP OPERATOR === (boolean, boolean);
\ No newline at end of file
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 4b650d1..d86072f 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -70,6 +70,7 @@ AlterFunctionStmt
AlterObjectSchemaStmt
AlterOpFamilyStmt
AlterOwnerStmt
+AlterOperatorStmt
AlterPolicyStmt
AlterRoleSetStmt
AlterRoleStmt
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers