+
+/*
+ * AlterOperator
+ * routine implementing ALTER OPERATOR <operator> SET (option = ...).
+ *
+ * Currently, only RESTRICT and JOIN estimator functions can be changed.
+ */
+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];
+ List *restrictionName = NIL; /* optional restrict. sel. procedure */
+ bool updateRestriction = false;
+ Oid restrictionOid;
+ List *joinName = NIL; /* optional join sel. procedure */
+ bool updateJoin = false;
+ Oid joinOid;
+
+ /* Look up the operator */
+ oprId = LookupOperNameTypeNames(NULL, stmt->opername,
+ (TypeName *) linitial(stmt->operargs),
+ (TypeName *) lsecond(stmt->operargs),
+ false, -1);
+ catalog = heap_open(OperatorRelationId, RowExclusiveLock);
+ tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
+ if (tup == NULL)
+ 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);
+
+ if (pg_strcasecmp(defel->defname, "restrict") == 0)
+ {
+ restrictionName = param;
+ updateRestriction = true;
+ }
+ else if (pg_strcasecmp(defel->defname, "join") == 0)
+ {
+ joinName = param;
+ updateJoin = true;
+ }
+
+ /*
+ * The rest of the options that CREATE accepts cannot be changed.
+ * Check for them so that we can give a meaningful error message.
+ */
+ else if (pg_strcasecmp(defel->defname, "leftarg") == 0 ||
+ pg_strcasecmp(defel->defname, "rightarg") == 0 ||
+ pg_strcasecmp(defel->defname, "procedure") == 0 ||
+ pg_strcasecmp(defel->defname, "commutator") == 0 ||
+ pg_strcasecmp(defel->defname, "negator") == 0 ||
+ pg_strcasecmp(defel->defname, "hashes") == 0 ||
+ pg_strcasecmp(defel->defname, "merges") == 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("operator attribute \"%s\" can not be changed",
+ defel->defname)));
+ }
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("operator attribute \"%s\" not recognized",
+ defel->defname)));
+ }
+
+ /* Check permissions. Must be owner. */
+ if (!pg_oper_ownercheck(oprId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
+ NameStr(oprForm->oprname));
+
+ /*
+ * Look up restriction and join estimators if specified
+ */
+ if (restrictionName)
+ restrictionOid = ValidateRestrictionEstimator(restrictionName);
+ else
+ restrictionOid = InvalidOid;
+ if (joinName)
+ joinOid = ValidateJoinEstimator(joinName);
+ else
+ joinOid = InvalidOid;
+
+ /* Perform additional checks, like OperatorCreate does */
+ if (!(OidIsValid(oprForm->oprleft) && OidIsValid(oprForm->oprright)))
+ {
+ /* If it's not a binary op, these things mustn't be set: */
+ if (OidIsValid(joinOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("only binary operators can have join selectivity")));
+ }
+
+ if (oprForm->oprresult != BOOLOID)
+ {
+ if (OidIsValid(restrictionOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("only boolean operators can have restriction selectivity")));
+ if (OidIsValid(joinOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("only boolean operators can have join selectivity")));
+ }
+
+ /* 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;
+ values[Anum_pg_operator_oprrest - 1] = restrictionOid;
+ }
+ if (updateJoin)
+ {
+ replaces[Anum_pg_operator_oprjoin - 1] = true;
+ values[Anum_pg_operator_oprjoin - 1] = joinOid;
+ }
+
+ tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
+ values, nulls, replaces);
+
+ simple_heap_update(catalog, &tup->t_self, tup);
+ CatalogUpdateIndexes(catalog, tup);
+
+ address = makeOperatorDependencies(tup, true);
+
+ InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
+
+ heap_close(catalog, NoLock);
+
+ return address;
+}