Commit 321eed5f authored by Heikki Linnakangas's avatar Heikki Linnakangas

Add ALTER OPERATOR command, for changing selectivity estimator functions.

Other options cannot be changed, as it's not totally clear if cached plans
would need to be invalidated if one of the other options change. Selectivity
estimator functions only change plan costs, not correctness of plans, so
those should be safe.

Original patch by Uriy Zhuravlev, heavily edited by me.
parent 705d397c
...@@ -26,6 +26,11 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla ...@@ -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 } ) ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } )
SET SCHEMA <replaceable>new_schema</replaceable> 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> | NONE }
| JOIN = { <replaceable class="parameter">join_proc</replaceable> | NONE }
} [, ... ] )
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
...@@ -34,8 +39,7 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla ...@@ -34,8 +39,7 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
<para> <para>
<command>ALTER OPERATOR</command> changes the definition of <command>ALTER OPERATOR</command> changes the definition of
an operator. The only currently available functionality is to change the an operator.
owner of the operator.
</para> </para>
<para> <para>
...@@ -98,6 +102,25 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla ...@@ -98,6 +102,25 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><replaceable class="parameter">res_proc</replaceable></term>
<listitem>
<para>
The restriction selectivity estimator function for this operator; write NONE to remove existing selectivity estimator.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">join_proc</replaceable></term>
<listitem>
<para>
The join selectivity estimator function for this operator; write NONE to remove existing selectivity estimator.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
...@@ -109,6 +132,13 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla ...@@ -109,6 +132,13 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
<programlisting> <programlisting>
ALTER OPERATOR @@ (text, text) OWNER TO joe; ALTER OPERATOR @@ (text, text) OWNER TO joe;
</programlisting></para> </programlisting></para>
<para>
Change the restriction and join selectivity estimator functions 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>
<refsect1> <refsect1>
......
...@@ -51,6 +51,9 @@ ...@@ -51,6 +51,9 @@
#include "utils/rel.h" #include "utils/rel.h"
#include "utils/syscache.h" #include "utils/syscache.h"
static Oid ValidateRestrictionEstimator(List *restrictionName);
static Oid ValidateJoinEstimator(List *joinName);
/* /*
* DefineOperator * DefineOperator
* this function extracts all the information from the * this function extracts all the information from the
...@@ -80,7 +83,7 @@ DefineOperator(List *names, List *parameters) ...@@ -80,7 +83,7 @@ DefineOperator(List *names, List *parameters)
Oid functionOid; /* functions converted to OID */ Oid functionOid; /* functions converted to OID */
Oid restrictionOid; Oid restrictionOid;
Oid joinOid; Oid joinOid;
Oid typeId[5]; /* only need up to 5 args here */ Oid typeId[2]; /* to hold left and right arg */
int nargs; int nargs;
ListCell *pl; ListCell *pl;
...@@ -140,11 +143,14 @@ DefineOperator(List *names, List *parameters) ...@@ -140,11 +143,14 @@ DefineOperator(List *names, List *parameters)
else if (pg_strcasecmp(defel->defname, "gtcmp") == 0) else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
canMerge = true; canMerge = true;
else else
{
/* WARNING, not ERROR, for historical backwards-compatibility */
ereport(WARNING, ereport(WARNING,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("operator attribute \"%s\" not recognized", errmsg("operator attribute \"%s\" not recognized",
defel->defname))); defel->defname)));
} }
}
/* /*
* make sure we have our required definitions * make sure we have our required definitions
...@@ -216,10 +222,46 @@ DefineOperator(List *names, List *parameters) ...@@ -216,10 +222,46 @@ DefineOperator(List *names, List *parameters)
aclcheck_error_type(aclresult, rettype); aclcheck_error_type(aclresult, rettype);
/* /*
* Look up restriction estimator if specified * Look up restriction and join estimators if specified
*/ */
if (restrictionName) if (restrictionName)
{ restrictionOid = ValidateRestrictionEstimator(restrictionName);
else
restrictionOid = InvalidOid;
if (joinName)
joinOid = ValidateJoinEstimator(joinName);
else
joinOid = InvalidOid;
/*
* now have OperatorCreate do all the work..
*/
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 */
restrictionOid, /* optional restrict. sel. procedure */
joinOid, /* optional join sel. procedure name */
canMerge, /* operator merges */
canHash); /* operator hashes */
}
/*
* Look up a restriction estimator function ny name, and verify that it has
* 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[0] = INTERNALOID; /* PlannerInfo */
typeId[1] = OIDOID; /* operator OID */ typeId[1] = OIDOID; /* operator OID */
typeId[2] = INTERNALOID; /* args list */ typeId[2] = INTERNALOID; /* args list */
...@@ -239,15 +281,22 @@ DefineOperator(List *names, List *parameters) ...@@ -239,15 +281,22 @@ DefineOperator(List *names, List *parameters)
if (aclresult != ACLCHECK_OK) if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC, aclcheck_error(aclresult, ACL_KIND_PROC,
NameListToString(restrictionName)); NameListToString(restrictionName));
}
else
restrictionOid = InvalidOid;
/* return restrictionOid;
* Look up join estimator if specified }
/*
* Look up a join estimator function ny name, and verify that it has the
* correct signature and we have the permissions to attach it to an
* operator.
*/ */
if (joinName) static Oid
{ ValidateJoinEstimator(List *joinName)
{
Oid typeId[5];
Oid joinOid;
AclResult aclresult;
typeId[0] = INTERNALOID; /* PlannerInfo */ typeId[0] = INTERNALOID; /* PlannerInfo */
typeId[1] = OIDOID; /* operator OID */ typeId[1] = OIDOID; /* operator OID */
typeId[2] = INTERNALOID; /* args list */ typeId[2] = INTERNALOID; /* args list */
...@@ -255,8 +304,8 @@ DefineOperator(List *names, List *parameters) ...@@ -255,8 +304,8 @@ DefineOperator(List *names, List *parameters)
typeId[4] = INTERNALOID; /* SpecialJoinInfo */ typeId[4] = INTERNALOID; /* SpecialJoinInfo */
/* /*
* As of Postgres 8.4, the preferred signature for join estimators has * As of Postgres 8.4, the preferred signature for join estimators has 5
* 5 arguments, but we still allow the old 4-argument form. Try the * arguments, but we still allow the old 4-argument form. Try the
* preferred form first. * preferred form first.
*/ */
joinOid = LookupFuncName(joinName, 5, typeId, true); joinOid = LookupFuncName(joinName, 5, typeId, true);
...@@ -278,25 +327,8 @@ DefineOperator(List *names, List *parameters) ...@@ -278,25 +327,8 @@ DefineOperator(List *names, List *parameters)
if (aclresult != ACLCHECK_OK) if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC, aclcheck_error(aclresult, ACL_KIND_PROC,
NameListToString(joinName)); NameListToString(joinName));
}
else
joinOid = InvalidOid;
/* return joinOid;
* now have OperatorCreate do all the work..
*/
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 */
restrictionOid, /* optional restrict. sel. procedure */
joinOid, /* optional join sel. procedure name */
canMerge, /* operator merges */
canHash); /* operator hashes */
} }
/* /*
...@@ -320,3 +352,154 @@ RemoveOperatorById(Oid operOid) ...@@ -320,3 +352,154 @@ RemoveOperatorById(Oid operOid)
heap_close(relation, RowExclusiveLock); heap_close(relation, RowExclusiveLock);
} }
/*
* 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);
heap_close(catalog, RowExclusiveLock);
return address;
}
...@@ -3212,6 +3212,18 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from) ...@@ -3212,6 +3212,18 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from)
return newnode; return newnode;
} }
static AlterOperatorStmt *
_copyAlterOperatorStmt(const AlterOperatorStmt *from)
{
AlterOperatorStmt *newnode = makeNode(AlterOperatorStmt);
COPY_NODE_FIELD(opername);
COPY_NODE_FIELD(operargs);
COPY_NODE_FIELD(options);
return newnode;
}
static RuleStmt * static RuleStmt *
_copyRuleStmt(const RuleStmt *from) _copyRuleStmt(const RuleStmt *from)
{ {
...@@ -4615,6 +4627,9 @@ copyObject(const void *from) ...@@ -4615,6 +4627,9 @@ copyObject(const void *from)
case T_AlterOwnerStmt: case T_AlterOwnerStmt:
retval = _copyAlterOwnerStmt(from); retval = _copyAlterOwnerStmt(from);
break; break;
case T_AlterOperatorStmt:
retval = _copyAlterOperatorStmt(from);
break;
case T_RuleStmt: case T_RuleStmt:
retval = _copyRuleStmt(from); retval = _copyRuleStmt(from);
break; break;
......
...@@ -1338,6 +1338,16 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b) ...@@ -1338,6 +1338,16 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
return true; return true;
} }
static bool
_equalAlterOperatorStmt(const AlterOperatorStmt *a, const AlterOperatorStmt *b)
{
COMPARE_NODE_FIELD(opername);
COMPARE_NODE_FIELD(operargs);
COMPARE_NODE_FIELD(options);
return true;
}
static bool static bool
_equalRuleStmt(const RuleStmt *a, const RuleStmt *b) _equalRuleStmt(const RuleStmt *a, const RuleStmt *b)
{ {
...@@ -2980,6 +2990,9 @@ equal(const void *a, const void *b) ...@@ -2980,6 +2990,9 @@ equal(const void *a, const void *b)
case T_AlterOwnerStmt: case T_AlterOwnerStmt:
retval = _equalAlterOwnerStmt(a, b); retval = _equalAlterOwnerStmt(a, b);
break; break;
case T_AlterOperatorStmt:
retval = _equalAlterOperatorStmt(a, b);
break;
case T_RuleStmt: case T_RuleStmt:
retval = _equalRuleStmt(a, b); retval = _equalRuleStmt(a, b);
break; break;
......
...@@ -232,7 +232,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); ...@@ -232,7 +232,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
AlterEventTrigStmt AlterEventTrigStmt
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
AlterFdwStmt AlterForeignServerStmt AlterGroupStmt AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterSystemStmt AlterTableStmt AlterObjectSchemaStmt AlterOwnerStmt AlterOperatorStmt AlterSeqStmt AlterSystemStmt AlterTableStmt
AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt
AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt
AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt
...@@ -359,7 +359,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); ...@@ -359,7 +359,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
any_operator expr_list attrs any_operator expr_list attrs
target_list opt_target_list insert_column_list set_target_list target_list opt_target_list insert_column_list set_target_list
set_clause_list set_clause multiple_set_clause set_clause_list set_clause multiple_set_clause
ctext_expr_list ctext_row def_list indirection opt_indirection ctext_expr_list ctext_row def_list operator_def_list indirection opt_indirection
reloption_list group_clause TriggerFuncArgs select_limit reloption_list group_clause TriggerFuncArgs select_limit
opt_select_limit opclass_item_list opclass_drop_list opt_select_limit opclass_item_list opclass_drop_list
opclass_purpose opt_opfamily transaction_mode_list_or_empty opclass_purpose opt_opfamily transaction_mode_list_or_empty
...@@ -432,7 +432,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); ...@@ -432,7 +432,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <node> TableElement TypedTableElement ConstraintElem TableFuncElement %type <node> TableElement TypedTableElement ConstraintElem TableFuncElement
%type <node> columnDef columnOptions %type <node> columnDef columnOptions
%type <defelt> def_elem reloption_elem old_aggr_elem %type <defelt> def_elem reloption_elem old_aggr_elem operator_def_elem
%type <node> def_arg columnElem where_clause where_or_current_clause %type <node> def_arg columnElem where_clause where_or_current_clause
a_expr b_expr c_expr AexprConst indirection_el a_expr b_expr c_expr AexprConst indirection_el
columnref in_expr having_clause func_table array_expr columnref in_expr having_clause func_table array_expr
...@@ -769,6 +769,7 @@ stmt : ...@@ -769,6 +769,7 @@ stmt :
| AlterGroupStmt | AlterGroupStmt
| AlterObjectSchemaStmt | AlterObjectSchemaStmt
| AlterOwnerStmt | AlterOwnerStmt
| AlterOperatorStmt
| AlterPolicyStmt | AlterPolicyStmt
| AlterSeqStmt | AlterSeqStmt
| AlterSystemStmt | AlterSystemStmt
...@@ -8196,6 +8197,33 @@ AlterObjectSchemaStmt: ...@@ -8196,6 +8197,33 @@ AlterObjectSchemaStmt:
} }
; ;
/*****************************************************************************
*
* ALTER OPERATOR name SET define
*
*****************************************************************************/
AlterOperatorStmt:
ALTER OPERATOR any_operator oper_argtypes SET '(' operator_def_list ')'
{
AlterOperatorStmt *n = makeNode(AlterOperatorStmt);
n->opername = $3;
n->operargs = $4;
n->options = $7;
$$ = (Node *)n;
}
;
operator_def_list: operator_def_elem { $$ = list_make1($1); }
| operator_def_list ',' operator_def_elem { $$ = lappend($1, $3); }
;
operator_def_elem: ColLabel '=' NONE
{ $$ = makeDefElem($1, NULL); }
| ColLabel '=' def_arg
{ $$ = makeDefElem($1, (Node *) $3); }
;
/***************************************************************************** /*****************************************************************************
* *
* ALTER THING name OWNER TO newname * ALTER THING name OWNER TO newname
......
...@@ -149,6 +149,7 @@ check_xact_readonly(Node *parsetree) ...@@ -149,6 +149,7 @@ check_xact_readonly(Node *parsetree)
case T_AlterRoleSetStmt: case T_AlterRoleSetStmt:
case T_AlterObjectSchemaStmt: case T_AlterObjectSchemaStmt:
case T_AlterOwnerStmt: case T_AlterOwnerStmt:
case T_AlterOperatorStmt:
case T_AlterSeqStmt: case T_AlterSeqStmt:
case T_AlterTableMoveAllStmt: case T_AlterTableMoveAllStmt:
case T_AlterTableStmt: case T_AlterTableStmt:
...@@ -1481,6 +1482,10 @@ ProcessUtilitySlow(Node *parsetree, ...@@ -1481,6 +1482,10 @@ ProcessUtilitySlow(Node *parsetree,
address = ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree); address = ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
break; break;
case T_AlterOperatorStmt:
address = AlterOperator((AlterOperatorStmt *) parsetree);
break;
case T_CommentStmt: case T_CommentStmt:
address = CommentObject((CommentStmt *) parsetree); address = CommentObject((CommentStmt *) parsetree);
break; break;
...@@ -2494,6 +2499,10 @@ CreateCommandTag(Node *parsetree) ...@@ -2494,6 +2499,10 @@ CreateCommandTag(Node *parsetree)
tag = "ALTER OPERATOR FAMILY"; tag = "ALTER OPERATOR FAMILY";
break; break;
case T_AlterOperatorStmt:
tag = "ALTER OPERATOR";
break;
case T_AlterTSDictionaryStmt: case T_AlterTSDictionaryStmt:
tag = "ALTER TEXT SEARCH DICTIONARY"; tag = "ALTER TEXT SEARCH DICTIONARY";
break; break;
......
...@@ -73,6 +73,7 @@ extern void interpret_function_parameter_list(List *parameters, ...@@ -73,6 +73,7 @@ extern void interpret_function_parameter_list(List *parameters,
/* commands/operatorcmds.c */ /* commands/operatorcmds.c */
extern ObjectAddress DefineOperator(List *names, List *parameters); extern ObjectAddress DefineOperator(List *names, List *parameters);
extern void RemoveOperatorById(Oid operOid); extern void RemoveOperatorById(Oid operOid);
extern ObjectAddress AlterOperator(AlterOperatorStmt *stmt);
/* commands/aggregatecmds.c */ /* commands/aggregatecmds.c */
extern ObjectAddress DefineAggregate(List *name, List *args, bool oldstyle, extern ObjectAddress DefineAggregate(List *name, List *args, bool oldstyle,
......
...@@ -347,6 +347,7 @@ typedef enum NodeTag ...@@ -347,6 +347,7 @@ typedef enum NodeTag
T_DropTableSpaceStmt, T_DropTableSpaceStmt,
T_AlterObjectSchemaStmt, T_AlterObjectSchemaStmt,
T_AlterOwnerStmt, T_AlterOwnerStmt,
T_AlterOperatorStmt,
T_DropOwnedStmt, T_DropOwnedStmt,
T_ReassignOwnedStmt, T_ReassignOwnedStmt,
T_CompositeTypeStmt, T_CompositeTypeStmt,
......
...@@ -2543,6 +2543,19 @@ typedef struct AlterOwnerStmt ...@@ -2543,6 +2543,19 @@ typedef struct AlterOwnerStmt
} AlterOwnerStmt; } AlterOwnerStmt;
/* ----------------------
* Alter Operator Set Restrict, Join
* ----------------------
*/
typedef struct AlterOperatorStmt
{
NodeTag type;
List *opername; /* operator name */
List *operargs; /* operator's argument TypeNames */
List *options; /* List of DefElem nodes */
} AlterOperatorStmt;
/* ---------------------- /* ----------------------
* Create Rule Statement * Create Rule Statement
* ---------------------- * ----------------------
......
CREATE OR REPLACE FUNCTION alter_op_test_fn(boolean, boolean)
RETURNS boolean AS $$ SELECT NULL::BOOLEAN; $$ LANGUAGE sql IMMUTABLE;
CREATE OPERATOR === (
LEFTARG = boolean,
RIGHTARG = boolean,
PROCEDURE = alter_op_test_fn,
COMMUTATOR = ===,
NEGATOR = !==,
RESTRICT = contsel,
JOIN = contjoinsel,
HASHES, MERGES
);
--
-- Reset and set params
--
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NONE);
ALTER OPERATOR === (boolean, boolean) SET (JOIN = NONE);
SELECT oprrest, oprjoin FROM pg_operator WHERE oprname = '==='
AND oprleft = 'boolean'::regtype AND oprright = 'boolean'::regtype;
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 = 'boolean'::regtype AND oprright = 'boolean'::regtype;
oprrest | oprjoin
---------+-------------
contsel | contjoinsel
(1 row)
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NONE, JOIN = NONE);
SELECT oprrest, oprjoin FROM pg_operator WHERE oprname = '==='
AND oprleft = 'boolean'::regtype AND oprright = 'boolean'::regtype;
oprrest | oprjoin
---------+---------
- | -
(1 row)
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = contsel, JOIN = contjoinsel);
SELECT oprrest, oprjoin FROM pg_operator WHERE oprname = '==='
AND oprleft = 'boolean'::regtype AND oprright = 'boolean'::regtype;
oprrest | oprjoin
---------+-------------
contsel | contjoinsel
(1 row)
--
-- Test invalid options.
--
ALTER OPERATOR === (boolean, boolean) SET (COMMUTATOR = ====);
ERROR: operator attribute "commutator" can not be changed
ALTER OPERATOR === (boolean, boolean) SET (NEGATOR = ====);
ERROR: operator attribute "negator" can not be changed
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = non_existent_func);
ERROR: function non_existent_func(internal, oid, internal, integer) does not exist
ALTER OPERATOR === (boolean, boolean) SET (JOIN = non_existent_func);
ERROR: function non_existent_func(internal, oid, internal, smallint, internal) does not exist
ALTER OPERATOR === (boolean, boolean) SET (COMMUTATOR = !==);
ERROR: operator attribute "commutator" can not be changed
ALTER OPERATOR === (boolean, boolean) SET (NEGATOR = !==);
ERROR: operator attribute "negator" can not be changed
--
-- Test permission check. Must be owner to ALTER OPERATOR.
--
CREATE USER regtest_alter_user;
SET SESSION AUTHORIZATION regtest_alter_user_user;
ERROR: role "regtest_alter_user_user" does not exist
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NONE);
RESET SESSION AUTHORIZATION;
-- Clean up
DROP USER regression_alter_user;
ERROR: role "regression_alter_user" does not exist
DROP OPERATOR === (boolean, boolean);
...@@ -89,7 +89,7 @@ test: brin gin gist spgist privileges security_label collate matview lock replic ...@@ -89,7 +89,7 @@ test: brin gin gist spgist privileges security_label collate matview lock replic
# ---------- # ----------
# Another group of parallel tests # Another group of parallel tests
# ---------- # ----------
test: alter_generic misc psql async test: alter_generic alter_operator misc psql async
# rules cannot run concurrently with any test that creates a view # rules cannot run concurrently with any test that creates a view
test: rules test: rules
......
...@@ -111,6 +111,7 @@ test: replica_identity ...@@ -111,6 +111,7 @@ test: replica_identity
test: rowsecurity test: rowsecurity
test: object_address test: object_address
test: alter_generic test: alter_generic
test: alter_operator
test: misc test: misc
test: psql test: psql
test: async test: async
......
CREATE OR REPLACE FUNCTION alter_op_test_fn(boolean, boolean)
RETURNS boolean AS $$ SELECT NULL::BOOLEAN; $$ LANGUAGE sql IMMUTABLE;
CREATE OPERATOR === (
LEFTARG = boolean,
RIGHTARG = boolean,
PROCEDURE = alter_op_test_fn,
COMMUTATOR = ===,
NEGATOR = !==,
RESTRICT = contsel,
JOIN = contjoinsel,
HASHES, MERGES
);
--
-- Reset and set params
--
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NONE);
ALTER OPERATOR === (boolean, boolean) SET (JOIN = NONE);
SELECT oprrest, oprjoin FROM pg_operator WHERE oprname = '==='
AND oprleft = 'boolean'::regtype AND oprright = 'boolean'::regtype;
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = contsel);
ALTER OPERATOR === (boolean, boolean) SET (JOIN = contjoinsel);
SELECT oprrest, oprjoin FROM pg_operator WHERE oprname = '==='
AND oprleft = 'boolean'::regtype AND oprright = 'boolean'::regtype;
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NONE, JOIN = NONE);
SELECT oprrest, oprjoin FROM pg_operator WHERE oprname = '==='
AND oprleft = 'boolean'::regtype AND oprright = 'boolean'::regtype;
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = contsel, JOIN = contjoinsel);
SELECT oprrest, oprjoin FROM pg_operator WHERE oprname = '==='
AND oprleft = 'boolean'::regtype AND oprright = 'boolean'::regtype;
--
-- Test invalid options.
--
ALTER OPERATOR === (boolean, boolean) SET (COMMUTATOR = ====);
ALTER OPERATOR === (boolean, boolean) SET (NEGATOR = ====);
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = non_existent_func);
ALTER OPERATOR === (boolean, boolean) SET (JOIN = non_existent_func);
ALTER OPERATOR === (boolean, boolean) SET (COMMUTATOR = !==);
ALTER OPERATOR === (boolean, boolean) SET (NEGATOR = !==);
--
-- Test permission check. Must be owner to ALTER OPERATOR.
--
CREATE USER regtest_alter_user;
SET SESSION AUTHORIZATION regtest_alter_user_user;
ALTER OPERATOR === (boolean, boolean) SET (RESTRICT = NONE);
RESET SESSION AUTHORIZATION;
-- Clean up
DROP USER regression_alter_user;
DROP OPERATOR === (boolean, boolean);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment