Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * operatorcmds.c
4 : *
5 : * Routines for operator manipulation commands
6 : *
7 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
8 : * Portions Copyright (c) 1994, Regents of the University of California
9 : *
10 : *
11 : * IDENTIFICATION
12 : * src/backend/commands/operatorcmds.c
13 : *
14 : * DESCRIPTION
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.
20 : *
21 : * NOTES
22 : * These things must be defined and committed in the following order:
23 : * "create function":
24 : * input/output, recv/send functions
25 : * "create type":
26 : * type
27 : * "create operator":
28 : * operators
29 : *
30 : *-------------------------------------------------------------------------
31 : */
32 : #include "postgres.h"
33 :
34 : #include "access/htup_details.h"
35 : #include "access/table.h"
36 : #include "catalog/dependency.h"
37 : #include "catalog/indexing.h"
38 : #include "catalog/objectaccess.h"
39 : #include "catalog/pg_namespace.h"
40 : #include "catalog/pg_operator.h"
41 : #include "catalog/pg_proc.h"
42 : #include "catalog/pg_type.h"
43 : #include "commands/alter.h"
44 : #include "commands/defrem.h"
45 : #include "miscadmin.h"
46 : #include "parser/parse_func.h"
47 : #include "parser/parse_oper.h"
48 : #include "parser/parse_type.h"
49 : #include "utils/acl.h"
50 : #include "utils/builtins.h"
51 : #include "utils/lsyscache.h"
52 : #include "utils/rel.h"
53 : #include "utils/syscache.h"
54 :
55 : static Oid ValidateRestrictionEstimator(List *restrictionName);
56 : static Oid ValidateJoinEstimator(List *joinName);
57 :
58 : /*
59 : * DefineOperator
60 : * this function extracts all the information from the
61 : * parameter list generated by the parser and then has
62 : * OperatorCreate() do all the actual work.
63 : *
64 : * 'parameters' is a list of DefElem
65 : */
66 : ObjectAddress
7664 tgl 67 GIC 742 : DefineOperator(List *names, List *parameters)
68 : {
7664 tgl 69 ECB : char *oprName;
70 : Oid oprNamespace;
71 : AclResult aclresult;
2118 tgl 72 GIC 742 : bool canMerge = false; /* operator merges */
5624 bruce 73 742 : bool canHash = false; /* operator hashes */
2118 tgl 74 CBC 742 : List *functionName = NIL; /* function for operator */
75 742 : TypeName *typeName1 = NULL; /* first type name */
76 742 : TypeName *typeName2 = NULL; /* second type name */
7664 77 742 : Oid typeId1 = InvalidOid; /* types converted to OID */
78 742 : Oid typeId2 = InvalidOid;
4128 peter_e 79 ECB : Oid rettype;
6385 bruce 80 CBC 742 : List *commutatorName = NIL; /* optional commutator operator name */
2118 tgl 81 GIC 742 : List *negatorName = NIL; /* optional negator operator name */
1698 peter_e 82 CBC 742 : List *restrictionName = NIL; /* optional restrict. sel. function */
83 742 : List *joinName = NIL; /* optional join sel. function */
5349 tgl 84 ECB : Oid functionOid; /* functions converted to OID */
85 : Oid restrictionOid;
86 : Oid joinOid;
87 : Oid typeId[2]; /* to hold left and right arg */
88 : int nargs;
89 : ListCell *pl;
90 :
91 : /* Convert list of names to a name and namespace */
7664 tgl 92 GIC 742 : oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
93 :
7652 tgl 94 ECB : /* Check we have creation rights in target namespace */
147 peter 95 GNC 742 : aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE);
7652 tgl 96 GIC 742 : if (aclresult != ACLCHECK_OK)
1954 peter_e 97 CBC 3 : aclcheck_error(aclresult, OBJECT_SCHEMA,
7191 tgl 98 3 : get_namespace_name(oprNamespace));
7652 tgl 99 ECB :
7664 100 : /*
101 : * loop over the definition list and extract the information we need.
102 : */
7664 tgl 103 GIC 4816 : foreach(pl, parameters)
104 : {
7664 tgl 105 CBC 4083 : DefElem *defel = (DefElem *) lfirst(pl);
106 :
1899 107 4083 : if (strcmp(defel->defname, "leftarg") == 0)
108 : {
7664 109 693 : typeName1 = defGetTypeName(defel);
7664 tgl 110 GIC 693 : if (typeName1->setof)
7203 tgl 111 CBC 3 : ereport(ERROR,
7203 tgl 112 ECB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2118 113 : errmsg("SETOF type not allowed for operator argument")));
114 : }
1899 tgl 115 GIC 3390 : else if (strcmp(defel->defname, "rightarg") == 0)
116 : {
7664 tgl 117 CBC 727 : typeName2 = defGetTypeName(defel);
7664 tgl 118 GIC 727 : if (typeName2->setof)
7203 tgl 119 CBC 3 : ereport(ERROR,
7203 tgl 120 ECB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2118 121 : errmsg("SETOF type not allowed for operator argument")));
122 : }
123 : /* "function" and "procedure" are equivalent here */
1698 peter_e 124 GIC 2663 : else if (strcmp(defel->defname, "function") == 0)
125 14 : functionName = defGetQualifiedName(defel);
1899 tgl 126 CBC 2649 : else if (strcmp(defel->defname, "procedure") == 0)
7663 127 713 : functionName = defGetQualifiedName(defel);
1899 128 1936 : else if (strcmp(defel->defname, "commutator") == 0)
7663 129 474 : commutatorName = defGetQualifiedName(defel);
1899 130 1462 : else if (strcmp(defel->defname, "negator") == 0)
7663 131 320 : negatorName = defGetQualifiedName(defel);
1899 132 1142 : else if (strcmp(defel->defname, "restrict") == 0)
7663 133 496 : restrictionName = defGetQualifiedName(defel);
1899 134 646 : else if (strcmp(defel->defname, "join") == 0)
7663 135 484 : joinName = defGetQualifiedName(defel);
1899 136 162 : else if (strcmp(defel->defname, "hashes") == 0)
6904 137 46 : canHash = defGetBoolean(defel);
1899 138 116 : else if (strcmp(defel->defname, "merges") == 0)
6904 139 70 : canMerge = defGetBoolean(defel);
5951 tgl 140 ECB : /* These obsolete options are taken as meaning canMerge */
1899 tgl 141 CBC 46 : else if (strcmp(defel->defname, "sort1") == 0)
5951 tgl 142 GIC 5 : canMerge = true;
1899 tgl 143 CBC 41 : else if (strcmp(defel->defname, "sort2") == 0)
5951 144 5 : canMerge = true;
1899 145 36 : else if (strcmp(defel->defname, "ltcmp") == 0)
5951 146 3 : canMerge = true;
1899 147 33 : else if (strcmp(defel->defname, "gtcmp") == 0)
5951 148 3 : canMerge = true;
7664 tgl 149 ECB : else
2826 heikki.linnakangas 150 : {
151 : /* WARNING, not ERROR, for historical backwards-compatibility */
7203 tgl 152 GIC 30 : ereport(WARNING,
153 : (errcode(ERRCODE_SYNTAX_ERROR),
7203 tgl 154 ECB : errmsg("operator attribute \"%s\" not recognized",
155 : defel->defname)));
156 : }
157 : }
158 :
159 : /*
160 : * make sure we have our required definitions
161 : */
7663 tgl 162 GIC 733 : if (functionName == NIL)
7203 163 6 : ereport(ERROR,
7203 tgl 164 ECB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1698 peter_e 165 : errmsg("operator function must be specified")));
166 :
167 : /* Transform type names to type OIDs */
7664 tgl 168 GIC 727 : if (typeName1)
4549 peter_e 169 690 : typeId1 = typenameTypeId(NULL, typeName1);
7664 tgl 170 CBC 727 : if (typeName2)
4549 peter_e 171 721 : typeId2 = typenameTypeId(NULL, typeName2);
7664 tgl 172 ECB :
934 173 : /*
174 : * If only the right argument is missing, the user is likely trying to
175 : * create a postfix operator, so give them a hint about why that does not
176 : * work. But if both arguments are missing, do not mention postfix
177 : * operators, as the user most likely simply neglected to mention the
178 : * arguments.
179 : */
5349 tgl 180 GIC 727 : if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
181 3 : ereport(ERROR,
5349 tgl 182 ECB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
934 183 : errmsg("operator argument types must be specified")));
934 tgl 184 GIC 724 : if (!OidIsValid(typeId2))
185 3 : ereport(ERROR,
934 tgl 186 ECB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
187 : errmsg("operator right argument type must be specified"),
188 : errdetail("Postfix operators are not supported.")));
189 :
4128 peter_e 190 GIC 721 : if (typeName1)
191 : {
147 peter 192 GNC 687 : aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE);
4128 peter_e 193 GIC 687 : if (aclresult != ACLCHECK_OK)
3950 peter_e 194 CBC 6 : aclcheck_error_type(aclresult, typeId1);
4128 peter_e 195 ECB : }
196 :
4128 peter_e 197 GIC 715 : if (typeName2)
198 : {
147 peter 199 GNC 715 : aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE);
4128 peter_e 200 GIC 715 : if (aclresult != ACLCHECK_OK)
3950 peter_e 201 CBC 3 : aclcheck_error_type(aclresult, typeId2);
4128 peter_e 202 ECB : }
203 :
204 : /*
205 : * Look up the operator's underlying function.
206 : */
5349 tgl 207 GIC 712 : if (!OidIsValid(typeId1))
208 : {
5349 tgl 209 CBC 34 : typeId[0] = typeId2;
5349 tgl 210 GIC 34 : nargs = 1;
5349 tgl 211 ECB : }
5349 tgl 212 CBC 678 : else if (!OidIsValid(typeId2))
213 : {
5349 tgl 214 LBC 0 : typeId[0] = typeId1;
5349 tgl 215 UIC 0 : nargs = 1;
5349 tgl 216 EUB : }
217 : else
218 : {
5349 tgl 219 GIC 678 : typeId[0] = typeId1;
220 678 : typeId[1] = typeId2;
5349 tgl 221 CBC 678 : nargs = 2;
5349 tgl 222 ECB : }
5349 tgl 223 CBC 712 : functionOid = LookupFuncName(functionName, nargs, typeId, false);
224 :
5349 tgl 225 ECB : /*
226 : * We require EXECUTE rights for the function. This isn't strictly
227 : * necessary, since EXECUTE will be checked at any attempted use of the
228 : * operator, but it seems like a good idea anyway.
229 : */
147 peter 230 GNC 712 : aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
5349 tgl 231 GIC 712 : if (aclresult != ACLCHECK_OK)
1954 peter_e 232 CBC 3 : aclcheck_error(aclresult, OBJECT_FUNCTION,
5349 tgl 233 3 : NameListToString(functionName));
5349 tgl 234 ECB :
4128 peter_e 235 CBC 709 : rettype = get_func_rettype(functionOid);
147 peter 236 GNC 709 : aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
4128 peter_e 237 CBC 709 : if (aclresult != ACLCHECK_OK)
3950 238 3 : aclcheck_error_type(aclresult, rettype);
4128 peter_e 239 ECB :
5349 tgl 240 : /*
241 : * Look up restriction and join estimators if specified
242 : */
5349 tgl 243 GIC 706 : if (restrictionName)
2826 heikki.linnakangas 244 496 : restrictionOid = ValidateRestrictionEstimator(restrictionName);
5349 tgl 245 ECB : else
5349 tgl 246 CBC 210 : restrictionOid = InvalidOid;
5349 tgl 247 GIC 706 : if (joinName)
2826 heikki.linnakangas 248 CBC 484 : joinOid = ValidateJoinEstimator(joinName);
5349 tgl 249 ECB : else
5349 tgl 250 CBC 222 : joinOid = InvalidOid;
251 :
7664 tgl 252 ECB : /*
253 : * now have OperatorCreate do all the work..
254 : */
255 : return
3602 bruce 256 GIC 706 : OperatorCreate(oprName, /* operator name */
257 : oprNamespace, /* namespace */
3602 bruce 258 ECB : typeId1, /* left type id */
259 : typeId2, /* right type id */
260 : functionOid, /* function for operator */
261 : commutatorName, /* optional commutator operator name */
262 : negatorName, /* optional negator operator name */
263 : restrictionOid, /* optional restrict. sel. function */
264 : joinOid, /* optional join sel. function name */
265 : canMerge, /* operator merges */
266 : canHash); /* operator hashes */
267 : }
268 :
269 : /*
270 : * Look up a restriction estimator function by name, and verify that it has
271 : * the correct signature and we have the permissions to attach it to an
272 : * operator.
273 : */
274 : static Oid
2826 heikki.linnakangas 275 GIC 721 : ValidateRestrictionEstimator(List *restrictionName)
276 : {
2826 heikki.linnakangas 277 ECB : Oid typeId[4];
278 : Oid restrictionOid;
279 : AclResult aclresult;
280 :
2826 heikki.linnakangas 281 GIC 721 : typeId[0] = INTERNALOID; /* PlannerInfo */
282 721 : typeId[1] = OIDOID; /* operator OID */
2826 heikki.linnakangas 283 CBC 721 : typeId[2] = INTERNALOID; /* args list */
284 721 : typeId[3] = INT4OID; /* varRelid */
2826 heikki.linnakangas 285 ECB :
2826 heikki.linnakangas 286 CBC 721 : restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
287 :
2826 heikki.linnakangas 288 ECB : /* estimators must return float8 */
2826 heikki.linnakangas 289 GIC 718 : if (get_func_rettype(restrictionOid) != FLOAT8OID)
2826 heikki.linnakangas 290 UIC 0 : ereport(ERROR,
2826 heikki.linnakangas 291 ECB : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2118 tgl 292 EUB : errmsg("restriction estimator function %s must return type %s",
293 : NameListToString(restrictionName), "float8")));
294 :
295 : /* Require EXECUTE rights for the estimator */
147 peter 296 GNC 718 : aclresult = object_aclcheck(ProcedureRelationId, restrictionOid, GetUserId(), ACL_EXECUTE);
2826 heikki.linnakangas 297 GIC 718 : if (aclresult != ACLCHECK_OK)
1954 peter_e 298 LBC 0 : aclcheck_error(aclresult, OBJECT_FUNCTION,
2826 heikki.linnakangas 299 0 : NameListToString(restrictionName));
2826 heikki.linnakangas 300 EUB :
2826 heikki.linnakangas 301 GBC 718 : return restrictionOid;
302 : }
2826 heikki.linnakangas 303 ECB :
304 : /*
305 : * Look up a join estimator function by name, and verify that it has the
306 : * correct signature and we have the permissions to attach it to an
307 : * operator.
308 : */
309 : static Oid
2826 heikki.linnakangas 310 GIC 709 : ValidateJoinEstimator(List *joinName)
311 : {
2826 heikki.linnakangas 312 ECB : Oid typeId[5];
313 : Oid joinOid;
314 : Oid joinOid2;
315 : AclResult aclresult;
316 :
2826 heikki.linnakangas 317 GIC 709 : typeId[0] = INTERNALOID; /* PlannerInfo */
318 709 : typeId[1] = OIDOID; /* operator OID */
2826 heikki.linnakangas 319 CBC 709 : typeId[2] = INTERNALOID; /* args list */
320 709 : typeId[3] = INT2OID; /* jointype */
321 709 : typeId[4] = INTERNALOID; /* SpecialJoinInfo */
2826 heikki.linnakangas 322 ECB :
323 : /*
324 : * As of Postgres 8.4, the preferred signature for join estimators has 5
325 : * arguments, but we still allow the old 4-argument form. Whine about
326 : * ambiguity if both forms exist.
327 : */
2826 heikki.linnakangas 328 GIC 709 : joinOid = LookupFuncName(joinName, 5, typeId, true);
972 tgl 329 709 : joinOid2 = LookupFuncName(joinName, 4, typeId, true);
972 tgl 330 CBC 709 : if (OidIsValid(joinOid))
972 tgl 331 ECB : {
972 tgl 332 CBC 706 : if (OidIsValid(joinOid2))
972 tgl 333 UIC 0 : ereport(ERROR,
972 tgl 334 ECB : (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
972 tgl 335 EUB : errmsg("join estimator function %s has multiple matches",
336 : NameListToString(joinName))));
337 : }
338 : else
339 : {
972 tgl 340 GIC 3 : joinOid = joinOid2;
341 : /* If not found, reference the 5-argument signature in error msg */
972 tgl 342 CBC 3 : if (!OidIsValid(joinOid))
972 tgl 343 GIC 3 : joinOid = LookupFuncName(joinName, 5, typeId, false);
972 tgl 344 ECB : }
2826 heikki.linnakangas 345 :
346 : /* estimators must return float8 */
2826 heikki.linnakangas 347 GIC 706 : if (get_func_rettype(joinOid) != FLOAT8OID)
2826 heikki.linnakangas 348 UIC 0 : ereport(ERROR,
2826 heikki.linnakangas 349 ECB : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2495 rhaas 350 EUB : errmsg("join estimator function %s must return type %s",
351 : NameListToString(joinName), "float8")));
352 :
353 : /* Require EXECUTE rights for the estimator */
147 peter 354 GNC 706 : aclresult = object_aclcheck(ProcedureRelationId, joinOid, GetUserId(), ACL_EXECUTE);
2826 heikki.linnakangas 355 GIC 706 : if (aclresult != ACLCHECK_OK)
1954 peter_e 356 LBC 0 : aclcheck_error(aclresult, OBJECT_FUNCTION,
2826 heikki.linnakangas 357 0 : NameListToString(joinName));
2826 heikki.linnakangas 358 EUB :
2826 heikki.linnakangas 359 GBC 706 : return joinOid;
360 : }
2826 heikki.linnakangas 361 ECB :
362 : /*
363 : * Guts of operator deletion.
364 : */
365 : void
7576 tgl 366 GIC 336 : RemoveOperatorById(Oid operOid)
367 : {
7576 tgl 368 ECB : Relation relation;
369 : HeapTuple tup;
370 : Form_pg_operator op;
371 :
1539 andres 372 GIC 336 : relation = table_open(OperatorRelationId, RowExclusiveLock);
373 :
4802 rhaas 374 CBC 336 : tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
7522 bruce 375 GIC 336 : if (!HeapTupleIsValid(tup)) /* should not happen */
7203 tgl 376 LBC 0 : elog(ERROR, "cache lookup failed for operator %u", operOid);
2571 tgl 377 CBC 336 : op = (Form_pg_operator) GETSTRUCT(tup);
2571 tgl 378 EUB :
2571 tgl 379 ECB : /*
380 : * Reset links from commutator and negator, if any. In case of a
381 : * self-commutator or self-negator, this means we have to re-fetch the
382 : * updated tuple. (We could optimize away updates on the tuple we're
383 : * about to drop, but it doesn't seem worth convoluting the logic for.)
384 : */
2571 tgl 385 GIC 336 : if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
386 : {
2571 tgl 387 CBC 154 : OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
2571 tgl 388 GIC 154 : if (operOid == op->oprcom || operOid == op->oprnegate)
2571 tgl 389 ECB : {
2571 tgl 390 CBC 47 : ReleaseSysCache(tup);
2571 tgl 391 GIC 47 : tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
2571 tgl 392 CBC 47 : if (!HeapTupleIsValid(tup)) /* should not happen */
2571 tgl 393 LBC 0 : elog(ERROR, "cache lookup failed for operator %u", operOid);
2571 tgl 394 ECB : }
2571 tgl 395 EUB : }
396 :
2258 tgl 397 GIC 336 : CatalogTupleDelete(relation, &tup->t_self);
398 :
7576 tgl 399 CBC 336 : ReleaseSysCache(tup);
400 :
1539 andres 401 336 : table_close(relation, RowExclusiveLock);
7664 tgl 402 GIC 336 : }
2826 heikki.linnakangas 403 ECB :
404 : /*
405 : * AlterOperator
406 : * routine implementing ALTER OPERATOR <operator> SET (option = ...).
407 : *
408 : * Currently, only RESTRICT and JOIN estimator functions can be changed.
409 : */
410 : ObjectAddress
2826 heikki.linnakangas 411 GIC 258 : AlterOperator(AlterOperatorStmt *stmt)
412 : {
2826 heikki.linnakangas 413 ECB : ObjectAddress address;
414 : Oid oprId;
415 : Relation catalog;
416 : HeapTuple tup;
417 : Form_pg_operator oprForm;
418 : int i;
419 : ListCell *pl;
420 : Datum values[Natts_pg_operator];
421 : bool nulls[Natts_pg_operator];
422 : bool replaces[Natts_pg_operator];
1698 peter_e 423 GIC 258 : List *restrictionName = NIL; /* optional restrict. sel. function */
2826 heikki.linnakangas 424 258 : bool updateRestriction = false;
2826 heikki.linnakangas 425 ECB : Oid restrictionOid;
1698 peter_e 426 CBC 258 : List *joinName = NIL; /* optional join sel. function */
2826 heikki.linnakangas 427 GIC 258 : bool updateJoin = false;
2826 heikki.linnakangas 428 ECB : Oid joinOid;
429 :
430 : /* Look up the operator */
2293 peter_e 431 GIC 258 : oprId = LookupOperWithArgs(stmt->opername, false);
1539 andres 432 258 : catalog = table_open(OperatorRelationId, RowExclusiveLock);
2826 heikki.linnakangas 433 CBC 258 : tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
1435 tgl 434 258 : if (!HeapTupleIsValid(tup))
2826 heikki.linnakangas 435 LBC 0 : elog(ERROR, "cache lookup failed for operator %u", oprId);
2826 heikki.linnakangas 436 CBC 258 : oprForm = (Form_pg_operator) GETSTRUCT(tup);
2826 heikki.linnakangas 437 EUB :
2826 heikki.linnakangas 438 ECB : /* Process options */
2826 heikki.linnakangas 439 GIC 723 : foreach(pl, stmt->options)
440 : {
2826 heikki.linnakangas 441 CBC 480 : DefElem *defel = (DefElem *) lfirst(pl);
442 : List *param;
2826 heikki.linnakangas 443 ECB :
2826 heikki.linnakangas 444 GIC 480 : if (defel->arg == NULL)
445 15 : param = NIL; /* NONE, removes the function */
2826 heikki.linnakangas 446 ECB : else
2826 heikki.linnakangas 447 CBC 465 : param = defGetQualifiedName(defel);
448 :
1899 tgl 449 480 : if (strcmp(defel->defname, "restrict") == 0)
450 : {
2826 heikki.linnakangas 451 234 : restrictionName = param;
2826 heikki.linnakangas 452 GIC 234 : updateRestriction = true;
2826 heikki.linnakangas 453 ECB : }
1899 tgl 454 CBC 246 : else if (strcmp(defel->defname, "join") == 0)
455 : {
2826 heikki.linnakangas 456 231 : joinName = param;
2826 heikki.linnakangas 457 GIC 231 : updateJoin = true;
2826 heikki.linnakangas 458 ECB : }
459 :
460 : /*
461 : * The rest of the options that CREATE accepts cannot be changed.
462 : * Check for them so that we can give a meaningful error message.
463 : */
1899 tgl 464 GIC 15 : else if (strcmp(defel->defname, "leftarg") == 0 ||
465 15 : strcmp(defel->defname, "rightarg") == 0 ||
1698 peter_e 466 CBC 15 : strcmp(defel->defname, "function") == 0 ||
1899 tgl 467 15 : strcmp(defel->defname, "procedure") == 0 ||
468 15 : strcmp(defel->defname, "commutator") == 0 ||
469 9 : strcmp(defel->defname, "negator") == 0 ||
470 3 : strcmp(defel->defname, "hashes") == 0 ||
471 3 : strcmp(defel->defname, "merges") == 0)
2826 heikki.linnakangas 472 ECB : {
2826 heikki.linnakangas 473 CBC 12 : ereport(ERROR,
474 : (errcode(ERRCODE_SYNTAX_ERROR),
2497 peter_e 475 ECB : errmsg("operator attribute \"%s\" cannot be changed",
476 : defel->defname)));
477 : }
478 : else
2826 heikki.linnakangas 479 GIC 3 : ereport(ERROR,
480 : (errcode(ERRCODE_SYNTAX_ERROR),
2826 heikki.linnakangas 481 ECB : errmsg("operator attribute \"%s\" not recognized",
482 : defel->defname)));
483 : }
484 :
485 : /* Check permissions. Must be owner. */
147 peter 486 GNC 243 : if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
1954 peter_e 487 GIC 3 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
2826 heikki.linnakangas 488 CBC 3 : NameStr(oprForm->oprname));
2826 heikki.linnakangas 489 ECB :
490 : /*
491 : * Look up restriction and join estimators if specified
492 : */
2826 heikki.linnakangas 493 GIC 240 : if (restrictionName)
494 225 : restrictionOid = ValidateRestrictionEstimator(restrictionName);
2826 heikki.linnakangas 495 ECB : else
2826 heikki.linnakangas 496 CBC 15 : restrictionOid = InvalidOid;
2826 heikki.linnakangas 497 GIC 237 : if (joinName)
2826 heikki.linnakangas 498 CBC 225 : joinOid = ValidateJoinEstimator(joinName);
2826 heikki.linnakangas 499 ECB : else
2826 heikki.linnakangas 500 CBC 12 : joinOid = InvalidOid;
501 :
2826 heikki.linnakangas 502 ECB : /* Perform additional checks, like OperatorCreate does */
2826 heikki.linnakangas 503 GIC 234 : if (!(OidIsValid(oprForm->oprleft) && OidIsValid(oprForm->oprright)))
504 : {
2826 heikki.linnakangas 505 ECB : /* If it's not a binary op, these things mustn't be set: */
2826 heikki.linnakangas 506 UIC 0 : if (OidIsValid(joinOid))
507 0 : ereport(ERROR,
2826 heikki.linnakangas 508 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2118 tgl 509 : errmsg("only binary operators can have join selectivity")));
510 : }
511 :
2826 heikki.linnakangas 512 GIC 234 : if (oprForm->oprresult != BOOLOID)
513 : {
2826 heikki.linnakangas 514 LBC 0 : if (OidIsValid(restrictionOid))
2826 heikki.linnakangas 515 UIC 0 : ereport(ERROR,
2826 heikki.linnakangas 516 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
517 : errmsg("only boolean operators can have restriction selectivity")));
2826 heikki.linnakangas 518 UIC 0 : if (OidIsValid(joinOid))
519 0 : ereport(ERROR,
2826 heikki.linnakangas 520 EUB : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2118 tgl 521 : errmsg("only boolean operators can have join selectivity")));
522 : }
523 :
524 : /* Update the tuple */
2826 heikki.linnakangas 525 GIC 3744 : for (i = 0; i < Natts_pg_operator; ++i)
526 : {
2826 heikki.linnakangas 527 CBC 3510 : values[i] = (Datum) 0;
2826 heikki.linnakangas 528 GIC 3510 : replaces[i] = false;
2826 heikki.linnakangas 529 CBC 3510 : nulls[i] = false;
2826 heikki.linnakangas 530 ECB : }
2826 heikki.linnakangas 531 CBC 234 : if (updateRestriction)
532 : {
533 228 : replaces[Anum_pg_operator_oprrest - 1] = true;
2826 heikki.linnakangas 534 GIC 228 : values[Anum_pg_operator_oprrest - 1] = restrictionOid;
2826 heikki.linnakangas 535 ECB : }
2826 heikki.linnakangas 536 CBC 234 : if (updateJoin)
537 : {
538 228 : replaces[Anum_pg_operator_oprjoin - 1] = true;
2826 heikki.linnakangas 539 GIC 228 : values[Anum_pg_operator_oprjoin - 1] = joinOid;
2826 heikki.linnakangas 540 ECB : }
541 :
2826 heikki.linnakangas 542 GIC 234 : tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
543 : values, nulls, replaces);
2826 heikki.linnakangas 544 ECB :
2259 alvherre 545 GIC 234 : CatalogTupleUpdate(catalog, &tup->t_self, tup);
546 :
600 tgl 547 CBC 234 : address = makeOperatorDependencies(tup, false, true);
548 :
2656 549 234 : InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
550 :
1539 andres 551 234 : table_close(catalog, NoLock);
552 :
2826 heikki.linnakangas 553 234 : return address;
554 : }
|