Hello hackers.

This is the fifth version of the patch (the fourth was unsuccessful :)).
I added documentation and was held a small refactoring.

Thanks.
-- 
Uriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
diff --git a/doc/src/sgml/ref/alter_operator.sgml b/doc/src/sgml/ref/alter_operator.sgml
index bdb2d02..4aaeed0 100644
--- a/doc/src/sgml/ref/alter_operator.sgml
+++ b/doc/src/sgml/ref/alter_operator.sgml
@@ -26,6 +26,11 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
 
 ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } )
                SET SCHEMA <replaceable>new_schema</replaceable>
+
+ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } ) SET (
+    [, RESTRICT = { <replaceable class="parameter">res_proc</replaceable> | NULL } ]
+    [, JOIN = { <replaceable class="parameter">join_proc</replaceable> | NULL } ]
+)
 </synopsis>
  </refsynopsisdiv>
 
@@ -34,8 +39,7 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
 
   <para>
    <command>ALTER OPERATOR</command> changes the definition of
-   an operator.  The only currently available functionality is to change the
-   owner of the operator.
+   an operator.
   </para>
 
   <para>
@@ -98,6 +102,25 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
      </para>
     </listitem>
    </varlistentry>
+
+   <varlistentry>
+     <term><replaceable class="parameter">res_proc</replaceable></term>
+     <listitem>
+       <para>
+         The restriction selectivity estimator function for this operator.
+       </para>
+      </listitem>
+   </varlistentry>
+
+   <varlistentry>
+     <term><replaceable class="parameter">join_proc</replaceable></term>
+     <listitem>
+       <para>
+         The join selectivity estimator function for this operator.
+       </para>
+     </listitem>
+   </varlistentry>
+
   </variablelist>
  </refsect1>
 
@@ -109,6 +132,13 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
 <programlisting>
 ALTER OPERATOR @@ (text, text) OWNER TO joe;
 </programlisting></para>
+
+  <para>
+    Change the restriction and join selectivity estimator function of a custom operator <literal>a && b</literal> for type <type>int[]</type>:
+<programlisting>
+ALTER OPERATOR && (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
+</programlisting></para>
+
  </refsect1>
 
  <refsect1>
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 072f530..f5ff381 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,150 @@ 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 (PointerIsValid(param) && pg_strcasecmp(NameListToString(param), "null") == 0)
+			{
+				values[param_type - 1] = ObjectIdGetDatum(InvalidOid);
+				replaces[param_type - 1] = true;
+				continue;
+			}
+
+			if (!PointerIsValid(param))
+				operator_param_id = InvalidOid;
+			else if (param_type == Anum_pg_operator_oprrest)
+			{
+				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 if (param_type == Anum_pg_operator_oprjoin)
+			{
+				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));
+			}
+
+			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);
+}
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index b4a1aac..181823b 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;
+}
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..213f2ce 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;
@@ -1481,6 +1495,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 +2512,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..967de1f
--- /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);
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

Reply via email to