aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/commands/operatorcmds.c301
-rw-r--r--src/backend/nodes/copyfuncs.c15
-rw-r--r--src/backend/nodes/equalfuncs.c13
-rw-r--r--src/backend/parser/gram.y34
-rw-r--r--src/backend/tcop/utility.c9
5 files changed, 310 insertions, 62 deletions
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index b4a1aac3a14..32065185ea4 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -51,6 +51,9 @@
#include "utils/rel.h"
#include "utils/syscache.h"
+static Oid ValidateRestrictionEstimator(List *restrictionName);
+static Oid ValidateJoinEstimator(List *joinName);
+
/*
* DefineOperator
* this function extracts all the information from the
@@ -80,7 +83,7 @@ DefineOperator(List *names, List *parameters)
Oid functionOid; /* functions converted to OID */
Oid restrictionOid;
Oid joinOid;
- Oid typeId[5]; /* only need up to 5 args here */
+ Oid typeId[2]; /* to hold left and right arg */
int nargs;
ListCell *pl;
@@ -140,10 +143,13 @@ DefineOperator(List *names, List *parameters)
else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
canMerge = true;
else
+ {
+ /* WARNING, not ERROR, for historical backwards-compatibility */
ereport(WARNING,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("operator attribute \"%s\" not recognized",
defel->defname)));
+ }
}
/*
@@ -216,69 +222,14 @@ DefineOperator(List *names, List *parameters)
aclcheck_error_type(aclresult, rettype);
/*
- * Look up restriction estimator if specified
+ * Look up restriction and join estimators if specified
*/
if (restrictionName)
- {
- 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),
- errmsg("restriction estimator function %s must return type \"float8\"",
- NameListToString(restrictionName))));
-
- /* Require EXECUTE rights for the estimator */
- aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
- if (aclresult != ACLCHECK_OK)
- aclcheck_error(aclresult, ACL_KIND_PROC,
- NameListToString(restrictionName));
- }
+ restrictionOid = ValidateRestrictionEstimator(restrictionName);
else
restrictionOid = InvalidOid;
-
- /*
- * Look up join estimator if specified
- */
if (joinName)
- {
- 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.
- */
- joinOid = LookupFuncName(joinName, 5, typeId, true);
- if (!OidIsValid(joinOid))
- joinOid = LookupFuncName(joinName, 4, typeId, true);
- /* If not found, reference the 5-argument signature in error msg */
- if (!OidIsValid(joinOid))
- joinOid = LookupFuncName(joinName, 5, typeId, false);
-
- /* estimators must return float8 */
- if (get_func_rettype(joinOid) != FLOAT8OID)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("join estimator function %s must return type \"float8\"",
- NameListToString(joinName))));
-
- /* Require EXECUTE rights for the estimator */
- aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
- if (aclresult != ACLCHECK_OK)
- aclcheck_error(aclresult, ACL_KIND_PROC,
- NameListToString(joinName));
- }
+ joinOid = ValidateJoinEstimator(joinName);
else
joinOid = InvalidOid;
@@ -300,6 +251,87 @@ DefineOperator(List *names, List *parameters)
}
/*
+ * 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[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),
+ errmsg("restriction estimator function %s must return type \"float8\"",
+ NameListToString(restrictionName))));
+
+ /* Require EXECUTE rights for the estimator */
+ aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_PROC,
+ NameListToString(restrictionName));
+
+ return restrictionOid;
+}
+
+/*
+ * 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.
+ */
+static Oid
+ValidateJoinEstimator(List *joinName)
+{
+ Oid typeId[5];
+ Oid joinOid;
+ 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.
+ */
+ joinOid = LookupFuncName(joinName, 5, typeId, true);
+ if (!OidIsValid(joinOid))
+ joinOid = LookupFuncName(joinName, 4, typeId, true);
+ /* If not found, reference the 5-argument signature in error msg */
+ if (!OidIsValid(joinOid))
+ joinOid = LookupFuncName(joinName, 5, typeId, false);
+
+ /* estimators must return float8 */
+ if (get_func_rettype(joinOid) != FLOAT8OID)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("join estimator function %s must return type \"float8\"",
+ NameListToString(joinName))));
+
+ /* Require EXECUTE rights for the estimator */
+ aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_PROC,
+ NameListToString(joinName));
+
+ return joinOid;
+}
+
+/*
* Guts of operator deletion.
*/
void
@@ -320,3 +352,154 @@ RemoveOperatorById(Oid operOid)
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;
+}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 4c363d3d39a..6a08c2db211 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3212,6 +3212,18 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from)
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 *
_copyRuleStmt(const RuleStmt *from)
{
@@ -4615,6 +4627,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 f19251e7c41..faf5eedab4e 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1339,6 +1339,16 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
}
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
_equalRuleStmt(const RuleStmt *a, const RuleStmt *b)
{
COMPARE_NODE_FIELD(relation);
@@ -2980,6 +2990,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 e0ff6f16a21..2b02a2e5233 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
@@ -359,7 +359,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
any_operator expr_list attrs
target_list opt_target_list insert_column_list set_target_list
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
opt_select_limit opclass_item_list opclass_drop_list
opclass_purpose opt_opfamily transaction_mode_list_or_empty
@@ -432,7 +432,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <node> TableElement TypedTableElement ConstraintElem TableFuncElement
%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
a_expr b_expr c_expr AexprConst indirection_el
columnref in_expr having_clause func_table array_expr
@@ -769,6 +769,7 @@ stmt :
| AlterGroupStmt
| AlterObjectSchemaStmt
| AlterOwnerStmt
+ | AlterOperatorStmt
| AlterPolicyStmt
| AlterSeqStmt
| AlterSystemStmt
@@ -8198,6 +8199,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
*
*****************************************************************************/
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 0dabcc130e0..e81bbc6c9d1 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:
@@ -1481,6 +1482,10 @@ ProcessUtilitySlow(Node *parsetree,
address = ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
break;
+ case T_AlterOperatorStmt:
+ address = AlterOperator((AlterOperatorStmt *) parsetree);
+ break;
+
case T_CommentStmt:
address = CommentObject((CommentStmt *) parsetree);
break;
@@ -2494,6 +2499,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;