1 /*-------------------------------------------------------------------------
4 * Routines for SQL commands that manipulate types (and domains).
6 * Portions Copyright (c) 1996-2011, 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/xact.h"
37 #include "catalog/catalog.h"
38 #include "catalog/dependency.h"
39 #include "catalog/heap.h"
40 #include "catalog/indexing.h"
41 #include "catalog/pg_collation.h"
42 #include "catalog/pg_constraint.h"
43 #include "catalog/pg_depend.h"
44 #include "catalog/pg_enum.h"
45 #include "catalog/pg_language.h"
46 #include "catalog/pg_namespace.h"
47 #include "catalog/pg_proc.h"
48 #include "catalog/pg_proc_fn.h"
49 #include "catalog/pg_range.h"
50 #include "catalog/pg_type.h"
51 #include "catalog/pg_type_fn.h"
52 #include "commands/defrem.h"
53 #include "commands/tablecmds.h"
54 #include "commands/typecmds.h"
55 #include "executor/executor.h"
56 #include "miscadmin.h"
57 #include "nodes/makefuncs.h"
58 #include "optimizer/planner.h"
59 #include "optimizer/var.h"
60 #include "parser/parse_coerce.h"
61 #include "parser/parse_collate.h"
62 #include "parser/parse_expr.h"
63 #include "parser/parse_func.h"
64 #include "parser/parse_type.h"
65 #include "utils/acl.h"
66 #include "utils/builtins.h"
67 #include "utils/fmgroids.h"
68 #include "utils/lsyscache.h"
69 #include "utils/memutils.h"
70 #include "utils/rangetypes.h"
71 #include "utils/rel.h"
72 #include "utils/syscache.h"
73 #include "utils/tqual.h"
76 /* result structure for get_rels_with_domain() */
79 Relation rel; /* opened and locked relation */
80 int natts; /* number of attributes of interest */
81 int *atts; /* attribute numbers */
82 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
85 /* Potentially set by contrib/pg_upgrade_support functions */
86 Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
88 static Oid findTypeInputFunction(List *procname, Oid typeOid);
89 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
90 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
91 static Oid findTypeSendFunction(List *procname, Oid typeOid);
92 static Oid findTypeTypmodinFunction(List *procname);
93 static Oid findTypeTypmodoutFunction(List *procname);
94 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
95 static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
96 static Oid findRangeSubOpclass(List *procname, Oid typeOid);
97 static Oid findRangeSubtypeDiffFunction(List *procname, Oid typeOid);
98 static void validateDomainConstraint(Oid domainoid, char *ccbin);
99 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
100 static void checkDomainOwner(HeapTuple tup);
101 static void checkEnumOwner(HeapTuple tup);
102 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
104 int typMod, Constraint *constr,
106 static void makeRangeConstructor(char *name, Oid namespace, Oid rettype,
112 * Registers a new base type.
115 DefineType(List *names, List *parameters)
119 int16 internalLength = -1; /* default: variable-length */
120 List *inputName = NIL;
121 List *outputName = NIL;
122 List *receiveName = NIL;
123 List *sendName = NIL;
124 List *typmodinName = NIL;
125 List *typmodoutName = NIL;
126 List *analyzeName = NIL;
127 char category = TYPCATEGORY_USER;
128 bool preferred = false;
129 char delimiter = DEFAULT_TYPDELIM;
130 Oid elemType = InvalidOid;
131 char *defaultValue = NULL;
132 bool byValue = false;
133 char alignment = 'i'; /* default alignment */
134 char storage = 'p'; /* default TOAST storage method */
135 Oid collation = InvalidOid;
136 DefElem *likeTypeEl = NULL;
137 DefElem *internalLengthEl = NULL;
138 DefElem *inputNameEl = NULL;
139 DefElem *outputNameEl = NULL;
140 DefElem *receiveNameEl = NULL;
141 DefElem *sendNameEl = NULL;
142 DefElem *typmodinNameEl = NULL;
143 DefElem *typmodoutNameEl = NULL;
144 DefElem *analyzeNameEl = NULL;
145 DefElem *categoryEl = NULL;
146 DefElem *preferredEl = NULL;
147 DefElem *delimiterEl = NULL;
148 DefElem *elemTypeEl = NULL;
149 DefElem *defaultValueEl = NULL;
150 DefElem *byValueEl = NULL;
151 DefElem *alignmentEl = NULL;
152 DefElem *storageEl = NULL;
153 DefElem *collatableEl = NULL;
156 Oid receiveOid = InvalidOid;
157 Oid sendOid = InvalidOid;
158 Oid typmodinOid = InvalidOid;
159 Oid typmodoutOid = InvalidOid;
160 Oid analyzeOid = InvalidOid;
168 * As of Postgres 8.4, we require superuser privilege to create a base
169 * type. This is simple paranoia: there are too many ways to mess up the
170 * system with an incorrect type definition (for instance, representation
171 * parameters that don't match what the C code expects). In practice it
172 * takes superuser privilege to create the I/O functions, and so the
173 * former requirement that you own the I/O functions pretty much forced
174 * superuserness anyway. We're just making doubly sure here.
176 * XXX re-enable NOT_USED code sections below if you remove this test.
180 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
181 errmsg("must be superuser to create a base type")));
183 /* Convert list of names to a name and namespace */
184 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
187 /* XXX this is unnecessary given the superuser check above */
188 /* Check we have creation rights in target namespace */
189 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
190 if (aclresult != ACLCHECK_OK)
191 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
192 get_namespace_name(typeNamespace));
196 * Look to see if type already exists (presumably as a shell; if not,
197 * TypeCreate will complain).
199 typoid = GetSysCacheOid2(TYPENAMENSP,
200 CStringGetDatum(typeName),
201 ObjectIdGetDatum(typeNamespace));
204 * If it's not a shell, see if it's an autogenerated array type, and if so
205 * rename it out of the way.
207 if (OidIsValid(typoid) && get_typisdefined(typoid))
209 if (moveArrayTypeName(typoid, typeName, typeNamespace))
214 * If it doesn't exist, create it as a shell, so that the OID is known for
215 * use in the I/O function definitions.
217 if (!OidIsValid(typoid))
219 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
220 /* Make new shell type visible for modification below */
221 CommandCounterIncrement();
224 * If the command was a parameterless CREATE TYPE, we're done ---
225 * creating the shell type was all we're supposed to do.
227 if (parameters == NIL)
232 /* Complain if dummy CREATE TYPE and entry already exists */
233 if (parameters == NIL)
235 (errcode(ERRCODE_DUPLICATE_OBJECT),
236 errmsg("type \"%s\" already exists", typeName)));
239 /* Extract the parameters from the parameter list */
240 foreach(pl, parameters)
242 DefElem *defel = (DefElem *) lfirst(pl);
245 if (pg_strcasecmp(defel->defname, "like") == 0)
246 defelp = &likeTypeEl;
247 else if (pg_strcasecmp(defel->defname, "internallength") == 0)
248 defelp = &internalLengthEl;
249 else if (pg_strcasecmp(defel->defname, "input") == 0)
250 defelp = &inputNameEl;
251 else if (pg_strcasecmp(defel->defname, "output") == 0)
252 defelp = &outputNameEl;
253 else if (pg_strcasecmp(defel->defname, "receive") == 0)
254 defelp = &receiveNameEl;
255 else if (pg_strcasecmp(defel->defname, "send") == 0)
256 defelp = &sendNameEl;
257 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
258 defelp = &typmodinNameEl;
259 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
260 defelp = &typmodoutNameEl;
261 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
262 pg_strcasecmp(defel->defname, "analyse") == 0)
263 defelp = &analyzeNameEl;
264 else if (pg_strcasecmp(defel->defname, "category") == 0)
265 defelp = &categoryEl;
266 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
267 defelp = &preferredEl;
268 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
269 defelp = &delimiterEl;
270 else if (pg_strcasecmp(defel->defname, "element") == 0)
271 defelp = &elemTypeEl;
272 else if (pg_strcasecmp(defel->defname, "default") == 0)
273 defelp = &defaultValueEl;
274 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
276 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
277 defelp = &alignmentEl;
278 else if (pg_strcasecmp(defel->defname, "storage") == 0)
280 else if (pg_strcasecmp(defel->defname, "collatable") == 0)
281 defelp = &collatableEl;
284 /* WARNING, not ERROR, for historical backwards-compatibility */
286 (errcode(ERRCODE_SYNTAX_ERROR),
287 errmsg("type attribute \"%s\" not recognized",
293 (errcode(ERRCODE_SYNTAX_ERROR),
294 errmsg("conflicting or redundant options")));
299 * Now interpret the options; we do this separately so that LIKE can be
300 * overridden by other options regardless of the ordering in the parameter
306 Form_pg_type likeForm;
308 likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
309 likeForm = (Form_pg_type) GETSTRUCT(likeType);
310 internalLength = likeForm->typlen;
311 byValue = likeForm->typbyval;
312 alignment = likeForm->typalign;
313 storage = likeForm->typstorage;
314 ReleaseSysCache(likeType);
316 if (internalLengthEl)
317 internalLength = defGetTypeLength(internalLengthEl);
319 inputName = defGetQualifiedName(inputNameEl);
321 outputName = defGetQualifiedName(outputNameEl);
323 receiveName = defGetQualifiedName(receiveNameEl);
325 sendName = defGetQualifiedName(sendNameEl);
327 typmodinName = defGetQualifiedName(typmodinNameEl);
329 typmodoutName = defGetQualifiedName(typmodoutNameEl);
331 analyzeName = defGetQualifiedName(analyzeNameEl);
334 char *p = defGetString(categoryEl);
337 /* restrict to non-control ASCII */
338 if (category < 32 || category > 126)
340 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
341 errmsg("invalid type category \"%s\": must be simple ASCII",
345 preferred = defGetBoolean(preferredEl);
348 char *p = defGetString(delimiterEl);
351 /* XXX shouldn't we restrict the delimiter? */
355 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
356 /* disallow arrays of pseudotypes */
357 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
359 (errcode(ERRCODE_DATATYPE_MISMATCH),
360 errmsg("array element type cannot be %s",
361 format_type_be(elemType))));
364 defaultValue = defGetString(defaultValueEl);
366 byValue = defGetBoolean(byValueEl);
369 char *a = defGetString(alignmentEl);
372 * Note: if argument was an unquoted identifier, parser will have
373 * applied translations to it, so be prepared to recognize translated
374 * type names as well as the nominal form.
376 if (pg_strcasecmp(a, "double") == 0 ||
377 pg_strcasecmp(a, "float8") == 0 ||
378 pg_strcasecmp(a, "pg_catalog.float8") == 0)
380 else if (pg_strcasecmp(a, "int4") == 0 ||
381 pg_strcasecmp(a, "pg_catalog.int4") == 0)
383 else if (pg_strcasecmp(a, "int2") == 0 ||
384 pg_strcasecmp(a, "pg_catalog.int2") == 0)
386 else if (pg_strcasecmp(a, "char") == 0 ||
387 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
391 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
392 errmsg("alignment \"%s\" not recognized", a)));
396 char *a = defGetString(storageEl);
398 if (pg_strcasecmp(a, "plain") == 0)
400 else if (pg_strcasecmp(a, "external") == 0)
402 else if (pg_strcasecmp(a, "extended") == 0)
404 else if (pg_strcasecmp(a, "main") == 0)
408 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
409 errmsg("storage \"%s\" not recognized", a)));
412 collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
415 * make sure we have our required definitions
417 if (inputName == NIL)
419 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
420 errmsg("type input function must be specified")));
421 if (outputName == NIL)
423 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
424 errmsg("type output function must be specified")));
426 if (typmodinName == NIL && typmodoutName != NIL)
428 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
429 errmsg("type modifier output function is useless without a type modifier input function")));
432 * Convert I/O proc names to OIDs
434 inputOid = findTypeInputFunction(inputName, typoid);
435 outputOid = findTypeOutputFunction(outputName, typoid);
437 receiveOid = findTypeReceiveFunction(receiveName, typoid);
439 sendOid = findTypeSendFunction(sendName, typoid);
442 * Verify that I/O procs return the expected thing. If we see OPAQUE,
443 * complain and change it to the correct type-safe choice.
445 resulttype = get_func_rettype(inputOid);
446 if (resulttype != typoid)
448 if (resulttype == OPAQUEOID)
450 /* backwards-compatibility hack */
452 (errmsg("changing return type of function %s from \"opaque\" to %s",
453 NameListToString(inputName), typeName)));
454 SetFunctionReturnType(inputOid, typoid);
458 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
459 errmsg("type input function %s must return type %s",
460 NameListToString(inputName), typeName)));
462 resulttype = get_func_rettype(outputOid);
463 if (resulttype != CSTRINGOID)
465 if (resulttype == OPAQUEOID)
467 /* backwards-compatibility hack */
469 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
470 NameListToString(outputName))));
471 SetFunctionReturnType(outputOid, CSTRINGOID);
475 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
476 errmsg("type output function %s must return type \"cstring\"",
477 NameListToString(outputName))));
481 resulttype = get_func_rettype(receiveOid);
482 if (resulttype != typoid)
484 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
485 errmsg("type receive function %s must return type %s",
486 NameListToString(receiveName), typeName)));
490 resulttype = get_func_rettype(sendOid);
491 if (resulttype != BYTEAOID)
493 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
494 errmsg("type send function %s must return type \"bytea\"",
495 NameListToString(sendName))));
499 * Convert typmodin/out function proc names to OIDs.
502 typmodinOid = findTypeTypmodinFunction(typmodinName);
504 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
507 * Convert analysis function proc name to an OID. If no analysis function
508 * is specified, we'll use zero to select the built-in default algorithm.
511 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
514 * Check permissions on functions. We choose to require the creator/owner
515 * of a type to also own the underlying functions. Since creating a type
516 * is tantamount to granting public execute access on the functions, the
517 * minimum sane check would be for execute-with-grant-option. But we
518 * don't have a way to make the type go away if the grant option is
519 * revoked, so ownership seems better.
522 /* XXX this is unnecessary given the superuser check above */
523 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
524 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
525 NameListToString(inputName));
526 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
527 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
528 NameListToString(outputName));
529 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
530 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
531 NameListToString(receiveName));
532 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
533 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
534 NameListToString(sendName));
535 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
536 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
537 NameListToString(typmodinName));
538 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
539 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
540 NameListToString(typmodoutName));
541 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
542 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
543 NameListToString(analyzeName));
546 array_oid = AssignTypeArrayOid();
549 * now have TypeCreate do all the real work.
551 * Note: the pg_type.oid is stored in user tables as array elements (base
552 * types) in ArrayType and in composite types in DatumTupleFields. This
553 * oid must be preserved by binary upgrades.
556 TypeCreate(InvalidOid, /* no predetermined type OID */
557 typeName, /* type name */
558 typeNamespace, /* namespace */
559 InvalidOid, /* relation oid (n/a here) */
560 0, /* relation kind (ditto) */
561 GetUserId(), /* owner's ID */
562 internalLength, /* internal size */
563 TYPTYPE_BASE, /* type-type (base type) */
564 category, /* type-category */
565 preferred, /* is it a preferred type? */
566 delimiter, /* array element delimiter */
567 inputOid, /* input procedure */
568 outputOid, /* output procedure */
569 receiveOid, /* receive procedure */
570 sendOid, /* send procedure */
571 typmodinOid, /* typmodin procedure */
572 typmodoutOid, /* typmodout procedure */
573 analyzeOid, /* analyze procedure */
574 elemType, /* element type ID */
575 false, /* this is not an array type */
576 array_oid, /* array type we are about to create */
577 InvalidOid, /* base type ID (only for domains) */
578 defaultValue, /* default type value */
579 NULL, /* no binary form available */
580 byValue, /* passed by value */
581 alignment, /* required alignment */
582 storage, /* TOAST strategy */
583 -1, /* typMod (Domains only) */
584 0, /* Array Dimensions of typbasetype */
585 false, /* Type NOT NULL */
586 collation); /* type's collation */
589 * Create the array type that goes with it.
591 array_type = makeArrayTypeName(typeName, typeNamespace);
593 /* alignment must be 'i' or 'd' for arrays */
594 alignment = (alignment == 'd') ? 'd' : 'i';
596 TypeCreate(array_oid, /* force assignment of this type OID */
597 array_type, /* type name */
598 typeNamespace, /* namespace */
599 InvalidOid, /* relation oid (n/a here) */
600 0, /* relation kind (ditto) */
601 GetUserId(), /* owner's ID */
602 -1, /* internal size (always varlena) */
603 TYPTYPE_BASE, /* type-type (base type) */
604 TYPCATEGORY_ARRAY, /* type-category (array) */
605 false, /* array types are never preferred */
606 delimiter, /* array element delimiter */
607 F_ARRAY_IN, /* input procedure */
608 F_ARRAY_OUT, /* output procedure */
609 F_ARRAY_RECV, /* receive procedure */
610 F_ARRAY_SEND, /* send procedure */
611 typmodinOid, /* typmodin procedure */
612 typmodoutOid, /* typmodout procedure */
613 InvalidOid, /* analyze procedure - default */
614 typoid, /* element type ID */
615 true, /* yes this is an array type */
616 InvalidOid, /* no further array type */
617 InvalidOid, /* base type ID */
618 NULL, /* never a default type value */
619 NULL, /* binary default isn't sent either */
620 false, /* never passed by value */
621 alignment, /* see above */
622 'x', /* ARRAY is always toastable */
623 -1, /* typMod (Domains only) */
624 0, /* Array dimensions of typbasetype */
625 false, /* Type NOT NULL */
626 collation); /* type's collation */
632 * Guts of type deletion.
635 RemoveTypeById(Oid typeOid)
640 relation = heap_open(TypeRelationId, RowExclusiveLock);
642 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
643 if (!HeapTupleIsValid(tup))
644 elog(ERROR, "cache lookup failed for type %u", typeOid);
646 simple_heap_delete(relation, &tup->t_self);
649 * If it is an enum, delete the pg_enum entries too; we don't bother with
650 * making dependency entries for those, so it has to be done "by hand"
653 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
654 EnumValuesDelete(typeOid);
657 * If it is a range type, delete the pg_range entries too; we don't bother
658 * with making dependency entries for those, so it has to be done "by
661 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
662 RangeDelete(typeOid);
664 ReleaseSysCache(tup);
666 heap_close(relation, RowExclusiveLock);
672 * Registers a new domain.
675 DefineDomain(CreateDomainStmt *stmt)
680 int16 internalLength;
683 Oid receiveProcedure;
685 Oid analyzeProcedure;
694 char *defaultValue = NULL;
695 char *defaultValueBin = NULL;
696 bool saw_default = false;
697 bool typNotNull = false;
698 bool nullDefined = false;
699 int32 typNDims = list_length(stmt->typeName->arrayBounds);
701 List *schema = stmt->constraints;
707 Form_pg_type baseType;
711 /* Convert list of names to a name and namespace */
712 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
715 /* Check we have creation rights in target namespace */
716 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
718 if (aclresult != ACLCHECK_OK)
719 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
720 get_namespace_name(domainNamespace));
723 * Check for collision with an existing type name. If there is one and
724 * it's an autogenerated array, we can rename it out of the way.
726 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
727 CStringGetDatum(domainName),
728 ObjectIdGetDatum(domainNamespace));
729 if (OidIsValid(old_type_oid))
731 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
733 (errcode(ERRCODE_DUPLICATE_OBJECT),
734 errmsg("type \"%s\" already exists", domainName)));
738 * Look up the base type.
740 typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
741 baseType = (Form_pg_type) GETSTRUCT(typeTup);
742 basetypeoid = HeapTupleGetOid(typeTup);
745 * Base type must be a plain base type, another domain, an enum or a range
746 * type. Domains over pseudotypes would create a security hole. Domains
747 * over composite types might be made to work in the future, but not
750 typtype = baseType->typtype;
751 if (typtype != TYPTYPE_BASE &&
752 typtype != TYPTYPE_DOMAIN &&
753 typtype != TYPTYPE_ENUM &&
754 typtype != TYPTYPE_RANGE)
756 (errcode(ERRCODE_DATATYPE_MISMATCH),
757 errmsg("\"%s\" is not a valid base type for a domain",
758 TypeNameToString(stmt->typeName))));
761 * Identify the collation if any
763 baseColl = baseType->typcollation;
764 if (stmt->collClause)
765 domaincoll = get_collation_oid(stmt->collClause->collname, false);
767 domaincoll = baseColl;
769 /* Complain if COLLATE is applied to an uncollatable type */
770 if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
772 (errcode(ERRCODE_DATATYPE_MISMATCH),
773 errmsg("collations are not supported by type %s",
774 format_type_be(basetypeoid))));
776 /* passed by value */
777 byValue = baseType->typbyval;
779 /* Required Alignment */
780 alignment = baseType->typalign;
783 storage = baseType->typstorage;
786 internalLength = baseType->typlen;
789 category = baseType->typcategory;
791 /* Array element Delimiter */
792 delimiter = baseType->typdelim;
795 inputProcedure = F_DOMAIN_IN;
796 outputProcedure = baseType->typoutput;
797 receiveProcedure = F_DOMAIN_RECV;
798 sendProcedure = baseType->typsend;
800 /* Domains never accept typmods, so no typmodin/typmodout needed */
802 /* Analysis function */
803 analyzeProcedure = baseType->typanalyze;
805 /* Inherited default value */
806 datum = SysCacheGetAttr(TYPEOID, typeTup,
807 Anum_pg_type_typdefault, &isnull);
809 defaultValue = TextDatumGetCString(datum);
811 /* Inherited default binary value */
812 datum = SysCacheGetAttr(TYPEOID, typeTup,
813 Anum_pg_type_typdefaultbin, &isnull);
815 defaultValueBin = TextDatumGetCString(datum);
818 * Run through constraints manually to avoid the additional processing
819 * conducted by DefineRelation() and friends.
821 foreach(listptr, schema)
823 Constraint *constr = lfirst(listptr);
825 if (!IsA(constr, Constraint))
826 elog(ERROR, "unrecognized node type: %d",
827 (int) nodeTag(constr));
828 switch (constr->contype)
833 * The inherited default value may be overridden by the user
834 * with the DEFAULT <expr> clause ... but only once.
838 (errcode(ERRCODE_SYNTAX_ERROR),
839 errmsg("multiple default expressions")));
842 if (constr->raw_expr)
847 /* Create a dummy ParseState for transformExpr */
848 pstate = make_parsestate(NULL);
851 * Cook the constr->raw_expr into an expression. Note:
852 * name is strictly for error message
854 defaultExpr = cookDefault(pstate, constr->raw_expr,
860 * If the expression is just a NULL constant, we treat it
861 * like not having a default.
863 * Note that if the basetype is another domain, we'll see
864 * a CoerceToDomain expr here and not discard the default.
865 * This is critical because the domain default needs to be
866 * retained to override any default that the base domain
869 if (defaultExpr == NULL ||
870 (IsA(defaultExpr, Const) &&
871 ((Const *) defaultExpr)->constisnull))
874 defaultValueBin = NULL;
879 * Expression must be stored as a nodeToString result,
880 * but we also require a valid textual representation
881 * (mainly to make life easier for pg_dump).
884 deparse_expression(defaultExpr,
885 deparse_context_for(domainName,
888 defaultValueBin = nodeToString(defaultExpr);
893 /* No default (can this still happen?) */
895 defaultValueBin = NULL;
900 if (nullDefined && !typNotNull)
902 (errcode(ERRCODE_SYNTAX_ERROR),
903 errmsg("conflicting NULL/NOT NULL constraints")));
909 if (nullDefined && typNotNull)
911 (errcode(ERRCODE_SYNTAX_ERROR),
912 errmsg("conflicting NULL/NOT NULL constraints")));
920 * Check constraints are handled after domain creation, as
921 * they require the Oid of the domain
926 * All else are error cases
930 (errcode(ERRCODE_SYNTAX_ERROR),
931 errmsg("unique constraints not possible for domains")));
936 (errcode(ERRCODE_SYNTAX_ERROR),
937 errmsg("primary key constraints not possible for domains")));
940 case CONSTR_EXCLUSION:
942 (errcode(ERRCODE_SYNTAX_ERROR),
943 errmsg("exclusion constraints not possible for domains")));
948 (errcode(ERRCODE_SYNTAX_ERROR),
949 errmsg("foreign key constraints not possible for domains")));
952 case CONSTR_ATTR_DEFERRABLE:
953 case CONSTR_ATTR_NOT_DEFERRABLE:
954 case CONSTR_ATTR_DEFERRED:
955 case CONSTR_ATTR_IMMEDIATE:
957 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
958 errmsg("specifying constraint deferrability not supported for domains")));
962 elog(ERROR, "unrecognized constraint subtype: %d",
963 (int) constr->contype);
969 * Have TypeCreate do all the real work.
972 TypeCreate(InvalidOid, /* no predetermined type OID */
973 domainName, /* type name */
974 domainNamespace, /* namespace */
975 InvalidOid, /* relation oid (n/a here) */
976 0, /* relation kind (ditto) */
977 GetUserId(), /* owner's ID */
978 internalLength, /* internal size */
979 TYPTYPE_DOMAIN, /* type-type (domain type) */
980 category, /* type-category */
981 false, /* domain types are never preferred */
982 delimiter, /* array element delimiter */
983 inputProcedure, /* input procedure */
984 outputProcedure, /* output procedure */
985 receiveProcedure, /* receive procedure */
986 sendProcedure, /* send procedure */
987 InvalidOid, /* typmodin procedure - none */
988 InvalidOid, /* typmodout procedure - none */
989 analyzeProcedure, /* analyze procedure */
990 InvalidOid, /* no array element type */
991 false, /* this isn't an array */
992 InvalidOid, /* no arrays for domains (yet) */
993 basetypeoid, /* base type ID */
994 defaultValue, /* default type value (text) */
995 defaultValueBin, /* default type value (binary) */
996 byValue, /* passed by value */
997 alignment, /* required alignment */
998 storage, /* TOAST strategy */
999 basetypeMod, /* typeMod value */
1000 typNDims, /* Array dimensions for base type */
1001 typNotNull, /* Type NOT NULL */
1002 domaincoll); /* type's collation */
1005 * Process constraints which refer to the domain ID returned by TypeCreate
1007 foreach(listptr, schema)
1009 Constraint *constr = lfirst(listptr);
1011 /* it must be a Constraint, per check above */
1013 switch (constr->contype)
1016 domainAddConstraint(domainoid, domainNamespace,
1017 basetypeoid, basetypeMod,
1018 constr, domainName);
1021 /* Other constraint types were fully processed above */
1027 /* CCI so we can detect duplicate constraint names */
1028 CommandCounterIncrement();
1032 * Now we can clean up.
1034 ReleaseSysCache(typeTup);
1040 * Registers a new enum.
1043 DefineEnum(CreateEnumStmt *stmt)
1046 char *enumArrayName;
1049 AclResult aclresult;
1053 /* Convert list of names to a name and namespace */
1054 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1057 /* Check we have creation rights in target namespace */
1058 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1059 if (aclresult != ACLCHECK_OK)
1060 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1061 get_namespace_name(enumNamespace));
1064 * Check for collision with an existing type name. If there is one and
1065 * it's an autogenerated array, we can rename it out of the way.
1067 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1068 CStringGetDatum(enumName),
1069 ObjectIdGetDatum(enumNamespace));
1070 if (OidIsValid(old_type_oid))
1072 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1074 (errcode(ERRCODE_DUPLICATE_OBJECT),
1075 errmsg("type \"%s\" already exists", enumName)));
1078 enumArrayOid = AssignTypeArrayOid();
1080 /* Create the pg_type entry */
1082 TypeCreate(InvalidOid, /* no predetermined type OID */
1083 enumName, /* type name */
1084 enumNamespace, /* namespace */
1085 InvalidOid, /* relation oid (n/a here) */
1086 0, /* relation kind (ditto) */
1087 GetUserId(), /* owner's ID */
1088 sizeof(Oid), /* internal size */
1089 TYPTYPE_ENUM, /* type-type (enum type) */
1090 TYPCATEGORY_ENUM, /* type-category (enum type) */
1091 false, /* enum types are never preferred */
1092 DEFAULT_TYPDELIM, /* array element delimiter */
1093 F_ENUM_IN, /* input procedure */
1094 F_ENUM_OUT, /* output procedure */
1095 F_ENUM_RECV, /* receive procedure */
1096 F_ENUM_SEND, /* send procedure */
1097 InvalidOid, /* typmodin procedure - none */
1098 InvalidOid, /* typmodout procedure - none */
1099 InvalidOid, /* analyze procedure - default */
1100 InvalidOid, /* element type ID */
1101 false, /* this is not an array type */
1102 enumArrayOid, /* array type we are about to create */
1103 InvalidOid, /* base type ID (only for domains) */
1104 NULL, /* never a default type value */
1105 NULL, /* binary default isn't sent either */
1106 true, /* always passed by value */
1107 'i', /* int alignment */
1108 'p', /* TOAST strategy always plain */
1109 -1, /* typMod (Domains only) */
1110 0, /* Array dimensions of typbasetype */
1111 false, /* Type NOT NULL */
1112 InvalidOid); /* type's collation */
1114 /* Enter the enum's values into pg_enum */
1115 EnumValuesCreate(enumTypeOid, stmt->vals);
1118 * Create the array type that goes with it.
1120 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1122 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1123 enumArrayName, /* type name */
1124 enumNamespace, /* namespace */
1125 InvalidOid, /* relation oid (n/a here) */
1126 0, /* relation kind (ditto) */
1127 GetUserId(), /* owner's ID */
1128 -1, /* internal size (always varlena) */
1129 TYPTYPE_BASE, /* type-type (base type) */
1130 TYPCATEGORY_ARRAY, /* type-category (array) */
1131 false, /* array types are never preferred */
1132 DEFAULT_TYPDELIM, /* array element delimiter */
1133 F_ARRAY_IN, /* input procedure */
1134 F_ARRAY_OUT, /* output procedure */
1135 F_ARRAY_RECV, /* receive procedure */
1136 F_ARRAY_SEND, /* send procedure */
1137 InvalidOid, /* typmodin procedure - none */
1138 InvalidOid, /* typmodout procedure - none */
1139 InvalidOid, /* analyze procedure - default */
1140 enumTypeOid, /* element type ID */
1141 true, /* yes this is an array type */
1142 InvalidOid, /* no further array type */
1143 InvalidOid, /* base type ID */
1144 NULL, /* never a default type value */
1145 NULL, /* binary default isn't sent either */
1146 false, /* never passed by value */
1147 'i', /* enums have align i, so do their arrays */
1148 'x', /* ARRAY is always toastable */
1149 -1, /* typMod (Domains only) */
1150 0, /* Array dimensions of typbasetype */
1151 false, /* Type NOT NULL */
1152 InvalidOid); /* type's collation */
1154 pfree(enumArrayName);
1159 * Registers a new range type.
1162 DefineRange(CreateRangeStmt *stmt)
1165 char *rangeArrayName;
1169 List *parameters = stmt->params;
1170 List *rangeSubOpclassName = NIL;
1171 List *rangeSubtypeDiffName = NIL;
1172 List *rangeCollationName = NIL;
1173 Oid rangeCollation = InvalidOid;
1174 regproc rangeAnalyze = InvalidOid;
1175 Oid rangeSubtype = InvalidOid;
1176 regproc rangeSubOpclass = InvalidOid;
1177 regproc rangeCanonical = InvalidOid;
1178 regproc rangeSubtypeDiff = InvalidOid;
1183 AclResult aclresult;
1186 /* Convert list of names to a name and namespace */
1187 typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1190 /* Check we have creation rights in target namespace */
1191 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1192 if (aclresult != ACLCHECK_OK)
1193 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1194 get_namespace_name(typeNamespace));
1197 * Look to see if type already exists (presumably as a shell; if not,
1198 * TypeCreate will complain).
1200 typoid = GetSysCacheOid2(TYPENAMENSP,
1201 CStringGetDatum(typeName),
1202 ObjectIdGetDatum(typeNamespace));
1205 * If it's not a shell, see if it's an autogenerated array type, and if so
1206 * rename it out of the way.
1208 if (OidIsValid(typoid) && get_typisdefined(typoid))
1210 if (moveArrayTypeName(typoid, typeName, typeNamespace))
1211 typoid = InvalidOid;
1215 * If it doesn't exist, create it as a shell, so that the OID is known for
1216 * use in the I/O function definitions.
1218 if (!OidIsValid(typoid))
1220 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
1221 /* Make new shell type visible for modification below */
1222 CommandCounterIncrement();
1225 * If the command was a parameterless CREATE TYPE, we're done ---
1226 * creating the shell type was all we're supposed to do.
1228 if (parameters == NIL)
1233 /* Complain if dummy CREATE TYPE and entry already exists */
1234 if (parameters == NIL)
1236 (errcode(ERRCODE_DUPLICATE_OBJECT),
1237 errmsg("type \"%s\" already exists", typeName)));
1240 foreach(lc, stmt->params)
1242 DefElem *defel = lfirst(lc);
1244 if (pg_strcasecmp(defel->defname, "subtype") == 0)
1246 if (OidIsValid(rangeSubtype))
1248 (errcode(ERRCODE_SYNTAX_ERROR),
1249 errmsg("conflicting or redundant options")));
1250 rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1252 else if (pg_strcasecmp(defel->defname, "canonical") == 0)
1254 if (OidIsValid(rangeCanonical))
1256 (errcode(ERRCODE_SYNTAX_ERROR),
1257 errmsg("conflicting or redundant options")));
1258 rangeCanonical = findRangeCanonicalFunction(
1259 defGetQualifiedName(defel), typoid);
1261 else if (pg_strcasecmp(defel->defname, "collation") == 0)
1263 if (rangeCollationName != NIL)
1265 (errcode(ERRCODE_SYNTAX_ERROR),
1266 errmsg("conflicting or redundant options")));
1267 rangeCollationName = defGetQualifiedName(defel);
1269 else if (pg_strcasecmp(defel->defname, "analyze") == 0)
1271 if (OidIsValid(rangeAnalyze))
1273 (errcode(ERRCODE_SYNTAX_ERROR),
1274 errmsg("conflicting or redundant options")));
1275 rangeAnalyze = findTypeAnalyzeFunction(defGetQualifiedName(defel),
1278 else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
1280 if (rangeSubOpclassName != NIL)
1282 (errcode(ERRCODE_SYNTAX_ERROR),
1283 errmsg("conflicting or redundant options")));
1284 rangeSubOpclassName = defGetQualifiedName(defel);
1286 else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
1288 if (rangeSubtypeDiffName != NIL)
1290 (errcode(ERRCODE_SYNTAX_ERROR),
1291 errmsg("conflicting or redundant options")));
1292 rangeSubtypeDiffName = defGetQualifiedName(defel);
1297 (errcode(ERRCODE_SYNTAX_ERROR),
1298 errmsg("type attribute \"%s\" not recognized",
1304 if (!OidIsValid(rangeSubtype))
1306 (errcode(ERRCODE_SYNTAX_ERROR),
1307 errmsg("type attribute \"subtype\" is required")));
1309 if (type_is_collatable(rangeSubtype))
1311 if (rangeCollationName == NIL)
1312 rangeCollation = get_typcollation(rangeSubtype);
1314 rangeCollation = get_collation_oid(rangeCollationName, false);
1316 else if (rangeCollationName != NIL)
1318 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1319 errmsg("range collation specified but subtype does not support collation")));
1321 rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1323 if (rangeSubtypeDiffName != NIL)
1324 rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1327 get_typlenbyvalalign(rangeSubtype,
1328 &subtyplen, &subtypbyval, &subtypalign);
1330 /* alignment must be 'i' or 'd' for ranges */
1331 alignment = (subtypalign == 'd') ? 'd' : 'i';
1333 /* Allocate OID for array type */
1334 rangeArrayOid = AssignTypeArrayOid();
1336 /* Create the pg_type entry */
1338 TypeCreate(InvalidOid, /* no predetermined type OID */
1339 typeName, /* type name */
1340 typeNamespace, /* namespace */
1341 InvalidOid, /* relation oid (n/a here) */
1342 0, /* relation kind (ditto) */
1343 GetUserId(), /* owner's ID */
1344 -1, /* internal size (always varlena) */
1345 TYPTYPE_RANGE, /* type-type (range type) */
1346 TYPCATEGORY_RANGE, /* type-category (range type) */
1347 false, /* range types are never preferred */
1348 DEFAULT_TYPDELIM, /* array element delimiter */
1349 F_RANGE_IN, /* input procedure */
1350 F_RANGE_OUT, /* output procedure */
1351 F_RANGE_RECV, /* receive procedure */
1352 F_RANGE_SEND, /* send procedure */
1353 InvalidOid, /* typmodin procedure - none */
1354 InvalidOid, /* typmodout procedure - none */
1355 rangeAnalyze, /* analyze procedure */
1356 InvalidOid, /* element type ID - none */
1357 false, /* this is not an array type */
1358 rangeArrayOid, /* array type we are about to create */
1359 InvalidOid, /* base type ID (only for domains) */
1360 NULL, /* never a default type value */
1361 NULL, /* binary default isn't sent either */
1362 false, /* never passed by value */
1363 alignment, /* alignment */
1364 'x', /* TOAST strategy (always extended) */
1365 -1, /* typMod (Domains only) */
1366 0, /* Array dimensions of typbasetype */
1367 false, /* Type NOT NULL */
1368 InvalidOid); /* typcollation */
1370 /* create the entry in pg_range */
1371 RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1372 rangeCanonical, rangeSubtypeDiff);
1375 * Create the array type that goes with it.
1377 rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1379 TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1380 rangeArrayName, /* type name */
1381 typeNamespace, /* namespace */
1382 InvalidOid, /* relation oid (n/a here) */
1383 0, /* relation kind (ditto) */
1384 GetUserId(), /* owner's ID */
1385 -1, /* internal size (always varlena) */
1386 TYPTYPE_BASE, /* type-type (base type) */
1387 TYPCATEGORY_ARRAY, /* type-category (array) */
1388 false, /* array types are never preferred */
1389 DEFAULT_TYPDELIM, /* array element delimiter */
1390 F_ARRAY_IN, /* input procedure */
1391 F_ARRAY_OUT, /* output procedure */
1392 F_ARRAY_RECV, /* receive procedure */
1393 F_ARRAY_SEND, /* send procedure */
1394 InvalidOid, /* typmodin procedure - none */
1395 InvalidOid, /* typmodout procedure - none */
1396 InvalidOid, /* analyze procedure - default */
1397 typoid, /* element type ID */
1398 true, /* yes this is an array type */
1399 InvalidOid, /* no further array type */
1400 InvalidOid, /* base type ID */
1401 NULL, /* never a default type value */
1402 NULL, /* binary default isn't sent either */
1403 false, /* never passed by value */
1404 alignment, /* alignment - same as range's */
1405 'x', /* ARRAY is always toastable */
1406 -1, /* typMod (Domains only) */
1407 0, /* Array dimensions of typbasetype */
1408 false, /* Type NOT NULL */
1409 InvalidOid); /* typcollation */
1411 pfree(rangeArrayName);
1413 /* And create the constructor functions for this range type */
1414 makeRangeConstructor(typeName, typeNamespace, typoid, rangeSubtype);
1418 * Because there may exist several range types over one subtype, the range type
1419 * can't be determined from the subtype. This means that constructors can't be
1420 * polymorphic, and so we must generate a new constructor for every range type
1423 * We actually define 4 functions with 0 through 3 arguments. This is just to
1424 * offer more convenience for the user.
1427 makeRangeConstructor(char *name, Oid namespace, Oid rangeOid, Oid subtype)
1429 ObjectAddress referenced;
1430 Oid constructorArgTypes[3];
1433 referenced.classId = TypeRelationId;
1434 referenced.objectId = rangeOid;
1435 referenced.objectSubId = 0;
1437 constructorArgTypes[0] = subtype;
1438 constructorArgTypes[1] = subtype;
1439 constructorArgTypes[2] = TEXTOID;
1441 for (i = 0; i < 4; i++)
1443 oidvector *constructorArgTypesVector;
1444 ObjectAddress myself;
1446 char *prosrc[4] = {"range_constructor0",
1447 "range_constructor1",
1448 "range_constructor2",
1449 "range_constructor3"};
1451 constructorArgTypesVector = buildoidvector(constructorArgTypes, i);
1453 procOid = ProcedureCreate(
1455 namespace, /* namespace */
1456 false, /* replace */
1457 false, /* return set */
1458 rangeOid, /* return type */
1459 INTERNALlanguageId, /* language */
1460 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1461 prosrc[i], /* prosrc */
1465 false, /* security definer */
1467 PROVOLATILE_IMMUTABLE, /* volatility */
1468 constructorArgTypesVector, /* param types */
1469 PointerGetDatum(NULL), /* allParameterTypes */
1470 PointerGetDatum(NULL), /* parameterModes */
1471 PointerGetDatum(NULL), /* parameterNames */
1472 NIL, /* parameterDefaults */
1473 PointerGetDatum(NULL), /* proconfig */
1478 * Make the constructor internally-dependent on the range type so that
1479 * the user doesn't have to treat them as separate objects.
1481 myself.classId = ProcedureRelationId;
1482 myself.objectId = procOid;
1483 myself.objectSubId = 0;
1484 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1490 * Adds a new label to an existing enum.
1493 AlterEnum(AlterEnumStmt *stmt)
1499 /* Make a TypeName so we can use standard type lookup machinery */
1500 typename = makeTypeNameFromNameList(stmt->typeName);
1501 enum_type_oid = typenameTypeId(NULL, typename);
1503 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1504 if (!HeapTupleIsValid(tup))
1505 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1507 /* Check it's an enum and check user has permission to ALTER the enum */
1508 checkEnumOwner(tup);
1510 /* Add the new label */
1511 AddEnumLabel(enum_type_oid, stmt->newVal,
1512 stmt->newValNeighbor, stmt->newValIsAfter);
1514 ReleaseSysCache(tup);
1521 * Check that the type is actually an enum and that the current user
1522 * has permission to do ALTER TYPE on it. Throw an error if not.
1525 checkEnumOwner(HeapTuple tup)
1527 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1529 /* Check that this is actually an enum */
1530 if (typTup->typtype != TYPTYPE_ENUM)
1532 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1533 errmsg("%s is not an enum",
1534 format_type_be(HeapTupleGetOid(tup)))));
1536 /* Permission check: must own type */
1537 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1538 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
1539 format_type_be(HeapTupleGetOid(tup)));
1544 * Find suitable I/O functions for a type.
1546 * typeOid is the type's OID (which will already exist, if only as a shell
1551 findTypeInputFunction(List *procname, Oid typeOid)
1557 * Input functions can take a single argument of type CSTRING, or three
1558 * arguments (string, typioparam OID, typmod).
1560 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1561 * see this, we issue a warning and fix up the pg_proc entry.
1563 argList[0] = CSTRINGOID;
1565 procOid = LookupFuncName(procname, 1, argList, true);
1566 if (OidIsValid(procOid))
1569 argList[1] = OIDOID;
1570 argList[2] = INT4OID;
1572 procOid = LookupFuncName(procname, 3, argList, true);
1573 if (OidIsValid(procOid))
1576 /* No luck, try it with OPAQUE */
1577 argList[0] = OPAQUEOID;
1579 procOid = LookupFuncName(procname, 1, argList, true);
1581 if (!OidIsValid(procOid))
1583 argList[1] = OIDOID;
1584 argList[2] = INT4OID;
1586 procOid = LookupFuncName(procname, 3, argList, true);
1589 if (OidIsValid(procOid))
1591 /* Found, but must complain and fix the pg_proc entry */
1593 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1594 NameListToString(procname))));
1595 SetFunctionArgType(procOid, 0, CSTRINGOID);
1598 * Need CommandCounterIncrement since DefineType will likely try to
1599 * alter the pg_proc tuple again.
1601 CommandCounterIncrement();
1606 /* Use CSTRING (preferred) in the error message */
1607 argList[0] = CSTRINGOID;
1610 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1611 errmsg("function %s does not exist",
1612 func_signature_string(procname, 1, NIL, argList))));
1614 return InvalidOid; /* keep compiler quiet */
1618 findTypeOutputFunction(List *procname, Oid typeOid)
1624 * Output functions can take a single argument of the type.
1626 * For backwards compatibility we allow OPAQUE in place of the actual type
1627 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1629 argList[0] = typeOid;
1631 procOid = LookupFuncName(procname, 1, argList, true);
1632 if (OidIsValid(procOid))
1635 /* No luck, try it with OPAQUE */
1636 argList[0] = OPAQUEOID;
1638 procOid = LookupFuncName(procname, 1, argList, true);
1640 if (OidIsValid(procOid))
1642 /* Found, but must complain and fix the pg_proc entry */
1644 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1645 NameListToString(procname), format_type_be(typeOid))));
1646 SetFunctionArgType(procOid, 0, typeOid);
1649 * Need CommandCounterIncrement since DefineType will likely try to
1650 * alter the pg_proc tuple again.
1652 CommandCounterIncrement();
1657 /* Use type name, not OPAQUE, in the failure message. */
1658 argList[0] = typeOid;
1661 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1662 errmsg("function %s does not exist",
1663 func_signature_string(procname, 1, NIL, argList))));
1665 return InvalidOid; /* keep compiler quiet */
1669 findTypeReceiveFunction(List *procname, Oid typeOid)
1675 * Receive functions can take a single argument of type INTERNAL, or three
1676 * arguments (internal, typioparam OID, typmod).
1678 argList[0] = INTERNALOID;
1680 procOid = LookupFuncName(procname, 1, argList, true);
1681 if (OidIsValid(procOid))
1684 argList[1] = OIDOID;
1685 argList[2] = INT4OID;
1687 procOid = LookupFuncName(procname, 3, argList, true);
1688 if (OidIsValid(procOid))
1692 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1693 errmsg("function %s does not exist",
1694 func_signature_string(procname, 1, NIL, argList))));
1696 return InvalidOid; /* keep compiler quiet */
1700 findTypeSendFunction(List *procname, Oid typeOid)
1706 * Send functions can take a single argument of the type.
1708 argList[0] = typeOid;
1710 procOid = LookupFuncName(procname, 1, argList, true);
1711 if (OidIsValid(procOid))
1715 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1716 errmsg("function %s does not exist",
1717 func_signature_string(procname, 1, NIL, argList))));
1719 return InvalidOid; /* keep compiler quiet */
1723 findTypeTypmodinFunction(List *procname)
1729 * typmodin functions always take one cstring[] argument and return int4.
1731 argList[0] = CSTRINGARRAYOID;
1733 procOid = LookupFuncName(procname, 1, argList, true);
1734 if (!OidIsValid(procOid))
1736 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1737 errmsg("function %s does not exist",
1738 func_signature_string(procname, 1, NIL, argList))));
1740 if (get_func_rettype(procOid) != INT4OID)
1742 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1743 errmsg("typmod_in function %s must return type \"integer\"",
1744 NameListToString(procname))));
1750 findTypeTypmodoutFunction(List *procname)
1756 * typmodout functions always take one int4 argument and return cstring.
1758 argList[0] = INT4OID;
1760 procOid = LookupFuncName(procname, 1, argList, true);
1761 if (!OidIsValid(procOid))
1763 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1764 errmsg("function %s does not exist",
1765 func_signature_string(procname, 1, NIL, argList))));
1767 if (get_func_rettype(procOid) != CSTRINGOID)
1769 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1770 errmsg("typmod_out function %s must return type \"cstring\"",
1771 NameListToString(procname))));
1777 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1783 * Analyze functions always take one INTERNAL argument and return bool.
1785 argList[0] = INTERNALOID;
1787 procOid = LookupFuncName(procname, 1, argList, true);
1788 if (!OidIsValid(procOid))
1790 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1791 errmsg("function %s does not exist",
1792 func_signature_string(procname, 1, NIL, argList))));
1794 if (get_func_rettype(procOid) != BOOLOID)
1796 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1797 errmsg("type analyze function %s must return type \"boolean\"",
1798 NameListToString(procname))));
1804 * Find named btree opclass for subtype, or default btree opclass if
1805 * opcname is NIL. This will be used for comparing values of subtype.
1808 findRangeSubOpclass(List *opcname, Oid subtype)
1814 opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
1815 if (!OidIsValid(opcid))
1818 (errcode(ERRCODE_UNDEFINED_OBJECT),
1819 errmsg("data type %s has no default operator class for access method \"btree\"",
1820 format_type_be(subtype)),
1821 errhint("You must specify an operator class for the data type or define a default operator class for the data type.")));
1826 opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
1832 * Used to find a range's 'canonical' function.
1835 findRangeSubtypeDiffFunction(List *procname, Oid typeOid)
1840 argList[0] = typeOid;
1841 argList[1] = typeOid;
1843 procOid = LookupFuncName(procname, 2, argList, true);
1845 if (!OidIsValid(procOid))
1847 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1848 errmsg("function %s does not exist",
1849 func_signature_string(procname, 2, NIL, argList))));
1851 if (get_func_rettype(procOid) != FLOAT8OID)
1853 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1854 errmsg("range subtype diff function %s must return type \"float8\"",
1855 func_signature_string(procname, 2, NIL, argList))));
1857 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1859 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1860 errmsg("range subtype diff function %s must be immutable",
1861 func_signature_string(procname, 2, NIL, argList))));
1867 * Used to find a range's 'canonical' function.
1870 findRangeCanonicalFunction(List *procname, Oid typeOid)
1875 argList[0] = typeOid;
1877 procOid = LookupFuncName(procname, 1, argList, true);
1879 if (!OidIsValid(procOid))
1881 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1882 errmsg("function %s does not exist",
1883 func_signature_string(procname, 1, NIL, argList))));
1885 if (get_func_rettype(procOid) != typeOid)
1887 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1888 errmsg("range canonical function %s must return range type",
1889 NameListToString(procname))));
1891 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1893 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1894 errmsg("range canonical function %s must be immutable",
1895 func_signature_string(procname, 1, NIL, argList))));
1901 * AssignTypeArrayOid
1903 * Pre-assign the type's array OID for use in pg_type.typarray
1906 AssignTypeArrayOid(void)
1910 /* Use binary-upgrade override for pg_type.typarray, if supplied. */
1911 if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_array_pg_type_oid))
1913 type_array_oid = binary_upgrade_next_array_pg_type_oid;
1914 binary_upgrade_next_array_pg_type_oid = InvalidOid;
1918 Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
1920 type_array_oid = GetNewOid(pg_type);
1921 heap_close(pg_type, AccessShareLock);
1924 return type_array_oid;
1928 /*-------------------------------------------------------------------
1929 * DefineCompositeType
1931 * Create a Composite Type relation.
1932 * `DefineRelation' does all the work, we just provide the correct
1935 * If the relation already exists, then 'DefineRelation' will abort
1938 * DefineCompositeType returns relid for use when creating
1939 * an implicit composite type during function creation
1940 *-------------------------------------------------------------------
1943 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1945 CreateStmt *createStmt = makeNode(CreateStmt);
1951 * now set the parameters for keys/inheritance etc. All of these are
1952 * uninteresting for composite types...
1954 createStmt->relation = (RangeVar *) typevar;
1955 createStmt->tableElts = coldeflist;
1956 createStmt->inhRelations = NIL;
1957 createStmt->constraints = NIL;
1958 createStmt->options = list_make1(defWithOids(false));
1959 createStmt->oncommit = ONCOMMIT_NOOP;
1960 createStmt->tablespacename = NULL;
1961 createStmt->if_not_exists = false;
1964 * Check for collision with an existing type name. If there is one and
1965 * it's an autogenerated array, we can rename it out of the way. This
1966 * check is here mainly to get a better error message about a "type"
1967 * instead of below about a "relation".
1969 typeNamespace = RangeVarGetCreationNamespace(createStmt->relation);
1970 RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
1972 GetSysCacheOid2(TYPENAMENSP,
1973 CStringGetDatum(createStmt->relation->relname),
1974 ObjectIdGetDatum(typeNamespace));
1975 if (OidIsValid(old_type_oid))
1977 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
1979 (errcode(ERRCODE_DUPLICATE_OBJECT),
1980 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
1984 * Finally create the relation. This also creates the type.
1986 relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
1987 Assert(relid != InvalidOid);
1992 * AlterDomainDefault
1994 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
1997 AlterDomainDefault(List *names, Node *defaultRaw)
2005 Node *defaultExpr = NULL; /* NULL if no default specified */
2006 Datum new_record[Natts_pg_type];
2007 bool new_record_nulls[Natts_pg_type];
2008 bool new_record_repl[Natts_pg_type];
2010 Form_pg_type typTup;
2012 /* Make a TypeName so we can use standard type lookup machinery */
2013 typename = makeTypeNameFromNameList(names);
2014 domainoid = typenameTypeId(NULL, typename);
2016 /* Look up the domain in the type table */
2017 rel = heap_open(TypeRelationId, RowExclusiveLock);
2019 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2020 if (!HeapTupleIsValid(tup))
2021 elog(ERROR, "cache lookup failed for type %u", domainoid);
2022 typTup = (Form_pg_type) GETSTRUCT(tup);
2024 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2025 checkDomainOwner(tup);
2027 /* Setup new tuple */
2028 MemSet(new_record, (Datum) 0, sizeof(new_record));
2029 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2030 MemSet(new_record_repl, false, sizeof(new_record_repl));
2032 /* Store the new default into the tuple */
2035 /* Create a dummy ParseState for transformExpr */
2036 pstate = make_parsestate(NULL);
2039 * Cook the colDef->raw_expr into an expression. Note: Name is
2040 * strictly for error message
2042 defaultExpr = cookDefault(pstate, defaultRaw,
2043 typTup->typbasetype,
2045 NameStr(typTup->typname));
2048 * If the expression is just a NULL constant, we treat the command
2049 * like ALTER ... DROP DEFAULT. (But see note for same test in
2052 if (defaultExpr == NULL ||
2053 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
2055 /* Default is NULL, drop it */
2056 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2057 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2058 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2059 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2064 * Expression must be stored as a nodeToString result, but we also
2065 * require a valid textual representation (mainly to make life
2066 * easier for pg_dump).
2068 defaultValue = deparse_expression(defaultExpr,
2069 deparse_context_for(NameStr(typTup->typname),
2074 * Form an updated tuple with the new default and write it back.
2076 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2078 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2079 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2080 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2085 /* ALTER ... DROP DEFAULT */
2086 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2087 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2088 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2089 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2092 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2093 new_record, new_record_nulls,
2096 simple_heap_update(rel, &tup->t_self, newtuple);
2098 CatalogUpdateIndexes(rel, newtuple);
2100 /* Rebuild dependencies */
2101 GenerateTypeDependencies(typTup->typnamespace,
2103 InvalidOid, /* typrelid is n/a */
2104 0, /* relation kind is n/a */
2114 false, /* a domain isn't an implicit array */
2115 typTup->typbasetype,
2116 typTup->typcollation,
2118 true); /* Rebuild is true */
2121 heap_close(rel, NoLock);
2122 heap_freetuple(newtuple);
2126 * AlterDomainNotNull
2128 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2131 AlterDomainNotNull(List *names, bool notNull)
2137 Form_pg_type typTup;
2139 /* Make a TypeName so we can use standard type lookup machinery */
2140 typename = makeTypeNameFromNameList(names);
2141 domainoid = typenameTypeId(NULL, typename);
2143 /* Look up the domain in the type table */
2144 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2146 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2147 if (!HeapTupleIsValid(tup))
2148 elog(ERROR, "cache lookup failed for type %u", domainoid);
2149 typTup = (Form_pg_type) GETSTRUCT(tup);
2151 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2152 checkDomainOwner(tup);
2154 /* Is the domain already set to the desired constraint? */
2155 if (typTup->typnotnull == notNull)
2157 heap_close(typrel, RowExclusiveLock);
2161 /* Adding a NOT NULL constraint requires checking existing columns */
2167 /* Fetch relation list with attributes based on this domain */
2168 /* ShareLock is sufficient to prevent concurrent data changes */
2170 rels = get_rels_with_domain(domainoid, ShareLock);
2174 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2175 Relation testrel = rtc->rel;
2176 TupleDesc tupdesc = RelationGetDescr(testrel);
2180 /* Scan all tuples in this relation */
2181 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2182 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2186 /* Test attributes that are of the domain */
2187 for (i = 0; i < rtc->natts; i++)
2189 int attnum = rtc->atts[i];
2191 if (heap_attisnull(tuple, attnum))
2193 (errcode(ERRCODE_NOT_NULL_VIOLATION),
2194 errmsg("column \"%s\" of table \"%s\" contains null values",
2195 NameStr(tupdesc->attrs[attnum - 1]->attname),
2196 RelationGetRelationName(testrel))));
2201 /* Close each rel after processing, but keep lock */
2202 heap_close(testrel, NoLock);
2207 * Okay to update pg_type row. We can scribble on typTup because it's a
2210 typTup->typnotnull = notNull;
2212 simple_heap_update(typrel, &tup->t_self, tup);
2214 CatalogUpdateIndexes(typrel, tup);
2217 heap_freetuple(tup);
2218 heap_close(typrel, RowExclusiveLock);
2222 * AlterDomainDropConstraint
2224 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2227 AlterDomainDropConstraint(List *names, const char *constrName,
2228 DropBehavior behavior)
2235 SysScanDesc conscan;
2239 /* Make a TypeName so we can use standard type lookup machinery */
2240 typename = makeTypeNameFromNameList(names);
2241 domainoid = typenameTypeId(NULL, typename);
2243 /* Look up the domain in the type table */
2244 rel = heap_open(TypeRelationId, RowExclusiveLock);
2246 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2247 if (!HeapTupleIsValid(tup))
2248 elog(ERROR, "cache lookup failed for type %u", domainoid);
2250 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2251 checkDomainOwner(tup);
2253 /* Grab an appropriate lock on the pg_constraint relation */
2254 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2256 /* Use the index to scan only constraints of the target relation */
2257 ScanKeyInit(&key[0],
2258 Anum_pg_constraint_contypid,
2259 BTEqualStrategyNumber, F_OIDEQ,
2260 ObjectIdGetDatum(HeapTupleGetOid(tup)));
2262 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2263 SnapshotNow, 1, key);
2266 * Scan over the result set, removing any matching entries.
2268 while ((contup = systable_getnext(conscan)) != NULL)
2270 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
2272 if (strcmp(NameStr(con->conname), constrName) == 0)
2274 ObjectAddress conobj;
2276 conobj.classId = ConstraintRelationId;
2277 conobj.objectId = HeapTupleGetOid(contup);
2278 conobj.objectSubId = 0;
2280 performDeletion(&conobj, behavior);
2283 /* Clean up after the scan */
2284 systable_endscan(conscan);
2285 heap_close(conrel, RowExclusiveLock);
2287 heap_close(rel, NoLock);
2291 * AlterDomainAddConstraint
2293 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2296 AlterDomainAddConstraint(List *names, Node *newConstraint)
2302 Form_pg_type typTup;
2306 /* Make a TypeName so we can use standard type lookup machinery */
2307 typename = makeTypeNameFromNameList(names);
2308 domainoid = typenameTypeId(NULL, typename);
2310 /* Look up the domain in the type table */
2311 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2313 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2314 if (!HeapTupleIsValid(tup))
2315 elog(ERROR, "cache lookup failed for type %u", domainoid);
2316 typTup = (Form_pg_type) GETSTRUCT(tup);
2318 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2319 checkDomainOwner(tup);
2321 if (!IsA(newConstraint, Constraint))
2322 elog(ERROR, "unrecognized node type: %d",
2323 (int) nodeTag(newConstraint));
2325 constr = (Constraint *) newConstraint;
2327 switch (constr->contype)
2330 /* processed below */
2335 (errcode(ERRCODE_SYNTAX_ERROR),
2336 errmsg("unique constraints not possible for domains")));
2339 case CONSTR_PRIMARY:
2341 (errcode(ERRCODE_SYNTAX_ERROR),
2342 errmsg("primary key constraints not possible for domains")));
2345 case CONSTR_EXCLUSION:
2347 (errcode(ERRCODE_SYNTAX_ERROR),
2348 errmsg("exclusion constraints not possible for domains")));
2351 case CONSTR_FOREIGN:
2353 (errcode(ERRCODE_SYNTAX_ERROR),
2354 errmsg("foreign key constraints not possible for domains")));
2357 case CONSTR_ATTR_DEFERRABLE:
2358 case CONSTR_ATTR_NOT_DEFERRABLE:
2359 case CONSTR_ATTR_DEFERRED:
2360 case CONSTR_ATTR_IMMEDIATE:
2362 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2363 errmsg("specifying constraint deferrability not supported for domains")));
2367 elog(ERROR, "unrecognized constraint subtype: %d",
2368 (int) constr->contype);
2373 * Since all other constraint types throw errors, this must be a check
2374 * constraint. First, process the constraint expression and add an entry
2378 ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
2379 typTup->typbasetype, typTup->typtypmod,
2380 constr, NameStr(typTup->typname));
2383 * If requested to validate the constraint, test all values stored in the
2384 * attributes based on the domain the constraint is being added to.
2386 if (!constr->skip_validation)
2387 validateDomainConstraint(domainoid, ccbin);
2390 heap_close(typrel, RowExclusiveLock);
2394 * AlterDomainValidateConstraint
2396 * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
2399 AlterDomainValidateConstraint(List *names, char *constrName)
2406 Form_pg_constraint con = NULL;
2407 Form_pg_constraint copy_con;
2414 HeapTuple copyTuple;
2417 /* Make a TypeName so we can use standard type lookup machinery */
2418 typename = makeTypeNameFromNameList(names);
2419 domainoid = typenameTypeId(NULL, typename);
2421 /* Look up the domain in the type table */
2422 typrel = heap_open(TypeRelationId, AccessShareLock);
2424 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2425 if (!HeapTupleIsValid(tup))
2426 elog(ERROR, "cache lookup failed for type %u", domainoid);
2428 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2429 checkDomainOwner(tup);
2432 * Find and check the target constraint
2434 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2436 Anum_pg_constraint_contypid,
2437 BTEqualStrategyNumber, F_OIDEQ,
2438 ObjectIdGetDatum(domainoid));
2439 scan = systable_beginscan(conrel, ConstraintTypidIndexId,
2440 true, SnapshotNow, 1, &key);
2442 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2444 con = (Form_pg_constraint) GETSTRUCT(tuple);
2445 if (strcmp(NameStr(con->conname), constrName) == 0)
2454 (errcode(ERRCODE_UNDEFINED_OBJECT),
2455 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2456 constrName, TypeNameToString(typename))));
2458 if (con->contype != CONSTRAINT_CHECK)
2460 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2461 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2462 constrName, TypeNameToString(typename))));
2464 val = SysCacheGetAttr(CONSTROID, tuple,
2465 Anum_pg_constraint_conbin,
2468 elog(ERROR, "null conbin for constraint %u",
2469 HeapTupleGetOid(tuple));
2470 conbin = TextDatumGetCString(val);
2472 validateDomainConstraint(domainoid, conbin);
2475 * Now update the catalog, while we have the door open.
2477 copyTuple = heap_copytuple(tuple);
2478 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2479 copy_con->convalidated = true;
2480 simple_heap_update(conrel, ©Tuple->t_self, copyTuple);
2481 CatalogUpdateIndexes(conrel, copyTuple);
2482 heap_freetuple(copyTuple);
2484 systable_endscan(scan);
2486 heap_close(typrel, AccessShareLock);
2487 heap_close(conrel, RowExclusiveLock);
2489 ReleaseSysCache(tup);
2493 validateDomainConstraint(Oid domainoid, char *ccbin)
2495 Expr *expr = (Expr *) stringToNode(ccbin);
2499 ExprContext *econtext;
2500 ExprState *exprstate;
2502 /* Need an EState to run ExecEvalExpr */
2503 estate = CreateExecutorState();
2504 econtext = GetPerTupleExprContext(estate);
2506 /* build execution state for expr */
2507 exprstate = ExecPrepareExpr(expr, estate);
2509 /* Fetch relation list with attributes based on this domain */
2510 /* ShareLock is sufficient to prevent concurrent data changes */
2512 rels = get_rels_with_domain(domainoid, ShareLock);
2516 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2517 Relation testrel = rtc->rel;
2518 TupleDesc tupdesc = RelationGetDescr(testrel);
2522 /* Scan all tuples in this relation */
2523 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2524 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2528 /* Test attributes that are of the domain */
2529 for (i = 0; i < rtc->natts; i++)
2531 int attnum = rtc->atts[i];
2536 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2538 econtext->domainValue_datum = d;
2539 econtext->domainValue_isNull = isNull;
2541 conResult = ExecEvalExprSwitchContext(exprstate,
2545 if (!isNull && !DatumGetBool(conResult))
2547 (errcode(ERRCODE_CHECK_VIOLATION),
2548 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2549 NameStr(tupdesc->attrs[attnum - 1]->attname),
2550 RelationGetRelationName(testrel))));
2553 ResetExprContext(econtext);
2557 /* Hold relation lock till commit (XXX bad for concurrency) */
2558 heap_close(testrel, NoLock);
2561 FreeExecutorState(estate);
2565 * get_rels_with_domain
2567 * Fetch all relations / attributes which are using the domain
2569 * The result is a list of RelToCheck structs, one for each distinct
2570 * relation, each containing one or more attribute numbers that are of
2571 * the domain type. We have opened each rel and acquired the specified lock
2574 * We support nested domains by including attributes that are of derived
2575 * domain types. Current callers do not need to distinguish between attributes
2576 * that are of exactly the given domain and those that are of derived domains.
2578 * XXX this is completely broken because there is no way to lock the domain
2579 * to prevent columns from being added or dropped while our command runs.
2580 * We can partially protect against column drops by locking relations as we
2581 * come across them, but there is still a race condition (the window between
2582 * seeing a pg_depend entry and acquiring lock on the relation it references).
2583 * Also, holding locks on all these relations simultaneously creates a non-
2584 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2585 * risk by using the weakest suitable lock (ShareLock for most callers).
2587 * XXX the API for this is not sufficient to support checking domain values
2588 * that are inside composite types or arrays. Currently we just error out
2589 * if a composite type containing the target domain is stored anywhere.
2590 * There are not currently arrays of domains; if there were, we could take
2591 * the same approach, but it'd be nicer to fix it properly.
2593 * Generally used for retrieving a list of tests when adding
2594 * new constraints to a domain.
2597 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2602 SysScanDesc depScan;
2605 Assert(lockmode != NoLock);
2608 * We scan pg_depend to find those things that depend on the domain. (We
2609 * assume we can ignore refobjsubid for a domain.)
2611 depRel = heap_open(DependRelationId, AccessShareLock);
2613 ScanKeyInit(&key[0],
2614 Anum_pg_depend_refclassid,
2615 BTEqualStrategyNumber, F_OIDEQ,
2616 ObjectIdGetDatum(TypeRelationId));
2617 ScanKeyInit(&key[1],
2618 Anum_pg_depend_refobjid,
2619 BTEqualStrategyNumber, F_OIDEQ,
2620 ObjectIdGetDatum(domainOid));
2622 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2623 SnapshotNow, 2, key);
2625 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2627 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2628 RelToCheck *rtc = NULL;
2630 Form_pg_attribute pg_att;
2633 /* Check for directly dependent types --- must be domains */
2634 if (pg_depend->classid == TypeRelationId)
2636 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2639 * Recursively add dependent columns to the output list. This is
2640 * a bit inefficient since we may fail to combine RelToCheck
2641 * entries when attributes of the same rel have different derived
2642 * domain types, but it's probably not worth improving.
2644 result = list_concat(result,
2645 get_rels_with_domain(pg_depend->objid,
2650 /* Else, ignore dependees that aren't user columns of relations */
2651 /* (we assume system columns are never of domain types) */
2652 if (pg_depend->classid != RelationRelationId ||
2653 pg_depend->objsubid <= 0)
2656 /* See if we already have an entry for this relation */
2657 foreach(rellist, result)
2659 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2661 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2670 /* First attribute found for this relation */
2673 /* Acquire requested lock on relation */
2674 rel = relation_open(pg_depend->objid, lockmode);
2677 * Check to see if rowtype is stored anyplace as a composite-type
2678 * column; if so we have to fail, for now anyway.
2680 if (OidIsValid(rel->rd_rel->reltype))
2681 find_composite_type_dependencies(rel->rd_rel->reltype,
2683 format_type_be(domainOid));
2685 /* Otherwise we can ignore views, composite types, etc */
2686 if (rel->rd_rel->relkind != RELKIND_RELATION)
2688 relation_close(rel, lockmode);
2692 /* Build the RelToCheck entry with enough space for all atts */
2693 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2696 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2697 result = lcons(rtc, result);
2701 * Confirm column has not been dropped, and is of the expected type.
2702 * This defends against an ALTER DROP COLUMN occuring just before we
2703 * acquired lock ... but if the whole table were dropped, we'd still
2706 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2708 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2709 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2713 * Okay, add column to result. We store the columns in column-number
2714 * order; this is just a hack to improve predictability of regression
2717 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2720 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2722 rtc->atts[ptr] = rtc->atts[ptr - 1];
2725 rtc->atts[ptr] = pg_depend->objsubid;
2728 systable_endscan(depScan);
2730 relation_close(depRel, AccessShareLock);
2738 * Check that the type is actually a domain and that the current user
2739 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2742 checkDomainOwner(HeapTuple tup)
2744 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2746 /* Check that this is actually a domain */
2747 if (typTup->typtype != TYPTYPE_DOMAIN)
2749 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2750 errmsg("%s is not a domain",
2751 format_type_be(HeapTupleGetOid(tup)))));
2753 /* Permission check: must own type */
2754 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2755 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2756 format_type_be(HeapTupleGetOid(tup)));
2760 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2763 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2764 int typMod, Constraint *constr,
2771 CoerceToDomainValue *domVal;
2774 * Assign or validate constraint name
2776 if (constr->conname)
2778 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2783 (errcode(ERRCODE_DUPLICATE_OBJECT),
2784 errmsg("constraint \"%s\" for domain \"%s\" already exists",
2785 constr->conname, domainName)));
2788 constr->conname = ChooseConstraintName(domainName,
2795 * Convert the A_EXPR in raw_expr into an EXPR
2797 pstate = make_parsestate(NULL);
2800 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2801 * the expression. Note that it will appear to have the type of the base
2802 * type, not the domain. This seems correct since within the check
2803 * expression, we should not assume the input value can be considered a
2804 * member of the domain.
2806 domVal = makeNode(CoerceToDomainValue);
2807 domVal->typeId = baseTypeOid;
2808 domVal->typeMod = typMod;
2809 domVal->collation = get_typcollation(baseTypeOid);
2810 domVal->location = -1; /* will be set when/if used */
2812 pstate->p_value_substitute = (Node *) domVal;
2814 expr = transformExpr(pstate, constr->raw_expr);
2817 * Make sure it yields a boolean result.
2819 expr = coerce_to_boolean(pstate, expr, "CHECK");
2822 * Fix up collation information.
2824 assign_expr_collations(pstate, expr);
2827 * Make sure no outside relations are referred to.
2829 if (list_length(pstate->p_rtable) != 0)
2831 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2832 errmsg("cannot use table references in domain check constraint")));
2835 * Domains don't allow var clauses (this should be redundant with the
2836 * above check, but make it anyway)
2838 if (contain_var_clause(expr))
2840 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2841 errmsg("cannot use table references in domain check constraint")));
2844 * No subplans or aggregates, either...
2846 if (pstate->p_hasSubLinks)
2848 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2849 errmsg("cannot use subquery in check constraint")));
2850 if (pstate->p_hasAggs)
2852 (errcode(ERRCODE_GROUPING_ERROR),
2853 errmsg("cannot use aggregate function in check constraint")));
2854 if (pstate->p_hasWindowFuncs)
2856 (errcode(ERRCODE_WINDOWING_ERROR),
2857 errmsg("cannot use window function in check constraint")));
2860 * Convert to string form for storage.
2862 ccbin = nodeToString(expr);
2865 * Deparse it to produce text for consrc.
2867 * Since VARNOs aren't allowed in domain constraints, relation context
2868 * isn't required as anything other than a shell.
2870 ccsrc = deparse_expression(expr,
2871 deparse_context_for(domainName,
2876 * Store the constraint in pg_constraint
2878 CreateConstraintEntry(constr->conname, /* Constraint Name */
2879 domainNamespace, /* namespace */
2880 CONSTRAINT_CHECK, /* Constraint Type */
2881 false, /* Is Deferrable */
2882 false, /* Is Deferred */
2883 !constr->skip_validation, /* Is Validated */
2884 InvalidOid, /* not a relation constraint */
2887 domainOid, /* domain constraint */
2888 InvalidOid, /* no associated index */
2889 InvalidOid, /* Foreign key fields */
2898 NULL, /* not an exclusion constraint */
2899 expr, /* Tree form of check constraint */
2900 ccbin, /* Binary form of check constraint */
2901 ccsrc, /* Source form of check constraint */
2902 true, /* is local */
2906 * Return the compiled constraint expression so the calling routine can
2907 * perform any additional required tests.
2913 * GetDomainConstraints - get a list of the current constraints of domain
2915 * Returns a possibly-empty list of DomainConstraintState nodes.
2917 * This is called by the executor during plan startup for a CoerceToDomain
2918 * expression node. The given constraints will be checked for each value
2919 * passed through the node.
2921 * We allow this to be called for non-domain types, in which case the result
2925 GetDomainConstraints(Oid typeOid)
2928 bool notNull = false;
2931 conRel = heap_open(ConstraintRelationId, AccessShareLock);
2937 Form_pg_type typTup;
2941 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
2942 if (!HeapTupleIsValid(tup))
2943 elog(ERROR, "cache lookup failed for type %u", typeOid);
2944 typTup = (Form_pg_type) GETSTRUCT(tup);
2946 if (typTup->typtype != TYPTYPE_DOMAIN)
2948 /* Not a domain, so done */
2949 ReleaseSysCache(tup);
2953 /* Test for NOT NULL Constraint */
2954 if (typTup->typnotnull)
2957 /* Look for CHECK Constraints on this domain */
2958 ScanKeyInit(&key[0],
2959 Anum_pg_constraint_contypid,
2960 BTEqualStrategyNumber, F_OIDEQ,
2961 ObjectIdGetDatum(typeOid));
2963 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
2964 SnapshotNow, 1, key);
2966 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
2968 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
2972 DomainConstraintState *r;
2974 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
2975 if (c->contype != CONSTRAINT_CHECK)
2979 * Not expecting conbin to be NULL, but we'll test for it anyway
2981 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
2982 conRel->rd_att, &isNull);
2984 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
2985 NameStr(typTup->typname), NameStr(c->conname));
2987 check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
2989 /* ExecInitExpr assumes we've planned the expression */
2990 check_expr = expression_planner(check_expr);
2992 r = makeNode(DomainConstraintState);
2993 r->constrainttype = DOM_CONSTRAINT_CHECK;
2994 r->name = pstrdup(NameStr(c->conname));
2995 r->check_expr = ExecInitExpr(check_expr, NULL);
2998 * use lcons() here because constraints of lower domains should be
3001 result = lcons(r, result);
3004 systable_endscan(scan);
3006 /* loop to next domain in stack */
3007 typeOid = typTup->typbasetype;
3008 ReleaseSysCache(tup);
3011 heap_close(conRel, AccessShareLock);
3014 * Only need to add one NOT NULL check regardless of how many domains in
3015 * the stack request it.
3019 DomainConstraintState *r = makeNode(DomainConstraintState);
3021 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
3022 r->name = pstrdup("NOT NULL");
3023 r->check_expr = NULL;
3025 /* lcons to apply the nullness check FIRST */
3026 result = lcons(r, result);
3034 * Execute ALTER TYPE RENAME
3037 RenameType(List *names, const char *newTypeName)
3043 Form_pg_type typTup;
3045 /* Make a TypeName so we can use standard type lookup machinery */
3046 typename = makeTypeNameFromNameList(names);
3047 typeOid = typenameTypeId(NULL, typename);
3049 /* Look up the type in the type table */
3050 rel = heap_open(TypeRelationId, RowExclusiveLock);
3052 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3053 if (!HeapTupleIsValid(tup))
3054 elog(ERROR, "cache lookup failed for type %u", typeOid);
3055 typTup = (Form_pg_type) GETSTRUCT(tup);
3057 /* check permissions on type */
3058 if (!pg_type_ownercheck(typeOid, GetUserId()))
3059 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
3060 format_type_be(typeOid));
3063 * If it's a composite type, we need to check that it really is a
3064 * free-standing composite type, and not a table's rowtype. We want people
3065 * to use ALTER TABLE not ALTER TYPE for that case.
3067 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3068 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3070 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3071 errmsg("%s is a table's row type",
3072 format_type_be(typeOid)),
3073 errhint("Use ALTER TABLE instead.")));
3075 /* don't allow direct alteration of array types, either */
3076 if (OidIsValid(typTup->typelem) &&
3077 get_array_type(typTup->typelem) == typeOid)
3079 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3080 errmsg("cannot alter array type %s",
3081 format_type_be(typeOid)),
3082 errhint("You can alter type %s, which will alter the array type as well.",
3083 format_type_be(typTup->typelem))));
3086 * If type is composite we need to rename associated pg_class entry too.
3087 * RenameRelationInternal will call RenameTypeInternal automatically.
3089 if (typTup->typtype == TYPTYPE_COMPOSITE)
3090 RenameRelationInternal(typTup->typrelid, newTypeName,
3091 typTup->typnamespace);
3093 RenameTypeInternal(typeOid, newTypeName,
3094 typTup->typnamespace);
3097 heap_close(rel, RowExclusiveLock);
3101 * Change the owner of a type.
3104 AlterTypeOwner(List *names, Oid newOwnerId)
3111 Form_pg_type typTup;
3112 AclResult aclresult;
3114 rel = heap_open(TypeRelationId, RowExclusiveLock);
3116 /* Make a TypeName so we can use standard type lookup machinery */
3117 typename = makeTypeNameFromNameList(names);
3119 /* Use LookupTypeName here so that shell types can be processed */
3120 tup = LookupTypeName(NULL, typename, NULL);
3123 (errcode(ERRCODE_UNDEFINED_OBJECT),
3124 errmsg("type \"%s\" does not exist",
3125 TypeNameToString(typename))));
3126 typeOid = typeTypeId(tup);
3128 /* Copy the syscache entry so we can scribble on it below */
3129 newtup = heap_copytuple(tup);
3130 ReleaseSysCache(tup);
3132 typTup = (Form_pg_type) GETSTRUCT(tup);
3135 * If it's a composite type, we need to check that it really is a
3136 * free-standing composite type, and not a table's rowtype. We want people
3137 * to use ALTER TABLE not ALTER TYPE for that case.
3139 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3140 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3142 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3143 errmsg("%s is a table's row type",
3144 format_type_be(typeOid)),
3145 errhint("Use ALTER TABLE instead.")));
3147 /* don't allow direct alteration of array types, either */
3148 if (OidIsValid(typTup->typelem) &&
3149 get_array_type(typTup->typelem) == typeOid)
3151 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3152 errmsg("cannot alter array type %s",
3153 format_type_be(typeOid)),
3154 errhint("You can alter type %s, which will alter the array type as well.",
3155 format_type_be(typTup->typelem))));
3158 * If the new owner is the same as the existing owner, consider the
3159 * command to have succeeded. This is for dump restoration purposes.
3161 if (typTup->typowner != newOwnerId)
3163 /* Superusers can always do it */
3166 /* Otherwise, must be owner of the existing object */
3167 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
3168 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
3169 format_type_be(HeapTupleGetOid(tup)));
3171 /* Must be able to become new owner */
3172 check_is_member_of_role(GetUserId(), newOwnerId);
3174 /* New owner must have CREATE privilege on namespace */
3175 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3178 if (aclresult != ACLCHECK_OK)
3179 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
3180 get_namespace_name(typTup->typnamespace));
3184 * If it's a composite type, invoke ATExecChangeOwner so that we fix
3185 * up the pg_class entry properly. That will call back to
3186 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3188 if (typTup->typtype == TYPTYPE_COMPOSITE)
3189 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3193 * We can just apply the modification directly.
3195 * okay to scribble on typTup because it's a copy
3197 typTup->typowner = newOwnerId;
3199 simple_heap_update(rel, &tup->t_self, tup);
3201 CatalogUpdateIndexes(rel, tup);
3203 /* Update owner dependency reference */
3204 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3206 /* If it has an array type, update that too */
3207 if (OidIsValid(typTup->typarray))
3208 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3213 heap_close(rel, RowExclusiveLock);
3217 * AlterTypeOwnerInternal - change type owner unconditionally
3219 * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
3220 * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
3221 * It assumes the caller has done all needed checks. The function will
3222 * automatically recurse to an array type if the type has one.
3224 * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
3225 * entry (ie, it's not a table rowtype nor an array type).
3228 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
3229 bool hasDependEntry)
3233 Form_pg_type typTup;
3235 rel = heap_open(TypeRelationId, RowExclusiveLock);
3237 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3238 if (!HeapTupleIsValid(tup))
3239 elog(ERROR, "cache lookup failed for type %u", typeOid);
3240 typTup = (Form_pg_type) GETSTRUCT(tup);
3243 * Modify the owner --- okay to scribble on typTup because it's a copy
3245 typTup->typowner = newOwnerId;
3247 simple_heap_update(rel, &tup->t_self, tup);
3249 CatalogUpdateIndexes(rel, tup);
3251 /* Update owner dependency reference, if it has one */
3253 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3255 /* If it has an array type, update that too */
3256 if (OidIsValid(typTup->typarray))
3257 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3260 heap_close(rel, RowExclusiveLock);
3264 * Execute ALTER TYPE SET SCHEMA
3267 AlterTypeNamespace(List *names, const char *newschema)
3273 /* Make a TypeName so we can use standard type lookup machinery */
3274 typename = makeTypeNameFromNameList(names);
3275 typeOid = typenameTypeId(NULL, typename);
3277 /* get schema OID and check its permissions */
3278 nspOid = LookupCreationNamespace(newschema);
3280 AlterTypeNamespace_oid(typeOid, nspOid);
3284 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid)
3288 /* check permissions on type */
3289 if (!pg_type_ownercheck(typeOid, GetUserId()))
3290 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
3291 format_type_be(typeOid));
3293 /* don't allow direct alteration of array types */
3294 elemOid = get_element_type(typeOid);
3295 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3297 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3298 errmsg("cannot alter array type %s",
3299 format_type_be(typeOid)),
3300 errhint("You can alter type %s, which will alter the array type as well.",
3301 format_type_be(elemOid))));
3303 /* and do the work */
3304 return AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
3308 * Move specified type to new namespace.
3310 * Caller must have already checked privileges.
3312 * The function automatically recurses to process the type's array type,
3313 * if any. isImplicitArray should be TRUE only when doing this internal
3314 * recursion (outside callers must never try to move an array type directly).
3316 * If errorOnTableType is TRUE, the function errors out if the type is
3317 * a table type. ALTER TABLE has to be used to move a table to a new
3320 * Returns the type's old namespace OID.
3323 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
3324 bool isImplicitArray,
3325 bool errorOnTableType)
3329 Form_pg_type typform;
3332 bool isCompositeType;
3334 rel = heap_open(TypeRelationId, RowExclusiveLock);
3336 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3337 if (!HeapTupleIsValid(tup))
3338 elog(ERROR, "cache lookup failed for type %u", typeOid);
3339 typform = (Form_pg_type) GETSTRUCT(tup);
3341 oldNspOid = typform->typnamespace;
3342 arrayOid = typform->typarray;
3344 /* common checks on switching namespaces */
3345 CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
3347 /* check for duplicate name (more friendly than unique-index failure) */
3348 if (SearchSysCacheExists2(TYPENAMENSP,
3349 CStringGetDatum(NameStr(typform->typname)),
3350 ObjectIdGetDatum(nspOid)))
3352 (errcode(ERRCODE_DUPLICATE_OBJECT),
3353 errmsg("type \"%s\" already exists in schema \"%s\"",
3354 NameStr(typform->typname),
3355 get_namespace_name(nspOid))));
3357 /* Detect whether type is a composite type (but not a table rowtype) */
3359 (typform->typtype == TYPTYPE_COMPOSITE &&
3360 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3362 /* Enforce not-table-type if requested */
3363 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3366 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3367 errmsg("%s is a table's row type",
3368 format_type_be(typeOid)),
3369 errhint("Use ALTER TABLE instead.")));
3371 /* OK, modify the pg_type row */
3373 /* tup is a copy, so we can scribble directly on it */
3374 typform->typnamespace = nspOid;
3376 simple_heap_update(rel, &tup->t_self, tup);
3377 CatalogUpdateIndexes(rel, tup);
3380 * Composite types have pg_class entries.
3382 * We need to modify the pg_class tuple as well to reflect the change of
3385 if (isCompositeType)
3389 classRel = heap_open(RelationRelationId, RowExclusiveLock);
3391 AlterRelationNamespaceInternal(classRel, typform->typrelid,
3395 heap_close(classRel, RowExclusiveLock);
3398 * Check for constraints associated with the composite type (we don't
3399 * currently support this, but probably will someday).
3401 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3406 /* If it's a domain, it might have constraints */
3407 if (typform->typtype == TYPTYPE_DOMAIN)
3408 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
3412 * Update dependency on schema, if any --- a table rowtype has not got
3413 * one, and neither does an implicit array.
3415 if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3417 if (changeDependencyFor(TypeRelationId, typeOid,
3418 NamespaceRelationId, oldNspOid, nspOid) != 1)
3419 elog(ERROR, "failed to change schema dependency for type %s",
3420 format_type_be(typeOid));
3422 heap_freetuple(tup);
3424 heap_close(rel, RowExclusiveLock);
3426 /* Recursively alter the associated array type, if any */
3427 if (OidIsValid(arrayOid))
3428 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);