1 /*-------------------------------------------------------------------------
4 * Routines for SQL commands that manipulate types (and domains).
6 * Portions Copyright (c) 1996-2013, 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/catalog.h"
39 #include "catalog/dependency.h"
40 #include "catalog/heap.h"
41 #include "catalog/indexing.h"
42 #include "catalog/pg_authid.h"
43 #include "catalog/pg_collation.h"
44 #include "catalog/pg_constraint.h"
45 #include "catalog/pg_depend.h"
46 #include "catalog/pg_enum.h"
47 #include "catalog/pg_language.h"
48 #include "catalog/pg_namespace.h"
49 #include "catalog/pg_proc.h"
50 #include "catalog/pg_proc_fn.h"
51 #include "catalog/pg_range.h"
52 #include "catalog/pg_type.h"
53 #include "catalog/pg_type_fn.h"
54 #include "commands/defrem.h"
55 #include "commands/tablecmds.h"
56 #include "commands/typecmds.h"
57 #include "executor/executor.h"
58 #include "miscadmin.h"
59 #include "nodes/makefuncs.h"
60 #include "optimizer/planner.h"
61 #include "optimizer/var.h"
62 #include "parser/parse_coerce.h"
63 #include "parser/parse_collate.h"
64 #include "parser/parse_expr.h"
65 #include "parser/parse_func.h"
66 #include "parser/parse_type.h"
67 #include "utils/acl.h"
68 #include "utils/builtins.h"
69 #include "utils/fmgroids.h"
70 #include "utils/lsyscache.h"
71 #include "utils/memutils.h"
72 #include "utils/rel.h"
73 #include "utils/syscache.h"
74 #include "utils/tqual.h"
77 /* result structure for get_rels_with_domain() */
80 Relation rel; /* opened and locked relation */
81 int natts; /* number of attributes of interest */
82 int *atts; /* attribute numbers */
83 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
86 /* Potentially set by contrib/pg_upgrade_support functions */
87 Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
89 static void makeRangeConstructors(const char *name, Oid namespace,
90 Oid rangeOid, Oid subtype);
91 static Oid findTypeInputFunction(List *procname, Oid typeOid);
92 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
93 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
94 static Oid findTypeSendFunction(List *procname, Oid typeOid);
95 static Oid findTypeTypmodinFunction(List *procname);
96 static Oid findTypeTypmodoutFunction(List *procname);
97 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
98 static Oid findRangeSubOpclass(List *opcname, Oid subtype);
99 static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
100 static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
101 static void validateDomainConstraint(Oid domainoid, char *ccbin);
102 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
103 static void checkEnumOwner(HeapTuple tup);
104 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
106 int typMod, Constraint *constr,
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 typoid = 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 F_ARRAY_TYPANALYZE, /* analyze procedure */
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 */
634 * Guts of type deletion.
637 RemoveTypeById(Oid typeOid)
642 relation = heap_open(TypeRelationId, RowExclusiveLock);
644 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
645 if (!HeapTupleIsValid(tup))
646 elog(ERROR, "cache lookup failed for type %u", typeOid);
648 simple_heap_delete(relation, &tup->t_self);
651 * If it is an enum, delete the pg_enum entries too; we don't bother with
652 * making dependency entries for those, so it has to be done "by hand"
655 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
656 EnumValuesDelete(typeOid);
659 * If it is a range type, delete the pg_range entry too; we don't bother
660 * with making a dependency entry for that, so it has to be done "by hand"
663 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
664 RangeDelete(typeOid);
666 ReleaseSysCache(tup);
668 heap_close(relation, RowExclusiveLock);
674 * Registers a new domain.
677 DefineDomain(CreateDomainStmt *stmt)
682 int16 internalLength;
685 Oid receiveProcedure;
687 Oid analyzeProcedure;
696 char *defaultValue = NULL;
697 char *defaultValueBin = NULL;
698 bool saw_default = false;
699 bool typNotNull = false;
700 bool nullDefined = false;
701 int32 typNDims = list_length(stmt->typeName->arrayBounds);
703 List *schema = stmt->constraints;
709 Form_pg_type baseType;
713 /* Convert list of names to a name and namespace */
714 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
717 /* Check we have creation rights in target namespace */
718 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
720 if (aclresult != ACLCHECK_OK)
721 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
722 get_namespace_name(domainNamespace));
725 * Check for collision with an existing type name. If there is one and
726 * it's an autogenerated array, we can rename it out of the way.
728 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
729 CStringGetDatum(domainName),
730 ObjectIdGetDatum(domainNamespace));
731 if (OidIsValid(old_type_oid))
733 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
735 (errcode(ERRCODE_DUPLICATE_OBJECT),
736 errmsg("type \"%s\" already exists", domainName)));
740 * Look up the base type.
742 typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
743 baseType = (Form_pg_type) GETSTRUCT(typeTup);
744 basetypeoid = HeapTupleGetOid(typeTup);
747 * Base type must be a plain base type, another domain, an enum or a range
748 * type. Domains over pseudotypes would create a security hole. Domains
749 * over composite types might be made to work in the future, but not
752 typtype = baseType->typtype;
753 if (typtype != TYPTYPE_BASE &&
754 typtype != TYPTYPE_DOMAIN &&
755 typtype != TYPTYPE_ENUM &&
756 typtype != TYPTYPE_RANGE)
758 (errcode(ERRCODE_DATATYPE_MISMATCH),
759 errmsg("\"%s\" is not a valid base type for a domain",
760 TypeNameToString(stmt->typeName))));
762 aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
763 if (aclresult != ACLCHECK_OK)
764 aclcheck_error_type(aclresult, basetypeoid);
767 * Identify the collation if any
769 baseColl = baseType->typcollation;
770 if (stmt->collClause)
771 domaincoll = get_collation_oid(stmt->collClause->collname, false);
773 domaincoll = baseColl;
775 /* Complain if COLLATE is applied to an uncollatable type */
776 if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
778 (errcode(ERRCODE_DATATYPE_MISMATCH),
779 errmsg("collations are not supported by type %s",
780 format_type_be(basetypeoid))));
782 /* passed by value */
783 byValue = baseType->typbyval;
785 /* Required Alignment */
786 alignment = baseType->typalign;
789 storage = baseType->typstorage;
792 internalLength = baseType->typlen;
795 category = baseType->typcategory;
797 /* Array element Delimiter */
798 delimiter = baseType->typdelim;
801 inputProcedure = F_DOMAIN_IN;
802 outputProcedure = baseType->typoutput;
803 receiveProcedure = F_DOMAIN_RECV;
804 sendProcedure = baseType->typsend;
806 /* Domains never accept typmods, so no typmodin/typmodout needed */
808 /* Analysis function */
809 analyzeProcedure = baseType->typanalyze;
811 /* Inherited default value */
812 datum = SysCacheGetAttr(TYPEOID, typeTup,
813 Anum_pg_type_typdefault, &isnull);
815 defaultValue = TextDatumGetCString(datum);
817 /* Inherited default binary value */
818 datum = SysCacheGetAttr(TYPEOID, typeTup,
819 Anum_pg_type_typdefaultbin, &isnull);
821 defaultValueBin = TextDatumGetCString(datum);
824 * Run through constraints manually to avoid the additional processing
825 * conducted by DefineRelation() and friends.
827 foreach(listptr, schema)
829 Constraint *constr = lfirst(listptr);
831 if (!IsA(constr, Constraint))
832 elog(ERROR, "unrecognized node type: %d",
833 (int) nodeTag(constr));
834 switch (constr->contype)
839 * The inherited default value may be overridden by the user
840 * with the DEFAULT <expr> clause ... but only once.
844 (errcode(ERRCODE_SYNTAX_ERROR),
845 errmsg("multiple default expressions")));
848 if (constr->raw_expr)
853 /* Create a dummy ParseState for transformExpr */
854 pstate = make_parsestate(NULL);
857 * Cook the constr->raw_expr into an expression. Note:
858 * name is strictly for error message
860 defaultExpr = cookDefault(pstate, constr->raw_expr,
866 * If the expression is just a NULL constant, we treat it
867 * like not having a default.
869 * Note that if the basetype is another domain, we'll see
870 * a CoerceToDomain expr here and not discard the default.
871 * This is critical because the domain default needs to be
872 * retained to override any default that the base domain
875 if (defaultExpr == NULL ||
876 (IsA(defaultExpr, Const) &&
877 ((Const *) defaultExpr)->constisnull))
880 defaultValueBin = NULL;
885 * Expression must be stored as a nodeToString result,
886 * but we also require a valid textual representation
887 * (mainly to make life easier for pg_dump).
890 deparse_expression(defaultExpr,
892 defaultValueBin = nodeToString(defaultExpr);
897 /* No default (can this still happen?) */
899 defaultValueBin = NULL;
904 if (nullDefined && !typNotNull)
906 (errcode(ERRCODE_SYNTAX_ERROR),
907 errmsg("conflicting NULL/NOT NULL constraints")));
913 if (nullDefined && typNotNull)
915 (errcode(ERRCODE_SYNTAX_ERROR),
916 errmsg("conflicting NULL/NOT NULL constraints")));
924 * Check constraints are handled after domain creation, as
925 * they require the Oid of the domain; at this point we can
926 * only check that they're not marked NO INHERIT, because
927 * that would be bogus.
929 if (constr->is_no_inherit)
931 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
932 errmsg("check constraints for domains cannot be marked NO INHERIT")));
936 * All else are error cases
940 (errcode(ERRCODE_SYNTAX_ERROR),
941 errmsg("unique constraints not possible for domains")));
946 (errcode(ERRCODE_SYNTAX_ERROR),
947 errmsg("primary key constraints not possible for domains")));
950 case CONSTR_EXCLUSION:
952 (errcode(ERRCODE_SYNTAX_ERROR),
953 errmsg("exclusion constraints not possible for domains")));
958 (errcode(ERRCODE_SYNTAX_ERROR),
959 errmsg("foreign key constraints not possible for domains")));
962 case CONSTR_ATTR_DEFERRABLE:
963 case CONSTR_ATTR_NOT_DEFERRABLE:
964 case CONSTR_ATTR_DEFERRED:
965 case CONSTR_ATTR_IMMEDIATE:
967 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
968 errmsg("specifying constraint deferrability not supported for domains")));
972 elog(ERROR, "unrecognized constraint subtype: %d",
973 (int) constr->contype);
979 * Have TypeCreate do all the real work.
982 TypeCreate(InvalidOid, /* no predetermined type OID */
983 domainName, /* type name */
984 domainNamespace, /* namespace */
985 InvalidOid, /* relation oid (n/a here) */
986 0, /* relation kind (ditto) */
987 GetUserId(), /* owner's ID */
988 internalLength, /* internal size */
989 TYPTYPE_DOMAIN, /* type-type (domain type) */
990 category, /* type-category */
991 false, /* domain types are never preferred */
992 delimiter, /* array element delimiter */
993 inputProcedure, /* input procedure */
994 outputProcedure, /* output procedure */
995 receiveProcedure, /* receive procedure */
996 sendProcedure, /* send procedure */
997 InvalidOid, /* typmodin procedure - none */
998 InvalidOid, /* typmodout procedure - none */
999 analyzeProcedure, /* analyze procedure */
1000 InvalidOid, /* no array element type */
1001 false, /* this isn't an array */
1002 InvalidOid, /* no arrays for domains (yet) */
1003 basetypeoid, /* base type ID */
1004 defaultValue, /* default type value (text) */
1005 defaultValueBin, /* default type value (binary) */
1006 byValue, /* passed by value */
1007 alignment, /* required alignment */
1008 storage, /* TOAST strategy */
1009 basetypeMod, /* typeMod value */
1010 typNDims, /* Array dimensions for base type */
1011 typNotNull, /* Type NOT NULL */
1012 domaincoll); /* type's collation */
1015 * Process constraints which refer to the domain ID returned by TypeCreate
1017 foreach(listptr, schema)
1019 Constraint *constr = lfirst(listptr);
1021 /* it must be a Constraint, per check above */
1023 switch (constr->contype)
1026 domainAddConstraint(domainoid, domainNamespace,
1027 basetypeoid, basetypeMod,
1028 constr, domainName);
1031 /* Other constraint types were fully processed above */
1037 /* CCI so we can detect duplicate constraint names */
1038 CommandCounterIncrement();
1042 * Now we can clean up.
1044 ReleaseSysCache(typeTup);
1052 * Registers a new enum.
1055 DefineEnum(CreateEnumStmt *stmt)
1058 char *enumArrayName;
1061 AclResult aclresult;
1065 /* Convert list of names to a name and namespace */
1066 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1069 /* Check we have creation rights in target namespace */
1070 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1071 if (aclresult != ACLCHECK_OK)
1072 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1073 get_namespace_name(enumNamespace));
1076 * Check for collision with an existing type name. If there is one and
1077 * it's an autogenerated array, we can rename it out of the way.
1079 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1080 CStringGetDatum(enumName),
1081 ObjectIdGetDatum(enumNamespace));
1082 if (OidIsValid(old_type_oid))
1084 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1086 (errcode(ERRCODE_DUPLICATE_OBJECT),
1087 errmsg("type \"%s\" already exists", enumName)));
1090 enumArrayOid = AssignTypeArrayOid();
1092 /* Create the pg_type entry */
1094 TypeCreate(InvalidOid, /* no predetermined type OID */
1095 enumName, /* type name */
1096 enumNamespace, /* namespace */
1097 InvalidOid, /* relation oid (n/a here) */
1098 0, /* relation kind (ditto) */
1099 GetUserId(), /* owner's ID */
1100 sizeof(Oid), /* internal size */
1101 TYPTYPE_ENUM, /* type-type (enum type) */
1102 TYPCATEGORY_ENUM, /* type-category (enum type) */
1103 false, /* enum types are never preferred */
1104 DEFAULT_TYPDELIM, /* array element delimiter */
1105 F_ENUM_IN, /* input procedure */
1106 F_ENUM_OUT, /* output procedure */
1107 F_ENUM_RECV, /* receive procedure */
1108 F_ENUM_SEND, /* send procedure */
1109 InvalidOid, /* typmodin procedure - none */
1110 InvalidOid, /* typmodout procedure - none */
1111 InvalidOid, /* analyze procedure - default */
1112 InvalidOid, /* element type ID */
1113 false, /* this is not an array type */
1114 enumArrayOid, /* array type we are about to create */
1115 InvalidOid, /* base type ID (only for domains) */
1116 NULL, /* never a default type value */
1117 NULL, /* binary default isn't sent either */
1118 true, /* always passed by value */
1119 'i', /* int alignment */
1120 'p', /* TOAST strategy always plain */
1121 -1, /* typMod (Domains only) */
1122 0, /* Array dimensions of typbasetype */
1123 false, /* Type NOT NULL */
1124 InvalidOid); /* type's collation */
1126 /* Enter the enum's values into pg_enum */
1127 EnumValuesCreate(enumTypeOid, stmt->vals);
1130 * Create the array type that goes with it.
1132 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1134 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1135 enumArrayName, /* type name */
1136 enumNamespace, /* namespace */
1137 InvalidOid, /* relation oid (n/a here) */
1138 0, /* relation kind (ditto) */
1139 GetUserId(), /* owner's ID */
1140 -1, /* internal size (always varlena) */
1141 TYPTYPE_BASE, /* type-type (base type) */
1142 TYPCATEGORY_ARRAY, /* type-category (array) */
1143 false, /* array types are never preferred */
1144 DEFAULT_TYPDELIM, /* array element delimiter */
1145 F_ARRAY_IN, /* input procedure */
1146 F_ARRAY_OUT, /* output procedure */
1147 F_ARRAY_RECV, /* receive procedure */
1148 F_ARRAY_SEND, /* send procedure */
1149 InvalidOid, /* typmodin procedure - none */
1150 InvalidOid, /* typmodout procedure - none */
1151 F_ARRAY_TYPANALYZE, /* analyze procedure */
1152 enumTypeOid, /* element type ID */
1153 true, /* yes this is an array type */
1154 InvalidOid, /* no further array type */
1155 InvalidOid, /* base type ID */
1156 NULL, /* never a default type value */
1157 NULL, /* binary default isn't sent either */
1158 false, /* never passed by value */
1159 'i', /* enums have align i, so do their arrays */
1160 'x', /* ARRAY is always toastable */
1161 -1, /* typMod (Domains only) */
1162 0, /* Array dimensions of typbasetype */
1163 false, /* Type NOT NULL */
1164 InvalidOid); /* type's collation */
1166 pfree(enumArrayName);
1173 * Adds a new label to an existing enum.
1176 AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
1182 /* Make a TypeName so we can use standard type lookup machinery */
1183 typename = makeTypeNameFromNameList(stmt->typeName);
1184 enum_type_oid = typenameTypeId(NULL, typename);
1186 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1187 if (!HeapTupleIsValid(tup))
1188 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1191 * Ordinarily we disallow adding values within transaction blocks, because
1192 * we can't cope with enum OID values getting into indexes and then having
1193 * their defining pg_enum entries go away. However, it's okay if the enum
1194 * type was created in the current transaction, since then there can be
1195 * no such indexes that wouldn't themselves go away on rollback. (We
1196 * support this case because pg_dump --binary-upgrade needs it.) We test
1197 * this by seeing if the pg_type row has xmin == current XID and is not
1198 * HEAP_UPDATED. If it is HEAP_UPDATED, we can't be sure whether the
1199 * type was created or only modified in this xact. So we are disallowing
1200 * some cases that could theoretically be safe; but fortunately pg_dump
1201 * only needs the simplest case.
1203 if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() &&
1204 !(tup->t_data->t_infomask & HEAP_UPDATED))
1205 /* safe to do inside transaction block */ ;
1207 PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD");
1209 /* Check it's an enum and check user has permission to ALTER the enum */
1210 checkEnumOwner(tup);
1212 /* Add the new label */
1213 AddEnumLabel(enum_type_oid, stmt->newVal,
1214 stmt->newValNeighbor, stmt->newValIsAfter,
1215 stmt->skipIfExists);
1217 ReleaseSysCache(tup);
1219 return enum_type_oid;
1226 * Check that the type is actually an enum and that the current user
1227 * has permission to do ALTER TYPE on it. Throw an error if not.
1230 checkEnumOwner(HeapTuple tup)
1232 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1234 /* Check that this is actually an enum */
1235 if (typTup->typtype != TYPTYPE_ENUM)
1237 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1238 errmsg("%s is not an enum",
1239 format_type_be(HeapTupleGetOid(tup)))));
1241 /* Permission check: must own type */
1242 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1243 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
1249 * Registers a new range type.
1252 DefineRange(CreateRangeStmt *stmt)
1257 char *rangeArrayName;
1259 Oid rangeSubtype = InvalidOid;
1260 List *rangeSubOpclassName = NIL;
1261 List *rangeCollationName = NIL;
1262 List *rangeCanonicalName = NIL;
1263 List *rangeSubtypeDiffName = NIL;
1264 Oid rangeSubOpclass;
1266 regproc rangeCanonical;
1267 regproc rangeSubtypeDiff;
1272 AclResult aclresult;
1275 /* Convert list of names to a name and namespace */
1276 typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1279 /* Check we have creation rights in target namespace */
1280 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1281 if (aclresult != ACLCHECK_OK)
1282 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1283 get_namespace_name(typeNamespace));
1286 * Look to see if type already exists.
1288 typoid = GetSysCacheOid2(TYPENAMENSP,
1289 CStringGetDatum(typeName),
1290 ObjectIdGetDatum(typeNamespace));
1293 * If it's not a shell, see if it's an autogenerated array type, and if so
1294 * rename it out of the way.
1296 if (OidIsValid(typoid) && get_typisdefined(typoid))
1298 if (moveArrayTypeName(typoid, typeName, typeNamespace))
1299 typoid = InvalidOid;
1302 (errcode(ERRCODE_DUPLICATE_OBJECT),
1303 errmsg("type \"%s\" already exists", typeName)));
1307 * If it doesn't exist, create it as a shell, so that the OID is known for
1308 * use in the range function definitions.
1310 if (!OidIsValid(typoid))
1312 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
1313 /* Make new shell type visible for modification below */
1314 CommandCounterIncrement();
1317 /* Extract the parameters from the parameter list */
1318 foreach(lc, stmt->params)
1320 DefElem *defel = (DefElem *) lfirst(lc);
1322 if (pg_strcasecmp(defel->defname, "subtype") == 0)
1324 if (OidIsValid(rangeSubtype))
1326 (errcode(ERRCODE_SYNTAX_ERROR),
1327 errmsg("conflicting or redundant options")));
1328 /* we can look up the subtype name immediately */
1329 rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1331 else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
1333 if (rangeSubOpclassName != NIL)
1335 (errcode(ERRCODE_SYNTAX_ERROR),
1336 errmsg("conflicting or redundant options")));
1337 rangeSubOpclassName = defGetQualifiedName(defel);
1339 else if (pg_strcasecmp(defel->defname, "collation") == 0)
1341 if (rangeCollationName != NIL)
1343 (errcode(ERRCODE_SYNTAX_ERROR),
1344 errmsg("conflicting or redundant options")));
1345 rangeCollationName = defGetQualifiedName(defel);
1347 else if (pg_strcasecmp(defel->defname, "canonical") == 0)
1349 if (rangeCanonicalName != NIL)
1351 (errcode(ERRCODE_SYNTAX_ERROR),
1352 errmsg("conflicting or redundant options")));
1353 rangeCanonicalName = defGetQualifiedName(defel);
1355 else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
1357 if (rangeSubtypeDiffName != NIL)
1359 (errcode(ERRCODE_SYNTAX_ERROR),
1360 errmsg("conflicting or redundant options")));
1361 rangeSubtypeDiffName = defGetQualifiedName(defel);
1365 (errcode(ERRCODE_SYNTAX_ERROR),
1366 errmsg("type attribute \"%s\" not recognized",
1370 /* Must have a subtype */
1371 if (!OidIsValid(rangeSubtype))
1373 (errcode(ERRCODE_SYNTAX_ERROR),
1374 errmsg("type attribute \"subtype\" is required")));
1375 /* disallow ranges of pseudotypes */
1376 if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
1378 (errcode(ERRCODE_DATATYPE_MISMATCH),
1379 errmsg("range subtype cannot be %s",
1380 format_type_be(rangeSubtype))));
1382 /* Identify subopclass */
1383 rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1385 /* Identify collation to use, if any */
1386 if (type_is_collatable(rangeSubtype))
1388 if (rangeCollationName != NIL)
1389 rangeCollation = get_collation_oid(rangeCollationName, false);
1391 rangeCollation = get_typcollation(rangeSubtype);
1395 if (rangeCollationName != NIL)
1397 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1398 errmsg("range collation specified but subtype does not support collation")));
1399 rangeCollation = InvalidOid;
1402 /* Identify support functions, if provided */
1403 if (rangeCanonicalName != NIL)
1404 rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1407 rangeCanonical = InvalidOid;
1409 if (rangeSubtypeDiffName != NIL)
1410 rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1413 rangeSubtypeDiff = InvalidOid;
1415 get_typlenbyvalalign(rangeSubtype,
1416 &subtyplen, &subtypbyval, &subtypalign);
1418 /* alignment must be 'i' or 'd' for ranges */
1419 alignment = (subtypalign == 'd') ? 'd' : 'i';
1421 /* Allocate OID for array type */
1422 rangeArrayOid = AssignTypeArrayOid();
1424 /* Create the pg_type entry */
1426 TypeCreate(InvalidOid, /* no predetermined type OID */
1427 typeName, /* type name */
1428 typeNamespace, /* namespace */
1429 InvalidOid, /* relation oid (n/a here) */
1430 0, /* relation kind (ditto) */
1431 GetUserId(), /* owner's ID */
1432 -1, /* internal size (always varlena) */
1433 TYPTYPE_RANGE, /* type-type (range type) */
1434 TYPCATEGORY_RANGE, /* type-category (range type) */
1435 false, /* range types are never preferred */
1436 DEFAULT_TYPDELIM, /* array element delimiter */
1437 F_RANGE_IN, /* input procedure */
1438 F_RANGE_OUT, /* output procedure */
1439 F_RANGE_RECV, /* receive procedure */
1440 F_RANGE_SEND, /* send procedure */
1441 InvalidOid, /* typmodin procedure - none */
1442 InvalidOid, /* typmodout procedure - none */
1443 F_RANGE_TYPANALYZE, /* analyze procedure */
1444 InvalidOid, /* element type ID - none */
1445 false, /* this is not an array type */
1446 rangeArrayOid, /* array type we are about to create */
1447 InvalidOid, /* base type ID (only for domains) */
1448 NULL, /* never a default type value */
1449 NULL, /* no binary form available either */
1450 false, /* never passed by value */
1451 alignment, /* alignment */
1452 'x', /* TOAST strategy (always extended) */
1453 -1, /* typMod (Domains only) */
1454 0, /* Array dimensions of typbasetype */
1455 false, /* Type NOT NULL */
1456 InvalidOid); /* type's collation (ranges never have one) */
1458 /* Create the entry in pg_range */
1459 RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1460 rangeCanonical, rangeSubtypeDiff);
1463 * Create the array type that goes with it.
1465 rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1467 TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1468 rangeArrayName, /* type name */
1469 typeNamespace, /* namespace */
1470 InvalidOid, /* relation oid (n/a here) */
1471 0, /* relation kind (ditto) */
1472 GetUserId(), /* owner's ID */
1473 -1, /* internal size (always varlena) */
1474 TYPTYPE_BASE, /* type-type (base type) */
1475 TYPCATEGORY_ARRAY, /* type-category (array) */
1476 false, /* array types are never preferred */
1477 DEFAULT_TYPDELIM, /* array element delimiter */
1478 F_ARRAY_IN, /* input procedure */
1479 F_ARRAY_OUT, /* output procedure */
1480 F_ARRAY_RECV, /* receive procedure */
1481 F_ARRAY_SEND, /* send procedure */
1482 InvalidOid, /* typmodin procedure - none */
1483 InvalidOid, /* typmodout procedure - none */
1484 F_ARRAY_TYPANALYZE, /* analyze procedure */
1485 typoid, /* element type ID */
1486 true, /* yes this is an array type */
1487 InvalidOid, /* no further array type */
1488 InvalidOid, /* base type ID */
1489 NULL, /* never a default type value */
1490 NULL, /* binary default isn't sent either */
1491 false, /* never passed by value */
1492 alignment, /* alignment - same as range's */
1493 'x', /* ARRAY is always toastable */
1494 -1, /* typMod (Domains only) */
1495 0, /* Array dimensions of typbasetype */
1496 false, /* Type NOT NULL */
1497 InvalidOid); /* typcollation */
1499 pfree(rangeArrayName);
1501 /* And create the constructor functions for this range type */
1502 makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1508 * Because there may exist several range types over the same subtype, the
1509 * range type can't be uniquely determined from the subtype. So it's
1510 * impossible to define a polymorphic constructor; we have to generate new
1511 * constructor functions explicitly for each range type.
1513 * We actually define 4 functions, with 0 through 3 arguments. This is just
1514 * to offer more convenience for the user.
1517 makeRangeConstructors(const char *name, Oid namespace,
1518 Oid rangeOid, Oid subtype)
1520 static const char *const prosrc[2] = {"range_constructor2",
1521 "range_constructor3"};
1522 static const int pronargs[2] = {2, 3};
1524 Oid constructorArgTypes[3];
1525 ObjectAddress myself,
1529 constructorArgTypes[0] = subtype;
1530 constructorArgTypes[1] = subtype;
1531 constructorArgTypes[2] = TEXTOID;
1533 referenced.classId = TypeRelationId;
1534 referenced.objectId = rangeOid;
1535 referenced.objectSubId = 0;
1537 for (i = 0; i < lengthof(prosrc); i++)
1539 oidvector *constructorArgTypesVector;
1542 constructorArgTypesVector = buildoidvector(constructorArgTypes,
1545 procOid = ProcedureCreate(name, /* name: same as range type */
1546 namespace, /* namespace */
1547 false, /* replace */
1548 false, /* returns set */
1549 rangeOid, /* return type */
1550 BOOTSTRAP_SUPERUSERID, /* proowner */
1551 INTERNALlanguageId, /* language */
1552 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1553 prosrc[i], /* prosrc */
1556 false, /* isWindowFunc */
1557 false, /* security_definer */
1558 false, /* leakproof */
1559 false, /* isStrict */
1560 PROVOLATILE_IMMUTABLE, /* volatility */
1561 constructorArgTypesVector, /* parameterTypes */
1562 PointerGetDatum(NULL), /* allParameterTypes */
1563 PointerGetDatum(NULL), /* parameterModes */
1564 PointerGetDatum(NULL), /* parameterNames */
1565 NIL, /* parameterDefaults */
1566 PointerGetDatum(NULL), /* proconfig */
1571 * Make the constructors internally-dependent on the range type so
1572 * that they go away silently when the type is dropped. Note that
1573 * pg_dump depends on this choice to avoid dumping the constructors.
1575 myself.classId = ProcedureRelationId;
1576 myself.objectId = procOid;
1577 myself.objectSubId = 0;
1579 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1585 * Find suitable I/O functions for a type.
1587 * typeOid is the type's OID (which will already exist, if only as a shell
1592 findTypeInputFunction(List *procname, Oid typeOid)
1598 * Input functions can take a single argument of type CSTRING, or three
1599 * arguments (string, typioparam OID, typmod).
1601 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1602 * see this, we issue a warning and fix up the pg_proc entry.
1604 argList[0] = CSTRINGOID;
1606 procOid = LookupFuncName(procname, 1, argList, true);
1607 if (OidIsValid(procOid))
1610 argList[1] = OIDOID;
1611 argList[2] = INT4OID;
1613 procOid = LookupFuncName(procname, 3, argList, true);
1614 if (OidIsValid(procOid))
1617 /* No luck, try it with OPAQUE */
1618 argList[0] = OPAQUEOID;
1620 procOid = LookupFuncName(procname, 1, argList, true);
1622 if (!OidIsValid(procOid))
1624 argList[1] = OIDOID;
1625 argList[2] = INT4OID;
1627 procOid = LookupFuncName(procname, 3, argList, true);
1630 if (OidIsValid(procOid))
1632 /* Found, but must complain and fix the pg_proc entry */
1634 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1635 NameListToString(procname))));
1636 SetFunctionArgType(procOid, 0, CSTRINGOID);
1639 * Need CommandCounterIncrement since DefineType will likely try to
1640 * alter the pg_proc tuple again.
1642 CommandCounterIncrement();
1647 /* Use CSTRING (preferred) in the error message */
1648 argList[0] = CSTRINGOID;
1651 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1652 errmsg("function %s does not exist",
1653 func_signature_string(procname, 1, NIL, argList))));
1655 return InvalidOid; /* keep compiler quiet */
1659 findTypeOutputFunction(List *procname, Oid typeOid)
1665 * Output functions can take a single argument of the type.
1667 * For backwards compatibility we allow OPAQUE in place of the actual type
1668 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1670 argList[0] = typeOid;
1672 procOid = LookupFuncName(procname, 1, argList, true);
1673 if (OidIsValid(procOid))
1676 /* No luck, try it with OPAQUE */
1677 argList[0] = OPAQUEOID;
1679 procOid = LookupFuncName(procname, 1, argList, true);
1681 if (OidIsValid(procOid))
1683 /* Found, but must complain and fix the pg_proc entry */
1685 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1686 NameListToString(procname), format_type_be(typeOid))));
1687 SetFunctionArgType(procOid, 0, typeOid);
1690 * Need CommandCounterIncrement since DefineType will likely try to
1691 * alter the pg_proc tuple again.
1693 CommandCounterIncrement();
1698 /* Use type name, not OPAQUE, in the failure message. */
1699 argList[0] = typeOid;
1702 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1703 errmsg("function %s does not exist",
1704 func_signature_string(procname, 1, NIL, argList))));
1706 return InvalidOid; /* keep compiler quiet */
1710 findTypeReceiveFunction(List *procname, Oid typeOid)
1716 * Receive functions can take a single argument of type INTERNAL, or three
1717 * arguments (internal, typioparam OID, typmod).
1719 argList[0] = INTERNALOID;
1721 procOid = LookupFuncName(procname, 1, argList, true);
1722 if (OidIsValid(procOid))
1725 argList[1] = OIDOID;
1726 argList[2] = INT4OID;
1728 procOid = LookupFuncName(procname, 3, argList, true);
1729 if (OidIsValid(procOid))
1733 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1734 errmsg("function %s does not exist",
1735 func_signature_string(procname, 1, NIL, argList))));
1737 return InvalidOid; /* keep compiler quiet */
1741 findTypeSendFunction(List *procname, Oid typeOid)
1747 * Send functions can take a single argument of the type.
1749 argList[0] = typeOid;
1751 procOid = LookupFuncName(procname, 1, argList, true);
1752 if (OidIsValid(procOid))
1756 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1757 errmsg("function %s does not exist",
1758 func_signature_string(procname, 1, NIL, argList))));
1760 return InvalidOid; /* keep compiler quiet */
1764 findTypeTypmodinFunction(List *procname)
1770 * typmodin functions always take one cstring[] argument and return int4.
1772 argList[0] = CSTRINGARRAYOID;
1774 procOid = LookupFuncName(procname, 1, argList, true);
1775 if (!OidIsValid(procOid))
1777 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1778 errmsg("function %s does not exist",
1779 func_signature_string(procname, 1, NIL, argList))));
1781 if (get_func_rettype(procOid) != INT4OID)
1783 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1784 errmsg("typmod_in function %s must return type \"integer\"",
1785 NameListToString(procname))));
1791 findTypeTypmodoutFunction(List *procname)
1797 * typmodout functions always take one int4 argument and return cstring.
1799 argList[0] = INT4OID;
1801 procOid = LookupFuncName(procname, 1, argList, true);
1802 if (!OidIsValid(procOid))
1804 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1805 errmsg("function %s does not exist",
1806 func_signature_string(procname, 1, NIL, argList))));
1808 if (get_func_rettype(procOid) != CSTRINGOID)
1810 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1811 errmsg("typmod_out function %s must return type \"cstring\"",
1812 NameListToString(procname))));
1818 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1824 * Analyze functions always take one INTERNAL argument and return bool.
1826 argList[0] = INTERNALOID;
1828 procOid = LookupFuncName(procname, 1, argList, true);
1829 if (!OidIsValid(procOid))
1831 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1832 errmsg("function %s does not exist",
1833 func_signature_string(procname, 1, NIL, argList))));
1835 if (get_func_rettype(procOid) != BOOLOID)
1837 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1838 errmsg("type analyze function %s must return type \"boolean\"",
1839 NameListToString(procname))));
1845 * Find suitable support functions and opclasses for a range type.
1849 * Find named btree opclass for subtype, or default btree opclass if
1853 findRangeSubOpclass(List *opcname, Oid subtype)
1860 opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
1863 * Verify that the operator class accepts this datatype. Note we will
1864 * accept binary compatibility.
1866 opInputType = get_opclass_input_type(opcid);
1867 if (!IsBinaryCoercible(subtype, opInputType))
1869 (errcode(ERRCODE_DATATYPE_MISMATCH),
1870 errmsg("operator class \"%s\" does not accept data type %s",
1871 NameListToString(opcname),
1872 format_type_be(subtype))));
1876 opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
1877 if (!OidIsValid(opcid))
1879 /* We spell the error message identically to GetIndexOpClass */
1881 (errcode(ERRCODE_UNDEFINED_OBJECT),
1882 errmsg("data type %s has no default operator class for access method \"%s\"",
1883 format_type_be(subtype), "btree"),
1884 errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
1892 findRangeCanonicalFunction(List *procname, Oid typeOid)
1896 AclResult aclresult;
1899 * Range canonical functions must take and return the range type, and must
1902 argList[0] = typeOid;
1904 procOid = LookupFuncName(procname, 1, argList, true);
1906 if (!OidIsValid(procOid))
1908 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1909 errmsg("function %s does not exist",
1910 func_signature_string(procname, 1, NIL, argList))));
1912 if (get_func_rettype(procOid) != typeOid)
1914 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1915 errmsg("range canonical function %s must return range type",
1916 func_signature_string(procname, 1, NIL, argList))));
1918 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1920 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1921 errmsg("range canonical function %s must be immutable",
1922 func_signature_string(procname, 1, NIL, argList))));
1924 /* Also, range type's creator must have permission to call function */
1925 aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
1926 if (aclresult != ACLCHECK_OK)
1927 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
1933 findRangeSubtypeDiffFunction(List *procname, Oid subtype)
1937 AclResult aclresult;
1940 * Range subtype diff functions must take two arguments of the subtype,
1941 * must return float8, and must be immutable.
1943 argList[0] = subtype;
1944 argList[1] = subtype;
1946 procOid = LookupFuncName(procname, 2, argList, true);
1948 if (!OidIsValid(procOid))
1950 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1951 errmsg("function %s does not exist",
1952 func_signature_string(procname, 2, NIL, argList))));
1954 if (get_func_rettype(procOid) != FLOAT8OID)
1956 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1957 errmsg("range subtype diff function %s must return type double precision",
1958 func_signature_string(procname, 2, NIL, argList))));
1960 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1962 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1963 errmsg("range subtype diff function %s must be immutable",
1964 func_signature_string(procname, 2, NIL, argList))));
1966 /* Also, range type's creator must have permission to call function */
1967 aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
1968 if (aclresult != ACLCHECK_OK)
1969 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
1975 * AssignTypeArrayOid
1977 * Pre-assign the type's array OID for use in pg_type.typarray
1980 AssignTypeArrayOid(void)
1984 /* Use binary-upgrade override for pg_type.typarray, if supplied. */
1985 if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_array_pg_type_oid))
1987 type_array_oid = binary_upgrade_next_array_pg_type_oid;
1988 binary_upgrade_next_array_pg_type_oid = InvalidOid;
1992 Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
1994 type_array_oid = GetNewOid(pg_type);
1995 heap_close(pg_type, AccessShareLock);
1998 return type_array_oid;
2002 /*-------------------------------------------------------------------
2003 * DefineCompositeType
2005 * Create a Composite Type relation.
2006 * `DefineRelation' does all the work, we just provide the correct
2009 * If the relation already exists, then 'DefineRelation' will abort
2012 * DefineCompositeType returns relid for use when creating
2013 * an implicit composite type during function creation
2014 *-------------------------------------------------------------------
2017 DefineCompositeType(RangeVar *typevar, List *coldeflist)
2019 CreateStmt *createStmt = makeNode(CreateStmt);
2025 * now set the parameters for keys/inheritance etc. All of these are
2026 * uninteresting for composite types...
2028 createStmt->relation = typevar;
2029 createStmt->tableElts = coldeflist;
2030 createStmt->inhRelations = NIL;
2031 createStmt->constraints = NIL;
2032 createStmt->options = list_make1(defWithOids(false));
2033 createStmt->oncommit = ONCOMMIT_NOOP;
2034 createStmt->tablespacename = NULL;
2035 createStmt->if_not_exists = false;
2038 * Check for collision with an existing type name. If there is one and
2039 * it's an autogenerated array, we can rename it out of the way. This
2040 * check is here mainly to get a better error message about a "type"
2041 * instead of below about a "relation".
2043 typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2045 RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2047 GetSysCacheOid2(TYPENAMENSP,
2048 CStringGetDatum(createStmt->relation->relname),
2049 ObjectIdGetDatum(typeNamespace));
2050 if (OidIsValid(old_type_oid))
2052 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2054 (errcode(ERRCODE_DUPLICATE_OBJECT),
2055 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2059 * Finally create the relation. This also creates the type.
2061 relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
2062 Assert(relid != InvalidOid);
2067 * AlterDomainDefault
2069 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
2072 AlterDomainDefault(List *names, Node *defaultRaw)
2080 Node *defaultExpr = NULL; /* NULL if no default specified */
2081 Datum new_record[Natts_pg_type];
2082 bool new_record_nulls[Natts_pg_type];
2083 bool new_record_repl[Natts_pg_type];
2085 Form_pg_type typTup;
2087 /* Make a TypeName so we can use standard type lookup machinery */
2088 typename = makeTypeNameFromNameList(names);
2089 domainoid = typenameTypeId(NULL, typename);
2091 /* Look up the domain in the type table */
2092 rel = heap_open(TypeRelationId, RowExclusiveLock);
2094 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2095 if (!HeapTupleIsValid(tup))
2096 elog(ERROR, "cache lookup failed for type %u", domainoid);
2097 typTup = (Form_pg_type) GETSTRUCT(tup);
2099 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2100 checkDomainOwner(tup);
2102 /* Setup new tuple */
2103 MemSet(new_record, (Datum) 0, sizeof(new_record));
2104 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2105 MemSet(new_record_repl, false, sizeof(new_record_repl));
2107 /* Store the new default into the tuple */
2110 /* Create a dummy ParseState for transformExpr */
2111 pstate = make_parsestate(NULL);
2114 * Cook the colDef->raw_expr into an expression. Note: Name is
2115 * strictly for error message
2117 defaultExpr = cookDefault(pstate, defaultRaw,
2118 typTup->typbasetype,
2120 NameStr(typTup->typname));
2123 * If the expression is just a NULL constant, we treat the command
2124 * like ALTER ... DROP DEFAULT. (But see note for same test in
2127 if (defaultExpr == NULL ||
2128 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
2130 /* Default is NULL, drop it */
2131 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2132 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2133 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2134 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2139 * Expression must be stored as a nodeToString result, but we also
2140 * require a valid textual representation (mainly to make life
2141 * easier for pg_dump).
2143 defaultValue = deparse_expression(defaultExpr,
2147 * Form an updated tuple with the new default and write it back.
2149 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2151 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2152 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2153 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2158 /* ALTER ... DROP DEFAULT */
2159 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2160 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2161 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2162 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2165 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2166 new_record, new_record_nulls,
2169 simple_heap_update(rel, &tup->t_self, newtuple);
2171 CatalogUpdateIndexes(rel, newtuple);
2173 /* Rebuild dependencies */
2174 GenerateTypeDependencies(typTup->typnamespace,
2176 InvalidOid, /* typrelid is n/a */
2177 0, /* relation kind is n/a */
2187 false, /* a domain isn't an implicit array */
2188 typTup->typbasetype,
2189 typTup->typcollation,
2191 true); /* Rebuild is true */
2194 heap_close(rel, NoLock);
2195 heap_freetuple(newtuple);
2201 * AlterDomainNotNull
2203 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2206 AlterDomainNotNull(List *names, bool notNull)
2212 Form_pg_type typTup;
2214 /* Make a TypeName so we can use standard type lookup machinery */
2215 typename = makeTypeNameFromNameList(names);
2216 domainoid = typenameTypeId(NULL, typename);
2218 /* Look up the domain in the type table */
2219 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2221 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2222 if (!HeapTupleIsValid(tup))
2223 elog(ERROR, "cache lookup failed for type %u", domainoid);
2224 typTup = (Form_pg_type) GETSTRUCT(tup);
2226 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2227 checkDomainOwner(tup);
2229 /* Is the domain already set to the desired constraint? */
2230 if (typTup->typnotnull == notNull)
2232 heap_close(typrel, RowExclusiveLock);
2236 /* Adding a NOT NULL constraint requires checking existing columns */
2242 /* Fetch relation list with attributes based on this domain */
2243 /* ShareLock is sufficient to prevent concurrent data changes */
2245 rels = get_rels_with_domain(domainoid, ShareLock);
2249 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2250 Relation testrel = rtc->rel;
2251 TupleDesc tupdesc = RelationGetDescr(testrel);
2255 /* Scan all tuples in this relation */
2256 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2257 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2261 /* Test attributes that are of the domain */
2262 for (i = 0; i < rtc->natts; i++)
2264 int attnum = rtc->atts[i];
2266 if (heap_attisnull(tuple, attnum))
2269 * In principle the auxiliary information for this
2270 * error should be errdatatype(), but errtablecol()
2271 * seems considerably more useful in practice. Since
2272 * this code only executes in an ALTER DOMAIN command,
2273 * the client should already know which domain is in
2277 (errcode(ERRCODE_NOT_NULL_VIOLATION),
2278 errmsg("column \"%s\" of table \"%s\" contains null values",
2279 NameStr(tupdesc->attrs[attnum - 1]->attname),
2280 RelationGetRelationName(testrel)),
2281 errtablecol(testrel, attnum)));
2287 /* Close each rel after processing, but keep lock */
2288 heap_close(testrel, NoLock);
2293 * Okay to update pg_type row. We can scribble on typTup because it's a
2296 typTup->typnotnull = notNull;
2298 simple_heap_update(typrel, &tup->t_self, tup);
2300 CatalogUpdateIndexes(typrel, tup);
2303 heap_freetuple(tup);
2304 heap_close(typrel, RowExclusiveLock);
2310 * AlterDomainDropConstraint
2312 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2315 AlterDomainDropConstraint(List *names, const char *constrName,
2316 DropBehavior behavior, bool missing_ok)
2323 SysScanDesc conscan;
2328 /* Make a TypeName so we can use standard type lookup machinery */
2329 typename = makeTypeNameFromNameList(names);
2330 domainoid = typenameTypeId(NULL, typename);
2332 /* Look up the domain in the type table */
2333 rel = heap_open(TypeRelationId, RowExclusiveLock);
2335 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2336 if (!HeapTupleIsValid(tup))
2337 elog(ERROR, "cache lookup failed for type %u", domainoid);
2339 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2340 checkDomainOwner(tup);
2342 /* Grab an appropriate lock on the pg_constraint relation */
2343 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2345 /* Use the index to scan only constraints of the target relation */
2346 ScanKeyInit(&key[0],
2347 Anum_pg_constraint_contypid,
2348 BTEqualStrategyNumber, F_OIDEQ,
2349 ObjectIdGetDatum(HeapTupleGetOid(tup)));
2351 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2352 SnapshotNow, 1, key);
2355 * Scan over the result set, removing any matching entries.
2357 while ((contup = systable_getnext(conscan)) != NULL)
2359 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
2361 if (strcmp(NameStr(con->conname), constrName) == 0)
2363 ObjectAddress conobj;
2365 conobj.classId = ConstraintRelationId;
2366 conobj.objectId = HeapTupleGetOid(contup);
2367 conobj.objectSubId = 0;
2369 performDeletion(&conobj, behavior, 0);
2373 /* Clean up after the scan */
2374 systable_endscan(conscan);
2375 heap_close(conrel, RowExclusiveLock);
2377 heap_close(rel, NoLock);
2383 (errcode(ERRCODE_UNDEFINED_OBJECT),
2384 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2385 constrName, TypeNameToString(typename))));
2388 (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2389 constrName, TypeNameToString(typename))));
2396 * AlterDomainAddConstraint
2398 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2401 AlterDomainAddConstraint(List *names, Node *newConstraint)
2407 Form_pg_type typTup;
2411 /* Make a TypeName so we can use standard type lookup machinery */
2412 typename = makeTypeNameFromNameList(names);
2413 domainoid = typenameTypeId(NULL, typename);
2415 /* Look up the domain in the type table */
2416 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2418 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2419 if (!HeapTupleIsValid(tup))
2420 elog(ERROR, "cache lookup failed for type %u", domainoid);
2421 typTup = (Form_pg_type) GETSTRUCT(tup);
2423 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2424 checkDomainOwner(tup);
2426 if (!IsA(newConstraint, Constraint))
2427 elog(ERROR, "unrecognized node type: %d",
2428 (int) nodeTag(newConstraint));
2430 constr = (Constraint *) newConstraint;
2432 switch (constr->contype)
2435 /* processed below */
2440 (errcode(ERRCODE_SYNTAX_ERROR),
2441 errmsg("unique constraints not possible for domains")));
2444 case CONSTR_PRIMARY:
2446 (errcode(ERRCODE_SYNTAX_ERROR),
2447 errmsg("primary key constraints not possible for domains")));
2450 case CONSTR_EXCLUSION:
2452 (errcode(ERRCODE_SYNTAX_ERROR),
2453 errmsg("exclusion constraints not possible for domains")));
2456 case CONSTR_FOREIGN:
2458 (errcode(ERRCODE_SYNTAX_ERROR),
2459 errmsg("foreign key constraints not possible for domains")));
2462 case CONSTR_ATTR_DEFERRABLE:
2463 case CONSTR_ATTR_NOT_DEFERRABLE:
2464 case CONSTR_ATTR_DEFERRED:
2465 case CONSTR_ATTR_IMMEDIATE:
2467 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2468 errmsg("specifying constraint deferrability not supported for domains")));
2472 elog(ERROR, "unrecognized constraint subtype: %d",
2473 (int) constr->contype);
2478 * Since all other constraint types throw errors, this must be a check
2479 * constraint. First, process the constraint expression and add an entry
2483 ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
2484 typTup->typbasetype, typTup->typtypmod,
2485 constr, NameStr(typTup->typname));
2488 * If requested to validate the constraint, test all values stored in the
2489 * attributes based on the domain the constraint is being added to.
2491 if (!constr->skip_validation)
2492 validateDomainConstraint(domainoid, ccbin);
2495 heap_close(typrel, RowExclusiveLock);
2501 * AlterDomainValidateConstraint
2503 * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
2506 AlterDomainValidateConstraint(List *names, char *constrName)
2513 Form_pg_constraint con = NULL;
2514 Form_pg_constraint copy_con;
2521 HeapTuple copyTuple;
2524 /* Make a TypeName so we can use standard type lookup machinery */
2525 typename = makeTypeNameFromNameList(names);
2526 domainoid = typenameTypeId(NULL, typename);
2528 /* Look up the domain in the type table */
2529 typrel = heap_open(TypeRelationId, AccessShareLock);
2531 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2532 if (!HeapTupleIsValid(tup))
2533 elog(ERROR, "cache lookup failed for type %u", domainoid);
2535 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2536 checkDomainOwner(tup);
2539 * Find and check the target constraint
2541 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2543 Anum_pg_constraint_contypid,
2544 BTEqualStrategyNumber, F_OIDEQ,
2545 ObjectIdGetDatum(domainoid));
2546 scan = systable_beginscan(conrel, ConstraintTypidIndexId,
2547 true, SnapshotNow, 1, &key);
2549 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2551 con = (Form_pg_constraint) GETSTRUCT(tuple);
2552 if (strcmp(NameStr(con->conname), constrName) == 0)
2561 (errcode(ERRCODE_UNDEFINED_OBJECT),
2562 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2563 constrName, TypeNameToString(typename))));
2565 if (con->contype != CONSTRAINT_CHECK)
2567 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2568 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2569 constrName, TypeNameToString(typename))));
2571 val = SysCacheGetAttr(CONSTROID, tuple,
2572 Anum_pg_constraint_conbin,
2575 elog(ERROR, "null conbin for constraint %u",
2576 HeapTupleGetOid(tuple));
2577 conbin = TextDatumGetCString(val);
2579 validateDomainConstraint(domainoid, conbin);
2582 * Now update the catalog, while we have the door open.
2584 copyTuple = heap_copytuple(tuple);
2585 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2586 copy_con->convalidated = true;
2587 simple_heap_update(conrel, ©Tuple->t_self, copyTuple);
2588 CatalogUpdateIndexes(conrel, copyTuple);
2589 heap_freetuple(copyTuple);
2591 systable_endscan(scan);
2593 heap_close(typrel, AccessShareLock);
2594 heap_close(conrel, RowExclusiveLock);
2596 ReleaseSysCache(tup);
2602 validateDomainConstraint(Oid domainoid, char *ccbin)
2604 Expr *expr = (Expr *) stringToNode(ccbin);
2608 ExprContext *econtext;
2609 ExprState *exprstate;
2611 /* Need an EState to run ExecEvalExpr */
2612 estate = CreateExecutorState();
2613 econtext = GetPerTupleExprContext(estate);
2615 /* build execution state for expr */
2616 exprstate = ExecPrepareExpr(expr, estate);
2618 /* Fetch relation list with attributes based on this domain */
2619 /* ShareLock is sufficient to prevent concurrent data changes */
2621 rels = get_rels_with_domain(domainoid, ShareLock);
2625 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2626 Relation testrel = rtc->rel;
2627 TupleDesc tupdesc = RelationGetDescr(testrel);
2631 /* Scan all tuples in this relation */
2632 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2633 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2637 /* Test attributes that are of the domain */
2638 for (i = 0; i < rtc->natts; i++)
2640 int attnum = rtc->atts[i];
2645 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2647 econtext->domainValue_datum = d;
2648 econtext->domainValue_isNull = isNull;
2650 conResult = ExecEvalExprSwitchContext(exprstate,
2654 if (!isNull && !DatumGetBool(conResult))
2657 * In principle the auxiliary information for this error
2658 * should be errdomainconstraint(), but errtablecol()
2659 * seems considerably more useful in practice. Since this
2660 * code only executes in an ALTER DOMAIN command, the
2661 * client should already know which domain is in question,
2662 * and which constraint too.
2665 (errcode(ERRCODE_CHECK_VIOLATION),
2666 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2667 NameStr(tupdesc->attrs[attnum - 1]->attname),
2668 RelationGetRelationName(testrel)),
2669 errtablecol(testrel, attnum)));
2673 ResetExprContext(econtext);
2677 /* Hold relation lock till commit (XXX bad for concurrency) */
2678 heap_close(testrel, NoLock);
2681 FreeExecutorState(estate);
2685 * get_rels_with_domain
2687 * Fetch all relations / attributes which are using the domain
2689 * The result is a list of RelToCheck structs, one for each distinct
2690 * relation, each containing one or more attribute numbers that are of
2691 * the domain type. We have opened each rel and acquired the specified lock
2694 * We support nested domains by including attributes that are of derived
2695 * domain types. Current callers do not need to distinguish between attributes
2696 * that are of exactly the given domain and those that are of derived domains.
2698 * XXX this is completely broken because there is no way to lock the domain
2699 * to prevent columns from being added or dropped while our command runs.
2700 * We can partially protect against column drops by locking relations as we
2701 * come across them, but there is still a race condition (the window between
2702 * seeing a pg_depend entry and acquiring lock on the relation it references).
2703 * Also, holding locks on all these relations simultaneously creates a non-
2704 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2705 * risk by using the weakest suitable lock (ShareLock for most callers).
2707 * XXX the API for this is not sufficient to support checking domain values
2708 * that are inside composite types or arrays. Currently we just error out
2709 * if a composite type containing the target domain is stored anywhere.
2710 * There are not currently arrays of domains; if there were, we could take
2711 * the same approach, but it'd be nicer to fix it properly.
2713 * Generally used for retrieving a list of tests when adding
2714 * new constraints to a domain.
2717 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2722 SysScanDesc depScan;
2725 Assert(lockmode != NoLock);
2728 * We scan pg_depend to find those things that depend on the domain. (We
2729 * assume we can ignore refobjsubid for a domain.)
2731 depRel = heap_open(DependRelationId, AccessShareLock);
2733 ScanKeyInit(&key[0],
2734 Anum_pg_depend_refclassid,
2735 BTEqualStrategyNumber, F_OIDEQ,
2736 ObjectIdGetDatum(TypeRelationId));
2737 ScanKeyInit(&key[1],
2738 Anum_pg_depend_refobjid,
2739 BTEqualStrategyNumber, F_OIDEQ,
2740 ObjectIdGetDatum(domainOid));
2742 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2743 SnapshotNow, 2, key);
2745 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2747 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2748 RelToCheck *rtc = NULL;
2750 Form_pg_attribute pg_att;
2753 /* Check for directly dependent types --- must be domains */
2754 if (pg_depend->classid == TypeRelationId)
2756 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2759 * Recursively add dependent columns to the output list. This is
2760 * a bit inefficient since we may fail to combine RelToCheck
2761 * entries when attributes of the same rel have different derived
2762 * domain types, but it's probably not worth improving.
2764 result = list_concat(result,
2765 get_rels_with_domain(pg_depend->objid,
2770 /* Else, ignore dependees that aren't user columns of relations */
2771 /* (we assume system columns are never of domain types) */
2772 if (pg_depend->classid != RelationRelationId ||
2773 pg_depend->objsubid <= 0)
2776 /* See if we already have an entry for this relation */
2777 foreach(rellist, result)
2779 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2781 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2790 /* First attribute found for this relation */
2793 /* Acquire requested lock on relation */
2794 rel = relation_open(pg_depend->objid, lockmode);
2797 * Check to see if rowtype is stored anyplace as a composite-type
2798 * column; if so we have to fail, for now anyway.
2800 if (OidIsValid(rel->rd_rel->reltype))
2801 find_composite_type_dependencies(rel->rd_rel->reltype,
2803 format_type_be(domainOid));
2805 /* Otherwise we can ignore views, composite types, etc */
2806 if (rel->rd_rel->relkind != RELKIND_RELATION &&
2807 rel->rd_rel->relkind != RELKIND_MATVIEW)
2809 relation_close(rel, lockmode);
2813 /* Build the RelToCheck entry with enough space for all atts */
2814 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2817 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2818 result = lcons(rtc, result);
2822 * Confirm column has not been dropped, and is of the expected type.
2823 * This defends against an ALTER DROP COLUMN occurring just before we
2824 * acquired lock ... but if the whole table were dropped, we'd still
2827 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2829 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2830 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2834 * Okay, add column to result. We store the columns in column-number
2835 * order; this is just a hack to improve predictability of regression
2838 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2841 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2843 rtc->atts[ptr] = rtc->atts[ptr - 1];
2846 rtc->atts[ptr] = pg_depend->objsubid;
2849 systable_endscan(depScan);
2851 relation_close(depRel, AccessShareLock);
2859 * Check that the type is actually a domain and that the current user
2860 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2863 checkDomainOwner(HeapTuple tup)
2865 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2867 /* Check that this is actually a domain */
2868 if (typTup->typtype != TYPTYPE_DOMAIN)
2870 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2871 errmsg("%s is not a domain",
2872 format_type_be(HeapTupleGetOid(tup)))));
2874 /* Permission check: must own type */
2875 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2876 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
2880 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2883 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2884 int typMod, Constraint *constr,
2891 CoerceToDomainValue *domVal;
2894 * Assign or validate constraint name
2896 if (constr->conname)
2898 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2903 (errcode(ERRCODE_DUPLICATE_OBJECT),
2904 errmsg("constraint \"%s\" for domain \"%s\" already exists",
2905 constr->conname, domainName)));
2908 constr->conname = ChooseConstraintName(domainName,
2915 * Convert the A_EXPR in raw_expr into an EXPR
2917 pstate = make_parsestate(NULL);
2920 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2921 * the expression. Note that it will appear to have the type of the base
2922 * type, not the domain. This seems correct since within the check
2923 * expression, we should not assume the input value can be considered a
2924 * member of the domain.
2926 domVal = makeNode(CoerceToDomainValue);
2927 domVal->typeId = baseTypeOid;
2928 domVal->typeMod = typMod;
2929 domVal->collation = get_typcollation(baseTypeOid);
2930 domVal->location = -1; /* will be set when/if used */
2932 pstate->p_value_substitute = (Node *) domVal;
2934 expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
2937 * Make sure it yields a boolean result.
2939 expr = coerce_to_boolean(pstate, expr, "CHECK");
2942 * Fix up collation information.
2944 assign_expr_collations(pstate, expr);
2947 * Domains don't allow variables (this is probably dead code now that
2948 * add_missing_from is history, but let's be sure).
2950 if (list_length(pstate->p_rtable) != 0 ||
2951 contain_var_clause(expr))
2953 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2954 errmsg("cannot use table references in domain check constraint")));
2957 * Convert to string form for storage.
2959 ccbin = nodeToString(expr);
2962 * Deparse it to produce text for consrc.
2964 ccsrc = deparse_expression(expr,
2968 * Store the constraint in pg_constraint
2970 CreateConstraintEntry(constr->conname, /* Constraint Name */
2971 domainNamespace, /* namespace */
2972 CONSTRAINT_CHECK, /* Constraint Type */
2973 false, /* Is Deferrable */
2974 false, /* Is Deferred */
2975 !constr->skip_validation, /* Is Validated */
2976 InvalidOid, /* not a relation constraint */
2979 domainOid, /* domain constraint */
2980 InvalidOid, /* no associated index */
2981 InvalidOid, /* Foreign key fields */
2990 NULL, /* not an exclusion constraint */
2991 expr, /* Tree form of check constraint */
2992 ccbin, /* Binary form of check constraint */
2993 ccsrc, /* Source form of check constraint */
2994 true, /* is local */
2996 false); /* connoinherit */
2999 * Return the compiled constraint expression so the calling routine can
3000 * perform any additional required tests.
3006 * GetDomainConstraints - get a list of the current constraints of domain
3008 * Returns a possibly-empty list of DomainConstraintState nodes.
3010 * This is called by the executor during plan startup for a CoerceToDomain
3011 * expression node. The given constraints will be checked for each value
3012 * passed through the node.
3014 * We allow this to be called for non-domain types, in which case the result
3018 GetDomainConstraints(Oid typeOid)
3021 bool notNull = false;
3024 conRel = heap_open(ConstraintRelationId, AccessShareLock);
3030 Form_pg_type typTup;
3034 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3035 if (!HeapTupleIsValid(tup))
3036 elog(ERROR, "cache lookup failed for type %u", typeOid);
3037 typTup = (Form_pg_type) GETSTRUCT(tup);
3039 if (typTup->typtype != TYPTYPE_DOMAIN)
3041 /* Not a domain, so done */
3042 ReleaseSysCache(tup);
3046 /* Test for NOT NULL Constraint */
3047 if (typTup->typnotnull)
3050 /* Look for CHECK Constraints on this domain */
3051 ScanKeyInit(&key[0],
3052 Anum_pg_constraint_contypid,
3053 BTEqualStrategyNumber, F_OIDEQ,
3054 ObjectIdGetDatum(typeOid));
3056 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
3057 SnapshotNow, 1, key);
3059 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
3061 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
3065 DomainConstraintState *r;
3067 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
3068 if (c->contype != CONSTRAINT_CHECK)
3072 * Not expecting conbin to be NULL, but we'll test for it anyway
3074 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
3075 conRel->rd_att, &isNull);
3077 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
3078 NameStr(typTup->typname), NameStr(c->conname));
3080 check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
3082 /* ExecInitExpr assumes we've planned the expression */
3083 check_expr = expression_planner(check_expr);
3085 r = makeNode(DomainConstraintState);
3086 r->constrainttype = DOM_CONSTRAINT_CHECK;
3087 r->name = pstrdup(NameStr(c->conname));
3088 r->check_expr = ExecInitExpr(check_expr, NULL);
3091 * use lcons() here because constraints of lower domains should be
3094 result = lcons(r, result);
3097 systable_endscan(scan);
3099 /* loop to next domain in stack */
3100 typeOid = typTup->typbasetype;
3101 ReleaseSysCache(tup);
3104 heap_close(conRel, AccessShareLock);
3107 * Only need to add one NOT NULL check regardless of how many domains in
3108 * the stack request it.
3112 DomainConstraintState *r = makeNode(DomainConstraintState);
3114 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
3115 r->name = pstrdup("NOT NULL");
3116 r->check_expr = NULL;
3118 /* lcons to apply the nullness check FIRST */
3119 result = lcons(r, result);
3127 * Execute ALTER TYPE RENAME
3130 RenameType(RenameStmt *stmt)
3132 List *names = stmt->object;
3133 const char *newTypeName = stmt->newname;
3138 Form_pg_type typTup;
3140 /* Make a TypeName so we can use standard type lookup machinery */
3141 typename = makeTypeNameFromNameList(names);
3142 typeOid = typenameTypeId(NULL, typename);
3144 /* Look up the type in the type table */
3145 rel = heap_open(TypeRelationId, RowExclusiveLock);
3147 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3148 if (!HeapTupleIsValid(tup))
3149 elog(ERROR, "cache lookup failed for type %u", typeOid);
3150 typTup = (Form_pg_type) GETSTRUCT(tup);
3152 /* check permissions on type */
3153 if (!pg_type_ownercheck(typeOid, GetUserId()))
3154 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3156 /* ALTER DOMAIN used on a non-domain? */
3157 if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3159 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3160 errmsg("\"%s\" is not a domain",
3161 format_type_be(typeOid))));
3164 * If it's a composite type, we need to check that it really is a
3165 * free-standing composite type, and not a table's rowtype. We want people
3166 * to use ALTER TABLE not ALTER TYPE for that case.
3168 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3169 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3171 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3172 errmsg("%s is a table's row type",
3173 format_type_be(typeOid)),
3174 errhint("Use ALTER TABLE instead.")));
3176 /* don't allow direct alteration of array types, either */
3177 if (OidIsValid(typTup->typelem) &&
3178 get_array_type(typTup->typelem) == typeOid)
3180 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3181 errmsg("cannot alter array type %s",
3182 format_type_be(typeOid)),
3183 errhint("You can alter type %s, which will alter the array type as well.",
3184 format_type_be(typTup->typelem))));
3187 * If type is composite we need to rename associated pg_class entry too.
3188 * RenameRelationInternal will call RenameTypeInternal automatically.
3190 if (typTup->typtype == TYPTYPE_COMPOSITE)
3191 RenameRelationInternal(typTup->typrelid, newTypeName);
3193 RenameTypeInternal(typeOid, newTypeName,
3194 typTup->typnamespace);
3197 heap_close(rel, RowExclusiveLock);
3203 * Change the owner of a type.
3206 AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
3213 Form_pg_type typTup;
3214 AclResult aclresult;
3216 rel = heap_open(TypeRelationId, RowExclusiveLock);
3218 /* Make a TypeName so we can use standard type lookup machinery */
3219 typename = makeTypeNameFromNameList(names);
3221 /* Use LookupTypeName here so that shell types can be processed */
3222 tup = LookupTypeName(NULL, typename, NULL);
3225 (errcode(ERRCODE_UNDEFINED_OBJECT),
3226 errmsg("type \"%s\" does not exist",
3227 TypeNameToString(typename))));
3228 typeOid = typeTypeId(tup);
3230 /* Copy the syscache entry so we can scribble on it below */
3231 newtup = heap_copytuple(tup);
3232 ReleaseSysCache(tup);
3234 typTup = (Form_pg_type) GETSTRUCT(tup);
3236 /* Don't allow ALTER DOMAIN on a type */
3237 if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3239 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3240 errmsg("%s is not a domain",
3241 format_type_be(typeOid))));
3244 * If it's a composite type, we need to check that it really is a
3245 * free-standing composite type, and not a table's rowtype. We want people
3246 * to use ALTER TABLE not ALTER TYPE for that case.
3248 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3249 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3251 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3252 errmsg("%s is a table's row type",
3253 format_type_be(typeOid)),
3254 errhint("Use ALTER TABLE instead.")));
3256 /* don't allow direct alteration of array types, either */
3257 if (OidIsValid(typTup->typelem) &&
3258 get_array_type(typTup->typelem) == typeOid)
3260 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3261 errmsg("cannot alter array type %s",
3262 format_type_be(typeOid)),
3263 errhint("You can alter type %s, which will alter the array type as well.",
3264 format_type_be(typTup->typelem))));
3267 * If the new owner is the same as the existing owner, consider the
3268 * command to have succeeded. This is for dump restoration purposes.
3270 if (typTup->typowner != newOwnerId)
3272 /* Superusers can always do it */
3275 /* Otherwise, must be owner of the existing object */
3276 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
3277 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
3279 /* Must be able to become new owner */
3280 check_is_member_of_role(GetUserId(), newOwnerId);
3282 /* New owner must have CREATE privilege on namespace */
3283 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3286 if (aclresult != ACLCHECK_OK)
3287 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
3288 get_namespace_name(typTup->typnamespace));
3292 * If it's a composite type, invoke ATExecChangeOwner so that we fix
3293 * up the pg_class entry properly. That will call back to
3294 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3296 if (typTup->typtype == TYPTYPE_COMPOSITE)
3297 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3301 * We can just apply the modification directly.
3303 * okay to scribble on typTup because it's a copy
3305 typTup->typowner = newOwnerId;
3307 simple_heap_update(rel, &tup->t_self, tup);
3309 CatalogUpdateIndexes(rel, tup);
3311 /* Update owner dependency reference */
3312 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3314 /* If it has an array type, update that too */
3315 if (OidIsValid(typTup->typarray))
3316 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3321 heap_close(rel, RowExclusiveLock);
3327 * AlterTypeOwnerInternal - change type owner unconditionally
3329 * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
3330 * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
3331 * It assumes the caller has done all needed checks. The function will
3332 * automatically recurse to an array type if the type has one.
3334 * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
3335 * entry (ie, it's not a table rowtype nor an array type).
3338 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
3339 bool hasDependEntry)
3343 Form_pg_type typTup;
3345 rel = heap_open(TypeRelationId, RowExclusiveLock);
3347 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3348 if (!HeapTupleIsValid(tup))
3349 elog(ERROR, "cache lookup failed for type %u", typeOid);
3350 typTup = (Form_pg_type) GETSTRUCT(tup);
3353 * Modify the owner --- okay to scribble on typTup because it's a copy
3355 typTup->typowner = newOwnerId;
3357 simple_heap_update(rel, &tup->t_self, tup);
3359 CatalogUpdateIndexes(rel, tup);
3361 /* Update owner dependency reference, if it has one */
3363 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3365 /* If it has an array type, update that too */
3366 if (OidIsValid(typTup->typarray))
3367 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3370 heap_close(rel, RowExclusiveLock);
3374 * Execute ALTER TYPE SET SCHEMA
3377 AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype)
3382 ObjectAddresses *objsMoved;
3384 /* Make a TypeName so we can use standard type lookup machinery */
3385 typename = makeTypeNameFromNameList(names);
3386 typeOid = typenameTypeId(NULL, typename);
3388 /* Don't allow ALTER DOMAIN on a type */
3389 if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3391 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3392 errmsg("%s is not a domain",
3393 format_type_be(typeOid))));
3395 /* get schema OID and check its permissions */
3396 nspOid = LookupCreationNamespace(newschema);
3398 objsMoved = new_object_addresses();
3399 AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3400 free_object_addresses(objsMoved);
3406 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
3410 /* check permissions on type */
3411 if (!pg_type_ownercheck(typeOid, GetUserId()))
3412 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3414 /* don't allow direct alteration of array types */
3415 elemOid = get_element_type(typeOid);
3416 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3418 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3419 errmsg("cannot alter array type %s",
3420 format_type_be(typeOid)),
3421 errhint("You can alter type %s, which will alter the array type as well.",
3422 format_type_be(elemOid))));
3424 /* and do the work */
3425 return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3429 * Move specified type to new namespace.
3431 * Caller must have already checked privileges.
3433 * The function automatically recurses to process the type's array type,
3434 * if any. isImplicitArray should be TRUE only when doing this internal
3435 * recursion (outside callers must never try to move an array type directly).
3437 * If errorOnTableType is TRUE, the function errors out if the type is
3438 * a table type. ALTER TABLE has to be used to move a table to a new
3441 * Returns the type's old namespace OID.
3444 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
3445 bool isImplicitArray,
3446 bool errorOnTableType,
3447 ObjectAddresses *objsMoved)
3451 Form_pg_type typform;
3454 bool isCompositeType;
3455 ObjectAddress thisobj;
3458 * Make sure we haven't moved this object previously.
3460 thisobj.classId = TypeRelationId;
3461 thisobj.objectId = typeOid;
3462 thisobj.objectSubId = 0;
3464 if (object_address_present(&thisobj, objsMoved))
3467 rel = heap_open(TypeRelationId, RowExclusiveLock);
3469 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3470 if (!HeapTupleIsValid(tup))
3471 elog(ERROR, "cache lookup failed for type %u", typeOid);
3472 typform = (Form_pg_type) GETSTRUCT(tup);
3474 oldNspOid = typform->typnamespace;
3475 arrayOid = typform->typarray;
3477 /* common checks on switching namespaces */
3478 CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
3480 /* check for duplicate name (more friendly than unique-index failure) */
3481 if (SearchSysCacheExists2(TYPENAMENSP,
3482 CStringGetDatum(NameStr(typform->typname)),
3483 ObjectIdGetDatum(nspOid)))
3485 (errcode(ERRCODE_DUPLICATE_OBJECT),
3486 errmsg("type \"%s\" already exists in schema \"%s\"",
3487 NameStr(typform->typname),
3488 get_namespace_name(nspOid))));
3490 /* Detect whether type is a composite type (but not a table rowtype) */
3492 (typform->typtype == TYPTYPE_COMPOSITE &&
3493 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3495 /* Enforce not-table-type if requested */
3496 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3499 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3500 errmsg("%s is a table's row type",
3501 format_type_be(typeOid)),
3502 errhint("Use ALTER TABLE instead.")));
3504 /* OK, modify the pg_type row */
3506 /* tup is a copy, so we can scribble directly on it */
3507 typform->typnamespace = nspOid;
3509 simple_heap_update(rel, &tup->t_self, tup);
3510 CatalogUpdateIndexes(rel, tup);
3513 * Composite types have pg_class entries.
3515 * We need to modify the pg_class tuple as well to reflect the change of
3518 if (isCompositeType)
3522 classRel = heap_open(RelationRelationId, RowExclusiveLock);
3524 AlterRelationNamespaceInternal(classRel, typform->typrelid,
3528 heap_close(classRel, RowExclusiveLock);
3531 * Check for constraints associated with the composite type (we don't
3532 * currently support this, but probably will someday).
3534 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3535 nspOid, false, objsMoved);
3539 /* If it's a domain, it might have constraints */
3540 if (typform->typtype == TYPTYPE_DOMAIN)
3541 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
3546 * Update dependency on schema, if any --- a table rowtype has not got
3547 * one, and neither does an implicit array.
3549 if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3551 if (changeDependencyFor(TypeRelationId, typeOid,
3552 NamespaceRelationId, oldNspOid, nspOid) != 1)
3553 elog(ERROR, "failed to change schema dependency for type %s",
3554 format_type_be(typeOid));
3556 heap_freetuple(tup);
3558 heap_close(rel, RowExclusiveLock);
3560 add_exact_object_address(&thisobj, objsMoved);
3562 /* Recursively alter the associated array type, if any */
3563 if (OidIsValid(arrayOid))
3564 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);