1 /*-------------------------------------------------------------------------
4 * Routines for SQL commands that manipulate types (and domains).
6 * Portions Copyright (c) 1996-2015, 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_authid.h"
41 #include "catalog/pg_collation.h"
42 #include "catalog/pg_constraint.h"
43 #include "catalog/pg_depend.h"
44 #include "catalog/pg_enum.h"
45 #include "catalog/pg_language.h"
46 #include "catalog/pg_namespace.h"
47 #include "catalog/pg_proc.h"
48 #include "catalog/pg_proc_fn.h"
49 #include "catalog/pg_range.h"
50 #include "catalog/pg_type.h"
51 #include "catalog/pg_type_fn.h"
52 #include "commands/defrem.h"
53 #include "commands/tablecmds.h"
54 #include "commands/typecmds.h"
55 #include "executor/executor.h"
56 #include "miscadmin.h"
57 #include "nodes/makefuncs.h"
58 #include "optimizer/var.h"
59 #include "parser/parse_coerce.h"
60 #include "parser/parse_collate.h"
61 #include "parser/parse_expr.h"
62 #include "parser/parse_func.h"
63 #include "parser/parse_type.h"
64 #include "utils/builtins.h"
65 #include "utils/fmgroids.h"
66 #include "utils/lsyscache.h"
67 #include "utils/memutils.h"
68 #include "utils/rel.h"
69 #include "utils/ruleutils.h"
70 #include "utils/snapmgr.h"
71 #include "utils/syscache.h"
74 /* result structure for get_rels_with_domain() */
77 Relation rel; /* opened and locked relation */
78 int natts; /* number of attributes of interest */
79 int *atts; /* attribute numbers */
80 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
83 /* Potentially set by contrib/pg_upgrade_support functions */
84 Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
86 static void makeRangeConstructors(const char *name, Oid namespace,
87 Oid rangeOid, Oid subtype);
88 static Oid findTypeInputFunction(List *procname, Oid typeOid);
89 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
90 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
91 static Oid findTypeSendFunction(List *procname, Oid typeOid);
92 static Oid findTypeTypmodinFunction(List *procname);
93 static Oid findTypeTypmodoutFunction(List *procname);
94 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
95 static Oid findRangeSubOpclass(List *opcname, Oid subtype);
96 static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
97 static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
98 static void validateDomainConstraint(Oid domainoid, char *ccbin);
99 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
100 static void checkEnumOwner(HeapTuple tup);
101 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
103 int typMod, Constraint *constr,
109 * Registers a new base type.
112 DefineType(List *names, List *parameters)
116 int16 internalLength = -1; /* default: variable-length */
117 List *inputName = NIL;
118 List *outputName = NIL;
119 List *receiveName = NIL;
120 List *sendName = NIL;
121 List *typmodinName = NIL;
122 List *typmodoutName = NIL;
123 List *analyzeName = NIL;
124 char category = TYPCATEGORY_USER;
125 bool preferred = false;
126 char delimiter = DEFAULT_TYPDELIM;
127 Oid elemType = InvalidOid;
128 char *defaultValue = NULL;
129 bool byValue = false;
130 char alignment = 'i'; /* default alignment */
131 char storage = 'p'; /* default TOAST storage method */
132 Oid collation = InvalidOid;
133 DefElem *likeTypeEl = NULL;
134 DefElem *internalLengthEl = NULL;
135 DefElem *inputNameEl = NULL;
136 DefElem *outputNameEl = NULL;
137 DefElem *receiveNameEl = NULL;
138 DefElem *sendNameEl = NULL;
139 DefElem *typmodinNameEl = NULL;
140 DefElem *typmodoutNameEl = NULL;
141 DefElem *analyzeNameEl = NULL;
142 DefElem *categoryEl = NULL;
143 DefElem *preferredEl = NULL;
144 DefElem *delimiterEl = NULL;
145 DefElem *elemTypeEl = NULL;
146 DefElem *defaultValueEl = NULL;
147 DefElem *byValueEl = NULL;
148 DefElem *alignmentEl = NULL;
149 DefElem *storageEl = NULL;
150 DefElem *collatableEl = NULL;
153 Oid receiveOid = InvalidOid;
154 Oid sendOid = InvalidOid;
155 Oid typmodinOid = InvalidOid;
156 Oid typmodoutOid = InvalidOid;
157 Oid analyzeOid = InvalidOid;
165 * As of Postgres 8.4, we require superuser privilege to create a base
166 * type. This is simple paranoia: there are too many ways to mess up the
167 * system with an incorrect type definition (for instance, representation
168 * parameters that don't match what the C code expects). In practice it
169 * takes superuser privilege to create the I/O functions, and so the
170 * former requirement that you own the I/O functions pretty much forced
171 * superuserness anyway. We're just making doubly sure here.
173 * XXX re-enable NOT_USED code sections below if you remove this test.
177 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
178 errmsg("must be superuser to create a base type")));
180 /* Convert list of names to a name and namespace */
181 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
184 /* XXX this is unnecessary given the superuser check above */
185 /* Check we have creation rights in target namespace */
186 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
187 if (aclresult != ACLCHECK_OK)
188 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
189 get_namespace_name(typeNamespace));
193 * Look to see if type already exists (presumably as a shell; if not,
194 * TypeCreate will complain).
196 typoid = GetSysCacheOid2(TYPENAMENSP,
197 CStringGetDatum(typeName),
198 ObjectIdGetDatum(typeNamespace));
201 * If it's not a shell, see if it's an autogenerated array type, and if so
202 * rename it out of the way.
204 if (OidIsValid(typoid) && get_typisdefined(typoid))
206 if (moveArrayTypeName(typoid, typeName, typeNamespace))
211 * If it doesn't exist, create it as a shell, so that the OID is known for
212 * use in the I/O function definitions.
214 if (!OidIsValid(typoid))
216 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
217 /* Make new shell type visible for modification below */
218 CommandCounterIncrement();
221 * If the command was a parameterless CREATE TYPE, we're done ---
222 * creating the shell type was all we're supposed to do.
224 if (parameters == NIL)
229 /* Complain if dummy CREATE TYPE and entry already exists */
230 if (parameters == NIL)
232 (errcode(ERRCODE_DUPLICATE_OBJECT),
233 errmsg("type \"%s\" already exists", typeName)));
236 /* Extract the parameters from the parameter list */
237 foreach(pl, parameters)
239 DefElem *defel = (DefElem *) lfirst(pl);
242 if (pg_strcasecmp(defel->defname, "like") == 0)
243 defelp = &likeTypeEl;
244 else if (pg_strcasecmp(defel->defname, "internallength") == 0)
245 defelp = &internalLengthEl;
246 else if (pg_strcasecmp(defel->defname, "input") == 0)
247 defelp = &inputNameEl;
248 else if (pg_strcasecmp(defel->defname, "output") == 0)
249 defelp = &outputNameEl;
250 else if (pg_strcasecmp(defel->defname, "receive") == 0)
251 defelp = &receiveNameEl;
252 else if (pg_strcasecmp(defel->defname, "send") == 0)
253 defelp = &sendNameEl;
254 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
255 defelp = &typmodinNameEl;
256 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
257 defelp = &typmodoutNameEl;
258 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
259 pg_strcasecmp(defel->defname, "analyse") == 0)
260 defelp = &analyzeNameEl;
261 else if (pg_strcasecmp(defel->defname, "category") == 0)
262 defelp = &categoryEl;
263 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
264 defelp = &preferredEl;
265 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
266 defelp = &delimiterEl;
267 else if (pg_strcasecmp(defel->defname, "element") == 0)
268 defelp = &elemTypeEl;
269 else if (pg_strcasecmp(defel->defname, "default") == 0)
270 defelp = &defaultValueEl;
271 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
273 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
274 defelp = &alignmentEl;
275 else if (pg_strcasecmp(defel->defname, "storage") == 0)
277 else if (pg_strcasecmp(defel->defname, "collatable") == 0)
278 defelp = &collatableEl;
281 /* WARNING, not ERROR, for historical backwards-compatibility */
283 (errcode(ERRCODE_SYNTAX_ERROR),
284 errmsg("type attribute \"%s\" not recognized",
290 (errcode(ERRCODE_SYNTAX_ERROR),
291 errmsg("conflicting or redundant options")));
296 * Now interpret the options; we do this separately so that LIKE can be
297 * overridden by other options regardless of the ordering in the parameter
303 Form_pg_type likeForm;
305 likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
306 likeForm = (Form_pg_type) GETSTRUCT(likeType);
307 internalLength = likeForm->typlen;
308 byValue = likeForm->typbyval;
309 alignment = likeForm->typalign;
310 storage = likeForm->typstorage;
311 ReleaseSysCache(likeType);
313 if (internalLengthEl)
314 internalLength = defGetTypeLength(internalLengthEl);
316 inputName = defGetQualifiedName(inputNameEl);
318 outputName = defGetQualifiedName(outputNameEl);
320 receiveName = defGetQualifiedName(receiveNameEl);
322 sendName = defGetQualifiedName(sendNameEl);
324 typmodinName = defGetQualifiedName(typmodinNameEl);
326 typmodoutName = defGetQualifiedName(typmodoutNameEl);
328 analyzeName = defGetQualifiedName(analyzeNameEl);
331 char *p = defGetString(categoryEl);
334 /* restrict to non-control ASCII */
335 if (category < 32 || category > 126)
337 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
338 errmsg("invalid type category \"%s\": must be simple ASCII",
342 preferred = defGetBoolean(preferredEl);
345 char *p = defGetString(delimiterEl);
348 /* XXX shouldn't we restrict the delimiter? */
352 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
353 /* disallow arrays of pseudotypes */
354 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
356 (errcode(ERRCODE_DATATYPE_MISMATCH),
357 errmsg("array element type cannot be %s",
358 format_type_be(elemType))));
361 defaultValue = defGetString(defaultValueEl);
363 byValue = defGetBoolean(byValueEl);
366 char *a = defGetString(alignmentEl);
369 * Note: if argument was an unquoted identifier, parser will have
370 * applied translations to it, so be prepared to recognize translated
371 * type names as well as the nominal form.
373 if (pg_strcasecmp(a, "double") == 0 ||
374 pg_strcasecmp(a, "float8") == 0 ||
375 pg_strcasecmp(a, "pg_catalog.float8") == 0)
377 else if (pg_strcasecmp(a, "int4") == 0 ||
378 pg_strcasecmp(a, "pg_catalog.int4") == 0)
380 else if (pg_strcasecmp(a, "int2") == 0 ||
381 pg_strcasecmp(a, "pg_catalog.int2") == 0)
383 else if (pg_strcasecmp(a, "char") == 0 ||
384 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
388 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
389 errmsg("alignment \"%s\" not recognized", a)));
393 char *a = defGetString(storageEl);
395 if (pg_strcasecmp(a, "plain") == 0)
397 else if (pg_strcasecmp(a, "external") == 0)
399 else if (pg_strcasecmp(a, "extended") == 0)
401 else if (pg_strcasecmp(a, "main") == 0)
405 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
406 errmsg("storage \"%s\" not recognized", a)));
409 collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
412 * make sure we have our required definitions
414 if (inputName == NIL)
416 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
417 errmsg("type input function must be specified")));
418 if (outputName == NIL)
420 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
421 errmsg("type output function must be specified")));
423 if (typmodinName == NIL && typmodoutName != NIL)
425 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
426 errmsg("type modifier output function is useless without a type modifier input function")));
429 * Convert I/O proc names to OIDs
431 inputOid = findTypeInputFunction(inputName, typoid);
432 outputOid = findTypeOutputFunction(outputName, typoid);
434 receiveOid = findTypeReceiveFunction(receiveName, typoid);
436 sendOid = findTypeSendFunction(sendName, typoid);
439 * Verify that I/O procs return the expected thing. If we see OPAQUE,
440 * complain and change it to the correct type-safe choice.
442 resulttype = get_func_rettype(inputOid);
443 if (resulttype != typoid)
445 if (resulttype == OPAQUEOID)
447 /* backwards-compatibility hack */
449 (errmsg("changing return type of function %s from \"opaque\" to %s",
450 NameListToString(inputName), typeName)));
451 SetFunctionReturnType(inputOid, typoid);
455 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
456 errmsg("type input function %s must return type %s",
457 NameListToString(inputName), typeName)));
459 resulttype = get_func_rettype(outputOid);
460 if (resulttype != CSTRINGOID)
462 if (resulttype == OPAQUEOID)
464 /* backwards-compatibility hack */
466 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
467 NameListToString(outputName))));
468 SetFunctionReturnType(outputOid, CSTRINGOID);
472 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
473 errmsg("type output function %s must return type \"cstring\"",
474 NameListToString(outputName))));
478 resulttype = get_func_rettype(receiveOid);
479 if (resulttype != typoid)
481 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
482 errmsg("type receive function %s must return type %s",
483 NameListToString(receiveName), typeName)));
487 resulttype = get_func_rettype(sendOid);
488 if (resulttype != BYTEAOID)
490 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
491 errmsg("type send function %s must return type \"bytea\"",
492 NameListToString(sendName))));
496 * Convert typmodin/out function proc names to OIDs.
499 typmodinOid = findTypeTypmodinFunction(typmodinName);
501 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
504 * Convert analysis function proc name to an OID. If no analysis function
505 * is specified, we'll use zero to select the built-in default algorithm.
508 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
511 * Check permissions on functions. We choose to require the creator/owner
512 * of a type to also own the underlying functions. Since creating a type
513 * is tantamount to granting public execute access on the functions, the
514 * minimum sane check would be for execute-with-grant-option. But we
515 * don't have a way to make the type go away if the grant option is
516 * revoked, so ownership seems better.
519 /* XXX this is unnecessary given the superuser check above */
520 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
521 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
522 NameListToString(inputName));
523 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
524 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
525 NameListToString(outputName));
526 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
527 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
528 NameListToString(receiveName));
529 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
530 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
531 NameListToString(sendName));
532 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
533 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
534 NameListToString(typmodinName));
535 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
536 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
537 NameListToString(typmodoutName));
538 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
539 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
540 NameListToString(analyzeName));
544 * Print warnings if any of the type's I/O functions are marked volatile.
545 * There is a general assumption that I/O functions are stable or
546 * immutable; this allows us for example to mark record_in/record_out
547 * stable rather than volatile. Ideally we would throw errors not just
548 * warnings here; but since this check is new as of 9.5, and since the
549 * volatility marking might be just an error-of-omission and not a true
550 * indication of how the function behaves, we'll let it pass as a warning
553 if (inputOid && func_volatile(inputOid) == PROVOLATILE_VOLATILE)
555 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
556 errmsg("type input function %s should not be volatile",
557 NameListToString(inputName))));
558 if (outputOid && func_volatile(outputOid) == PROVOLATILE_VOLATILE)
560 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
561 errmsg("type output function %s should not be volatile",
562 NameListToString(outputName))));
563 if (receiveOid && func_volatile(receiveOid) == PROVOLATILE_VOLATILE)
565 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
566 errmsg("type receive function %s should not be volatile",
567 NameListToString(receiveName))));
568 if (sendOid && func_volatile(sendOid) == PROVOLATILE_VOLATILE)
570 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
571 errmsg("type send function %s should not be volatile",
572 NameListToString(sendName))));
573 if (typmodinOid && func_volatile(typmodinOid) == PROVOLATILE_VOLATILE)
575 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
576 errmsg("type modifier input function %s should not be volatile",
577 NameListToString(typmodinName))));
578 if (typmodoutOid && func_volatile(typmodoutOid) == PROVOLATILE_VOLATILE)
580 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
581 errmsg("type modifier output function %s should not be volatile",
582 NameListToString(typmodoutName))));
585 * OK, we're done checking, time to make the type. We must assign the
586 * array type OID ahead of calling TypeCreate, since the base type and
587 * array type each refer to the other.
589 array_oid = AssignTypeArrayOid();
592 * now have TypeCreate do all the real work.
594 * Note: the pg_type.oid is stored in user tables as array elements (base
595 * types) in ArrayType and in composite types in DatumTupleFields. This
596 * oid must be preserved by binary upgrades.
599 TypeCreate(InvalidOid, /* no predetermined type OID */
600 typeName, /* type name */
601 typeNamespace, /* namespace */
602 InvalidOid, /* relation oid (n/a here) */
603 0, /* relation kind (ditto) */
604 GetUserId(), /* owner's ID */
605 internalLength, /* internal size */
606 TYPTYPE_BASE, /* type-type (base type) */
607 category, /* type-category */
608 preferred, /* is it a preferred type? */
609 delimiter, /* array element delimiter */
610 inputOid, /* input procedure */
611 outputOid, /* output procedure */
612 receiveOid, /* receive procedure */
613 sendOid, /* send procedure */
614 typmodinOid, /* typmodin procedure */
615 typmodoutOid, /* typmodout procedure */
616 analyzeOid, /* analyze procedure */
617 elemType, /* element type ID */
618 false, /* this is not an array type */
619 array_oid, /* array type we are about to create */
620 InvalidOid, /* base type ID (only for domains) */
621 defaultValue, /* default type value */
622 NULL, /* no binary form available */
623 byValue, /* passed by value */
624 alignment, /* required alignment */
625 storage, /* TOAST strategy */
626 -1, /* typMod (Domains only) */
627 0, /* Array Dimensions of typbasetype */
628 false, /* Type NOT NULL */
629 collation); /* type's collation */
632 * Create the array type that goes with it.
634 array_type = makeArrayTypeName(typeName, typeNamespace);
636 /* alignment must be 'i' or 'd' for arrays */
637 alignment = (alignment == 'd') ? 'd' : 'i';
639 TypeCreate(array_oid, /* force assignment of this type OID */
640 array_type, /* type name */
641 typeNamespace, /* namespace */
642 InvalidOid, /* relation oid (n/a here) */
643 0, /* relation kind (ditto) */
644 GetUserId(), /* owner's ID */
645 -1, /* internal size (always varlena) */
646 TYPTYPE_BASE, /* type-type (base type) */
647 TYPCATEGORY_ARRAY, /* type-category (array) */
648 false, /* array types are never preferred */
649 delimiter, /* array element delimiter */
650 F_ARRAY_IN, /* input procedure */
651 F_ARRAY_OUT, /* output procedure */
652 F_ARRAY_RECV, /* receive procedure */
653 F_ARRAY_SEND, /* send procedure */
654 typmodinOid, /* typmodin procedure */
655 typmodoutOid, /* typmodout procedure */
656 F_ARRAY_TYPANALYZE, /* analyze procedure */
657 typoid, /* element type ID */
658 true, /* yes this is an array type */
659 InvalidOid, /* no further array type */
660 InvalidOid, /* base type ID */
661 NULL, /* never a default type value */
662 NULL, /* binary default isn't sent either */
663 false, /* never passed by value */
664 alignment, /* see above */
665 'x', /* ARRAY is always toastable */
666 -1, /* typMod (Domains only) */
667 0, /* Array dimensions of typbasetype */
668 false, /* Type NOT NULL */
669 collation); /* type's collation */
677 * Guts of type deletion.
680 RemoveTypeById(Oid typeOid)
685 relation = heap_open(TypeRelationId, RowExclusiveLock);
687 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
688 if (!HeapTupleIsValid(tup))
689 elog(ERROR, "cache lookup failed for type %u", typeOid);
691 simple_heap_delete(relation, &tup->t_self);
694 * If it is an enum, delete the pg_enum entries too; we don't bother with
695 * making dependency entries for those, so it has to be done "by hand"
698 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
699 EnumValuesDelete(typeOid);
702 * If it is a range type, delete the pg_range entry too; we don't bother
703 * with making a dependency entry for that, so it has to be done "by hand"
706 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
707 RangeDelete(typeOid);
709 ReleaseSysCache(tup);
711 heap_close(relation, RowExclusiveLock);
717 * Registers a new domain.
720 DefineDomain(CreateDomainStmt *stmt)
725 int16 internalLength;
728 Oid receiveProcedure;
730 Oid analyzeProcedure;
739 char *defaultValue = NULL;
740 char *defaultValueBin = NULL;
741 bool saw_default = false;
742 bool typNotNull = false;
743 bool nullDefined = false;
744 int32 typNDims = list_length(stmt->typeName->arrayBounds);
746 List *schema = stmt->constraints;
752 Form_pg_type baseType;
756 /* Convert list of names to a name and namespace */
757 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
760 /* Check we have creation rights in target namespace */
761 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
763 if (aclresult != ACLCHECK_OK)
764 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
765 get_namespace_name(domainNamespace));
768 * Check for collision with an existing type name. If there is one and
769 * it's an autogenerated array, we can rename it out of the way.
771 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
772 CStringGetDatum(domainName),
773 ObjectIdGetDatum(domainNamespace));
774 if (OidIsValid(old_type_oid))
776 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
778 (errcode(ERRCODE_DUPLICATE_OBJECT),
779 errmsg("type \"%s\" already exists", domainName)));
783 * Look up the base type.
785 typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
786 baseType = (Form_pg_type) GETSTRUCT(typeTup);
787 basetypeoid = HeapTupleGetOid(typeTup);
790 * Base type must be a plain base type, another domain, an enum or a range
791 * type. Domains over pseudotypes would create a security hole. Domains
792 * over composite types might be made to work in the future, but not
795 typtype = baseType->typtype;
796 if (typtype != TYPTYPE_BASE &&
797 typtype != TYPTYPE_DOMAIN &&
798 typtype != TYPTYPE_ENUM &&
799 typtype != TYPTYPE_RANGE)
801 (errcode(ERRCODE_DATATYPE_MISMATCH),
802 errmsg("\"%s\" is not a valid base type for a domain",
803 TypeNameToString(stmt->typeName))));
805 aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
806 if (aclresult != ACLCHECK_OK)
807 aclcheck_error_type(aclresult, basetypeoid);
810 * Identify the collation if any
812 baseColl = baseType->typcollation;
813 if (stmt->collClause)
814 domaincoll = get_collation_oid(stmt->collClause->collname, false);
816 domaincoll = baseColl;
818 /* Complain if COLLATE is applied to an uncollatable type */
819 if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
821 (errcode(ERRCODE_DATATYPE_MISMATCH),
822 errmsg("collations are not supported by type %s",
823 format_type_be(basetypeoid))));
825 /* passed by value */
826 byValue = baseType->typbyval;
828 /* Required Alignment */
829 alignment = baseType->typalign;
832 storage = baseType->typstorage;
835 internalLength = baseType->typlen;
838 category = baseType->typcategory;
840 /* Array element Delimiter */
841 delimiter = baseType->typdelim;
844 inputProcedure = F_DOMAIN_IN;
845 outputProcedure = baseType->typoutput;
846 receiveProcedure = F_DOMAIN_RECV;
847 sendProcedure = baseType->typsend;
849 /* Domains never accept typmods, so no typmodin/typmodout needed */
851 /* Analysis function */
852 analyzeProcedure = baseType->typanalyze;
854 /* Inherited default value */
855 datum = SysCacheGetAttr(TYPEOID, typeTup,
856 Anum_pg_type_typdefault, &isnull);
858 defaultValue = TextDatumGetCString(datum);
860 /* Inherited default binary value */
861 datum = SysCacheGetAttr(TYPEOID, typeTup,
862 Anum_pg_type_typdefaultbin, &isnull);
864 defaultValueBin = TextDatumGetCString(datum);
867 * Run through constraints manually to avoid the additional processing
868 * conducted by DefineRelation() and friends.
870 foreach(listptr, schema)
872 Constraint *constr = lfirst(listptr);
874 if (!IsA(constr, Constraint))
875 elog(ERROR, "unrecognized node type: %d",
876 (int) nodeTag(constr));
877 switch (constr->contype)
882 * The inherited default value may be overridden by the user
883 * with the DEFAULT <expr> clause ... but only once.
887 (errcode(ERRCODE_SYNTAX_ERROR),
888 errmsg("multiple default expressions")));
891 if (constr->raw_expr)
896 /* Create a dummy ParseState for transformExpr */
897 pstate = make_parsestate(NULL);
900 * Cook the constr->raw_expr into an expression. Note:
901 * name is strictly for error message
903 defaultExpr = cookDefault(pstate, constr->raw_expr,
909 * If the expression is just a NULL constant, we treat it
910 * like not having a default.
912 * Note that if the basetype is another domain, we'll see
913 * a CoerceToDomain expr here and not discard the default.
914 * This is critical because the domain default needs to be
915 * retained to override any default that the base domain
918 if (defaultExpr == NULL ||
919 (IsA(defaultExpr, Const) &&
920 ((Const *) defaultExpr)->constisnull))
923 defaultValueBin = NULL;
928 * Expression must be stored as a nodeToString result,
929 * but we also require a valid textual representation
930 * (mainly to make life easier for pg_dump).
933 deparse_expression(defaultExpr,
935 defaultValueBin = nodeToString(defaultExpr);
940 /* No default (can this still happen?) */
942 defaultValueBin = NULL;
947 if (nullDefined && !typNotNull)
949 (errcode(ERRCODE_SYNTAX_ERROR),
950 errmsg("conflicting NULL/NOT NULL constraints")));
956 if (nullDefined && typNotNull)
958 (errcode(ERRCODE_SYNTAX_ERROR),
959 errmsg("conflicting NULL/NOT NULL constraints")));
967 * Check constraints are handled after domain creation, as
968 * they require the Oid of the domain; at this point we can
969 * only check that they're not marked NO INHERIT, because that
972 if (constr->is_no_inherit)
974 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
975 errmsg("check constraints for domains cannot be marked NO INHERIT")));
979 * All else are error cases
983 (errcode(ERRCODE_SYNTAX_ERROR),
984 errmsg("unique constraints not possible for domains")));
989 (errcode(ERRCODE_SYNTAX_ERROR),
990 errmsg("primary key constraints not possible for domains")));
993 case CONSTR_EXCLUSION:
995 (errcode(ERRCODE_SYNTAX_ERROR),
996 errmsg("exclusion constraints not possible for domains")));
1001 (errcode(ERRCODE_SYNTAX_ERROR),
1002 errmsg("foreign key constraints not possible for domains")));
1005 case CONSTR_ATTR_DEFERRABLE:
1006 case CONSTR_ATTR_NOT_DEFERRABLE:
1007 case CONSTR_ATTR_DEFERRED:
1008 case CONSTR_ATTR_IMMEDIATE:
1010 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1011 errmsg("specifying constraint deferrability not supported for domains")));
1015 elog(ERROR, "unrecognized constraint subtype: %d",
1016 (int) constr->contype);
1022 * Have TypeCreate do all the real work.
1025 TypeCreate(InvalidOid, /* no predetermined type OID */
1026 domainName, /* type name */
1027 domainNamespace, /* namespace */
1028 InvalidOid, /* relation oid (n/a here) */
1029 0, /* relation kind (ditto) */
1030 GetUserId(), /* owner's ID */
1031 internalLength, /* internal size */
1032 TYPTYPE_DOMAIN, /* type-type (domain type) */
1033 category, /* type-category */
1034 false, /* domain types are never preferred */
1035 delimiter, /* array element delimiter */
1036 inputProcedure, /* input procedure */
1037 outputProcedure, /* output procedure */
1038 receiveProcedure, /* receive procedure */
1039 sendProcedure, /* send procedure */
1040 InvalidOid, /* typmodin procedure - none */
1041 InvalidOid, /* typmodout procedure - none */
1042 analyzeProcedure, /* analyze procedure */
1043 InvalidOid, /* no array element type */
1044 false, /* this isn't an array */
1045 InvalidOid, /* no arrays for domains (yet) */
1046 basetypeoid, /* base type ID */
1047 defaultValue, /* default type value (text) */
1048 defaultValueBin, /* default type value (binary) */
1049 byValue, /* passed by value */
1050 alignment, /* required alignment */
1051 storage, /* TOAST strategy */
1052 basetypeMod, /* typeMod value */
1053 typNDims, /* Array dimensions for base type */
1054 typNotNull, /* Type NOT NULL */
1055 domaincoll); /* type's collation */
1058 * Process constraints which refer to the domain ID returned by TypeCreate
1060 foreach(listptr, schema)
1062 Constraint *constr = lfirst(listptr);
1064 /* it must be a Constraint, per check above */
1066 switch (constr->contype)
1069 domainAddConstraint(domainoid, domainNamespace,
1070 basetypeoid, basetypeMod,
1071 constr, domainName);
1074 /* Other constraint types were fully processed above */
1080 /* CCI so we can detect duplicate constraint names */
1081 CommandCounterIncrement();
1085 * Now we can clean up.
1087 ReleaseSysCache(typeTup);
1095 * Registers a new enum.
1098 DefineEnum(CreateEnumStmt *stmt)
1101 char *enumArrayName;
1104 AclResult aclresult;
1108 /* Convert list of names to a name and namespace */
1109 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1112 /* Check we have creation rights in target namespace */
1113 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1114 if (aclresult != ACLCHECK_OK)
1115 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1116 get_namespace_name(enumNamespace));
1119 * Check for collision with an existing type name. If there is one and
1120 * it's an autogenerated array, we can rename it out of the way.
1122 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1123 CStringGetDatum(enumName),
1124 ObjectIdGetDatum(enumNamespace));
1125 if (OidIsValid(old_type_oid))
1127 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1129 (errcode(ERRCODE_DUPLICATE_OBJECT),
1130 errmsg("type \"%s\" already exists", enumName)));
1133 enumArrayOid = AssignTypeArrayOid();
1135 /* Create the pg_type entry */
1137 TypeCreate(InvalidOid, /* no predetermined type OID */
1138 enumName, /* type name */
1139 enumNamespace, /* namespace */
1140 InvalidOid, /* relation oid (n/a here) */
1141 0, /* relation kind (ditto) */
1142 GetUserId(), /* owner's ID */
1143 sizeof(Oid), /* internal size */
1144 TYPTYPE_ENUM, /* type-type (enum type) */
1145 TYPCATEGORY_ENUM, /* type-category (enum type) */
1146 false, /* enum types are never preferred */
1147 DEFAULT_TYPDELIM, /* array element delimiter */
1148 F_ENUM_IN, /* input procedure */
1149 F_ENUM_OUT, /* output procedure */
1150 F_ENUM_RECV, /* receive procedure */
1151 F_ENUM_SEND, /* send procedure */
1152 InvalidOid, /* typmodin procedure - none */
1153 InvalidOid, /* typmodout procedure - none */
1154 InvalidOid, /* analyze procedure - default */
1155 InvalidOid, /* element type ID */
1156 false, /* this is not an array type */
1157 enumArrayOid, /* array type we are about to create */
1158 InvalidOid, /* base type ID (only for domains) */
1159 NULL, /* never a default type value */
1160 NULL, /* binary default isn't sent either */
1161 true, /* always passed by value */
1162 'i', /* int alignment */
1163 'p', /* TOAST strategy always plain */
1164 -1, /* typMod (Domains only) */
1165 0, /* Array dimensions of typbasetype */
1166 false, /* Type NOT NULL */
1167 InvalidOid); /* type's collation */
1169 /* Enter the enum's values into pg_enum */
1170 EnumValuesCreate(enumTypeOid, stmt->vals);
1173 * Create the array type that goes with it.
1175 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1177 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1178 enumArrayName, /* type name */
1179 enumNamespace, /* namespace */
1180 InvalidOid, /* relation oid (n/a here) */
1181 0, /* relation kind (ditto) */
1182 GetUserId(), /* owner's ID */
1183 -1, /* internal size (always varlena) */
1184 TYPTYPE_BASE, /* type-type (base type) */
1185 TYPCATEGORY_ARRAY, /* type-category (array) */
1186 false, /* array types are never preferred */
1187 DEFAULT_TYPDELIM, /* array element delimiter */
1188 F_ARRAY_IN, /* input procedure */
1189 F_ARRAY_OUT, /* output procedure */
1190 F_ARRAY_RECV, /* receive procedure */
1191 F_ARRAY_SEND, /* send procedure */
1192 InvalidOid, /* typmodin procedure - none */
1193 InvalidOid, /* typmodout procedure - none */
1194 F_ARRAY_TYPANALYZE, /* analyze procedure */
1195 enumTypeOid, /* element type ID */
1196 true, /* yes this is an array type */
1197 InvalidOid, /* no further array type */
1198 InvalidOid, /* base type ID */
1199 NULL, /* never a default type value */
1200 NULL, /* binary default isn't sent either */
1201 false, /* never passed by value */
1202 'i', /* enums have align i, so do their arrays */
1203 'x', /* ARRAY is always toastable */
1204 -1, /* typMod (Domains only) */
1205 0, /* Array dimensions of typbasetype */
1206 false, /* Type NOT NULL */
1207 InvalidOid); /* type's collation */
1209 pfree(enumArrayName);
1216 * Adds a new label to an existing enum.
1219 AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
1225 /* Make a TypeName so we can use standard type lookup machinery */
1226 typename = makeTypeNameFromNameList(stmt->typeName);
1227 enum_type_oid = typenameTypeId(NULL, typename);
1229 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1230 if (!HeapTupleIsValid(tup))
1231 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1234 * Ordinarily we disallow adding values within transaction blocks, because
1235 * we can't cope with enum OID values getting into indexes and then having
1236 * their defining pg_enum entries go away. However, it's okay if the enum
1237 * type was created in the current transaction, since then there can be no
1238 * such indexes that wouldn't themselves go away on rollback. (We support
1239 * this case because pg_dump --binary-upgrade needs it.) We test this by
1240 * seeing if the pg_type row has xmin == current XID and is not
1241 * HEAP_UPDATED. If it is HEAP_UPDATED, we can't be sure whether the type
1242 * was created or only modified in this xact. So we are disallowing some
1243 * cases that could theoretically be safe; but fortunately pg_dump only
1244 * needs the simplest case.
1246 if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() &&
1247 !(tup->t_data->t_infomask & HEAP_UPDATED))
1248 /* safe to do inside transaction block */ ;
1250 PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD");
1252 /* Check it's an enum and check user has permission to ALTER the enum */
1253 checkEnumOwner(tup);
1255 /* Add the new label */
1256 AddEnumLabel(enum_type_oid, stmt->newVal,
1257 stmt->newValNeighbor, stmt->newValIsAfter,
1258 stmt->skipIfExists);
1260 InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1262 ReleaseSysCache(tup);
1264 return enum_type_oid;
1271 * Check that the type is actually an enum and that the current user
1272 * has permission to do ALTER TYPE on it. Throw an error if not.
1275 checkEnumOwner(HeapTuple tup)
1277 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1279 /* Check that this is actually an enum */
1280 if (typTup->typtype != TYPTYPE_ENUM)
1282 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1283 errmsg("%s is not an enum",
1284 format_type_be(HeapTupleGetOid(tup)))));
1286 /* Permission check: must own type */
1287 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1288 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
1294 * Registers a new range type.
1297 DefineRange(CreateRangeStmt *stmt)
1302 char *rangeArrayName;
1304 Oid rangeSubtype = InvalidOid;
1305 List *rangeSubOpclassName = NIL;
1306 List *rangeCollationName = NIL;
1307 List *rangeCanonicalName = NIL;
1308 List *rangeSubtypeDiffName = NIL;
1309 Oid rangeSubOpclass;
1311 regproc rangeCanonical;
1312 regproc rangeSubtypeDiff;
1317 AclResult aclresult;
1320 /* Convert list of names to a name and namespace */
1321 typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1324 /* Check we have creation rights in target namespace */
1325 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1326 if (aclresult != ACLCHECK_OK)
1327 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1328 get_namespace_name(typeNamespace));
1331 * Look to see if type already exists.
1333 typoid = GetSysCacheOid2(TYPENAMENSP,
1334 CStringGetDatum(typeName),
1335 ObjectIdGetDatum(typeNamespace));
1338 * If it's not a shell, see if it's an autogenerated array type, and if so
1339 * rename it out of the way.
1341 if (OidIsValid(typoid) && get_typisdefined(typoid))
1343 if (moveArrayTypeName(typoid, typeName, typeNamespace))
1344 typoid = InvalidOid;
1347 (errcode(ERRCODE_DUPLICATE_OBJECT),
1348 errmsg("type \"%s\" already exists", typeName)));
1352 * If it doesn't exist, create it as a shell, so that the OID is known for
1353 * use in the range function definitions.
1355 if (!OidIsValid(typoid))
1357 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
1358 /* Make new shell type visible for modification below */
1359 CommandCounterIncrement();
1362 /* Extract the parameters from the parameter list */
1363 foreach(lc, stmt->params)
1365 DefElem *defel = (DefElem *) lfirst(lc);
1367 if (pg_strcasecmp(defel->defname, "subtype") == 0)
1369 if (OidIsValid(rangeSubtype))
1371 (errcode(ERRCODE_SYNTAX_ERROR),
1372 errmsg("conflicting or redundant options")));
1373 /* we can look up the subtype name immediately */
1374 rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1376 else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
1378 if (rangeSubOpclassName != NIL)
1380 (errcode(ERRCODE_SYNTAX_ERROR),
1381 errmsg("conflicting or redundant options")));
1382 rangeSubOpclassName = defGetQualifiedName(defel);
1384 else if (pg_strcasecmp(defel->defname, "collation") == 0)
1386 if (rangeCollationName != NIL)
1388 (errcode(ERRCODE_SYNTAX_ERROR),
1389 errmsg("conflicting or redundant options")));
1390 rangeCollationName = defGetQualifiedName(defel);
1392 else if (pg_strcasecmp(defel->defname, "canonical") == 0)
1394 if (rangeCanonicalName != NIL)
1396 (errcode(ERRCODE_SYNTAX_ERROR),
1397 errmsg("conflicting or redundant options")));
1398 rangeCanonicalName = defGetQualifiedName(defel);
1400 else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
1402 if (rangeSubtypeDiffName != NIL)
1404 (errcode(ERRCODE_SYNTAX_ERROR),
1405 errmsg("conflicting or redundant options")));
1406 rangeSubtypeDiffName = defGetQualifiedName(defel);
1410 (errcode(ERRCODE_SYNTAX_ERROR),
1411 errmsg("type attribute \"%s\" not recognized",
1415 /* Must have a subtype */
1416 if (!OidIsValid(rangeSubtype))
1418 (errcode(ERRCODE_SYNTAX_ERROR),
1419 errmsg("type attribute \"subtype\" is required")));
1420 /* disallow ranges of pseudotypes */
1421 if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
1423 (errcode(ERRCODE_DATATYPE_MISMATCH),
1424 errmsg("range subtype cannot be %s",
1425 format_type_be(rangeSubtype))));
1427 /* Identify subopclass */
1428 rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1430 /* Identify collation to use, if any */
1431 if (type_is_collatable(rangeSubtype))
1433 if (rangeCollationName != NIL)
1434 rangeCollation = get_collation_oid(rangeCollationName, false);
1436 rangeCollation = get_typcollation(rangeSubtype);
1440 if (rangeCollationName != NIL)
1442 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1443 errmsg("range collation specified but subtype does not support collation")));
1444 rangeCollation = InvalidOid;
1447 /* Identify support functions, if provided */
1448 if (rangeCanonicalName != NIL)
1449 rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1452 rangeCanonical = InvalidOid;
1454 if (rangeSubtypeDiffName != NIL)
1455 rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1458 rangeSubtypeDiff = InvalidOid;
1460 get_typlenbyvalalign(rangeSubtype,
1461 &subtyplen, &subtypbyval, &subtypalign);
1463 /* alignment must be 'i' or 'd' for ranges */
1464 alignment = (subtypalign == 'd') ? 'd' : 'i';
1466 /* Allocate OID for array type */
1467 rangeArrayOid = AssignTypeArrayOid();
1469 /* Create the pg_type entry */
1471 TypeCreate(InvalidOid, /* no predetermined type OID */
1472 typeName, /* type name */
1473 typeNamespace, /* namespace */
1474 InvalidOid, /* relation oid (n/a here) */
1475 0, /* relation kind (ditto) */
1476 GetUserId(), /* owner's ID */
1477 -1, /* internal size (always varlena) */
1478 TYPTYPE_RANGE, /* type-type (range type) */
1479 TYPCATEGORY_RANGE, /* type-category (range type) */
1480 false, /* range types are never preferred */
1481 DEFAULT_TYPDELIM, /* array element delimiter */
1482 F_RANGE_IN, /* input procedure */
1483 F_RANGE_OUT, /* output procedure */
1484 F_RANGE_RECV, /* receive procedure */
1485 F_RANGE_SEND, /* send procedure */
1486 InvalidOid, /* typmodin procedure - none */
1487 InvalidOid, /* typmodout procedure - none */
1488 F_RANGE_TYPANALYZE, /* analyze procedure */
1489 InvalidOid, /* element type ID - none */
1490 false, /* this is not an array type */
1491 rangeArrayOid, /* array type we are about to create */
1492 InvalidOid, /* base type ID (only for domains) */
1493 NULL, /* never a default type value */
1494 NULL, /* no binary form available either */
1495 false, /* never passed by value */
1496 alignment, /* alignment */
1497 'x', /* TOAST strategy (always extended) */
1498 -1, /* typMod (Domains only) */
1499 0, /* Array dimensions of typbasetype */
1500 false, /* Type NOT NULL */
1501 InvalidOid); /* type's collation (ranges never have one) */
1503 /* Create the entry in pg_range */
1504 RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1505 rangeCanonical, rangeSubtypeDiff);
1508 * Create the array type that goes with it.
1510 rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1512 TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1513 rangeArrayName, /* type name */
1514 typeNamespace, /* namespace */
1515 InvalidOid, /* relation oid (n/a here) */
1516 0, /* relation kind (ditto) */
1517 GetUserId(), /* owner's ID */
1518 -1, /* internal size (always varlena) */
1519 TYPTYPE_BASE, /* type-type (base type) */
1520 TYPCATEGORY_ARRAY, /* type-category (array) */
1521 false, /* array types are never preferred */
1522 DEFAULT_TYPDELIM, /* array element delimiter */
1523 F_ARRAY_IN, /* input procedure */
1524 F_ARRAY_OUT, /* output procedure */
1525 F_ARRAY_RECV, /* receive procedure */
1526 F_ARRAY_SEND, /* send procedure */
1527 InvalidOid, /* typmodin procedure - none */
1528 InvalidOid, /* typmodout procedure - none */
1529 F_ARRAY_TYPANALYZE, /* analyze procedure */
1530 typoid, /* element type ID */
1531 true, /* yes this is an array type */
1532 InvalidOid, /* no further array type */
1533 InvalidOid, /* base type ID */
1534 NULL, /* never a default type value */
1535 NULL, /* binary default isn't sent either */
1536 false, /* never passed by value */
1537 alignment, /* alignment - same as range's */
1538 'x', /* ARRAY is always toastable */
1539 -1, /* typMod (Domains only) */
1540 0, /* Array dimensions of typbasetype */
1541 false, /* Type NOT NULL */
1542 InvalidOid); /* typcollation */
1544 pfree(rangeArrayName);
1546 /* And create the constructor functions for this range type */
1547 makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1553 * Because there may exist several range types over the same subtype, the
1554 * range type can't be uniquely determined from the subtype. So it's
1555 * impossible to define a polymorphic constructor; we have to generate new
1556 * constructor functions explicitly for each range type.
1558 * We actually define 4 functions, with 0 through 3 arguments. This is just
1559 * to offer more convenience for the user.
1562 makeRangeConstructors(const char *name, Oid namespace,
1563 Oid rangeOid, Oid subtype)
1565 static const char *const prosrc[2] = {"range_constructor2",
1566 "range_constructor3"};
1567 static const int pronargs[2] = {2, 3};
1569 Oid constructorArgTypes[3];
1570 ObjectAddress myself,
1574 constructorArgTypes[0] = subtype;
1575 constructorArgTypes[1] = subtype;
1576 constructorArgTypes[2] = TEXTOID;
1578 referenced.classId = TypeRelationId;
1579 referenced.objectId = rangeOid;
1580 referenced.objectSubId = 0;
1582 for (i = 0; i < lengthof(prosrc); i++)
1584 oidvector *constructorArgTypesVector;
1587 constructorArgTypesVector = buildoidvector(constructorArgTypes,
1590 procOid = ProcedureCreate(name, /* name: same as range type */
1591 namespace, /* namespace */
1592 false, /* replace */
1593 false, /* returns set */
1594 rangeOid, /* return type */
1595 BOOTSTRAP_SUPERUSERID, /* proowner */
1596 INTERNALlanguageId, /* language */
1597 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1598 prosrc[i], /* prosrc */
1601 false, /* isWindowFunc */
1602 false, /* security_definer */
1603 false, /* leakproof */
1604 false, /* isStrict */
1605 PROVOLATILE_IMMUTABLE, /* volatility */
1606 constructorArgTypesVector, /* parameterTypes */
1607 PointerGetDatum(NULL), /* allParameterTypes */
1608 PointerGetDatum(NULL), /* parameterModes */
1609 PointerGetDatum(NULL), /* parameterNames */
1610 NIL, /* parameterDefaults */
1611 PointerGetDatum(NULL), /* proconfig */
1616 * Make the constructors internally-dependent on the range type so
1617 * that they go away silently when the type is dropped. Note that
1618 * pg_dump depends on this choice to avoid dumping the constructors.
1620 myself.classId = ProcedureRelationId;
1621 myself.objectId = procOid;
1622 myself.objectSubId = 0;
1624 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1630 * Find suitable I/O functions for a type.
1632 * typeOid is the type's OID (which will already exist, if only as a shell
1637 findTypeInputFunction(List *procname, Oid typeOid)
1643 * Input functions can take a single argument of type CSTRING, or three
1644 * arguments (string, typioparam OID, typmod).
1646 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1647 * see this, we issue a warning and fix up the pg_proc entry.
1649 argList[0] = CSTRINGOID;
1651 procOid = LookupFuncName(procname, 1, argList, true);
1652 if (OidIsValid(procOid))
1655 argList[1] = OIDOID;
1656 argList[2] = INT4OID;
1658 procOid = LookupFuncName(procname, 3, argList, true);
1659 if (OidIsValid(procOid))
1662 /* No luck, try it with OPAQUE */
1663 argList[0] = OPAQUEOID;
1665 procOid = LookupFuncName(procname, 1, argList, true);
1667 if (!OidIsValid(procOid))
1669 argList[1] = OIDOID;
1670 argList[2] = INT4OID;
1672 procOid = LookupFuncName(procname, 3, argList, true);
1675 if (OidIsValid(procOid))
1677 /* Found, but must complain and fix the pg_proc entry */
1679 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1680 NameListToString(procname))));
1681 SetFunctionArgType(procOid, 0, CSTRINGOID);
1684 * Need CommandCounterIncrement since DefineType will likely try to
1685 * alter the pg_proc tuple again.
1687 CommandCounterIncrement();
1692 /* Use CSTRING (preferred) in the error message */
1693 argList[0] = CSTRINGOID;
1696 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1697 errmsg("function %s does not exist",
1698 func_signature_string(procname, 1, NIL, argList))));
1700 return InvalidOid; /* keep compiler quiet */
1704 findTypeOutputFunction(List *procname, Oid typeOid)
1710 * Output functions can take a single argument of the type.
1712 * For backwards compatibility we allow OPAQUE in place of the actual type
1713 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1715 argList[0] = typeOid;
1717 procOid = LookupFuncName(procname, 1, argList, true);
1718 if (OidIsValid(procOid))
1721 /* No luck, try it with OPAQUE */
1722 argList[0] = OPAQUEOID;
1724 procOid = LookupFuncName(procname, 1, argList, true);
1726 if (OidIsValid(procOid))
1728 /* Found, but must complain and fix the pg_proc entry */
1730 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1731 NameListToString(procname), format_type_be(typeOid))));
1732 SetFunctionArgType(procOid, 0, typeOid);
1735 * Need CommandCounterIncrement since DefineType will likely try to
1736 * alter the pg_proc tuple again.
1738 CommandCounterIncrement();
1743 /* Use type name, not OPAQUE, in the failure message. */
1744 argList[0] = typeOid;
1747 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1748 errmsg("function %s does not exist",
1749 func_signature_string(procname, 1, NIL, argList))));
1751 return InvalidOid; /* keep compiler quiet */
1755 findTypeReceiveFunction(List *procname, Oid typeOid)
1761 * Receive functions can take a single argument of type INTERNAL, or three
1762 * arguments (internal, typioparam OID, typmod).
1764 argList[0] = INTERNALOID;
1766 procOid = LookupFuncName(procname, 1, argList, true);
1767 if (OidIsValid(procOid))
1770 argList[1] = OIDOID;
1771 argList[2] = INT4OID;
1773 procOid = LookupFuncName(procname, 3, argList, true);
1774 if (OidIsValid(procOid))
1778 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1779 errmsg("function %s does not exist",
1780 func_signature_string(procname, 1, NIL, argList))));
1782 return InvalidOid; /* keep compiler quiet */
1786 findTypeSendFunction(List *procname, Oid typeOid)
1792 * Send functions can take a single argument of the type.
1794 argList[0] = typeOid;
1796 procOid = LookupFuncName(procname, 1, argList, true);
1797 if (OidIsValid(procOid))
1801 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1802 errmsg("function %s does not exist",
1803 func_signature_string(procname, 1, NIL, argList))));
1805 return InvalidOid; /* keep compiler quiet */
1809 findTypeTypmodinFunction(List *procname)
1815 * typmodin functions always take one cstring[] argument and return int4.
1817 argList[0] = CSTRINGARRAYOID;
1819 procOid = LookupFuncName(procname, 1, argList, true);
1820 if (!OidIsValid(procOid))
1822 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1823 errmsg("function %s does not exist",
1824 func_signature_string(procname, 1, NIL, argList))));
1826 if (get_func_rettype(procOid) != INT4OID)
1828 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1829 errmsg("typmod_in function %s must return type \"integer\"",
1830 NameListToString(procname))));
1836 findTypeTypmodoutFunction(List *procname)
1842 * typmodout functions always take one int4 argument and return cstring.
1844 argList[0] = INT4OID;
1846 procOid = LookupFuncName(procname, 1, argList, true);
1847 if (!OidIsValid(procOid))
1849 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1850 errmsg("function %s does not exist",
1851 func_signature_string(procname, 1, NIL, argList))));
1853 if (get_func_rettype(procOid) != CSTRINGOID)
1855 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1856 errmsg("typmod_out function %s must return type \"cstring\"",
1857 NameListToString(procname))));
1863 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1869 * Analyze functions always take one INTERNAL argument and return bool.
1871 argList[0] = INTERNALOID;
1873 procOid = LookupFuncName(procname, 1, argList, true);
1874 if (!OidIsValid(procOid))
1876 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1877 errmsg("function %s does not exist",
1878 func_signature_string(procname, 1, NIL, argList))));
1880 if (get_func_rettype(procOid) != BOOLOID)
1882 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1883 errmsg("type analyze function %s must return type \"boolean\"",
1884 NameListToString(procname))));
1890 * Find suitable support functions and opclasses for a range type.
1894 * Find named btree opclass for subtype, or default btree opclass if
1898 findRangeSubOpclass(List *opcname, Oid subtype)
1905 opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
1908 * Verify that the operator class accepts this datatype. Note we will
1909 * accept binary compatibility.
1911 opInputType = get_opclass_input_type(opcid);
1912 if (!IsBinaryCoercible(subtype, opInputType))
1914 (errcode(ERRCODE_DATATYPE_MISMATCH),
1915 errmsg("operator class \"%s\" does not accept data type %s",
1916 NameListToString(opcname),
1917 format_type_be(subtype))));
1921 opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
1922 if (!OidIsValid(opcid))
1924 /* We spell the error message identically to GetIndexOpClass */
1926 (errcode(ERRCODE_UNDEFINED_OBJECT),
1927 errmsg("data type %s has no default operator class for access method \"%s\"",
1928 format_type_be(subtype), "btree"),
1929 errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
1937 findRangeCanonicalFunction(List *procname, Oid typeOid)
1941 AclResult aclresult;
1944 * Range canonical functions must take and return the range type, and must
1947 argList[0] = typeOid;
1949 procOid = LookupFuncName(procname, 1, argList, true);
1951 if (!OidIsValid(procOid))
1953 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1954 errmsg("function %s does not exist",
1955 func_signature_string(procname, 1, NIL, argList))));
1957 if (get_func_rettype(procOid) != typeOid)
1959 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1960 errmsg("range canonical function %s must return range type",
1961 func_signature_string(procname, 1, NIL, argList))));
1963 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1965 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1966 errmsg("range canonical function %s must be immutable",
1967 func_signature_string(procname, 1, NIL, argList))));
1969 /* Also, range type's creator must have permission to call function */
1970 aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
1971 if (aclresult != ACLCHECK_OK)
1972 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
1978 findRangeSubtypeDiffFunction(List *procname, Oid subtype)
1982 AclResult aclresult;
1985 * Range subtype diff functions must take two arguments of the subtype,
1986 * must return float8, and must be immutable.
1988 argList[0] = subtype;
1989 argList[1] = subtype;
1991 procOid = LookupFuncName(procname, 2, argList, true);
1993 if (!OidIsValid(procOid))
1995 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1996 errmsg("function %s does not exist",
1997 func_signature_string(procname, 2, NIL, argList))));
1999 if (get_func_rettype(procOid) != FLOAT8OID)
2001 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2002 errmsg("range subtype diff function %s must return type double precision",
2003 func_signature_string(procname, 2, NIL, argList))));
2005 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2007 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2008 errmsg("range subtype diff function %s must be immutable",
2009 func_signature_string(procname, 2, NIL, argList))));
2011 /* Also, range type's creator must have permission to call function */
2012 aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
2013 if (aclresult != ACLCHECK_OK)
2014 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
2020 * AssignTypeArrayOid
2022 * Pre-assign the type's array OID for use in pg_type.typarray
2025 AssignTypeArrayOid(void)
2029 /* Use binary-upgrade override for pg_type.typarray? */
2030 if (IsBinaryUpgrade)
2032 if (!OidIsValid(binary_upgrade_next_array_pg_type_oid))
2034 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2035 errmsg("pg_type array OID value not set when in binary upgrade mode")));
2037 type_array_oid = binary_upgrade_next_array_pg_type_oid;
2038 binary_upgrade_next_array_pg_type_oid = InvalidOid;
2042 Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
2044 type_array_oid = GetNewOid(pg_type);
2045 heap_close(pg_type, AccessShareLock);
2048 return type_array_oid;
2052 /*-------------------------------------------------------------------
2053 * DefineCompositeType
2055 * Create a Composite Type relation.
2056 * `DefineRelation' does all the work, we just provide the correct
2059 * If the relation already exists, then 'DefineRelation' will abort
2062 * DefineCompositeType returns relid for use when creating
2063 * an implicit composite type during function creation
2064 *-------------------------------------------------------------------
2067 DefineCompositeType(RangeVar *typevar, List *coldeflist)
2069 CreateStmt *createStmt = makeNode(CreateStmt);
2075 * now set the parameters for keys/inheritance etc. All of these are
2076 * uninteresting for composite types...
2078 createStmt->relation = typevar;
2079 createStmt->tableElts = coldeflist;
2080 createStmt->inhRelations = NIL;
2081 createStmt->constraints = NIL;
2082 createStmt->options = NIL;
2083 createStmt->oncommit = ONCOMMIT_NOOP;
2084 createStmt->tablespacename = NULL;
2085 createStmt->if_not_exists = false;
2088 * Check for collision with an existing type name. If there is one and
2089 * it's an autogenerated array, we can rename it out of the way. This
2090 * check is here mainly to get a better error message about a "type"
2091 * instead of below about a "relation".
2093 typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2095 RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2097 GetSysCacheOid2(TYPENAMENSP,
2098 CStringGetDatum(createStmt->relation->relname),
2099 ObjectIdGetDatum(typeNamespace));
2100 if (OidIsValid(old_type_oid))
2102 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2104 (errcode(ERRCODE_DUPLICATE_OBJECT),
2105 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2109 * Finally create the relation. This also creates the type.
2111 relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
2112 Assert(relid != InvalidOid);
2117 * AlterDomainDefault
2119 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
2122 AlterDomainDefault(List *names, Node *defaultRaw)
2130 Node *defaultExpr = NULL; /* NULL if no default specified */
2131 Datum new_record[Natts_pg_type];
2132 bool new_record_nulls[Natts_pg_type];
2133 bool new_record_repl[Natts_pg_type];
2135 Form_pg_type typTup;
2137 /* Make a TypeName so we can use standard type lookup machinery */
2138 typename = makeTypeNameFromNameList(names);
2139 domainoid = typenameTypeId(NULL, typename);
2141 /* Look up the domain in the type table */
2142 rel = heap_open(TypeRelationId, RowExclusiveLock);
2144 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2145 if (!HeapTupleIsValid(tup))
2146 elog(ERROR, "cache lookup failed for type %u", domainoid);
2147 typTup = (Form_pg_type) GETSTRUCT(tup);
2149 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2150 checkDomainOwner(tup);
2152 /* Setup new tuple */
2153 MemSet(new_record, (Datum) 0, sizeof(new_record));
2154 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2155 MemSet(new_record_repl, false, sizeof(new_record_repl));
2157 /* Store the new default into the tuple */
2160 /* Create a dummy ParseState for transformExpr */
2161 pstate = make_parsestate(NULL);
2164 * Cook the colDef->raw_expr into an expression. Note: Name is
2165 * strictly for error message
2167 defaultExpr = cookDefault(pstate, defaultRaw,
2168 typTup->typbasetype,
2170 NameStr(typTup->typname));
2173 * If the expression is just a NULL constant, we treat the command
2174 * like ALTER ... DROP DEFAULT. (But see note for same test in
2177 if (defaultExpr == NULL ||
2178 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
2180 /* Default is NULL, drop it */
2181 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2182 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2183 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2184 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2189 * Expression must be stored as a nodeToString result, but we also
2190 * require a valid textual representation (mainly to make life
2191 * easier for pg_dump).
2193 defaultValue = deparse_expression(defaultExpr,
2197 * Form an updated tuple with the new default and write it back.
2199 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2201 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2202 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2203 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2208 /* ALTER ... DROP DEFAULT */
2209 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2210 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2211 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2212 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2215 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2216 new_record, new_record_nulls,
2219 simple_heap_update(rel, &tup->t_self, newtuple);
2221 CatalogUpdateIndexes(rel, newtuple);
2223 /* Rebuild dependencies */
2224 GenerateTypeDependencies(typTup->typnamespace,
2226 InvalidOid, /* typrelid is n/a */
2227 0, /* relation kind is n/a */
2237 false, /* a domain isn't an implicit array */
2238 typTup->typbasetype,
2239 typTup->typcollation,
2241 true); /* Rebuild is true */
2243 InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2246 heap_close(rel, NoLock);
2247 heap_freetuple(newtuple);
2253 * AlterDomainNotNull
2255 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2258 AlterDomainNotNull(List *names, bool notNull)
2264 Form_pg_type typTup;
2266 /* Make a TypeName so we can use standard type lookup machinery */
2267 typename = makeTypeNameFromNameList(names);
2268 domainoid = typenameTypeId(NULL, typename);
2270 /* Look up the domain in the type table */
2271 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2273 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2274 if (!HeapTupleIsValid(tup))
2275 elog(ERROR, "cache lookup failed for type %u", domainoid);
2276 typTup = (Form_pg_type) GETSTRUCT(tup);
2278 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2279 checkDomainOwner(tup);
2281 /* Is the domain already set to the desired constraint? */
2282 if (typTup->typnotnull == notNull)
2284 heap_close(typrel, RowExclusiveLock);
2288 /* Adding a NOT NULL constraint requires checking existing columns */
2294 /* Fetch relation list with attributes based on this domain */
2295 /* ShareLock is sufficient to prevent concurrent data changes */
2297 rels = get_rels_with_domain(domainoid, ShareLock);
2301 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2302 Relation testrel = rtc->rel;
2303 TupleDesc tupdesc = RelationGetDescr(testrel);
2308 /* Scan all tuples in this relation */
2309 snapshot = RegisterSnapshot(GetLatestSnapshot());
2310 scan = heap_beginscan(testrel, snapshot, 0, NULL);
2311 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2315 /* Test attributes that are of the domain */
2316 for (i = 0; i < rtc->natts; i++)
2318 int attnum = rtc->atts[i];
2320 if (heap_attisnull(tuple, attnum))
2323 * In principle the auxiliary information for this
2324 * error should be errdatatype(), but errtablecol()
2325 * seems considerably more useful in practice. Since
2326 * this code only executes in an ALTER DOMAIN command,
2327 * the client should already know which domain is in
2331 (errcode(ERRCODE_NOT_NULL_VIOLATION),
2332 errmsg("column \"%s\" of table \"%s\" contains null values",
2333 NameStr(tupdesc->attrs[attnum - 1]->attname),
2334 RelationGetRelationName(testrel)),
2335 errtablecol(testrel, attnum)));
2340 UnregisterSnapshot(snapshot);
2342 /* Close each rel after processing, but keep lock */
2343 heap_close(testrel, NoLock);
2348 * Okay to update pg_type row. We can scribble on typTup because it's a
2351 typTup->typnotnull = notNull;
2353 simple_heap_update(typrel, &tup->t_self, tup);
2355 CatalogUpdateIndexes(typrel, tup);
2357 InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2360 heap_freetuple(tup);
2361 heap_close(typrel, RowExclusiveLock);
2367 * AlterDomainDropConstraint
2369 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2372 AlterDomainDropConstraint(List *names, const char *constrName,
2373 DropBehavior behavior, bool missing_ok)
2380 SysScanDesc conscan;
2385 /* Make a TypeName so we can use standard type lookup machinery */
2386 typename = makeTypeNameFromNameList(names);
2387 domainoid = typenameTypeId(NULL, typename);
2389 /* Look up the domain in the type table */
2390 rel = heap_open(TypeRelationId, RowExclusiveLock);
2392 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2393 if (!HeapTupleIsValid(tup))
2394 elog(ERROR, "cache lookup failed for type %u", domainoid);
2396 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2397 checkDomainOwner(tup);
2399 /* Grab an appropriate lock on the pg_constraint relation */
2400 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2402 /* Use the index to scan only constraints of the target relation */
2403 ScanKeyInit(&key[0],
2404 Anum_pg_constraint_contypid,
2405 BTEqualStrategyNumber, F_OIDEQ,
2406 ObjectIdGetDatum(HeapTupleGetOid(tup)));
2408 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2412 * Scan over the result set, removing any matching entries.
2414 while ((contup = systable_getnext(conscan)) != NULL)
2416 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
2418 if (strcmp(NameStr(con->conname), constrName) == 0)
2420 ObjectAddress conobj;
2422 conobj.classId = ConstraintRelationId;
2423 conobj.objectId = HeapTupleGetOid(contup);
2424 conobj.objectSubId = 0;
2426 performDeletion(&conobj, behavior, 0);
2430 /* Clean up after the scan */
2431 systable_endscan(conscan);
2432 heap_close(conrel, RowExclusiveLock);
2434 heap_close(rel, NoLock);
2440 (errcode(ERRCODE_UNDEFINED_OBJECT),
2441 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2442 constrName, TypeNameToString(typename))));
2445 (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2446 constrName, TypeNameToString(typename))));
2453 * AlterDomainAddConstraint
2455 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2458 AlterDomainAddConstraint(List *names, Node *newConstraint)
2464 Form_pg_type typTup;
2468 /* Make a TypeName so we can use standard type lookup machinery */
2469 typename = makeTypeNameFromNameList(names);
2470 domainoid = typenameTypeId(NULL, typename);
2472 /* Look up the domain in the type table */
2473 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2475 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2476 if (!HeapTupleIsValid(tup))
2477 elog(ERROR, "cache lookup failed for type %u", domainoid);
2478 typTup = (Form_pg_type) GETSTRUCT(tup);
2480 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2481 checkDomainOwner(tup);
2483 if (!IsA(newConstraint, Constraint))
2484 elog(ERROR, "unrecognized node type: %d",
2485 (int) nodeTag(newConstraint));
2487 constr = (Constraint *) newConstraint;
2489 switch (constr->contype)
2492 /* processed below */
2497 (errcode(ERRCODE_SYNTAX_ERROR),
2498 errmsg("unique constraints not possible for domains")));
2501 case CONSTR_PRIMARY:
2503 (errcode(ERRCODE_SYNTAX_ERROR),
2504 errmsg("primary key constraints not possible for domains")));
2507 case CONSTR_EXCLUSION:
2509 (errcode(ERRCODE_SYNTAX_ERROR),
2510 errmsg("exclusion constraints not possible for domains")));
2513 case CONSTR_FOREIGN:
2515 (errcode(ERRCODE_SYNTAX_ERROR),
2516 errmsg("foreign key constraints not possible for domains")));
2519 case CONSTR_ATTR_DEFERRABLE:
2520 case CONSTR_ATTR_NOT_DEFERRABLE:
2521 case CONSTR_ATTR_DEFERRED:
2522 case CONSTR_ATTR_IMMEDIATE:
2524 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2525 errmsg("specifying constraint deferrability not supported for domains")));
2529 elog(ERROR, "unrecognized constraint subtype: %d",
2530 (int) constr->contype);
2535 * Since all other constraint types throw errors, this must be a check
2536 * constraint. First, process the constraint expression and add an entry
2540 ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
2541 typTup->typbasetype, typTup->typtypmod,
2542 constr, NameStr(typTup->typname));
2545 * If requested to validate the constraint, test all values stored in the
2546 * attributes based on the domain the constraint is being added to.
2548 if (!constr->skip_validation)
2549 validateDomainConstraint(domainoid, ccbin);
2552 heap_close(typrel, RowExclusiveLock);
2558 * AlterDomainValidateConstraint
2560 * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
2563 AlterDomainValidateConstraint(List *names, char *constrName)
2570 Form_pg_constraint con = NULL;
2571 Form_pg_constraint copy_con;
2578 HeapTuple copyTuple;
2581 /* Make a TypeName so we can use standard type lookup machinery */
2582 typename = makeTypeNameFromNameList(names);
2583 domainoid = typenameTypeId(NULL, typename);
2585 /* Look up the domain in the type table */
2586 typrel = heap_open(TypeRelationId, AccessShareLock);
2588 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2589 if (!HeapTupleIsValid(tup))
2590 elog(ERROR, "cache lookup failed for type %u", domainoid);
2592 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2593 checkDomainOwner(tup);
2596 * Find and check the target constraint
2598 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2600 Anum_pg_constraint_contypid,
2601 BTEqualStrategyNumber, F_OIDEQ,
2602 ObjectIdGetDatum(domainoid));
2603 scan = systable_beginscan(conrel, ConstraintTypidIndexId,
2604 true, NULL, 1, &key);
2606 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2608 con = (Form_pg_constraint) GETSTRUCT(tuple);
2609 if (strcmp(NameStr(con->conname), constrName) == 0)
2618 (errcode(ERRCODE_UNDEFINED_OBJECT),
2619 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2620 constrName, TypeNameToString(typename))));
2622 if (con->contype != CONSTRAINT_CHECK)
2624 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2625 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2626 constrName, TypeNameToString(typename))));
2628 val = SysCacheGetAttr(CONSTROID, tuple,
2629 Anum_pg_constraint_conbin,
2632 elog(ERROR, "null conbin for constraint %u",
2633 HeapTupleGetOid(tuple));
2634 conbin = TextDatumGetCString(val);
2636 validateDomainConstraint(domainoid, conbin);
2639 * Now update the catalog, while we have the door open.
2641 copyTuple = heap_copytuple(tuple);
2642 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2643 copy_con->convalidated = true;
2644 simple_heap_update(conrel, ©Tuple->t_self, copyTuple);
2645 CatalogUpdateIndexes(conrel, copyTuple);
2647 InvokeObjectPostAlterHook(ConstraintRelationId,
2648 HeapTupleGetOid(copyTuple), 0);
2650 heap_freetuple(copyTuple);
2652 systable_endscan(scan);
2654 heap_close(typrel, AccessShareLock);
2655 heap_close(conrel, RowExclusiveLock);
2657 ReleaseSysCache(tup);
2663 validateDomainConstraint(Oid domainoid, char *ccbin)
2665 Expr *expr = (Expr *) stringToNode(ccbin);
2669 ExprContext *econtext;
2670 ExprState *exprstate;
2672 /* Need an EState to run ExecEvalExpr */
2673 estate = CreateExecutorState();
2674 econtext = GetPerTupleExprContext(estate);
2676 /* build execution state for expr */
2677 exprstate = ExecPrepareExpr(expr, estate);
2679 /* Fetch relation list with attributes based on this domain */
2680 /* ShareLock is sufficient to prevent concurrent data changes */
2682 rels = get_rels_with_domain(domainoid, ShareLock);
2686 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2687 Relation testrel = rtc->rel;
2688 TupleDesc tupdesc = RelationGetDescr(testrel);
2693 /* Scan all tuples in this relation */
2694 snapshot = RegisterSnapshot(GetLatestSnapshot());
2695 scan = heap_beginscan(testrel, snapshot, 0, NULL);
2696 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2700 /* Test attributes that are of the domain */
2701 for (i = 0; i < rtc->natts; i++)
2703 int attnum = rtc->atts[i];
2708 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2710 econtext->domainValue_datum = d;
2711 econtext->domainValue_isNull = isNull;
2713 conResult = ExecEvalExprSwitchContext(exprstate,
2717 if (!isNull && !DatumGetBool(conResult))
2720 * In principle the auxiliary information for this error
2721 * should be errdomainconstraint(), but errtablecol()
2722 * seems considerably more useful in practice. Since this
2723 * code only executes in an ALTER DOMAIN command, the
2724 * client should already know which domain is in question,
2725 * and which constraint too.
2728 (errcode(ERRCODE_CHECK_VIOLATION),
2729 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2730 NameStr(tupdesc->attrs[attnum - 1]->attname),
2731 RelationGetRelationName(testrel)),
2732 errtablecol(testrel, attnum)));
2736 ResetExprContext(econtext);
2739 UnregisterSnapshot(snapshot);
2741 /* Hold relation lock till commit (XXX bad for concurrency) */
2742 heap_close(testrel, NoLock);
2745 FreeExecutorState(estate);
2749 * get_rels_with_domain
2751 * Fetch all relations / attributes which are using the domain
2753 * The result is a list of RelToCheck structs, one for each distinct
2754 * relation, each containing one or more attribute numbers that are of
2755 * the domain type. We have opened each rel and acquired the specified lock
2758 * We support nested domains by including attributes that are of derived
2759 * domain types. Current callers do not need to distinguish between attributes
2760 * that are of exactly the given domain and those that are of derived domains.
2762 * XXX this is completely broken because there is no way to lock the domain
2763 * to prevent columns from being added or dropped while our command runs.
2764 * We can partially protect against column drops by locking relations as we
2765 * come across them, but there is still a race condition (the window between
2766 * seeing a pg_depend entry and acquiring lock on the relation it references).
2767 * Also, holding locks on all these relations simultaneously creates a non-
2768 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2769 * risk by using the weakest suitable lock (ShareLock for most callers).
2771 * XXX the API for this is not sufficient to support checking domain values
2772 * that are inside composite types or arrays. Currently we just error out
2773 * if a composite type containing the target domain is stored anywhere.
2774 * There are not currently arrays of domains; if there were, we could take
2775 * the same approach, but it'd be nicer to fix it properly.
2777 * Generally used for retrieving a list of tests when adding
2778 * new constraints to a domain.
2781 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2786 SysScanDesc depScan;
2789 Assert(lockmode != NoLock);
2792 * We scan pg_depend to find those things that depend on the domain. (We
2793 * assume we can ignore refobjsubid for a domain.)
2795 depRel = heap_open(DependRelationId, AccessShareLock);
2797 ScanKeyInit(&key[0],
2798 Anum_pg_depend_refclassid,
2799 BTEqualStrategyNumber, F_OIDEQ,
2800 ObjectIdGetDatum(TypeRelationId));
2801 ScanKeyInit(&key[1],
2802 Anum_pg_depend_refobjid,
2803 BTEqualStrategyNumber, F_OIDEQ,
2804 ObjectIdGetDatum(domainOid));
2806 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2809 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2811 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2812 RelToCheck *rtc = NULL;
2814 Form_pg_attribute pg_att;
2817 /* Check for directly dependent types --- must be domains */
2818 if (pg_depend->classid == TypeRelationId)
2820 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2823 * Recursively add dependent columns to the output list. This is
2824 * a bit inefficient since we may fail to combine RelToCheck
2825 * entries when attributes of the same rel have different derived
2826 * domain types, but it's probably not worth improving.
2828 result = list_concat(result,
2829 get_rels_with_domain(pg_depend->objid,
2834 /* Else, ignore dependees that aren't user columns of relations */
2835 /* (we assume system columns are never of domain types) */
2836 if (pg_depend->classid != RelationRelationId ||
2837 pg_depend->objsubid <= 0)
2840 /* See if we already have an entry for this relation */
2841 foreach(rellist, result)
2843 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2845 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2854 /* First attribute found for this relation */
2857 /* Acquire requested lock on relation */
2858 rel = relation_open(pg_depend->objid, lockmode);
2861 * Check to see if rowtype is stored anyplace as a composite-type
2862 * column; if so we have to fail, for now anyway.
2864 if (OidIsValid(rel->rd_rel->reltype))
2865 find_composite_type_dependencies(rel->rd_rel->reltype,
2867 format_type_be(domainOid));
2870 * Otherwise, we can ignore relations except those with both
2871 * storage and user-chosen column types.
2873 * XXX If an index-only scan could satisfy "col::some_domain" from
2874 * a suitable expression index, this should also check expression
2877 if (rel->rd_rel->relkind != RELKIND_RELATION &&
2878 rel->rd_rel->relkind != RELKIND_MATVIEW)
2880 relation_close(rel, lockmode);
2884 /* Build the RelToCheck entry with enough space for all atts */
2885 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2888 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2889 result = lcons(rtc, result);
2893 * Confirm column has not been dropped, and is of the expected type.
2894 * This defends against an ALTER DROP COLUMN occurring just before we
2895 * acquired lock ... but if the whole table were dropped, we'd still
2898 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2900 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2901 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2905 * Okay, add column to result. We store the columns in column-number
2906 * order; this is just a hack to improve predictability of regression
2909 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2912 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2914 rtc->atts[ptr] = rtc->atts[ptr - 1];
2917 rtc->atts[ptr] = pg_depend->objsubid;
2920 systable_endscan(depScan);
2922 relation_close(depRel, AccessShareLock);
2930 * Check that the type is actually a domain and that the current user
2931 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2934 checkDomainOwner(HeapTuple tup)
2936 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2938 /* Check that this is actually a domain */
2939 if (typTup->typtype != TYPTYPE_DOMAIN)
2941 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2942 errmsg("%s is not a domain",
2943 format_type_be(HeapTupleGetOid(tup)))));
2945 /* Permission check: must own type */
2946 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2947 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
2951 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2954 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2955 int typMod, Constraint *constr,
2962 CoerceToDomainValue *domVal;
2965 * Assign or validate constraint name
2967 if (constr->conname)
2969 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2974 (errcode(ERRCODE_DUPLICATE_OBJECT),
2975 errmsg("constraint \"%s\" for domain \"%s\" already exists",
2976 constr->conname, domainName)));
2979 constr->conname = ChooseConstraintName(domainName,
2986 * Convert the A_EXPR in raw_expr into an EXPR
2988 pstate = make_parsestate(NULL);
2991 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2992 * the expression. Note that it will appear to have the type of the base
2993 * type, not the domain. This seems correct since within the check
2994 * expression, we should not assume the input value can be considered a
2995 * member of the domain.
2997 domVal = makeNode(CoerceToDomainValue);
2998 domVal->typeId = baseTypeOid;
2999 domVal->typeMod = typMod;
3000 domVal->collation = get_typcollation(baseTypeOid);
3001 domVal->location = -1; /* will be set when/if used */
3003 pstate->p_value_substitute = (Node *) domVal;
3005 expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
3008 * Make sure it yields a boolean result.
3010 expr = coerce_to_boolean(pstate, expr, "CHECK");
3013 * Fix up collation information.
3015 assign_expr_collations(pstate, expr);
3018 * Domains don't allow variables (this is probably dead code now that
3019 * add_missing_from is history, but let's be sure).
3021 if (list_length(pstate->p_rtable) != 0 ||
3022 contain_var_clause(expr))
3024 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3025 errmsg("cannot use table references in domain check constraint")));
3028 * Convert to string form for storage.
3030 ccbin = nodeToString(expr);
3033 * Deparse it to produce text for consrc.
3035 ccsrc = deparse_expression(expr,
3039 * Store the constraint in pg_constraint
3041 CreateConstraintEntry(constr->conname, /* Constraint Name */
3042 domainNamespace, /* namespace */
3043 CONSTRAINT_CHECK, /* Constraint Type */
3044 false, /* Is Deferrable */
3045 false, /* Is Deferred */
3046 !constr->skip_validation, /* Is Validated */
3047 InvalidOid, /* not a relation constraint */
3050 domainOid, /* domain constraint */
3051 InvalidOid, /* no associated index */
3052 InvalidOid, /* Foreign key fields */
3061 NULL, /* not an exclusion constraint */
3062 expr, /* Tree form of check constraint */
3063 ccbin, /* Binary form of check constraint */
3064 ccsrc, /* Source form of check constraint */
3065 true, /* is local */
3067 false, /* connoinherit */
3068 false); /* is_internal */
3071 * Return the compiled constraint expression so the calling routine can
3072 * perform any additional required tests.
3079 * Execute ALTER TYPE RENAME
3082 RenameType(RenameStmt *stmt)
3084 List *names = stmt->object;
3085 const char *newTypeName = stmt->newname;
3090 Form_pg_type typTup;
3092 /* Make a TypeName so we can use standard type lookup machinery */
3093 typename = makeTypeNameFromNameList(names);
3094 typeOid = typenameTypeId(NULL, typename);
3096 /* Look up the type in the type table */
3097 rel = heap_open(TypeRelationId, RowExclusiveLock);
3099 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3100 if (!HeapTupleIsValid(tup))
3101 elog(ERROR, "cache lookup failed for type %u", typeOid);
3102 typTup = (Form_pg_type) GETSTRUCT(tup);
3104 /* check permissions on type */
3105 if (!pg_type_ownercheck(typeOid, GetUserId()))
3106 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3108 /* ALTER DOMAIN used on a non-domain? */
3109 if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3111 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3112 errmsg("\"%s\" is not a domain",
3113 format_type_be(typeOid))));
3116 * If it's a composite type, we need to check that it really is a
3117 * free-standing composite type, and not a table's rowtype. We want people
3118 * to use ALTER TABLE not ALTER TYPE for that case.
3120 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3121 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3123 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3124 errmsg("%s is a table's row type",
3125 format_type_be(typeOid)),
3126 errhint("Use ALTER TABLE instead.")));
3128 /* don't allow direct alteration of array types, either */
3129 if (OidIsValid(typTup->typelem) &&
3130 get_array_type(typTup->typelem) == typeOid)
3132 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3133 errmsg("cannot alter array type %s",
3134 format_type_be(typeOid)),
3135 errhint("You can alter type %s, which will alter the array type as well.",
3136 format_type_be(typTup->typelem))));
3139 * If type is composite we need to rename associated pg_class entry too.
3140 * RenameRelationInternal will call RenameTypeInternal automatically.
3142 if (typTup->typtype == TYPTYPE_COMPOSITE)
3143 RenameRelationInternal(typTup->typrelid, newTypeName, false);
3145 RenameTypeInternal(typeOid, newTypeName,
3146 typTup->typnamespace);
3149 heap_close(rel, RowExclusiveLock);
3155 * Change the owner of a type.
3158 AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
3165 Form_pg_type typTup;
3166 AclResult aclresult;
3168 rel = heap_open(TypeRelationId, RowExclusiveLock);
3170 /* Make a TypeName so we can use standard type lookup machinery */
3171 typename = makeTypeNameFromNameList(names);
3173 /* Use LookupTypeName here so that shell types can be processed */
3174 tup = LookupTypeName(NULL, typename, NULL, false);
3177 (errcode(ERRCODE_UNDEFINED_OBJECT),
3178 errmsg("type \"%s\" does not exist",
3179 TypeNameToString(typename))));
3180 typeOid = typeTypeId(tup);
3182 /* Copy the syscache entry so we can scribble on it below */
3183 newtup = heap_copytuple(tup);
3184 ReleaseSysCache(tup);
3186 typTup = (Form_pg_type) GETSTRUCT(tup);
3188 /* Don't allow ALTER DOMAIN on a type */
3189 if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3191 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3192 errmsg("%s is not a domain",
3193 format_type_be(typeOid))));
3196 * If it's a composite type, we need to check that it really is a
3197 * free-standing composite type, and not a table's rowtype. We want people
3198 * to use ALTER TABLE not ALTER TYPE for that case.
3200 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3201 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3203 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3204 errmsg("%s is a table's row type",
3205 format_type_be(typeOid)),
3206 errhint("Use ALTER TABLE instead.")));
3208 /* don't allow direct alteration of array types, either */
3209 if (OidIsValid(typTup->typelem) &&
3210 get_array_type(typTup->typelem) == typeOid)
3212 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3213 errmsg("cannot alter array type %s",
3214 format_type_be(typeOid)),
3215 errhint("You can alter type %s, which will alter the array type as well.",
3216 format_type_be(typTup->typelem))));
3219 * If the new owner is the same as the existing owner, consider the
3220 * command to have succeeded. This is for dump restoration purposes.
3222 if (typTup->typowner != newOwnerId)
3224 /* Superusers can always do it */
3227 /* Otherwise, must be owner of the existing object */
3228 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
3229 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
3231 /* Must be able to become new owner */
3232 check_is_member_of_role(GetUserId(), newOwnerId);
3234 /* New owner must have CREATE privilege on namespace */
3235 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3238 if (aclresult != ACLCHECK_OK)
3239 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
3240 get_namespace_name(typTup->typnamespace));
3244 * If it's a composite type, invoke ATExecChangeOwner so that we fix
3245 * up the pg_class entry properly. That will call back to
3246 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3248 if (typTup->typtype == TYPTYPE_COMPOSITE)
3249 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3252 Datum repl_val[Natts_pg_type];
3253 bool repl_null[Natts_pg_type];
3254 bool repl_repl[Natts_pg_type];
3259 memset(repl_null, false, sizeof(repl_null));
3260 memset(repl_repl, false, sizeof(repl_repl));
3262 repl_repl[Anum_pg_type_typowner - 1] = true;
3263 repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
3265 aclDatum = heap_getattr(tup,
3266 Anum_pg_type_typacl,
3267 RelationGetDescr(rel),
3269 /* Null ACLs do not require changes */
3272 newAcl = aclnewowner(DatumGetAclP(aclDatum),
3273 typTup->typowner, newOwnerId);
3274 repl_repl[Anum_pg_type_typacl - 1] = true;
3275 repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3278 tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3281 simple_heap_update(rel, &tup->t_self, tup);
3283 CatalogUpdateIndexes(rel, tup);
3285 /* Update owner dependency reference */
3286 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3288 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3290 /* If it has an array type, update that too */
3291 if (OidIsValid(typTup->typarray))
3292 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3297 heap_close(rel, RowExclusiveLock);
3303 * AlterTypeOwnerInternal - change type owner unconditionally
3305 * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
3306 * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
3307 * It assumes the caller has done all needed checks. The function will
3308 * automatically recurse to an array type if the type has one.
3310 * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
3311 * entry (ie, it's not a table rowtype nor an array type).
3312 * is_primary_ops should be TRUE if this function is invoked with user's
3313 * direct operation (e.g, shdepReassignOwned). Elsewhere,
3316 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
3317 bool hasDependEntry)
3321 Form_pg_type typTup;
3322 Datum repl_val[Natts_pg_type];
3323 bool repl_null[Natts_pg_type];
3324 bool repl_repl[Natts_pg_type];
3329 rel = heap_open(TypeRelationId, RowExclusiveLock);
3331 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3332 if (!HeapTupleIsValid(tup))
3333 elog(ERROR, "cache lookup failed for type %u", typeOid);
3334 typTup = (Form_pg_type) GETSTRUCT(tup);
3336 memset(repl_null, false, sizeof(repl_null));
3337 memset(repl_repl, false, sizeof(repl_repl));
3339 repl_repl[Anum_pg_type_typowner - 1] = true;
3340 repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
3342 aclDatum = heap_getattr(tup,
3343 Anum_pg_type_typacl,
3344 RelationGetDescr(rel),
3346 /* Null ACLs do not require changes */
3349 newAcl = aclnewowner(DatumGetAclP(aclDatum),
3350 typTup->typowner, newOwnerId);
3351 repl_repl[Anum_pg_type_typacl - 1] = true;
3352 repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3355 tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3358 simple_heap_update(rel, &tup->t_self, tup);
3360 CatalogUpdateIndexes(rel, tup);
3362 /* Update owner dependency reference, if it has one */
3364 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3366 /* If it has an array type, update that too */
3367 if (OidIsValid(typTup->typarray))
3368 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3370 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3373 heap_close(rel, RowExclusiveLock);
3377 * Execute ALTER TYPE SET SCHEMA
3380 AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype)
3385 ObjectAddresses *objsMoved;
3387 /* Make a TypeName so we can use standard type lookup machinery */
3388 typename = makeTypeNameFromNameList(names);
3389 typeOid = typenameTypeId(NULL, typename);
3391 /* Don't allow ALTER DOMAIN on a type */
3392 if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3394 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3395 errmsg("%s is not a domain",
3396 format_type_be(typeOid))));
3398 /* get schema OID and check its permissions */
3399 nspOid = LookupCreationNamespace(newschema);
3401 objsMoved = new_object_addresses();
3402 AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3403 free_object_addresses(objsMoved);
3409 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
3413 /* check permissions on type */
3414 if (!pg_type_ownercheck(typeOid, GetUserId()))
3415 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3417 /* don't allow direct alteration of array types */
3418 elemOid = get_element_type(typeOid);
3419 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3421 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3422 errmsg("cannot alter array type %s",
3423 format_type_be(typeOid)),
3424 errhint("You can alter type %s, which will alter the array type as well.",
3425 format_type_be(elemOid))));
3427 /* and do the work */
3428 return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3432 * Move specified type to new namespace.
3434 * Caller must have already checked privileges.
3436 * The function automatically recurses to process the type's array type,
3437 * if any. isImplicitArray should be TRUE only when doing this internal
3438 * recursion (outside callers must never try to move an array type directly).
3440 * If errorOnTableType is TRUE, the function errors out if the type is
3441 * a table type. ALTER TABLE has to be used to move a table to a new
3444 * Returns the type's old namespace OID.
3447 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
3448 bool isImplicitArray,
3449 bool errorOnTableType,
3450 ObjectAddresses *objsMoved)
3454 Form_pg_type typform;
3457 bool isCompositeType;
3458 ObjectAddress thisobj;
3461 * Make sure we haven't moved this object previously.
3463 thisobj.classId = TypeRelationId;
3464 thisobj.objectId = typeOid;
3465 thisobj.objectSubId = 0;
3467 if (object_address_present(&thisobj, objsMoved))
3470 rel = heap_open(TypeRelationId, RowExclusiveLock);
3472 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3473 if (!HeapTupleIsValid(tup))
3474 elog(ERROR, "cache lookup failed for type %u", typeOid);
3475 typform = (Form_pg_type) GETSTRUCT(tup);
3477 oldNspOid = typform->typnamespace;
3478 arrayOid = typform->typarray;
3480 /* common checks on switching namespaces */
3481 CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
3483 /* check for duplicate name (more friendly than unique-index failure) */
3484 if (SearchSysCacheExists2(TYPENAMENSP,
3485 CStringGetDatum(NameStr(typform->typname)),
3486 ObjectIdGetDatum(nspOid)))
3488 (errcode(ERRCODE_DUPLICATE_OBJECT),
3489 errmsg("type \"%s\" already exists in schema \"%s\"",
3490 NameStr(typform->typname),
3491 get_namespace_name(nspOid))));
3493 /* Detect whether type is a composite type (but not a table rowtype) */
3495 (typform->typtype == TYPTYPE_COMPOSITE &&
3496 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3498 /* Enforce not-table-type if requested */
3499 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3502 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3503 errmsg("%s is a table's row type",
3504 format_type_be(typeOid)),
3505 errhint("Use ALTER TABLE instead.")));
3507 /* OK, modify the pg_type row */
3509 /* tup is a copy, so we can scribble directly on it */
3510 typform->typnamespace = nspOid;
3512 simple_heap_update(rel, &tup->t_self, tup);
3513 CatalogUpdateIndexes(rel, tup);
3516 * Composite types have pg_class entries.
3518 * We need to modify the pg_class tuple as well to reflect the change of
3521 if (isCompositeType)
3525 classRel = heap_open(RelationRelationId, RowExclusiveLock);
3527 AlterRelationNamespaceInternal(classRel, typform->typrelid,
3531 heap_close(classRel, RowExclusiveLock);
3534 * Check for constraints associated with the composite type (we don't
3535 * currently support this, but probably will someday).
3537 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3538 nspOid, false, objsMoved);
3542 /* If it's a domain, it might have constraints */
3543 if (typform->typtype == TYPTYPE_DOMAIN)
3544 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
3549 * Update dependency on schema, if any --- a table rowtype has not got
3550 * one, and neither does an implicit array.
3552 if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3554 if (changeDependencyFor(TypeRelationId, typeOid,
3555 NamespaceRelationId, oldNspOid, nspOid) != 1)
3556 elog(ERROR, "failed to change schema dependency for type %s",
3557 format_type_be(typeOid));
3559 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3561 heap_freetuple(tup);
3563 heap_close(rel, RowExclusiveLock);
3565 add_exact_object_address(&thisobj, objsMoved);
3567 /* Recursively alter the associated array type, if any */
3568 if (OidIsValid(arrayOid))
3569 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);