1 /*-------------------------------------------------------------------------
4 * Routines for SQL commands that manipulate types (and domains).
6 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/commands/typecmds.c
14 * The "DefineFoo" routines take the parse tree and pick out the
15 * appropriate arguments/flags, passing the results to the
16 * corresponding "FooDefine" routines (in src/catalog) that do
17 * the actual catalog-munging. These routines also verify permission
18 * of the user to execute the command.
21 * These things must be defined and committed in the following order:
23 * input/output, recv/send functions
30 *-------------------------------------------------------------------------
34 #include "access/genam.h"
35 #include "access/heapam.h"
36 #include "access/xact.h"
37 #include "catalog/catalog.h"
38 #include "catalog/dependency.h"
39 #include "catalog/heap.h"
40 #include "catalog/indexing.h"
41 #include "catalog/pg_collation.h"
42 #include "catalog/pg_constraint.h"
43 #include "catalog/pg_depend.h"
44 #include "catalog/pg_enum.h"
45 #include "catalog/pg_language.h"
46 #include "catalog/pg_namespace.h"
47 #include "catalog/pg_proc.h"
48 #include "catalog/pg_proc_fn.h"
49 #include "catalog/pg_range.h"
50 #include "catalog/pg_type.h"
51 #include "catalog/pg_type_fn.h"
52 #include "commands/defrem.h"
53 #include "commands/tablecmds.h"
54 #include "commands/typecmds.h"
55 #include "executor/executor.h"
56 #include "miscadmin.h"
57 #include "nodes/makefuncs.h"
58 #include "optimizer/planner.h"
59 #include "optimizer/var.h"
60 #include "parser/parse_coerce.h"
61 #include "parser/parse_collate.h"
62 #include "parser/parse_expr.h"
63 #include "parser/parse_func.h"
64 #include "parser/parse_type.h"
65 #include "utils/acl.h"
66 #include "utils/builtins.h"
67 #include "utils/fmgroids.h"
68 #include "utils/lsyscache.h"
69 #include "utils/memutils.h"
70 #include "utils/rel.h"
71 #include "utils/syscache.h"
72 #include "utils/tqual.h"
75 /* result structure for get_rels_with_domain() */
78 Relation rel; /* opened and locked relation */
79 int natts; /* number of attributes of interest */
80 int *atts; /* attribute numbers */
81 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
84 /* Potentially set by contrib/pg_upgrade_support functions */
85 Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
87 static void makeRangeConstructors(const char *name, Oid namespace,
88 Oid rangeOid, Oid subtype);
89 static Oid findTypeInputFunction(List *procname, Oid typeOid);
90 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
91 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
92 static Oid findTypeSendFunction(List *procname, Oid typeOid);
93 static Oid findTypeTypmodinFunction(List *procname);
94 static Oid findTypeTypmodoutFunction(List *procname);
95 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
96 static Oid findRangeSubOpclass(List *opcname, Oid subtype);
97 static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
98 static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
99 static void validateDomainConstraint(Oid domainoid, char *ccbin);
100 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
101 static void checkEnumOwner(HeapTuple tup);
102 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
104 int typMod, Constraint *constr,
110 * Registers a new base type.
113 DefineType(List *names, List *parameters)
117 int16 internalLength = -1; /* default: variable-length */
118 List *inputName = NIL;
119 List *outputName = NIL;
120 List *receiveName = NIL;
121 List *sendName = NIL;
122 List *typmodinName = NIL;
123 List *typmodoutName = NIL;
124 List *analyzeName = NIL;
125 char category = TYPCATEGORY_USER;
126 bool preferred = false;
127 char delimiter = DEFAULT_TYPDELIM;
128 Oid elemType = InvalidOid;
129 char *defaultValue = NULL;
130 bool byValue = false;
131 char alignment = 'i'; /* default alignment */
132 char storage = 'p'; /* default TOAST storage method */
133 Oid collation = InvalidOid;
134 DefElem *likeTypeEl = NULL;
135 DefElem *internalLengthEl = NULL;
136 DefElem *inputNameEl = NULL;
137 DefElem *outputNameEl = NULL;
138 DefElem *receiveNameEl = NULL;
139 DefElem *sendNameEl = NULL;
140 DefElem *typmodinNameEl = NULL;
141 DefElem *typmodoutNameEl = NULL;
142 DefElem *analyzeNameEl = NULL;
143 DefElem *categoryEl = NULL;
144 DefElem *preferredEl = NULL;
145 DefElem *delimiterEl = NULL;
146 DefElem *elemTypeEl = NULL;
147 DefElem *defaultValueEl = NULL;
148 DefElem *byValueEl = NULL;
149 DefElem *alignmentEl = NULL;
150 DefElem *storageEl = NULL;
151 DefElem *collatableEl = NULL;
154 Oid receiveOid = InvalidOid;
155 Oid sendOid = InvalidOid;
156 Oid typmodinOid = InvalidOid;
157 Oid typmodoutOid = InvalidOid;
158 Oid analyzeOid = InvalidOid;
166 * As of Postgres 8.4, we require superuser privilege to create a base
167 * type. This is simple paranoia: there are too many ways to mess up the
168 * system with an incorrect type definition (for instance, representation
169 * parameters that don't match what the C code expects). In practice it
170 * takes superuser privilege to create the I/O functions, and so the
171 * former requirement that you own the I/O functions pretty much forced
172 * superuserness anyway. We're just making doubly sure here.
174 * XXX re-enable NOT_USED code sections below if you remove this test.
178 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
179 errmsg("must be superuser to create a base type")));
181 /* Convert list of names to a name and namespace */
182 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
185 /* XXX this is unnecessary given the superuser check above */
186 /* Check we have creation rights in target namespace */
187 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
188 if (aclresult != ACLCHECK_OK)
189 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
190 get_namespace_name(typeNamespace));
194 * Look to see if type already exists (presumably as a shell; if not,
195 * TypeCreate will complain).
197 typoid = GetSysCacheOid2(TYPENAMENSP,
198 CStringGetDatum(typeName),
199 ObjectIdGetDatum(typeNamespace));
202 * If it's not a shell, see if it's an autogenerated array type, and if so
203 * rename it out of the way.
205 if (OidIsValid(typoid) && get_typisdefined(typoid))
207 if (moveArrayTypeName(typoid, typeName, typeNamespace))
212 * If it doesn't exist, create it as a shell, so that the OID is known for
213 * use in the I/O function definitions.
215 if (!OidIsValid(typoid))
217 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
218 /* Make new shell type visible for modification below */
219 CommandCounterIncrement();
222 * If the command was a parameterless CREATE TYPE, we're done ---
223 * creating the shell type was all we're supposed to do.
225 if (parameters == NIL)
230 /* Complain if dummy CREATE TYPE and entry already exists */
231 if (parameters == NIL)
233 (errcode(ERRCODE_DUPLICATE_OBJECT),
234 errmsg("type \"%s\" already exists", typeName)));
237 /* Extract the parameters from the parameter list */
238 foreach(pl, parameters)
240 DefElem *defel = (DefElem *) lfirst(pl);
243 if (pg_strcasecmp(defel->defname, "like") == 0)
244 defelp = &likeTypeEl;
245 else if (pg_strcasecmp(defel->defname, "internallength") == 0)
246 defelp = &internalLengthEl;
247 else if (pg_strcasecmp(defel->defname, "input") == 0)
248 defelp = &inputNameEl;
249 else if (pg_strcasecmp(defel->defname, "output") == 0)
250 defelp = &outputNameEl;
251 else if (pg_strcasecmp(defel->defname, "receive") == 0)
252 defelp = &receiveNameEl;
253 else if (pg_strcasecmp(defel->defname, "send") == 0)
254 defelp = &sendNameEl;
255 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
256 defelp = &typmodinNameEl;
257 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
258 defelp = &typmodoutNameEl;
259 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
260 pg_strcasecmp(defel->defname, "analyse") == 0)
261 defelp = &analyzeNameEl;
262 else if (pg_strcasecmp(defel->defname, "category") == 0)
263 defelp = &categoryEl;
264 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
265 defelp = &preferredEl;
266 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
267 defelp = &delimiterEl;
268 else if (pg_strcasecmp(defel->defname, "element") == 0)
269 defelp = &elemTypeEl;
270 else if (pg_strcasecmp(defel->defname, "default") == 0)
271 defelp = &defaultValueEl;
272 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
274 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
275 defelp = &alignmentEl;
276 else if (pg_strcasecmp(defel->defname, "storage") == 0)
278 else if (pg_strcasecmp(defel->defname, "collatable") == 0)
279 defelp = &collatableEl;
282 /* WARNING, not ERROR, for historical backwards-compatibility */
284 (errcode(ERRCODE_SYNTAX_ERROR),
285 errmsg("type attribute \"%s\" not recognized",
291 (errcode(ERRCODE_SYNTAX_ERROR),
292 errmsg("conflicting or redundant options")));
297 * Now interpret the options; we do this separately so that LIKE can be
298 * overridden by other options regardless of the ordering in the parameter
304 Form_pg_type likeForm;
306 likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
307 likeForm = (Form_pg_type) GETSTRUCT(likeType);
308 internalLength = likeForm->typlen;
309 byValue = likeForm->typbyval;
310 alignment = likeForm->typalign;
311 storage = likeForm->typstorage;
312 ReleaseSysCache(likeType);
314 if (internalLengthEl)
315 internalLength = defGetTypeLength(internalLengthEl);
317 inputName = defGetQualifiedName(inputNameEl);
319 outputName = defGetQualifiedName(outputNameEl);
321 receiveName = defGetQualifiedName(receiveNameEl);
323 sendName = defGetQualifiedName(sendNameEl);
325 typmodinName = defGetQualifiedName(typmodinNameEl);
327 typmodoutName = defGetQualifiedName(typmodoutNameEl);
329 analyzeName = defGetQualifiedName(analyzeNameEl);
332 char *p = defGetString(categoryEl);
335 /* restrict to non-control ASCII */
336 if (category < 32 || category > 126)
338 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
339 errmsg("invalid type category \"%s\": must be simple ASCII",
343 preferred = defGetBoolean(preferredEl);
346 char *p = defGetString(delimiterEl);
349 /* XXX shouldn't we restrict the delimiter? */
353 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
354 /* disallow arrays of pseudotypes */
355 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
357 (errcode(ERRCODE_DATATYPE_MISMATCH),
358 errmsg("array element type cannot be %s",
359 format_type_be(elemType))));
362 defaultValue = defGetString(defaultValueEl);
364 byValue = defGetBoolean(byValueEl);
367 char *a = defGetString(alignmentEl);
370 * Note: if argument was an unquoted identifier, parser will have
371 * applied translations to it, so be prepared to recognize translated
372 * type names as well as the nominal form.
374 if (pg_strcasecmp(a, "double") == 0 ||
375 pg_strcasecmp(a, "float8") == 0 ||
376 pg_strcasecmp(a, "pg_catalog.float8") == 0)
378 else if (pg_strcasecmp(a, "int4") == 0 ||
379 pg_strcasecmp(a, "pg_catalog.int4") == 0)
381 else if (pg_strcasecmp(a, "int2") == 0 ||
382 pg_strcasecmp(a, "pg_catalog.int2") == 0)
384 else if (pg_strcasecmp(a, "char") == 0 ||
385 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
389 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
390 errmsg("alignment \"%s\" not recognized", a)));
394 char *a = defGetString(storageEl);
396 if (pg_strcasecmp(a, "plain") == 0)
398 else if (pg_strcasecmp(a, "external") == 0)
400 else if (pg_strcasecmp(a, "extended") == 0)
402 else if (pg_strcasecmp(a, "main") == 0)
406 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
407 errmsg("storage \"%s\" not recognized", a)));
410 collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
413 * make sure we have our required definitions
415 if (inputName == NIL)
417 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
418 errmsg("type input function must be specified")));
419 if (outputName == NIL)
421 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
422 errmsg("type output function must be specified")));
424 if (typmodinName == NIL && typmodoutName != NIL)
426 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
427 errmsg("type modifier output function is useless without a type modifier input function")));
430 * Convert I/O proc names to OIDs
432 inputOid = findTypeInputFunction(inputName, typoid);
433 outputOid = findTypeOutputFunction(outputName, typoid);
435 receiveOid = findTypeReceiveFunction(receiveName, typoid);
437 sendOid = findTypeSendFunction(sendName, typoid);
440 * Verify that I/O procs return the expected thing. If we see OPAQUE,
441 * complain and change it to the correct type-safe choice.
443 resulttype = get_func_rettype(inputOid);
444 if (resulttype != typoid)
446 if (resulttype == OPAQUEOID)
448 /* backwards-compatibility hack */
450 (errmsg("changing return type of function %s from \"opaque\" to %s",
451 NameListToString(inputName), typeName)));
452 SetFunctionReturnType(inputOid, typoid);
456 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
457 errmsg("type input function %s must return type %s",
458 NameListToString(inputName), typeName)));
460 resulttype = get_func_rettype(outputOid);
461 if (resulttype != CSTRINGOID)
463 if (resulttype == OPAQUEOID)
465 /* backwards-compatibility hack */
467 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
468 NameListToString(outputName))));
469 SetFunctionReturnType(outputOid, CSTRINGOID);
473 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
474 errmsg("type output function %s must return type \"cstring\"",
475 NameListToString(outputName))));
479 resulttype = get_func_rettype(receiveOid);
480 if (resulttype != typoid)
482 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
483 errmsg("type receive function %s must return type %s",
484 NameListToString(receiveName), typeName)));
488 resulttype = get_func_rettype(sendOid);
489 if (resulttype != BYTEAOID)
491 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
492 errmsg("type send function %s must return type \"bytea\"",
493 NameListToString(sendName))));
497 * Convert typmodin/out function proc names to OIDs.
500 typmodinOid = findTypeTypmodinFunction(typmodinName);
502 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
505 * Convert analysis function proc name to an OID. If no analysis function
506 * is specified, we'll use zero to select the built-in default algorithm.
509 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
512 * Check permissions on functions. We choose to require the creator/owner
513 * of a type to also own the underlying functions. Since creating a type
514 * is tantamount to granting public execute access on the functions, the
515 * minimum sane check would be for execute-with-grant-option. But we
516 * don't have a way to make the type go away if the grant option is
517 * revoked, so ownership seems better.
520 /* XXX this is unnecessary given the superuser check above */
521 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
522 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
523 NameListToString(inputName));
524 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
525 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
526 NameListToString(outputName));
527 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
528 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
529 NameListToString(receiveName));
530 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
531 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
532 NameListToString(sendName));
533 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
534 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
535 NameListToString(typmodinName));
536 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
537 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
538 NameListToString(typmodoutName));
539 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
540 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
541 NameListToString(analyzeName));
544 array_oid = AssignTypeArrayOid();
547 * now have TypeCreate do all the real work.
549 * Note: the pg_type.oid is stored in user tables as array elements (base
550 * types) in ArrayType and in composite types in DatumTupleFields. This
551 * oid must be preserved by binary upgrades.
554 TypeCreate(InvalidOid, /* no predetermined type OID */
555 typeName, /* type name */
556 typeNamespace, /* namespace */
557 InvalidOid, /* relation oid (n/a here) */
558 0, /* relation kind (ditto) */
559 GetUserId(), /* owner's ID */
560 internalLength, /* internal size */
561 TYPTYPE_BASE, /* type-type (base type) */
562 category, /* type-category */
563 preferred, /* is it a preferred type? */
564 delimiter, /* array element delimiter */
565 inputOid, /* input procedure */
566 outputOid, /* output procedure */
567 receiveOid, /* receive procedure */
568 sendOid, /* send procedure */
569 typmodinOid, /* typmodin procedure */
570 typmodoutOid, /* typmodout procedure */
571 analyzeOid, /* analyze procedure */
572 elemType, /* element type ID */
573 false, /* this is not an array type */
574 array_oid, /* array type we are about to create */
575 InvalidOid, /* base type ID (only for domains) */
576 defaultValue, /* default type value */
577 NULL, /* no binary form available */
578 byValue, /* passed by value */
579 alignment, /* required alignment */
580 storage, /* TOAST strategy */
581 -1, /* typMod (Domains only) */
582 0, /* Array Dimensions of typbasetype */
583 false, /* Type NOT NULL */
584 collation); /* type's collation */
587 * Create the array type that goes with it.
589 array_type = makeArrayTypeName(typeName, typeNamespace);
591 /* alignment must be 'i' or 'd' for arrays */
592 alignment = (alignment == 'd') ? 'd' : 'i';
594 TypeCreate(array_oid, /* force assignment of this type OID */
595 array_type, /* type name */
596 typeNamespace, /* namespace */
597 InvalidOid, /* relation oid (n/a here) */
598 0, /* relation kind (ditto) */
599 GetUserId(), /* owner's ID */
600 -1, /* internal size (always varlena) */
601 TYPTYPE_BASE, /* type-type (base type) */
602 TYPCATEGORY_ARRAY, /* type-category (array) */
603 false, /* array types are never preferred */
604 delimiter, /* array element delimiter */
605 F_ARRAY_IN, /* input procedure */
606 F_ARRAY_OUT, /* output procedure */
607 F_ARRAY_RECV, /* receive procedure */
608 F_ARRAY_SEND, /* send procedure */
609 typmodinOid, /* typmodin procedure */
610 typmodoutOid, /* typmodout procedure */
611 F_ARRAY_TYPANALYZE, /* analyze procedure */
612 typoid, /* element type ID */
613 true, /* yes this is an array type */
614 InvalidOid, /* no further array type */
615 InvalidOid, /* base type ID */
616 NULL, /* never a default type value */
617 NULL, /* binary default isn't sent either */
618 false, /* never passed by value */
619 alignment, /* see above */
620 'x', /* ARRAY is always toastable */
621 -1, /* typMod (Domains only) */
622 0, /* Array dimensions of typbasetype */
623 false, /* Type NOT NULL */
624 collation); /* type's collation */
630 * Guts of type deletion.
633 RemoveTypeById(Oid typeOid)
638 relation = heap_open(TypeRelationId, RowExclusiveLock);
640 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
641 if (!HeapTupleIsValid(tup))
642 elog(ERROR, "cache lookup failed for type %u", typeOid);
644 simple_heap_delete(relation, &tup->t_self);
647 * If it is an enum, delete the pg_enum entries too; we don't bother with
648 * making dependency entries for those, so it has to be done "by hand"
651 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
652 EnumValuesDelete(typeOid);
655 * If it is a range type, delete the pg_range entry too; we don't bother
656 * with making a dependency entry for that, so it has to be done "by hand"
659 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
660 RangeDelete(typeOid);
662 ReleaseSysCache(tup);
664 heap_close(relation, RowExclusiveLock);
670 * Registers a new domain.
673 DefineDomain(CreateDomainStmt *stmt)
678 int16 internalLength;
681 Oid receiveProcedure;
683 Oid analyzeProcedure;
692 char *defaultValue = NULL;
693 char *defaultValueBin = NULL;
694 bool saw_default = false;
695 bool typNotNull = false;
696 bool nullDefined = false;
697 int32 typNDims = list_length(stmt->typeName->arrayBounds);
699 List *schema = stmt->constraints;
705 Form_pg_type baseType;
709 /* Convert list of names to a name and namespace */
710 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
713 /* Check we have creation rights in target namespace */
714 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
716 if (aclresult != ACLCHECK_OK)
717 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
718 get_namespace_name(domainNamespace));
721 * Check for collision with an existing type name. If there is one and
722 * it's an autogenerated array, we can rename it out of the way.
724 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
725 CStringGetDatum(domainName),
726 ObjectIdGetDatum(domainNamespace));
727 if (OidIsValid(old_type_oid))
729 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
731 (errcode(ERRCODE_DUPLICATE_OBJECT),
732 errmsg("type \"%s\" already exists", domainName)));
736 * Look up the base type.
738 typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
739 baseType = (Form_pg_type) GETSTRUCT(typeTup);
740 basetypeoid = HeapTupleGetOid(typeTup);
743 * Base type must be a plain base type, another domain, an enum or a range
744 * type. Domains over pseudotypes would create a security hole. Domains
745 * over composite types might be made to work in the future, but not
748 typtype = baseType->typtype;
749 if (typtype != TYPTYPE_BASE &&
750 typtype != TYPTYPE_DOMAIN &&
751 typtype != TYPTYPE_ENUM &&
752 typtype != TYPTYPE_RANGE)
754 (errcode(ERRCODE_DATATYPE_MISMATCH),
755 errmsg("\"%s\" is not a valid base type for a domain",
756 TypeNameToString(stmt->typeName))));
758 aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
759 if (aclresult != ACLCHECK_OK)
760 aclcheck_error(aclresult, ACL_KIND_TYPE,
761 format_type_be(basetypeoid));
764 * Identify the collation if any
766 baseColl = baseType->typcollation;
767 if (stmt->collClause)
768 domaincoll = get_collation_oid(stmt->collClause->collname, false);
770 domaincoll = baseColl;
772 /* Complain if COLLATE is applied to an uncollatable type */
773 if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
775 (errcode(ERRCODE_DATATYPE_MISMATCH),
776 errmsg("collations are not supported by type %s",
777 format_type_be(basetypeoid))));
779 /* passed by value */
780 byValue = baseType->typbyval;
782 /* Required Alignment */
783 alignment = baseType->typalign;
786 storage = baseType->typstorage;
789 internalLength = baseType->typlen;
792 category = baseType->typcategory;
794 /* Array element Delimiter */
795 delimiter = baseType->typdelim;
798 inputProcedure = F_DOMAIN_IN;
799 outputProcedure = baseType->typoutput;
800 receiveProcedure = F_DOMAIN_RECV;
801 sendProcedure = baseType->typsend;
803 /* Domains never accept typmods, so no typmodin/typmodout needed */
805 /* Analysis function */
806 analyzeProcedure = baseType->typanalyze;
808 /* Inherited default value */
809 datum = SysCacheGetAttr(TYPEOID, typeTup,
810 Anum_pg_type_typdefault, &isnull);
812 defaultValue = TextDatumGetCString(datum);
814 /* Inherited default binary value */
815 datum = SysCacheGetAttr(TYPEOID, typeTup,
816 Anum_pg_type_typdefaultbin, &isnull);
818 defaultValueBin = TextDatumGetCString(datum);
821 * Run through constraints manually to avoid the additional processing
822 * conducted by DefineRelation() and friends.
824 foreach(listptr, schema)
826 Constraint *constr = lfirst(listptr);
828 if (!IsA(constr, Constraint))
829 elog(ERROR, "unrecognized node type: %d",
830 (int) nodeTag(constr));
831 switch (constr->contype)
836 * The inherited default value may be overridden by the user
837 * with the DEFAULT <expr> clause ... but only once.
841 (errcode(ERRCODE_SYNTAX_ERROR),
842 errmsg("multiple default expressions")));
845 if (constr->raw_expr)
850 /* Create a dummy ParseState for transformExpr */
851 pstate = make_parsestate(NULL);
854 * Cook the constr->raw_expr into an expression. Note:
855 * name is strictly for error message
857 defaultExpr = cookDefault(pstate, constr->raw_expr,
863 * If the expression is just a NULL constant, we treat it
864 * like not having a default.
866 * Note that if the basetype is another domain, we'll see
867 * a CoerceToDomain expr here and not discard the default.
868 * This is critical because the domain default needs to be
869 * retained to override any default that the base domain
872 if (defaultExpr == NULL ||
873 (IsA(defaultExpr, Const) &&
874 ((Const *) defaultExpr)->constisnull))
877 defaultValueBin = NULL;
882 * Expression must be stored as a nodeToString result,
883 * but we also require a valid textual representation
884 * (mainly to make life easier for pg_dump).
887 deparse_expression(defaultExpr,
888 deparse_context_for(domainName,
891 defaultValueBin = nodeToString(defaultExpr);
896 /* No default (can this still happen?) */
898 defaultValueBin = NULL;
903 if (nullDefined && !typNotNull)
905 (errcode(ERRCODE_SYNTAX_ERROR),
906 errmsg("conflicting NULL/NOT NULL constraints")));
912 if (nullDefined && typNotNull)
914 (errcode(ERRCODE_SYNTAX_ERROR),
915 errmsg("conflicting NULL/NOT NULL constraints")));
923 * Check constraints are handled after domain creation, as
924 * they require the Oid of the domain
929 * All else are error cases
933 (errcode(ERRCODE_SYNTAX_ERROR),
934 errmsg("unique constraints not possible for domains")));
939 (errcode(ERRCODE_SYNTAX_ERROR),
940 errmsg("primary key constraints not possible for domains")));
943 case CONSTR_EXCLUSION:
945 (errcode(ERRCODE_SYNTAX_ERROR),
946 errmsg("exclusion constraints not possible for domains")));
951 (errcode(ERRCODE_SYNTAX_ERROR),
952 errmsg("foreign key constraints not possible for domains")));
955 case CONSTR_ATTR_DEFERRABLE:
956 case CONSTR_ATTR_NOT_DEFERRABLE:
957 case CONSTR_ATTR_DEFERRED:
958 case CONSTR_ATTR_IMMEDIATE:
960 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
961 errmsg("specifying constraint deferrability not supported for domains")));
965 elog(ERROR, "unrecognized constraint subtype: %d",
966 (int) constr->contype);
972 * Have TypeCreate do all the real work.
975 TypeCreate(InvalidOid, /* no predetermined type OID */
976 domainName, /* type name */
977 domainNamespace, /* namespace */
978 InvalidOid, /* relation oid (n/a here) */
979 0, /* relation kind (ditto) */
980 GetUserId(), /* owner's ID */
981 internalLength, /* internal size */
982 TYPTYPE_DOMAIN, /* type-type (domain type) */
983 category, /* type-category */
984 false, /* domain types are never preferred */
985 delimiter, /* array element delimiter */
986 inputProcedure, /* input procedure */
987 outputProcedure, /* output procedure */
988 receiveProcedure, /* receive procedure */
989 sendProcedure, /* send procedure */
990 InvalidOid, /* typmodin procedure - none */
991 InvalidOid, /* typmodout procedure - none */
992 analyzeProcedure, /* analyze procedure */
993 InvalidOid, /* no array element type */
994 false, /* this isn't an array */
995 InvalidOid, /* no arrays for domains (yet) */
996 basetypeoid, /* base type ID */
997 defaultValue, /* default type value (text) */
998 defaultValueBin, /* default type value (binary) */
999 byValue, /* passed by value */
1000 alignment, /* required alignment */
1001 storage, /* TOAST strategy */
1002 basetypeMod, /* typeMod value */
1003 typNDims, /* Array dimensions for base type */
1004 typNotNull, /* Type NOT NULL */
1005 domaincoll); /* type's collation */
1008 * Process constraints which refer to the domain ID returned by TypeCreate
1010 foreach(listptr, schema)
1012 Constraint *constr = lfirst(listptr);
1014 /* it must be a Constraint, per check above */
1016 switch (constr->contype)
1019 domainAddConstraint(domainoid, domainNamespace,
1020 basetypeoid, basetypeMod,
1021 constr, domainName);
1024 /* Other constraint types were fully processed above */
1030 /* CCI so we can detect duplicate constraint names */
1031 CommandCounterIncrement();
1035 * Now we can clean up.
1037 ReleaseSysCache(typeTup);
1043 * Registers a new enum.
1046 DefineEnum(CreateEnumStmt *stmt)
1049 char *enumArrayName;
1052 AclResult aclresult;
1056 /* Convert list of names to a name and namespace */
1057 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1060 /* Check we have creation rights in target namespace */
1061 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1062 if (aclresult != ACLCHECK_OK)
1063 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1064 get_namespace_name(enumNamespace));
1067 * Check for collision with an existing type name. If there is one and
1068 * it's an autogenerated array, we can rename it out of the way.
1070 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1071 CStringGetDatum(enumName),
1072 ObjectIdGetDatum(enumNamespace));
1073 if (OidIsValid(old_type_oid))
1075 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1077 (errcode(ERRCODE_DUPLICATE_OBJECT),
1078 errmsg("type \"%s\" already exists", enumName)));
1081 enumArrayOid = AssignTypeArrayOid();
1083 /* Create the pg_type entry */
1085 TypeCreate(InvalidOid, /* no predetermined type OID */
1086 enumName, /* type name */
1087 enumNamespace, /* namespace */
1088 InvalidOid, /* relation oid (n/a here) */
1089 0, /* relation kind (ditto) */
1090 GetUserId(), /* owner's ID */
1091 sizeof(Oid), /* internal size */
1092 TYPTYPE_ENUM, /* type-type (enum type) */
1093 TYPCATEGORY_ENUM, /* type-category (enum type) */
1094 false, /* enum types are never preferred */
1095 DEFAULT_TYPDELIM, /* array element delimiter */
1096 F_ENUM_IN, /* input procedure */
1097 F_ENUM_OUT, /* output procedure */
1098 F_ENUM_RECV, /* receive procedure */
1099 F_ENUM_SEND, /* send procedure */
1100 InvalidOid, /* typmodin procedure - none */
1101 InvalidOid, /* typmodout procedure - none */
1102 InvalidOid, /* analyze procedure - default */
1103 InvalidOid, /* element type ID */
1104 false, /* this is not an array type */
1105 enumArrayOid, /* array type we are about to create */
1106 InvalidOid, /* base type ID (only for domains) */
1107 NULL, /* never a default type value */
1108 NULL, /* binary default isn't sent either */
1109 true, /* always passed by value */
1110 'i', /* int alignment */
1111 'p', /* TOAST strategy always plain */
1112 -1, /* typMod (Domains only) */
1113 0, /* Array dimensions of typbasetype */
1114 false, /* Type NOT NULL */
1115 InvalidOid); /* type's collation */
1117 /* Enter the enum's values into pg_enum */
1118 EnumValuesCreate(enumTypeOid, stmt->vals);
1121 * Create the array type that goes with it.
1123 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1125 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1126 enumArrayName, /* type name */
1127 enumNamespace, /* namespace */
1128 InvalidOid, /* relation oid (n/a here) */
1129 0, /* relation kind (ditto) */
1130 GetUserId(), /* owner's ID */
1131 -1, /* internal size (always varlena) */
1132 TYPTYPE_BASE, /* type-type (base type) */
1133 TYPCATEGORY_ARRAY, /* type-category (array) */
1134 false, /* array types are never preferred */
1135 DEFAULT_TYPDELIM, /* array element delimiter */
1136 F_ARRAY_IN, /* input procedure */
1137 F_ARRAY_OUT, /* output procedure */
1138 F_ARRAY_RECV, /* receive procedure */
1139 F_ARRAY_SEND, /* send procedure */
1140 InvalidOid, /* typmodin procedure - none */
1141 InvalidOid, /* typmodout procedure - none */
1142 F_ARRAY_TYPANALYZE, /* analyze procedure */
1143 enumTypeOid, /* element type ID */
1144 true, /* yes this is an array type */
1145 InvalidOid, /* no further array type */
1146 InvalidOid, /* base type ID */
1147 NULL, /* never a default type value */
1148 NULL, /* binary default isn't sent either */
1149 false, /* never passed by value */
1150 'i', /* enums have align i, so do their arrays */
1151 'x', /* ARRAY is always toastable */
1152 -1, /* typMod (Domains only) */
1153 0, /* Array dimensions of typbasetype */
1154 false, /* Type NOT NULL */
1155 InvalidOid); /* type's collation */
1157 pfree(enumArrayName);
1162 * Adds a new label to an existing enum.
1165 AlterEnum(AlterEnumStmt *stmt)
1171 /* Make a TypeName so we can use standard type lookup machinery */
1172 typename = makeTypeNameFromNameList(stmt->typeName);
1173 enum_type_oid = typenameTypeId(NULL, typename);
1175 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1176 if (!HeapTupleIsValid(tup))
1177 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1179 /* Check it's an enum and check user has permission to ALTER the enum */
1180 checkEnumOwner(tup);
1182 /* Add the new label */
1183 AddEnumLabel(enum_type_oid, stmt->newVal,
1184 stmt->newValNeighbor, stmt->newValIsAfter);
1186 ReleaseSysCache(tup);
1193 * Check that the type is actually an enum and that the current user
1194 * has permission to do ALTER TYPE on it. Throw an error if not.
1197 checkEnumOwner(HeapTuple tup)
1199 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1201 /* Check that this is actually an enum */
1202 if (typTup->typtype != TYPTYPE_ENUM)
1204 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1205 errmsg("%s is not an enum",
1206 format_type_be(HeapTupleGetOid(tup)))));
1208 /* Permission check: must own type */
1209 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1210 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
1211 format_type_be(HeapTupleGetOid(tup)));
1217 * Registers a new range type.
1220 DefineRange(CreateRangeStmt *stmt)
1225 char *rangeArrayName;
1227 Oid rangeSubtype = InvalidOid;
1228 List *rangeSubOpclassName = NIL;
1229 List *rangeCollationName = NIL;
1230 List *rangeCanonicalName = NIL;
1231 List *rangeSubtypeDiffName = NIL;
1232 Oid rangeSubOpclass;
1234 regproc rangeCanonical;
1235 regproc rangeSubtypeDiff;
1240 AclResult aclresult;
1243 /* Convert list of names to a name and namespace */
1244 typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1247 /* Check we have creation rights in target namespace */
1248 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1249 if (aclresult != ACLCHECK_OK)
1250 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1251 get_namespace_name(typeNamespace));
1254 * Look to see if type already exists.
1256 typoid = GetSysCacheOid2(TYPENAMENSP,
1257 CStringGetDatum(typeName),
1258 ObjectIdGetDatum(typeNamespace));
1261 * If it's not a shell, see if it's an autogenerated array type, and if so
1262 * rename it out of the way.
1264 if (OidIsValid(typoid) && get_typisdefined(typoid))
1266 if (moveArrayTypeName(typoid, typeName, typeNamespace))
1267 typoid = InvalidOid;
1270 (errcode(ERRCODE_DUPLICATE_OBJECT),
1271 errmsg("type \"%s\" already exists", typeName)));
1275 * If it doesn't exist, create it as a shell, so that the OID is known for
1276 * use in the range function definitions.
1278 if (!OidIsValid(typoid))
1280 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
1281 /* Make new shell type visible for modification below */
1282 CommandCounterIncrement();
1285 /* Extract the parameters from the parameter list */
1286 foreach(lc, stmt->params)
1288 DefElem *defel = (DefElem *) lfirst(lc);
1290 if (pg_strcasecmp(defel->defname, "subtype") == 0)
1292 if (OidIsValid(rangeSubtype))
1294 (errcode(ERRCODE_SYNTAX_ERROR),
1295 errmsg("conflicting or redundant options")));
1296 /* we can look up the subtype name immediately */
1297 rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1299 else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
1301 if (rangeSubOpclassName != NIL)
1303 (errcode(ERRCODE_SYNTAX_ERROR),
1304 errmsg("conflicting or redundant options")));
1305 rangeSubOpclassName = defGetQualifiedName(defel);
1307 else if (pg_strcasecmp(defel->defname, "collation") == 0)
1309 if (rangeCollationName != NIL)
1311 (errcode(ERRCODE_SYNTAX_ERROR),
1312 errmsg("conflicting or redundant options")));
1313 rangeCollationName = defGetQualifiedName(defel);
1315 else if (pg_strcasecmp(defel->defname, "canonical") == 0)
1317 if (rangeCanonicalName != NIL)
1319 (errcode(ERRCODE_SYNTAX_ERROR),
1320 errmsg("conflicting or redundant options")));
1321 rangeCanonicalName = defGetQualifiedName(defel);
1323 else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
1325 if (rangeSubtypeDiffName != NIL)
1327 (errcode(ERRCODE_SYNTAX_ERROR),
1328 errmsg("conflicting or redundant options")));
1329 rangeSubtypeDiffName = defGetQualifiedName(defel);
1333 (errcode(ERRCODE_SYNTAX_ERROR),
1334 errmsg("type attribute \"%s\" not recognized",
1338 /* Must have a subtype */
1339 if (!OidIsValid(rangeSubtype))
1341 (errcode(ERRCODE_SYNTAX_ERROR),
1342 errmsg("type attribute \"subtype\" is required")));
1343 /* disallow ranges of pseudotypes */
1344 if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
1346 (errcode(ERRCODE_DATATYPE_MISMATCH),
1347 errmsg("range subtype cannot be %s",
1348 format_type_be(rangeSubtype))));
1350 /* Identify subopclass */
1351 rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1353 /* Identify collation to use, if any */
1354 if (type_is_collatable(rangeSubtype))
1356 if (rangeCollationName != NIL)
1357 rangeCollation = get_collation_oid(rangeCollationName, false);
1359 rangeCollation = get_typcollation(rangeSubtype);
1363 if (rangeCollationName != NIL)
1365 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1366 errmsg("range collation specified but subtype does not support collation")));
1367 rangeCollation = InvalidOid;
1370 /* Identify support functions, if provided */
1371 if (rangeCanonicalName != NIL)
1372 rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1375 rangeCanonical = InvalidOid;
1377 if (rangeSubtypeDiffName != NIL)
1378 rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1381 rangeSubtypeDiff = InvalidOid;
1383 get_typlenbyvalalign(rangeSubtype,
1384 &subtyplen, &subtypbyval, &subtypalign);
1386 /* alignment must be 'i' or 'd' for ranges */
1387 alignment = (subtypalign == 'd') ? 'd' : 'i';
1389 /* Allocate OID for array type */
1390 rangeArrayOid = AssignTypeArrayOid();
1392 /* Create the pg_type entry */
1394 TypeCreate(InvalidOid, /* no predetermined type OID */
1395 typeName, /* type name */
1396 typeNamespace, /* namespace */
1397 InvalidOid, /* relation oid (n/a here) */
1398 0, /* relation kind (ditto) */
1399 GetUserId(), /* owner's ID */
1400 -1, /* internal size (always varlena) */
1401 TYPTYPE_RANGE, /* type-type (range type) */
1402 TYPCATEGORY_RANGE, /* type-category (range type) */
1403 false, /* range types are never preferred */
1404 DEFAULT_TYPDELIM, /* array element delimiter */
1405 F_RANGE_IN, /* input procedure */
1406 F_RANGE_OUT, /* output procedure */
1407 F_RANGE_RECV, /* receive procedure */
1408 F_RANGE_SEND, /* send procedure */
1409 InvalidOid, /* typmodin procedure - none */
1410 InvalidOid, /* typmodout procedure - none */
1411 F_RANGE_TYPANALYZE, /* analyze procedure */
1412 InvalidOid, /* element type ID - none */
1413 false, /* this is not an array type */
1414 rangeArrayOid, /* array type we are about to create */
1415 InvalidOid, /* base type ID (only for domains) */
1416 NULL, /* never a default type value */
1417 NULL, /* no binary form available either */
1418 false, /* never passed by value */
1419 alignment, /* alignment */
1420 'x', /* TOAST strategy (always extended) */
1421 -1, /* typMod (Domains only) */
1422 0, /* Array dimensions of typbasetype */
1423 false, /* Type NOT NULL */
1424 InvalidOid); /* type's collation (ranges never have one) */
1426 /* Create the entry in pg_range */
1427 RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1428 rangeCanonical, rangeSubtypeDiff);
1431 * Create the array type that goes with it.
1433 rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1435 TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1436 rangeArrayName, /* type name */
1437 typeNamespace, /* namespace */
1438 InvalidOid, /* relation oid (n/a here) */
1439 0, /* relation kind (ditto) */
1440 GetUserId(), /* owner's ID */
1441 -1, /* internal size (always varlena) */
1442 TYPTYPE_BASE, /* type-type (base type) */
1443 TYPCATEGORY_ARRAY, /* type-category (array) */
1444 false, /* array types are never preferred */
1445 DEFAULT_TYPDELIM, /* array element delimiter */
1446 F_ARRAY_IN, /* input procedure */
1447 F_ARRAY_OUT, /* output procedure */
1448 F_ARRAY_RECV, /* receive procedure */
1449 F_ARRAY_SEND, /* send procedure */
1450 InvalidOid, /* typmodin procedure - none */
1451 InvalidOid, /* typmodout procedure - none */
1452 F_ARRAY_TYPANALYZE, /* analyze procedure */
1453 typoid, /* element type ID */
1454 true, /* yes this is an array type */
1455 InvalidOid, /* no further array type */
1456 InvalidOid, /* base type ID */
1457 NULL, /* never a default type value */
1458 NULL, /* binary default isn't sent either */
1459 false, /* never passed by value */
1460 alignment, /* alignment - same as range's */
1461 'x', /* ARRAY is always toastable */
1462 -1, /* typMod (Domains only) */
1463 0, /* Array dimensions of typbasetype */
1464 false, /* Type NOT NULL */
1465 InvalidOid); /* typcollation */
1467 pfree(rangeArrayName);
1469 /* And create the constructor functions for this range type */
1470 makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1474 * Because there may exist several range types over the same subtype, the
1475 * range type can't be uniquely determined from the subtype. So it's
1476 * impossible to define a polymorphic constructor; we have to generate new
1477 * constructor functions explicitly for each range type.
1479 * We actually define 4 functions, with 0 through 3 arguments. This is just
1480 * to offer more convenience for the user.
1483 makeRangeConstructors(const char *name, Oid namespace,
1484 Oid rangeOid, Oid subtype)
1486 static const char * const prosrc[2] = {"range_constructor2",
1487 "range_constructor3"};
1488 static const int pronargs[2] = {2, 3};
1490 Oid constructorArgTypes[3];
1491 ObjectAddress myself,
1495 constructorArgTypes[0] = subtype;
1496 constructorArgTypes[1] = subtype;
1497 constructorArgTypes[2] = TEXTOID;
1499 referenced.classId = TypeRelationId;
1500 referenced.objectId = rangeOid;
1501 referenced.objectSubId = 0;
1503 for (i = 0; i < lengthof(prosrc); i++)
1505 oidvector *constructorArgTypesVector;
1508 constructorArgTypesVector = buildoidvector(constructorArgTypes,
1511 procOid = ProcedureCreate(name, /* name: same as range type */
1512 namespace, /* namespace */
1513 false, /* replace */
1514 false, /* returns set */
1515 rangeOid, /* return type */
1516 INTERNALlanguageId, /* language */
1517 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1518 prosrc[i], /* prosrc */
1521 false, /* isWindowFunc */
1522 false, /* security_definer */
1523 false, /* leakproof */
1524 false, /* isStrict */
1525 PROVOLATILE_IMMUTABLE, /* volatility */
1526 constructorArgTypesVector, /* parameterTypes */
1527 PointerGetDatum(NULL), /* allParameterTypes */
1528 PointerGetDatum(NULL), /* parameterModes */
1529 PointerGetDatum(NULL), /* parameterNames */
1530 NIL, /* parameterDefaults */
1531 PointerGetDatum(NULL), /* proconfig */
1536 * Make the constructors internally-dependent on the range type so
1537 * that they go away silently when the type is dropped. Note that
1538 * pg_dump depends on this choice to avoid dumping the constructors.
1540 myself.classId = ProcedureRelationId;
1541 myself.objectId = procOid;
1542 myself.objectSubId = 0;
1544 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1550 * Find suitable I/O functions for a type.
1552 * typeOid is the type's OID (which will already exist, if only as a shell
1557 findTypeInputFunction(List *procname, Oid typeOid)
1563 * Input functions can take a single argument of type CSTRING, or three
1564 * arguments (string, typioparam OID, typmod).
1566 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1567 * see this, we issue a warning and fix up the pg_proc entry.
1569 argList[0] = CSTRINGOID;
1571 procOid = LookupFuncName(procname, 1, argList, true);
1572 if (OidIsValid(procOid))
1575 argList[1] = OIDOID;
1576 argList[2] = INT4OID;
1578 procOid = LookupFuncName(procname, 3, argList, true);
1579 if (OidIsValid(procOid))
1582 /* No luck, try it with OPAQUE */
1583 argList[0] = OPAQUEOID;
1585 procOid = LookupFuncName(procname, 1, argList, true);
1587 if (!OidIsValid(procOid))
1589 argList[1] = OIDOID;
1590 argList[2] = INT4OID;
1592 procOid = LookupFuncName(procname, 3, argList, true);
1595 if (OidIsValid(procOid))
1597 /* Found, but must complain and fix the pg_proc entry */
1599 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1600 NameListToString(procname))));
1601 SetFunctionArgType(procOid, 0, CSTRINGOID);
1604 * Need CommandCounterIncrement since DefineType will likely try to
1605 * alter the pg_proc tuple again.
1607 CommandCounterIncrement();
1612 /* Use CSTRING (preferred) in the error message */
1613 argList[0] = CSTRINGOID;
1616 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1617 errmsg("function %s does not exist",
1618 func_signature_string(procname, 1, NIL, argList))));
1620 return InvalidOid; /* keep compiler quiet */
1624 findTypeOutputFunction(List *procname, Oid typeOid)
1630 * Output functions can take a single argument of the type.
1632 * For backwards compatibility we allow OPAQUE in place of the actual type
1633 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1635 argList[0] = typeOid;
1637 procOid = LookupFuncName(procname, 1, argList, true);
1638 if (OidIsValid(procOid))
1641 /* No luck, try it with OPAQUE */
1642 argList[0] = OPAQUEOID;
1644 procOid = LookupFuncName(procname, 1, argList, true);
1646 if (OidIsValid(procOid))
1648 /* Found, but must complain and fix the pg_proc entry */
1650 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1651 NameListToString(procname), format_type_be(typeOid))));
1652 SetFunctionArgType(procOid, 0, typeOid);
1655 * Need CommandCounterIncrement since DefineType will likely try to
1656 * alter the pg_proc tuple again.
1658 CommandCounterIncrement();
1663 /* Use type name, not OPAQUE, in the failure message. */
1664 argList[0] = typeOid;
1667 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1668 errmsg("function %s does not exist",
1669 func_signature_string(procname, 1, NIL, argList))));
1671 return InvalidOid; /* keep compiler quiet */
1675 findTypeReceiveFunction(List *procname, Oid typeOid)
1681 * Receive functions can take a single argument of type INTERNAL, or three
1682 * arguments (internal, typioparam OID, typmod).
1684 argList[0] = INTERNALOID;
1686 procOid = LookupFuncName(procname, 1, argList, true);
1687 if (OidIsValid(procOid))
1690 argList[1] = OIDOID;
1691 argList[2] = INT4OID;
1693 procOid = LookupFuncName(procname, 3, argList, true);
1694 if (OidIsValid(procOid))
1698 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1699 errmsg("function %s does not exist",
1700 func_signature_string(procname, 1, NIL, argList))));
1702 return InvalidOid; /* keep compiler quiet */
1706 findTypeSendFunction(List *procname, Oid typeOid)
1712 * Send functions can take a single argument of the type.
1714 argList[0] = typeOid;
1716 procOid = LookupFuncName(procname, 1, argList, true);
1717 if (OidIsValid(procOid))
1721 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1722 errmsg("function %s does not exist",
1723 func_signature_string(procname, 1, NIL, argList))));
1725 return InvalidOid; /* keep compiler quiet */
1729 findTypeTypmodinFunction(List *procname)
1735 * typmodin functions always take one cstring[] argument and return int4.
1737 argList[0] = CSTRINGARRAYOID;
1739 procOid = LookupFuncName(procname, 1, argList, true);
1740 if (!OidIsValid(procOid))
1742 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1743 errmsg("function %s does not exist",
1744 func_signature_string(procname, 1, NIL, argList))));
1746 if (get_func_rettype(procOid) != INT4OID)
1748 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1749 errmsg("typmod_in function %s must return type \"integer\"",
1750 NameListToString(procname))));
1756 findTypeTypmodoutFunction(List *procname)
1762 * typmodout functions always take one int4 argument and return cstring.
1764 argList[0] = INT4OID;
1766 procOid = LookupFuncName(procname, 1, argList, true);
1767 if (!OidIsValid(procOid))
1769 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1770 errmsg("function %s does not exist",
1771 func_signature_string(procname, 1, NIL, argList))));
1773 if (get_func_rettype(procOid) != CSTRINGOID)
1775 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1776 errmsg("typmod_out function %s must return type \"cstring\"",
1777 NameListToString(procname))));
1783 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1789 * Analyze functions always take one INTERNAL argument and return bool.
1791 argList[0] = INTERNALOID;
1793 procOid = LookupFuncName(procname, 1, argList, true);
1794 if (!OidIsValid(procOid))
1796 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1797 errmsg("function %s does not exist",
1798 func_signature_string(procname, 1, NIL, argList))));
1800 if (get_func_rettype(procOid) != BOOLOID)
1802 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1803 errmsg("type analyze function %s must return type \"boolean\"",
1804 NameListToString(procname))));
1810 * Find suitable support functions and opclasses for a range type.
1814 * Find named btree opclass for subtype, or default btree opclass if
1818 findRangeSubOpclass(List *opcname, Oid subtype)
1825 opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
1828 * Verify that the operator class accepts this datatype. Note we will
1829 * accept binary compatibility.
1831 opInputType = get_opclass_input_type(opcid);
1832 if (!IsBinaryCoercible(subtype, opInputType))
1834 (errcode(ERRCODE_DATATYPE_MISMATCH),
1835 errmsg("operator class \"%s\" does not accept data type %s",
1836 NameListToString(opcname),
1837 format_type_be(subtype))));
1841 opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
1842 if (!OidIsValid(opcid))
1844 /* We spell the error message identically to GetIndexOpClass */
1846 (errcode(ERRCODE_UNDEFINED_OBJECT),
1847 errmsg("data type %s has no default operator class for access method \"%s\"",
1848 format_type_be(subtype), "btree"),
1849 errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
1857 findRangeCanonicalFunction(List *procname, Oid typeOid)
1861 AclResult aclresult;
1864 * Range canonical functions must take and return the range type, and must
1867 argList[0] = typeOid;
1869 procOid = LookupFuncName(procname, 1, argList, true);
1871 if (!OidIsValid(procOid))
1873 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1874 errmsg("function %s does not exist",
1875 func_signature_string(procname, 1, NIL, argList))));
1877 if (get_func_rettype(procOid) != typeOid)
1879 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1880 errmsg("range canonical function %s must return range type",
1881 func_signature_string(procname, 1, NIL, argList))));
1883 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1885 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1886 errmsg("range canonical function %s must be immutable",
1887 func_signature_string(procname, 1, NIL, argList))));
1889 /* Also, range type's creator must have permission to call function */
1890 aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
1891 if (aclresult != ACLCHECK_OK)
1892 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
1898 findRangeSubtypeDiffFunction(List *procname, Oid subtype)
1902 AclResult aclresult;
1905 * Range subtype diff functions must take two arguments of the subtype,
1906 * must return float8, and must be immutable.
1908 argList[0] = subtype;
1909 argList[1] = subtype;
1911 procOid = LookupFuncName(procname, 2, argList, true);
1913 if (!OidIsValid(procOid))
1915 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1916 errmsg("function %s does not exist",
1917 func_signature_string(procname, 2, NIL, argList))));
1919 if (get_func_rettype(procOid) != FLOAT8OID)
1921 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1922 errmsg("range subtype diff function %s must return type double precision",
1923 func_signature_string(procname, 2, NIL, argList))));
1925 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1927 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1928 errmsg("range subtype diff function %s must be immutable",
1929 func_signature_string(procname, 2, NIL, argList))));
1931 /* Also, range type's creator must have permission to call function */
1932 aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
1933 if (aclresult != ACLCHECK_OK)
1934 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
1940 * AssignTypeArrayOid
1942 * Pre-assign the type's array OID for use in pg_type.typarray
1945 AssignTypeArrayOid(void)
1949 /* Use binary-upgrade override for pg_type.typarray, if supplied. */
1950 if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_array_pg_type_oid))
1952 type_array_oid = binary_upgrade_next_array_pg_type_oid;
1953 binary_upgrade_next_array_pg_type_oid = InvalidOid;
1957 Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
1959 type_array_oid = GetNewOid(pg_type);
1960 heap_close(pg_type, AccessShareLock);
1963 return type_array_oid;
1967 /*-------------------------------------------------------------------
1968 * DefineCompositeType
1970 * Create a Composite Type relation.
1971 * `DefineRelation' does all the work, we just provide the correct
1974 * If the relation already exists, then 'DefineRelation' will abort
1977 * DefineCompositeType returns relid for use when creating
1978 * an implicit composite type during function creation
1979 *-------------------------------------------------------------------
1982 DefineCompositeType(RangeVar *typevar, List *coldeflist)
1984 CreateStmt *createStmt = makeNode(CreateStmt);
1990 * now set the parameters for keys/inheritance etc. All of these are
1991 * uninteresting for composite types...
1993 createStmt->relation = typevar;
1994 createStmt->tableElts = coldeflist;
1995 createStmt->inhRelations = NIL;
1996 createStmt->constraints = NIL;
1997 createStmt->options = list_make1(defWithOids(false));
1998 createStmt->oncommit = ONCOMMIT_NOOP;
1999 createStmt->tablespacename = NULL;
2000 createStmt->if_not_exists = false;
2003 * Check for collision with an existing type name. If there is one and
2004 * it's an autogenerated array, we can rename it out of the way. This
2005 * check is here mainly to get a better error message about a "type"
2006 * instead of below about a "relation".
2008 typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2010 RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2012 GetSysCacheOid2(TYPENAMENSP,
2013 CStringGetDatum(createStmt->relation->relname),
2014 ObjectIdGetDatum(typeNamespace));
2015 if (OidIsValid(old_type_oid))
2017 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2019 (errcode(ERRCODE_DUPLICATE_OBJECT),
2020 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2024 * Finally create the relation. This also creates the type.
2026 relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
2027 Assert(relid != InvalidOid);
2032 * AlterDomainDefault
2034 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
2037 AlterDomainDefault(List *names, Node *defaultRaw)
2045 Node *defaultExpr = NULL; /* NULL if no default specified */
2046 Datum new_record[Natts_pg_type];
2047 bool new_record_nulls[Natts_pg_type];
2048 bool new_record_repl[Natts_pg_type];
2050 Form_pg_type typTup;
2052 /* Make a TypeName so we can use standard type lookup machinery */
2053 typename = makeTypeNameFromNameList(names);
2054 domainoid = typenameTypeId(NULL, typename);
2056 /* Look up the domain in the type table */
2057 rel = heap_open(TypeRelationId, RowExclusiveLock);
2059 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2060 if (!HeapTupleIsValid(tup))
2061 elog(ERROR, "cache lookup failed for type %u", domainoid);
2062 typTup = (Form_pg_type) GETSTRUCT(tup);
2064 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2065 checkDomainOwner(tup);
2067 /* Setup new tuple */
2068 MemSet(new_record, (Datum) 0, sizeof(new_record));
2069 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2070 MemSet(new_record_repl, false, sizeof(new_record_repl));
2072 /* Store the new default into the tuple */
2075 /* Create a dummy ParseState for transformExpr */
2076 pstate = make_parsestate(NULL);
2079 * Cook the colDef->raw_expr into an expression. Note: Name is
2080 * strictly for error message
2082 defaultExpr = cookDefault(pstate, defaultRaw,
2083 typTup->typbasetype,
2085 NameStr(typTup->typname));
2088 * If the expression is just a NULL constant, we treat the command
2089 * like ALTER ... DROP DEFAULT. (But see note for same test in
2092 if (defaultExpr == NULL ||
2093 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
2095 /* Default is NULL, drop it */
2096 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2097 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2098 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2099 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2104 * Expression must be stored as a nodeToString result, but we also
2105 * require a valid textual representation (mainly to make life
2106 * easier for pg_dump).
2108 defaultValue = deparse_expression(defaultExpr,
2109 deparse_context_for(NameStr(typTup->typname),
2114 * Form an updated tuple with the new default and write it back.
2116 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2118 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2119 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2120 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2125 /* ALTER ... DROP DEFAULT */
2126 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2127 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2128 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2129 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2132 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2133 new_record, new_record_nulls,
2136 simple_heap_update(rel, &tup->t_self, newtuple);
2138 CatalogUpdateIndexes(rel, newtuple);
2140 /* Rebuild dependencies */
2141 GenerateTypeDependencies(typTup->typnamespace,
2143 InvalidOid, /* typrelid is n/a */
2144 0, /* relation kind is n/a */
2154 false, /* a domain isn't an implicit array */
2155 typTup->typbasetype,
2156 typTup->typcollation,
2158 true); /* Rebuild is true */
2161 heap_close(rel, NoLock);
2162 heap_freetuple(newtuple);
2166 * AlterDomainNotNull
2168 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2171 AlterDomainNotNull(List *names, bool notNull)
2177 Form_pg_type typTup;
2179 /* Make a TypeName so we can use standard type lookup machinery */
2180 typename = makeTypeNameFromNameList(names);
2181 domainoid = typenameTypeId(NULL, typename);
2183 /* Look up the domain in the type table */
2184 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2186 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2187 if (!HeapTupleIsValid(tup))
2188 elog(ERROR, "cache lookup failed for type %u", domainoid);
2189 typTup = (Form_pg_type) GETSTRUCT(tup);
2191 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2192 checkDomainOwner(tup);
2194 /* Is the domain already set to the desired constraint? */
2195 if (typTup->typnotnull == notNull)
2197 heap_close(typrel, RowExclusiveLock);
2201 /* Adding a NOT NULL constraint requires checking existing columns */
2207 /* Fetch relation list with attributes based on this domain */
2208 /* ShareLock is sufficient to prevent concurrent data changes */
2210 rels = get_rels_with_domain(domainoid, ShareLock);
2214 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2215 Relation testrel = rtc->rel;
2216 TupleDesc tupdesc = RelationGetDescr(testrel);
2220 /* Scan all tuples in this relation */
2221 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2222 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2226 /* Test attributes that are of the domain */
2227 for (i = 0; i < rtc->natts; i++)
2229 int attnum = rtc->atts[i];
2231 if (heap_attisnull(tuple, attnum))
2233 (errcode(ERRCODE_NOT_NULL_VIOLATION),
2234 errmsg("column \"%s\" of table \"%s\" contains null values",
2235 NameStr(tupdesc->attrs[attnum - 1]->attname),
2236 RelationGetRelationName(testrel))));
2241 /* Close each rel after processing, but keep lock */
2242 heap_close(testrel, NoLock);
2247 * Okay to update pg_type row. We can scribble on typTup because it's a
2250 typTup->typnotnull = notNull;
2252 simple_heap_update(typrel, &tup->t_self, tup);
2254 CatalogUpdateIndexes(typrel, tup);
2257 heap_freetuple(tup);
2258 heap_close(typrel, RowExclusiveLock);
2262 * AlterDomainDropConstraint
2264 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2267 AlterDomainDropConstraint(List *names, const char *constrName,
2268 DropBehavior behavior, bool missing_ok)
2275 SysScanDesc conscan;
2280 /* Make a TypeName so we can use standard type lookup machinery */
2281 typename = makeTypeNameFromNameList(names);
2282 domainoid = typenameTypeId(NULL, typename);
2284 /* Look up the domain in the type table */
2285 rel = heap_open(TypeRelationId, RowExclusiveLock);
2287 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2288 if (!HeapTupleIsValid(tup))
2289 elog(ERROR, "cache lookup failed for type %u", domainoid);
2291 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2292 checkDomainOwner(tup);
2294 /* Grab an appropriate lock on the pg_constraint relation */
2295 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2297 /* Use the index to scan only constraints of the target relation */
2298 ScanKeyInit(&key[0],
2299 Anum_pg_constraint_contypid,
2300 BTEqualStrategyNumber, F_OIDEQ,
2301 ObjectIdGetDatum(HeapTupleGetOid(tup)));
2303 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2304 SnapshotNow, 1, key);
2307 * Scan over the result set, removing any matching entries.
2309 while ((contup = systable_getnext(conscan)) != NULL)
2311 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
2313 if (strcmp(NameStr(con->conname), constrName) == 0)
2315 ObjectAddress conobj;
2317 conobj.classId = ConstraintRelationId;
2318 conobj.objectId = HeapTupleGetOid(contup);
2319 conobj.objectSubId = 0;
2321 performDeletion(&conobj, behavior, 0);
2325 /* Clean up after the scan */
2326 systable_endscan(conscan);
2327 heap_close(conrel, RowExclusiveLock);
2329 heap_close(rel, NoLock);
2335 (errcode(ERRCODE_UNDEFINED_OBJECT),
2336 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2337 constrName, TypeNameToString(typename))));
2340 (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2341 constrName, TypeNameToString(typename))));
2346 * AlterDomainAddConstraint
2348 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2351 AlterDomainAddConstraint(List *names, Node *newConstraint)
2357 Form_pg_type typTup;
2361 /* Make a TypeName so we can use standard type lookup machinery */
2362 typename = makeTypeNameFromNameList(names);
2363 domainoid = typenameTypeId(NULL, typename);
2365 /* Look up the domain in the type table */
2366 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2368 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2369 if (!HeapTupleIsValid(tup))
2370 elog(ERROR, "cache lookup failed for type %u", domainoid);
2371 typTup = (Form_pg_type) GETSTRUCT(tup);
2373 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2374 checkDomainOwner(tup);
2376 if (!IsA(newConstraint, Constraint))
2377 elog(ERROR, "unrecognized node type: %d",
2378 (int) nodeTag(newConstraint));
2380 constr = (Constraint *) newConstraint;
2382 switch (constr->contype)
2385 /* processed below */
2390 (errcode(ERRCODE_SYNTAX_ERROR),
2391 errmsg("unique constraints not possible for domains")));
2394 case CONSTR_PRIMARY:
2396 (errcode(ERRCODE_SYNTAX_ERROR),
2397 errmsg("primary key constraints not possible for domains")));
2400 case CONSTR_EXCLUSION:
2402 (errcode(ERRCODE_SYNTAX_ERROR),
2403 errmsg("exclusion constraints not possible for domains")));
2406 case CONSTR_FOREIGN:
2408 (errcode(ERRCODE_SYNTAX_ERROR),
2409 errmsg("foreign key constraints not possible for domains")));
2412 case CONSTR_ATTR_DEFERRABLE:
2413 case CONSTR_ATTR_NOT_DEFERRABLE:
2414 case CONSTR_ATTR_DEFERRED:
2415 case CONSTR_ATTR_IMMEDIATE:
2417 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2418 errmsg("specifying constraint deferrability not supported for domains")));
2422 elog(ERROR, "unrecognized constraint subtype: %d",
2423 (int) constr->contype);
2428 * Since all other constraint types throw errors, this must be a check
2429 * constraint. First, process the constraint expression and add an entry
2433 ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
2434 typTup->typbasetype, typTup->typtypmod,
2435 constr, NameStr(typTup->typname));
2438 * If requested to validate the constraint, test all values stored in the
2439 * attributes based on the domain the constraint is being added to.
2441 if (!constr->skip_validation)
2442 validateDomainConstraint(domainoid, ccbin);
2445 heap_close(typrel, RowExclusiveLock);
2449 * AlterDomainValidateConstraint
2451 * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
2454 AlterDomainValidateConstraint(List *names, char *constrName)
2461 Form_pg_constraint con = NULL;
2462 Form_pg_constraint copy_con;
2469 HeapTuple copyTuple;
2472 /* Make a TypeName so we can use standard type lookup machinery */
2473 typename = makeTypeNameFromNameList(names);
2474 domainoid = typenameTypeId(NULL, typename);
2476 /* Look up the domain in the type table */
2477 typrel = heap_open(TypeRelationId, AccessShareLock);
2479 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2480 if (!HeapTupleIsValid(tup))
2481 elog(ERROR, "cache lookup failed for type %u", domainoid);
2483 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2484 checkDomainOwner(tup);
2487 * Find and check the target constraint
2489 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2491 Anum_pg_constraint_contypid,
2492 BTEqualStrategyNumber, F_OIDEQ,
2493 ObjectIdGetDatum(domainoid));
2494 scan = systable_beginscan(conrel, ConstraintTypidIndexId,
2495 true, SnapshotNow, 1, &key);
2497 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2499 con = (Form_pg_constraint) GETSTRUCT(tuple);
2500 if (strcmp(NameStr(con->conname), constrName) == 0)
2509 (errcode(ERRCODE_UNDEFINED_OBJECT),
2510 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2511 constrName, TypeNameToString(typename))));
2513 if (con->contype != CONSTRAINT_CHECK)
2515 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2516 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2517 constrName, TypeNameToString(typename))));
2519 val = SysCacheGetAttr(CONSTROID, tuple,
2520 Anum_pg_constraint_conbin,
2523 elog(ERROR, "null conbin for constraint %u",
2524 HeapTupleGetOid(tuple));
2525 conbin = TextDatumGetCString(val);
2527 validateDomainConstraint(domainoid, conbin);
2530 * Now update the catalog, while we have the door open.
2532 copyTuple = heap_copytuple(tuple);
2533 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2534 copy_con->convalidated = true;
2535 simple_heap_update(conrel, ©Tuple->t_self, copyTuple);
2536 CatalogUpdateIndexes(conrel, copyTuple);
2537 heap_freetuple(copyTuple);
2539 systable_endscan(scan);
2541 heap_close(typrel, AccessShareLock);
2542 heap_close(conrel, RowExclusiveLock);
2544 ReleaseSysCache(tup);
2548 validateDomainConstraint(Oid domainoid, char *ccbin)
2550 Expr *expr = (Expr *) stringToNode(ccbin);
2554 ExprContext *econtext;
2555 ExprState *exprstate;
2557 /* Need an EState to run ExecEvalExpr */
2558 estate = CreateExecutorState();
2559 econtext = GetPerTupleExprContext(estate);
2561 /* build execution state for expr */
2562 exprstate = ExecPrepareExpr(expr, estate);
2564 /* Fetch relation list with attributes based on this domain */
2565 /* ShareLock is sufficient to prevent concurrent data changes */
2567 rels = get_rels_with_domain(domainoid, ShareLock);
2571 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2572 Relation testrel = rtc->rel;
2573 TupleDesc tupdesc = RelationGetDescr(testrel);
2577 /* Scan all tuples in this relation */
2578 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2579 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2583 /* Test attributes that are of the domain */
2584 for (i = 0; i < rtc->natts; i++)
2586 int attnum = rtc->atts[i];
2591 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2593 econtext->domainValue_datum = d;
2594 econtext->domainValue_isNull = isNull;
2596 conResult = ExecEvalExprSwitchContext(exprstate,
2600 if (!isNull && !DatumGetBool(conResult))
2602 (errcode(ERRCODE_CHECK_VIOLATION),
2603 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2604 NameStr(tupdesc->attrs[attnum - 1]->attname),
2605 RelationGetRelationName(testrel))));
2608 ResetExprContext(econtext);
2612 /* Hold relation lock till commit (XXX bad for concurrency) */
2613 heap_close(testrel, NoLock);
2616 FreeExecutorState(estate);
2620 * get_rels_with_domain
2622 * Fetch all relations / attributes which are using the domain
2624 * The result is a list of RelToCheck structs, one for each distinct
2625 * relation, each containing one or more attribute numbers that are of
2626 * the domain type. We have opened each rel and acquired the specified lock
2629 * We support nested domains by including attributes that are of derived
2630 * domain types. Current callers do not need to distinguish between attributes
2631 * that are of exactly the given domain and those that are of derived domains.
2633 * XXX this is completely broken because there is no way to lock the domain
2634 * to prevent columns from being added or dropped while our command runs.
2635 * We can partially protect against column drops by locking relations as we
2636 * come across them, but there is still a race condition (the window between
2637 * seeing a pg_depend entry and acquiring lock on the relation it references).
2638 * Also, holding locks on all these relations simultaneously creates a non-
2639 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2640 * risk by using the weakest suitable lock (ShareLock for most callers).
2642 * XXX the API for this is not sufficient to support checking domain values
2643 * that are inside composite types or arrays. Currently we just error out
2644 * if a composite type containing the target domain is stored anywhere.
2645 * There are not currently arrays of domains; if there were, we could take
2646 * the same approach, but it'd be nicer to fix it properly.
2648 * Generally used for retrieving a list of tests when adding
2649 * new constraints to a domain.
2652 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2657 SysScanDesc depScan;
2660 Assert(lockmode != NoLock);
2663 * We scan pg_depend to find those things that depend on the domain. (We
2664 * assume we can ignore refobjsubid for a domain.)
2666 depRel = heap_open(DependRelationId, AccessShareLock);
2668 ScanKeyInit(&key[0],
2669 Anum_pg_depend_refclassid,
2670 BTEqualStrategyNumber, F_OIDEQ,
2671 ObjectIdGetDatum(TypeRelationId));
2672 ScanKeyInit(&key[1],
2673 Anum_pg_depend_refobjid,
2674 BTEqualStrategyNumber, F_OIDEQ,
2675 ObjectIdGetDatum(domainOid));
2677 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2678 SnapshotNow, 2, key);
2680 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2682 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2683 RelToCheck *rtc = NULL;
2685 Form_pg_attribute pg_att;
2688 /* Check for directly dependent types --- must be domains */
2689 if (pg_depend->classid == TypeRelationId)
2691 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2694 * Recursively add dependent columns to the output list. This is
2695 * a bit inefficient since we may fail to combine RelToCheck
2696 * entries when attributes of the same rel have different derived
2697 * domain types, but it's probably not worth improving.
2699 result = list_concat(result,
2700 get_rels_with_domain(pg_depend->objid,
2705 /* Else, ignore dependees that aren't user columns of relations */
2706 /* (we assume system columns are never of domain types) */
2707 if (pg_depend->classid != RelationRelationId ||
2708 pg_depend->objsubid <= 0)
2711 /* See if we already have an entry for this relation */
2712 foreach(rellist, result)
2714 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2716 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2725 /* First attribute found for this relation */
2728 /* Acquire requested lock on relation */
2729 rel = relation_open(pg_depend->objid, lockmode);
2732 * Check to see if rowtype is stored anyplace as a composite-type
2733 * column; if so we have to fail, for now anyway.
2735 if (OidIsValid(rel->rd_rel->reltype))
2736 find_composite_type_dependencies(rel->rd_rel->reltype,
2738 format_type_be(domainOid));
2740 /* Otherwise we can ignore views, composite types, etc */
2741 if (rel->rd_rel->relkind != RELKIND_RELATION)
2743 relation_close(rel, lockmode);
2747 /* Build the RelToCheck entry with enough space for all atts */
2748 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2751 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2752 result = lcons(rtc, result);
2756 * Confirm column has not been dropped, and is of the expected type.
2757 * This defends against an ALTER DROP COLUMN occurring just before we
2758 * acquired lock ... but if the whole table were dropped, we'd still
2761 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2763 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2764 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2768 * Okay, add column to result. We store the columns in column-number
2769 * order; this is just a hack to improve predictability of regression
2772 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2775 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2777 rtc->atts[ptr] = rtc->atts[ptr - 1];
2780 rtc->atts[ptr] = pg_depend->objsubid;
2783 systable_endscan(depScan);
2785 relation_close(depRel, AccessShareLock);
2793 * Check that the type is actually a domain and that the current user
2794 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2797 checkDomainOwner(HeapTuple tup)
2799 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2801 /* Check that this is actually a domain */
2802 if (typTup->typtype != TYPTYPE_DOMAIN)
2804 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2805 errmsg("%s is not a domain",
2806 format_type_be(HeapTupleGetOid(tup)))));
2808 /* Permission check: must own type */
2809 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2810 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2811 format_type_be(HeapTupleGetOid(tup)));
2815 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2818 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2819 int typMod, Constraint *constr,
2826 CoerceToDomainValue *domVal;
2829 * Assign or validate constraint name
2831 if (constr->conname)
2833 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2838 (errcode(ERRCODE_DUPLICATE_OBJECT),
2839 errmsg("constraint \"%s\" for domain \"%s\" already exists",
2840 constr->conname, domainName)));
2843 constr->conname = ChooseConstraintName(domainName,
2850 * Convert the A_EXPR in raw_expr into an EXPR
2852 pstate = make_parsestate(NULL);
2855 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2856 * the expression. Note that it will appear to have the type of the base
2857 * type, not the domain. This seems correct since within the check
2858 * expression, we should not assume the input value can be considered a
2859 * member of the domain.
2861 domVal = makeNode(CoerceToDomainValue);
2862 domVal->typeId = baseTypeOid;
2863 domVal->typeMod = typMod;
2864 domVal->collation = get_typcollation(baseTypeOid);
2865 domVal->location = -1; /* will be set when/if used */
2867 pstate->p_value_substitute = (Node *) domVal;
2869 expr = transformExpr(pstate, constr->raw_expr);
2872 * Make sure it yields a boolean result.
2874 expr = coerce_to_boolean(pstate, expr, "CHECK");
2877 * Fix up collation information.
2879 assign_expr_collations(pstate, expr);
2882 * Make sure no outside relations are referred to.
2884 if (list_length(pstate->p_rtable) != 0)
2886 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2887 errmsg("cannot use table references in domain check constraint")));
2890 * Domains don't allow var clauses (this should be redundant with the
2891 * above check, but make it anyway)
2893 if (contain_var_clause(expr))
2895 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2896 errmsg("cannot use table references in domain check constraint")));
2899 * No subplans or aggregates, either...
2901 if (pstate->p_hasSubLinks)
2903 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2904 errmsg("cannot use subquery in check constraint")));
2905 if (pstate->p_hasAggs)
2907 (errcode(ERRCODE_GROUPING_ERROR),
2908 errmsg("cannot use aggregate function in check constraint")));
2909 if (pstate->p_hasWindowFuncs)
2911 (errcode(ERRCODE_WINDOWING_ERROR),
2912 errmsg("cannot use window function in check constraint")));
2915 * Convert to string form for storage.
2917 ccbin = nodeToString(expr);
2920 * Deparse it to produce text for consrc.
2922 * Since VARNOs aren't allowed in domain constraints, relation context
2923 * isn't required as anything other than a shell.
2925 ccsrc = deparse_expression(expr,
2926 deparse_context_for(domainName,
2931 * Store the constraint in pg_constraint
2933 CreateConstraintEntry(constr->conname, /* Constraint Name */
2934 domainNamespace, /* namespace */
2935 CONSTRAINT_CHECK, /* Constraint Type */
2936 false, /* Is Deferrable */
2937 false, /* Is Deferred */
2938 !constr->skip_validation, /* Is Validated */
2939 InvalidOid, /* not a relation constraint */
2942 domainOid, /* domain constraint */
2943 InvalidOid, /* no associated index */
2944 InvalidOid, /* Foreign key fields */
2953 NULL, /* not an exclusion constraint */
2954 expr, /* Tree form of check constraint */
2955 ccbin, /* Binary form of check constraint */
2956 ccsrc, /* Source form of check constraint */
2957 true, /* is local */
2959 false); /* is only */
2962 * Return the compiled constraint expression so the calling routine can
2963 * perform any additional required tests.
2969 * GetDomainConstraints - get a list of the current constraints of domain
2971 * Returns a possibly-empty list of DomainConstraintState nodes.
2973 * This is called by the executor during plan startup for a CoerceToDomain
2974 * expression node. The given constraints will be checked for each value
2975 * passed through the node.
2977 * We allow this to be called for non-domain types, in which case the result
2981 GetDomainConstraints(Oid typeOid)
2984 bool notNull = false;
2987 conRel = heap_open(ConstraintRelationId, AccessShareLock);
2993 Form_pg_type typTup;
2997 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
2998 if (!HeapTupleIsValid(tup))
2999 elog(ERROR, "cache lookup failed for type %u", typeOid);
3000 typTup = (Form_pg_type) GETSTRUCT(tup);
3002 if (typTup->typtype != TYPTYPE_DOMAIN)
3004 /* Not a domain, so done */
3005 ReleaseSysCache(tup);
3009 /* Test for NOT NULL Constraint */
3010 if (typTup->typnotnull)
3013 /* Look for CHECK Constraints on this domain */
3014 ScanKeyInit(&key[0],
3015 Anum_pg_constraint_contypid,
3016 BTEqualStrategyNumber, F_OIDEQ,
3017 ObjectIdGetDatum(typeOid));
3019 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
3020 SnapshotNow, 1, key);
3022 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
3024 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
3028 DomainConstraintState *r;
3030 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
3031 if (c->contype != CONSTRAINT_CHECK)
3035 * Not expecting conbin to be NULL, but we'll test for it anyway
3037 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
3038 conRel->rd_att, &isNull);
3040 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
3041 NameStr(typTup->typname), NameStr(c->conname));
3043 check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
3045 /* ExecInitExpr assumes we've planned the expression */
3046 check_expr = expression_planner(check_expr);
3048 r = makeNode(DomainConstraintState);
3049 r->constrainttype = DOM_CONSTRAINT_CHECK;
3050 r->name = pstrdup(NameStr(c->conname));
3051 r->check_expr = ExecInitExpr(check_expr, NULL);
3054 * use lcons() here because constraints of lower domains should be
3057 result = lcons(r, result);
3060 systable_endscan(scan);
3062 /* loop to next domain in stack */
3063 typeOid = typTup->typbasetype;
3064 ReleaseSysCache(tup);
3067 heap_close(conRel, AccessShareLock);
3070 * Only need to add one NOT NULL check regardless of how many domains in
3071 * the stack request it.
3075 DomainConstraintState *r = makeNode(DomainConstraintState);
3077 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
3078 r->name = pstrdup("NOT NULL");
3079 r->check_expr = NULL;
3081 /* lcons to apply the nullness check FIRST */
3082 result = lcons(r, result);
3090 * Execute ALTER TYPE RENAME
3093 RenameType(RenameStmt *stmt)
3095 List *names = stmt->object;
3096 const char *newTypeName = stmt->newname;
3101 Form_pg_type typTup;
3103 /* Make a TypeName so we can use standard type lookup machinery */
3104 typename = makeTypeNameFromNameList(names);
3105 typeOid = typenameTypeId(NULL, typename);
3107 /* Look up the type in the type table */
3108 rel = heap_open(TypeRelationId, RowExclusiveLock);
3110 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3111 if (!HeapTupleIsValid(tup))
3112 elog(ERROR, "cache lookup failed for type %u", typeOid);
3113 typTup = (Form_pg_type) GETSTRUCT(tup);
3115 /* check permissions on type */
3116 if (!pg_type_ownercheck(typeOid, GetUserId()))
3117 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
3118 format_type_be(typeOid));
3120 /* ALTER DOMAIN used on a non-domain? */
3121 if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3123 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3124 errmsg("\"%s\" is not a domain",
3125 format_type_be(typeOid))));
3128 * If it's a composite type, we need to check that it really is a
3129 * free-standing composite type, and not a table's rowtype. We want people
3130 * to use ALTER TABLE not ALTER TYPE for that case.
3132 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3133 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3135 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3136 errmsg("%s is a table's row type",
3137 format_type_be(typeOid)),
3138 errhint("Use ALTER TABLE instead.")));
3140 /* don't allow direct alteration of array types, either */
3141 if (OidIsValid(typTup->typelem) &&
3142 get_array_type(typTup->typelem) == typeOid)
3144 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3145 errmsg("cannot alter array type %s",
3146 format_type_be(typeOid)),
3147 errhint("You can alter type %s, which will alter the array type as well.",
3148 format_type_be(typTup->typelem))));
3151 * If type is composite we need to rename associated pg_class entry too.
3152 * RenameRelationInternal will call RenameTypeInternal automatically.
3154 if (typTup->typtype == TYPTYPE_COMPOSITE)
3155 RenameRelationInternal(typTup->typrelid, newTypeName);
3157 RenameTypeInternal(typeOid, newTypeName,
3158 typTup->typnamespace);
3161 heap_close(rel, RowExclusiveLock);
3165 * Change the owner of a type.
3168 AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
3175 Form_pg_type typTup;
3176 AclResult aclresult;
3178 rel = heap_open(TypeRelationId, RowExclusiveLock);
3180 /* Make a TypeName so we can use standard type lookup machinery */
3181 typename = makeTypeNameFromNameList(names);
3183 /* Use LookupTypeName here so that shell types can be processed */
3184 tup = LookupTypeName(NULL, typename, NULL);
3187 (errcode(ERRCODE_UNDEFINED_OBJECT),
3188 errmsg("type \"%s\" does not exist",
3189 TypeNameToString(typename))));
3190 typeOid = typeTypeId(tup);
3192 /* Copy the syscache entry so we can scribble on it below */
3193 newtup = heap_copytuple(tup);
3194 ReleaseSysCache(tup);
3196 typTup = (Form_pg_type) GETSTRUCT(tup);
3198 /* Don't allow ALTER DOMAIN on a type */
3199 if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3201 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3202 errmsg("%s is not a domain",
3203 format_type_be(typeOid))));
3206 * If it's a composite type, we need to check that it really is a
3207 * free-standing composite type, and not a table's rowtype. We want people
3208 * to use ALTER TABLE not ALTER TYPE for that case.
3210 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3211 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3213 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3214 errmsg("%s is a table's row type",
3215 format_type_be(typeOid)),
3216 errhint("Use ALTER TABLE instead.")));
3218 /* don't allow direct alteration of array types, either */
3219 if (OidIsValid(typTup->typelem) &&
3220 get_array_type(typTup->typelem) == typeOid)
3222 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3223 errmsg("cannot alter array type %s",
3224 format_type_be(typeOid)),
3225 errhint("You can alter type %s, which will alter the array type as well.",
3226 format_type_be(typTup->typelem))));
3229 * If the new owner is the same as the existing owner, consider the
3230 * command to have succeeded. This is for dump restoration purposes.
3232 if (typTup->typowner != newOwnerId)
3234 /* Superusers can always do it */
3237 /* Otherwise, must be owner of the existing object */
3238 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
3239 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
3240 format_type_be(HeapTupleGetOid(tup)));
3242 /* Must be able to become new owner */
3243 check_is_member_of_role(GetUserId(), newOwnerId);
3245 /* New owner must have CREATE privilege on namespace */
3246 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3249 if (aclresult != ACLCHECK_OK)
3250 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
3251 get_namespace_name(typTup->typnamespace));
3255 * If it's a composite type, invoke ATExecChangeOwner so that we fix
3256 * up the pg_class entry properly. That will call back to
3257 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3259 if (typTup->typtype == TYPTYPE_COMPOSITE)
3260 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3264 * We can just apply the modification directly.
3266 * okay to scribble on typTup because it's a copy
3268 typTup->typowner = newOwnerId;
3270 simple_heap_update(rel, &tup->t_self, tup);
3272 CatalogUpdateIndexes(rel, tup);
3274 /* Update owner dependency reference */
3275 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3277 /* If it has an array type, update that too */
3278 if (OidIsValid(typTup->typarray))
3279 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3284 heap_close(rel, RowExclusiveLock);
3288 * AlterTypeOwnerInternal - change type owner unconditionally
3290 * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
3291 * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
3292 * It assumes the caller has done all needed checks. The function will
3293 * automatically recurse to an array type if the type has one.
3295 * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
3296 * entry (ie, it's not a table rowtype nor an array type).
3299 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
3300 bool hasDependEntry)
3304 Form_pg_type typTup;
3306 rel = heap_open(TypeRelationId, RowExclusiveLock);
3308 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3309 if (!HeapTupleIsValid(tup))
3310 elog(ERROR, "cache lookup failed for type %u", typeOid);
3311 typTup = (Form_pg_type) GETSTRUCT(tup);
3314 * Modify the owner --- okay to scribble on typTup because it's a copy
3316 typTup->typowner = newOwnerId;
3318 simple_heap_update(rel, &tup->t_self, tup);
3320 CatalogUpdateIndexes(rel, tup);
3322 /* Update owner dependency reference, if it has one */
3324 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3326 /* If it has an array type, update that too */
3327 if (OidIsValid(typTup->typarray))
3328 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3331 heap_close(rel, RowExclusiveLock);
3335 * Execute ALTER TYPE SET SCHEMA
3338 AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype)
3344 /* Make a TypeName so we can use standard type lookup machinery */
3345 typename = makeTypeNameFromNameList(names);
3346 typeOid = typenameTypeId(NULL, typename);
3348 /* Don't allow ALTER DOMAIN on a type */
3349 if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3351 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3352 errmsg("%s is not a domain",
3353 format_type_be(typeOid))));
3355 /* get schema OID and check its permissions */
3356 nspOid = LookupCreationNamespace(newschema);
3358 AlterTypeNamespace_oid(typeOid, nspOid);
3362 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid)
3366 /* check permissions on type */
3367 if (!pg_type_ownercheck(typeOid, GetUserId()))
3368 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
3369 format_type_be(typeOid));
3371 /* don't allow direct alteration of array types */
3372 elemOid = get_element_type(typeOid);
3373 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3375 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3376 errmsg("cannot alter array type %s",
3377 format_type_be(typeOid)),
3378 errhint("You can alter type %s, which will alter the array type as well.",
3379 format_type_be(elemOid))));
3381 /* and do the work */
3382 return AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
3386 * Move specified type to new namespace.
3388 * Caller must have already checked privileges.
3390 * The function automatically recurses to process the type's array type,
3391 * if any. isImplicitArray should be TRUE only when doing this internal
3392 * recursion (outside callers must never try to move an array type directly).
3394 * If errorOnTableType is TRUE, the function errors out if the type is
3395 * a table type. ALTER TABLE has to be used to move a table to a new
3398 * Returns the type's old namespace OID.
3401 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
3402 bool isImplicitArray,
3403 bool errorOnTableType)
3407 Form_pg_type typform;
3410 bool isCompositeType;
3412 rel = heap_open(TypeRelationId, RowExclusiveLock);
3414 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3415 if (!HeapTupleIsValid(tup))
3416 elog(ERROR, "cache lookup failed for type %u", typeOid);
3417 typform = (Form_pg_type) GETSTRUCT(tup);
3419 oldNspOid = typform->typnamespace;
3420 arrayOid = typform->typarray;
3422 /* common checks on switching namespaces */
3423 CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
3425 /* check for duplicate name (more friendly than unique-index failure) */
3426 if (SearchSysCacheExists2(TYPENAMENSP,
3427 CStringGetDatum(NameStr(typform->typname)),
3428 ObjectIdGetDatum(nspOid)))
3430 (errcode(ERRCODE_DUPLICATE_OBJECT),
3431 errmsg("type \"%s\" already exists in schema \"%s\"",
3432 NameStr(typform->typname),
3433 get_namespace_name(nspOid))));
3435 /* Detect whether type is a composite type (but not a table rowtype) */
3437 (typform->typtype == TYPTYPE_COMPOSITE &&
3438 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3440 /* Enforce not-table-type if requested */
3441 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3444 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3445 errmsg("%s is a table's row type",
3446 format_type_be(typeOid)),
3447 errhint("Use ALTER TABLE instead.")));
3449 /* OK, modify the pg_type row */
3451 /* tup is a copy, so we can scribble directly on it */
3452 typform->typnamespace = nspOid;
3454 simple_heap_update(rel, &tup->t_self, tup);
3455 CatalogUpdateIndexes(rel, tup);
3458 * Composite types have pg_class entries.
3460 * We need to modify the pg_class tuple as well to reflect the change of
3463 if (isCompositeType)
3467 classRel = heap_open(RelationRelationId, RowExclusiveLock);
3469 AlterRelationNamespaceInternal(classRel, typform->typrelid,
3473 heap_close(classRel, RowExclusiveLock);
3476 * Check for constraints associated with the composite type (we don't
3477 * currently support this, but probably will someday).
3479 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3484 /* If it's a domain, it might have constraints */
3485 if (typform->typtype == TYPTYPE_DOMAIN)
3486 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
3490 * Update dependency on schema, if any --- a table rowtype has not got
3491 * one, and neither does an implicit array.
3493 if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3495 if (changeDependencyFor(TypeRelationId, typeOid,
3496 NamespaceRelationId, oldNspOid, nspOid) != 1)
3497 elog(ERROR, "failed to change schema dependency for type %s",
3498 format_type_be(typeOid));
3500 heap_freetuple(tup);
3502 heap_close(rel, RowExclusiveLock);
3504 /* Recursively alter the associated array type, if any */
3505 if (OidIsValid(arrayOid))
3506 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);