diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/operatorcmds.c | 301 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 15 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 13 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 34 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 9 |
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; |