1 /*-------------------------------------------------------------------------
5 * Routines for operator manipulation commands
7 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
15 * The "DefineFoo" routines take the parse tree and pick out the
16 * appropriate arguments/flags, passing the results to the
17 * corresponding "FooDefine" routines (in src/catalog) that do
18 * the actual catalog-munging. These routines also verify permission
19 * of the user to execute the command.
22 * These things must be defined and committed in the following order:
24 * input/output, recv/send procedures
30 * Most of the parse-tree manipulation routines are defined in
33 *-------------------------------------------------------------------------
37 #include "access/heapam.h"
38 #include "catalog/dependency.h"
39 #include "catalog/indexing.h"
40 #include "catalog/namespace.h"
41 #include "catalog/pg_operator.h"
42 #include "catalog/pg_type.h"
43 #include "commands/defrem.h"
44 #include "miscadmin.h"
45 #include "parser/parse_func.h"
46 #include "parser/parse_oper.h"
47 #include "parser/parse_type.h"
48 #include "utils/acl.h"
49 #include "utils/lsyscache.h"
50 #include "utils/rel.h"
51 #include "utils/syscache.h"
54 static void AlterOperatorOwner_internal(Relation rel
, Oid operOid
, Oid newOwnerId
);
58 * this function extracts all the information from the
59 * parameter list generated by the parser and then has
60 * OperatorCreate() do all the actual work.
62 * 'parameters' is a list of DefElem
65 DefineOperator(List
*names
, List
*parameters
)
70 bool canMerge
= false; /* operator merges */
71 bool canHash
= false; /* operator hashes */
72 List
*functionName
= NIL
; /* function for operator */
73 TypeName
*typeName1
= NULL
; /* first type name */
74 TypeName
*typeName2
= NULL
; /* second type name */
75 Oid typeId1
= InvalidOid
; /* types converted to OID */
76 Oid typeId2
= InvalidOid
;
77 List
*commutatorName
= NIL
; /* optional commutator operator name */
78 List
*negatorName
= NIL
; /* optional negator operator name */
79 List
*restrictionName
= NIL
; /* optional restrict. sel. procedure */
80 List
*joinName
= NIL
; /* optional join sel. procedure */
81 Oid functionOid
; /* functions converted to OID */
84 Oid typeId
[5]; /* only need up to 5 args here */
88 /* Convert list of names to a name and namespace */
89 oprNamespace
= QualifiedNameGetCreationNamespace(names
, &oprName
);
91 /* Check we have creation rights in target namespace */
92 aclresult
= pg_namespace_aclcheck(oprNamespace
, GetUserId(), ACL_CREATE
);
93 if (aclresult
!= ACLCHECK_OK
)
94 aclcheck_error(aclresult
, ACL_KIND_NAMESPACE
,
95 get_namespace_name(oprNamespace
));
98 * loop over the definition list and extract the information we need.
100 foreach(pl
, parameters
)
102 DefElem
*defel
= (DefElem
*) lfirst(pl
);
104 if (pg_strcasecmp(defel
->defname
, "leftarg") == 0)
106 typeName1
= defGetTypeName(defel
);
107 if (typeName1
->setof
)
109 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION
),
110 errmsg("SETOF type not allowed for operator argument")));
112 else if (pg_strcasecmp(defel
->defname
, "rightarg") == 0)
114 typeName2
= defGetTypeName(defel
);
115 if (typeName2
->setof
)
117 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION
),
118 errmsg("SETOF type not allowed for operator argument")));
120 else if (pg_strcasecmp(defel
->defname
, "procedure") == 0)
121 functionName
= defGetQualifiedName(defel
);
122 else if (pg_strcasecmp(defel
->defname
, "commutator") == 0)
123 commutatorName
= defGetQualifiedName(defel
);
124 else if (pg_strcasecmp(defel
->defname
, "negator") == 0)
125 negatorName
= defGetQualifiedName(defel
);
126 else if (pg_strcasecmp(defel
->defname
, "restrict") == 0)
127 restrictionName
= defGetQualifiedName(defel
);
128 else if (pg_strcasecmp(defel
->defname
, "join") == 0)
129 joinName
= defGetQualifiedName(defel
);
130 else if (pg_strcasecmp(defel
->defname
, "hashes") == 0)
131 canHash
= defGetBoolean(defel
);
132 else if (pg_strcasecmp(defel
->defname
, "merges") == 0)
133 canMerge
= defGetBoolean(defel
);
134 /* These obsolete options are taken as meaning canMerge */
135 else if (pg_strcasecmp(defel
->defname
, "sort1") == 0)
137 else if (pg_strcasecmp(defel
->defname
, "sort2") == 0)
139 else if (pg_strcasecmp(defel
->defname
, "ltcmp") == 0)
141 else if (pg_strcasecmp(defel
->defname
, "gtcmp") == 0)
145 (errcode(ERRCODE_SYNTAX_ERROR
),
146 errmsg("operator attribute \"%s\" not recognized",
151 * make sure we have our required definitions
153 if (functionName
== NIL
)
155 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION
),
156 errmsg("operator procedure must be specified")));
158 /* Transform type names to type OIDs */
160 typeId1
= typenameTypeId(NULL
, typeName1
, NULL
);
162 typeId2
= typenameTypeId(NULL
, typeName2
, NULL
);
164 if (!OidIsValid(typeId1
) && !OidIsValid(typeId2
))
166 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION
),
167 errmsg("at least one of leftarg or rightarg must be specified")));
170 * Look up the operator's underlying function.
172 if (!OidIsValid(typeId1
))
177 else if (!OidIsValid(typeId2
))
188 functionOid
= LookupFuncName(functionName
, nargs
, typeId
, false);
191 * We require EXECUTE rights for the function. This isn't strictly
192 * necessary, since EXECUTE will be checked at any attempted use of the
193 * operator, but it seems like a good idea anyway.
195 aclresult
= pg_proc_aclcheck(functionOid
, GetUserId(), ACL_EXECUTE
);
196 if (aclresult
!= ACLCHECK_OK
)
197 aclcheck_error(aclresult
, ACL_KIND_PROC
,
198 NameListToString(functionName
));
201 * Look up restriction estimator if specified
205 typeId
[0] = INTERNALOID
; /* PlannerInfo */
206 typeId
[1] = OIDOID
; /* operator OID */
207 typeId
[2] = INTERNALOID
; /* args list */
208 typeId
[3] = INT4OID
; /* varRelid */
210 restrictionOid
= LookupFuncName(restrictionName
, 4, typeId
, false);
212 /* estimators must return float8 */
213 if (get_func_rettype(restrictionOid
) != FLOAT8OID
)
215 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
216 errmsg("restriction estimator function %s must return type \"float8\"",
217 NameListToString(restrictionName
))));
219 /* Require EXECUTE rights for the estimator */
220 aclresult
= pg_proc_aclcheck(restrictionOid
, GetUserId(), ACL_EXECUTE
);
221 if (aclresult
!= ACLCHECK_OK
)
222 aclcheck_error(aclresult
, ACL_KIND_PROC
,
223 NameListToString(restrictionName
));
226 restrictionOid
= InvalidOid
;
229 * Look up join estimator if specified
233 typeId
[0] = INTERNALOID
; /* PlannerInfo */
234 typeId
[1] = OIDOID
; /* operator OID */
235 typeId
[2] = INTERNALOID
; /* args list */
236 typeId
[3] = INT2OID
; /* jointype */
237 typeId
[4] = INTERNALOID
; /* SpecialJoinInfo */
240 * As of Postgres 8.4, the preferred signature for join estimators has
241 * 5 arguments, but we still allow the old 4-argument form. Try the
242 * preferred form first.
244 joinOid
= LookupFuncName(joinName
, 5, typeId
, true);
245 if (!OidIsValid(joinOid
))
246 joinOid
= LookupFuncName(joinName
, 4, typeId
, true);
247 /* If not found, reference the 5-argument signature in error msg */
248 if (!OidIsValid(joinOid
))
249 joinOid
= LookupFuncName(joinName
, 5, typeId
, false);
251 /* estimators must return float8 */
252 if (get_func_rettype(joinOid
) != FLOAT8OID
)
254 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
255 errmsg("join estimator function %s must return type \"float8\"",
256 NameListToString(joinName
))));
258 /* Require EXECUTE rights for the estimator */
259 aclresult
= pg_proc_aclcheck(joinOid
, GetUserId(), ACL_EXECUTE
);
260 if (aclresult
!= ACLCHECK_OK
)
261 aclcheck_error(aclresult
, ACL_KIND_PROC
,
262 NameListToString(joinName
));
265 joinOid
= InvalidOid
;
268 * now have OperatorCreate do all the work..
270 OperatorCreate(oprName
, /* operator name */
271 oprNamespace
, /* namespace */
272 typeId1
, /* left type id */
273 typeId2
, /* right type id */
274 functionOid
, /* function for operator */
275 commutatorName
, /* optional commutator operator name */
276 negatorName
, /* optional negator operator name */
277 restrictionOid
, /* optional restrict. sel. procedure */
278 joinOid
, /* optional join sel. procedure name */
279 canMerge
, /* operator merges */
280 canHash
); /* operator hashes */
286 * Deletes an operator.
289 RemoveOperator(RemoveFuncStmt
*stmt
)
291 List
*operatorName
= stmt
->name
;
292 TypeName
*typeName1
= (TypeName
*) linitial(stmt
->args
);
293 TypeName
*typeName2
= (TypeName
*) lsecond(stmt
->args
);
296 ObjectAddress object
;
298 Assert(list_length(stmt
->args
) == 2);
299 operOid
= LookupOperNameTypeNames(NULL
, operatorName
,
300 typeName1
, typeName2
,
301 stmt
->missing_ok
, -1);
303 if (stmt
->missing_ok
&& !OidIsValid(operOid
))
306 (errmsg("operator %s does not exist, skipping",
307 NameListToString(operatorName
))));
311 tup
= SearchSysCache(OPEROID
,
312 ObjectIdGetDatum(operOid
),
314 if (!HeapTupleIsValid(tup
)) /* should not happen */
315 elog(ERROR
, "cache lookup failed for operator %u", operOid
);
317 /* Permission check: must own operator or its namespace */
318 if (!pg_oper_ownercheck(operOid
, GetUserId()) &&
319 !pg_namespace_ownercheck(((Form_pg_operator
) GETSTRUCT(tup
))->oprnamespace
,
321 aclcheck_error(ACLCHECK_NOT_OWNER
, ACL_KIND_OPER
,
322 NameListToString(operatorName
));
324 ReleaseSysCache(tup
);
329 object
.classId
= OperatorRelationId
;
330 object
.objectId
= operOid
;
331 object
.objectSubId
= 0;
333 performDeletion(&object
, stmt
->behavior
);
337 * Guts of operator deletion.
340 RemoveOperatorById(Oid operOid
)
345 relation
= heap_open(OperatorRelationId
, RowExclusiveLock
);
347 tup
= SearchSysCache(OPEROID
,
348 ObjectIdGetDatum(operOid
),
350 if (!HeapTupleIsValid(tup
)) /* should not happen */
351 elog(ERROR
, "cache lookup failed for operator %u", operOid
);
353 simple_heap_delete(relation
, &tup
->t_self
);
355 ReleaseSysCache(tup
);
357 heap_close(relation
, RowExclusiveLock
);
361 AlterOperatorOwner_oid(Oid operOid
, Oid newOwnerId
)
365 rel
= heap_open(OperatorRelationId
, RowExclusiveLock
);
367 AlterOperatorOwner_internal(rel
, operOid
, newOwnerId
);
369 heap_close(rel
, NoLock
);
373 * change operator owner
376 AlterOperatorOwner(List
*name
, TypeName
*typeName1
, TypeName
*typeName2
,
382 rel
= heap_open(OperatorRelationId
, RowExclusiveLock
);
384 operOid
= LookupOperNameTypeNames(NULL
, name
,
385 typeName1
, typeName2
,
388 AlterOperatorOwner_internal(rel
, operOid
, newOwnerId
);
390 heap_close(rel
, NoLock
);
394 AlterOperatorOwner_internal(Relation rel
, Oid operOid
, Oid newOwnerId
)
398 Form_pg_operator oprForm
;
400 Assert(RelationGetRelid(rel
) == OperatorRelationId
);
402 tup
= SearchSysCacheCopy(OPEROID
,
403 ObjectIdGetDatum(operOid
),
405 if (!HeapTupleIsValid(tup
)) /* should not happen */
406 elog(ERROR
, "cache lookup failed for operator %u", operOid
);
408 oprForm
= (Form_pg_operator
) GETSTRUCT(tup
);
411 * If the new owner is the same as the existing owner, consider the
412 * command to have succeeded. This is for dump restoration purposes.
414 if (oprForm
->oprowner
!= newOwnerId
)
416 /* Superusers can always do it */
419 /* Otherwise, must be owner of the existing object */
420 if (!pg_oper_ownercheck(operOid
, GetUserId()))
421 aclcheck_error(ACLCHECK_NOT_OWNER
, ACL_KIND_OPER
,
422 NameStr(oprForm
->oprname
));
424 /* Must be able to become new owner */
425 check_is_member_of_role(GetUserId(), newOwnerId
);
427 /* New owner must have CREATE privilege on namespace */
428 aclresult
= pg_namespace_aclcheck(oprForm
->oprnamespace
,
431 if (aclresult
!= ACLCHECK_OK
)
432 aclcheck_error(aclresult
, ACL_KIND_NAMESPACE
,
433 get_namespace_name(oprForm
->oprnamespace
));
437 * Modify the owner --- okay to scribble on tup because it's a copy
439 oprForm
->oprowner
= newOwnerId
;
441 simple_heap_update(rel
, &tup
->t_self
, tup
);
443 CatalogUpdateIndexes(rel
, tup
);
445 /* Update owner dependency reference */
446 changeDependencyOnOwner(OperatorRelationId
, operOid
, newOwnerId
);