1 /*-------------------------------------------------------------------------
4 * Routines for SQL commands that manipulate types (and domains).
6 * Portions Copyright (c) 1996-2014, 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/genam.h"
35 #include "access/heapam.h"
36 #include "access/htup_details.h"
37 #include "access/xact.h"
38 #include "catalog/binary_upgrade.h"
39 #include "catalog/catalog.h"
40 #include "catalog/dependency.h"
41 #include "catalog/heap.h"
42 #include "catalog/indexing.h"
43 #include "catalog/objectaccess.h"
44 #include "catalog/pg_authid.h"
45 #include "catalog/pg_collation.h"
46 #include "catalog/pg_constraint.h"
47 #include "catalog/pg_depend.h"
48 #include "catalog/pg_enum.h"
49 #include "catalog/pg_language.h"
50 #include "catalog/pg_namespace.h"
51 #include "catalog/pg_proc.h"
52 #include "catalog/pg_proc_fn.h"
53 #include "catalog/pg_range.h"
54 #include "catalog/pg_type.h"
55 #include "catalog/pg_type_fn.h"
56 #include "commands/defrem.h"
57 #include "commands/tablecmds.h"
58 #include "commands/typecmds.h"
59 #include "executor/executor.h"
60 #include "miscadmin.h"
61 #include "nodes/makefuncs.h"
62 #include "optimizer/planner.h"
63 #include "optimizer/var.h"
64 #include "parser/parse_coerce.h"
65 #include "parser/parse_collate.h"
66 #include "parser/parse_expr.h"
67 #include "parser/parse_func.h"
68 #include "parser/parse_type.h"
69 #include "utils/acl.h"
70 #include "utils/builtins.h"
71 #include "utils/fmgroids.h"
72 #include "utils/lsyscache.h"
73 #include "utils/memutils.h"
74 #include "utils/rel.h"
75 #include "utils/snapmgr.h"
76 #include "utils/syscache.h"
77 #include "utils/tqual.h"
80 /* result structure for get_rels_with_domain() */
83 Relation rel; /* opened and locked relation */
84 int natts; /* number of attributes of interest */
85 int *atts; /* attribute numbers */
86 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
89 /* Potentially set by contrib/pg_upgrade_support functions */
90 Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
92 static void makeRangeConstructors(const char *name, Oid namespace,
93 Oid rangeOid, Oid subtype);
94 static Oid findTypeInputFunction(List *procname, Oid typeOid);
95 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
96 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
97 static Oid findTypeSendFunction(List *procname, Oid typeOid);
98 static Oid findTypeTypmodinFunction(List *procname);
99 static Oid findTypeTypmodoutFunction(List *procname);
100 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
101 static Oid findRangeSubOpclass(List *opcname, Oid subtype);
102 static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
103 static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
104 static void validateDomainConstraint(Oid domainoid, char *ccbin);
105 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
106 static void checkEnumOwner(HeapTuple tup);
107 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
109 int typMod, Constraint *constr,
115 * Registers a new base type.
118 DefineType(List *names, List *parameters)
122 int16 internalLength = -1; /* default: variable-length */
123 List *inputName = NIL;
124 List *outputName = NIL;
125 List *receiveName = NIL;
126 List *sendName = NIL;
127 List *typmodinName = NIL;
128 List *typmodoutName = NIL;
129 List *analyzeName = NIL;
130 char category = TYPCATEGORY_USER;
131 bool preferred = false;
132 char delimiter = DEFAULT_TYPDELIM;
133 Oid elemType = InvalidOid;
134 char *defaultValue = NULL;
135 bool byValue = false;
136 char alignment = 'i'; /* default alignment */
137 char storage = 'p'; /* default TOAST storage method */
138 Oid collation = InvalidOid;
139 DefElem *likeTypeEl = NULL;
140 DefElem *internalLengthEl = NULL;
141 DefElem *inputNameEl = NULL;
142 DefElem *outputNameEl = NULL;
143 DefElem *receiveNameEl = NULL;
144 DefElem *sendNameEl = NULL;
145 DefElem *typmodinNameEl = NULL;
146 DefElem *typmodoutNameEl = NULL;
147 DefElem *analyzeNameEl = NULL;
148 DefElem *categoryEl = NULL;
149 DefElem *preferredEl = NULL;
150 DefElem *delimiterEl = NULL;
151 DefElem *elemTypeEl = NULL;
152 DefElem *defaultValueEl = NULL;
153 DefElem *byValueEl = NULL;
154 DefElem *alignmentEl = NULL;
155 DefElem *storageEl = NULL;
156 DefElem *collatableEl = NULL;
159 Oid receiveOid = InvalidOid;
160 Oid sendOid = InvalidOid;
161 Oid typmodinOid = InvalidOid;
162 Oid typmodoutOid = InvalidOid;
163 Oid analyzeOid = InvalidOid;
171 * As of Postgres 8.4, we require superuser privilege to create a base
172 * type. This is simple paranoia: there are too many ways to mess up the
173 * system with an incorrect type definition (for instance, representation
174 * parameters that don't match what the C code expects). In practice it
175 * takes superuser privilege to create the I/O functions, and so the
176 * former requirement that you own the I/O functions pretty much forced
177 * superuserness anyway. We're just making doubly sure here.
179 * XXX re-enable NOT_USED code sections below if you remove this test.
183 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
184 errmsg("must be superuser to create a base type")));
186 /* Convert list of names to a name and namespace */
187 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
190 /* XXX this is unnecessary given the superuser check above */
191 /* Check we have creation rights in target namespace */
192 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
193 if (aclresult != ACLCHECK_OK)
194 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
195 get_namespace_name(typeNamespace));
199 * Look to see if type already exists (presumably as a shell; if not,
200 * TypeCreate will complain).
202 typoid = GetSysCacheOid2(TYPENAMENSP,
203 CStringGetDatum(typeName),
204 ObjectIdGetDatum(typeNamespace));
207 * If it's not a shell, see if it's an autogenerated array type, and if so
208 * rename it out of the way.
210 if (OidIsValid(typoid) && get_typisdefined(typoid))
212 if (moveArrayTypeName(typoid, typeName, typeNamespace))
217 * If it doesn't exist, create it as a shell, so that the OID is known for
218 * use in the I/O function definitions.
220 if (!OidIsValid(typoid))
222 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
223 /* Make new shell type visible for modification below */
224 CommandCounterIncrement();
227 * If the command was a parameterless CREATE TYPE, we're done ---
228 * creating the shell type was all we're supposed to do.
230 if (parameters == NIL)
235 /* Complain if dummy CREATE TYPE and entry already exists */
236 if (parameters == NIL)
238 (errcode(ERRCODE_DUPLICATE_OBJECT),
239 errmsg("type \"%s\" already exists", typeName)));
242 /* Extract the parameters from the parameter list */
243 foreach(pl, parameters)
245 DefElem *defel = (DefElem *) lfirst(pl);
248 if (pg_strcasecmp(defel->defname, "like") == 0)
249 defelp = &likeTypeEl;
250 else if (pg_strcasecmp(defel->defname, "internallength") == 0)
251 defelp = &internalLengthEl;
252 else if (pg_strcasecmp(defel->defname, "input") == 0)
253 defelp = &inputNameEl;
254 else if (pg_strcasecmp(defel->defname, "output") == 0)
255 defelp = &outputNameEl;
256 else if (pg_strcasecmp(defel->defname, "receive") == 0)
257 defelp = &receiveNameEl;
258 else if (pg_strcasecmp(defel->defname, "send") == 0)
259 defelp = &sendNameEl;
260 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
261 defelp = &typmodinNameEl;
262 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
263 defelp = &typmodoutNameEl;
264 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
265 pg_strcasecmp(defel->defname, "analyse") == 0)
266 defelp = &analyzeNameEl;
267 else if (pg_strcasecmp(defel->defname, "category") == 0)
268 defelp = &categoryEl;
269 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
270 defelp = &preferredEl;
271 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
272 defelp = &delimiterEl;
273 else if (pg_strcasecmp(defel->defname, "element") == 0)
274 defelp = &elemTypeEl;
275 else if (pg_strcasecmp(defel->defname, "default") == 0)
276 defelp = &defaultValueEl;
277 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
279 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
280 defelp = &alignmentEl;
281 else if (pg_strcasecmp(defel->defname, "storage") == 0)
283 else if (pg_strcasecmp(defel->defname, "collatable") == 0)
284 defelp = &collatableEl;
287 /* WARNING, not ERROR, for historical backwards-compatibility */
289 (errcode(ERRCODE_SYNTAX_ERROR),
290 errmsg("type attribute \"%s\" not recognized",
296 (errcode(ERRCODE_SYNTAX_ERROR),
297 errmsg("conflicting or redundant options")));
302 * Now interpret the options; we do this separately so that LIKE can be
303 * overridden by other options regardless of the ordering in the parameter
309 Form_pg_type likeForm;
311 likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
312 likeForm = (Form_pg_type) GETSTRUCT(likeType);
313 internalLength = likeForm->typlen;
314 byValue = likeForm->typbyval;
315 alignment = likeForm->typalign;
316 storage = likeForm->typstorage;
317 ReleaseSysCache(likeType);
319 if (internalLengthEl)
320 internalLength = defGetTypeLength(internalLengthEl);
322 inputName = defGetQualifiedName(inputNameEl);
324 outputName = defGetQualifiedName(outputNameEl);
326 receiveName = defGetQualifiedName(receiveNameEl);
328 sendName = defGetQualifiedName(sendNameEl);
330 typmodinName = defGetQualifiedName(typmodinNameEl);
332 typmodoutName = defGetQualifiedName(typmodoutNameEl);
334 analyzeName = defGetQualifiedName(analyzeNameEl);
337 char *p = defGetString(categoryEl);
340 /* restrict to non-control ASCII */
341 if (category < 32 || category > 126)
343 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
344 errmsg("invalid type category \"%s\": must be simple ASCII",
348 preferred = defGetBoolean(preferredEl);
351 char *p = defGetString(delimiterEl);
354 /* XXX shouldn't we restrict the delimiter? */
358 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
359 /* disallow arrays of pseudotypes */
360 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
362 (errcode(ERRCODE_DATATYPE_MISMATCH),
363 errmsg("array element type cannot be %s",
364 format_type_be(elemType))));
367 defaultValue = defGetString(defaultValueEl);
369 byValue = defGetBoolean(byValueEl);
372 char *a = defGetString(alignmentEl);
375 * Note: if argument was an unquoted identifier, parser will have
376 * applied translations to it, so be prepared to recognize translated
377 * type names as well as the nominal form.
379 if (pg_strcasecmp(a, "double") == 0 ||
380 pg_strcasecmp(a, "float8") == 0 ||
381 pg_strcasecmp(a, "pg_catalog.float8") == 0)
383 else if (pg_strcasecmp(a, "int4") == 0 ||
384 pg_strcasecmp(a, "pg_catalog.int4") == 0)
386 else if (pg_strcasecmp(a, "int2") == 0 ||
387 pg_strcasecmp(a, "pg_catalog.int2") == 0)
389 else if (pg_strcasecmp(a, "char") == 0 ||
390 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
394 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
395 errmsg("alignment \"%s\" not recognized", a)));
399 char *a = defGetString(storageEl);
401 if (pg_strcasecmp(a, "plain") == 0)
403 else if (pg_strcasecmp(a, "external") == 0)
405 else if (pg_strcasecmp(a, "extended") == 0)
407 else if (pg_strcasecmp(a, "main") == 0)
411 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
412 errmsg("storage \"%s\" not recognized", a)));
415 collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
418 * make sure we have our required definitions
420 if (inputName == NIL)
422 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
423 errmsg("type input function must be specified")));
424 if (outputName == NIL)
426 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
427 errmsg("type output function must be specified")));
429 if (typmodinName == NIL && typmodoutName != NIL)
431 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
432 errmsg("type modifier output function is useless without a type modifier input function")));
435 * Convert I/O proc names to OIDs
437 inputOid = findTypeInputFunction(inputName, typoid);
438 outputOid = findTypeOutputFunction(outputName, typoid);
440 receiveOid = findTypeReceiveFunction(receiveName, typoid);
442 sendOid = findTypeSendFunction(sendName, typoid);
445 * Verify that I/O procs return the expected thing. If we see OPAQUE,
446 * complain and change it to the correct type-safe choice.
448 resulttype = get_func_rettype(inputOid);
449 if (resulttype != typoid)
451 if (resulttype == OPAQUEOID)
453 /* backwards-compatibility hack */
455 (errmsg("changing return type of function %s from \"opaque\" to %s",
456 NameListToString(inputName), typeName)));
457 SetFunctionReturnType(inputOid, typoid);
461 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
462 errmsg("type input function %s must return type %s",
463 NameListToString(inputName), typeName)));
465 resulttype = get_func_rettype(outputOid);
466 if (resulttype != CSTRINGOID)
468 if (resulttype == OPAQUEOID)
470 /* backwards-compatibility hack */
472 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
473 NameListToString(outputName))));
474 SetFunctionReturnType(outputOid, CSTRINGOID);
478 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
479 errmsg("type output function %s must return type \"cstring\"",
480 NameListToString(outputName))));
484 resulttype = get_func_rettype(receiveOid);
485 if (resulttype != typoid)
487 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
488 errmsg("type receive function %s must return type %s",
489 NameListToString(receiveName), typeName)));
493 resulttype = get_func_rettype(sendOid);
494 if (resulttype != BYTEAOID)
496 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
497 errmsg("type send function %s must return type \"bytea\"",
498 NameListToString(sendName))));
502 * Convert typmodin/out function proc names to OIDs.
505 typmodinOid = findTypeTypmodinFunction(typmodinName);
507 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
510 * Convert analysis function proc name to an OID. If no analysis function
511 * is specified, we'll use zero to select the built-in default algorithm.
514 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
517 * Check permissions on functions. We choose to require the creator/owner
518 * of a type to also own the underlying functions. Since creating a type
519 * is tantamount to granting public execute access on the functions, the
520 * minimum sane check would be for execute-with-grant-option. But we
521 * don't have a way to make the type go away if the grant option is
522 * revoked, so ownership seems better.
525 /* XXX this is unnecessary given the superuser check above */
526 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
527 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
528 NameListToString(inputName));
529 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
530 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
531 NameListToString(outputName));
532 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
533 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
534 NameListToString(receiveName));
535 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
536 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
537 NameListToString(sendName));
538 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
539 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
540 NameListToString(typmodinName));
541 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
542 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
543 NameListToString(typmodoutName));
544 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
545 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
546 NameListToString(analyzeName));
549 array_oid = AssignTypeArrayOid();
552 * now have TypeCreate do all the real work.
554 * Note: the pg_type.oid is stored in user tables as array elements (base
555 * types) in ArrayType and in composite types in DatumTupleFields. This
556 * oid must be preserved by binary upgrades.
559 TypeCreate(InvalidOid, /* no predetermined type OID */
560 typeName, /* type name */
561 typeNamespace, /* namespace */
562 InvalidOid, /* relation oid (n/a here) */
563 0, /* relation kind (ditto) */
564 GetUserId(), /* owner's ID */
565 internalLength, /* internal size */
566 TYPTYPE_BASE, /* type-type (base type) */
567 category, /* type-category */
568 preferred, /* is it a preferred type? */
569 delimiter, /* array element delimiter */
570 inputOid, /* input procedure */
571 outputOid, /* output procedure */
572 receiveOid, /* receive procedure */
573 sendOid, /* send procedure */
574 typmodinOid, /* typmodin procedure */
575 typmodoutOid, /* typmodout procedure */
576 analyzeOid, /* analyze procedure */
577 elemType, /* element type ID */
578 false, /* this is not an array type */
579 array_oid, /* array type we are about to create */
580 InvalidOid, /* base type ID (only for domains) */
581 defaultValue, /* default type value */
582 NULL, /* no binary form available */
583 byValue, /* passed by value */
584 alignment, /* required alignment */
585 storage, /* TOAST strategy */
586 -1, /* typMod (Domains only) */
587 0, /* Array Dimensions of typbasetype */
588 false, /* Type NOT NULL */
589 collation); /* type's collation */
592 * Create the array type that goes with it.
594 array_type = makeArrayTypeName(typeName, typeNamespace);
596 /* alignment must be 'i' or 'd' for arrays */
597 alignment = (alignment == 'd') ? 'd' : 'i';
599 typoid = TypeCreate(array_oid, /* force assignment of this type OID */
600 array_type, /* type name */
601 typeNamespace, /* namespace */
602 InvalidOid, /* relation oid (n/a here) */
603 0, /* relation kind (ditto) */
604 GetUserId(), /* owner's ID */
605 -1, /* internal size (always varlena) */
606 TYPTYPE_BASE, /* type-type (base type) */
607 TYPCATEGORY_ARRAY, /* type-category (array) */
608 false, /* array types are never preferred */
609 delimiter, /* array element delimiter */
610 F_ARRAY_IN, /* input procedure */
611 F_ARRAY_OUT, /* output procedure */
612 F_ARRAY_RECV, /* receive procedure */
613 F_ARRAY_SEND, /* send procedure */
614 typmodinOid, /* typmodin procedure */
615 typmodoutOid, /* typmodout procedure */
616 F_ARRAY_TYPANALYZE, /* analyze procedure */
617 typoid, /* element type ID */
618 true, /* yes this is an array type */
619 InvalidOid, /* no further array type */
620 InvalidOid, /* base type ID */
621 NULL, /* never a default type value */
622 NULL, /* binary default isn't sent either */
623 false, /* never passed by value */
624 alignment, /* see above */
625 'x', /* ARRAY is always toastable */
626 -1, /* typMod (Domains only) */
627 0, /* Array dimensions of typbasetype */
628 false, /* Type NOT NULL */
629 collation); /* type's collation */
637 * Guts of type deletion.
640 RemoveTypeById(Oid typeOid)
645 relation = heap_open(TypeRelationId, RowExclusiveLock);
647 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
648 if (!HeapTupleIsValid(tup))
649 elog(ERROR, "cache lookup failed for type %u", typeOid);
651 simple_heap_delete(relation, &tup->t_self);
654 * If it is an enum, delete the pg_enum entries too; we don't bother with
655 * making dependency entries for those, so it has to be done "by hand"
658 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
659 EnumValuesDelete(typeOid);
662 * If it is a range type, delete the pg_range entry too; we don't bother
663 * with making a dependency entry for that, so it has to be done "by hand"
666 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
667 RangeDelete(typeOid);
669 ReleaseSysCache(tup);
671 heap_close(relation, RowExclusiveLock);
677 * Registers a new domain.
680 DefineDomain(CreateDomainStmt *stmt)
685 int16 internalLength;
688 Oid receiveProcedure;
690 Oid analyzeProcedure;
699 char *defaultValue = NULL;
700 char *defaultValueBin = NULL;
701 bool saw_default = false;
702 bool typNotNull = false;
703 bool nullDefined = false;
704 int32 typNDims = list_length(stmt->typeName->arrayBounds);
706 List *schema = stmt->constraints;
712 Form_pg_type baseType;
716 /* Convert list of names to a name and namespace */
717 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
720 /* Check we have creation rights in target namespace */
721 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
723 if (aclresult != ACLCHECK_OK)
724 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
725 get_namespace_name(domainNamespace));
728 * Check for collision with an existing type name. If there is one and
729 * it's an autogenerated array, we can rename it out of the way.
731 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
732 CStringGetDatum(domainName),
733 ObjectIdGetDatum(domainNamespace));
734 if (OidIsValid(old_type_oid))
736 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
738 (errcode(ERRCODE_DUPLICATE_OBJECT),
739 errmsg("type \"%s\" already exists", domainName)));
743 * Look up the base type.
745 typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
746 baseType = (Form_pg_type) GETSTRUCT(typeTup);
747 basetypeoid = HeapTupleGetOid(typeTup);
750 * Base type must be a plain base type, another domain, an enum or a range
751 * type. Domains over pseudotypes would create a security hole. Domains
752 * over composite types might be made to work in the future, but not
755 typtype = baseType->typtype;
756 if (typtype != TYPTYPE_BASE &&
757 typtype != TYPTYPE_DOMAIN &&
758 typtype != TYPTYPE_ENUM &&
759 typtype != TYPTYPE_RANGE)
761 (errcode(ERRCODE_DATATYPE_MISMATCH),
762 errmsg("\"%s\" is not a valid base type for a domain",
763 TypeNameToString(stmt->typeName))));
765 aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
766 if (aclresult != ACLCHECK_OK)
767 aclcheck_error_type(aclresult, basetypeoid);
770 * Identify the collation if any
772 baseColl = baseType->typcollation;
773 if (stmt->collClause)
774 domaincoll = get_collation_oid(stmt->collClause->collname, false);
776 domaincoll = baseColl;
778 /* Complain if COLLATE is applied to an uncollatable type */
779 if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
781 (errcode(ERRCODE_DATATYPE_MISMATCH),
782 errmsg("collations are not supported by type %s",
783 format_type_be(basetypeoid))));
785 /* passed by value */
786 byValue = baseType->typbyval;
788 /* Required Alignment */
789 alignment = baseType->typalign;
792 storage = baseType->typstorage;
795 internalLength = baseType->typlen;
798 category = baseType->typcategory;
800 /* Array element Delimiter */
801 delimiter = baseType->typdelim;
804 inputProcedure = F_DOMAIN_IN;
805 outputProcedure = baseType->typoutput;
806 receiveProcedure = F_DOMAIN_RECV;
807 sendProcedure = baseType->typsend;
809 /* Domains never accept typmods, so no typmodin/typmodout needed */
811 /* Analysis function */
812 analyzeProcedure = baseType->typanalyze;
814 /* Inherited default value */
815 datum = SysCacheGetAttr(TYPEOID, typeTup,
816 Anum_pg_type_typdefault, &isnull);
818 defaultValue = TextDatumGetCString(datum);
820 /* Inherited default binary value */
821 datum = SysCacheGetAttr(TYPEOID, typeTup,
822 Anum_pg_type_typdefaultbin, &isnull);
824 defaultValueBin = TextDatumGetCString(datum);
827 * Run through constraints manually to avoid the additional processing
828 * conducted by DefineRelation() and friends.
830 foreach(listptr, schema)
832 Constraint *constr = lfirst(listptr);
834 if (!IsA(constr, Constraint))
835 elog(ERROR, "unrecognized node type: %d",
836 (int) nodeTag(constr));
837 switch (constr->contype)
842 * The inherited default value may be overridden by the user
843 * with the DEFAULT <expr> clause ... but only once.
847 (errcode(ERRCODE_SYNTAX_ERROR),
848 errmsg("multiple default expressions")));
851 if (constr->raw_expr)
856 /* Create a dummy ParseState for transformExpr */
857 pstate = make_parsestate(NULL);
860 * Cook the constr->raw_expr into an expression. Note:
861 * name is strictly for error message
863 defaultExpr = cookDefault(pstate, constr->raw_expr,
869 * If the expression is just a NULL constant, we treat it
870 * like not having a default.
872 * Note that if the basetype is another domain, we'll see
873 * a CoerceToDomain expr here and not discard the default.
874 * This is critical because the domain default needs to be
875 * retained to override any default that the base domain
878 if (defaultExpr == NULL ||
879 (IsA(defaultExpr, Const) &&
880 ((Const *) defaultExpr)->constisnull))
883 defaultValueBin = NULL;
888 * Expression must be stored as a nodeToString result,
889 * but we also require a valid textual representation
890 * (mainly to make life easier for pg_dump).
893 deparse_expression(defaultExpr,
895 defaultValueBin = nodeToString(defaultExpr);
900 /* No default (can this still happen?) */
902 defaultValueBin = NULL;
907 if (nullDefined && !typNotNull)
909 (errcode(ERRCODE_SYNTAX_ERROR),
910 errmsg("conflicting NULL/NOT NULL constraints")));
916 if (nullDefined && typNotNull)
918 (errcode(ERRCODE_SYNTAX_ERROR),
919 errmsg("conflicting NULL/NOT NULL constraints")));
927 * Check constraints are handled after domain creation, as
928 * they require the Oid of the domain; at this point we can
929 * only check that they're not marked NO INHERIT, because that
932 if (constr->is_no_inherit)
934 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
935 errmsg("check constraints for domains cannot be marked NO INHERIT")));
939 * All else are error cases
943 (errcode(ERRCODE_SYNTAX_ERROR),
944 errmsg("unique constraints not possible for domains")));
949 (errcode(ERRCODE_SYNTAX_ERROR),
950 errmsg("primary key constraints not possible for domains")));
953 case CONSTR_EXCLUSION:
955 (errcode(ERRCODE_SYNTAX_ERROR),
956 errmsg("exclusion constraints not possible for domains")));
961 (errcode(ERRCODE_SYNTAX_ERROR),
962 errmsg("foreign key constraints not possible for domains")));
965 case CONSTR_ATTR_DEFERRABLE:
966 case CONSTR_ATTR_NOT_DEFERRABLE:
967 case CONSTR_ATTR_DEFERRED:
968 case CONSTR_ATTR_IMMEDIATE:
970 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
971 errmsg("specifying constraint deferrability not supported for domains")));
975 elog(ERROR, "unrecognized constraint subtype: %d",
976 (int) constr->contype);
982 * Have TypeCreate do all the real work.
985 TypeCreate(InvalidOid, /* no predetermined type OID */
986 domainName, /* type name */
987 domainNamespace, /* namespace */
988 InvalidOid, /* relation oid (n/a here) */
989 0, /* relation kind (ditto) */
990 GetUserId(), /* owner's ID */
991 internalLength, /* internal size */
992 TYPTYPE_DOMAIN, /* type-type (domain type) */
993 category, /* type-category */
994 false, /* domain types are never preferred */
995 delimiter, /* array element delimiter */
996 inputProcedure, /* input procedure */
997 outputProcedure, /* output procedure */
998 receiveProcedure, /* receive procedure */
999 sendProcedure, /* send procedure */
1000 InvalidOid, /* typmodin procedure - none */
1001 InvalidOid, /* typmodout procedure - none */
1002 analyzeProcedure, /* analyze procedure */
1003 InvalidOid, /* no array element type */
1004 false, /* this isn't an array */
1005 InvalidOid, /* no arrays for domains (yet) */
1006 basetypeoid, /* base type ID */
1007 defaultValue, /* default type value (text) */
1008 defaultValueBin, /* default type value (binary) */
1009 byValue, /* passed by value */
1010 alignment, /* required alignment */
1011 storage, /* TOAST strategy */
1012 basetypeMod, /* typeMod value */
1013 typNDims, /* Array dimensions for base type */
1014 typNotNull, /* Type NOT NULL */
1015 domaincoll); /* type's collation */
1018 * Process constraints which refer to the domain ID returned by TypeCreate
1020 foreach(listptr, schema)
1022 Constraint *constr = lfirst(listptr);
1024 /* it must be a Constraint, per check above */
1026 switch (constr->contype)
1029 domainAddConstraint(domainoid, domainNamespace,
1030 basetypeoid, basetypeMod,
1031 constr, domainName);
1034 /* Other constraint types were fully processed above */
1040 /* CCI so we can detect duplicate constraint names */
1041 CommandCounterIncrement();
1045 * Now we can clean up.
1047 ReleaseSysCache(typeTup);
1055 * Registers a new enum.
1058 DefineEnum(CreateEnumStmt *stmt)
1061 char *enumArrayName;
1064 AclResult aclresult;
1068 /* Convert list of names to a name and namespace */
1069 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1072 /* Check we have creation rights in target namespace */
1073 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1074 if (aclresult != ACLCHECK_OK)
1075 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1076 get_namespace_name(enumNamespace));
1079 * Check for collision with an existing type name. If there is one and
1080 * it's an autogenerated array, we can rename it out of the way.
1082 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1083 CStringGetDatum(enumName),
1084 ObjectIdGetDatum(enumNamespace));
1085 if (OidIsValid(old_type_oid))
1087 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1089 (errcode(ERRCODE_DUPLICATE_OBJECT),
1090 errmsg("type \"%s\" already exists", enumName)));
1093 enumArrayOid = AssignTypeArrayOid();
1095 /* Create the pg_type entry */
1097 TypeCreate(InvalidOid, /* no predetermined type OID */
1098 enumName, /* type name */
1099 enumNamespace, /* namespace */
1100 InvalidOid, /* relation oid (n/a here) */
1101 0, /* relation kind (ditto) */
1102 GetUserId(), /* owner's ID */
1103 sizeof(Oid), /* internal size */
1104 TYPTYPE_ENUM, /* type-type (enum type) */
1105 TYPCATEGORY_ENUM, /* type-category (enum type) */
1106 false, /* enum types are never preferred */
1107 DEFAULT_TYPDELIM, /* array element delimiter */
1108 F_ENUM_IN, /* input procedure */
1109 F_ENUM_OUT, /* output procedure */
1110 F_ENUM_RECV, /* receive procedure */
1111 F_ENUM_SEND, /* send procedure */
1112 InvalidOid, /* typmodin procedure - none */
1113 InvalidOid, /* typmodout procedure - none */
1114 InvalidOid, /* analyze procedure - default */
1115 InvalidOid, /* element type ID */
1116 false, /* this is not an array type */
1117 enumArrayOid, /* array type we are about to create */
1118 InvalidOid, /* base type ID (only for domains) */
1119 NULL, /* never a default type value */
1120 NULL, /* binary default isn't sent either */
1121 true, /* always passed by value */
1122 'i', /* int alignment */
1123 'p', /* TOAST strategy always plain */
1124 -1, /* typMod (Domains only) */
1125 0, /* Array dimensions of typbasetype */
1126 false, /* Type NOT NULL */
1127 InvalidOid); /* type's collation */
1129 /* Enter the enum's values into pg_enum */
1130 EnumValuesCreate(enumTypeOid, stmt->vals);
1133 * Create the array type that goes with it.
1135 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1137 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1138 enumArrayName, /* type name */
1139 enumNamespace, /* namespace */
1140 InvalidOid, /* relation oid (n/a here) */
1141 0, /* relation kind (ditto) */
1142 GetUserId(), /* owner's ID */
1143 -1, /* internal size (always varlena) */
1144 TYPTYPE_BASE, /* type-type (base type) */
1145 TYPCATEGORY_ARRAY, /* type-category (array) */
1146 false, /* array types are never preferred */
1147 DEFAULT_TYPDELIM, /* array element delimiter */
1148 F_ARRAY_IN, /* input procedure */
1149 F_ARRAY_OUT, /* output procedure */
1150 F_ARRAY_RECV, /* receive procedure */
1151 F_ARRAY_SEND, /* send procedure */
1152 InvalidOid, /* typmodin procedure - none */
1153 InvalidOid, /* typmodout procedure - none */
1154 F_ARRAY_TYPANALYZE, /* analyze procedure */
1155 enumTypeOid, /* element type ID */
1156 true, /* yes this is an array type */
1157 InvalidOid, /* no further array type */
1158 InvalidOid, /* base type ID */
1159 NULL, /* never a default type value */
1160 NULL, /* binary default isn't sent either */
1161 false, /* never passed by value */
1162 'i', /* enums have align i, so do their arrays */
1163 'x', /* ARRAY is always toastable */
1164 -1, /* typMod (Domains only) */
1165 0, /* Array dimensions of typbasetype */
1166 false, /* Type NOT NULL */
1167 InvalidOid); /* type's collation */
1169 pfree(enumArrayName);
1176 * Adds a new label to an existing enum.
1179 AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
1185 /* Make a TypeName so we can use standard type lookup machinery */
1186 typename = makeTypeNameFromNameList(stmt->typeName);
1187 enum_type_oid = typenameTypeId(NULL, typename);
1189 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1190 if (!HeapTupleIsValid(tup))
1191 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1194 * Ordinarily we disallow adding values within transaction blocks, because
1195 * we can't cope with enum OID values getting into indexes and then having
1196 * their defining pg_enum entries go away. However, it's okay if the enum
1197 * type was created in the current transaction, since then there can be no
1198 * such indexes that wouldn't themselves go away on rollback. (We support
1199 * this case because pg_dump --binary-upgrade needs it.) We test this by
1200 * seeing if the pg_type row has xmin == current XID and is not
1201 * HEAP_UPDATED. If it is HEAP_UPDATED, we can't be sure whether the type
1202 * was created or only modified in this xact. So we are disallowing some
1203 * cases that could theoretically be safe; but fortunately pg_dump only
1204 * needs the simplest case.
1206 if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() &&
1207 !(tup->t_data->t_infomask & HEAP_UPDATED))
1208 /* safe to do inside transaction block */ ;
1210 PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD");
1212 /* Check it's an enum and check user has permission to ALTER the enum */
1213 checkEnumOwner(tup);
1215 /* Add the new label */
1216 AddEnumLabel(enum_type_oid, stmt->newVal,
1217 stmt->newValNeighbor, stmt->newValIsAfter,
1218 stmt->skipIfExists);
1220 InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1222 ReleaseSysCache(tup);
1224 return enum_type_oid;
1231 * Check that the type is actually an enum and that the current user
1232 * has permission to do ALTER TYPE on it. Throw an error if not.
1235 checkEnumOwner(HeapTuple tup)
1237 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1239 /* Check that this is actually an enum */
1240 if (typTup->typtype != TYPTYPE_ENUM)
1242 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1243 errmsg("%s is not an enum",
1244 format_type_be(HeapTupleGetOid(tup)))));
1246 /* Permission check: must own type */
1247 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1248 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
1254 * Registers a new range type.
1257 DefineRange(CreateRangeStmt *stmt)
1262 char *rangeArrayName;
1264 Oid rangeSubtype = InvalidOid;
1265 List *rangeSubOpclassName = NIL;
1266 List *rangeCollationName = NIL;
1267 List *rangeCanonicalName = NIL;
1268 List *rangeSubtypeDiffName = NIL;
1269 Oid rangeSubOpclass;
1271 regproc rangeCanonical;
1272 regproc rangeSubtypeDiff;
1277 AclResult aclresult;
1280 /* Convert list of names to a name and namespace */
1281 typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1284 /* Check we have creation rights in target namespace */
1285 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1286 if (aclresult != ACLCHECK_OK)
1287 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1288 get_namespace_name(typeNamespace));
1291 * Look to see if type already exists.
1293 typoid = GetSysCacheOid2(TYPENAMENSP,
1294 CStringGetDatum(typeName),
1295 ObjectIdGetDatum(typeNamespace));
1298 * If it's not a shell, see if it's an autogenerated array type, and if so
1299 * rename it out of the way.
1301 if (OidIsValid(typoid) && get_typisdefined(typoid))
1303 if (moveArrayTypeName(typoid, typeName, typeNamespace))
1304 typoid = InvalidOid;
1307 (errcode(ERRCODE_DUPLICATE_OBJECT),
1308 errmsg("type \"%s\" already exists", typeName)));
1312 * If it doesn't exist, create it as a shell, so that the OID is known for
1313 * use in the range function definitions.
1315 if (!OidIsValid(typoid))
1317 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
1318 /* Make new shell type visible for modification below */
1319 CommandCounterIncrement();
1322 /* Extract the parameters from the parameter list */
1323 foreach(lc, stmt->params)
1325 DefElem *defel = (DefElem *) lfirst(lc);
1327 if (pg_strcasecmp(defel->defname, "subtype") == 0)
1329 if (OidIsValid(rangeSubtype))
1331 (errcode(ERRCODE_SYNTAX_ERROR),
1332 errmsg("conflicting or redundant options")));
1333 /* we can look up the subtype name immediately */
1334 rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1336 else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
1338 if (rangeSubOpclassName != NIL)
1340 (errcode(ERRCODE_SYNTAX_ERROR),
1341 errmsg("conflicting or redundant options")));
1342 rangeSubOpclassName = defGetQualifiedName(defel);
1344 else if (pg_strcasecmp(defel->defname, "collation") == 0)
1346 if (rangeCollationName != NIL)
1348 (errcode(ERRCODE_SYNTAX_ERROR),
1349 errmsg("conflicting or redundant options")));
1350 rangeCollationName = defGetQualifiedName(defel);
1352 else if (pg_strcasecmp(defel->defname, "canonical") == 0)
1354 if (rangeCanonicalName != NIL)
1356 (errcode(ERRCODE_SYNTAX_ERROR),
1357 errmsg("conflicting or redundant options")));
1358 rangeCanonicalName = defGetQualifiedName(defel);
1360 else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
1362 if (rangeSubtypeDiffName != NIL)
1364 (errcode(ERRCODE_SYNTAX_ERROR),
1365 errmsg("conflicting or redundant options")));
1366 rangeSubtypeDiffName = defGetQualifiedName(defel);
1370 (errcode(ERRCODE_SYNTAX_ERROR),
1371 errmsg("type attribute \"%s\" not recognized",
1375 /* Must have a subtype */
1376 if (!OidIsValid(rangeSubtype))
1378 (errcode(ERRCODE_SYNTAX_ERROR),
1379 errmsg("type attribute \"subtype\" is required")));
1380 /* disallow ranges of pseudotypes */
1381 if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
1383 (errcode(ERRCODE_DATATYPE_MISMATCH),
1384 errmsg("range subtype cannot be %s",
1385 format_type_be(rangeSubtype))));
1387 /* Identify subopclass */
1388 rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1390 /* Identify collation to use, if any */
1391 if (type_is_collatable(rangeSubtype))
1393 if (rangeCollationName != NIL)
1394 rangeCollation = get_collation_oid(rangeCollationName, false);
1396 rangeCollation = get_typcollation(rangeSubtype);
1400 if (rangeCollationName != NIL)
1402 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1403 errmsg("range collation specified but subtype does not support collation")));
1404 rangeCollation = InvalidOid;
1407 /* Identify support functions, if provided */
1408 if (rangeCanonicalName != NIL)
1409 rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1412 rangeCanonical = InvalidOid;
1414 if (rangeSubtypeDiffName != NIL)
1415 rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1418 rangeSubtypeDiff = InvalidOid;
1420 get_typlenbyvalalign(rangeSubtype,
1421 &subtyplen, &subtypbyval, &subtypalign);
1423 /* alignment must be 'i' or 'd' for ranges */
1424 alignment = (subtypalign == 'd') ? 'd' : 'i';
1426 /* Allocate OID for array type */
1427 rangeArrayOid = AssignTypeArrayOid();
1429 /* Create the pg_type entry */
1431 TypeCreate(InvalidOid, /* no predetermined type OID */
1432 typeName, /* type name */
1433 typeNamespace, /* namespace */
1434 InvalidOid, /* relation oid (n/a here) */
1435 0, /* relation kind (ditto) */
1436 GetUserId(), /* owner's ID */
1437 -1, /* internal size (always varlena) */
1438 TYPTYPE_RANGE, /* type-type (range type) */
1439 TYPCATEGORY_RANGE, /* type-category (range type) */
1440 false, /* range types are never preferred */
1441 DEFAULT_TYPDELIM, /* array element delimiter */
1442 F_RANGE_IN, /* input procedure */
1443 F_RANGE_OUT, /* output procedure */
1444 F_RANGE_RECV, /* receive procedure */
1445 F_RANGE_SEND, /* send procedure */
1446 InvalidOid, /* typmodin procedure - none */
1447 InvalidOid, /* typmodout procedure - none */
1448 F_RANGE_TYPANALYZE, /* analyze procedure */
1449 InvalidOid, /* element type ID - none */
1450 false, /* this is not an array type */
1451 rangeArrayOid, /* array type we are about to create */
1452 InvalidOid, /* base type ID (only for domains) */
1453 NULL, /* never a default type value */
1454 NULL, /* no binary form available either */
1455 false, /* never passed by value */
1456 alignment, /* alignment */
1457 'x', /* TOAST strategy (always extended) */
1458 -1, /* typMod (Domains only) */
1459 0, /* Array dimensions of typbasetype */
1460 false, /* Type NOT NULL */
1461 InvalidOid); /* type's collation (ranges never have one) */
1463 /* Create the entry in pg_range */
1464 RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1465 rangeCanonical, rangeSubtypeDiff);
1468 * Create the array type that goes with it.
1470 rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1472 TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1473 rangeArrayName, /* type name */
1474 typeNamespace, /* namespace */
1475 InvalidOid, /* relation oid (n/a here) */
1476 0, /* relation kind (ditto) */
1477 GetUserId(), /* owner's ID */
1478 -1, /* internal size (always varlena) */
1479 TYPTYPE_BASE, /* type-type (base type) */
1480 TYPCATEGORY_ARRAY, /* type-category (array) */
1481 false, /* array types are never preferred */
1482 DEFAULT_TYPDELIM, /* array element delimiter */
1483 F_ARRAY_IN, /* input procedure */
1484 F_ARRAY_OUT, /* output procedure */
1485 F_ARRAY_RECV, /* receive procedure */
1486 F_ARRAY_SEND, /* send procedure */
1487 InvalidOid, /* typmodin procedure - none */
1488 InvalidOid, /* typmodout procedure - none */
1489 F_ARRAY_TYPANALYZE, /* analyze procedure */
1490 typoid, /* element type ID */
1491 true, /* yes this is an array type */
1492 InvalidOid, /* no further array type */
1493 InvalidOid, /* base type ID */
1494 NULL, /* never a default type value */
1495 NULL, /* binary default isn't sent either */
1496 false, /* never passed by value */
1497 alignment, /* alignment - same as range's */
1498 'x', /* ARRAY is always toastable */
1499 -1, /* typMod (Domains only) */
1500 0, /* Array dimensions of typbasetype */
1501 false, /* Type NOT NULL */
1502 InvalidOid); /* typcollation */
1504 pfree(rangeArrayName);
1506 /* And create the constructor functions for this range type */
1507 makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1513 * Because there may exist several range types over the same subtype, the
1514 * range type can't be uniquely determined from the subtype. So it's
1515 * impossible to define a polymorphic constructor; we have to generate new
1516 * constructor functions explicitly for each range type.
1518 * We actually define 4 functions, with 0 through 3 arguments. This is just
1519 * to offer more convenience for the user.
1522 makeRangeConstructors(const char *name, Oid namespace,
1523 Oid rangeOid, Oid subtype)
1525 static const char *const prosrc[2] = {"range_constructor2",
1526 "range_constructor3"};
1527 static const int pronargs[2] = {2, 3};
1529 Oid constructorArgTypes[3];
1530 ObjectAddress myself,
1534 constructorArgTypes[0] = subtype;
1535 constructorArgTypes[1] = subtype;
1536 constructorArgTypes[2] = TEXTOID;
1538 referenced.classId = TypeRelationId;
1539 referenced.objectId = rangeOid;
1540 referenced.objectSubId = 0;
1542 for (i = 0; i < lengthof(prosrc); i++)
1544 oidvector *constructorArgTypesVector;
1547 constructorArgTypesVector = buildoidvector(constructorArgTypes,
1550 procOid = ProcedureCreate(name, /* name: same as range type */
1551 namespace, /* namespace */
1552 false, /* replace */
1553 false, /* returns set */
1554 rangeOid, /* return type */
1555 BOOTSTRAP_SUPERUSERID, /* proowner */
1556 INTERNALlanguageId, /* language */
1557 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1558 prosrc[i], /* prosrc */
1561 false, /* isWindowFunc */
1562 false, /* security_definer */
1563 false, /* leakproof */
1564 false, /* isStrict */
1565 PROVOLATILE_IMMUTABLE, /* volatility */
1566 constructorArgTypesVector, /* parameterTypes */
1567 PointerGetDatum(NULL), /* allParameterTypes */
1568 PointerGetDatum(NULL), /* parameterModes */
1569 PointerGetDatum(NULL), /* parameterNames */
1570 NIL, /* parameterDefaults */
1571 PointerGetDatum(NULL), /* proconfig */
1576 * Make the constructors internally-dependent on the range type so
1577 * that they go away silently when the type is dropped. Note that
1578 * pg_dump depends on this choice to avoid dumping the constructors.
1580 myself.classId = ProcedureRelationId;
1581 myself.objectId = procOid;
1582 myself.objectSubId = 0;
1584 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1590 * Find suitable I/O functions for a type.
1592 * typeOid is the type's OID (which will already exist, if only as a shell
1597 findTypeInputFunction(List *procname, Oid typeOid)
1603 * Input functions can take a single argument of type CSTRING, or three
1604 * arguments (string, typioparam OID, typmod).
1606 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1607 * see this, we issue a warning and fix up the pg_proc entry.
1609 argList[0] = CSTRINGOID;
1611 procOid = LookupFuncName(procname, 1, argList, true);
1612 if (OidIsValid(procOid))
1615 argList[1] = OIDOID;
1616 argList[2] = INT4OID;
1618 procOid = LookupFuncName(procname, 3, argList, true);
1619 if (OidIsValid(procOid))
1622 /* No luck, try it with OPAQUE */
1623 argList[0] = OPAQUEOID;
1625 procOid = LookupFuncName(procname, 1, argList, true);
1627 if (!OidIsValid(procOid))
1629 argList[1] = OIDOID;
1630 argList[2] = INT4OID;
1632 procOid = LookupFuncName(procname, 3, argList, true);
1635 if (OidIsValid(procOid))
1637 /* Found, but must complain and fix the pg_proc entry */
1639 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1640 NameListToString(procname))));
1641 SetFunctionArgType(procOid, 0, CSTRINGOID);
1644 * Need CommandCounterIncrement since DefineType will likely try to
1645 * alter the pg_proc tuple again.
1647 CommandCounterIncrement();
1652 /* Use CSTRING (preferred) in the error message */
1653 argList[0] = CSTRINGOID;
1656 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1657 errmsg("function %s does not exist",
1658 func_signature_string(procname, 1, NIL, argList))));
1660 return InvalidOid; /* keep compiler quiet */
1664 findTypeOutputFunction(List *procname, Oid typeOid)
1670 * Output functions can take a single argument of the type.
1672 * For backwards compatibility we allow OPAQUE in place of the actual type
1673 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1675 argList[0] = typeOid;
1677 procOid = LookupFuncName(procname, 1, argList, true);
1678 if (OidIsValid(procOid))
1681 /* No luck, try it with OPAQUE */
1682 argList[0] = OPAQUEOID;
1684 procOid = LookupFuncName(procname, 1, argList, true);
1686 if (OidIsValid(procOid))
1688 /* Found, but must complain and fix the pg_proc entry */
1690 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1691 NameListToString(procname), format_type_be(typeOid))));
1692 SetFunctionArgType(procOid, 0, typeOid);
1695 * Need CommandCounterIncrement since DefineType will likely try to
1696 * alter the pg_proc tuple again.
1698 CommandCounterIncrement();
1703 /* Use type name, not OPAQUE, in the failure message. */
1704 argList[0] = typeOid;
1707 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1708 errmsg("function %s does not exist",
1709 func_signature_string(procname, 1, NIL, argList))));
1711 return InvalidOid; /* keep compiler quiet */
1715 findTypeReceiveFunction(List *procname, Oid typeOid)
1721 * Receive functions can take a single argument of type INTERNAL, or three
1722 * arguments (internal, typioparam OID, typmod).
1724 argList[0] = INTERNALOID;
1726 procOid = LookupFuncName(procname, 1, argList, true);
1727 if (OidIsValid(procOid))
1730 argList[1] = OIDOID;
1731 argList[2] = INT4OID;
1733 procOid = LookupFuncName(procname, 3, argList, true);
1734 if (OidIsValid(procOid))
1738 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1739 errmsg("function %s does not exist",
1740 func_signature_string(procname, 1, NIL, argList))));
1742 return InvalidOid; /* keep compiler quiet */
1746 findTypeSendFunction(List *procname, Oid typeOid)
1752 * Send functions can take a single argument of the type.
1754 argList[0] = typeOid;
1756 procOid = LookupFuncName(procname, 1, argList, true);
1757 if (OidIsValid(procOid))
1761 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1762 errmsg("function %s does not exist",
1763 func_signature_string(procname, 1, NIL, argList))));
1765 return InvalidOid; /* keep compiler quiet */
1769 findTypeTypmodinFunction(List *procname)
1775 * typmodin functions always take one cstring[] argument and return int4.
1777 argList[0] = CSTRINGARRAYOID;
1779 procOid = LookupFuncName(procname, 1, argList, true);
1780 if (!OidIsValid(procOid))
1782 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1783 errmsg("function %s does not exist",
1784 func_signature_string(procname, 1, NIL, argList))));
1786 if (get_func_rettype(procOid) != INT4OID)
1788 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1789 errmsg("typmod_in function %s must return type \"integer\"",
1790 NameListToString(procname))));
1796 findTypeTypmodoutFunction(List *procname)
1802 * typmodout functions always take one int4 argument and return cstring.
1804 argList[0] = INT4OID;
1806 procOid = LookupFuncName(procname, 1, argList, true);
1807 if (!OidIsValid(procOid))
1809 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1810 errmsg("function %s does not exist",
1811 func_signature_string(procname, 1, NIL, argList))));
1813 if (get_func_rettype(procOid) != CSTRINGOID)
1815 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1816 errmsg("typmod_out function %s must return type \"cstring\"",
1817 NameListToString(procname))));
1823 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1829 * Analyze functions always take one INTERNAL argument and return bool.
1831 argList[0] = INTERNALOID;
1833 procOid = LookupFuncName(procname, 1, argList, true);
1834 if (!OidIsValid(procOid))
1836 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1837 errmsg("function %s does not exist",
1838 func_signature_string(procname, 1, NIL, argList))));
1840 if (get_func_rettype(procOid) != BOOLOID)
1842 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1843 errmsg("type analyze function %s must return type \"boolean\"",
1844 NameListToString(procname))));
1850 * Find suitable support functions and opclasses for a range type.
1854 * Find named btree opclass for subtype, or default btree opclass if
1858 findRangeSubOpclass(List *opcname, Oid subtype)
1865 opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
1868 * Verify that the operator class accepts this datatype. Note we will
1869 * accept binary compatibility.
1871 opInputType = get_opclass_input_type(opcid);
1872 if (!IsBinaryCoercible(subtype, opInputType))
1874 (errcode(ERRCODE_DATATYPE_MISMATCH),
1875 errmsg("operator class \"%s\" does not accept data type %s",
1876 NameListToString(opcname),
1877 format_type_be(subtype))));
1881 opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
1882 if (!OidIsValid(opcid))
1884 /* We spell the error message identically to GetIndexOpClass */
1886 (errcode(ERRCODE_UNDEFINED_OBJECT),
1887 errmsg("data type %s has no default operator class for access method \"%s\"",
1888 format_type_be(subtype), "btree"),
1889 errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
1897 findRangeCanonicalFunction(List *procname, Oid typeOid)
1901 AclResult aclresult;
1904 * Range canonical functions must take and return the range type, and must
1907 argList[0] = typeOid;
1909 procOid = LookupFuncName(procname, 1, argList, true);
1911 if (!OidIsValid(procOid))
1913 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1914 errmsg("function %s does not exist",
1915 func_signature_string(procname, 1, NIL, argList))));
1917 if (get_func_rettype(procOid) != typeOid)
1919 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1920 errmsg("range canonical function %s must return range type",
1921 func_signature_string(procname, 1, NIL, argList))));
1923 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1925 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1926 errmsg("range canonical function %s must be immutable",
1927 func_signature_string(procname, 1, NIL, argList))));
1929 /* Also, range type's creator must have permission to call function */
1930 aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
1931 if (aclresult != ACLCHECK_OK)
1932 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
1938 findRangeSubtypeDiffFunction(List *procname, Oid subtype)
1942 AclResult aclresult;
1945 * Range subtype diff functions must take two arguments of the subtype,
1946 * must return float8, and must be immutable.
1948 argList[0] = subtype;
1949 argList[1] = subtype;
1951 procOid = LookupFuncName(procname, 2, argList, true);
1953 if (!OidIsValid(procOid))
1955 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1956 errmsg("function %s does not exist",
1957 func_signature_string(procname, 2, NIL, argList))));
1959 if (get_func_rettype(procOid) != FLOAT8OID)
1961 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1962 errmsg("range subtype diff function %s must return type double precision",
1963 func_signature_string(procname, 2, NIL, argList))));
1965 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1967 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1968 errmsg("range subtype diff function %s must be immutable",
1969 func_signature_string(procname, 2, NIL, argList))));
1971 /* Also, range type's creator must have permission to call function */
1972 aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
1973 if (aclresult != ACLCHECK_OK)
1974 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
1980 * AssignTypeArrayOid
1982 * Pre-assign the type's array OID for use in pg_type.typarray
1985 AssignTypeArrayOid(void)
1989 /* Use binary-upgrade override for pg_type.typarray, if supplied. */
1990 if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_array_pg_type_oid))
1992 type_array_oid = binary_upgrade_next_array_pg_type_oid;
1993 binary_upgrade_next_array_pg_type_oid = InvalidOid;
1997 Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
1999 type_array_oid = GetNewOid(pg_type);
2000 heap_close(pg_type, AccessShareLock);
2003 return type_array_oid;
2007 /*-------------------------------------------------------------------
2008 * DefineCompositeType
2010 * Create a Composite Type relation.
2011 * `DefineRelation' does all the work, we just provide the correct
2014 * If the relation already exists, then 'DefineRelation' will abort
2017 * DefineCompositeType returns relid for use when creating
2018 * an implicit composite type during function creation
2019 *-------------------------------------------------------------------
2022 DefineCompositeType(RangeVar *typevar, List *coldeflist)
2024 CreateStmt *createStmt = makeNode(CreateStmt);
2030 * now set the parameters for keys/inheritance etc. All of these are
2031 * uninteresting for composite types...
2033 createStmt->relation = typevar;
2034 createStmt->tableElts = coldeflist;
2035 createStmt->inhRelations = NIL;
2036 createStmt->constraints = NIL;
2037 createStmt->options = NIL;
2038 createStmt->oncommit = ONCOMMIT_NOOP;
2039 createStmt->tablespacename = NULL;
2040 createStmt->if_not_exists = false;
2043 * Check for collision with an existing type name. If there is one and
2044 * it's an autogenerated array, we can rename it out of the way. This
2045 * check is here mainly to get a better error message about a "type"
2046 * instead of below about a "relation".
2048 typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2050 RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2052 GetSysCacheOid2(TYPENAMENSP,
2053 CStringGetDatum(createStmt->relation->relname),
2054 ObjectIdGetDatum(typeNamespace));
2055 if (OidIsValid(old_type_oid))
2057 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2059 (errcode(ERRCODE_DUPLICATE_OBJECT),
2060 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2064 * Finally create the relation. This also creates the type.
2066 relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
2067 Assert(relid != InvalidOid);
2072 * AlterDomainDefault
2074 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
2077 AlterDomainDefault(List *names, Node *defaultRaw)
2085 Node *defaultExpr = NULL; /* NULL if no default specified */
2086 Datum new_record[Natts_pg_type];
2087 bool new_record_nulls[Natts_pg_type];
2088 bool new_record_repl[Natts_pg_type];
2090 Form_pg_type typTup;
2092 /* Make a TypeName so we can use standard type lookup machinery */
2093 typename = makeTypeNameFromNameList(names);
2094 domainoid = typenameTypeId(NULL, typename);
2096 /* Look up the domain in the type table */
2097 rel = heap_open(TypeRelationId, RowExclusiveLock);
2099 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2100 if (!HeapTupleIsValid(tup))
2101 elog(ERROR, "cache lookup failed for type %u", domainoid);
2102 typTup = (Form_pg_type) GETSTRUCT(tup);
2104 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2105 checkDomainOwner(tup);
2107 /* Setup new tuple */
2108 MemSet(new_record, (Datum) 0, sizeof(new_record));
2109 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2110 MemSet(new_record_repl, false, sizeof(new_record_repl));
2112 /* Store the new default into the tuple */
2115 /* Create a dummy ParseState for transformExpr */
2116 pstate = make_parsestate(NULL);
2119 * Cook the colDef->raw_expr into an expression. Note: Name is
2120 * strictly for error message
2122 defaultExpr = cookDefault(pstate, defaultRaw,
2123 typTup->typbasetype,
2125 NameStr(typTup->typname));
2128 * If the expression is just a NULL constant, we treat the command
2129 * like ALTER ... DROP DEFAULT. (But see note for same test in
2132 if (defaultExpr == NULL ||
2133 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
2135 /* Default is NULL, drop it */
2136 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2137 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2138 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2139 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2144 * Expression must be stored as a nodeToString result, but we also
2145 * require a valid textual representation (mainly to make life
2146 * easier for pg_dump).
2148 defaultValue = deparse_expression(defaultExpr,
2152 * Form an updated tuple with the new default and write it back.
2154 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2156 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2157 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2158 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2163 /* ALTER ... DROP DEFAULT */
2164 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2165 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2166 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2167 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2170 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2171 new_record, new_record_nulls,
2174 simple_heap_update(rel, &tup->t_self, newtuple);
2176 CatalogUpdateIndexes(rel, newtuple);
2178 /* Rebuild dependencies */
2179 GenerateTypeDependencies(typTup->typnamespace,
2181 InvalidOid, /* typrelid is n/a */
2182 0, /* relation kind is n/a */
2192 false, /* a domain isn't an implicit array */
2193 typTup->typbasetype,
2194 typTup->typcollation,
2196 true); /* Rebuild is true */
2198 InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2201 heap_close(rel, NoLock);
2202 heap_freetuple(newtuple);
2208 * AlterDomainNotNull
2210 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2213 AlterDomainNotNull(List *names, bool notNull)
2219 Form_pg_type typTup;
2221 /* Make a TypeName so we can use standard type lookup machinery */
2222 typename = makeTypeNameFromNameList(names);
2223 domainoid = typenameTypeId(NULL, typename);
2225 /* Look up the domain in the type table */
2226 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2228 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2229 if (!HeapTupleIsValid(tup))
2230 elog(ERROR, "cache lookup failed for type %u", domainoid);
2231 typTup = (Form_pg_type) GETSTRUCT(tup);
2233 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2234 checkDomainOwner(tup);
2236 /* Is the domain already set to the desired constraint? */
2237 if (typTup->typnotnull == notNull)
2239 heap_close(typrel, RowExclusiveLock);
2243 /* Adding a NOT NULL constraint requires checking existing columns */
2249 /* Fetch relation list with attributes based on this domain */
2250 /* ShareLock is sufficient to prevent concurrent data changes */
2252 rels = get_rels_with_domain(domainoid, ShareLock);
2256 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2257 Relation testrel = rtc->rel;
2258 TupleDesc tupdesc = RelationGetDescr(testrel);
2263 /* Scan all tuples in this relation */
2264 snapshot = RegisterSnapshot(GetLatestSnapshot());
2265 scan = heap_beginscan(testrel, snapshot, 0, NULL);
2266 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2270 /* Test attributes that are of the domain */
2271 for (i = 0; i < rtc->natts; i++)
2273 int attnum = rtc->atts[i];
2275 if (heap_attisnull(tuple, attnum))
2278 * In principle the auxiliary information for this
2279 * error should be errdatatype(), but errtablecol()
2280 * seems considerably more useful in practice. Since
2281 * this code only executes in an ALTER DOMAIN command,
2282 * the client should already know which domain is in
2286 (errcode(ERRCODE_NOT_NULL_VIOLATION),
2287 errmsg("column \"%s\" of table \"%s\" contains null values",
2288 NameStr(tupdesc->attrs[attnum - 1]->attname),
2289 RelationGetRelationName(testrel)),
2290 errtablecol(testrel, attnum)));
2295 UnregisterSnapshot(snapshot);
2297 /* Close each rel after processing, but keep lock */
2298 heap_close(testrel, NoLock);
2303 * Okay to update pg_type row. We can scribble on typTup because it's a
2306 typTup->typnotnull = notNull;
2308 simple_heap_update(typrel, &tup->t_self, tup);
2310 CatalogUpdateIndexes(typrel, tup);
2312 InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2315 heap_freetuple(tup);
2316 heap_close(typrel, RowExclusiveLock);
2322 * AlterDomainDropConstraint
2324 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2327 AlterDomainDropConstraint(List *names, const char *constrName,
2328 DropBehavior behavior, bool missing_ok)
2335 SysScanDesc conscan;
2340 /* Make a TypeName so we can use standard type lookup machinery */
2341 typename = makeTypeNameFromNameList(names);
2342 domainoid = typenameTypeId(NULL, typename);
2344 /* Look up the domain in the type table */
2345 rel = heap_open(TypeRelationId, RowExclusiveLock);
2347 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2348 if (!HeapTupleIsValid(tup))
2349 elog(ERROR, "cache lookup failed for type %u", domainoid);
2351 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2352 checkDomainOwner(tup);
2354 /* Grab an appropriate lock on the pg_constraint relation */
2355 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2357 /* Use the index to scan only constraints of the target relation */
2358 ScanKeyInit(&key[0],
2359 Anum_pg_constraint_contypid,
2360 BTEqualStrategyNumber, F_OIDEQ,
2361 ObjectIdGetDatum(HeapTupleGetOid(tup)));
2363 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2367 * Scan over the result set, removing any matching entries.
2369 while ((contup = systable_getnext(conscan)) != NULL)
2371 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
2373 if (strcmp(NameStr(con->conname), constrName) == 0)
2375 ObjectAddress conobj;
2377 conobj.classId = ConstraintRelationId;
2378 conobj.objectId = HeapTupleGetOid(contup);
2379 conobj.objectSubId = 0;
2381 performDeletion(&conobj, behavior, 0);
2385 /* Clean up after the scan */
2386 systable_endscan(conscan);
2387 heap_close(conrel, RowExclusiveLock);
2389 heap_close(rel, NoLock);
2395 (errcode(ERRCODE_UNDEFINED_OBJECT),
2396 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2397 constrName, TypeNameToString(typename))));
2400 (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2401 constrName, TypeNameToString(typename))));
2408 * AlterDomainAddConstraint
2410 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2413 AlterDomainAddConstraint(List *names, Node *newConstraint)
2419 Form_pg_type typTup;
2423 /* Make a TypeName so we can use standard type lookup machinery */
2424 typename = makeTypeNameFromNameList(names);
2425 domainoid = typenameTypeId(NULL, typename);
2427 /* Look up the domain in the type table */
2428 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2430 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2431 if (!HeapTupleIsValid(tup))
2432 elog(ERROR, "cache lookup failed for type %u", domainoid);
2433 typTup = (Form_pg_type) GETSTRUCT(tup);
2435 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2436 checkDomainOwner(tup);
2438 if (!IsA(newConstraint, Constraint))
2439 elog(ERROR, "unrecognized node type: %d",
2440 (int) nodeTag(newConstraint));
2442 constr = (Constraint *) newConstraint;
2444 switch (constr->contype)
2447 /* processed below */
2452 (errcode(ERRCODE_SYNTAX_ERROR),
2453 errmsg("unique constraints not possible for domains")));
2456 case CONSTR_PRIMARY:
2458 (errcode(ERRCODE_SYNTAX_ERROR),
2459 errmsg("primary key constraints not possible for domains")));
2462 case CONSTR_EXCLUSION:
2464 (errcode(ERRCODE_SYNTAX_ERROR),
2465 errmsg("exclusion constraints not possible for domains")));
2468 case CONSTR_FOREIGN:
2470 (errcode(ERRCODE_SYNTAX_ERROR),
2471 errmsg("foreign key constraints not possible for domains")));
2474 case CONSTR_ATTR_DEFERRABLE:
2475 case CONSTR_ATTR_NOT_DEFERRABLE:
2476 case CONSTR_ATTR_DEFERRED:
2477 case CONSTR_ATTR_IMMEDIATE:
2479 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2480 errmsg("specifying constraint deferrability not supported for domains")));
2484 elog(ERROR, "unrecognized constraint subtype: %d",
2485 (int) constr->contype);
2490 * Since all other constraint types throw errors, this must be a check
2491 * constraint. First, process the constraint expression and add an entry
2495 ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
2496 typTup->typbasetype, typTup->typtypmod,
2497 constr, NameStr(typTup->typname));
2500 * If requested to validate the constraint, test all values stored in the
2501 * attributes based on the domain the constraint is being added to.
2503 if (!constr->skip_validation)
2504 validateDomainConstraint(domainoid, ccbin);
2507 heap_close(typrel, RowExclusiveLock);
2513 * AlterDomainValidateConstraint
2515 * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
2518 AlterDomainValidateConstraint(List *names, char *constrName)
2525 Form_pg_constraint con = NULL;
2526 Form_pg_constraint copy_con;
2533 HeapTuple copyTuple;
2536 /* Make a TypeName so we can use standard type lookup machinery */
2537 typename = makeTypeNameFromNameList(names);
2538 domainoid = typenameTypeId(NULL, typename);
2540 /* Look up the domain in the type table */
2541 typrel = heap_open(TypeRelationId, AccessShareLock);
2543 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2544 if (!HeapTupleIsValid(tup))
2545 elog(ERROR, "cache lookup failed for type %u", domainoid);
2547 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2548 checkDomainOwner(tup);
2551 * Find and check the target constraint
2553 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2555 Anum_pg_constraint_contypid,
2556 BTEqualStrategyNumber, F_OIDEQ,
2557 ObjectIdGetDatum(domainoid));
2558 scan = systable_beginscan(conrel, ConstraintTypidIndexId,
2559 true, NULL, 1, &key);
2561 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2563 con = (Form_pg_constraint) GETSTRUCT(tuple);
2564 if (strcmp(NameStr(con->conname), constrName) == 0)
2573 (errcode(ERRCODE_UNDEFINED_OBJECT),
2574 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2575 constrName, TypeNameToString(typename))));
2577 if (con->contype != CONSTRAINT_CHECK)
2579 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2580 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2581 constrName, TypeNameToString(typename))));
2583 val = SysCacheGetAttr(CONSTROID, tuple,
2584 Anum_pg_constraint_conbin,
2587 elog(ERROR, "null conbin for constraint %u",
2588 HeapTupleGetOid(tuple));
2589 conbin = TextDatumGetCString(val);
2591 validateDomainConstraint(domainoid, conbin);
2594 * Now update the catalog, while we have the door open.
2596 copyTuple = heap_copytuple(tuple);
2597 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2598 copy_con->convalidated = true;
2599 simple_heap_update(conrel, ©Tuple->t_self, copyTuple);
2600 CatalogUpdateIndexes(conrel, copyTuple);
2602 InvokeObjectPostAlterHook(ConstraintRelationId,
2603 HeapTupleGetOid(copyTuple), 0);
2605 heap_freetuple(copyTuple);
2607 systable_endscan(scan);
2609 heap_close(typrel, AccessShareLock);
2610 heap_close(conrel, RowExclusiveLock);
2612 ReleaseSysCache(tup);
2618 validateDomainConstraint(Oid domainoid, char *ccbin)
2620 Expr *expr = (Expr *) stringToNode(ccbin);
2624 ExprContext *econtext;
2625 ExprState *exprstate;
2627 /* Need an EState to run ExecEvalExpr */
2628 estate = CreateExecutorState();
2629 econtext = GetPerTupleExprContext(estate);
2631 /* build execution state for expr */
2632 exprstate = ExecPrepareExpr(expr, estate);
2634 /* Fetch relation list with attributes based on this domain */
2635 /* ShareLock is sufficient to prevent concurrent data changes */
2637 rels = get_rels_with_domain(domainoid, ShareLock);
2641 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2642 Relation testrel = rtc->rel;
2643 TupleDesc tupdesc = RelationGetDescr(testrel);
2648 /* Scan all tuples in this relation */
2649 snapshot = RegisterSnapshot(GetLatestSnapshot());
2650 scan = heap_beginscan(testrel, snapshot, 0, NULL);
2651 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2655 /* Test attributes that are of the domain */
2656 for (i = 0; i < rtc->natts; i++)
2658 int attnum = rtc->atts[i];
2663 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2665 econtext->domainValue_datum = d;
2666 econtext->domainValue_isNull = isNull;
2668 conResult = ExecEvalExprSwitchContext(exprstate,
2672 if (!isNull && !DatumGetBool(conResult))
2675 * In principle the auxiliary information for this error
2676 * should be errdomainconstraint(), but errtablecol()
2677 * seems considerably more useful in practice. Since this
2678 * code only executes in an ALTER DOMAIN command, the
2679 * client should already know which domain is in question,
2680 * and which constraint too.
2683 (errcode(ERRCODE_CHECK_VIOLATION),
2684 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2685 NameStr(tupdesc->attrs[attnum - 1]->attname),
2686 RelationGetRelationName(testrel)),
2687 errtablecol(testrel, attnum)));
2691 ResetExprContext(econtext);
2694 UnregisterSnapshot(snapshot);
2696 /* Hold relation lock till commit (XXX bad for concurrency) */
2697 heap_close(testrel, NoLock);
2700 FreeExecutorState(estate);
2704 * get_rels_with_domain
2706 * Fetch all relations / attributes which are using the domain
2708 * The result is a list of RelToCheck structs, one for each distinct
2709 * relation, each containing one or more attribute numbers that are of
2710 * the domain type. We have opened each rel and acquired the specified lock
2713 * We support nested domains by including attributes that are of derived
2714 * domain types. Current callers do not need to distinguish between attributes
2715 * that are of exactly the given domain and those that are of derived domains.
2717 * XXX this is completely broken because there is no way to lock the domain
2718 * to prevent columns from being added or dropped while our command runs.
2719 * We can partially protect against column drops by locking relations as we
2720 * come across them, but there is still a race condition (the window between
2721 * seeing a pg_depend entry and acquiring lock on the relation it references).
2722 * Also, holding locks on all these relations simultaneously creates a non-
2723 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2724 * risk by using the weakest suitable lock (ShareLock for most callers).
2726 * XXX the API for this is not sufficient to support checking domain values
2727 * that are inside composite types or arrays. Currently we just error out
2728 * if a composite type containing the target domain is stored anywhere.
2729 * There are not currently arrays of domains; if there were, we could take
2730 * the same approach, but it'd be nicer to fix it properly.
2732 * Generally used for retrieving a list of tests when adding
2733 * new constraints to a domain.
2736 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2741 SysScanDesc depScan;
2744 Assert(lockmode != NoLock);
2747 * We scan pg_depend to find those things that depend on the domain. (We
2748 * assume we can ignore refobjsubid for a domain.)
2750 depRel = heap_open(DependRelationId, AccessShareLock);
2752 ScanKeyInit(&key[0],
2753 Anum_pg_depend_refclassid,
2754 BTEqualStrategyNumber, F_OIDEQ,
2755 ObjectIdGetDatum(TypeRelationId));
2756 ScanKeyInit(&key[1],
2757 Anum_pg_depend_refobjid,
2758 BTEqualStrategyNumber, F_OIDEQ,
2759 ObjectIdGetDatum(domainOid));
2761 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2764 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2766 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2767 RelToCheck *rtc = NULL;
2769 Form_pg_attribute pg_att;
2772 /* Check for directly dependent types --- must be domains */
2773 if (pg_depend->classid == TypeRelationId)
2775 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2778 * Recursively add dependent columns to the output list. This is
2779 * a bit inefficient since we may fail to combine RelToCheck
2780 * entries when attributes of the same rel have different derived
2781 * domain types, but it's probably not worth improving.
2783 result = list_concat(result,
2784 get_rels_with_domain(pg_depend->objid,
2789 /* Else, ignore dependees that aren't user columns of relations */
2790 /* (we assume system columns are never of domain types) */
2791 if (pg_depend->classid != RelationRelationId ||
2792 pg_depend->objsubid <= 0)
2795 /* See if we already have an entry for this relation */
2796 foreach(rellist, result)
2798 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2800 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2809 /* First attribute found for this relation */
2812 /* Acquire requested lock on relation */
2813 rel = relation_open(pg_depend->objid, lockmode);
2816 * Check to see if rowtype is stored anyplace as a composite-type
2817 * column; if so we have to fail, for now anyway.
2819 if (OidIsValid(rel->rd_rel->reltype))
2820 find_composite_type_dependencies(rel->rd_rel->reltype,
2822 format_type_be(domainOid));
2825 * Otherwise, we can ignore relations except those with both
2826 * storage and user-chosen column types.
2828 * XXX If an index-only scan could satisfy "col::some_domain" from
2829 * a suitable expression index, this should also check expression
2832 if (rel->rd_rel->relkind != RELKIND_RELATION &&
2833 rel->rd_rel->relkind != RELKIND_MATVIEW)
2835 relation_close(rel, lockmode);
2839 /* Build the RelToCheck entry with enough space for all atts */
2840 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2843 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2844 result = lcons(rtc, result);
2848 * Confirm column has not been dropped, and is of the expected type.
2849 * This defends against an ALTER DROP COLUMN occurring just before we
2850 * acquired lock ... but if the whole table were dropped, we'd still
2853 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2855 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2856 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2860 * Okay, add column to result. We store the columns in column-number
2861 * order; this is just a hack to improve predictability of regression
2864 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2867 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2869 rtc->atts[ptr] = rtc->atts[ptr - 1];
2872 rtc->atts[ptr] = pg_depend->objsubid;
2875 systable_endscan(depScan);
2877 relation_close(depRel, AccessShareLock);
2885 * Check that the type is actually a domain and that the current user
2886 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2889 checkDomainOwner(HeapTuple tup)
2891 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2893 /* Check that this is actually a domain */
2894 if (typTup->typtype != TYPTYPE_DOMAIN)
2896 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2897 errmsg("%s is not a domain",
2898 format_type_be(HeapTupleGetOid(tup)))));
2900 /* Permission check: must own type */
2901 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2902 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
2906 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2909 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2910 int typMod, Constraint *constr,
2917 CoerceToDomainValue *domVal;
2920 * Assign or validate constraint name
2922 if (constr->conname)
2924 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2929 (errcode(ERRCODE_DUPLICATE_OBJECT),
2930 errmsg("constraint \"%s\" for domain \"%s\" already exists",
2931 constr->conname, domainName)));
2934 constr->conname = ChooseConstraintName(domainName,
2941 * Convert the A_EXPR in raw_expr into an EXPR
2943 pstate = make_parsestate(NULL);
2946 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2947 * the expression. Note that it will appear to have the type of the base
2948 * type, not the domain. This seems correct since within the check
2949 * expression, we should not assume the input value can be considered a
2950 * member of the domain.
2952 domVal = makeNode(CoerceToDomainValue);
2953 domVal->typeId = baseTypeOid;
2954 domVal->typeMod = typMod;
2955 domVal->collation = get_typcollation(baseTypeOid);
2956 domVal->location = -1; /* will be set when/if used */
2958 pstate->p_value_substitute = (Node *) domVal;
2960 expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
2963 * Make sure it yields a boolean result.
2965 expr = coerce_to_boolean(pstate, expr, "CHECK");
2968 * Fix up collation information.
2970 assign_expr_collations(pstate, expr);
2973 * Domains don't allow variables (this is probably dead code now that
2974 * add_missing_from is history, but let's be sure).
2976 if (list_length(pstate->p_rtable) != 0 ||
2977 contain_var_clause(expr))
2979 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2980 errmsg("cannot use table references in domain check constraint")));
2983 * Convert to string form for storage.
2985 ccbin = nodeToString(expr);
2988 * Deparse it to produce text for consrc.
2990 ccsrc = deparse_expression(expr,
2994 * Store the constraint in pg_constraint
2996 CreateConstraintEntry(constr->conname, /* Constraint Name */
2997 domainNamespace, /* namespace */
2998 CONSTRAINT_CHECK, /* Constraint Type */
2999 false, /* Is Deferrable */
3000 false, /* Is Deferred */
3001 !constr->skip_validation, /* Is Validated */
3002 InvalidOid, /* not a relation constraint */
3005 domainOid, /* domain constraint */
3006 InvalidOid, /* no associated index */
3007 InvalidOid, /* Foreign key fields */
3016 NULL, /* not an exclusion constraint */
3017 expr, /* Tree form of check constraint */
3018 ccbin, /* Binary form of check constraint */
3019 ccsrc, /* Source form of check constraint */
3020 true, /* is local */
3022 false, /* connoinherit */
3023 false); /* is_internal */
3026 * Return the compiled constraint expression so the calling routine can
3027 * perform any additional required tests.
3033 * GetDomainConstraints - get a list of the current constraints of domain
3035 * Returns a possibly-empty list of DomainConstraintState nodes.
3037 * This is called by the executor during plan startup for a CoerceToDomain
3038 * expression node. The given constraints will be checked for each value
3039 * passed through the node.
3041 * We allow this to be called for non-domain types, in which case the result
3045 GetDomainConstraints(Oid typeOid)
3048 bool notNull = false;
3051 conRel = heap_open(ConstraintRelationId, AccessShareLock);
3057 Form_pg_type typTup;
3061 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3062 if (!HeapTupleIsValid(tup))
3063 elog(ERROR, "cache lookup failed for type %u", typeOid);
3064 typTup = (Form_pg_type) GETSTRUCT(tup);
3066 if (typTup->typtype != TYPTYPE_DOMAIN)
3068 /* Not a domain, so done */
3069 ReleaseSysCache(tup);
3073 /* Test for NOT NULL Constraint */
3074 if (typTup->typnotnull)
3077 /* Look for CHECK Constraints on this domain */
3078 ScanKeyInit(&key[0],
3079 Anum_pg_constraint_contypid,
3080 BTEqualStrategyNumber, F_OIDEQ,
3081 ObjectIdGetDatum(typeOid));
3083 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
3086 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
3088 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
3092 DomainConstraintState *r;
3094 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
3095 if (c->contype != CONSTRAINT_CHECK)
3099 * Not expecting conbin to be NULL, but we'll test for it anyway
3101 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
3102 conRel->rd_att, &isNull);
3104 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
3105 NameStr(typTup->typname), NameStr(c->conname));
3107 check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
3109 /* ExecInitExpr assumes we've planned the expression */
3110 check_expr = expression_planner(check_expr);
3112 r = makeNode(DomainConstraintState);
3113 r->constrainttype = DOM_CONSTRAINT_CHECK;
3114 r->name = pstrdup(NameStr(c->conname));
3115 r->check_expr = ExecInitExpr(check_expr, NULL);
3118 * use lcons() here because constraints of lower domains should be
3121 result = lcons(r, result);
3124 systable_endscan(scan);
3126 /* loop to next domain in stack */
3127 typeOid = typTup->typbasetype;
3128 ReleaseSysCache(tup);
3131 heap_close(conRel, AccessShareLock);
3134 * Only need to add one NOT NULL check regardless of how many domains in
3135 * the stack request it.
3139 DomainConstraintState *r = makeNode(DomainConstraintState);
3141 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
3142 r->name = pstrdup("NOT NULL");
3143 r->check_expr = NULL;
3145 /* lcons to apply the nullness check FIRST */
3146 result = lcons(r, result);
3154 * Execute ALTER TYPE RENAME
3157 RenameType(RenameStmt *stmt)
3159 List *names = stmt->object;
3160 const char *newTypeName = stmt->newname;
3165 Form_pg_type typTup;
3167 /* Make a TypeName so we can use standard type lookup machinery */
3168 typename = makeTypeNameFromNameList(names);
3169 typeOid = typenameTypeId(NULL, typename);
3171 /* Look up the type in the type table */
3172 rel = heap_open(TypeRelationId, RowExclusiveLock);
3174 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3175 if (!HeapTupleIsValid(tup))
3176 elog(ERROR, "cache lookup failed for type %u", typeOid);
3177 typTup = (Form_pg_type) GETSTRUCT(tup);
3179 /* check permissions on type */
3180 if (!pg_type_ownercheck(typeOid, GetUserId()))
3181 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3183 /* ALTER DOMAIN used on a non-domain? */
3184 if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3186 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3187 errmsg("\"%s\" is not a domain",
3188 format_type_be(typeOid))));
3191 * If it's a composite type, we need to check that it really is a
3192 * free-standing composite type, and not a table's rowtype. We want people
3193 * to use ALTER TABLE not ALTER TYPE for that case.
3195 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3196 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3198 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3199 errmsg("%s is a table's row type",
3200 format_type_be(typeOid)),
3201 errhint("Use ALTER TABLE instead.")));
3203 /* don't allow direct alteration of array types, either */
3204 if (OidIsValid(typTup->typelem) &&
3205 get_array_type(typTup->typelem) == typeOid)
3207 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3208 errmsg("cannot alter array type %s",
3209 format_type_be(typeOid)),
3210 errhint("You can alter type %s, which will alter the array type as well.",
3211 format_type_be(typTup->typelem))));
3214 * If type is composite we need to rename associated pg_class entry too.
3215 * RenameRelationInternal will call RenameTypeInternal automatically.
3217 if (typTup->typtype == TYPTYPE_COMPOSITE)
3218 RenameRelationInternal(typTup->typrelid, newTypeName, false);
3220 RenameTypeInternal(typeOid, newTypeName,
3221 typTup->typnamespace);
3224 heap_close(rel, RowExclusiveLock);
3230 * Change the owner of a type.
3233 AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
3240 Form_pg_type typTup;
3241 AclResult aclresult;
3243 rel = heap_open(TypeRelationId, RowExclusiveLock);
3245 /* Make a TypeName so we can use standard type lookup machinery */
3246 typename = makeTypeNameFromNameList(names);
3248 /* Use LookupTypeName here so that shell types can be processed */
3249 tup = LookupTypeName(NULL, typename, NULL);
3252 (errcode(ERRCODE_UNDEFINED_OBJECT),
3253 errmsg("type \"%s\" does not exist",
3254 TypeNameToString(typename))));
3255 typeOid = typeTypeId(tup);
3257 /* Copy the syscache entry so we can scribble on it below */
3258 newtup = heap_copytuple(tup);
3259 ReleaseSysCache(tup);
3261 typTup = (Form_pg_type) GETSTRUCT(tup);
3263 /* Don't allow ALTER DOMAIN on a type */
3264 if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3266 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3267 errmsg("%s is not a domain",
3268 format_type_be(typeOid))));
3271 * If it's a composite type, we need to check that it really is a
3272 * free-standing composite type, and not a table's rowtype. We want people
3273 * to use ALTER TABLE not ALTER TYPE for that case.
3275 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3276 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3278 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3279 errmsg("%s is a table's row type",
3280 format_type_be(typeOid)),
3281 errhint("Use ALTER TABLE instead.")));
3283 /* don't allow direct alteration of array types, either */
3284 if (OidIsValid(typTup->typelem) &&
3285 get_array_type(typTup->typelem) == typeOid)
3287 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3288 errmsg("cannot alter array type %s",
3289 format_type_be(typeOid)),
3290 errhint("You can alter type %s, which will alter the array type as well.",
3291 format_type_be(typTup->typelem))));
3294 * If the new owner is the same as the existing owner, consider the
3295 * command to have succeeded. This is for dump restoration purposes.
3297 if (typTup->typowner != newOwnerId)
3299 /* Superusers can always do it */
3302 /* Otherwise, must be owner of the existing object */
3303 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
3304 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
3306 /* Must be able to become new owner */
3307 check_is_member_of_role(GetUserId(), newOwnerId);
3309 /* New owner must have CREATE privilege on namespace */
3310 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3313 if (aclresult != ACLCHECK_OK)
3314 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
3315 get_namespace_name(typTup->typnamespace));
3319 * If it's a composite type, invoke ATExecChangeOwner so that we fix
3320 * up the pg_class entry properly. That will call back to
3321 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3323 if (typTup->typtype == TYPTYPE_COMPOSITE)
3324 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3328 * We can just apply the modification directly.
3330 * okay to scribble on typTup because it's a copy
3332 typTup->typowner = newOwnerId;
3334 simple_heap_update(rel, &tup->t_self, tup);
3336 CatalogUpdateIndexes(rel, tup);
3338 /* Update owner dependency reference */
3339 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3341 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3343 /* If it has an array type, update that too */
3344 if (OidIsValid(typTup->typarray))
3345 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3350 heap_close(rel, RowExclusiveLock);
3356 * AlterTypeOwnerInternal - change type owner unconditionally
3358 * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
3359 * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
3360 * It assumes the caller has done all needed checks. The function will
3361 * automatically recurse to an array type if the type has one.
3363 * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
3364 * entry (ie, it's not a table rowtype nor an array type).
3365 * is_primary_ops should be TRUE if this function is invoked with user's
3366 * direct operation (e.g, shdepReassignOwned). Elsewhere,
3369 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
3370 bool hasDependEntry)
3374 Form_pg_type typTup;
3376 rel = heap_open(TypeRelationId, RowExclusiveLock);
3378 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3379 if (!HeapTupleIsValid(tup))
3380 elog(ERROR, "cache lookup failed for type %u", typeOid);
3381 typTup = (Form_pg_type) GETSTRUCT(tup);
3384 * Modify the owner --- okay to scribble on typTup because it's a copy
3386 typTup->typowner = newOwnerId;
3388 simple_heap_update(rel, &tup->t_self, tup);
3390 CatalogUpdateIndexes(rel, tup);
3392 /* Update owner dependency reference, if it has one */
3394 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3396 /* If it has an array type, update that too */
3397 if (OidIsValid(typTup->typarray))
3398 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3400 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3403 heap_close(rel, RowExclusiveLock);
3407 * Execute ALTER TYPE SET SCHEMA
3410 AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype)
3415 ObjectAddresses *objsMoved;
3417 /* Make a TypeName so we can use standard type lookup machinery */
3418 typename = makeTypeNameFromNameList(names);
3419 typeOid = typenameTypeId(NULL, typename);
3421 /* Don't allow ALTER DOMAIN on a type */
3422 if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3424 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3425 errmsg("%s is not a domain",
3426 format_type_be(typeOid))));
3428 /* get schema OID and check its permissions */
3429 nspOid = LookupCreationNamespace(newschema);
3431 objsMoved = new_object_addresses();
3432 AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3433 free_object_addresses(objsMoved);
3439 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
3443 /* check permissions on type */
3444 if (!pg_type_ownercheck(typeOid, GetUserId()))
3445 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3447 /* don't allow direct alteration of array types */
3448 elemOid = get_element_type(typeOid);
3449 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3451 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3452 errmsg("cannot alter array type %s",
3453 format_type_be(typeOid)),
3454 errhint("You can alter type %s, which will alter the array type as well.",
3455 format_type_be(elemOid))));
3457 /* and do the work */
3458 return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3462 * Move specified type to new namespace.
3464 * Caller must have already checked privileges.
3466 * The function automatically recurses to process the type's array type,
3467 * if any. isImplicitArray should be TRUE only when doing this internal
3468 * recursion (outside callers must never try to move an array type directly).
3470 * If errorOnTableType is TRUE, the function errors out if the type is
3471 * a table type. ALTER TABLE has to be used to move a table to a new
3474 * Returns the type's old namespace OID.
3477 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
3478 bool isImplicitArray,
3479 bool errorOnTableType,
3480 ObjectAddresses *objsMoved)
3484 Form_pg_type typform;
3487 bool isCompositeType;
3488 ObjectAddress thisobj;
3491 * Make sure we haven't moved this object previously.
3493 thisobj.classId = TypeRelationId;
3494 thisobj.objectId = typeOid;
3495 thisobj.objectSubId = 0;
3497 if (object_address_present(&thisobj, objsMoved))
3500 rel = heap_open(TypeRelationId, RowExclusiveLock);
3502 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3503 if (!HeapTupleIsValid(tup))
3504 elog(ERROR, "cache lookup failed for type %u", typeOid);
3505 typform = (Form_pg_type) GETSTRUCT(tup);
3507 oldNspOid = typform->typnamespace;
3508 arrayOid = typform->typarray;
3510 /* common checks on switching namespaces */
3511 CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
3513 /* check for duplicate name (more friendly than unique-index failure) */
3514 if (SearchSysCacheExists2(TYPENAMENSP,
3515 CStringGetDatum(NameStr(typform->typname)),
3516 ObjectIdGetDatum(nspOid)))
3518 (errcode(ERRCODE_DUPLICATE_OBJECT),
3519 errmsg("type \"%s\" already exists in schema \"%s\"",
3520 NameStr(typform->typname),
3521 get_namespace_name(nspOid))));
3523 /* Detect whether type is a composite type (but not a table rowtype) */
3525 (typform->typtype == TYPTYPE_COMPOSITE &&
3526 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3528 /* Enforce not-table-type if requested */
3529 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3532 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3533 errmsg("%s is a table's row type",
3534 format_type_be(typeOid)),
3535 errhint("Use ALTER TABLE instead.")));
3537 /* OK, modify the pg_type row */
3539 /* tup is a copy, so we can scribble directly on it */
3540 typform->typnamespace = nspOid;
3542 simple_heap_update(rel, &tup->t_self, tup);
3543 CatalogUpdateIndexes(rel, tup);
3546 * Composite types have pg_class entries.
3548 * We need to modify the pg_class tuple as well to reflect the change of
3551 if (isCompositeType)
3555 classRel = heap_open(RelationRelationId, RowExclusiveLock);
3557 AlterRelationNamespaceInternal(classRel, typform->typrelid,
3561 heap_close(classRel, RowExclusiveLock);
3564 * Check for constraints associated with the composite type (we don't
3565 * currently support this, but probably will someday).
3567 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3568 nspOid, false, objsMoved);
3572 /* If it's a domain, it might have constraints */
3573 if (typform->typtype == TYPTYPE_DOMAIN)
3574 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
3579 * Update dependency on schema, if any --- a table rowtype has not got
3580 * one, and neither does an implicit array.
3582 if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3584 if (changeDependencyFor(TypeRelationId, typeOid,
3585 NamespaceRelationId, oldNspOid, nspOid) != 1)
3586 elog(ERROR, "failed to change schema dependency for type %s",
3587 format_type_be(typeOid));
3589 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3591 heap_freetuple(tup);
3593 heap_close(rel, RowExclusiveLock);
3595 add_exact_object_address(&thisobj, objsMoved);
3597 /* Recursively alter the associated array type, if any */
3598 if (OidIsValid(arrayOid))
3599 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);