1 /*-------------------------------------------------------------------------
2 *
3 * typecmds.c
4 * Routines for SQL commands that manipulate types (and domains).
5 *
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/commands/typecmds.c
12 *
13 * DESCRIPTION
14 * The "DefineFoo" routines take the parse tree and pick out the
15 * appropriate arguments/flags, passing the results to the
16 * corresponding "FooDefine" routines (in src/catalog) that do
17 * the actual catalog-munging. These routines also verify permission
18 * of the user to execute the command.
19 *
20 * NOTES
21 * These things must be defined and committed in the following order:
22 * "create function":
23 * input/output, recv/send functions
24 * "create type":
25 * type
26 * "create operator":
27 * operators
28 *
29 *
30 *-------------------------------------------------------------------------
31 */
32 #include "postgres.h"
33
34 #include "access/htup_details.h"
35 #include "access/xact.h"
36 #include "catalog/binary_upgrade.h"
37 #include "catalog/catalog.h"
38 #include "catalog/heap.h"
39 #include "catalog/objectaccess.h"
40 #include "catalog/pg_am.h"
41 #include "catalog/pg_authid.h"
42 #include "catalog/pg_collation.h"
43 #include "catalog/pg_constraint.h"
44 #include "catalog/pg_constraint_fn.h"
45 #include "catalog/pg_depend.h"
46 #include "catalog/pg_enum.h"
47 #include "catalog/pg_language.h"
48 #include "catalog/pg_namespace.h"
49 #include "catalog/pg_proc.h"
50 #include "catalog/pg_proc_fn.h"
51 #include "catalog/pg_range.h"
52 #include "catalog/pg_type.h"
53 #include "catalog/pg_type_fn.h"
54 #include "commands/defrem.h"
55 #include "commands/tablecmds.h"
56 #include "commands/typecmds.h"
57 #include "executor/executor.h"
58 #include "miscadmin.h"
59 #include "nodes/makefuncs.h"
60 #include "optimizer/var.h"
61 #include "parser/parse_coerce.h"
62 #include "parser/parse_collate.h"
63 #include "parser/parse_expr.h"
64 #include "parser/parse_func.h"
65 #include "parser/parse_type.h"
66 #include "utils/builtins.h"
67 #include "utils/fmgroids.h"
68 #include "utils/lsyscache.h"
69 #include "utils/memutils.h"
70 #include "utils/rel.h"
71 #include "utils/ruleutils.h"
72 #include "utils/snapmgr.h"
73 #include "utils/syscache.h"
74
75
76 /* result structure for get_rels_with_domain() */
77 typedef struct
78 {
79 Relation rel; /* opened and locked relation */
80 int natts; /* number of attributes of interest */
81 int *atts; /* attribute numbers */
82 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
83 } RelToCheck;
84
85 /* Potentially set by pg_upgrade_support functions */
86 Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
87
88 static void makeRangeConstructors(const char *name, Oid namespace,
89 Oid rangeOid, Oid subtype);
90 static Oid findTypeInputFunction(List *procname, Oid typeOid);
91 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
92 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
93 static Oid findTypeSendFunction(List *procname, Oid typeOid);
94 static Oid findTypeTypmodinFunction(List *procname);
95 static Oid findTypeTypmodoutFunction(List *procname);
96 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
97 static Oid findRangeSubOpclass(List *opcname, Oid subtype);
98 static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
99 static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
100 static void validateDomainConstraint(Oid domainoid, char *ccbin);
101 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
102 static void checkEnumOwner(HeapTuple tup);
103 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
104 Oid baseTypeOid,
105 int typMod, Constraint *constr,
106 char *domainName, ObjectAddress *constrAddr);
107 static Node *replace_domain_constraint_value(ParseState *pstate,
108 ColumnRef *cref);
109
110
111 /*
112 * DefineType
113 * Registers a new base type.
114 */
115 ObjectAddress
DefineType(ParseState * pstate,List * names,List * parameters)116 DefineType(ParseState *pstate, List *names, List *parameters)
117 {
118 char *typeName;
119 Oid typeNamespace;
120 int16 internalLength = -1; /* default: variable-length */
121 List *inputName = NIL;
122 List *outputName = NIL;
123 List *receiveName = NIL;
124 List *sendName = NIL;
125 List *typmodinName = NIL;
126 List *typmodoutName = NIL;
127 List *analyzeName = NIL;
128 char category = TYPCATEGORY_USER;
129 bool preferred = false;
130 char delimiter = DEFAULT_TYPDELIM;
131 Oid elemType = InvalidOid;
132 char *defaultValue = NULL;
133 bool byValue = false;
134 char alignment = 'i'; /* default alignment */
135 char storage = 'p'; /* default TOAST storage method */
136 Oid collation = InvalidOid;
137 DefElem *likeTypeEl = NULL;
138 DefElem *internalLengthEl = NULL;
139 DefElem *inputNameEl = NULL;
140 DefElem *outputNameEl = NULL;
141 DefElem *receiveNameEl = NULL;
142 DefElem *sendNameEl = NULL;
143 DefElem *typmodinNameEl = NULL;
144 DefElem *typmodoutNameEl = NULL;
145 DefElem *analyzeNameEl = NULL;
146 DefElem *categoryEl = NULL;
147 DefElem *preferredEl = NULL;
148 DefElem *delimiterEl = NULL;
149 DefElem *elemTypeEl = NULL;
150 DefElem *defaultValueEl = NULL;
151 DefElem *byValueEl = NULL;
152 DefElem *alignmentEl = NULL;
153 DefElem *storageEl = NULL;
154 DefElem *collatableEl = NULL;
155 Oid inputOid;
156 Oid outputOid;
157 Oid receiveOid = InvalidOid;
158 Oid sendOid = InvalidOid;
159 Oid typmodinOid = InvalidOid;
160 Oid typmodoutOid = InvalidOid;
161 Oid analyzeOid = InvalidOid;
162 char *array_type;
163 Oid array_oid;
164 Oid typoid;
165 Oid resulttype;
166 ListCell *pl;
167 ObjectAddress address;
168
169 /*
170 * As of Postgres 8.4, we require superuser privilege to create a base
171 * type. This is simple paranoia: there are too many ways to mess up the
172 * system with an incorrect type definition (for instance, representation
173 * parameters that don't match what the C code expects). In practice it
174 * takes superuser privilege to create the I/O functions, and so the
175 * former requirement that you own the I/O functions pretty much forced
176 * superuserness anyway. We're just making doubly sure here.
177 *
178 * XXX re-enable NOT_USED code sections below if you remove this test.
179 */
180 if (!superuser())
181 ereport(ERROR,
182 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
183 errmsg("must be superuser to create a base type")));
184
185 /* Convert list of names to a name and namespace */
186 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
187
188 #ifdef NOT_USED
189 /* XXX this is unnecessary given the superuser check above */
190 /* Check we have creation rights in target namespace */
191 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
192 if (aclresult != ACLCHECK_OK)
193 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
194 get_namespace_name(typeNamespace));
195 #endif
196
197 /*
198 * Look to see if type already exists (presumably as a shell; if not,
199 * TypeCreate will complain).
200 */
201 typoid = GetSysCacheOid2(TYPENAMENSP,
202 CStringGetDatum(typeName),
203 ObjectIdGetDatum(typeNamespace));
204
205 /*
206 * If it's not a shell, see if it's an autogenerated array type, and if so
207 * rename it out of the way.
208 */
209 if (OidIsValid(typoid) && get_typisdefined(typoid))
210 {
211 if (moveArrayTypeName(typoid, typeName, typeNamespace))
212 typoid = InvalidOid;
213 }
214
215 /*
216 * If it doesn't exist, create it as a shell, so that the OID is known for
217 * use in the I/O function definitions.
218 */
219 if (!OidIsValid(typoid))
220 {
221 address = TypeShellMake(typeName, typeNamespace, GetUserId());
222 typoid = address.objectId;
223 /* Make new shell type visible for modification below */
224 CommandCounterIncrement();
225
226 /*
227 * If the command was a parameterless CREATE TYPE, we're done ---
228 * creating the shell type was all we're supposed to do.
229 */
230 if (parameters == NIL)
231 return address;
232 }
233 else
234 {
235 /* Complain if dummy CREATE TYPE and entry already exists */
236 if (parameters == NIL)
237 ereport(ERROR,
238 (errcode(ERRCODE_DUPLICATE_OBJECT),
239 errmsg("type \"%s\" already exists", typeName)));
240 }
241
242 /* Extract the parameters from the parameter list */
243 foreach(pl, parameters)
244 {
245 DefElem *defel = (DefElem *) lfirst(pl);
246 DefElem **defelp;
247
248 if (pg_strcasecmp(defel->defname, "like") == 0)
249 defelp = &likeTypeEl;
250 else if (pg_strcasecmp(defel->defname, "internallength") == 0)
251 defelp = &internalLengthEl;
252 else if (pg_strcasecmp(defel->defname, "input") == 0)
253 defelp = &inputNameEl;
254 else if (pg_strcasecmp(defel->defname, "output") == 0)
255 defelp = &outputNameEl;
256 else if (pg_strcasecmp(defel->defname, "receive") == 0)
257 defelp = &receiveNameEl;
258 else if (pg_strcasecmp(defel->defname, "send") == 0)
259 defelp = &sendNameEl;
260 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
261 defelp = &typmodinNameEl;
262 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
263 defelp = &typmodoutNameEl;
264 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
265 pg_strcasecmp(defel->defname, "analyse") == 0)
266 defelp = &analyzeNameEl;
267 else if (pg_strcasecmp(defel->defname, "category") == 0)
268 defelp = &categoryEl;
269 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
270 defelp = &preferredEl;
271 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
272 defelp = &delimiterEl;
273 else if (pg_strcasecmp(defel->defname, "element") == 0)
274 defelp = &elemTypeEl;
275 else if (pg_strcasecmp(defel->defname, "default") == 0)
276 defelp = &defaultValueEl;
277 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
278 defelp = &byValueEl;
279 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
280 defelp = &alignmentEl;
281 else if (pg_strcasecmp(defel->defname, "storage") == 0)
282 defelp = &storageEl;
283 else if (pg_strcasecmp(defel->defname, "collatable") == 0)
284 defelp = &collatableEl;
285 else
286 {
287 /* WARNING, not ERROR, for historical backwards-compatibility */
288 ereport(WARNING,
289 (errcode(ERRCODE_SYNTAX_ERROR),
290 errmsg("type attribute \"%s\" not recognized",
291 defel->defname),
292 parser_errposition(pstate, defel->location)));
293 continue;
294 }
295 if (*defelp != NULL)
296 ereport(ERROR,
297 (errcode(ERRCODE_SYNTAX_ERROR),
298 errmsg("conflicting or redundant options"),
299 parser_errposition(pstate, defel->location)));
300 *defelp = defel;
301 }
302
303 /*
304 * Now interpret the options; we do this separately so that LIKE can be
305 * overridden by other options regardless of the ordering in the parameter
306 * list.
307 */
308 if (likeTypeEl)
309 {
310 Type likeType;
311 Form_pg_type likeForm;
312
313 likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
314 likeForm = (Form_pg_type) GETSTRUCT(likeType);
315 internalLength = likeForm->typlen;
316 byValue = likeForm->typbyval;
317 alignment = likeForm->typalign;
318 storage = likeForm->typstorage;
319 ReleaseSysCache(likeType);
320 }
321 if (internalLengthEl)
322 internalLength = defGetTypeLength(internalLengthEl);
323 if (inputNameEl)
324 inputName = defGetQualifiedName(inputNameEl);
325 if (outputNameEl)
326 outputName = defGetQualifiedName(outputNameEl);
327 if (receiveNameEl)
328 receiveName = defGetQualifiedName(receiveNameEl);
329 if (sendNameEl)
330 sendName = defGetQualifiedName(sendNameEl);
331 if (typmodinNameEl)
332 typmodinName = defGetQualifiedName(typmodinNameEl);
333 if (typmodoutNameEl)
334 typmodoutName = defGetQualifiedName(typmodoutNameEl);
335 if (analyzeNameEl)
336 analyzeName = defGetQualifiedName(analyzeNameEl);
337 if (categoryEl)
338 {
339 char *p = defGetString(categoryEl);
340
341 category = p[0];
342 /* restrict to non-control ASCII */
343 if (category < 32 || category > 126)
344 ereport(ERROR,
345 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
346 errmsg("invalid type category \"%s\": must be simple ASCII",
347 p)));
348 }
349 if (preferredEl)
350 preferred = defGetBoolean(preferredEl);
351 if (delimiterEl)
352 {
353 char *p = defGetString(delimiterEl);
354
355 delimiter = p[0];
356 /* XXX shouldn't we restrict the delimiter? */
357 }
358 if (elemTypeEl)
359 {
360 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
361 /* disallow arrays of pseudotypes */
362 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
363 ereport(ERROR,
364 (errcode(ERRCODE_DATATYPE_MISMATCH),
365 errmsg("array element type cannot be %s",
366 format_type_be(elemType))));
367 }
368 if (defaultValueEl)
369 defaultValue = defGetString(defaultValueEl);
370 if (byValueEl)
371 byValue = defGetBoolean(byValueEl);
372 if (alignmentEl)
373 {
374 char *a = defGetString(alignmentEl);
375
376 /*
377 * Note: if argument was an unquoted identifier, parser will have
378 * applied translations to it, so be prepared to recognize translated
379 * type names as well as the nominal form.
380 */
381 if (pg_strcasecmp(a, "double") == 0 ||
382 pg_strcasecmp(a, "float8") == 0 ||
383 pg_strcasecmp(a, "pg_catalog.float8") == 0)
384 alignment = 'd';
385 else if (pg_strcasecmp(a, "int4") == 0 ||
386 pg_strcasecmp(a, "pg_catalog.int4") == 0)
387 alignment = 'i';
388 else if (pg_strcasecmp(a, "int2") == 0 ||
389 pg_strcasecmp(a, "pg_catalog.int2") == 0)
390 alignment = 's';
391 else if (pg_strcasecmp(a, "char") == 0 ||
392 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
393 alignment = 'c';
394 else
395 ereport(ERROR,
396 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
397 errmsg("alignment \"%s\" not recognized", a)));
398 }
399 if (storageEl)
400 {
401 char *a = defGetString(storageEl);
402
403 if (pg_strcasecmp(a, "plain") == 0)
404 storage = 'p';
405 else if (pg_strcasecmp(a, "external") == 0)
406 storage = 'e';
407 else if (pg_strcasecmp(a, "extended") == 0)
408 storage = 'x';
409 else if (pg_strcasecmp(a, "main") == 0)
410 storage = 'm';
411 else
412 ereport(ERROR,
413 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
414 errmsg("storage \"%s\" not recognized", a)));
415 }
416 if (collatableEl)
417 collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
418
419 /*
420 * make sure we have our required definitions
421 */
422 if (inputName == NIL)
423 ereport(ERROR,
424 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
425 errmsg("type input function must be specified")));
426 if (outputName == NIL)
427 ereport(ERROR,
428 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
429 errmsg("type output function must be specified")));
430
431 if (typmodinName == NIL && typmodoutName != NIL)
432 ereport(ERROR,
433 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
434 errmsg("type modifier output function is useless without a type modifier input function")));
435
436 /*
437 * Convert I/O proc names to OIDs
438 */
439 inputOid = findTypeInputFunction(inputName, typoid);
440 outputOid = findTypeOutputFunction(outputName, typoid);
441 if (receiveName)
442 receiveOid = findTypeReceiveFunction(receiveName, typoid);
443 if (sendName)
444 sendOid = findTypeSendFunction(sendName, typoid);
445
446 /*
447 * Verify that I/O procs return the expected thing. If we see OPAQUE,
448 * complain and change it to the correct type-safe choice.
449 */
450 resulttype = get_func_rettype(inputOid);
451 if (resulttype != typoid)
452 {
453 if (resulttype == OPAQUEOID)
454 {
455 /* backwards-compatibility hack */
456 ereport(WARNING,
457 (errmsg("changing return type of function %s from %s to %s",
458 NameListToString(inputName), "opaque", typeName)));
459 SetFunctionReturnType(inputOid, typoid);
460 }
461 else
462 ereport(ERROR,
463 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
464 errmsg("type input function %s must return type %s",
465 NameListToString(inputName), typeName)));
466 }
467 resulttype = get_func_rettype(outputOid);
468 if (resulttype != CSTRINGOID)
469 {
470 if (resulttype == OPAQUEOID)
471 {
472 /* backwards-compatibility hack */
473 ereport(WARNING,
474 (errmsg("changing return type of function %s from %s to %s",
475 NameListToString(outputName), "opaque", "cstring")));
476 SetFunctionReturnType(outputOid, CSTRINGOID);
477 }
478 else
479 ereport(ERROR,
480 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
481 errmsg("type output function %s must return type %s",
482 NameListToString(outputName), "cstring")));
483 }
484 if (receiveOid)
485 {
486 resulttype = get_func_rettype(receiveOid);
487 if (resulttype != typoid)
488 ereport(ERROR,
489 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
490 errmsg("type receive function %s must return type %s",
491 NameListToString(receiveName), typeName)));
492 }
493 if (sendOid)
494 {
495 resulttype = get_func_rettype(sendOid);
496 if (resulttype != BYTEAOID)
497 ereport(ERROR,
498 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
499 errmsg("type send function %s must return type %s",
500 NameListToString(sendName), "bytea")));
501 }
502
503 /*
504 * Convert typmodin/out function proc names to OIDs.
505 */
506 if (typmodinName)
507 typmodinOid = findTypeTypmodinFunction(typmodinName);
508 if (typmodoutName)
509 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
510
511 /*
512 * Convert analysis function proc name to an OID. If no analysis function
513 * is specified, we'll use zero to select the built-in default algorithm.
514 */
515 if (analyzeName)
516 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
517
518 /*
519 * Check permissions on functions. We choose to require the creator/owner
520 * of a type to also own the underlying functions. Since creating a type
521 * is tantamount to granting public execute access on the functions, the
522 * minimum sane check would be for execute-with-grant-option. But we
523 * don't have a way to make the type go away if the grant option is
524 * revoked, so ownership seems better.
525 */
526 #ifdef NOT_USED
527 /* XXX this is unnecessary given the superuser check above */
528 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
529 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
530 NameListToString(inputName));
531 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
532 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
533 NameListToString(outputName));
534 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
535 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
536 NameListToString(receiveName));
537 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
538 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
539 NameListToString(sendName));
540 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
541 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
542 NameListToString(typmodinName));
543 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
544 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
545 NameListToString(typmodoutName));
546 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
547 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
548 NameListToString(analyzeName));
549 #endif
550
551 /*
552 * Print warnings if any of the type's I/O functions are marked volatile.
553 * There is a general assumption that I/O functions are stable or
554 * immutable; this allows us for example to mark record_in/record_out
555 * stable rather than volatile. Ideally we would throw errors not just
556 * warnings here; but since this check is new as of 9.5, and since the
557 * volatility marking might be just an error-of-omission and not a true
558 * indication of how the function behaves, we'll let it pass as a warning
559 * for now.
560 */
561 if (inputOid && func_volatile(inputOid) == PROVOLATILE_VOLATILE)
562 ereport(WARNING,
563 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
564 errmsg("type input function %s should not be volatile",
565 NameListToString(inputName))));
566 if (outputOid && func_volatile(outputOid) == PROVOLATILE_VOLATILE)
567 ereport(WARNING,
568 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
569 errmsg("type output function %s should not be volatile",
570 NameListToString(outputName))));
571 if (receiveOid && func_volatile(receiveOid) == PROVOLATILE_VOLATILE)
572 ereport(WARNING,
573 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
574 errmsg("type receive function %s should not be volatile",
575 NameListToString(receiveName))));
576 if (sendOid && func_volatile(sendOid) == PROVOLATILE_VOLATILE)
577 ereport(WARNING,
578 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
579 errmsg("type send function %s should not be volatile",
580 NameListToString(sendName))));
581 if (typmodinOid && func_volatile(typmodinOid) == PROVOLATILE_VOLATILE)
582 ereport(WARNING,
583 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
584 errmsg("type modifier input function %s should not be volatile",
585 NameListToString(typmodinName))));
586 if (typmodoutOid && func_volatile(typmodoutOid) == PROVOLATILE_VOLATILE)
587 ereport(WARNING,
588 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
589 errmsg("type modifier output function %s should not be volatile",
590 NameListToString(typmodoutName))));
591
592 /*
593 * OK, we're done checking, time to make the type. We must assign the
594 * array type OID ahead of calling TypeCreate, since the base type and
595 * array type each refer to the other.
596 */
597 array_oid = AssignTypeArrayOid();
598
599 /*
600 * now have TypeCreate do all the real work.
601 *
602 * Note: the pg_type.oid is stored in user tables as array elements (base
603 * types) in ArrayType and in composite types in DatumTupleFields. This
604 * oid must be preserved by binary upgrades.
605 */
606 address =
607 TypeCreate(InvalidOid, /* no predetermined type OID */
608 typeName, /* type name */
609 typeNamespace, /* namespace */
610 InvalidOid, /* relation oid (n/a here) */
611 0, /* relation kind (ditto) */
612 GetUserId(), /* owner's ID */
613 internalLength, /* internal size */
614 TYPTYPE_BASE, /* type-type (base type) */
615 category, /* type-category */
616 preferred, /* is it a preferred type? */
617 delimiter, /* array element delimiter */
618 inputOid, /* input procedure */
619 outputOid, /* output procedure */
620 receiveOid, /* receive procedure */
621 sendOid, /* send procedure */
622 typmodinOid, /* typmodin procedure */
623 typmodoutOid, /* typmodout procedure */
624 analyzeOid, /* analyze procedure */
625 elemType, /* element type ID */
626 false, /* this is not an array type */
627 array_oid, /* array type we are about to create */
628 InvalidOid, /* base type ID (only for domains) */
629 defaultValue, /* default type value */
630 NULL, /* no binary form available */
631 byValue, /* passed by value */
632 alignment, /* required alignment */
633 storage, /* TOAST strategy */
634 -1, /* typMod (Domains only) */
635 0, /* Array Dimensions of typbasetype */
636 false, /* Type NOT NULL */
637 collation); /* type's collation */
638 Assert(typoid == address.objectId);
639
640 /*
641 * Create the array type that goes with it.
642 */
643 array_type = makeArrayTypeName(typeName, typeNamespace);
644
645 /* alignment must be 'i' or 'd' for arrays */
646 alignment = (alignment == 'd') ? 'd' : 'i';
647
648 TypeCreate(array_oid, /* force assignment of this type OID */
649 array_type, /* type name */
650 typeNamespace, /* namespace */
651 InvalidOid, /* relation oid (n/a here) */
652 0, /* relation kind (ditto) */
653 GetUserId(), /* owner's ID */
654 -1, /* internal size (always varlena) */
655 TYPTYPE_BASE, /* type-type (base type) */
656 TYPCATEGORY_ARRAY, /* type-category (array) */
657 false, /* array types are never preferred */
658 delimiter, /* array element delimiter */
659 F_ARRAY_IN, /* input procedure */
660 F_ARRAY_OUT, /* output procedure */
661 F_ARRAY_RECV, /* receive procedure */
662 F_ARRAY_SEND, /* send procedure */
663 typmodinOid, /* typmodin procedure */
664 typmodoutOid, /* typmodout procedure */
665 F_ARRAY_TYPANALYZE, /* analyze procedure */
666 typoid, /* element type ID */
667 true, /* yes this is an array type */
668 InvalidOid, /* no further array type */
669 InvalidOid, /* base type ID */
670 NULL, /* never a default type value */
671 NULL, /* binary default isn't sent either */
672 false, /* never passed by value */
673 alignment, /* see above */
674 'x', /* ARRAY is always toastable */
675 -1, /* typMod (Domains only) */
676 0, /* Array dimensions of typbasetype */
677 false, /* Type NOT NULL */
678 collation); /* type's collation */
679
680 pfree(array_type);
681
682 return address;
683 }
684
685 /*
686 * Guts of type deletion.
687 */
688 void
RemoveTypeById(Oid typeOid)689 RemoveTypeById(Oid typeOid)
690 {
691 Relation relation;
692 HeapTuple tup;
693
694 relation = heap_open(TypeRelationId, RowExclusiveLock);
695
696 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
697 if (!HeapTupleIsValid(tup))
698 elog(ERROR, "cache lookup failed for type %u", typeOid);
699
700 CatalogTupleDelete(relation, &tup->t_self);
701
702 /*
703 * If it is an enum, delete the pg_enum entries too; we don't bother with
704 * making dependency entries for those, so it has to be done "by hand"
705 * here.
706 */
707 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
708 EnumValuesDelete(typeOid);
709
710 /*
711 * If it is a range type, delete the pg_range entry too; we don't bother
712 * with making a dependency entry for that, so it has to be done "by hand"
713 * here.
714 */
715 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
716 RangeDelete(typeOid);
717
718 ReleaseSysCache(tup);
719
720 heap_close(relation, RowExclusiveLock);
721 }
722
723
724 /*
725 * DefineDomain
726 * Registers a new domain.
727 */
728 ObjectAddress
DefineDomain(CreateDomainStmt * stmt)729 DefineDomain(CreateDomainStmt *stmt)
730 {
731 char *domainName;
732 Oid domainNamespace;
733 AclResult aclresult;
734 int16 internalLength;
735 Oid inputProcedure;
736 Oid outputProcedure;
737 Oid receiveProcedure;
738 Oid sendProcedure;
739 Oid analyzeProcedure;
740 bool byValue;
741 char category;
742 char delimiter;
743 char alignment;
744 char storage;
745 char typtype;
746 Datum datum;
747 bool isnull;
748 char *defaultValue = NULL;
749 char *defaultValueBin = NULL;
750 bool saw_default = false;
751 bool typNotNull = false;
752 bool nullDefined = false;
753 int32 typNDims = list_length(stmt->typeName->arrayBounds);
754 HeapTuple typeTup;
755 List *schema = stmt->constraints;
756 ListCell *listptr;
757 Oid basetypeoid;
758 Oid old_type_oid;
759 Oid domaincoll;
760 Form_pg_type baseType;
761 int32 basetypeMod;
762 Oid baseColl;
763 ObjectAddress address;
764
765 /* Convert list of names to a name and namespace */
766 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
767 &domainName);
768
769 /* Check we have creation rights in target namespace */
770 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
771 ACL_CREATE);
772 if (aclresult != ACLCHECK_OK)
773 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
774 get_namespace_name(domainNamespace));
775
776 /*
777 * Check for collision with an existing type name. If there is one and
778 * it's an autogenerated array, we can rename it out of the way.
779 */
780 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
781 CStringGetDatum(domainName),
782 ObjectIdGetDatum(domainNamespace));
783 if (OidIsValid(old_type_oid))
784 {
785 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
786 ereport(ERROR,
787 (errcode(ERRCODE_DUPLICATE_OBJECT),
788 errmsg("type \"%s\" already exists", domainName)));
789 }
790
791 /*
792 * Look up the base type.
793 */
794 typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
795 baseType = (Form_pg_type) GETSTRUCT(typeTup);
796 basetypeoid = HeapTupleGetOid(typeTup);
797
798 /*
799 * Base type must be a plain base type, another domain, an enum or a range
800 * type. Domains over pseudotypes would create a security hole. Domains
801 * over composite types might be made to work in the future, but not
802 * today.
803 */
804 typtype = baseType->typtype;
805 if (typtype != TYPTYPE_BASE &&
806 typtype != TYPTYPE_DOMAIN &&
807 typtype != TYPTYPE_ENUM &&
808 typtype != TYPTYPE_RANGE)
809 ereport(ERROR,
810 (errcode(ERRCODE_DATATYPE_MISMATCH),
811 errmsg("\"%s\" is not a valid base type for a domain",
812 TypeNameToString(stmt->typeName))));
813
814 aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
815 if (aclresult != ACLCHECK_OK)
816 aclcheck_error_type(aclresult, basetypeoid);
817
818 /*
819 * Identify the collation if any
820 */
821 baseColl = baseType->typcollation;
822 if (stmt->collClause)
823 domaincoll = get_collation_oid(stmt->collClause->collname, false);
824 else
825 domaincoll = baseColl;
826
827 /* Complain if COLLATE is applied to an uncollatable type */
828 if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
829 ereport(ERROR,
830 (errcode(ERRCODE_DATATYPE_MISMATCH),
831 errmsg("collations are not supported by type %s",
832 format_type_be(basetypeoid))));
833
834 /* passed by value */
835 byValue = baseType->typbyval;
836
837 /* Required Alignment */
838 alignment = baseType->typalign;
839
840 /* TOAST Strategy */
841 storage = baseType->typstorage;
842
843 /* Storage Length */
844 internalLength = baseType->typlen;
845
846 /* Type Category */
847 category = baseType->typcategory;
848
849 /* Array element Delimiter */
850 delimiter = baseType->typdelim;
851
852 /* I/O Functions */
853 inputProcedure = F_DOMAIN_IN;
854 outputProcedure = baseType->typoutput;
855 receiveProcedure = F_DOMAIN_RECV;
856 sendProcedure = baseType->typsend;
857
858 /* Domains never accept typmods, so no typmodin/typmodout needed */
859
860 /* Analysis function */
861 analyzeProcedure = baseType->typanalyze;
862
863 /* Inherited default value */
864 datum = SysCacheGetAttr(TYPEOID, typeTup,
865 Anum_pg_type_typdefault, &isnull);
866 if (!isnull)
867 defaultValue = TextDatumGetCString(datum);
868
869 /* Inherited default binary value */
870 datum = SysCacheGetAttr(TYPEOID, typeTup,
871 Anum_pg_type_typdefaultbin, &isnull);
872 if (!isnull)
873 defaultValueBin = TextDatumGetCString(datum);
874
875 /*
876 * Run through constraints manually to avoid the additional processing
877 * conducted by DefineRelation() and friends.
878 */
879 foreach(listptr, schema)
880 {
881 Constraint *constr = lfirst(listptr);
882
883 if (!IsA(constr, Constraint))
884 elog(ERROR, "unrecognized node type: %d",
885 (int) nodeTag(constr));
886 switch (constr->contype)
887 {
888 case CONSTR_DEFAULT:
889
890 /*
891 * The inherited default value may be overridden by the user
892 * with the DEFAULT <expr> clause ... but only once.
893 */
894 if (saw_default)
895 ereport(ERROR,
896 (errcode(ERRCODE_SYNTAX_ERROR),
897 errmsg("multiple default expressions")));
898 saw_default = true;
899
900 if (constr->raw_expr)
901 {
902 ParseState *pstate;
903 Node *defaultExpr;
904
905 /* Create a dummy ParseState for transformExpr */
906 pstate = make_parsestate(NULL);
907
908 /*
909 * Cook the constr->raw_expr into an expression; copy it
910 * in case the input is in plan cache. Note: name is used
911 * only for error messages.
912 */
913 defaultExpr = cookDefault(pstate,
914 copyObject(constr->raw_expr),
915 basetypeoid,
916 basetypeMod,
917 domainName);
918
919 /*
920 * If the expression is just a NULL constant, we treat it
921 * like not having a default.
922 *
923 * Note that if the basetype is another domain, we'll see
924 * a CoerceToDomain expr here and not discard the default.
925 * This is critical because the domain default needs to be
926 * retained to override any default that the base domain
927 * might have.
928 */
929 if (defaultExpr == NULL ||
930 (IsA(defaultExpr, Const) &&
931 ((Const *) defaultExpr)->constisnull))
932 {
933 defaultValue = NULL;
934 defaultValueBin = NULL;
935 }
936 else
937 {
938 /*
939 * Expression must be stored as a nodeToString result,
940 * but we also require a valid textual representation
941 * (mainly to make life easier for pg_dump).
942 */
943 defaultValue =
944 deparse_expression(defaultExpr,
945 NIL, false, false);
946 defaultValueBin = nodeToString(defaultExpr);
947 }
948 }
949 else
950 {
951 /* No default (can this still happen?) */
952 defaultValue = NULL;
953 defaultValueBin = NULL;
954 }
955 break;
956
957 case CONSTR_NOTNULL:
958 if (nullDefined && !typNotNull)
959 ereport(ERROR,
960 (errcode(ERRCODE_SYNTAX_ERROR),
961 errmsg("conflicting NULL/NOT NULL constraints")));
962 typNotNull = true;
963 nullDefined = true;
964 break;
965
966 case CONSTR_NULL:
967 if (nullDefined && typNotNull)
968 ereport(ERROR,
969 (errcode(ERRCODE_SYNTAX_ERROR),
970 errmsg("conflicting NULL/NOT NULL constraints")));
971 typNotNull = false;
972 nullDefined = true;
973 break;
974
975 case CONSTR_CHECK:
976
977 /*
978 * Check constraints are handled after domain creation, as
979 * they require the Oid of the domain; at this point we can
980 * only check that they're not marked NO INHERIT, because that
981 * would be bogus.
982 */
983 if (constr->is_no_inherit)
984 ereport(ERROR,
985 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
986 errmsg("check constraints for domains cannot be marked NO INHERIT")));
987 break;
988
989 /*
990 * All else are error cases
991 */
992 case CONSTR_UNIQUE:
993 ereport(ERROR,
994 (errcode(ERRCODE_SYNTAX_ERROR),
995 errmsg("unique constraints not possible for domains")));
996 break;
997
998 case CONSTR_PRIMARY:
999 ereport(ERROR,
1000 (errcode(ERRCODE_SYNTAX_ERROR),
1001 errmsg("primary key constraints not possible for domains")));
1002 break;
1003
1004 case CONSTR_EXCLUSION:
1005 ereport(ERROR,
1006 (errcode(ERRCODE_SYNTAX_ERROR),
1007 errmsg("exclusion constraints not possible for domains")));
1008 break;
1009
1010 case CONSTR_FOREIGN:
1011 ereport(ERROR,
1012 (errcode(ERRCODE_SYNTAX_ERROR),
1013 errmsg("foreign key constraints not possible for domains")));
1014 break;
1015
1016 case CONSTR_ATTR_DEFERRABLE:
1017 case CONSTR_ATTR_NOT_DEFERRABLE:
1018 case CONSTR_ATTR_DEFERRED:
1019 case CONSTR_ATTR_IMMEDIATE:
1020 ereport(ERROR,
1021 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1022 errmsg("specifying constraint deferrability not supported for domains")));
1023 break;
1024
1025 default:
1026 elog(ERROR, "unrecognized constraint subtype: %d",
1027 (int) constr->contype);
1028 break;
1029 }
1030 }
1031
1032 /*
1033 * Have TypeCreate do all the real work.
1034 */
1035 address =
1036 TypeCreate(InvalidOid, /* no predetermined type OID */
1037 domainName, /* type name */
1038 domainNamespace, /* namespace */
1039 InvalidOid, /* relation oid (n/a here) */
1040 0, /* relation kind (ditto) */
1041 GetUserId(), /* owner's ID */
1042 internalLength, /* internal size */
1043 TYPTYPE_DOMAIN, /* type-type (domain type) */
1044 category, /* type-category */
1045 false, /* domain types are never preferred */
1046 delimiter, /* array element delimiter */
1047 inputProcedure, /* input procedure */
1048 outputProcedure, /* output procedure */
1049 receiveProcedure, /* receive procedure */
1050 sendProcedure, /* send procedure */
1051 InvalidOid, /* typmodin procedure - none */
1052 InvalidOid, /* typmodout procedure - none */
1053 analyzeProcedure, /* analyze procedure */
1054 InvalidOid, /* no array element type */
1055 false, /* this isn't an array */
1056 InvalidOid, /* no arrays for domains (yet) */
1057 basetypeoid, /* base type ID */
1058 defaultValue, /* default type value (text) */
1059 defaultValueBin, /* default type value (binary) */
1060 byValue, /* passed by value */
1061 alignment, /* required alignment */
1062 storage, /* TOAST strategy */
1063 basetypeMod, /* typeMod value */
1064 typNDims, /* Array dimensions for base type */
1065 typNotNull, /* Type NOT NULL */
1066 domaincoll); /* type's collation */
1067
1068 /*
1069 * Process constraints which refer to the domain ID returned by TypeCreate
1070 */
1071 foreach(listptr, schema)
1072 {
1073 Constraint *constr = lfirst(listptr);
1074
1075 /* it must be a Constraint, per check above */
1076
1077 switch (constr->contype)
1078 {
1079 case CONSTR_CHECK:
1080 domainAddConstraint(address.objectId, domainNamespace,
1081 basetypeoid, basetypeMod,
1082 constr, domainName, NULL);
1083 break;
1084
1085 /* Other constraint types were fully processed above */
1086
1087 default:
1088 break;
1089 }
1090
1091 /* CCI so we can detect duplicate constraint names */
1092 CommandCounterIncrement();
1093 }
1094
1095 /*
1096 * Now we can clean up.
1097 */
1098 ReleaseSysCache(typeTup);
1099
1100 return address;
1101 }
1102
1103
1104 /*
1105 * DefineEnum
1106 * Registers a new enum.
1107 */
1108 ObjectAddress
DefineEnum(CreateEnumStmt * stmt)1109 DefineEnum(CreateEnumStmt *stmt)
1110 {
1111 char *enumName;
1112 char *enumArrayName;
1113 Oid enumNamespace;
1114 AclResult aclresult;
1115 Oid old_type_oid;
1116 Oid enumArrayOid;
1117 ObjectAddress enumTypeAddr;
1118
1119 /* Convert list of names to a name and namespace */
1120 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1121 &enumName);
1122
1123 /* Check we have creation rights in target namespace */
1124 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1125 if (aclresult != ACLCHECK_OK)
1126 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1127 get_namespace_name(enumNamespace));
1128
1129 /*
1130 * Check for collision with an existing type name. If there is one and
1131 * it's an autogenerated array, we can rename it out of the way.
1132 */
1133 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1134 CStringGetDatum(enumName),
1135 ObjectIdGetDatum(enumNamespace));
1136 if (OidIsValid(old_type_oid))
1137 {
1138 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1139 ereport(ERROR,
1140 (errcode(ERRCODE_DUPLICATE_OBJECT),
1141 errmsg("type \"%s\" already exists", enumName)));
1142 }
1143
1144 enumArrayOid = AssignTypeArrayOid();
1145
1146 /* Create the pg_type entry */
1147 enumTypeAddr =
1148 TypeCreate(InvalidOid, /* no predetermined type OID */
1149 enumName, /* type name */
1150 enumNamespace, /* namespace */
1151 InvalidOid, /* relation oid (n/a here) */
1152 0, /* relation kind (ditto) */
1153 GetUserId(), /* owner's ID */
1154 sizeof(Oid), /* internal size */
1155 TYPTYPE_ENUM, /* type-type (enum type) */
1156 TYPCATEGORY_ENUM, /* type-category (enum type) */
1157 false, /* enum types are never preferred */
1158 DEFAULT_TYPDELIM, /* array element delimiter */
1159 F_ENUM_IN, /* input procedure */
1160 F_ENUM_OUT, /* output procedure */
1161 F_ENUM_RECV, /* receive procedure */
1162 F_ENUM_SEND, /* send procedure */
1163 InvalidOid, /* typmodin procedure - none */
1164 InvalidOid, /* typmodout procedure - none */
1165 InvalidOid, /* analyze procedure - default */
1166 InvalidOid, /* element type ID */
1167 false, /* this is not an array type */
1168 enumArrayOid, /* array type we are about to create */
1169 InvalidOid, /* base type ID (only for domains) */
1170 NULL, /* never a default type value */
1171 NULL, /* binary default isn't sent either */
1172 true, /* always passed by value */
1173 'i', /* int alignment */
1174 'p', /* TOAST strategy always plain */
1175 -1, /* typMod (Domains only) */
1176 0, /* Array dimensions of typbasetype */
1177 false, /* Type NOT NULL */
1178 InvalidOid); /* type's collation */
1179
1180 /* Enter the enum's values into pg_enum */
1181 EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
1182
1183 /*
1184 * Create the array type that goes with it.
1185 */
1186 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1187
1188 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1189 enumArrayName, /* type name */
1190 enumNamespace, /* namespace */
1191 InvalidOid, /* relation oid (n/a here) */
1192 0, /* relation kind (ditto) */
1193 GetUserId(), /* owner's ID */
1194 -1, /* internal size (always varlena) */
1195 TYPTYPE_BASE, /* type-type (base type) */
1196 TYPCATEGORY_ARRAY, /* type-category (array) */
1197 false, /* array types are never preferred */
1198 DEFAULT_TYPDELIM, /* array element delimiter */
1199 F_ARRAY_IN, /* input procedure */
1200 F_ARRAY_OUT, /* output procedure */
1201 F_ARRAY_RECV, /* receive procedure */
1202 F_ARRAY_SEND, /* send procedure */
1203 InvalidOid, /* typmodin procedure - none */
1204 InvalidOid, /* typmodout procedure - none */
1205 F_ARRAY_TYPANALYZE, /* analyze procedure */
1206 enumTypeAddr.objectId, /* element type ID */
1207 true, /* yes this is an array type */
1208 InvalidOid, /* no further array type */
1209 InvalidOid, /* base type ID */
1210 NULL, /* never a default type value */
1211 NULL, /* binary default isn't sent either */
1212 false, /* never passed by value */
1213 'i', /* enums have align i, so do their arrays */
1214 'x', /* ARRAY is always toastable */
1215 -1, /* typMod (Domains only) */
1216 0, /* Array dimensions of typbasetype */
1217 false, /* Type NOT NULL */
1218 InvalidOid); /* type's collation */
1219
1220 pfree(enumArrayName);
1221
1222 return enumTypeAddr;
1223 }
1224
1225 /*
1226 * AlterEnum
1227 * ALTER TYPE on an enum.
1228 */
1229 ObjectAddress
AlterEnum(AlterEnumStmt * stmt,bool isTopLevel)1230 AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
1231 {
1232 Oid enum_type_oid;
1233 TypeName *typename;
1234 HeapTuple tup;
1235 ObjectAddress address;
1236
1237 /* Make a TypeName so we can use standard type lookup machinery */
1238 typename = makeTypeNameFromNameList(stmt->typeName);
1239 enum_type_oid = typenameTypeId(NULL, typename);
1240
1241 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1242 if (!HeapTupleIsValid(tup))
1243 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1244
1245 /* Check it's an enum and check user has permission to ALTER the enum */
1246 checkEnumOwner(tup);
1247
1248 if (stmt->oldVal)
1249 {
1250 /* Rename an existing label */
1251 RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
1252 }
1253 else
1254 {
1255 /* Add a new label */
1256
1257 /*
1258 * Ordinarily we disallow adding values within transaction blocks,
1259 * because we can't cope with enum OID values getting into indexes and
1260 * then having their defining pg_enum entries go away. However, it's
1261 * okay if the enum type was created in the current transaction, since
1262 * then there can be no such indexes that wouldn't themselves go away
1263 * on rollback. (We support this case because pg_dump
1264 * --binary-upgrade needs it.) We test this by seeing if the pg_type
1265 * row has xmin == current XID and is not HEAP_UPDATED. If it is
1266 * HEAP_UPDATED, we can't be sure whether the type was created or only
1267 * modified in this xact. So we are disallowing some cases that could
1268 * theoretically be safe; but fortunately pg_dump only needs the
1269 * simplest case.
1270 */
1271 if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() &&
1272 !(tup->t_data->t_infomask & HEAP_UPDATED))
1273 /* safe to do inside transaction block */ ;
1274 else
1275 PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD");
1276
1277 AddEnumLabel(enum_type_oid, stmt->newVal,
1278 stmt->newValNeighbor, stmt->newValIsAfter,
1279 stmt->skipIfNewValExists);
1280 }
1281
1282 InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1283
1284 ObjectAddressSet(address, TypeRelationId, enum_type_oid);
1285
1286 ReleaseSysCache(tup);
1287
1288 return address;
1289 }
1290
1291
1292 /*
1293 * checkEnumOwner
1294 *
1295 * Check that the type is actually an enum and that the current user
1296 * has permission to do ALTER TYPE on it. Throw an error if not.
1297 */
1298 static void
checkEnumOwner(HeapTuple tup)1299 checkEnumOwner(HeapTuple tup)
1300 {
1301 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1302
1303 /* Check that this is actually an enum */
1304 if (typTup->typtype != TYPTYPE_ENUM)
1305 ereport(ERROR,
1306 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1307 errmsg("%s is not an enum",
1308 format_type_be(HeapTupleGetOid(tup)))));
1309
1310 /* Permission check: must own type */
1311 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1312 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
1313 }
1314
1315
1316 /*
1317 * DefineRange
1318 * Registers a new range type.
1319 */
1320 ObjectAddress
DefineRange(CreateRangeStmt * stmt)1321 DefineRange(CreateRangeStmt *stmt)
1322 {
1323 char *typeName;
1324 Oid typeNamespace;
1325 Oid typoid;
1326 char *rangeArrayName;
1327 Oid rangeArrayOid;
1328 Oid rangeSubtype = InvalidOid;
1329 List *rangeSubOpclassName = NIL;
1330 List *rangeCollationName = NIL;
1331 List *rangeCanonicalName = NIL;
1332 List *rangeSubtypeDiffName = NIL;
1333 Oid rangeSubOpclass;
1334 Oid rangeCollation;
1335 regproc rangeCanonical;
1336 regproc rangeSubtypeDiff;
1337 int16 subtyplen;
1338 bool subtypbyval;
1339 char subtypalign;
1340 char alignment;
1341 AclResult aclresult;
1342 ListCell *lc;
1343 ObjectAddress address;
1344
1345 /* Convert list of names to a name and namespace */
1346 typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1347 &typeName);
1348
1349 /* Check we have creation rights in target namespace */
1350 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1351 if (aclresult != ACLCHECK_OK)
1352 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1353 get_namespace_name(typeNamespace));
1354
1355 /*
1356 * Look to see if type already exists.
1357 */
1358 typoid = GetSysCacheOid2(TYPENAMENSP,
1359 CStringGetDatum(typeName),
1360 ObjectIdGetDatum(typeNamespace));
1361
1362 /*
1363 * If it's not a shell, see if it's an autogenerated array type, and if so
1364 * rename it out of the way.
1365 */
1366 if (OidIsValid(typoid) && get_typisdefined(typoid))
1367 {
1368 if (moveArrayTypeName(typoid, typeName, typeNamespace))
1369 typoid = InvalidOid;
1370 else
1371 ereport(ERROR,
1372 (errcode(ERRCODE_DUPLICATE_OBJECT),
1373 errmsg("type \"%s\" already exists", typeName)));
1374 }
1375
1376 /*
1377 * If it doesn't exist, create it as a shell, so that the OID is known for
1378 * use in the range function definitions.
1379 */
1380 if (!OidIsValid(typoid))
1381 {
1382 address = TypeShellMake(typeName, typeNamespace, GetUserId());
1383 typoid = address.objectId;
1384 /* Make new shell type visible for modification below */
1385 CommandCounterIncrement();
1386 }
1387
1388 /* Extract the parameters from the parameter list */
1389 foreach(lc, stmt->params)
1390 {
1391 DefElem *defel = (DefElem *) lfirst(lc);
1392
1393 if (pg_strcasecmp(defel->defname, "subtype") == 0)
1394 {
1395 if (OidIsValid(rangeSubtype))
1396 ereport(ERROR,
1397 (errcode(ERRCODE_SYNTAX_ERROR),
1398 errmsg("conflicting or redundant options")));
1399 /* we can look up the subtype name immediately */
1400 rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1401 }
1402 else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
1403 {
1404 if (rangeSubOpclassName != NIL)
1405 ereport(ERROR,
1406 (errcode(ERRCODE_SYNTAX_ERROR),
1407 errmsg("conflicting or redundant options")));
1408 rangeSubOpclassName = defGetQualifiedName(defel);
1409 }
1410 else if (pg_strcasecmp(defel->defname, "collation") == 0)
1411 {
1412 if (rangeCollationName != NIL)
1413 ereport(ERROR,
1414 (errcode(ERRCODE_SYNTAX_ERROR),
1415 errmsg("conflicting or redundant options")));
1416 rangeCollationName = defGetQualifiedName(defel);
1417 }
1418 else if (pg_strcasecmp(defel->defname, "canonical") == 0)
1419 {
1420 if (rangeCanonicalName != NIL)
1421 ereport(ERROR,
1422 (errcode(ERRCODE_SYNTAX_ERROR),
1423 errmsg("conflicting or redundant options")));
1424 rangeCanonicalName = defGetQualifiedName(defel);
1425 }
1426 else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
1427 {
1428 if (rangeSubtypeDiffName != NIL)
1429 ereport(ERROR,
1430 (errcode(ERRCODE_SYNTAX_ERROR),
1431 errmsg("conflicting or redundant options")));
1432 rangeSubtypeDiffName = defGetQualifiedName(defel);
1433 }
1434 else
1435 ereport(ERROR,
1436 (errcode(ERRCODE_SYNTAX_ERROR),
1437 errmsg("type attribute \"%s\" not recognized",
1438 defel->defname)));
1439 }
1440
1441 /* Must have a subtype */
1442 if (!OidIsValid(rangeSubtype))
1443 ereport(ERROR,
1444 (errcode(ERRCODE_SYNTAX_ERROR),
1445 errmsg("type attribute \"subtype\" is required")));
1446 /* disallow ranges of pseudotypes */
1447 if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
1448 ereport(ERROR,
1449 (errcode(ERRCODE_DATATYPE_MISMATCH),
1450 errmsg("range subtype cannot be %s",
1451 format_type_be(rangeSubtype))));
1452
1453 /* Identify subopclass */
1454 rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1455
1456 /* Identify collation to use, if any */
1457 if (type_is_collatable(rangeSubtype))
1458 {
1459 if (rangeCollationName != NIL)
1460 rangeCollation = get_collation_oid(rangeCollationName, false);
1461 else
1462 rangeCollation = get_typcollation(rangeSubtype);
1463 }
1464 else
1465 {
1466 if (rangeCollationName != NIL)
1467 ereport(ERROR,
1468 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1469 errmsg("range collation specified but subtype does not support collation")));
1470 rangeCollation = InvalidOid;
1471 }
1472
1473 /* Identify support functions, if provided */
1474 if (rangeCanonicalName != NIL)
1475 rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1476 typoid);
1477 else
1478 rangeCanonical = InvalidOid;
1479
1480 if (rangeSubtypeDiffName != NIL)
1481 rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1482 rangeSubtype);
1483 else
1484 rangeSubtypeDiff = InvalidOid;
1485
1486 get_typlenbyvalalign(rangeSubtype,
1487 &subtyplen, &subtypbyval, &subtypalign);
1488
1489 /* alignment must be 'i' or 'd' for ranges */
1490 alignment = (subtypalign == 'd') ? 'd' : 'i';
1491
1492 /* Allocate OID for array type */
1493 rangeArrayOid = AssignTypeArrayOid();
1494
1495 /* Create the pg_type entry */
1496 address =
1497 TypeCreate(InvalidOid, /* no predetermined type OID */
1498 typeName, /* type name */
1499 typeNamespace, /* namespace */
1500 InvalidOid, /* relation oid (n/a here) */
1501 0, /* relation kind (ditto) */
1502 GetUserId(), /* owner's ID */
1503 -1, /* internal size (always varlena) */
1504 TYPTYPE_RANGE, /* type-type (range type) */
1505 TYPCATEGORY_RANGE, /* type-category (range type) */
1506 false, /* range types are never preferred */
1507 DEFAULT_TYPDELIM, /* array element delimiter */
1508 F_RANGE_IN, /* input procedure */
1509 F_RANGE_OUT, /* output procedure */
1510 F_RANGE_RECV, /* receive procedure */
1511 F_RANGE_SEND, /* send procedure */
1512 InvalidOid, /* typmodin procedure - none */
1513 InvalidOid, /* typmodout procedure - none */
1514 F_RANGE_TYPANALYZE, /* analyze procedure */
1515 InvalidOid, /* element type ID - none */
1516 false, /* this is not an array type */
1517 rangeArrayOid, /* array type we are about to create */
1518 InvalidOid, /* base type ID (only for domains) */
1519 NULL, /* never a default type value */
1520 NULL, /* no binary form available either */
1521 false, /* never passed by value */
1522 alignment, /* alignment */
1523 'x', /* TOAST strategy (always extended) */
1524 -1, /* typMod (Domains only) */
1525 0, /* Array dimensions of typbasetype */
1526 false, /* Type NOT NULL */
1527 InvalidOid); /* type's collation (ranges never have one) */
1528 Assert(typoid == address.objectId);
1529
1530 /* Create the entry in pg_range */
1531 RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1532 rangeCanonical, rangeSubtypeDiff);
1533
1534 /*
1535 * Create the array type that goes with it.
1536 */
1537 rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1538
1539 TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1540 rangeArrayName, /* type name */
1541 typeNamespace, /* namespace */
1542 InvalidOid, /* relation oid (n/a here) */
1543 0, /* relation kind (ditto) */
1544 GetUserId(), /* owner's ID */
1545 -1, /* internal size (always varlena) */
1546 TYPTYPE_BASE, /* type-type (base type) */
1547 TYPCATEGORY_ARRAY, /* type-category (array) */
1548 false, /* array types are never preferred */
1549 DEFAULT_TYPDELIM, /* array element delimiter */
1550 F_ARRAY_IN, /* input procedure */
1551 F_ARRAY_OUT, /* output procedure */
1552 F_ARRAY_RECV, /* receive procedure */
1553 F_ARRAY_SEND, /* send procedure */
1554 InvalidOid, /* typmodin procedure - none */
1555 InvalidOid, /* typmodout procedure - none */
1556 F_ARRAY_TYPANALYZE, /* analyze procedure */
1557 typoid, /* element type ID */
1558 true, /* yes this is an array type */
1559 InvalidOid, /* no further array type */
1560 InvalidOid, /* base type ID */
1561 NULL, /* never a default type value */
1562 NULL, /* binary default isn't sent either */
1563 false, /* never passed by value */
1564 alignment, /* alignment - same as range's */
1565 'x', /* ARRAY is always toastable */
1566 -1, /* typMod (Domains only) */
1567 0, /* Array dimensions of typbasetype */
1568 false, /* Type NOT NULL */
1569 InvalidOid); /* typcollation */
1570
1571 pfree(rangeArrayName);
1572
1573 /* And create the constructor functions for this range type */
1574 makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1575
1576 return address;
1577 }
1578
1579 /*
1580 * Because there may exist several range types over the same subtype, the
1581 * range type can't be uniquely determined from the subtype. So it's
1582 * impossible to define a polymorphic constructor; we have to generate new
1583 * constructor functions explicitly for each range type.
1584 *
1585 * We actually define 4 functions, with 0 through 3 arguments. This is just
1586 * to offer more convenience for the user.
1587 */
1588 static void
makeRangeConstructors(const char * name,Oid namespace,Oid rangeOid,Oid subtype)1589 makeRangeConstructors(const char *name, Oid namespace,
1590 Oid rangeOid, Oid subtype)
1591 {
1592 static const char *const prosrc[2] = {"range_constructor2",
1593 "range_constructor3"};
1594 static const int pronargs[2] = {2, 3};
1595
1596 Oid constructorArgTypes[3];
1597 ObjectAddress myself,
1598 referenced;
1599 int i;
1600
1601 constructorArgTypes[0] = subtype;
1602 constructorArgTypes[1] = subtype;
1603 constructorArgTypes[2] = TEXTOID;
1604
1605 referenced.classId = TypeRelationId;
1606 referenced.objectId = rangeOid;
1607 referenced.objectSubId = 0;
1608
1609 for (i = 0; i < lengthof(prosrc); i++)
1610 {
1611 oidvector *constructorArgTypesVector;
1612
1613 constructorArgTypesVector = buildoidvector(constructorArgTypes,
1614 pronargs[i]);
1615
1616 myself = ProcedureCreate(name, /* name: same as range type */
1617 namespace, /* namespace */
1618 false, /* replace */
1619 false, /* returns set */
1620 rangeOid, /* return type */
1621 BOOTSTRAP_SUPERUSERID, /* proowner */
1622 INTERNALlanguageId, /* language */
1623 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1624 prosrc[i], /* prosrc */
1625 NULL, /* probin */
1626 false, /* isAgg */
1627 false, /* isWindowFunc */
1628 false, /* security_definer */
1629 false, /* leakproof */
1630 false, /* isStrict */
1631 PROVOLATILE_IMMUTABLE, /* volatility */
1632 PROPARALLEL_SAFE, /* parallel safety */
1633 constructorArgTypesVector, /* parameterTypes */
1634 PointerGetDatum(NULL), /* allParameterTypes */
1635 PointerGetDatum(NULL), /* parameterModes */
1636 PointerGetDatum(NULL), /* parameterNames */
1637 NIL, /* parameterDefaults */
1638 PointerGetDatum(NULL), /* trftypes */
1639 PointerGetDatum(NULL), /* proconfig */
1640 1.0, /* procost */
1641 0.0); /* prorows */
1642
1643 /*
1644 * Make the constructors internally-dependent on the range type so
1645 * that they go away silently when the type is dropped. Note that
1646 * pg_dump depends on this choice to avoid dumping the constructors.
1647 */
1648 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1649 }
1650 }
1651
1652
1653 /*
1654 * Find suitable I/O functions for a type.
1655 *
1656 * typeOid is the type's OID (which will already exist, if only as a shell
1657 * type).
1658 */
1659
1660 static Oid
findTypeInputFunction(List * procname,Oid typeOid)1661 findTypeInputFunction(List *procname, Oid typeOid)
1662 {
1663 Oid argList[3];
1664 int nmatches = 0;
1665 Oid procOid;
1666 Oid procOid2;
1667 Oid procOid3;
1668 Oid procOid4;
1669
1670 /*
1671 * Input functions can take a single argument of type CSTRING, or three
1672 * arguments (string, typioparam OID, typmod).
1673 *
1674 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1675 * see this, we issue a warning and fix up the pg_proc entry.
1676 *
1677 * Whine about ambiguity if multiple forms exist.
1678 */
1679 argList[0] = CSTRINGOID;
1680 argList[1] = OIDOID;
1681 argList[2] = INT4OID;
1682
1683 procOid = LookupFuncName(procname, 1, argList, true);
1684 if (OidIsValid(procOid))
1685 nmatches++;
1686 procOid2 = LookupFuncName(procname, 3, argList, true);
1687 if (OidIsValid(procOid2))
1688 nmatches++;
1689
1690 argList[0] = OPAQUEOID;
1691
1692 procOid3 = LookupFuncName(procname, 1, argList, true);
1693 if (OidIsValid(procOid3))
1694 nmatches++;
1695 procOid4 = LookupFuncName(procname, 3, argList, true);
1696 if (OidIsValid(procOid4))
1697 nmatches++;
1698
1699 if (nmatches > 1)
1700 ereport(ERROR,
1701 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
1702 errmsg("type input function %s has multiple matches",
1703 NameListToString(procname))));
1704
1705 if (OidIsValid(procOid))
1706 return procOid;
1707 if (OidIsValid(procOid2))
1708 return procOid2;
1709
1710 /* Cases with OPAQUE need adjustment */
1711 if (OidIsValid(procOid3))
1712 procOid = procOid3;
1713 else
1714 procOid = procOid4;
1715
1716 if (OidIsValid(procOid))
1717 {
1718 /* Found, but must complain and fix the pg_proc entry */
1719 ereport(WARNING,
1720 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1721 NameListToString(procname))));
1722 SetFunctionArgType(procOid, 0, CSTRINGOID);
1723
1724 /*
1725 * Need CommandCounterIncrement since DefineType will likely try to
1726 * alter the pg_proc tuple again.
1727 */
1728 CommandCounterIncrement();
1729
1730 return procOid;
1731 }
1732
1733 /* Use CSTRING (preferred) in the error message */
1734 argList[0] = CSTRINGOID;
1735
1736 ereport(ERROR,
1737 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1738 errmsg("function %s does not exist",
1739 func_signature_string(procname, 1, NIL, argList))));
1740
1741 return InvalidOid; /* keep compiler quiet */
1742 }
1743
1744 static Oid
findTypeOutputFunction(List * procname,Oid typeOid)1745 findTypeOutputFunction(List *procname, Oid typeOid)
1746 {
1747 Oid argList[1];
1748 Oid procOid;
1749
1750 /*
1751 * Output functions can take a single argument of the type.
1752 *
1753 * For backwards compatibility we allow OPAQUE in place of the actual type
1754 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1755 */
1756 argList[0] = typeOid;
1757
1758 procOid = LookupFuncName(procname, 1, argList, true);
1759 if (OidIsValid(procOid))
1760 return procOid;
1761
1762 /* No luck, try it with OPAQUE */
1763 argList[0] = OPAQUEOID;
1764
1765 procOid = LookupFuncName(procname, 1, argList, true);
1766
1767 if (OidIsValid(procOid))
1768 {
1769 /* Found, but must complain and fix the pg_proc entry */
1770 ereport(WARNING,
1771 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1772 NameListToString(procname), format_type_be(typeOid))));
1773 SetFunctionArgType(procOid, 0, typeOid);
1774
1775 /*
1776 * Need CommandCounterIncrement since DefineType will likely try to
1777 * alter the pg_proc tuple again.
1778 */
1779 CommandCounterIncrement();
1780
1781 return procOid;
1782 }
1783
1784 /* Use type name, not OPAQUE, in the failure message. */
1785 argList[0] = typeOid;
1786
1787 ereport(ERROR,
1788 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1789 errmsg("function %s does not exist",
1790 func_signature_string(procname, 1, NIL, argList))));
1791
1792 return InvalidOid; /* keep compiler quiet */
1793 }
1794
1795 static Oid
findTypeReceiveFunction(List * procname,Oid typeOid)1796 findTypeReceiveFunction(List *procname, Oid typeOid)
1797 {
1798 Oid argList[3];
1799 Oid procOid;
1800 Oid procOid2;
1801
1802 /*
1803 * Receive functions can take a single argument of type INTERNAL, or three
1804 * arguments (internal, typioparam OID, typmod). Whine about ambiguity if
1805 * both forms exist.
1806 */
1807 argList[0] = INTERNALOID;
1808 argList[1] = OIDOID;
1809 argList[2] = INT4OID;
1810
1811 procOid = LookupFuncName(procname, 1, argList, true);
1812 procOid2 = LookupFuncName(procname, 3, argList, true);
1813 if (OidIsValid(procOid))
1814 {
1815 if (OidIsValid(procOid2))
1816 ereport(ERROR,
1817 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
1818 errmsg("type receive function %s has multiple matches",
1819 NameListToString(procname))));
1820 return procOid;
1821 }
1822 else if (OidIsValid(procOid2))
1823 return procOid2;
1824
1825 /* If not found, reference the 1-argument signature in error msg */
1826 ereport(ERROR,
1827 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1828 errmsg("function %s does not exist",
1829 func_signature_string(procname, 1, NIL, argList))));
1830
1831 return InvalidOid; /* keep compiler quiet */
1832 }
1833
1834 static Oid
findTypeSendFunction(List * procname,Oid typeOid)1835 findTypeSendFunction(List *procname, Oid typeOid)
1836 {
1837 Oid argList[1];
1838 Oid procOid;
1839
1840 /*
1841 * Send functions can take a single argument of the type.
1842 */
1843 argList[0] = typeOid;
1844
1845 procOid = LookupFuncName(procname, 1, argList, true);
1846 if (OidIsValid(procOid))
1847 return procOid;
1848
1849 ereport(ERROR,
1850 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1851 errmsg("function %s does not exist",
1852 func_signature_string(procname, 1, NIL, argList))));
1853
1854 return InvalidOid; /* keep compiler quiet */
1855 }
1856
1857 static Oid
findTypeTypmodinFunction(List * procname)1858 findTypeTypmodinFunction(List *procname)
1859 {
1860 Oid argList[1];
1861 Oid procOid;
1862
1863 /*
1864 * typmodin functions always take one cstring[] argument and return int4.
1865 */
1866 argList[0] = CSTRINGARRAYOID;
1867
1868 procOid = LookupFuncName(procname, 1, argList, true);
1869 if (!OidIsValid(procOid))
1870 ereport(ERROR,
1871 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1872 errmsg("function %s does not exist",
1873 func_signature_string(procname, 1, NIL, argList))));
1874
1875 if (get_func_rettype(procOid) != INT4OID)
1876 ereport(ERROR,
1877 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1878 errmsg("typmod_in function %s must return type %s",
1879 NameListToString(procname), "integer")));
1880
1881 return procOid;
1882 }
1883
1884 static Oid
findTypeTypmodoutFunction(List * procname)1885 findTypeTypmodoutFunction(List *procname)
1886 {
1887 Oid argList[1];
1888 Oid procOid;
1889
1890 /*
1891 * typmodout functions always take one int4 argument and return cstring.
1892 */
1893 argList[0] = INT4OID;
1894
1895 procOid = LookupFuncName(procname, 1, argList, true);
1896 if (!OidIsValid(procOid))
1897 ereport(ERROR,
1898 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1899 errmsg("function %s does not exist",
1900 func_signature_string(procname, 1, NIL, argList))));
1901
1902 if (get_func_rettype(procOid) != CSTRINGOID)
1903 ereport(ERROR,
1904 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1905 errmsg("typmod_out function %s must return type %s",
1906 NameListToString(procname), "cstring")));
1907
1908 return procOid;
1909 }
1910
1911 static Oid
findTypeAnalyzeFunction(List * procname,Oid typeOid)1912 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1913 {
1914 Oid argList[1];
1915 Oid procOid;
1916
1917 /*
1918 * Analyze functions always take one INTERNAL argument and return bool.
1919 */
1920 argList[0] = INTERNALOID;
1921
1922 procOid = LookupFuncName(procname, 1, argList, true);
1923 if (!OidIsValid(procOid))
1924 ereport(ERROR,
1925 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1926 errmsg("function %s does not exist",
1927 func_signature_string(procname, 1, NIL, argList))));
1928
1929 if (get_func_rettype(procOid) != BOOLOID)
1930 ereport(ERROR,
1931 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1932 errmsg("type analyze function %s must return type %s",
1933 NameListToString(procname), "boolean")));
1934
1935 return procOid;
1936 }
1937
1938 /*
1939 * Find suitable support functions and opclasses for a range type.
1940 */
1941
1942 /*
1943 * Find named btree opclass for subtype, or default btree opclass if
1944 * opcname is NIL.
1945 */
1946 static Oid
findRangeSubOpclass(List * opcname,Oid subtype)1947 findRangeSubOpclass(List *opcname, Oid subtype)
1948 {
1949 Oid opcid;
1950 Oid opInputType;
1951
1952 if (opcname != NIL)
1953 {
1954 opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
1955
1956 /*
1957 * Verify that the operator class accepts this datatype. Note we will
1958 * accept binary compatibility.
1959 */
1960 opInputType = get_opclass_input_type(opcid);
1961 if (!IsBinaryCoercible(subtype, opInputType))
1962 ereport(ERROR,
1963 (errcode(ERRCODE_DATATYPE_MISMATCH),
1964 errmsg("operator class \"%s\" does not accept data type %s",
1965 NameListToString(opcname),
1966 format_type_be(subtype))));
1967 }
1968 else
1969 {
1970 opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
1971 if (!OidIsValid(opcid))
1972 {
1973 /* We spell the error message identically to GetIndexOpClass */
1974 ereport(ERROR,
1975 (errcode(ERRCODE_UNDEFINED_OBJECT),
1976 errmsg("data type %s has no default operator class for access method \"%s\"",
1977 format_type_be(subtype), "btree"),
1978 errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
1979 }
1980 }
1981
1982 return opcid;
1983 }
1984
1985 static Oid
findRangeCanonicalFunction(List * procname,Oid typeOid)1986 findRangeCanonicalFunction(List *procname, Oid typeOid)
1987 {
1988 Oid argList[1];
1989 Oid procOid;
1990 AclResult aclresult;
1991
1992 /*
1993 * Range canonical functions must take and return the range type, and must
1994 * be immutable.
1995 */
1996 argList[0] = typeOid;
1997
1998 procOid = LookupFuncName(procname, 1, argList, true);
1999
2000 if (!OidIsValid(procOid))
2001 ereport(ERROR,
2002 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2003 errmsg("function %s does not exist",
2004 func_signature_string(procname, 1, NIL, argList))));
2005
2006 if (get_func_rettype(procOid) != typeOid)
2007 ereport(ERROR,
2008 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2009 errmsg("range canonical function %s must return range type",
2010 func_signature_string(procname, 1, NIL, argList))));
2011
2012 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2013 ereport(ERROR,
2014 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2015 errmsg("range canonical function %s must be immutable",
2016 func_signature_string(procname, 1, NIL, argList))));
2017
2018 /* Also, range type's creator must have permission to call function */
2019 aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
2020 if (aclresult != ACLCHECK_OK)
2021 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
2022
2023 return procOid;
2024 }
2025
2026 static Oid
findRangeSubtypeDiffFunction(List * procname,Oid subtype)2027 findRangeSubtypeDiffFunction(List *procname, Oid subtype)
2028 {
2029 Oid argList[2];
2030 Oid procOid;
2031 AclResult aclresult;
2032
2033 /*
2034 * Range subtype diff functions must take two arguments of the subtype,
2035 * must return float8, and must be immutable.
2036 */
2037 argList[0] = subtype;
2038 argList[1] = subtype;
2039
2040 procOid = LookupFuncName(procname, 2, argList, true);
2041
2042 if (!OidIsValid(procOid))
2043 ereport(ERROR,
2044 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2045 errmsg("function %s does not exist",
2046 func_signature_string(procname, 2, NIL, argList))));
2047
2048 if (get_func_rettype(procOid) != FLOAT8OID)
2049 ereport(ERROR,
2050 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2051 errmsg("range subtype diff function %s must return type %s",
2052 func_signature_string(procname, 2, NIL, argList),
2053 "double precision")));
2054
2055 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2056 ereport(ERROR,
2057 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2058 errmsg("range subtype diff function %s must be immutable",
2059 func_signature_string(procname, 2, NIL, argList))));
2060
2061 /* Also, range type's creator must have permission to call function */
2062 aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
2063 if (aclresult != ACLCHECK_OK)
2064 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
2065
2066 return procOid;
2067 }
2068
2069 /*
2070 * AssignTypeArrayOid
2071 *
2072 * Pre-assign the type's array OID for use in pg_type.typarray
2073 */
2074 Oid
AssignTypeArrayOid(void)2075 AssignTypeArrayOid(void)
2076 {
2077 Oid type_array_oid;
2078
2079 /* Use binary-upgrade override for pg_type.typarray? */
2080 if (IsBinaryUpgrade)
2081 {
2082 if (!OidIsValid(binary_upgrade_next_array_pg_type_oid))
2083 ereport(ERROR,
2084 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2085 errmsg("pg_type array OID value not set when in binary upgrade mode")));
2086
2087 type_array_oid = binary_upgrade_next_array_pg_type_oid;
2088 binary_upgrade_next_array_pg_type_oid = InvalidOid;
2089 }
2090 else
2091 {
2092 Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
2093
2094 type_array_oid = GetNewOid(pg_type);
2095 heap_close(pg_type, AccessShareLock);
2096 }
2097
2098 return type_array_oid;
2099 }
2100
2101
2102 /*-------------------------------------------------------------------
2103 * DefineCompositeType
2104 *
2105 * Create a Composite Type relation.
2106 * `DefineRelation' does all the work, we just provide the correct
2107 * arguments!
2108 *
2109 * If the relation already exists, then 'DefineRelation' will abort
2110 * the xact...
2111 *
2112 * Return type is the new type's object address.
2113 *-------------------------------------------------------------------
2114 */
2115 ObjectAddress
DefineCompositeType(RangeVar * typevar,List * coldeflist)2116 DefineCompositeType(RangeVar *typevar, List *coldeflist)
2117 {
2118 CreateStmt *createStmt = makeNode(CreateStmt);
2119 Oid old_type_oid;
2120 Oid typeNamespace;
2121 ObjectAddress address;
2122
2123 /*
2124 * now set the parameters for keys/inheritance etc. All of these are
2125 * uninteresting for composite types...
2126 */
2127 createStmt->relation = typevar;
2128 createStmt->tableElts = coldeflist;
2129 createStmt->inhRelations = NIL;
2130 createStmt->constraints = NIL;
2131 createStmt->options = NIL;
2132 createStmt->oncommit = ONCOMMIT_NOOP;
2133 createStmt->tablespacename = NULL;
2134 createStmt->if_not_exists = false;
2135
2136 /*
2137 * Check for collision with an existing type name. If there is one and
2138 * it's an autogenerated array, we can rename it out of the way. This
2139 * check is here mainly to get a better error message about a "type"
2140 * instead of below about a "relation".
2141 */
2142 typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2143 NoLock, NULL);
2144 RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2145 old_type_oid =
2146 GetSysCacheOid2(TYPENAMENSP,
2147 CStringGetDatum(createStmt->relation->relname),
2148 ObjectIdGetDatum(typeNamespace));
2149 if (OidIsValid(old_type_oid))
2150 {
2151 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2152 ereport(ERROR,
2153 (errcode(ERRCODE_DUPLICATE_OBJECT),
2154 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2155 }
2156
2157 /*
2158 * Finally create the relation. This also creates the type.
2159 */
2160 DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2161 NULL);
2162
2163 return address;
2164 }
2165
2166 /*
2167 * AlterDomainDefault
2168 *
2169 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
2170 *
2171 * Returns ObjectAddress of the modified domain.
2172 */
2173 ObjectAddress
AlterDomainDefault(List * names,Node * defaultRaw)2174 AlterDomainDefault(List *names, Node *defaultRaw)
2175 {
2176 TypeName *typename;
2177 Oid domainoid;
2178 HeapTuple tup;
2179 ParseState *pstate;
2180 Relation rel;
2181 char *defaultValue;
2182 Node *defaultExpr = NULL; /* NULL if no default specified */
2183 Acl *typacl;
2184 Datum aclDatum;
2185 bool isNull;
2186 Datum new_record[Natts_pg_type];
2187 bool new_record_nulls[Natts_pg_type];
2188 bool new_record_repl[Natts_pg_type];
2189 HeapTuple newtuple;
2190 Form_pg_type typTup;
2191 ObjectAddress address;
2192
2193 /* Make a TypeName so we can use standard type lookup machinery */
2194 typename = makeTypeNameFromNameList(names);
2195 domainoid = typenameTypeId(NULL, typename);
2196
2197 /* Look up the domain in the type table */
2198 rel = heap_open(TypeRelationId, RowExclusiveLock);
2199
2200 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2201 if (!HeapTupleIsValid(tup))
2202 elog(ERROR, "cache lookup failed for type %u", domainoid);
2203 typTup = (Form_pg_type) GETSTRUCT(tup);
2204
2205 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2206 checkDomainOwner(tup);
2207
2208 /* Setup new tuple */
2209 MemSet(new_record, (Datum) 0, sizeof(new_record));
2210 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2211 MemSet(new_record_repl, false, sizeof(new_record_repl));
2212
2213 /* Store the new default into the tuple */
2214 if (defaultRaw)
2215 {
2216 /* Create a dummy ParseState for transformExpr */
2217 pstate = make_parsestate(NULL);
2218
2219 /*
2220 * Cook the raw default into an expression; copy it in case the input
2221 * is in plan cache. Note: name is used only for error messages.
2222 */
2223 defaultExpr = cookDefault(pstate, copyObject(defaultRaw),
2224 typTup->typbasetype,
2225 typTup->typtypmod,
2226 NameStr(typTup->typname));
2227
2228 /*
2229 * If the expression is just a NULL constant, we treat the command
2230 * like ALTER ... DROP DEFAULT. (But see note for same test in
2231 * DefineDomain.)
2232 */
2233 if (defaultExpr == NULL ||
2234 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
2235 {
2236 /* Default is NULL, drop it */
2237 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2238 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2239 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2240 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2241 }
2242 else
2243 {
2244 /*
2245 * Expression must be stored as a nodeToString result, but we also
2246 * require a valid textual representation (mainly to make life
2247 * easier for pg_dump).
2248 */
2249 defaultValue = deparse_expression(defaultExpr,
2250 NIL, false, false);
2251
2252 /*
2253 * Form an updated tuple with the new default and write it back.
2254 */
2255 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2256
2257 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2258 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2259 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2260 }
2261 }
2262 else
2263 {
2264 /* ALTER ... DROP DEFAULT */
2265 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2266 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2267 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2268 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2269 }
2270
2271 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2272 new_record, new_record_nulls,
2273 new_record_repl);
2274
2275 CatalogTupleUpdate(rel, &tup->t_self, newtuple);
2276
2277 /* Must extract ACL for use of GenerateTypeDependencies */
2278 aclDatum = heap_getattr(newtuple, Anum_pg_type_typacl,
2279 RelationGetDescr(rel), &isNull);
2280 if (isNull)
2281 typacl = NULL;
2282 else
2283 typacl = DatumGetAclPCopy(aclDatum);
2284
2285 /* Rebuild dependencies */
2286 GenerateTypeDependencies(domainoid,
2287 (Form_pg_type) GETSTRUCT(newtuple),
2288 defaultExpr,
2289 typacl,
2290 0, /* relation kind is n/a */
2291 false, /* a domain isn't an implicit array */
2292 false, /* nor is it any kind of dependent type */
2293 true); /* We do need to rebuild dependencies */
2294
2295 InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2296
2297 ObjectAddressSet(address, TypeRelationId, domainoid);
2298
2299 /* Clean up */
2300 heap_close(rel, NoLock);
2301 heap_freetuple(newtuple);
2302
2303 return address;
2304 }
2305
2306 /*
2307 * AlterDomainNotNull
2308 *
2309 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2310 *
2311 * Returns ObjectAddress of the modified domain.
2312 */
2313 ObjectAddress
AlterDomainNotNull(List * names,bool notNull)2314 AlterDomainNotNull(List *names, bool notNull)
2315 {
2316 TypeName *typename;
2317 Oid domainoid;
2318 Relation typrel;
2319 HeapTuple tup;
2320 Form_pg_type typTup;
2321 ObjectAddress address = InvalidObjectAddress;
2322
2323 /* Make a TypeName so we can use standard type lookup machinery */
2324 typename = makeTypeNameFromNameList(names);
2325 domainoid = typenameTypeId(NULL, typename);
2326
2327 /* Look up the domain in the type table */
2328 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2329
2330 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2331 if (!HeapTupleIsValid(tup))
2332 elog(ERROR, "cache lookup failed for type %u", domainoid);
2333 typTup = (Form_pg_type) GETSTRUCT(tup);
2334
2335 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2336 checkDomainOwner(tup);
2337
2338 /* Is the domain already set to the desired constraint? */
2339 if (typTup->typnotnull == notNull)
2340 {
2341 heap_close(typrel, RowExclusiveLock);
2342 return address;
2343 }
2344
2345 /* Adding a NOT NULL constraint requires checking existing columns */
2346 if (notNull)
2347 {
2348 List *rels;
2349 ListCell *rt;
2350
2351 /* Fetch relation list with attributes based on this domain */
2352 /* ShareLock is sufficient to prevent concurrent data changes */
2353
2354 rels = get_rels_with_domain(domainoid, ShareLock);
2355
2356 foreach(rt, rels)
2357 {
2358 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2359 Relation testrel = rtc->rel;
2360 TupleDesc tupdesc = RelationGetDescr(testrel);
2361 HeapScanDesc scan;
2362 HeapTuple tuple;
2363 Snapshot snapshot;
2364
2365 /* Scan all tuples in this relation */
2366 snapshot = RegisterSnapshot(GetLatestSnapshot());
2367 scan = heap_beginscan(testrel, snapshot, 0, NULL);
2368 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2369 {
2370 int i;
2371
2372 /* Test attributes that are of the domain */
2373 for (i = 0; i < rtc->natts; i++)
2374 {
2375 int attnum = rtc->atts[i];
2376
2377 if (heap_attisnull(tuple, attnum))
2378 {
2379 /*
2380 * In principle the auxiliary information for this
2381 * error should be errdatatype(), but errtablecol()
2382 * seems considerably more useful in practice. Since
2383 * this code only executes in an ALTER DOMAIN command,
2384 * the client should already know which domain is in
2385 * question.
2386 */
2387 ereport(ERROR,
2388 (errcode(ERRCODE_NOT_NULL_VIOLATION),
2389 errmsg("column \"%s\" of table \"%s\" contains null values",
2390 NameStr(tupdesc->attrs[attnum - 1]->attname),
2391 RelationGetRelationName(testrel)),
2392 errtablecol(testrel, attnum)));
2393 }
2394 }
2395 }
2396 heap_endscan(scan);
2397 UnregisterSnapshot(snapshot);
2398
2399 /* Close each rel after processing, but keep lock */
2400 heap_close(testrel, NoLock);
2401 }
2402 }
2403
2404 /*
2405 * Okay to update pg_type row. We can scribble on typTup because it's a
2406 * copy.
2407 */
2408 typTup->typnotnull = notNull;
2409
2410 CatalogTupleUpdate(typrel, &tup->t_self, tup);
2411
2412 InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2413
2414 ObjectAddressSet(address, TypeRelationId, domainoid);
2415
2416 /* Clean up */
2417 heap_freetuple(tup);
2418 heap_close(typrel, RowExclusiveLock);
2419
2420 return address;
2421 }
2422
2423 /*
2424 * AlterDomainDropConstraint
2425 *
2426 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2427 */
2428 ObjectAddress
AlterDomainDropConstraint(List * names,const char * constrName,DropBehavior behavior,bool missing_ok)2429 AlterDomainDropConstraint(List *names, const char *constrName,
2430 DropBehavior behavior, bool missing_ok)
2431 {
2432 TypeName *typename;
2433 Oid domainoid;
2434 HeapTuple tup;
2435 Relation rel;
2436 Relation conrel;
2437 SysScanDesc conscan;
2438 ScanKeyData key[1];
2439 HeapTuple contup;
2440 bool found = false;
2441 ObjectAddress address = InvalidObjectAddress;
2442
2443 /* Make a TypeName so we can use standard type lookup machinery */
2444 typename = makeTypeNameFromNameList(names);
2445 domainoid = typenameTypeId(NULL, typename);
2446
2447 /* Look up the domain in the type table */
2448 rel = heap_open(TypeRelationId, RowExclusiveLock);
2449
2450 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2451 if (!HeapTupleIsValid(tup))
2452 elog(ERROR, "cache lookup failed for type %u", domainoid);
2453
2454 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2455 checkDomainOwner(tup);
2456
2457 /* Grab an appropriate lock on the pg_constraint relation */
2458 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2459
2460 /* Use the index to scan only constraints of the target relation */
2461 ScanKeyInit(&key[0],
2462 Anum_pg_constraint_contypid,
2463 BTEqualStrategyNumber, F_OIDEQ,
2464 ObjectIdGetDatum(HeapTupleGetOid(tup)));
2465
2466 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2467 NULL, 1, key);
2468
2469 /*
2470 * Scan over the result set, removing any matching entries.
2471 */
2472 while ((contup = systable_getnext(conscan)) != NULL)
2473 {
2474 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
2475
2476 if (strcmp(NameStr(con->conname), constrName) == 0)
2477 {
2478 ObjectAddress conobj;
2479
2480 conobj.classId = ConstraintRelationId;
2481 conobj.objectId = HeapTupleGetOid(contup);
2482 conobj.objectSubId = 0;
2483
2484 performDeletion(&conobj, behavior, 0);
2485 found = true;
2486 }
2487 }
2488
2489 ObjectAddressSet(address, TypeRelationId, domainoid);
2490
2491 /* Clean up after the scan */
2492 systable_endscan(conscan);
2493 heap_close(conrel, RowExclusiveLock);
2494
2495 heap_close(rel, NoLock);
2496
2497 if (!found)
2498 {
2499 if (!missing_ok)
2500 ereport(ERROR,
2501 (errcode(ERRCODE_UNDEFINED_OBJECT),
2502 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2503 constrName, TypeNameToString(typename))));
2504 else
2505 ereport(NOTICE,
2506 (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2507 constrName, TypeNameToString(typename))));
2508 }
2509
2510 return address;
2511 }
2512
2513 /*
2514 * AlterDomainAddConstraint
2515 *
2516 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2517 */
2518 ObjectAddress
AlterDomainAddConstraint(List * names,Node * newConstraint,ObjectAddress * constrAddr)2519 AlterDomainAddConstraint(List *names, Node *newConstraint,
2520 ObjectAddress *constrAddr)
2521 {
2522 TypeName *typename;
2523 Oid domainoid;
2524 Relation typrel;
2525 HeapTuple tup;
2526 Form_pg_type typTup;
2527 Constraint *constr;
2528 char *ccbin;
2529 ObjectAddress address;
2530
2531 /* Make a TypeName so we can use standard type lookup machinery */
2532 typename = makeTypeNameFromNameList(names);
2533 domainoid = typenameTypeId(NULL, typename);
2534
2535 /* Look up the domain in the type table */
2536 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2537
2538 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2539 if (!HeapTupleIsValid(tup))
2540 elog(ERROR, "cache lookup failed for type %u", domainoid);
2541 typTup = (Form_pg_type) GETSTRUCT(tup);
2542
2543 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2544 checkDomainOwner(tup);
2545
2546 if (!IsA(newConstraint, Constraint))
2547 elog(ERROR, "unrecognized node type: %d",
2548 (int) nodeTag(newConstraint));
2549
2550 constr = (Constraint *) newConstraint;
2551
2552 switch (constr->contype)
2553 {
2554 case CONSTR_CHECK:
2555 /* processed below */
2556 break;
2557
2558 case CONSTR_UNIQUE:
2559 ereport(ERROR,
2560 (errcode(ERRCODE_SYNTAX_ERROR),
2561 errmsg("unique constraints not possible for domains")));
2562 break;
2563
2564 case CONSTR_PRIMARY:
2565 ereport(ERROR,
2566 (errcode(ERRCODE_SYNTAX_ERROR),
2567 errmsg("primary key constraints not possible for domains")));
2568 break;
2569
2570 case CONSTR_EXCLUSION:
2571 ereport(ERROR,
2572 (errcode(ERRCODE_SYNTAX_ERROR),
2573 errmsg("exclusion constraints not possible for domains")));
2574 break;
2575
2576 case CONSTR_FOREIGN:
2577 ereport(ERROR,
2578 (errcode(ERRCODE_SYNTAX_ERROR),
2579 errmsg("foreign key constraints not possible for domains")));
2580 break;
2581
2582 case CONSTR_ATTR_DEFERRABLE:
2583 case CONSTR_ATTR_NOT_DEFERRABLE:
2584 case CONSTR_ATTR_DEFERRED:
2585 case CONSTR_ATTR_IMMEDIATE:
2586 ereport(ERROR,
2587 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2588 errmsg("specifying constraint deferrability not supported for domains")));
2589 break;
2590
2591 default:
2592 elog(ERROR, "unrecognized constraint subtype: %d",
2593 (int) constr->contype);
2594 break;
2595 }
2596
2597 /*
2598 * Since all other constraint types throw errors, this must be a check
2599 * constraint. First, process the constraint expression and add an entry
2600 * to pg_constraint.
2601 */
2602
2603 ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
2604 typTup->typbasetype, typTup->typtypmod,
2605 constr, NameStr(typTup->typname), constrAddr);
2606
2607 /*
2608 * If requested to validate the constraint, test all values stored in the
2609 * attributes based on the domain the constraint is being added to.
2610 */
2611 if (!constr->skip_validation)
2612 validateDomainConstraint(domainoid, ccbin);
2613
2614 ObjectAddressSet(address, TypeRelationId, domainoid);
2615
2616 /* Clean up */
2617 heap_close(typrel, RowExclusiveLock);
2618
2619 return address;
2620 }
2621
2622 /*
2623 * AlterDomainValidateConstraint
2624 *
2625 * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
2626 */
2627 ObjectAddress
AlterDomainValidateConstraint(List * names,char * constrName)2628 AlterDomainValidateConstraint(List *names, char *constrName)
2629 {
2630 TypeName *typename;
2631 Oid domainoid;
2632 Relation typrel;
2633 Relation conrel;
2634 HeapTuple tup;
2635 Form_pg_constraint con = NULL;
2636 Form_pg_constraint copy_con;
2637 char *conbin;
2638 SysScanDesc scan;
2639 Datum val;
2640 bool found = false;
2641 bool isnull;
2642 HeapTuple tuple;
2643 HeapTuple copyTuple;
2644 ScanKeyData key;
2645 ObjectAddress address;
2646
2647 /* Make a TypeName so we can use standard type lookup machinery */
2648 typename = makeTypeNameFromNameList(names);
2649 domainoid = typenameTypeId(NULL, typename);
2650
2651 /* Look up the domain in the type table */
2652 typrel = heap_open(TypeRelationId, AccessShareLock);
2653
2654 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2655 if (!HeapTupleIsValid(tup))
2656 elog(ERROR, "cache lookup failed for type %u", domainoid);
2657
2658 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2659 checkDomainOwner(tup);
2660
2661 /*
2662 * Find and check the target constraint
2663 */
2664 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2665 ScanKeyInit(&key,
2666 Anum_pg_constraint_contypid,
2667 BTEqualStrategyNumber, F_OIDEQ,
2668 ObjectIdGetDatum(domainoid));
2669 scan = systable_beginscan(conrel, ConstraintTypidIndexId,
2670 true, NULL, 1, &key);
2671
2672 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2673 {
2674 con = (Form_pg_constraint) GETSTRUCT(tuple);
2675 if (strcmp(NameStr(con->conname), constrName) == 0)
2676 {
2677 found = true;
2678 break;
2679 }
2680 }
2681
2682 if (!found)
2683 ereport(ERROR,
2684 (errcode(ERRCODE_UNDEFINED_OBJECT),
2685 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2686 constrName, TypeNameToString(typename))));
2687
2688 if (con->contype != CONSTRAINT_CHECK)
2689 ereport(ERROR,
2690 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2691 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2692 constrName, TypeNameToString(typename))));
2693
2694 val = SysCacheGetAttr(CONSTROID, tuple,
2695 Anum_pg_constraint_conbin,
2696 &isnull);
2697 if (isnull)
2698 elog(ERROR, "null conbin for constraint %u",
2699 HeapTupleGetOid(tuple));
2700 conbin = TextDatumGetCString(val);
2701
2702 validateDomainConstraint(domainoid, conbin);
2703
2704 /*
2705 * Now update the catalog, while we have the door open.
2706 */
2707 copyTuple = heap_copytuple(tuple);
2708 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2709 copy_con->convalidated = true;
2710 CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple);
2711
2712 InvokeObjectPostAlterHook(ConstraintRelationId,
2713 HeapTupleGetOid(copyTuple), 0);
2714
2715 ObjectAddressSet(address, TypeRelationId, domainoid);
2716
2717 heap_freetuple(copyTuple);
2718
2719 systable_endscan(scan);
2720
2721 heap_close(typrel, AccessShareLock);
2722 heap_close(conrel, RowExclusiveLock);
2723
2724 ReleaseSysCache(tup);
2725
2726 return address;
2727 }
2728
2729 static void
validateDomainConstraint(Oid domainoid,char * ccbin)2730 validateDomainConstraint(Oid domainoid, char *ccbin)
2731 {
2732 Expr *expr = (Expr *) stringToNode(ccbin);
2733 List *rels;
2734 ListCell *rt;
2735 EState *estate;
2736 ExprContext *econtext;
2737 ExprState *exprstate;
2738
2739 /* Need an EState to run ExecEvalExpr */
2740 estate = CreateExecutorState();
2741 econtext = GetPerTupleExprContext(estate);
2742
2743 /* build execution state for expr */
2744 exprstate = ExecPrepareExpr(expr, estate);
2745
2746 /* Fetch relation list with attributes based on this domain */
2747 /* ShareLock is sufficient to prevent concurrent data changes */
2748
2749 rels = get_rels_with_domain(domainoid, ShareLock);
2750
2751 foreach(rt, rels)
2752 {
2753 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2754 Relation testrel = rtc->rel;
2755 TupleDesc tupdesc = RelationGetDescr(testrel);
2756 HeapScanDesc scan;
2757 HeapTuple tuple;
2758 Snapshot snapshot;
2759
2760 /* Scan all tuples in this relation */
2761 snapshot = RegisterSnapshot(GetLatestSnapshot());
2762 scan = heap_beginscan(testrel, snapshot, 0, NULL);
2763 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2764 {
2765 int i;
2766
2767 /* Test attributes that are of the domain */
2768 for (i = 0; i < rtc->natts; i++)
2769 {
2770 int attnum = rtc->atts[i];
2771 Datum d;
2772 bool isNull;
2773 Datum conResult;
2774
2775 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2776
2777 econtext->domainValue_datum = d;
2778 econtext->domainValue_isNull = isNull;
2779
2780 conResult = ExecEvalExprSwitchContext(exprstate,
2781 econtext,
2782 &isNull);
2783
2784 if (!isNull && !DatumGetBool(conResult))
2785 {
2786 /*
2787 * In principle the auxiliary information for this error
2788 * should be errdomainconstraint(), but errtablecol()
2789 * seems considerably more useful in practice. Since this
2790 * code only executes in an ALTER DOMAIN command, the
2791 * client should already know which domain is in question,
2792 * and which constraint too.
2793 */
2794 ereport(ERROR,
2795 (errcode(ERRCODE_CHECK_VIOLATION),
2796 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2797 NameStr(tupdesc->attrs[attnum - 1]->attname),
2798 RelationGetRelationName(testrel)),
2799 errtablecol(testrel, attnum)));
2800 }
2801 }
2802
2803 ResetExprContext(econtext);
2804 }
2805 heap_endscan(scan);
2806 UnregisterSnapshot(snapshot);
2807
2808 /* Hold relation lock till commit (XXX bad for concurrency) */
2809 heap_close(testrel, NoLock);
2810 }
2811
2812 FreeExecutorState(estate);
2813 }
2814
2815 /*
2816 * get_rels_with_domain
2817 *
2818 * Fetch all relations / attributes which are using the domain
2819 *
2820 * The result is a list of RelToCheck structs, one for each distinct
2821 * relation, each containing one or more attribute numbers that are of
2822 * the domain type. We have opened each rel and acquired the specified lock
2823 * type on it.
2824 *
2825 * We support nested domains by including attributes that are of derived
2826 * domain types. Current callers do not need to distinguish between attributes
2827 * that are of exactly the given domain and those that are of derived domains.
2828 *
2829 * XXX this is completely broken because there is no way to lock the domain
2830 * to prevent columns from being added or dropped while our command runs.
2831 * We can partially protect against column drops by locking relations as we
2832 * come across them, but there is still a race condition (the window between
2833 * seeing a pg_depend entry and acquiring lock on the relation it references).
2834 * Also, holding locks on all these relations simultaneously creates a non-
2835 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2836 * risk by using the weakest suitable lock (ShareLock for most callers).
2837 *
2838 * XXX the API for this is not sufficient to support checking domain values
2839 * that are inside container types, such as composite types, arrays, or
2840 * ranges. Currently we just error out if a container type containing the
2841 * target domain is stored anywhere.
2842 *
2843 * Generally used for retrieving a list of tests when adding
2844 * new constraints to a domain.
2845 */
2846 static List *
get_rels_with_domain(Oid domainOid,LOCKMODE lockmode)2847 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2848 {
2849 List *result = NIL;
2850 char *domainTypeName = format_type_be(domainOid);
2851 Relation depRel;
2852 ScanKeyData key[2];
2853 SysScanDesc depScan;
2854 HeapTuple depTup;
2855
2856 Assert(lockmode != NoLock);
2857
2858 /* since this function recurses, it could be driven to stack overflow */
2859 check_stack_depth();
2860
2861 /*
2862 * We scan pg_depend to find those things that depend on the domain. (We
2863 * assume we can ignore refobjsubid for a domain.)
2864 */
2865 depRel = heap_open(DependRelationId, AccessShareLock);
2866
2867 ScanKeyInit(&key[0],
2868 Anum_pg_depend_refclassid,
2869 BTEqualStrategyNumber, F_OIDEQ,
2870 ObjectIdGetDatum(TypeRelationId));
2871 ScanKeyInit(&key[1],
2872 Anum_pg_depend_refobjid,
2873 BTEqualStrategyNumber, F_OIDEQ,
2874 ObjectIdGetDatum(domainOid));
2875
2876 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2877 NULL, 2, key);
2878
2879 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2880 {
2881 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2882 RelToCheck *rtc = NULL;
2883 ListCell *rellist;
2884 Form_pg_attribute pg_att;
2885 int ptr;
2886
2887 /* Check for directly dependent types */
2888 if (pg_depend->classid == TypeRelationId)
2889 {
2890 if (get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN)
2891 {
2892 /*
2893 * This is a sub-domain, so recursively add dependent columns
2894 * to the output list. This is a bit inefficient since we may
2895 * fail to combine RelToCheck entries when attributes of the
2896 * same rel have different derived domain types, but it's
2897 * probably not worth improving.
2898 */
2899 result = list_concat(result,
2900 get_rels_with_domain(pg_depend->objid,
2901 lockmode));
2902 }
2903 else
2904 {
2905 /*
2906 * Otherwise, it is some container type using the domain, so
2907 * fail if there are any columns of this type.
2908 */
2909 find_composite_type_dependencies(pg_depend->objid,
2910 NULL,
2911 domainTypeName);
2912 }
2913 continue;
2914 }
2915
2916 /* Else, ignore dependees that aren't user columns of relations */
2917 /* (we assume system columns are never of domain types) */
2918 if (pg_depend->classid != RelationRelationId ||
2919 pg_depend->objsubid <= 0)
2920 continue;
2921
2922 /* See if we already have an entry for this relation */
2923 foreach(rellist, result)
2924 {
2925 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2926
2927 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2928 {
2929 rtc = rt;
2930 break;
2931 }
2932 }
2933
2934 if (rtc == NULL)
2935 {
2936 /* First attribute found for this relation */
2937 Relation rel;
2938
2939 /* Acquire requested lock on relation */
2940 rel = relation_open(pg_depend->objid, lockmode);
2941
2942 /*
2943 * Check to see if rowtype is stored anyplace as a composite-type
2944 * column; if so we have to fail, for now anyway.
2945 */
2946 if (OidIsValid(rel->rd_rel->reltype))
2947 find_composite_type_dependencies(rel->rd_rel->reltype,
2948 NULL,
2949 domainTypeName);
2950
2951 /*
2952 * Otherwise, we can ignore relations except those with both
2953 * storage and user-chosen column types.
2954 *
2955 * XXX If an index-only scan could satisfy "col::some_domain" from
2956 * a suitable expression index, this should also check expression
2957 * index columns.
2958 */
2959 if (rel->rd_rel->relkind != RELKIND_RELATION &&
2960 rel->rd_rel->relkind != RELKIND_MATVIEW)
2961 {
2962 relation_close(rel, lockmode);
2963 continue;
2964 }
2965
2966 /* Build the RelToCheck entry with enough space for all atts */
2967 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2968 rtc->rel = rel;
2969 rtc->natts = 0;
2970 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2971 result = lcons(rtc, result);
2972 }
2973
2974 /*
2975 * Confirm column has not been dropped, and is of the expected type.
2976 * This defends against an ALTER DROP COLUMN occurring just before we
2977 * acquired lock ... but if the whole table were dropped, we'd still
2978 * have a problem.
2979 */
2980 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2981 continue;
2982 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2983 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2984 continue;
2985
2986 /*
2987 * Okay, add column to result. We store the columns in column-number
2988 * order; this is just a hack to improve predictability of regression
2989 * test output ...
2990 */
2991 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2992
2993 ptr = rtc->natts++;
2994 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2995 {
2996 rtc->atts[ptr] = rtc->atts[ptr - 1];
2997 ptr--;
2998 }
2999 rtc->atts[ptr] = pg_depend->objsubid;
3000 }
3001
3002 systable_endscan(depScan);
3003
3004 relation_close(depRel, AccessShareLock);
3005
3006 return result;
3007 }
3008
3009 /*
3010 * checkDomainOwner
3011 *
3012 * Check that the type is actually a domain and that the current user
3013 * has permission to do ALTER DOMAIN on it. Throw an error if not.
3014 */
3015 void
checkDomainOwner(HeapTuple tup)3016 checkDomainOwner(HeapTuple tup)
3017 {
3018 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
3019
3020 /* Check that this is actually a domain */
3021 if (typTup->typtype != TYPTYPE_DOMAIN)
3022 ereport(ERROR,
3023 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3024 errmsg("%s is not a domain",
3025 format_type_be(HeapTupleGetOid(tup)))));
3026
3027 /* Permission check: must own type */
3028 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
3029 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
3030 }
3031
3032 /*
3033 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
3034 */
3035 static char *
domainAddConstraint(Oid domainOid,Oid domainNamespace,Oid baseTypeOid,int typMod,Constraint * constr,char * domainName,ObjectAddress * constrAddr)3036 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
3037 int typMod, Constraint *constr,
3038 char *domainName, ObjectAddress *constrAddr)
3039 {
3040 Node *expr;
3041 char *ccsrc;
3042 char *ccbin;
3043 ParseState *pstate;
3044 CoerceToDomainValue *domVal;
3045 Oid ccoid;
3046
3047 /*
3048 * Assign or validate constraint name
3049 */
3050 if (constr->conname)
3051 {
3052 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
3053 domainOid,
3054 domainNamespace,
3055 constr->conname))
3056 ereport(ERROR,
3057 (errcode(ERRCODE_DUPLICATE_OBJECT),
3058 errmsg("constraint \"%s\" for domain \"%s\" already exists",
3059 constr->conname, domainName)));
3060 }
3061 else
3062 constr->conname = ChooseConstraintName(domainName,
3063 NULL,
3064 "check",
3065 domainNamespace,
3066 NIL);
3067
3068 /*
3069 * Convert the A_EXPR in raw_expr into an EXPR
3070 */
3071 pstate = make_parsestate(NULL);
3072
3073 /*
3074 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
3075 * the expression. Note that it will appear to have the type of the base
3076 * type, not the domain. This seems correct since within the check
3077 * expression, we should not assume the input value can be considered a
3078 * member of the domain.
3079 */
3080 domVal = makeNode(CoerceToDomainValue);
3081 domVal->typeId = baseTypeOid;
3082 domVal->typeMod = typMod;
3083 domVal->collation = get_typcollation(baseTypeOid);
3084 domVal->location = -1; /* will be set when/if used */
3085
3086 pstate->p_pre_columnref_hook = replace_domain_constraint_value;
3087 pstate->p_ref_hook_state = (void *) domVal;
3088
3089 /*
3090 * Transform the expression; first we must copy the input, in case it's in
3091 * plan cache.
3092 */
3093 expr = transformExpr(pstate, copyObject(constr->raw_expr),
3094 EXPR_KIND_DOMAIN_CHECK);
3095
3096 /*
3097 * Make sure it yields a boolean result.
3098 */
3099 expr = coerce_to_boolean(pstate, expr, "CHECK");
3100
3101 /*
3102 * Fix up collation information.
3103 */
3104 assign_expr_collations(pstate, expr);
3105
3106 /*
3107 * Domains don't allow variables (this is probably dead code now that
3108 * add_missing_from is history, but let's be sure).
3109 */
3110 if (list_length(pstate->p_rtable) != 0 ||
3111 contain_var_clause(expr))
3112 ereport(ERROR,
3113 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3114 errmsg("cannot use table references in domain check constraint")));
3115
3116 /*
3117 * Convert to string form for storage.
3118 */
3119 ccbin = nodeToString(expr);
3120
3121 /*
3122 * Deparse it to produce text for consrc.
3123 */
3124 ccsrc = deparse_expression(expr,
3125 NIL, false, false);
3126
3127 /*
3128 * Store the constraint in pg_constraint
3129 */
3130 ccoid =
3131 CreateConstraintEntry(constr->conname, /* Constraint Name */
3132 domainNamespace, /* namespace */
3133 CONSTRAINT_CHECK, /* Constraint Type */
3134 false, /* Is Deferrable */
3135 false, /* Is Deferred */
3136 !constr->skip_validation, /* Is Validated */
3137 InvalidOid, /* not a relation constraint */
3138 NULL,
3139 0,
3140 domainOid, /* domain constraint */
3141 InvalidOid, /* no associated index */
3142 InvalidOid, /* Foreign key fields */
3143 NULL,
3144 NULL,
3145 NULL,
3146 NULL,
3147 0,
3148 ' ',
3149 ' ',
3150 ' ',
3151 NULL, /* not an exclusion constraint */
3152 expr, /* Tree form of check constraint */
3153 ccbin, /* Binary form of check constraint */
3154 ccsrc, /* Source form of check constraint */
3155 true, /* is local */
3156 0, /* inhcount */
3157 false, /* connoinherit */
3158 false); /* is_internal */
3159 if (constrAddr)
3160 ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
3161
3162 /*
3163 * Return the compiled constraint expression so the calling routine can
3164 * perform any additional required tests.
3165 */
3166 return ccbin;
3167 }
3168
3169 /* Parser pre_columnref_hook for domain CHECK constraint parsing */
3170 static Node *
replace_domain_constraint_value(ParseState * pstate,ColumnRef * cref)3171 replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref)
3172 {
3173 /*
3174 * Check for a reference to "value", and if that's what it is, replace
3175 * with a CoerceToDomainValue as prepared for us by domainAddConstraint.
3176 * (We handle VALUE as a name, not a keyword, to avoid breaking a lot of
3177 * applications that have used VALUE as a column name in the past.)
3178 */
3179 if (list_length(cref->fields) == 1)
3180 {
3181 Node *field1 = (Node *) linitial(cref->fields);
3182 char *colname;
3183
3184 Assert(IsA(field1, String));
3185 colname = strVal(field1);
3186 if (strcmp(colname, "value") == 0)
3187 {
3188 CoerceToDomainValue *domVal = copyObject(pstate->p_ref_hook_state);
3189
3190 /* Propagate location knowledge, if any */
3191 domVal->location = cref->location;
3192 return (Node *) domVal;
3193 }
3194 }
3195 return NULL;
3196 }
3197
3198
3199 /*
3200 * Execute ALTER TYPE RENAME
3201 */
3202 ObjectAddress
RenameType(RenameStmt * stmt)3203 RenameType(RenameStmt *stmt)
3204 {
3205 List *names = castNode(List, stmt->object);
3206 const char *newTypeName = stmt->newname;
3207 TypeName *typename;
3208 Oid typeOid;
3209 Relation rel;
3210 HeapTuple tup;
3211 Form_pg_type typTup;
3212 ObjectAddress address;
3213
3214 /* Make a TypeName so we can use standard type lookup machinery */
3215 typename = makeTypeNameFromNameList(names);
3216 typeOid = typenameTypeId(NULL, typename);
3217
3218 /* Look up the type in the type table */
3219 rel = heap_open(TypeRelationId, RowExclusiveLock);
3220
3221 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3222 if (!HeapTupleIsValid(tup))
3223 elog(ERROR, "cache lookup failed for type %u", typeOid);
3224 typTup = (Form_pg_type) GETSTRUCT(tup);
3225
3226 /* check permissions on type */
3227 if (!pg_type_ownercheck(typeOid, GetUserId()))
3228 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3229
3230 /* ALTER DOMAIN used on a non-domain? */
3231 if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3232 ereport(ERROR,
3233 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3234 errmsg("%s is not a domain",
3235 format_type_be(typeOid))));
3236
3237 /*
3238 * If it's a composite type, we need to check that it really is a
3239 * free-standing composite type, and not a table's rowtype. We want people
3240 * to use ALTER TABLE not ALTER TYPE for that case.
3241 */
3242 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3243 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3244 ereport(ERROR,
3245 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3246 errmsg("%s is a table's row type",
3247 format_type_be(typeOid)),
3248 errhint("Use ALTER TABLE instead.")));
3249
3250 /* don't allow direct alteration of array types, either */
3251 if (OidIsValid(typTup->typelem) &&
3252 get_array_type(typTup->typelem) == typeOid)
3253 ereport(ERROR,
3254 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3255 errmsg("cannot alter array type %s",
3256 format_type_be(typeOid)),
3257 errhint("You can alter type %s, which will alter the array type as well.",
3258 format_type_be(typTup->typelem))));
3259
3260 /*
3261 * If type is composite we need to rename associated pg_class entry too.
3262 * RenameRelationInternal will call RenameTypeInternal automatically.
3263 */
3264 if (typTup->typtype == TYPTYPE_COMPOSITE)
3265 RenameRelationInternal(typTup->typrelid, newTypeName, false);
3266 else
3267 RenameTypeInternal(typeOid, newTypeName,
3268 typTup->typnamespace);
3269
3270 ObjectAddressSet(address, TypeRelationId, typeOid);
3271 /* Clean up */
3272 heap_close(rel, RowExclusiveLock);
3273
3274 return address;
3275 }
3276
3277 /*
3278 * Change the owner of a type.
3279 */
3280 ObjectAddress
AlterTypeOwner(List * names,Oid newOwnerId,ObjectType objecttype)3281 AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
3282 {
3283 TypeName *typename;
3284 Oid typeOid;
3285 Relation rel;
3286 HeapTuple tup;
3287 HeapTuple newtup;
3288 Form_pg_type typTup;
3289 AclResult aclresult;
3290 ObjectAddress address;
3291
3292 rel = heap_open(TypeRelationId, RowExclusiveLock);
3293
3294 /* Make a TypeName so we can use standard type lookup machinery */
3295 typename = makeTypeNameFromNameList(names);
3296
3297 /* Use LookupTypeName here so that shell types can be processed */
3298 tup = LookupTypeName(NULL, typename, NULL, false);
3299 if (tup == NULL)
3300 ereport(ERROR,
3301 (errcode(ERRCODE_UNDEFINED_OBJECT),
3302 errmsg("type \"%s\" does not exist",
3303 TypeNameToString(typename))));
3304 typeOid = typeTypeId(tup);
3305
3306 /* Copy the syscache entry so we can scribble on it below */
3307 newtup = heap_copytuple(tup);
3308 ReleaseSysCache(tup);
3309 tup = newtup;
3310 typTup = (Form_pg_type) GETSTRUCT(tup);
3311
3312 /* Don't allow ALTER DOMAIN on a type */
3313 if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3314 ereport(ERROR,
3315 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3316 errmsg("%s is not a domain",
3317 format_type_be(typeOid))));
3318
3319 /*
3320 * If it's a composite type, we need to check that it really is a
3321 * free-standing composite type, and not a table's rowtype. We want people
3322 * to use ALTER TABLE not ALTER TYPE for that case.
3323 */
3324 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3325 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3326 ereport(ERROR,
3327 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3328 errmsg("%s is a table's row type",
3329 format_type_be(typeOid)),
3330 errhint("Use ALTER TABLE instead.")));
3331
3332 /* don't allow direct alteration of array types, either */
3333 if (OidIsValid(typTup->typelem) &&
3334 get_array_type(typTup->typelem) == typeOid)
3335 ereport(ERROR,
3336 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3337 errmsg("cannot alter array type %s",
3338 format_type_be(typeOid)),
3339 errhint("You can alter type %s, which will alter the array type as well.",
3340 format_type_be(typTup->typelem))));
3341
3342 /*
3343 * If the new owner is the same as the existing owner, consider the
3344 * command to have succeeded. This is for dump restoration purposes.
3345 */
3346 if (typTup->typowner != newOwnerId)
3347 {
3348 /* Superusers can always do it */
3349 if (!superuser())
3350 {
3351 /* Otherwise, must be owner of the existing object */
3352 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
3353 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
3354
3355 /* Must be able to become new owner */
3356 check_is_member_of_role(GetUserId(), newOwnerId);
3357
3358 /* New owner must have CREATE privilege on namespace */
3359 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3360 newOwnerId,
3361 ACL_CREATE);
3362 if (aclresult != ACLCHECK_OK)
3363 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
3364 get_namespace_name(typTup->typnamespace));
3365 }
3366
3367 AlterTypeOwner_oid(typeOid, newOwnerId, true);
3368 }
3369
3370 ObjectAddressSet(address, TypeRelationId, typeOid);
3371
3372 /* Clean up */
3373 heap_close(rel, RowExclusiveLock);
3374
3375 return address;
3376 }
3377
3378 /*
3379 * AlterTypeOwner_oid - change type owner unconditionally
3380 *
3381 * This function recurses to handle a pg_class entry, if necessary. It
3382 * invokes any necessary access object hooks. If hasDependEntry is TRUE, this
3383 * function modifies the pg_shdepend entry appropriately (this should be
3384 * passed as FALSE only for table rowtypes and array types).
3385 *
3386 * This is used by ALTER TABLE/TYPE OWNER commands, as well as by REASSIGN
3387 * OWNED BY. It assumes the caller has done all needed check.
3388 */
3389 void
AlterTypeOwner_oid(Oid typeOid,Oid newOwnerId,bool hasDependEntry)3390 AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
3391 {
3392 Relation rel;
3393 HeapTuple tup;
3394 Form_pg_type typTup;
3395
3396 rel = heap_open(TypeRelationId, RowExclusiveLock);
3397
3398 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3399 if (!HeapTupleIsValid(tup))
3400 elog(ERROR, "cache lookup failed for type %u", typeOid);
3401 typTup = (Form_pg_type) GETSTRUCT(tup);
3402
3403 /*
3404 * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3405 * the pg_class entry properly. That will call back to
3406 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3407 */
3408 if (typTup->typtype == TYPTYPE_COMPOSITE)
3409 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3410 else
3411 AlterTypeOwnerInternal(typeOid, newOwnerId);
3412
3413 /* Update owner dependency reference */
3414 if (hasDependEntry)
3415 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3416
3417 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3418
3419 ReleaseSysCache(tup);
3420 heap_close(rel, RowExclusiveLock);
3421 }
3422
3423 /*
3424 * AlterTypeOwnerInternal - bare-bones type owner change.
3425 *
3426 * This routine simply modifies the owner of a pg_type entry, and recurses
3427 * to handle a possible array type.
3428 */
3429 void
AlterTypeOwnerInternal(Oid typeOid,Oid newOwnerId)3430 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
3431 {
3432 Relation rel;
3433 HeapTuple tup;
3434 Form_pg_type typTup;
3435 Datum repl_val[Natts_pg_type];
3436 bool repl_null[Natts_pg_type];
3437 bool repl_repl[Natts_pg_type];
3438 Acl *newAcl;
3439 Datum aclDatum;
3440 bool isNull;
3441
3442 rel = heap_open(TypeRelationId, RowExclusiveLock);
3443
3444 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3445 if (!HeapTupleIsValid(tup))
3446 elog(ERROR, "cache lookup failed for type %u", typeOid);
3447 typTup = (Form_pg_type) GETSTRUCT(tup);
3448
3449 memset(repl_null, false, sizeof(repl_null));
3450 memset(repl_repl, false, sizeof(repl_repl));
3451
3452 repl_repl[Anum_pg_type_typowner - 1] = true;
3453 repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
3454
3455 aclDatum = heap_getattr(tup,
3456 Anum_pg_type_typacl,
3457 RelationGetDescr(rel),
3458 &isNull);
3459 /* Null ACLs do not require changes */
3460 if (!isNull)
3461 {
3462 newAcl = aclnewowner(DatumGetAclP(aclDatum),
3463 typTup->typowner, newOwnerId);
3464 repl_repl[Anum_pg_type_typacl - 1] = true;
3465 repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3466 }
3467
3468 tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3469 repl_repl);
3470
3471 CatalogTupleUpdate(rel, &tup->t_self, tup);
3472
3473 /* If it has an array type, update that too */
3474 if (OidIsValid(typTup->typarray))
3475 AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
3476
3477 /* Clean up */
3478 heap_close(rel, RowExclusiveLock);
3479 }
3480
3481 /*
3482 * Execute ALTER TYPE SET SCHEMA
3483 */
3484 ObjectAddress
AlterTypeNamespace(List * names,const char * newschema,ObjectType objecttype,Oid * oldschema)3485 AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype,
3486 Oid *oldschema)
3487 {
3488 TypeName *typename;
3489 Oid typeOid;
3490 Oid nspOid;
3491 Oid oldNspOid;
3492 ObjectAddresses *objsMoved;
3493 ObjectAddress myself;
3494
3495 /* Make a TypeName so we can use standard type lookup machinery */
3496 typename = makeTypeNameFromNameList(names);
3497 typeOid = typenameTypeId(NULL, typename);
3498
3499 /* Don't allow ALTER DOMAIN on a type */
3500 if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3501 ereport(ERROR,
3502 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3503 errmsg("%s is not a domain",
3504 format_type_be(typeOid))));
3505
3506 /* get schema OID and check its permissions */
3507 nspOid = LookupCreationNamespace(newschema);
3508
3509 objsMoved = new_object_addresses();
3510 oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3511 free_object_addresses(objsMoved);
3512
3513 if (oldschema)
3514 *oldschema = oldNspOid;
3515
3516 ObjectAddressSet(myself, TypeRelationId, typeOid);
3517
3518 return myself;
3519 }
3520
3521 Oid
AlterTypeNamespace_oid(Oid typeOid,Oid nspOid,ObjectAddresses * objsMoved)3522 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
3523 {
3524 Oid elemOid;
3525
3526 /* check permissions on type */
3527 if (!pg_type_ownercheck(typeOid, GetUserId()))
3528 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3529
3530 /* don't allow direct alteration of array types */
3531 elemOid = get_element_type(typeOid);
3532 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3533 ereport(ERROR,
3534 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3535 errmsg("cannot alter array type %s",
3536 format_type_be(typeOid)),
3537 errhint("You can alter type %s, which will alter the array type as well.",
3538 format_type_be(elemOid))));
3539
3540 /* and do the work */
3541 return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3542 }
3543
3544 /*
3545 * Move specified type to new namespace.
3546 *
3547 * Caller must have already checked privileges.
3548 *
3549 * The function automatically recurses to process the type's array type,
3550 * if any. isImplicitArray should be TRUE only when doing this internal
3551 * recursion (outside callers must never try to move an array type directly).
3552 *
3553 * If errorOnTableType is TRUE, the function errors out if the type is
3554 * a table type. ALTER TABLE has to be used to move a table to a new
3555 * namespace.
3556 *
3557 * Returns the type's old namespace OID.
3558 */
3559 Oid
AlterTypeNamespaceInternal(Oid typeOid,Oid nspOid,bool isImplicitArray,bool errorOnTableType,ObjectAddresses * objsMoved)3560 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
3561 bool isImplicitArray,
3562 bool errorOnTableType,
3563 ObjectAddresses *objsMoved)
3564 {
3565 Relation rel;
3566 HeapTuple tup;
3567 Form_pg_type typform;
3568 Oid oldNspOid;
3569 Oid arrayOid;
3570 bool isCompositeType;
3571 ObjectAddress thisobj;
3572
3573 /*
3574 * Make sure we haven't moved this object previously.
3575 */
3576 thisobj.classId = TypeRelationId;
3577 thisobj.objectId = typeOid;
3578 thisobj.objectSubId = 0;
3579
3580 if (object_address_present(&thisobj, objsMoved))
3581 return InvalidOid;
3582
3583 rel = heap_open(TypeRelationId, RowExclusiveLock);
3584
3585 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3586 if (!HeapTupleIsValid(tup))
3587 elog(ERROR, "cache lookup failed for type %u", typeOid);
3588 typform = (Form_pg_type) GETSTRUCT(tup);
3589
3590 oldNspOid = typform->typnamespace;
3591 arrayOid = typform->typarray;
3592
3593 /* If the type is already there, we scan skip these next few checks. */
3594 if (oldNspOid != nspOid)
3595 {
3596 /* common checks on switching namespaces */
3597 CheckSetNamespace(oldNspOid, nspOid);
3598
3599 /* check for duplicate name (more friendly than unique-index failure) */
3600 if (SearchSysCacheExists2(TYPENAMENSP,
3601 NameGetDatum(&typform->typname),
3602 ObjectIdGetDatum(nspOid)))
3603 ereport(ERROR,
3604 (errcode(ERRCODE_DUPLICATE_OBJECT),
3605 errmsg("type \"%s\" already exists in schema \"%s\"",
3606 NameStr(typform->typname),
3607 get_namespace_name(nspOid))));
3608 }
3609
3610 /* Detect whether type is a composite type (but not a table rowtype) */
3611 isCompositeType =
3612 (typform->typtype == TYPTYPE_COMPOSITE &&
3613 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3614
3615 /* Enforce not-table-type if requested */
3616 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3617 errorOnTableType)
3618 ereport(ERROR,
3619 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3620 errmsg("%s is a table's row type",
3621 format_type_be(typeOid)),
3622 errhint("Use ALTER TABLE instead.")));
3623
3624 if (oldNspOid != nspOid)
3625 {
3626 /* OK, modify the pg_type row */
3627
3628 /* tup is a copy, so we can scribble directly on it */
3629 typform->typnamespace = nspOid;
3630
3631 CatalogTupleUpdate(rel, &tup->t_self, tup);
3632 }
3633
3634 /*
3635 * Composite types have pg_class entries.
3636 *
3637 * We need to modify the pg_class tuple as well to reflect the change of
3638 * schema.
3639 */
3640 if (isCompositeType)
3641 {
3642 Relation classRel;
3643
3644 classRel = heap_open(RelationRelationId, RowExclusiveLock);
3645
3646 AlterRelationNamespaceInternal(classRel, typform->typrelid,
3647 oldNspOid, nspOid,
3648 false, objsMoved);
3649
3650 heap_close(classRel, RowExclusiveLock);
3651
3652 /*
3653 * Check for constraints associated with the composite type (we don't
3654 * currently support this, but probably will someday).
3655 */
3656 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3657 nspOid, false, objsMoved);
3658 }
3659 else
3660 {
3661 /* If it's a domain, it might have constraints */
3662 if (typform->typtype == TYPTYPE_DOMAIN)
3663 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
3664 objsMoved);
3665 }
3666
3667 /*
3668 * Update dependency on schema, if any --- a table rowtype has not got
3669 * one, and neither does an implicit array.
3670 */
3671 if (oldNspOid != nspOid &&
3672 (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3673 !isImplicitArray)
3674 if (changeDependencyFor(TypeRelationId, typeOid,
3675 NamespaceRelationId, oldNspOid, nspOid) != 1)
3676 elog(ERROR, "failed to change schema dependency for type %s",
3677 format_type_be(typeOid));
3678
3679 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3680
3681 heap_freetuple(tup);
3682
3683 heap_close(rel, RowExclusiveLock);
3684
3685 add_exact_object_address(&thisobj, objsMoved);
3686
3687 /* Recursively alter the associated array type, if any */
3688 if (OidIsValid(arrayOid))
3689 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
3690
3691 return oldNspOid;
3692 }
3693