1 /*-------------------------------------------------------------------------
4 * Routines for SQL commands that manipulate types (and domains).
6 * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/commands/typecmds.c
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.
21 * These things must be defined and committed in the following order:
23 * input/output, recv/send functions
30 *-------------------------------------------------------------------------
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"
76 /* result structure for get_rels_with_domain() */
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) */
85 /* Potentially set by pg_upgrade_support functions */
86 Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
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,
105 int typMod, Constraint *constr,
106 char *domainName, ObjectAddress *constrAddr);
111 * Registers a new base type.
114 DefineType(List *names, List *parameters)
118 int16 internalLength = -1; /* default: variable-length */
119 List *inputName = NIL;
120 List *outputName = NIL;
121 List *receiveName = NIL;
122 List *sendName = NIL;
123 List *typmodinName = NIL;
124 List *typmodoutName = NIL;
125 List *analyzeName = NIL;
126 char category = TYPCATEGORY_USER;
127 bool preferred = false;
128 char delimiter = DEFAULT_TYPDELIM;
129 Oid elemType = InvalidOid;
130 char *defaultValue = NULL;
131 bool byValue = false;
132 char alignment = 'i'; /* default alignment */
133 char storage = 'p'; /* default TOAST storage method */
134 Oid collation = InvalidOid;
135 DefElem *likeTypeEl = NULL;
136 DefElem *internalLengthEl = NULL;
137 DefElem *inputNameEl = NULL;
138 DefElem *outputNameEl = NULL;
139 DefElem *receiveNameEl = NULL;
140 DefElem *sendNameEl = NULL;
141 DefElem *typmodinNameEl = NULL;
142 DefElem *typmodoutNameEl = NULL;
143 DefElem *analyzeNameEl = NULL;
144 DefElem *categoryEl = NULL;
145 DefElem *preferredEl = NULL;
146 DefElem *delimiterEl = NULL;
147 DefElem *elemTypeEl = NULL;
148 DefElem *defaultValueEl = NULL;
149 DefElem *byValueEl = NULL;
150 DefElem *alignmentEl = NULL;
151 DefElem *storageEl = NULL;
152 DefElem *collatableEl = NULL;
155 Oid receiveOid = InvalidOid;
156 Oid sendOid = InvalidOid;
157 Oid typmodinOid = InvalidOid;
158 Oid typmodoutOid = InvalidOid;
159 Oid analyzeOid = InvalidOid;
165 ObjectAddress address;
168 * As of Postgres 8.4, we require superuser privilege to create a base
169 * type. This is simple paranoia: there are too many ways to mess up the
170 * system with an incorrect type definition (for instance, representation
171 * parameters that don't match what the C code expects). In practice it
172 * takes superuser privilege to create the I/O functions, and so the
173 * former requirement that you own the I/O functions pretty much forced
174 * superuserness anyway. We're just making doubly sure here.
176 * XXX re-enable NOT_USED code sections below if you remove this test.
180 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
181 errmsg("must be superuser to create a base type")));
183 /* Convert list of names to a name and namespace */
184 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
187 /* XXX this is unnecessary given the superuser check above */
188 /* Check we have creation rights in target namespace */
189 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
190 if (aclresult != ACLCHECK_OK)
191 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
192 get_namespace_name(typeNamespace));
196 * Look to see if type already exists (presumably as a shell; if not,
197 * TypeCreate will complain).
199 typoid = GetSysCacheOid2(TYPENAMENSP,
200 CStringGetDatum(typeName),
201 ObjectIdGetDatum(typeNamespace));
204 * If it's not a shell, see if it's an autogenerated array type, and if so
205 * rename it out of the way.
207 if (OidIsValid(typoid) && get_typisdefined(typoid))
209 if (moveArrayTypeName(typoid, typeName, typeNamespace))
214 * If it doesn't exist, create it as a shell, so that the OID is known for
215 * use in the I/O function definitions.
217 if (!OidIsValid(typoid))
219 address = TypeShellMake(typeName, typeNamespace, GetUserId());
220 typoid = address.objectId;
221 /* Make new shell type visible for modification below */
222 CommandCounterIncrement();
225 * If the command was a parameterless CREATE TYPE, we're done ---
226 * creating the shell type was all we're supposed to do.
228 if (parameters == NIL)
233 /* Complain if dummy CREATE TYPE and entry already exists */
234 if (parameters == NIL)
236 (errcode(ERRCODE_DUPLICATE_OBJECT),
237 errmsg("type \"%s\" already exists", typeName)));
240 /* Extract the parameters from the parameter list */
241 foreach(pl, parameters)
243 DefElem *defel = (DefElem *) lfirst(pl);
246 if (pg_strcasecmp(defel->defname, "like") == 0)
247 defelp = &likeTypeEl;
248 else if (pg_strcasecmp(defel->defname, "internallength") == 0)
249 defelp = &internalLengthEl;
250 else if (pg_strcasecmp(defel->defname, "input") == 0)
251 defelp = &inputNameEl;
252 else if (pg_strcasecmp(defel->defname, "output") == 0)
253 defelp = &outputNameEl;
254 else if (pg_strcasecmp(defel->defname, "receive") == 0)
255 defelp = &receiveNameEl;
256 else if (pg_strcasecmp(defel->defname, "send") == 0)
257 defelp = &sendNameEl;
258 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
259 defelp = &typmodinNameEl;
260 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
261 defelp = &typmodoutNameEl;
262 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
263 pg_strcasecmp(defel->defname, "analyse") == 0)
264 defelp = &analyzeNameEl;
265 else if (pg_strcasecmp(defel->defname, "category") == 0)
266 defelp = &categoryEl;
267 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
268 defelp = &preferredEl;
269 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
270 defelp = &delimiterEl;
271 else if (pg_strcasecmp(defel->defname, "element") == 0)
272 defelp = &elemTypeEl;
273 else if (pg_strcasecmp(defel->defname, "default") == 0)
274 defelp = &defaultValueEl;
275 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
277 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
278 defelp = &alignmentEl;
279 else if (pg_strcasecmp(defel->defname, "storage") == 0)
281 else if (pg_strcasecmp(defel->defname, "collatable") == 0)
282 defelp = &collatableEl;
285 /* WARNING, not ERROR, for historical backwards-compatibility */
287 (errcode(ERRCODE_SYNTAX_ERROR),
288 errmsg("type attribute \"%s\" not recognized",
294 (errcode(ERRCODE_SYNTAX_ERROR),
295 errmsg("conflicting or redundant options")));
300 * Now interpret the options; we do this separately so that LIKE can be
301 * overridden by other options regardless of the ordering in the parameter
307 Form_pg_type likeForm;
309 likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
310 likeForm = (Form_pg_type) GETSTRUCT(likeType);
311 internalLength = likeForm->typlen;
312 byValue = likeForm->typbyval;
313 alignment = likeForm->typalign;
314 storage = likeForm->typstorage;
315 ReleaseSysCache(likeType);
317 if (internalLengthEl)
318 internalLength = defGetTypeLength(internalLengthEl);
320 inputName = defGetQualifiedName(inputNameEl);
322 outputName = defGetQualifiedName(outputNameEl);
324 receiveName = defGetQualifiedName(receiveNameEl);
326 sendName = defGetQualifiedName(sendNameEl);
328 typmodinName = defGetQualifiedName(typmodinNameEl);
330 typmodoutName = defGetQualifiedName(typmodoutNameEl);
332 analyzeName = defGetQualifiedName(analyzeNameEl);
335 char *p = defGetString(categoryEl);
338 /* restrict to non-control ASCII */
339 if (category < 32 || category > 126)
341 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
342 errmsg("invalid type category \"%s\": must be simple ASCII",
346 preferred = defGetBoolean(preferredEl);
349 char *p = defGetString(delimiterEl);
352 /* XXX shouldn't we restrict the delimiter? */
356 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
357 /* disallow arrays of pseudotypes */
358 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
360 (errcode(ERRCODE_DATATYPE_MISMATCH),
361 errmsg("array element type cannot be %s",
362 format_type_be(elemType))));
365 defaultValue = defGetString(defaultValueEl);
367 byValue = defGetBoolean(byValueEl);
370 char *a = defGetString(alignmentEl);
373 * Note: if argument was an unquoted identifier, parser will have
374 * applied translations to it, so be prepared to recognize translated
375 * type names as well as the nominal form.
377 if (pg_strcasecmp(a, "double") == 0 ||
378 pg_strcasecmp(a, "float8") == 0 ||
379 pg_strcasecmp(a, "pg_catalog.float8") == 0)
381 else if (pg_strcasecmp(a, "int4") == 0 ||
382 pg_strcasecmp(a, "pg_catalog.int4") == 0)
384 else if (pg_strcasecmp(a, "int2") == 0 ||
385 pg_strcasecmp(a, "pg_catalog.int2") == 0)
387 else if (pg_strcasecmp(a, "char") == 0 ||
388 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
392 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
393 errmsg("alignment \"%s\" not recognized", a)));
397 char *a = defGetString(storageEl);
399 if (pg_strcasecmp(a, "plain") == 0)
401 else if (pg_strcasecmp(a, "external") == 0)
403 else if (pg_strcasecmp(a, "extended") == 0)
405 else if (pg_strcasecmp(a, "main") == 0)
409 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
410 errmsg("storage \"%s\" not recognized", a)));
413 collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
416 * make sure we have our required definitions
418 if (inputName == NIL)
420 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
421 errmsg("type input function must be specified")));
422 if (outputName == NIL)
424 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
425 errmsg("type output function must be specified")));
427 if (typmodinName == NIL && typmodoutName != NIL)
429 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
430 errmsg("type modifier output function is useless without a type modifier input function")));
433 * Convert I/O proc names to OIDs
435 inputOid = findTypeInputFunction(inputName, typoid);
436 outputOid = findTypeOutputFunction(outputName, typoid);
438 receiveOid = findTypeReceiveFunction(receiveName, typoid);
440 sendOid = findTypeSendFunction(sendName, typoid);
443 * Verify that I/O procs return the expected thing. If we see OPAQUE,
444 * complain and change it to the correct type-safe choice.
446 resulttype = get_func_rettype(inputOid);
447 if (resulttype != typoid)
449 if (resulttype == OPAQUEOID)
451 /* backwards-compatibility hack */
453 (errmsg("changing return type of function %s from \"%s\" to \"%s\"",
454 NameListToString(inputName), "opaque", typeName)));
455 SetFunctionReturnType(inputOid, typoid);
459 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
460 errmsg("type input function %s must return type \"%s\"",
461 NameListToString(inputName), typeName)));
463 resulttype = get_func_rettype(outputOid);
464 if (resulttype != CSTRINGOID)
466 if (resulttype == OPAQUEOID)
468 /* backwards-compatibility hack */
470 (errmsg("changing return type of function %s from \"%s\" to \"%s\"",
471 NameListToString(outputName), "opaque", "cstring")));
472 SetFunctionReturnType(outputOid, CSTRINGOID);
476 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
477 errmsg("type output function %s must return type \"%s\"",
478 NameListToString(outputName), "cstring")));
482 resulttype = get_func_rettype(receiveOid);
483 if (resulttype != typoid)
485 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
486 errmsg("type receive function %s must return type \"%s\"",
487 NameListToString(receiveName), typeName)));
491 resulttype = get_func_rettype(sendOid);
492 if (resulttype != BYTEAOID)
494 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
495 errmsg("type send function %s must return type \"%s\"",
496 NameListToString(sendName), "bytea")));
500 * Convert typmodin/out function proc names to OIDs.
503 typmodinOid = findTypeTypmodinFunction(typmodinName);
505 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
508 * Convert analysis function proc name to an OID. If no analysis function
509 * is specified, we'll use zero to select the built-in default algorithm.
512 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
515 * Check permissions on functions. We choose to require the creator/owner
516 * of a type to also own the underlying functions. Since creating a type
517 * is tantamount to granting public execute access on the functions, the
518 * minimum sane check would be for execute-with-grant-option. But we
519 * don't have a way to make the type go away if the grant option is
520 * revoked, so ownership seems better.
523 /* XXX this is unnecessary given the superuser check above */
524 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
525 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
526 NameListToString(inputName));
527 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
528 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
529 NameListToString(outputName));
530 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
531 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
532 NameListToString(receiveName));
533 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
534 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
535 NameListToString(sendName));
536 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
537 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
538 NameListToString(typmodinName));
539 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
540 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
541 NameListToString(typmodoutName));
542 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
543 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
544 NameListToString(analyzeName));
548 * Print warnings if any of the type's I/O functions are marked volatile.
549 * There is a general assumption that I/O functions are stable or
550 * immutable; this allows us for example to mark record_in/record_out
551 * stable rather than volatile. Ideally we would throw errors not just
552 * warnings here; but since this check is new as of 9.5, and since the
553 * volatility marking might be just an error-of-omission and not a true
554 * indication of how the function behaves, we'll let it pass as a warning
557 if (inputOid && func_volatile(inputOid) == PROVOLATILE_VOLATILE)
559 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
560 errmsg("type input function %s should not be volatile",
561 NameListToString(inputName))));
562 if (outputOid && func_volatile(outputOid) == PROVOLATILE_VOLATILE)
564 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
565 errmsg("type output function %s should not be volatile",
566 NameListToString(outputName))));
567 if (receiveOid && func_volatile(receiveOid) == PROVOLATILE_VOLATILE)
569 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
570 errmsg("type receive function %s should not be volatile",
571 NameListToString(receiveName))));
572 if (sendOid && func_volatile(sendOid) == PROVOLATILE_VOLATILE)
574 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
575 errmsg("type send function %s should not be volatile",
576 NameListToString(sendName))));
577 if (typmodinOid && func_volatile(typmodinOid) == PROVOLATILE_VOLATILE)
579 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
580 errmsg("type modifier input function %s should not be volatile",
581 NameListToString(typmodinName))));
582 if (typmodoutOid && func_volatile(typmodoutOid) == PROVOLATILE_VOLATILE)
584 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
585 errmsg("type modifier output function %s should not be volatile",
586 NameListToString(typmodoutName))));
589 * OK, we're done checking, time to make the type. We must assign the
590 * array type OID ahead of calling TypeCreate, since the base type and
591 * array type each refer to the other.
593 array_oid = AssignTypeArrayOid();
596 * now have TypeCreate do all the real work.
598 * Note: the pg_type.oid is stored in user tables as array elements (base
599 * types) in ArrayType and in composite types in DatumTupleFields. This
600 * oid must be preserved by binary upgrades.
603 TypeCreate(InvalidOid, /* no predetermined type OID */
604 typeName, /* type name */
605 typeNamespace, /* namespace */
606 InvalidOid, /* relation oid (n/a here) */
607 0, /* relation kind (ditto) */
608 GetUserId(), /* owner's ID */
609 internalLength, /* internal size */
610 TYPTYPE_BASE, /* type-type (base type) */
611 category, /* type-category */
612 preferred, /* is it a preferred type? */
613 delimiter, /* array element delimiter */
614 inputOid, /* input procedure */
615 outputOid, /* output procedure */
616 receiveOid, /* receive procedure */
617 sendOid, /* send procedure */
618 typmodinOid, /* typmodin procedure */
619 typmodoutOid, /* typmodout procedure */
620 analyzeOid, /* analyze procedure */
621 elemType, /* element type ID */
622 false, /* this is not an array type */
623 array_oid, /* array type we are about to create */
624 InvalidOid, /* base type ID (only for domains) */
625 defaultValue, /* default type value */
626 NULL, /* no binary form available */
627 byValue, /* passed by value */
628 alignment, /* required alignment */
629 storage, /* TOAST strategy */
630 -1, /* typMod (Domains only) */
631 0, /* Array Dimensions of typbasetype */
632 false, /* Type NOT NULL */
633 collation); /* type's collation */
634 Assert(typoid == address.objectId);
637 * Create the array type that goes with it.
639 array_type = makeArrayTypeName(typeName, typeNamespace);
641 /* alignment must be 'i' or 'd' for arrays */
642 alignment = (alignment == 'd') ? 'd' : 'i';
644 TypeCreate(array_oid, /* force assignment of this type OID */
645 array_type, /* type name */
646 typeNamespace, /* namespace */
647 InvalidOid, /* relation oid (n/a here) */
648 0, /* relation kind (ditto) */
649 GetUserId(), /* owner's ID */
650 -1, /* internal size (always varlena) */
651 TYPTYPE_BASE, /* type-type (base type) */
652 TYPCATEGORY_ARRAY, /* type-category (array) */
653 false, /* array types are never preferred */
654 delimiter, /* array element delimiter */
655 F_ARRAY_IN, /* input procedure */
656 F_ARRAY_OUT, /* output procedure */
657 F_ARRAY_RECV, /* receive procedure */
658 F_ARRAY_SEND, /* send procedure */
659 typmodinOid, /* typmodin procedure */
660 typmodoutOid, /* typmodout procedure */
661 F_ARRAY_TYPANALYZE, /* analyze procedure */
662 typoid, /* element type ID */
663 true, /* yes this is an array type */
664 InvalidOid, /* no further array type */
665 InvalidOid, /* base type ID */
666 NULL, /* never a default type value */
667 NULL, /* binary default isn't sent either */
668 false, /* never passed by value */
669 alignment, /* see above */
670 'x', /* ARRAY is always toastable */
671 -1, /* typMod (Domains only) */
672 0, /* Array dimensions of typbasetype */
673 false, /* Type NOT NULL */
674 collation); /* type's collation */
682 * Guts of type deletion.
685 RemoveTypeById(Oid typeOid)
690 relation = heap_open(TypeRelationId, RowExclusiveLock);
692 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
693 if (!HeapTupleIsValid(tup))
694 elog(ERROR, "cache lookup failed for type %u", typeOid);
696 simple_heap_delete(relation, &tup->t_self);
699 * If it is an enum, delete the pg_enum entries too; we don't bother with
700 * making dependency entries for those, so it has to be done "by hand"
703 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
704 EnumValuesDelete(typeOid);
707 * If it is a range type, delete the pg_range entry too; we don't bother
708 * with making a dependency entry for that, so it has to be done "by hand"
711 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
712 RangeDelete(typeOid);
714 ReleaseSysCache(tup);
716 heap_close(relation, RowExclusiveLock);
722 * Registers a new domain.
725 DefineDomain(CreateDomainStmt *stmt)
730 int16 internalLength;
733 Oid receiveProcedure;
735 Oid analyzeProcedure;
744 char *defaultValue = NULL;
745 char *defaultValueBin = NULL;
746 bool saw_default = false;
747 bool typNotNull = false;
748 bool nullDefined = false;
749 int32 typNDims = list_length(stmt->typeName->arrayBounds);
751 List *schema = stmt->constraints;
756 Form_pg_type baseType;
759 ObjectAddress address;
761 /* Convert list of names to a name and namespace */
762 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
765 /* Check we have creation rights in target namespace */
766 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
768 if (aclresult != ACLCHECK_OK)
769 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
770 get_namespace_name(domainNamespace));
773 * Check for collision with an existing type name. If there is one and
774 * it's an autogenerated array, we can rename it out of the way.
776 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
777 CStringGetDatum(domainName),
778 ObjectIdGetDatum(domainNamespace));
779 if (OidIsValid(old_type_oid))
781 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
783 (errcode(ERRCODE_DUPLICATE_OBJECT),
784 errmsg("type \"%s\" already exists", domainName)));
788 * Look up the base type.
790 typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
791 baseType = (Form_pg_type) GETSTRUCT(typeTup);
792 basetypeoid = HeapTupleGetOid(typeTup);
795 * Base type must be a plain base type, another domain, an enum or a range
796 * type. Domains over pseudotypes would create a security hole. Domains
797 * over composite types might be made to work in the future, but not
800 typtype = baseType->typtype;
801 if (typtype != TYPTYPE_BASE &&
802 typtype != TYPTYPE_DOMAIN &&
803 typtype != TYPTYPE_ENUM &&
804 typtype != TYPTYPE_RANGE)
806 (errcode(ERRCODE_DATATYPE_MISMATCH),
807 errmsg("\"%s\" is not a valid base type for a domain",
808 TypeNameToString(stmt->typeName))));
810 aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
811 if (aclresult != ACLCHECK_OK)
812 aclcheck_error_type(aclresult, basetypeoid);
815 * Identify the collation if any
817 baseColl = baseType->typcollation;
818 if (stmt->collClause)
819 domaincoll = get_collation_oid(stmt->collClause->collname, false);
821 domaincoll = baseColl;
823 /* Complain if COLLATE is applied to an uncollatable type */
824 if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
826 (errcode(ERRCODE_DATATYPE_MISMATCH),
827 errmsg("collations are not supported by type %s",
828 format_type_be(basetypeoid))));
830 /* passed by value */
831 byValue = baseType->typbyval;
833 /* Required Alignment */
834 alignment = baseType->typalign;
837 storage = baseType->typstorage;
840 internalLength = baseType->typlen;
843 category = baseType->typcategory;
845 /* Array element Delimiter */
846 delimiter = baseType->typdelim;
849 inputProcedure = F_DOMAIN_IN;
850 outputProcedure = baseType->typoutput;
851 receiveProcedure = F_DOMAIN_RECV;
852 sendProcedure = baseType->typsend;
854 /* Domains never accept typmods, so no typmodin/typmodout needed */
856 /* Analysis function */
857 analyzeProcedure = baseType->typanalyze;
859 /* Inherited default value */
860 datum = SysCacheGetAttr(TYPEOID, typeTup,
861 Anum_pg_type_typdefault, &isnull);
863 defaultValue = TextDatumGetCString(datum);
865 /* Inherited default binary value */
866 datum = SysCacheGetAttr(TYPEOID, typeTup,
867 Anum_pg_type_typdefaultbin, &isnull);
869 defaultValueBin = TextDatumGetCString(datum);
872 * Run through constraints manually to avoid the additional processing
873 * conducted by DefineRelation() and friends.
875 foreach(listptr, schema)
877 Constraint *constr = lfirst(listptr);
879 if (!IsA(constr, Constraint))
880 elog(ERROR, "unrecognized node type: %d",
881 (int) nodeTag(constr));
882 switch (constr->contype)
887 * The inherited default value may be overridden by the user
888 * with the DEFAULT <expr> clause ... but only once.
892 (errcode(ERRCODE_SYNTAX_ERROR),
893 errmsg("multiple default expressions")));
896 if (constr->raw_expr)
901 /* Create a dummy ParseState for transformExpr */
902 pstate = make_parsestate(NULL);
905 * Cook the constr->raw_expr into an expression. Note:
906 * name is strictly for error message
908 defaultExpr = cookDefault(pstate, constr->raw_expr,
914 * If the expression is just a NULL constant, we treat it
915 * like not having a default.
917 * Note that if the basetype is another domain, we'll see
918 * a CoerceToDomain expr here and not discard the default.
919 * This is critical because the domain default needs to be
920 * retained to override any default that the base domain
923 if (defaultExpr == NULL ||
924 (IsA(defaultExpr, Const) &&
925 ((Const *) defaultExpr)->constisnull))
928 defaultValueBin = NULL;
933 * Expression must be stored as a nodeToString result,
934 * but we also require a valid textual representation
935 * (mainly to make life easier for pg_dump).
938 deparse_expression(defaultExpr,
940 defaultValueBin = nodeToString(defaultExpr);
945 /* No default (can this still happen?) */
947 defaultValueBin = NULL;
952 if (nullDefined && !typNotNull)
954 (errcode(ERRCODE_SYNTAX_ERROR),
955 errmsg("conflicting NULL/NOT NULL constraints")));
961 if (nullDefined && typNotNull)
963 (errcode(ERRCODE_SYNTAX_ERROR),
964 errmsg("conflicting NULL/NOT NULL constraints")));
972 * Check constraints are handled after domain creation, as
973 * they require the Oid of the domain; at this point we can
974 * only check that they're not marked NO INHERIT, because that
977 if (constr->is_no_inherit)
979 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
980 errmsg("check constraints for domains cannot be marked NO INHERIT")));
984 * All else are error cases
988 (errcode(ERRCODE_SYNTAX_ERROR),
989 errmsg("unique constraints not possible for domains")));
994 (errcode(ERRCODE_SYNTAX_ERROR),
995 errmsg("primary key constraints not possible for domains")));
998 case CONSTR_EXCLUSION:
1000 (errcode(ERRCODE_SYNTAX_ERROR),
1001 errmsg("exclusion constraints not possible for domains")));
1004 case CONSTR_FOREIGN:
1006 (errcode(ERRCODE_SYNTAX_ERROR),
1007 errmsg("foreign key constraints not possible for domains")));
1010 case CONSTR_ATTR_DEFERRABLE:
1011 case CONSTR_ATTR_NOT_DEFERRABLE:
1012 case CONSTR_ATTR_DEFERRED:
1013 case CONSTR_ATTR_IMMEDIATE:
1015 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1016 errmsg("specifying constraint deferrability not supported for domains")));
1020 elog(ERROR, "unrecognized constraint subtype: %d",
1021 (int) constr->contype);
1027 * Have TypeCreate do all the real work.
1030 TypeCreate(InvalidOid, /* no predetermined type OID */
1031 domainName, /* type name */
1032 domainNamespace, /* namespace */
1033 InvalidOid, /* relation oid (n/a here) */
1034 0, /* relation kind (ditto) */
1035 GetUserId(), /* owner's ID */
1036 internalLength, /* internal size */
1037 TYPTYPE_DOMAIN, /* type-type (domain type) */
1038 category, /* type-category */
1039 false, /* domain types are never preferred */
1040 delimiter, /* array element delimiter */
1041 inputProcedure, /* input procedure */
1042 outputProcedure, /* output procedure */
1043 receiveProcedure, /* receive procedure */
1044 sendProcedure, /* send procedure */
1045 InvalidOid, /* typmodin procedure - none */
1046 InvalidOid, /* typmodout procedure - none */
1047 analyzeProcedure, /* analyze procedure */
1048 InvalidOid, /* no array element type */
1049 false, /* this isn't an array */
1050 InvalidOid, /* no arrays for domains (yet) */
1051 basetypeoid, /* base type ID */
1052 defaultValue, /* default type value (text) */
1053 defaultValueBin, /* default type value (binary) */
1054 byValue, /* passed by value */
1055 alignment, /* required alignment */
1056 storage, /* TOAST strategy */
1057 basetypeMod, /* typeMod value */
1058 typNDims, /* Array dimensions for base type */
1059 typNotNull, /* Type NOT NULL */
1060 domaincoll); /* type's collation */
1063 * Process constraints which refer to the domain ID returned by TypeCreate
1065 foreach(listptr, schema)
1067 Constraint *constr = lfirst(listptr);
1069 /* it must be a Constraint, per check above */
1071 switch (constr->contype)
1074 domainAddConstraint(address.objectId, domainNamespace,
1075 basetypeoid, basetypeMod,
1076 constr, domainName, NULL);
1079 /* Other constraint types were fully processed above */
1085 /* CCI so we can detect duplicate constraint names */
1086 CommandCounterIncrement();
1090 * Now we can clean up.
1092 ReleaseSysCache(typeTup);
1100 * Registers a new enum.
1103 DefineEnum(CreateEnumStmt *stmt)
1106 char *enumArrayName;
1108 AclResult aclresult;
1111 ObjectAddress enumTypeAddr;
1113 /* Convert list of names to a name and namespace */
1114 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1117 /* Check we have creation rights in target namespace */
1118 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1119 if (aclresult != ACLCHECK_OK)
1120 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1121 get_namespace_name(enumNamespace));
1124 * Check for collision with an existing type name. If there is one and
1125 * it's an autogenerated array, we can rename it out of the way.
1127 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1128 CStringGetDatum(enumName),
1129 ObjectIdGetDatum(enumNamespace));
1130 if (OidIsValid(old_type_oid))
1132 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1134 (errcode(ERRCODE_DUPLICATE_OBJECT),
1135 errmsg("type \"%s\" already exists", enumName)));
1138 enumArrayOid = AssignTypeArrayOid();
1140 /* Create the pg_type entry */
1142 TypeCreate(InvalidOid, /* no predetermined type OID */
1143 enumName, /* type name */
1144 enumNamespace, /* namespace */
1145 InvalidOid, /* relation oid (n/a here) */
1146 0, /* relation kind (ditto) */
1147 GetUserId(), /* owner's ID */
1148 sizeof(Oid), /* internal size */
1149 TYPTYPE_ENUM, /* type-type (enum type) */
1150 TYPCATEGORY_ENUM, /* type-category (enum type) */
1151 false, /* enum types are never preferred */
1152 DEFAULT_TYPDELIM, /* array element delimiter */
1153 F_ENUM_IN, /* input procedure */
1154 F_ENUM_OUT, /* output procedure */
1155 F_ENUM_RECV, /* receive procedure */
1156 F_ENUM_SEND, /* send procedure */
1157 InvalidOid, /* typmodin procedure - none */
1158 InvalidOid, /* typmodout procedure - none */
1159 InvalidOid, /* analyze procedure - default */
1160 InvalidOid, /* element type ID */
1161 false, /* this is not an array type */
1162 enumArrayOid, /* array type we are about to create */
1163 InvalidOid, /* base type ID (only for domains) */
1164 NULL, /* never a default type value */
1165 NULL, /* binary default isn't sent either */
1166 true, /* always passed by value */
1167 'i', /* int alignment */
1168 'p', /* TOAST strategy always plain */
1169 -1, /* typMod (Domains only) */
1170 0, /* Array dimensions of typbasetype */
1171 false, /* Type NOT NULL */
1172 InvalidOid); /* type's collation */
1174 /* Enter the enum's values into pg_enum */
1175 EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
1178 * Create the array type that goes with it.
1180 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1182 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1183 enumArrayName, /* type name */
1184 enumNamespace, /* namespace */
1185 InvalidOid, /* relation oid (n/a here) */
1186 0, /* relation kind (ditto) */
1187 GetUserId(), /* owner's ID */
1188 -1, /* internal size (always varlena) */
1189 TYPTYPE_BASE, /* type-type (base type) */
1190 TYPCATEGORY_ARRAY, /* type-category (array) */
1191 false, /* array types are never preferred */
1192 DEFAULT_TYPDELIM, /* array element delimiter */
1193 F_ARRAY_IN, /* input procedure */
1194 F_ARRAY_OUT, /* output procedure */
1195 F_ARRAY_RECV, /* receive procedure */
1196 F_ARRAY_SEND, /* send procedure */
1197 InvalidOid, /* typmodin procedure - none */
1198 InvalidOid, /* typmodout procedure - none */
1199 F_ARRAY_TYPANALYZE, /* analyze procedure */
1200 enumTypeAddr.objectId, /* element type ID */
1201 true, /* yes this is an array type */
1202 InvalidOid, /* no further array type */
1203 InvalidOid, /* base type ID */
1204 NULL, /* never a default type value */
1205 NULL, /* binary default isn't sent either */
1206 false, /* never passed by value */
1207 'i', /* enums have align i, so do their arrays */
1208 'x', /* ARRAY is always toastable */
1209 -1, /* typMod (Domains only) */
1210 0, /* Array dimensions of typbasetype */
1211 false, /* Type NOT NULL */
1212 InvalidOid); /* type's collation */
1214 pfree(enumArrayName);
1216 return enumTypeAddr;
1221 * Adds a new label to an existing enum.
1224 AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
1229 ObjectAddress address;
1231 /* Make a TypeName so we can use standard type lookup machinery */
1232 typename = makeTypeNameFromNameList(stmt->typeName);
1233 enum_type_oid = typenameTypeId(NULL, typename);
1235 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1236 if (!HeapTupleIsValid(tup))
1237 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1240 * Ordinarily we disallow adding values within transaction blocks, because
1241 * we can't cope with enum OID values getting into indexes and then having
1242 * their defining pg_enum entries go away. However, it's okay if the enum
1243 * type was created in the current transaction, since then there can be no
1244 * such indexes that wouldn't themselves go away on rollback. (We support
1245 * this case because pg_dump --binary-upgrade needs it.) We test this by
1246 * seeing if the pg_type row has xmin == current XID and is not
1247 * HEAP_UPDATED. If it is HEAP_UPDATED, we can't be sure whether the type
1248 * was created or only modified in this xact. So we are disallowing some
1249 * cases that could theoretically be safe; but fortunately pg_dump only
1250 * needs the simplest case.
1252 if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() &&
1253 !(tup->t_data->t_infomask & HEAP_UPDATED))
1254 /* safe to do inside transaction block */ ;
1256 PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD");
1258 /* Check it's an enum and check user has permission to ALTER the enum */
1259 checkEnumOwner(tup);
1261 /* Add the new label */
1262 AddEnumLabel(enum_type_oid, stmt->newVal,
1263 stmt->newValNeighbor, stmt->newValIsAfter,
1264 stmt->skipIfExists);
1266 InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1268 ObjectAddressSet(address, TypeRelationId, enum_type_oid);
1270 ReleaseSysCache(tup);
1279 * Check that the type is actually an enum and that the current user
1280 * has permission to do ALTER TYPE on it. Throw an error if not.
1283 checkEnumOwner(HeapTuple tup)
1285 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1287 /* Check that this is actually an enum */
1288 if (typTup->typtype != TYPTYPE_ENUM)
1290 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1291 errmsg("%s is not an enum",
1292 format_type_be(HeapTupleGetOid(tup)))));
1294 /* Permission check: must own type */
1295 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1296 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
1302 * Registers a new range type.
1305 DefineRange(CreateRangeStmt *stmt)
1310 char *rangeArrayName;
1312 Oid rangeSubtype = InvalidOid;
1313 List *rangeSubOpclassName = NIL;
1314 List *rangeCollationName = NIL;
1315 List *rangeCanonicalName = NIL;
1316 List *rangeSubtypeDiffName = NIL;
1317 Oid rangeSubOpclass;
1319 regproc rangeCanonical;
1320 regproc rangeSubtypeDiff;
1325 AclResult aclresult;
1327 ObjectAddress address;
1329 /* Convert list of names to a name and namespace */
1330 typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1333 /* Check we have creation rights in target namespace */
1334 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1335 if (aclresult != ACLCHECK_OK)
1336 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1337 get_namespace_name(typeNamespace));
1340 * Look to see if type already exists.
1342 typoid = GetSysCacheOid2(TYPENAMENSP,
1343 CStringGetDatum(typeName),
1344 ObjectIdGetDatum(typeNamespace));
1347 * If it's not a shell, see if it's an autogenerated array type, and if so
1348 * rename it out of the way.
1350 if (OidIsValid(typoid) && get_typisdefined(typoid))
1352 if (moveArrayTypeName(typoid, typeName, typeNamespace))
1353 typoid = InvalidOid;
1356 (errcode(ERRCODE_DUPLICATE_OBJECT),
1357 errmsg("type \"%s\" already exists", typeName)));
1361 * If it doesn't exist, create it as a shell, so that the OID is known for
1362 * use in the range function definitions.
1364 if (!OidIsValid(typoid))
1366 address = TypeShellMake(typeName, typeNamespace, GetUserId());
1367 typoid = address.objectId;
1368 /* Make new shell type visible for modification below */
1369 CommandCounterIncrement();
1372 /* Extract the parameters from the parameter list */
1373 foreach(lc, stmt->params)
1375 DefElem *defel = (DefElem *) lfirst(lc);
1377 if (pg_strcasecmp(defel->defname, "subtype") == 0)
1379 if (OidIsValid(rangeSubtype))
1381 (errcode(ERRCODE_SYNTAX_ERROR),
1382 errmsg("conflicting or redundant options")));
1383 /* we can look up the subtype name immediately */
1384 rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1386 else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
1388 if (rangeSubOpclassName != NIL)
1390 (errcode(ERRCODE_SYNTAX_ERROR),
1391 errmsg("conflicting or redundant options")));
1392 rangeSubOpclassName = defGetQualifiedName(defel);
1394 else if (pg_strcasecmp(defel->defname, "collation") == 0)
1396 if (rangeCollationName != NIL)
1398 (errcode(ERRCODE_SYNTAX_ERROR),
1399 errmsg("conflicting or redundant options")));
1400 rangeCollationName = defGetQualifiedName(defel);
1402 else if (pg_strcasecmp(defel->defname, "canonical") == 0)
1404 if (rangeCanonicalName != NIL)
1406 (errcode(ERRCODE_SYNTAX_ERROR),
1407 errmsg("conflicting or redundant options")));
1408 rangeCanonicalName = defGetQualifiedName(defel);
1410 else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
1412 if (rangeSubtypeDiffName != NIL)
1414 (errcode(ERRCODE_SYNTAX_ERROR),
1415 errmsg("conflicting or redundant options")));
1416 rangeSubtypeDiffName = defGetQualifiedName(defel);
1420 (errcode(ERRCODE_SYNTAX_ERROR),
1421 errmsg("type attribute \"%s\" not recognized",
1425 /* Must have a subtype */
1426 if (!OidIsValid(rangeSubtype))
1428 (errcode(ERRCODE_SYNTAX_ERROR),
1429 errmsg("type attribute \"subtype\" is required")));
1430 /* disallow ranges of pseudotypes */
1431 if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
1433 (errcode(ERRCODE_DATATYPE_MISMATCH),
1434 errmsg("range subtype cannot be %s",
1435 format_type_be(rangeSubtype))));
1437 /* Identify subopclass */
1438 rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1440 /* Identify collation to use, if any */
1441 if (type_is_collatable(rangeSubtype))
1443 if (rangeCollationName != NIL)
1444 rangeCollation = get_collation_oid(rangeCollationName, false);
1446 rangeCollation = get_typcollation(rangeSubtype);
1450 if (rangeCollationName != NIL)
1452 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1453 errmsg("range collation specified but subtype does not support collation")));
1454 rangeCollation = InvalidOid;
1457 /* Identify support functions, if provided */
1458 if (rangeCanonicalName != NIL)
1459 rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1462 rangeCanonical = InvalidOid;
1464 if (rangeSubtypeDiffName != NIL)
1465 rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1468 rangeSubtypeDiff = InvalidOid;
1470 get_typlenbyvalalign(rangeSubtype,
1471 &subtyplen, &subtypbyval, &subtypalign);
1473 /* alignment must be 'i' or 'd' for ranges */
1474 alignment = (subtypalign == 'd') ? 'd' : 'i';
1476 /* Allocate OID for array type */
1477 rangeArrayOid = AssignTypeArrayOid();
1479 /* Create the pg_type entry */
1481 TypeCreate(InvalidOid, /* no predetermined type OID */
1482 typeName, /* type name */
1483 typeNamespace, /* namespace */
1484 InvalidOid, /* relation oid (n/a here) */
1485 0, /* relation kind (ditto) */
1486 GetUserId(), /* owner's ID */
1487 -1, /* internal size (always varlena) */
1488 TYPTYPE_RANGE, /* type-type (range type) */
1489 TYPCATEGORY_RANGE, /* type-category (range type) */
1490 false, /* range types are never preferred */
1491 DEFAULT_TYPDELIM, /* array element delimiter */
1492 F_RANGE_IN, /* input procedure */
1493 F_RANGE_OUT, /* output procedure */
1494 F_RANGE_RECV, /* receive procedure */
1495 F_RANGE_SEND, /* send procedure */
1496 InvalidOid, /* typmodin procedure - none */
1497 InvalidOid, /* typmodout procedure - none */
1498 F_RANGE_TYPANALYZE, /* analyze procedure */
1499 InvalidOid, /* element type ID - none */
1500 false, /* this is not an array type */
1501 rangeArrayOid, /* array type we are about to create */
1502 InvalidOid, /* base type ID (only for domains) */
1503 NULL, /* never a default type value */
1504 NULL, /* no binary form available either */
1505 false, /* never passed by value */
1506 alignment, /* alignment */
1507 'x', /* TOAST strategy (always extended) */
1508 -1, /* typMod (Domains only) */
1509 0, /* Array dimensions of typbasetype */
1510 false, /* Type NOT NULL */
1511 InvalidOid); /* type's collation (ranges never have one) */
1512 Assert(typoid == address.objectId);
1514 /* Create the entry in pg_range */
1515 RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1516 rangeCanonical, rangeSubtypeDiff);
1519 * Create the array type that goes with it.
1521 rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1523 TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1524 rangeArrayName, /* type name */
1525 typeNamespace, /* namespace */
1526 InvalidOid, /* relation oid (n/a here) */
1527 0, /* relation kind (ditto) */
1528 GetUserId(), /* owner's ID */
1529 -1, /* internal size (always varlena) */
1530 TYPTYPE_BASE, /* type-type (base type) */
1531 TYPCATEGORY_ARRAY, /* type-category (array) */
1532 false, /* array types are never preferred */
1533 DEFAULT_TYPDELIM, /* array element delimiter */
1534 F_ARRAY_IN, /* input procedure */
1535 F_ARRAY_OUT, /* output procedure */
1536 F_ARRAY_RECV, /* receive procedure */
1537 F_ARRAY_SEND, /* send procedure */
1538 InvalidOid, /* typmodin procedure - none */
1539 InvalidOid, /* typmodout procedure - none */
1540 F_ARRAY_TYPANALYZE, /* analyze procedure */
1541 typoid, /* element type ID */
1542 true, /* yes this is an array type */
1543 InvalidOid, /* no further array type */
1544 InvalidOid, /* base type ID */
1545 NULL, /* never a default type value */
1546 NULL, /* binary default isn't sent either */
1547 false, /* never passed by value */
1548 alignment, /* alignment - same as range's */
1549 'x', /* ARRAY is always toastable */
1550 -1, /* typMod (Domains only) */
1551 0, /* Array dimensions of typbasetype */
1552 false, /* Type NOT NULL */
1553 InvalidOid); /* typcollation */
1555 pfree(rangeArrayName);
1557 /* And create the constructor functions for this range type */
1558 makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1564 * Because there may exist several range types over the same subtype, the
1565 * range type can't be uniquely determined from the subtype. So it's
1566 * impossible to define a polymorphic constructor; we have to generate new
1567 * constructor functions explicitly for each range type.
1569 * We actually define 4 functions, with 0 through 3 arguments. This is just
1570 * to offer more convenience for the user.
1573 makeRangeConstructors(const char *name, Oid namespace,
1574 Oid rangeOid, Oid subtype)
1576 static const char *const prosrc[2] = {"range_constructor2",
1577 "range_constructor3"};
1578 static const int pronargs[2] = {2, 3};
1580 Oid constructorArgTypes[3];
1581 ObjectAddress myself,
1585 constructorArgTypes[0] = subtype;
1586 constructorArgTypes[1] = subtype;
1587 constructorArgTypes[2] = TEXTOID;
1589 referenced.classId = TypeRelationId;
1590 referenced.objectId = rangeOid;
1591 referenced.objectSubId = 0;
1593 for (i = 0; i < lengthof(prosrc); i++)
1595 oidvector *constructorArgTypesVector;
1597 constructorArgTypesVector = buildoidvector(constructorArgTypes,
1600 myself = ProcedureCreate(name, /* name: same as range type */
1601 namespace, /* namespace */
1602 false, /* replace */
1603 false, /* returns set */
1604 rangeOid, /* return type */
1605 BOOTSTRAP_SUPERUSERID, /* proowner */
1606 INTERNALlanguageId, /* language */
1607 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1608 prosrc[i], /* prosrc */
1611 false, /* isWindowFunc */
1612 false, /* security_definer */
1613 false, /* leakproof */
1614 false, /* isStrict */
1615 PROVOLATILE_IMMUTABLE, /* volatility */
1616 PROPARALLEL_SAFE, /* parallel safety */
1617 constructorArgTypesVector, /* parameterTypes */
1618 PointerGetDatum(NULL), /* allParameterTypes */
1619 PointerGetDatum(NULL), /* parameterModes */
1620 PointerGetDatum(NULL), /* parameterNames */
1621 NIL, /* parameterDefaults */
1622 PointerGetDatum(NULL), /* trftypes */
1623 PointerGetDatum(NULL), /* proconfig */
1628 * Make the constructors internally-dependent on the range type so
1629 * that they go away silently when the type is dropped. Note that
1630 * pg_dump depends on this choice to avoid dumping the constructors.
1632 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1638 * Find suitable I/O functions for a type.
1640 * typeOid is the type's OID (which will already exist, if only as a shell
1645 findTypeInputFunction(List *procname, Oid typeOid)
1651 * Input functions can take a single argument of type CSTRING, or three
1652 * arguments (string, typioparam OID, typmod).
1654 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1655 * see this, we issue a warning and fix up the pg_proc entry.
1657 argList[0] = CSTRINGOID;
1659 procOid = LookupFuncName(procname, 1, argList, true);
1660 if (OidIsValid(procOid))
1663 argList[1] = OIDOID;
1664 argList[2] = INT4OID;
1666 procOid = LookupFuncName(procname, 3, argList, true);
1667 if (OidIsValid(procOid))
1670 /* No luck, try it with OPAQUE */
1671 argList[0] = OPAQUEOID;
1673 procOid = LookupFuncName(procname, 1, argList, true);
1675 if (!OidIsValid(procOid))
1677 argList[1] = OIDOID;
1678 argList[2] = INT4OID;
1680 procOid = LookupFuncName(procname, 3, argList, true);
1683 if (OidIsValid(procOid))
1685 /* Found, but must complain and fix the pg_proc entry */
1687 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1688 NameListToString(procname))));
1689 SetFunctionArgType(procOid, 0, CSTRINGOID);
1692 * Need CommandCounterIncrement since DefineType will likely try to
1693 * alter the pg_proc tuple again.
1695 CommandCounterIncrement();
1700 /* Use CSTRING (preferred) in the error message */
1701 argList[0] = CSTRINGOID;
1704 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1705 errmsg("function %s does not exist",
1706 func_signature_string(procname, 1, NIL, argList))));
1708 return InvalidOid; /* keep compiler quiet */
1712 findTypeOutputFunction(List *procname, Oid typeOid)
1718 * Output functions can take a single argument of the type.
1720 * For backwards compatibility we allow OPAQUE in place of the actual type
1721 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1723 argList[0] = typeOid;
1725 procOid = LookupFuncName(procname, 1, argList, true);
1726 if (OidIsValid(procOid))
1729 /* No luck, try it with OPAQUE */
1730 argList[0] = OPAQUEOID;
1732 procOid = LookupFuncName(procname, 1, argList, true);
1734 if (OidIsValid(procOid))
1736 /* Found, but must complain and fix the pg_proc entry */
1738 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1739 NameListToString(procname), format_type_be(typeOid))));
1740 SetFunctionArgType(procOid, 0, typeOid);
1743 * Need CommandCounterIncrement since DefineType will likely try to
1744 * alter the pg_proc tuple again.
1746 CommandCounterIncrement();
1751 /* Use type name, not OPAQUE, in the failure message. */
1752 argList[0] = typeOid;
1755 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1756 errmsg("function %s does not exist",
1757 func_signature_string(procname, 1, NIL, argList))));
1759 return InvalidOid; /* keep compiler quiet */
1763 findTypeReceiveFunction(List *procname, Oid typeOid)
1769 * Receive functions can take a single argument of type INTERNAL, or three
1770 * arguments (internal, typioparam OID, typmod).
1772 argList[0] = INTERNALOID;
1774 procOid = LookupFuncName(procname, 1, argList, true);
1775 if (OidIsValid(procOid))
1778 argList[1] = OIDOID;
1779 argList[2] = INT4OID;
1781 procOid = LookupFuncName(procname, 3, argList, true);
1782 if (OidIsValid(procOid))
1786 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1787 errmsg("function %s does not exist",
1788 func_signature_string(procname, 1, NIL, argList))));
1790 return InvalidOid; /* keep compiler quiet */
1794 findTypeSendFunction(List *procname, Oid typeOid)
1800 * Send functions can take a single argument of the type.
1802 argList[0] = typeOid;
1804 procOid = LookupFuncName(procname, 1, argList, true);
1805 if (OidIsValid(procOid))
1809 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1810 errmsg("function %s does not exist",
1811 func_signature_string(procname, 1, NIL, argList))));
1813 return InvalidOid; /* keep compiler quiet */
1817 findTypeTypmodinFunction(List *procname)
1823 * typmodin functions always take one cstring[] argument and return int4.
1825 argList[0] = CSTRINGARRAYOID;
1827 procOid = LookupFuncName(procname, 1, argList, true);
1828 if (!OidIsValid(procOid))
1830 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1831 errmsg("function %s does not exist",
1832 func_signature_string(procname, 1, NIL, argList))));
1834 if (get_func_rettype(procOid) != INT4OID)
1836 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1837 errmsg("typmod_in function %s must return type \"%s\"",
1838 NameListToString(procname), "integer")));
1844 findTypeTypmodoutFunction(List *procname)
1850 * typmodout functions always take one int4 argument and return cstring.
1852 argList[0] = INT4OID;
1854 procOid = LookupFuncName(procname, 1, argList, true);
1855 if (!OidIsValid(procOid))
1857 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1858 errmsg("function %s does not exist",
1859 func_signature_string(procname, 1, NIL, argList))));
1861 if (get_func_rettype(procOid) != CSTRINGOID)
1863 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1864 errmsg("typmod_out function %s must return type \"%s\"",
1865 NameListToString(procname), "cstring")));
1871 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1877 * Analyze functions always take one INTERNAL argument and return bool.
1879 argList[0] = INTERNALOID;
1881 procOid = LookupFuncName(procname, 1, argList, true);
1882 if (!OidIsValid(procOid))
1884 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1885 errmsg("function %s does not exist",
1886 func_signature_string(procname, 1, NIL, argList))));
1888 if (get_func_rettype(procOid) != BOOLOID)
1890 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1891 errmsg("type analyze function %s must return type \"%s\"",
1892 NameListToString(procname), "boolean")));
1898 * Find suitable support functions and opclasses for a range type.
1902 * Find named btree opclass for subtype, or default btree opclass if
1906 findRangeSubOpclass(List *opcname, Oid subtype)
1913 opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
1916 * Verify that the operator class accepts this datatype. Note we will
1917 * accept binary compatibility.
1919 opInputType = get_opclass_input_type(opcid);
1920 if (!IsBinaryCoercible(subtype, opInputType))
1922 (errcode(ERRCODE_DATATYPE_MISMATCH),
1923 errmsg("operator class \"%s\" does not accept data type %s",
1924 NameListToString(opcname),
1925 format_type_be(subtype))));
1929 opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
1930 if (!OidIsValid(opcid))
1932 /* We spell the error message identically to GetIndexOpClass */
1934 (errcode(ERRCODE_UNDEFINED_OBJECT),
1935 errmsg("data type %s has no default operator class for access method \"%s\"",
1936 format_type_be(subtype), "btree"),
1937 errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
1945 findRangeCanonicalFunction(List *procname, Oid typeOid)
1949 AclResult aclresult;
1952 * Range canonical functions must take and return the range type, and must
1955 argList[0] = typeOid;
1957 procOid = LookupFuncName(procname, 1, argList, true);
1959 if (!OidIsValid(procOid))
1961 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1962 errmsg("function %s does not exist",
1963 func_signature_string(procname, 1, NIL, argList))));
1965 if (get_func_rettype(procOid) != typeOid)
1967 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1968 errmsg("range canonical function %s must return range type",
1969 func_signature_string(procname, 1, NIL, argList))));
1971 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1973 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1974 errmsg("range canonical function %s must be immutable",
1975 func_signature_string(procname, 1, NIL, argList))));
1977 /* Also, range type's creator must have permission to call function */
1978 aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
1979 if (aclresult != ACLCHECK_OK)
1980 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
1986 findRangeSubtypeDiffFunction(List *procname, Oid subtype)
1990 AclResult aclresult;
1993 * Range subtype diff functions must take two arguments of the subtype,
1994 * must return float8, and must be immutable.
1996 argList[0] = subtype;
1997 argList[1] = subtype;
1999 procOid = LookupFuncName(procname, 2, argList, true);
2001 if (!OidIsValid(procOid))
2003 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2004 errmsg("function %s does not exist",
2005 func_signature_string(procname, 2, NIL, argList))));
2007 if (get_func_rettype(procOid) != FLOAT8OID)
2009 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2010 errmsg("range subtype diff function %s must return type \"%s\"",
2011 func_signature_string(procname, 2, NIL, argList),
2012 "double precision")));
2014 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2016 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2017 errmsg("range subtype diff function %s must be immutable",
2018 func_signature_string(procname, 2, NIL, argList))));
2020 /* Also, range type's creator must have permission to call function */
2021 aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
2022 if (aclresult != ACLCHECK_OK)
2023 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
2029 * AssignTypeArrayOid
2031 * Pre-assign the type's array OID for use in pg_type.typarray
2034 AssignTypeArrayOid(void)
2038 /* Use binary-upgrade override for pg_type.typarray? */
2039 if (IsBinaryUpgrade)
2041 if (!OidIsValid(binary_upgrade_next_array_pg_type_oid))
2043 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2044 errmsg("pg_type array OID value not set when in binary upgrade mode")));
2046 type_array_oid = binary_upgrade_next_array_pg_type_oid;
2047 binary_upgrade_next_array_pg_type_oid = InvalidOid;
2051 Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
2053 type_array_oid = GetNewOid(pg_type);
2054 heap_close(pg_type, AccessShareLock);
2057 return type_array_oid;
2061 /*-------------------------------------------------------------------
2062 * DefineCompositeType
2064 * Create a Composite Type relation.
2065 * `DefineRelation' does all the work, we just provide the correct
2068 * If the relation already exists, then 'DefineRelation' will abort
2071 * Return type is the new type's object address.
2072 *-------------------------------------------------------------------
2075 DefineCompositeType(RangeVar *typevar, List *coldeflist)
2077 CreateStmt *createStmt = makeNode(CreateStmt);
2080 ObjectAddress address;
2083 * now set the parameters for keys/inheritance etc. All of these are
2084 * uninteresting for composite types...
2086 createStmt->relation = typevar;
2087 createStmt->tableElts = coldeflist;
2088 createStmt->inhRelations = NIL;
2089 createStmt->constraints = NIL;
2090 createStmt->options = NIL;
2091 createStmt->oncommit = ONCOMMIT_NOOP;
2092 createStmt->tablespacename = NULL;
2093 createStmt->if_not_exists = false;
2096 * Check for collision with an existing type name. If there is one and
2097 * it's an autogenerated array, we can rename it out of the way. This
2098 * check is here mainly to get a better error message about a "type"
2099 * instead of below about a "relation".
2101 typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2103 RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2105 GetSysCacheOid2(TYPENAMENSP,
2106 CStringGetDatum(createStmt->relation->relname),
2107 ObjectIdGetDatum(typeNamespace));
2108 if (OidIsValid(old_type_oid))
2110 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2112 (errcode(ERRCODE_DUPLICATE_OBJECT),
2113 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2117 * Finally create the relation. This also creates the type.
2119 DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address);
2125 * AlterDomainDefault
2127 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
2129 * Returns ObjectAddress of the modified domain.
2132 AlterDomainDefault(List *names, Node *defaultRaw)
2140 Node *defaultExpr = NULL; /* NULL if no default specified */
2141 Datum new_record[Natts_pg_type];
2142 bool new_record_nulls[Natts_pg_type];
2143 bool new_record_repl[Natts_pg_type];
2145 Form_pg_type typTup;
2146 ObjectAddress address;
2148 /* Make a TypeName so we can use standard type lookup machinery */
2149 typename = makeTypeNameFromNameList(names);
2150 domainoid = typenameTypeId(NULL, typename);
2152 /* Look up the domain in the type table */
2153 rel = heap_open(TypeRelationId, RowExclusiveLock);
2155 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2156 if (!HeapTupleIsValid(tup))
2157 elog(ERROR, "cache lookup failed for type %u", domainoid);
2158 typTup = (Form_pg_type) GETSTRUCT(tup);
2160 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2161 checkDomainOwner(tup);
2163 /* Setup new tuple */
2164 MemSet(new_record, (Datum) 0, sizeof(new_record));
2165 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2166 MemSet(new_record_repl, false, sizeof(new_record_repl));
2168 /* Store the new default into the tuple */
2171 /* Create a dummy ParseState for transformExpr */
2172 pstate = make_parsestate(NULL);
2175 * Cook the colDef->raw_expr into an expression. Note: Name is
2176 * strictly for error message
2178 defaultExpr = cookDefault(pstate, defaultRaw,
2179 typTup->typbasetype,
2181 NameStr(typTup->typname));
2184 * If the expression is just a NULL constant, we treat the command
2185 * like ALTER ... DROP DEFAULT. (But see note for same test in
2188 if (defaultExpr == NULL ||
2189 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
2191 /* Default is NULL, drop it */
2192 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2193 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2194 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2195 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2200 * Expression must be stored as a nodeToString result, but we also
2201 * require a valid textual representation (mainly to make life
2202 * easier for pg_dump).
2204 defaultValue = deparse_expression(defaultExpr,
2208 * Form an updated tuple with the new default and write it back.
2210 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2212 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2213 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2214 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2219 /* ALTER ... DROP DEFAULT */
2220 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2221 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2222 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2223 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2226 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2227 new_record, new_record_nulls,
2230 simple_heap_update(rel, &tup->t_self, newtuple);
2232 CatalogUpdateIndexes(rel, newtuple);
2234 /* Rebuild dependencies */
2235 GenerateTypeDependencies(typTup->typnamespace,
2237 InvalidOid, /* typrelid is n/a */
2238 0, /* relation kind is n/a */
2248 false, /* a domain isn't an implicit array */
2249 typTup->typbasetype,
2250 typTup->typcollation,
2252 true); /* Rebuild is true */
2254 InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2256 ObjectAddressSet(address, TypeRelationId, domainoid);
2259 heap_close(rel, NoLock);
2260 heap_freetuple(newtuple);
2266 * AlterDomainNotNull
2268 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2270 * Returns ObjectAddress of the modified domain.
2273 AlterDomainNotNull(List *names, bool notNull)
2279 Form_pg_type typTup;
2280 ObjectAddress address = InvalidObjectAddress;
2282 /* Make a TypeName so we can use standard type lookup machinery */
2283 typename = makeTypeNameFromNameList(names);
2284 domainoid = typenameTypeId(NULL, typename);
2286 /* Look up the domain in the type table */
2287 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2289 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2290 if (!HeapTupleIsValid(tup))
2291 elog(ERROR, "cache lookup failed for type %u", domainoid);
2292 typTup = (Form_pg_type) GETSTRUCT(tup);
2294 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2295 checkDomainOwner(tup);
2297 /* Is the domain already set to the desired constraint? */
2298 if (typTup->typnotnull == notNull)
2300 heap_close(typrel, RowExclusiveLock);
2304 /* Adding a NOT NULL constraint requires checking existing columns */
2310 /* Fetch relation list with attributes based on this domain */
2311 /* ShareLock is sufficient to prevent concurrent data changes */
2313 rels = get_rels_with_domain(domainoid, ShareLock);
2317 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2318 Relation testrel = rtc->rel;
2319 TupleDesc tupdesc = RelationGetDescr(testrel);
2324 /* Scan all tuples in this relation */
2325 snapshot = RegisterSnapshot(GetLatestSnapshot());
2326 scan = heap_beginscan(testrel, snapshot, 0, NULL);
2327 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2331 /* Test attributes that are of the domain */
2332 for (i = 0; i < rtc->natts; i++)
2334 int attnum = rtc->atts[i];
2336 if (heap_attisnull(tuple, attnum))
2339 * In principle the auxiliary information for this
2340 * error should be errdatatype(), but errtablecol()
2341 * seems considerably more useful in practice. Since
2342 * this code only executes in an ALTER DOMAIN command,
2343 * the client should already know which domain is in
2347 (errcode(ERRCODE_NOT_NULL_VIOLATION),
2348 errmsg("column \"%s\" of table \"%s\" contains null values",
2349 NameStr(tupdesc->attrs[attnum - 1]->attname),
2350 RelationGetRelationName(testrel)),
2351 errtablecol(testrel, attnum)));
2356 UnregisterSnapshot(snapshot);
2358 /* Close each rel after processing, but keep lock */
2359 heap_close(testrel, NoLock);
2364 * Okay to update pg_type row. We can scribble on typTup because it's a
2367 typTup->typnotnull = notNull;
2369 simple_heap_update(typrel, &tup->t_self, tup);
2371 CatalogUpdateIndexes(typrel, tup);
2373 InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2375 ObjectAddressSet(address, TypeRelationId, domainoid);
2378 heap_freetuple(tup);
2379 heap_close(typrel, RowExclusiveLock);
2385 * AlterDomainDropConstraint
2387 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2390 AlterDomainDropConstraint(List *names, const char *constrName,
2391 DropBehavior behavior, bool missing_ok)
2398 SysScanDesc conscan;
2402 ObjectAddress address = InvalidObjectAddress;
2404 /* Make a TypeName so we can use standard type lookup machinery */
2405 typename = makeTypeNameFromNameList(names);
2406 domainoid = typenameTypeId(NULL, typename);
2408 /* Look up the domain in the type table */
2409 rel = heap_open(TypeRelationId, RowExclusiveLock);
2411 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2412 if (!HeapTupleIsValid(tup))
2413 elog(ERROR, "cache lookup failed for type %u", domainoid);
2415 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2416 checkDomainOwner(tup);
2418 /* Grab an appropriate lock on the pg_constraint relation */
2419 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2421 /* Use the index to scan only constraints of the target relation */
2422 ScanKeyInit(&key[0],
2423 Anum_pg_constraint_contypid,
2424 BTEqualStrategyNumber, F_OIDEQ,
2425 ObjectIdGetDatum(HeapTupleGetOid(tup)));
2427 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2431 * Scan over the result set, removing any matching entries.
2433 while ((contup = systable_getnext(conscan)) != NULL)
2435 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
2437 if (strcmp(NameStr(con->conname), constrName) == 0)
2439 ObjectAddress conobj;
2441 conobj.classId = ConstraintRelationId;
2442 conobj.objectId = HeapTupleGetOid(contup);
2443 conobj.objectSubId = 0;
2445 performDeletion(&conobj, behavior, 0);
2450 ObjectAddressSet(address, TypeRelationId, domainoid);
2452 /* Clean up after the scan */
2453 systable_endscan(conscan);
2454 heap_close(conrel, RowExclusiveLock);
2456 heap_close(rel, NoLock);
2462 (errcode(ERRCODE_UNDEFINED_OBJECT),
2463 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2464 constrName, TypeNameToString(typename))));
2467 (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2468 constrName, TypeNameToString(typename))));
2475 * AlterDomainAddConstraint
2477 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2480 AlterDomainAddConstraint(List *names, Node *newConstraint,
2481 ObjectAddress *constrAddr)
2487 Form_pg_type typTup;
2490 ObjectAddress address;
2492 /* Make a TypeName so we can use standard type lookup machinery */
2493 typename = makeTypeNameFromNameList(names);
2494 domainoid = typenameTypeId(NULL, typename);
2496 /* Look up the domain in the type table */
2497 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2499 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2500 if (!HeapTupleIsValid(tup))
2501 elog(ERROR, "cache lookup failed for type %u", domainoid);
2502 typTup = (Form_pg_type) GETSTRUCT(tup);
2504 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2505 checkDomainOwner(tup);
2507 if (!IsA(newConstraint, Constraint))
2508 elog(ERROR, "unrecognized node type: %d",
2509 (int) nodeTag(newConstraint));
2511 constr = (Constraint *) newConstraint;
2513 switch (constr->contype)
2516 /* processed below */
2521 (errcode(ERRCODE_SYNTAX_ERROR),
2522 errmsg("unique constraints not possible for domains")));
2525 case CONSTR_PRIMARY:
2527 (errcode(ERRCODE_SYNTAX_ERROR),
2528 errmsg("primary key constraints not possible for domains")));
2531 case CONSTR_EXCLUSION:
2533 (errcode(ERRCODE_SYNTAX_ERROR),
2534 errmsg("exclusion constraints not possible for domains")));
2537 case CONSTR_FOREIGN:
2539 (errcode(ERRCODE_SYNTAX_ERROR),
2540 errmsg("foreign key constraints not possible for domains")));
2543 case CONSTR_ATTR_DEFERRABLE:
2544 case CONSTR_ATTR_NOT_DEFERRABLE:
2545 case CONSTR_ATTR_DEFERRED:
2546 case CONSTR_ATTR_IMMEDIATE:
2548 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2549 errmsg("specifying constraint deferrability not supported for domains")));
2553 elog(ERROR, "unrecognized constraint subtype: %d",
2554 (int) constr->contype);
2559 * Since all other constraint types throw errors, this must be a check
2560 * constraint. First, process the constraint expression and add an entry
2564 ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
2565 typTup->typbasetype, typTup->typtypmod,
2566 constr, NameStr(typTup->typname), constrAddr);
2569 * If requested to validate the constraint, test all values stored in the
2570 * attributes based on the domain the constraint is being added to.
2572 if (!constr->skip_validation)
2573 validateDomainConstraint(domainoid, ccbin);
2575 ObjectAddressSet(address, TypeRelationId, domainoid);
2578 heap_close(typrel, RowExclusiveLock);
2584 * AlterDomainValidateConstraint
2586 * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
2589 AlterDomainValidateConstraint(List *names, char *constrName)
2596 Form_pg_constraint con = NULL;
2597 Form_pg_constraint copy_con;
2604 HeapTuple copyTuple;
2606 ObjectAddress address;
2608 /* Make a TypeName so we can use standard type lookup machinery */
2609 typename = makeTypeNameFromNameList(names);
2610 domainoid = typenameTypeId(NULL, typename);
2612 /* Look up the domain in the type table */
2613 typrel = heap_open(TypeRelationId, AccessShareLock);
2615 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2616 if (!HeapTupleIsValid(tup))
2617 elog(ERROR, "cache lookup failed for type %u", domainoid);
2619 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2620 checkDomainOwner(tup);
2623 * Find and check the target constraint
2625 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2627 Anum_pg_constraint_contypid,
2628 BTEqualStrategyNumber, F_OIDEQ,
2629 ObjectIdGetDatum(domainoid));
2630 scan = systable_beginscan(conrel, ConstraintTypidIndexId,
2631 true, NULL, 1, &key);
2633 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2635 con = (Form_pg_constraint) GETSTRUCT(tuple);
2636 if (strcmp(NameStr(con->conname), constrName) == 0)
2645 (errcode(ERRCODE_UNDEFINED_OBJECT),
2646 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2647 constrName, TypeNameToString(typename))));
2649 if (con->contype != CONSTRAINT_CHECK)
2651 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2652 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2653 constrName, TypeNameToString(typename))));
2655 val = SysCacheGetAttr(CONSTROID, tuple,
2656 Anum_pg_constraint_conbin,
2659 elog(ERROR, "null conbin for constraint %u",
2660 HeapTupleGetOid(tuple));
2661 conbin = TextDatumGetCString(val);
2663 validateDomainConstraint(domainoid, conbin);
2666 * Now update the catalog, while we have the door open.
2668 copyTuple = heap_copytuple(tuple);
2669 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2670 copy_con->convalidated = true;
2671 simple_heap_update(conrel, ©Tuple->t_self, copyTuple);
2672 CatalogUpdateIndexes(conrel, copyTuple);
2674 InvokeObjectPostAlterHook(ConstraintRelationId,
2675 HeapTupleGetOid(copyTuple), 0);
2677 ObjectAddressSet(address, TypeRelationId, domainoid);
2679 heap_freetuple(copyTuple);
2681 systable_endscan(scan);
2683 heap_close(typrel, AccessShareLock);
2684 heap_close(conrel, RowExclusiveLock);
2686 ReleaseSysCache(tup);
2692 validateDomainConstraint(Oid domainoid, char *ccbin)
2694 Expr *expr = (Expr *) stringToNode(ccbin);
2698 ExprContext *econtext;
2699 ExprState *exprstate;
2701 /* Need an EState to run ExecEvalExpr */
2702 estate = CreateExecutorState();
2703 econtext = GetPerTupleExprContext(estate);
2705 /* build execution state for expr */
2706 exprstate = ExecPrepareExpr(expr, estate);
2708 /* Fetch relation list with attributes based on this domain */
2709 /* ShareLock is sufficient to prevent concurrent data changes */
2711 rels = get_rels_with_domain(domainoid, ShareLock);
2715 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2716 Relation testrel = rtc->rel;
2717 TupleDesc tupdesc = RelationGetDescr(testrel);
2722 /* Scan all tuples in this relation */
2723 snapshot = RegisterSnapshot(GetLatestSnapshot());
2724 scan = heap_beginscan(testrel, snapshot, 0, NULL);
2725 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2729 /* Test attributes that are of the domain */
2730 for (i = 0; i < rtc->natts; i++)
2732 int attnum = rtc->atts[i];
2737 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2739 econtext->domainValue_datum = d;
2740 econtext->domainValue_isNull = isNull;
2742 conResult = ExecEvalExprSwitchContext(exprstate,
2746 if (!isNull && !DatumGetBool(conResult))
2749 * In principle the auxiliary information for this error
2750 * should be errdomainconstraint(), but errtablecol()
2751 * seems considerably more useful in practice. Since this
2752 * code only executes in an ALTER DOMAIN command, the
2753 * client should already know which domain is in question,
2754 * and which constraint too.
2757 (errcode(ERRCODE_CHECK_VIOLATION),
2758 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2759 NameStr(tupdesc->attrs[attnum - 1]->attname),
2760 RelationGetRelationName(testrel)),
2761 errtablecol(testrel, attnum)));
2765 ResetExprContext(econtext);
2768 UnregisterSnapshot(snapshot);
2770 /* Hold relation lock till commit (XXX bad for concurrency) */
2771 heap_close(testrel, NoLock);
2774 FreeExecutorState(estate);
2778 * get_rels_with_domain
2780 * Fetch all relations / attributes which are using the domain
2782 * The result is a list of RelToCheck structs, one for each distinct
2783 * relation, each containing one or more attribute numbers that are of
2784 * the domain type. We have opened each rel and acquired the specified lock
2787 * We support nested domains by including attributes that are of derived
2788 * domain types. Current callers do not need to distinguish between attributes
2789 * that are of exactly the given domain and those that are of derived domains.
2791 * XXX this is completely broken because there is no way to lock the domain
2792 * to prevent columns from being added or dropped while our command runs.
2793 * We can partially protect against column drops by locking relations as we
2794 * come across them, but there is still a race condition (the window between
2795 * seeing a pg_depend entry and acquiring lock on the relation it references).
2796 * Also, holding locks on all these relations simultaneously creates a non-
2797 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2798 * risk by using the weakest suitable lock (ShareLock for most callers).
2800 * XXX the API for this is not sufficient to support checking domain values
2801 * that are inside composite types or arrays. Currently we just error out
2802 * if a composite type containing the target domain is stored anywhere.
2803 * There are not currently arrays of domains; if there were, we could take
2804 * the same approach, but it'd be nicer to fix it properly.
2806 * Generally used for retrieving a list of tests when adding
2807 * new constraints to a domain.
2810 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2815 SysScanDesc depScan;
2818 Assert(lockmode != NoLock);
2821 * We scan pg_depend to find those things that depend on the domain. (We
2822 * assume we can ignore refobjsubid for a domain.)
2824 depRel = heap_open(DependRelationId, AccessShareLock);
2826 ScanKeyInit(&key[0],
2827 Anum_pg_depend_refclassid,
2828 BTEqualStrategyNumber, F_OIDEQ,
2829 ObjectIdGetDatum(TypeRelationId));
2830 ScanKeyInit(&key[1],
2831 Anum_pg_depend_refobjid,
2832 BTEqualStrategyNumber, F_OIDEQ,
2833 ObjectIdGetDatum(domainOid));
2835 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2838 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2840 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2841 RelToCheck *rtc = NULL;
2843 Form_pg_attribute pg_att;
2846 /* Check for directly dependent types --- must be domains */
2847 if (pg_depend->classid == TypeRelationId)
2849 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2852 * Recursively add dependent columns to the output list. This is
2853 * a bit inefficient since we may fail to combine RelToCheck
2854 * entries when attributes of the same rel have different derived
2855 * domain types, but it's probably not worth improving.
2857 result = list_concat(result,
2858 get_rels_with_domain(pg_depend->objid,
2863 /* Else, ignore dependees that aren't user columns of relations */
2864 /* (we assume system columns are never of domain types) */
2865 if (pg_depend->classid != RelationRelationId ||
2866 pg_depend->objsubid <= 0)
2869 /* See if we already have an entry for this relation */
2870 foreach(rellist, result)
2872 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2874 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2883 /* First attribute found for this relation */
2886 /* Acquire requested lock on relation */
2887 rel = relation_open(pg_depend->objid, lockmode);
2890 * Check to see if rowtype is stored anyplace as a composite-type
2891 * column; if so we have to fail, for now anyway.
2893 if (OidIsValid(rel->rd_rel->reltype))
2894 find_composite_type_dependencies(rel->rd_rel->reltype,
2896 format_type_be(domainOid));
2899 * Otherwise, we can ignore relations except those with both
2900 * storage and user-chosen column types.
2902 * XXX If an index-only scan could satisfy "col::some_domain" from
2903 * a suitable expression index, this should also check expression
2906 if (rel->rd_rel->relkind != RELKIND_RELATION &&
2907 rel->rd_rel->relkind != RELKIND_MATVIEW)
2909 relation_close(rel, lockmode);
2913 /* Build the RelToCheck entry with enough space for all atts */
2914 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2917 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2918 result = lcons(rtc, result);
2922 * Confirm column has not been dropped, and is of the expected type.
2923 * This defends against an ALTER DROP COLUMN occurring just before we
2924 * acquired lock ... but if the whole table were dropped, we'd still
2927 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2929 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2930 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2934 * Okay, add column to result. We store the columns in column-number
2935 * order; this is just a hack to improve predictability of regression
2938 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2941 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2943 rtc->atts[ptr] = rtc->atts[ptr - 1];
2946 rtc->atts[ptr] = pg_depend->objsubid;
2949 systable_endscan(depScan);
2951 relation_close(depRel, AccessShareLock);
2959 * Check that the type is actually a domain and that the current user
2960 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2963 checkDomainOwner(HeapTuple tup)
2965 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2967 /* Check that this is actually a domain */
2968 if (typTup->typtype != TYPTYPE_DOMAIN)
2970 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2971 errmsg("%s is not a domain",
2972 format_type_be(HeapTupleGetOid(tup)))));
2974 /* Permission check: must own type */
2975 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2976 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
2980 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2983 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2984 int typMod, Constraint *constr,
2985 char *domainName, ObjectAddress *constrAddr)
2991 CoerceToDomainValue *domVal;
2995 * Assign or validate constraint name
2997 if (constr->conname)
2999 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
3004 (errcode(ERRCODE_DUPLICATE_OBJECT),
3005 errmsg("constraint \"%s\" for domain \"%s\" already exists",
3006 constr->conname, domainName)));
3009 constr->conname = ChooseConstraintName(domainName,
3016 * Convert the A_EXPR in raw_expr into an EXPR
3018 pstate = make_parsestate(NULL);
3021 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
3022 * the expression. Note that it will appear to have the type of the base
3023 * type, not the domain. This seems correct since within the check
3024 * expression, we should not assume the input value can be considered a
3025 * member of the domain.
3027 domVal = makeNode(CoerceToDomainValue);
3028 domVal->typeId = baseTypeOid;
3029 domVal->typeMod = typMod;
3030 domVal->collation = get_typcollation(baseTypeOid);
3031 domVal->location = -1; /* will be set when/if used */
3033 pstate->p_value_substitute = (Node *) domVal;
3035 expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
3038 * Make sure it yields a boolean result.
3040 expr = coerce_to_boolean(pstate, expr, "CHECK");
3043 * Fix up collation information.
3045 assign_expr_collations(pstate, expr);
3048 * Domains don't allow variables (this is probably dead code now that
3049 * add_missing_from is history, but let's be sure).
3051 if (list_length(pstate->p_rtable) != 0 ||
3052 contain_var_clause(expr))
3054 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3055 errmsg("cannot use table references in domain check constraint")));
3058 * Convert to string form for storage.
3060 ccbin = nodeToString(expr);
3063 * Deparse it to produce text for consrc.
3065 ccsrc = deparse_expression(expr,
3069 * Store the constraint in pg_constraint
3072 CreateConstraintEntry(constr->conname, /* Constraint Name */
3073 domainNamespace, /* namespace */
3074 CONSTRAINT_CHECK, /* Constraint Type */
3075 false, /* Is Deferrable */
3076 false, /* Is Deferred */
3077 !constr->skip_validation, /* Is Validated */
3078 InvalidOid, /* not a relation constraint */
3081 domainOid, /* domain constraint */
3082 InvalidOid, /* no associated index */
3083 InvalidOid, /* Foreign key fields */
3092 NULL, /* not an exclusion constraint */
3093 expr, /* Tree form of check constraint */
3094 ccbin, /* Binary form of check constraint */
3095 ccsrc, /* Source form of check constraint */
3096 true, /* is local */
3098 false, /* connoinherit */
3099 false); /* is_internal */
3101 ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
3104 * Return the compiled constraint expression so the calling routine can
3105 * perform any additional required tests.
3112 * Execute ALTER TYPE RENAME
3115 RenameType(RenameStmt *stmt)
3117 List *names = stmt->object;
3118 const char *newTypeName = stmt->newname;
3123 Form_pg_type typTup;
3124 ObjectAddress address;
3126 /* Make a TypeName so we can use standard type lookup machinery */
3127 typename = makeTypeNameFromNameList(names);
3128 typeOid = typenameTypeId(NULL, typename);
3130 /* Look up the type in the type table */
3131 rel = heap_open(TypeRelationId, RowExclusiveLock);
3133 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3134 if (!HeapTupleIsValid(tup))
3135 elog(ERROR, "cache lookup failed for type %u", typeOid);
3136 typTup = (Form_pg_type) GETSTRUCT(tup);
3138 /* check permissions on type */
3139 if (!pg_type_ownercheck(typeOid, GetUserId()))
3140 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3142 /* ALTER DOMAIN used on a non-domain? */
3143 if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3145 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3146 errmsg("\"%s\" is not a domain",
3147 format_type_be(typeOid))));
3150 * If it's a composite type, we need to check that it really is a
3151 * free-standing composite type, and not a table's rowtype. We want people
3152 * to use ALTER TABLE not ALTER TYPE for that case.
3154 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3155 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3157 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3158 errmsg("%s is a table's row type",
3159 format_type_be(typeOid)),
3160 errhint("Use ALTER TABLE instead.")));
3162 /* don't allow direct alteration of array types, either */
3163 if (OidIsValid(typTup->typelem) &&
3164 get_array_type(typTup->typelem) == typeOid)
3166 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3167 errmsg("cannot alter array type %s",
3168 format_type_be(typeOid)),
3169 errhint("You can alter type %s, which will alter the array type as well.",
3170 format_type_be(typTup->typelem))));
3173 * If type is composite we need to rename associated pg_class entry too.
3174 * RenameRelationInternal will call RenameTypeInternal automatically.
3176 if (typTup->typtype == TYPTYPE_COMPOSITE)
3177 RenameRelationInternal(typTup->typrelid, newTypeName, false);
3179 RenameTypeInternal(typeOid, newTypeName,
3180 typTup->typnamespace);
3182 ObjectAddressSet(address, TypeRelationId, typeOid);
3184 heap_close(rel, RowExclusiveLock);
3190 * Change the owner of a type.
3193 AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
3200 Form_pg_type typTup;
3201 AclResult aclresult;
3202 ObjectAddress address;
3204 rel = heap_open(TypeRelationId, RowExclusiveLock);
3206 /* Make a TypeName so we can use standard type lookup machinery */
3207 typename = makeTypeNameFromNameList(names);
3209 /* Use LookupTypeName here so that shell types can be processed */
3210 tup = LookupTypeName(NULL, typename, NULL, false);
3213 (errcode(ERRCODE_UNDEFINED_OBJECT),
3214 errmsg("type \"%s\" does not exist",
3215 TypeNameToString(typename))));
3216 typeOid = typeTypeId(tup);
3218 /* Copy the syscache entry so we can scribble on it below */
3219 newtup = heap_copytuple(tup);
3220 ReleaseSysCache(tup);
3222 typTup = (Form_pg_type) GETSTRUCT(tup);
3224 /* Don't allow ALTER DOMAIN on a type */
3225 if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3227 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3228 errmsg("%s is not a domain",
3229 format_type_be(typeOid))));
3232 * If it's a composite type, we need to check that it really is a
3233 * free-standing composite type, and not a table's rowtype. We want people
3234 * to use ALTER TABLE not ALTER TYPE for that case.
3236 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3237 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3239 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3240 errmsg("%s is a table's row type",
3241 format_type_be(typeOid)),
3242 errhint("Use ALTER TABLE instead.")));
3244 /* don't allow direct alteration of array types, either */
3245 if (OidIsValid(typTup->typelem) &&
3246 get_array_type(typTup->typelem) == typeOid)
3248 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3249 errmsg("cannot alter array type %s",
3250 format_type_be(typeOid)),
3251 errhint("You can alter type %s, which will alter the array type as well.",
3252 format_type_be(typTup->typelem))));
3255 * If the new owner is the same as the existing owner, consider the
3256 * command to have succeeded. This is for dump restoration purposes.
3258 if (typTup->typowner != newOwnerId)
3260 /* Superusers can always do it */
3263 /* Otherwise, must be owner of the existing object */
3264 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
3265 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
3267 /* Must be able to become new owner */
3268 check_is_member_of_role(GetUserId(), newOwnerId);
3270 /* New owner must have CREATE privilege on namespace */
3271 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3274 if (aclresult != ACLCHECK_OK)
3275 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
3276 get_namespace_name(typTup->typnamespace));
3279 AlterTypeOwner_oid(typeOid, newOwnerId, true);
3282 ObjectAddressSet(address, TypeRelationId, typeOid);
3285 heap_close(rel, RowExclusiveLock);
3291 * AlterTypeOwner_oid - change type owner unconditionally
3293 * This function recurses to handle a pg_class entry, if necessary. It
3294 * invokes any necessary access object hooks. If hasDependEntry is TRUE, this
3295 * function modifies the pg_shdepend entry appropriately (this should be
3296 * passed as FALSE only for table rowtypes and array types).
3298 * This is used by ALTER TABLE/TYPE OWNER commands, as well as by REASSIGN
3299 * OWNED BY. It assumes the caller has done all needed check.
3302 AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
3306 Form_pg_type typTup;
3308 rel = heap_open(TypeRelationId, RowExclusiveLock);
3310 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3311 if (!HeapTupleIsValid(tup))
3312 elog(ERROR, "cache lookup failed for type %u", typeOid);
3313 typTup = (Form_pg_type) GETSTRUCT(tup);
3316 * If it's a composite type, invoke ATExecChangeOwner so that we fix up the
3317 * pg_class entry properly. That will call back to AlterTypeOwnerInternal
3318 * to take care of the pg_type entry(s).
3320 if (typTup->typtype == TYPTYPE_COMPOSITE)
3321 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3323 AlterTypeOwnerInternal(typeOid, newOwnerId);
3325 /* Update owner dependency reference */
3327 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3329 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3331 ReleaseSysCache(tup);
3332 heap_close(rel, RowExclusiveLock);
3336 * AlterTypeOwnerInternal - bare-bones type owner change.
3338 * This routine simply modifies the owner of a pg_type entry, and recurses
3339 * to handle a possible array type.
3342 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
3346 Form_pg_type typTup;
3347 Datum repl_val[Natts_pg_type];
3348 bool repl_null[Natts_pg_type];
3349 bool repl_repl[Natts_pg_type];
3354 rel = heap_open(TypeRelationId, RowExclusiveLock);
3356 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3357 if (!HeapTupleIsValid(tup))
3358 elog(ERROR, "cache lookup failed for type %u", typeOid);
3359 typTup = (Form_pg_type) GETSTRUCT(tup);
3361 memset(repl_null, false, sizeof(repl_null));
3362 memset(repl_repl, false, sizeof(repl_repl));
3364 repl_repl[Anum_pg_type_typowner - 1] = true;
3365 repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
3367 aclDatum = heap_getattr(tup,
3368 Anum_pg_type_typacl,
3369 RelationGetDescr(rel),
3371 /* Null ACLs do not require changes */
3374 newAcl = aclnewowner(DatumGetAclP(aclDatum),
3375 typTup->typowner, newOwnerId);
3376 repl_repl[Anum_pg_type_typacl - 1] = true;
3377 repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3380 tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3383 simple_heap_update(rel, &tup->t_self, tup);
3385 CatalogUpdateIndexes(rel, tup);
3387 /* If it has an array type, update that too */
3388 if (OidIsValid(typTup->typarray))
3389 AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
3392 heap_close(rel, RowExclusiveLock);
3396 * Execute ALTER TYPE SET SCHEMA
3399 AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype,
3406 ObjectAddresses *objsMoved;
3407 ObjectAddress myself;
3409 /* Make a TypeName so we can use standard type lookup machinery */
3410 typename = makeTypeNameFromNameList(names);
3411 typeOid = typenameTypeId(NULL, typename);
3413 /* Don't allow ALTER DOMAIN on a type */
3414 if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3416 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3417 errmsg("%s is not a domain",
3418 format_type_be(typeOid))));
3420 /* get schema OID and check its permissions */
3421 nspOid = LookupCreationNamespace(newschema);
3423 objsMoved = new_object_addresses();
3424 oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3425 free_object_addresses(objsMoved);
3428 *oldschema = oldNspOid;
3430 ObjectAddressSet(myself, TypeRelationId, typeOid);
3436 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
3440 /* check permissions on type */
3441 if (!pg_type_ownercheck(typeOid, GetUserId()))
3442 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3444 /* don't allow direct alteration of array types */
3445 elemOid = get_element_type(typeOid);
3446 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3448 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3449 errmsg("cannot alter array type %s",
3450 format_type_be(typeOid)),
3451 errhint("You can alter type %s, which will alter the array type as well.",
3452 format_type_be(elemOid))));
3454 /* and do the work */
3455 return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3459 * Move specified type to new namespace.
3461 * Caller must have already checked privileges.
3463 * The function automatically recurses to process the type's array type,
3464 * if any. isImplicitArray should be TRUE only when doing this internal
3465 * recursion (outside callers must never try to move an array type directly).
3467 * If errorOnTableType is TRUE, the function errors out if the type is
3468 * a table type. ALTER TABLE has to be used to move a table to a new
3471 * Returns the type's old namespace OID.
3474 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
3475 bool isImplicitArray,
3476 bool errorOnTableType,
3477 ObjectAddresses *objsMoved)
3481 Form_pg_type typform;
3484 bool isCompositeType;
3485 ObjectAddress thisobj;
3488 * Make sure we haven't moved this object previously.
3490 thisobj.classId = TypeRelationId;
3491 thisobj.objectId = typeOid;
3492 thisobj.objectSubId = 0;
3494 if (object_address_present(&thisobj, objsMoved))
3497 rel = heap_open(TypeRelationId, RowExclusiveLock);
3499 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3500 if (!HeapTupleIsValid(tup))
3501 elog(ERROR, "cache lookup failed for type %u", typeOid);
3502 typform = (Form_pg_type) GETSTRUCT(tup);
3504 oldNspOid = typform->typnamespace;
3505 arrayOid = typform->typarray;
3507 /* If the type is already there, we scan skip these next few checks. */
3508 if (oldNspOid != nspOid)
3510 /* common checks on switching namespaces */
3511 CheckSetNamespace(oldNspOid, nspOid);
3513 /* check for duplicate name (more friendly than unique-index failure) */
3514 if (SearchSysCacheExists2(TYPENAMENSP,
3515 CStringGetDatum(NameStr(typform->typname)),
3516 ObjectIdGetDatum(nspOid)))
3518 (errcode(ERRCODE_DUPLICATE_OBJECT),
3519 errmsg("type \"%s\" already exists in schema \"%s\"",
3520 NameStr(typform->typname),
3521 get_namespace_name(nspOid))));
3524 /* Detect whether type is a composite type (but not a table rowtype) */
3526 (typform->typtype == TYPTYPE_COMPOSITE &&
3527 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3529 /* Enforce not-table-type if requested */
3530 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3533 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3534 errmsg("%s is a table's row type",
3535 format_type_be(typeOid)),
3536 errhint("Use ALTER TABLE instead.")));
3538 if (oldNspOid != nspOid)
3540 /* OK, modify the pg_type row */
3542 /* tup is a copy, so we can scribble directly on it */
3543 typform->typnamespace = nspOid;
3545 simple_heap_update(rel, &tup->t_self, tup);
3546 CatalogUpdateIndexes(rel, tup);
3550 * Composite types have pg_class entries.
3552 * We need to modify the pg_class tuple as well to reflect the change of
3555 if (isCompositeType)
3559 classRel = heap_open(RelationRelationId, RowExclusiveLock);
3561 AlterRelationNamespaceInternal(classRel, typform->typrelid,
3565 heap_close(classRel, RowExclusiveLock);
3568 * Check for constraints associated with the composite type (we don't
3569 * currently support this, but probably will someday).
3571 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3572 nspOid, false, objsMoved);
3576 /* If it's a domain, it might have constraints */
3577 if (typform->typtype == TYPTYPE_DOMAIN)
3578 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
3583 * Update dependency on schema, if any --- a table rowtype has not got
3584 * one, and neither does an implicit array.
3586 if (oldNspOid != nspOid &&
3587 (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3589 if (changeDependencyFor(TypeRelationId, typeOid,
3590 NamespaceRelationId, oldNspOid, nspOid) != 1)
3591 elog(ERROR, "failed to change schema dependency for type %s",
3592 format_type_be(typeOid));
3594 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3596 heap_freetuple(tup);
3598 heap_close(rel, RowExclusiveLock);
3600 add_exact_object_address(&thisobj, objsMoved);
3602 /* Recursively alter the associated array type, if any */
3603 if (OidIsValid(arrayOid))
3604 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);