1 /*-------------------------------------------------------------------------
4 * Routines for SQL commands that manipulate types (and domains).
6 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/commands/typecmds.c
14 * The "DefineFoo" routines take the parse tree and pick out the
15 * appropriate arguments/flags, passing the results to the
16 * corresponding "FooDefine" routines (in src/catalog) that do
17 * the actual catalog-munging. These routines also verify permission
18 * of the user to execute the command.
21 * These things must be defined and committed in the following order:
23 * input/output, recv/send functions
30 *-------------------------------------------------------------------------
34 #include "access/genam.h"
35 #include "access/heapam.h"
36 #include "access/xact.h"
37 #include "catalog/catalog.h"
38 #include "catalog/dependency.h"
39 #include "catalog/heap.h"
40 #include "catalog/indexing.h"
41 #include "catalog/pg_collation.h"
42 #include "catalog/pg_constraint.h"
43 #include "catalog/pg_depend.h"
44 #include "catalog/pg_enum.h"
45 #include "catalog/pg_namespace.h"
46 #include "catalog/pg_type.h"
47 #include "catalog/pg_type_fn.h"
48 #include "commands/defrem.h"
49 #include "commands/tablecmds.h"
50 #include "commands/typecmds.h"
51 #include "executor/executor.h"
52 #include "miscadmin.h"
53 #include "nodes/makefuncs.h"
54 #include "optimizer/planner.h"
55 #include "optimizer/var.h"
56 #include "parser/parse_coerce.h"
57 #include "parser/parse_collate.h"
58 #include "parser/parse_expr.h"
59 #include "parser/parse_func.h"
60 #include "parser/parse_type.h"
61 #include "utils/acl.h"
62 #include "utils/builtins.h"
63 #include "utils/fmgroids.h"
64 #include "utils/lsyscache.h"
65 #include "utils/memutils.h"
66 #include "utils/syscache.h"
67 #include "utils/tqual.h"
70 /* result structure for get_rels_with_domain() */
73 Relation rel; /* opened and locked relation */
74 int natts; /* number of attributes of interest */
75 int *atts; /* attribute numbers */
76 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
79 /* Potentially set by contrib/pg_upgrade_support functions */
80 Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
82 static Oid findTypeInputFunction(List *procname, Oid typeOid);
83 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
84 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
85 static Oid findTypeSendFunction(List *procname, Oid typeOid);
86 static Oid findTypeTypmodinFunction(List *procname);
87 static Oid findTypeTypmodoutFunction(List *procname);
88 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
89 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
90 static void checkDomainOwner(HeapTuple tup);
91 static void checkEnumOwner(HeapTuple tup);
92 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
94 int typMod, Constraint *constr,
100 * Registers a new base type.
103 DefineType(List *names, List *parameters)
107 int16 internalLength = -1; /* default: variable-length */
108 List *inputName = NIL;
109 List *outputName = NIL;
110 List *receiveName = NIL;
111 List *sendName = NIL;
112 List *typmodinName = NIL;
113 List *typmodoutName = NIL;
114 List *analyzeName = NIL;
115 char category = TYPCATEGORY_USER;
116 bool preferred = false;
117 char delimiter = DEFAULT_TYPDELIM;
118 Oid elemType = InvalidOid;
119 char *defaultValue = NULL;
120 bool byValue = false;
121 char alignment = 'i'; /* default alignment */
122 char storage = 'p'; /* default TOAST storage method */
123 Oid collation = InvalidOid;
124 DefElem *likeTypeEl = NULL;
125 DefElem *internalLengthEl = NULL;
126 DefElem *inputNameEl = NULL;
127 DefElem *outputNameEl = NULL;
128 DefElem *receiveNameEl = NULL;
129 DefElem *sendNameEl = NULL;
130 DefElem *typmodinNameEl = NULL;
131 DefElem *typmodoutNameEl = NULL;
132 DefElem *analyzeNameEl = NULL;
133 DefElem *categoryEl = NULL;
134 DefElem *preferredEl = NULL;
135 DefElem *delimiterEl = NULL;
136 DefElem *elemTypeEl = NULL;
137 DefElem *defaultValueEl = NULL;
138 DefElem *byValueEl = NULL;
139 DefElem *alignmentEl = NULL;
140 DefElem *storageEl = NULL;
141 DefElem *collatableEl = NULL;
144 Oid receiveOid = InvalidOid;
145 Oid sendOid = InvalidOid;
146 Oid typmodinOid = InvalidOid;
147 Oid typmodoutOid = InvalidOid;
148 Oid analyzeOid = InvalidOid;
156 * As of Postgres 8.4, we require superuser privilege to create a base
157 * type. This is simple paranoia: there are too many ways to mess up the
158 * system with an incorrect type definition (for instance, representation
159 * parameters that don't match what the C code expects). In practice it
160 * takes superuser privilege to create the I/O functions, and so the
161 * former requirement that you own the I/O functions pretty much forced
162 * superuserness anyway. We're just making doubly sure here.
164 * XXX re-enable NOT_USED code sections below if you remove this test.
168 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
169 errmsg("must be superuser to create a base type")));
171 /* Convert list of names to a name and namespace */
172 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
175 /* XXX this is unnecessary given the superuser check above */
176 /* Check we have creation rights in target namespace */
177 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
178 if (aclresult != ACLCHECK_OK)
179 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
180 get_namespace_name(typeNamespace));
184 * Look to see if type already exists (presumably as a shell; if not,
185 * TypeCreate will complain).
187 typoid = GetSysCacheOid2(TYPENAMENSP,
188 CStringGetDatum(typeName),
189 ObjectIdGetDatum(typeNamespace));
192 * If it's not a shell, see if it's an autogenerated array type, and if so
193 * rename it out of the way.
195 if (OidIsValid(typoid) && get_typisdefined(typoid))
197 if (moveArrayTypeName(typoid, typeName, typeNamespace))
202 * If it doesn't exist, create it as a shell, so that the OID is known for
203 * use in the I/O function definitions.
205 if (!OidIsValid(typoid))
207 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
208 /* Make new shell type visible for modification below */
209 CommandCounterIncrement();
212 * If the command was a parameterless CREATE TYPE, we're done ---
213 * creating the shell type was all we're supposed to do.
215 if (parameters == NIL)
220 /* Complain if dummy CREATE TYPE and entry already exists */
221 if (parameters == NIL)
223 (errcode(ERRCODE_DUPLICATE_OBJECT),
224 errmsg("type \"%s\" already exists", typeName)));
227 /* Extract the parameters from the parameter list */
228 foreach(pl, parameters)
230 DefElem *defel = (DefElem *) lfirst(pl);
233 if (pg_strcasecmp(defel->defname, "like") == 0)
234 defelp = &likeTypeEl;
235 else if (pg_strcasecmp(defel->defname, "internallength") == 0)
236 defelp = &internalLengthEl;
237 else if (pg_strcasecmp(defel->defname, "input") == 0)
238 defelp = &inputNameEl;
239 else if (pg_strcasecmp(defel->defname, "output") == 0)
240 defelp = &outputNameEl;
241 else if (pg_strcasecmp(defel->defname, "receive") == 0)
242 defelp = &receiveNameEl;
243 else if (pg_strcasecmp(defel->defname, "send") == 0)
244 defelp = &sendNameEl;
245 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
246 defelp = &typmodinNameEl;
247 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
248 defelp = &typmodoutNameEl;
249 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
250 pg_strcasecmp(defel->defname, "analyse") == 0)
251 defelp = &analyzeNameEl;
252 else if (pg_strcasecmp(defel->defname, "category") == 0)
253 defelp = &categoryEl;
254 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
255 defelp = &preferredEl;
256 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
257 defelp = &delimiterEl;
258 else if (pg_strcasecmp(defel->defname, "element") == 0)
259 defelp = &elemTypeEl;
260 else if (pg_strcasecmp(defel->defname, "default") == 0)
261 defelp = &defaultValueEl;
262 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
264 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
265 defelp = &alignmentEl;
266 else if (pg_strcasecmp(defel->defname, "storage") == 0)
268 else if (pg_strcasecmp(defel->defname, "collatable") == 0)
269 defelp = &collatableEl;
272 /* WARNING, not ERROR, for historical backwards-compatibility */
274 (errcode(ERRCODE_SYNTAX_ERROR),
275 errmsg("type attribute \"%s\" not recognized",
281 (errcode(ERRCODE_SYNTAX_ERROR),
282 errmsg("conflicting or redundant options")));
287 * Now interpret the options; we do this separately so that LIKE can be
288 * overridden by other options regardless of the ordering in the parameter
294 Form_pg_type likeForm;
296 likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
297 likeForm = (Form_pg_type) GETSTRUCT(likeType);
298 internalLength = likeForm->typlen;
299 byValue = likeForm->typbyval;
300 alignment = likeForm->typalign;
301 storage = likeForm->typstorage;
302 ReleaseSysCache(likeType);
304 if (internalLengthEl)
305 internalLength = defGetTypeLength(internalLengthEl);
307 inputName = defGetQualifiedName(inputNameEl);
309 outputName = defGetQualifiedName(outputNameEl);
311 receiveName = defGetQualifiedName(receiveNameEl);
313 sendName = defGetQualifiedName(sendNameEl);
315 typmodinName = defGetQualifiedName(typmodinNameEl);
317 typmodoutName = defGetQualifiedName(typmodoutNameEl);
319 analyzeName = defGetQualifiedName(analyzeNameEl);
322 char *p = defGetString(categoryEl);
325 /* restrict to non-control ASCII */
326 if (category < 32 || category > 126)
328 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
329 errmsg("invalid type category \"%s\": must be simple ASCII",
333 preferred = defGetBoolean(preferredEl);
336 char *p = defGetString(delimiterEl);
339 /* XXX shouldn't we restrict the delimiter? */
343 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
344 /* disallow arrays of pseudotypes */
345 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
347 (errcode(ERRCODE_DATATYPE_MISMATCH),
348 errmsg("array element type cannot be %s",
349 format_type_be(elemType))));
352 defaultValue = defGetString(defaultValueEl);
354 byValue = defGetBoolean(byValueEl);
357 char *a = defGetString(alignmentEl);
360 * Note: if argument was an unquoted identifier, parser will have
361 * applied translations to it, so be prepared to recognize translated
362 * type names as well as the nominal form.
364 if (pg_strcasecmp(a, "double") == 0 ||
365 pg_strcasecmp(a, "float8") == 0 ||
366 pg_strcasecmp(a, "pg_catalog.float8") == 0)
368 else if (pg_strcasecmp(a, "int4") == 0 ||
369 pg_strcasecmp(a, "pg_catalog.int4") == 0)
371 else if (pg_strcasecmp(a, "int2") == 0 ||
372 pg_strcasecmp(a, "pg_catalog.int2") == 0)
374 else if (pg_strcasecmp(a, "char") == 0 ||
375 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
379 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
380 errmsg("alignment \"%s\" not recognized", a)));
384 char *a = defGetString(storageEl);
386 if (pg_strcasecmp(a, "plain") == 0)
388 else if (pg_strcasecmp(a, "external") == 0)
390 else if (pg_strcasecmp(a, "extended") == 0)
392 else if (pg_strcasecmp(a, "main") == 0)
396 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
397 errmsg("storage \"%s\" not recognized", a)));
400 collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
403 * make sure we have our required definitions
405 if (inputName == NIL)
407 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
408 errmsg("type input function must be specified")));
409 if (outputName == NIL)
411 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
412 errmsg("type output function must be specified")));
414 if (typmodinName == NIL && typmodoutName != NIL)
416 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
417 errmsg("type modifier output function is useless without a type modifier input function")));
420 * Convert I/O proc names to OIDs
422 inputOid = findTypeInputFunction(inputName, typoid);
423 outputOid = findTypeOutputFunction(outputName, typoid);
425 receiveOid = findTypeReceiveFunction(receiveName, typoid);
427 sendOid = findTypeSendFunction(sendName, typoid);
430 * Verify that I/O procs return the expected thing. If we see OPAQUE,
431 * complain and change it to the correct type-safe choice.
433 resulttype = get_func_rettype(inputOid);
434 if (resulttype != typoid)
436 if (resulttype == OPAQUEOID)
438 /* backwards-compatibility hack */
440 (errmsg("changing return type of function %s from \"opaque\" to %s",
441 NameListToString(inputName), typeName)));
442 SetFunctionReturnType(inputOid, typoid);
446 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
447 errmsg("type input function %s must return type %s",
448 NameListToString(inputName), typeName)));
450 resulttype = get_func_rettype(outputOid);
451 if (resulttype != CSTRINGOID)
453 if (resulttype == OPAQUEOID)
455 /* backwards-compatibility hack */
457 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
458 NameListToString(outputName))));
459 SetFunctionReturnType(outputOid, CSTRINGOID);
463 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
464 errmsg("type output function %s must return type \"cstring\"",
465 NameListToString(outputName))));
469 resulttype = get_func_rettype(receiveOid);
470 if (resulttype != typoid)
472 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
473 errmsg("type receive function %s must return type %s",
474 NameListToString(receiveName), typeName)));
478 resulttype = get_func_rettype(sendOid);
479 if (resulttype != BYTEAOID)
481 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
482 errmsg("type send function %s must return type \"bytea\"",
483 NameListToString(sendName))));
487 * Convert typmodin/out function proc names to OIDs.
490 typmodinOid = findTypeTypmodinFunction(typmodinName);
492 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
495 * Convert analysis function proc name to an OID. If no analysis function
496 * is specified, we'll use zero to select the built-in default algorithm.
499 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
502 * Check permissions on functions. We choose to require the creator/owner
503 * of a type to also own the underlying functions. Since creating a type
504 * is tantamount to granting public execute access on the functions, the
505 * minimum sane check would be for execute-with-grant-option. But we
506 * don't have a way to make the type go away if the grant option is
507 * revoked, so ownership seems better.
510 /* XXX this is unnecessary given the superuser check above */
511 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
512 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
513 NameListToString(inputName));
514 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
515 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
516 NameListToString(outputName));
517 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
518 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
519 NameListToString(receiveName));
520 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
521 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
522 NameListToString(sendName));
523 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
524 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
525 NameListToString(typmodinName));
526 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
527 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
528 NameListToString(typmodoutName));
529 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
530 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
531 NameListToString(analyzeName));
534 array_oid = AssignTypeArrayOid();
537 * now have TypeCreate do all the real work.
539 * Note: the pg_type.oid is stored in user tables as array elements (base
540 * types) in ArrayType and in composite types in DatumTupleFields. This
541 * oid must be preserved by binary upgrades.
544 TypeCreate(InvalidOid, /* no predetermined type OID */
545 typeName, /* type name */
546 typeNamespace, /* namespace */
547 InvalidOid, /* relation oid (n/a here) */
548 0, /* relation kind (ditto) */
549 GetUserId(), /* owner's ID */
550 internalLength, /* internal size */
551 TYPTYPE_BASE, /* type-type (base type) */
552 category, /* type-category */
553 preferred, /* is it a preferred type? */
554 delimiter, /* array element delimiter */
555 inputOid, /* input procedure */
556 outputOid, /* output procedure */
557 receiveOid, /* receive procedure */
558 sendOid, /* send procedure */
559 typmodinOid, /* typmodin procedure */
560 typmodoutOid, /* typmodout procedure */
561 analyzeOid, /* analyze procedure */
562 elemType, /* element type ID */
563 false, /* this is not an array type */
564 array_oid, /* array type we are about to create */
565 InvalidOid, /* base type ID (only for domains) */
566 defaultValue, /* default type value */
567 NULL, /* no binary form available */
568 byValue, /* passed by value */
569 alignment, /* required alignment */
570 storage, /* TOAST strategy */
571 -1, /* typMod (Domains only) */
572 0, /* Array Dimensions of typbasetype */
573 false, /* Type NOT NULL */
574 collation); /* type's collation */
577 * Create the array type that goes with it.
579 array_type = makeArrayTypeName(typeName, typeNamespace);
581 /* alignment must be 'i' or 'd' for arrays */
582 alignment = (alignment == 'd') ? 'd' : 'i';
584 TypeCreate(array_oid, /* force assignment of this type OID */
585 array_type, /* type name */
586 typeNamespace, /* namespace */
587 InvalidOid, /* relation oid (n/a here) */
588 0, /* relation kind (ditto) */
589 GetUserId(), /* owner's ID */
590 -1, /* internal size (always varlena) */
591 TYPTYPE_BASE, /* type-type (base type) */
592 TYPCATEGORY_ARRAY, /* type-category (array) */
593 false, /* array types are never preferred */
594 delimiter, /* array element delimiter */
595 F_ARRAY_IN, /* input procedure */
596 F_ARRAY_OUT, /* output procedure */
597 F_ARRAY_RECV, /* receive procedure */
598 F_ARRAY_SEND, /* send procedure */
599 typmodinOid, /* typmodin procedure */
600 typmodoutOid, /* typmodout procedure */
601 InvalidOid, /* analyze procedure - default */
602 typoid, /* element type ID */
603 true, /* yes this is an array type */
604 InvalidOid, /* no further array type */
605 InvalidOid, /* base type ID */
606 NULL, /* never a default type value */
607 NULL, /* binary default isn't sent either */
608 false, /* never passed by value */
609 alignment, /* see above */
610 'x', /* ARRAY is always toastable */
611 -1, /* typMod (Domains only) */
612 0, /* Array dimensions of typbasetype */
613 false, /* Type NOT NULL */
614 collation); /* type's collation */
622 * Implements DROP TYPE and DROP DOMAIN
624 * Note: if DOMAIN is specified, we enforce that each type is a domain, but
625 * we don't enforce the converse for DROP TYPE
628 RemoveTypes(DropStmt *drop)
630 ObjectAddresses *objects;
634 * First we identify all the types, then we delete them in a single
635 * performMultipleDeletions() call. This is to avoid unwanted DROP
636 * RESTRICT errors if one of the types depends on another.
638 objects = new_object_addresses();
640 foreach(cell, drop->objects)
642 List *names = (List *) lfirst(cell);
646 ObjectAddress object;
649 /* Make a TypeName so we can use standard type lookup machinery */
650 typename = makeTypeNameFromNameList(names);
652 /* Use LookupTypeName here so that shell types can be removed. */
653 tup = LookupTypeName(NULL, typename, NULL);
656 if (!drop->missing_ok)
659 (errcode(ERRCODE_UNDEFINED_OBJECT),
660 errmsg("type \"%s\" does not exist",
661 TypeNameToString(typename))));
666 (errmsg("type \"%s\" does not exist, skipping",
667 TypeNameToString(typename))));
672 typeoid = typeTypeId(tup);
673 typ = (Form_pg_type) GETSTRUCT(tup);
675 /* Permission check: must own type or its namespace */
676 if (!pg_type_ownercheck(typeoid, GetUserId()) &&
677 !pg_namespace_ownercheck(typ->typnamespace, GetUserId()))
678 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
679 format_type_be(typeoid));
681 if (drop->removeType == OBJECT_DOMAIN)
683 /* Check that this is actually a domain */
684 if (typ->typtype != TYPTYPE_DOMAIN)
686 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
687 errmsg("\"%s\" is not a domain",
688 TypeNameToString(typename))));
692 * Note: we need no special check for array types here, as the normal
693 * treatment of internal dependencies handles it just fine
696 object.classId = TypeRelationId;
697 object.objectId = typeoid;
698 object.objectSubId = 0;
700 add_exact_object_address(&object, objects);
702 ReleaseSysCache(tup);
705 performMultipleDeletions(objects, drop->behavior);
707 free_object_addresses(objects);
712 * Guts of type deletion.
715 RemoveTypeById(Oid typeOid)
720 relation = heap_open(TypeRelationId, RowExclusiveLock);
722 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
723 if (!HeapTupleIsValid(tup))
724 elog(ERROR, "cache lookup failed for type %u", typeOid);
726 simple_heap_delete(relation, &tup->t_self);
729 * If it is an enum, delete the pg_enum entries too; we don't bother with
730 * making dependency entries for those, so it has to be done "by hand"
733 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
734 EnumValuesDelete(typeOid);
736 ReleaseSysCache(tup);
738 heap_close(relation, RowExclusiveLock);
744 * Registers a new domain.
747 DefineDomain(CreateDomainStmt *stmt)
752 int16 internalLength;
755 Oid receiveProcedure;
757 Oid analyzeProcedure;
766 char *defaultValue = NULL;
767 char *defaultValueBin = NULL;
768 bool saw_default = false;
769 bool typNotNull = false;
770 bool nullDefined = false;
771 int32 typNDims = list_length(stmt->typeName->arrayBounds);
773 List *schema = stmt->constraints;
779 Form_pg_type baseType;
783 /* Convert list of names to a name and namespace */
784 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
787 /* Check we have creation rights in target namespace */
788 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
790 if (aclresult != ACLCHECK_OK)
791 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
792 get_namespace_name(domainNamespace));
795 * Check for collision with an existing type name. If there is one and
796 * it's an autogenerated array, we can rename it out of the way.
798 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
799 CStringGetDatum(domainName),
800 ObjectIdGetDatum(domainNamespace));
801 if (OidIsValid(old_type_oid))
803 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
805 (errcode(ERRCODE_DUPLICATE_OBJECT),
806 errmsg("type \"%s\" already exists", domainName)));
810 * Look up the base type.
812 typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
813 baseType = (Form_pg_type) GETSTRUCT(typeTup);
814 basetypeoid = HeapTupleGetOid(typeTup);
817 * Base type must be a plain base type, another domain or an enum. Domains
818 * over pseudotypes would create a security hole. Domains over composite
819 * types might be made to work in the future, but not today.
821 typtype = baseType->typtype;
822 if (typtype != TYPTYPE_BASE &&
823 typtype != TYPTYPE_DOMAIN &&
824 typtype != TYPTYPE_ENUM)
826 (errcode(ERRCODE_DATATYPE_MISMATCH),
827 errmsg("\"%s\" is not a valid base type for a domain",
828 TypeNameToString(stmt->typeName))));
831 * Identify the collation if any
833 baseColl = baseType->typcollation;
834 if (stmt->collClause)
835 domaincoll = get_collation_oid(stmt->collClause->collname, false);
837 domaincoll = baseColl;
839 /* Complain if COLLATE is applied to an uncollatable type */
840 if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
842 (errcode(ERRCODE_DATATYPE_MISMATCH),
843 errmsg("collations are not supported by type %s",
844 format_type_be(basetypeoid))));
846 /* passed by value */
847 byValue = baseType->typbyval;
849 /* Required Alignment */
850 alignment = baseType->typalign;
853 storage = baseType->typstorage;
856 internalLength = baseType->typlen;
859 category = baseType->typcategory;
861 /* Array element Delimiter */
862 delimiter = baseType->typdelim;
865 inputProcedure = F_DOMAIN_IN;
866 outputProcedure = baseType->typoutput;
867 receiveProcedure = F_DOMAIN_RECV;
868 sendProcedure = baseType->typsend;
870 /* Domains never accept typmods, so no typmodin/typmodout needed */
872 /* Analysis function */
873 analyzeProcedure = baseType->typanalyze;
875 /* Inherited default value */
876 datum = SysCacheGetAttr(TYPEOID, typeTup,
877 Anum_pg_type_typdefault, &isnull);
879 defaultValue = TextDatumGetCString(datum);
881 /* Inherited default binary value */
882 datum = SysCacheGetAttr(TYPEOID, typeTup,
883 Anum_pg_type_typdefaultbin, &isnull);
885 defaultValueBin = TextDatumGetCString(datum);
888 * Run through constraints manually to avoid the additional processing
889 * conducted by DefineRelation() and friends.
891 foreach(listptr, schema)
893 Constraint *constr = lfirst(listptr);
895 if (!IsA(constr, Constraint))
896 elog(ERROR, "unrecognized node type: %d",
897 (int) nodeTag(constr));
898 switch (constr->contype)
903 * The inherited default value may be overridden by the user
904 * with the DEFAULT <expr> clause ... but only once.
908 (errcode(ERRCODE_SYNTAX_ERROR),
909 errmsg("multiple default expressions")));
912 if (constr->raw_expr)
917 /* Create a dummy ParseState for transformExpr */
918 pstate = make_parsestate(NULL);
921 * Cook the constr->raw_expr into an expression. Note:
922 * name is strictly for error message
924 defaultExpr = cookDefault(pstate, constr->raw_expr,
930 * If the expression is just a NULL constant, we treat it
931 * like not having a default.
933 * Note that if the basetype is another domain, we'll see
934 * a CoerceToDomain expr here and not discard the default.
935 * This is critical because the domain default needs to be
936 * retained to override any default that the base domain
939 if (defaultExpr == NULL ||
940 (IsA(defaultExpr, Const) &&
941 ((Const *) defaultExpr)->constisnull))
944 defaultValueBin = NULL;
949 * Expression must be stored as a nodeToString result,
950 * but we also require a valid textual representation
951 * (mainly to make life easier for pg_dump).
954 deparse_expression(defaultExpr,
955 deparse_context_for(domainName,
958 defaultValueBin = nodeToString(defaultExpr);
963 /* No default (can this still happen?) */
965 defaultValueBin = NULL;
970 if (nullDefined && !typNotNull)
972 (errcode(ERRCODE_SYNTAX_ERROR),
973 errmsg("conflicting NULL/NOT NULL constraints")));
979 if (nullDefined && typNotNull)
981 (errcode(ERRCODE_SYNTAX_ERROR),
982 errmsg("conflicting NULL/NOT NULL constraints")));
990 * Check constraints are handled after domain creation, as
991 * they require the Oid of the domain
996 * All else are error cases
1000 (errcode(ERRCODE_SYNTAX_ERROR),
1001 errmsg("unique constraints not possible for domains")));
1004 case CONSTR_PRIMARY:
1006 (errcode(ERRCODE_SYNTAX_ERROR),
1007 errmsg("primary key constraints not possible for domains")));
1010 case CONSTR_EXCLUSION:
1012 (errcode(ERRCODE_SYNTAX_ERROR),
1013 errmsg("exclusion constraints not possible for domains")));
1016 case CONSTR_FOREIGN:
1018 (errcode(ERRCODE_SYNTAX_ERROR),
1019 errmsg("foreign key constraints not possible for domains")));
1022 case CONSTR_ATTR_DEFERRABLE:
1023 case CONSTR_ATTR_NOT_DEFERRABLE:
1024 case CONSTR_ATTR_DEFERRED:
1025 case CONSTR_ATTR_IMMEDIATE:
1027 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1028 errmsg("specifying constraint deferrability not supported for domains")));
1032 elog(ERROR, "unrecognized constraint subtype: %d",
1033 (int) constr->contype);
1039 * Have TypeCreate do all the real work.
1042 TypeCreate(InvalidOid, /* no predetermined type OID */
1043 domainName, /* type name */
1044 domainNamespace, /* namespace */
1045 InvalidOid, /* relation oid (n/a here) */
1046 0, /* relation kind (ditto) */
1047 GetUserId(), /* owner's ID */
1048 internalLength, /* internal size */
1049 TYPTYPE_DOMAIN, /* type-type (domain type) */
1050 category, /* type-category */
1051 false, /* domain types are never preferred */
1052 delimiter, /* array element delimiter */
1053 inputProcedure, /* input procedure */
1054 outputProcedure, /* output procedure */
1055 receiveProcedure, /* receive procedure */
1056 sendProcedure, /* send procedure */
1057 InvalidOid, /* typmodin procedure - none */
1058 InvalidOid, /* typmodout procedure - none */
1059 analyzeProcedure, /* analyze procedure */
1060 InvalidOid, /* no array element type */
1061 false, /* this isn't an array */
1062 InvalidOid, /* no arrays for domains (yet) */
1063 basetypeoid, /* base type ID */
1064 defaultValue, /* default type value (text) */
1065 defaultValueBin, /* default type value (binary) */
1066 byValue, /* passed by value */
1067 alignment, /* required alignment */
1068 storage, /* TOAST strategy */
1069 basetypeMod, /* typeMod value */
1070 typNDims, /* Array dimensions for base type */
1071 typNotNull, /* Type NOT NULL */
1072 domaincoll); /* type's collation */
1075 * Process constraints which refer to the domain ID returned by TypeCreate
1077 foreach(listptr, schema)
1079 Constraint *constr = lfirst(listptr);
1081 /* it must be a Constraint, per check above */
1083 switch (constr->contype)
1086 domainAddConstraint(domainoid, domainNamespace,
1087 basetypeoid, basetypeMod,
1088 constr, domainName);
1091 /* Other constraint types were fully processed above */
1097 /* CCI so we can detect duplicate constraint names */
1098 CommandCounterIncrement();
1102 * Now we can clean up.
1104 ReleaseSysCache(typeTup);
1110 * Registers a new enum.
1113 DefineEnum(CreateEnumStmt *stmt)
1116 char *enumArrayName;
1119 AclResult aclresult;
1123 /* Convert list of names to a name and namespace */
1124 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1127 /* Check we have creation rights in target namespace */
1128 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1129 if (aclresult != ACLCHECK_OK)
1130 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1131 get_namespace_name(enumNamespace));
1134 * Check for collision with an existing type name. If there is one and
1135 * it's an autogenerated array, we can rename it out of the way.
1137 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1138 CStringGetDatum(enumName),
1139 ObjectIdGetDatum(enumNamespace));
1140 if (OidIsValid(old_type_oid))
1142 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1144 (errcode(ERRCODE_DUPLICATE_OBJECT),
1145 errmsg("type \"%s\" already exists", enumName)));
1148 enumArrayOid = AssignTypeArrayOid();
1150 /* Create the pg_type entry */
1152 TypeCreate(InvalidOid, /* no predetermined type OID */
1153 enumName, /* type name */
1154 enumNamespace, /* namespace */
1155 InvalidOid, /* relation oid (n/a here) */
1156 0, /* relation kind (ditto) */
1157 GetUserId(), /* owner's ID */
1158 sizeof(Oid), /* internal size */
1159 TYPTYPE_ENUM, /* type-type (enum type) */
1160 TYPCATEGORY_ENUM, /* type-category (enum type) */
1161 false, /* enum types are never preferred */
1162 DEFAULT_TYPDELIM, /* array element delimiter */
1163 F_ENUM_IN, /* input procedure */
1164 F_ENUM_OUT, /* output procedure */
1165 F_ENUM_RECV, /* receive procedure */
1166 F_ENUM_SEND, /* send procedure */
1167 InvalidOid, /* typmodin procedure - none */
1168 InvalidOid, /* typmodout procedure - none */
1169 InvalidOid, /* analyze procedure - default */
1170 InvalidOid, /* element type ID */
1171 false, /* this is not an array type */
1172 enumArrayOid, /* array type we are about to create */
1173 InvalidOid, /* base type ID (only for domains) */
1174 NULL, /* never a default type value */
1175 NULL, /* binary default isn't sent either */
1176 true, /* always passed by value */
1177 'i', /* int alignment */
1178 'p', /* TOAST strategy always plain */
1179 -1, /* typMod (Domains only) */
1180 0, /* Array dimensions of typbasetype */
1181 false, /* Type NOT NULL */
1182 InvalidOid); /* type's collation */
1184 /* Enter the enum's values into pg_enum */
1185 EnumValuesCreate(enumTypeOid, stmt->vals);
1188 * Create the array type that goes with it.
1190 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1192 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1193 enumArrayName, /* type name */
1194 enumNamespace, /* namespace */
1195 InvalidOid, /* relation oid (n/a here) */
1196 0, /* relation kind (ditto) */
1197 GetUserId(), /* owner's ID */
1198 -1, /* internal size (always varlena) */
1199 TYPTYPE_BASE, /* type-type (base type) */
1200 TYPCATEGORY_ARRAY, /* type-category (array) */
1201 false, /* array types are never preferred */
1202 DEFAULT_TYPDELIM, /* array element delimiter */
1203 F_ARRAY_IN, /* input procedure */
1204 F_ARRAY_OUT, /* output procedure */
1205 F_ARRAY_RECV, /* receive procedure */
1206 F_ARRAY_SEND, /* send procedure */
1207 InvalidOid, /* typmodin procedure - none */
1208 InvalidOid, /* typmodout procedure - none */
1209 InvalidOid, /* analyze procedure - default */
1210 enumTypeOid, /* element type ID */
1211 true, /* yes this is an array type */
1212 InvalidOid, /* no further array type */
1213 InvalidOid, /* base type ID */
1214 NULL, /* never a default type value */
1215 NULL, /* binary default isn't sent either */
1216 false, /* never passed by value */
1217 'i', /* enums have align i, so do their arrays */
1218 'x', /* ARRAY is always toastable */
1219 -1, /* typMod (Domains only) */
1220 0, /* Array dimensions of typbasetype */
1221 false, /* Type NOT NULL */
1222 InvalidOid); /* type's collation */
1224 pfree(enumArrayName);
1229 * Adds a new label to an existing enum.
1232 AlterEnum(AlterEnumStmt *stmt)
1238 /* Make a TypeName so we can use standard type lookup machinery */
1239 typename = makeTypeNameFromNameList(stmt->typeName);
1240 enum_type_oid = typenameTypeId(NULL, typename);
1242 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1243 if (!HeapTupleIsValid(tup))
1244 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1246 /* Check it's an enum and check user has permission to ALTER the enum */
1247 checkEnumOwner(tup);
1249 /* Add the new label */
1250 AddEnumLabel(enum_type_oid, stmt->newVal,
1251 stmt->newValNeighbor, stmt->newValIsAfter);
1253 ReleaseSysCache(tup);
1260 * Check that the type is actually an enum and that the current user
1261 * has permission to do ALTER TYPE on it. Throw an error if not.
1264 checkEnumOwner(HeapTuple tup)
1266 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1268 /* Check that this is actually an enum */
1269 if (typTup->typtype != TYPTYPE_ENUM)
1271 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1272 errmsg("%s is not an enum",
1273 format_type_be(HeapTupleGetOid(tup)))));
1275 /* Permission check: must own type */
1276 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1277 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
1278 format_type_be(HeapTupleGetOid(tup)));
1283 * Find suitable I/O functions for a type.
1285 * typeOid is the type's OID (which will already exist, if only as a shell
1290 findTypeInputFunction(List *procname, Oid typeOid)
1296 * Input functions can take a single argument of type CSTRING, or three
1297 * arguments (string, typioparam OID, typmod).
1299 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1300 * see this, we issue a warning and fix up the pg_proc entry.
1302 argList[0] = CSTRINGOID;
1304 procOid = LookupFuncName(procname, 1, argList, true);
1305 if (OidIsValid(procOid))
1308 argList[1] = OIDOID;
1309 argList[2] = INT4OID;
1311 procOid = LookupFuncName(procname, 3, argList, true);
1312 if (OidIsValid(procOid))
1315 /* No luck, try it with OPAQUE */
1316 argList[0] = OPAQUEOID;
1318 procOid = LookupFuncName(procname, 1, argList, true);
1320 if (!OidIsValid(procOid))
1322 argList[1] = OIDOID;
1323 argList[2] = INT4OID;
1325 procOid = LookupFuncName(procname, 3, argList, true);
1328 if (OidIsValid(procOid))
1330 /* Found, but must complain and fix the pg_proc entry */
1332 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1333 NameListToString(procname))));
1334 SetFunctionArgType(procOid, 0, CSTRINGOID);
1337 * Need CommandCounterIncrement since DefineType will likely try to
1338 * alter the pg_proc tuple again.
1340 CommandCounterIncrement();
1345 /* Use CSTRING (preferred) in the error message */
1346 argList[0] = CSTRINGOID;
1349 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1350 errmsg("function %s does not exist",
1351 func_signature_string(procname, 1, NIL, argList))));
1353 return InvalidOid; /* keep compiler quiet */
1357 findTypeOutputFunction(List *procname, Oid typeOid)
1363 * Output functions can take a single argument of the type.
1365 * For backwards compatibility we allow OPAQUE in place of the actual type
1366 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1368 argList[0] = typeOid;
1370 procOid = LookupFuncName(procname, 1, argList, true);
1371 if (OidIsValid(procOid))
1374 /* No luck, try it with OPAQUE */
1375 argList[0] = OPAQUEOID;
1377 procOid = LookupFuncName(procname, 1, argList, true);
1379 if (OidIsValid(procOid))
1381 /* Found, but must complain and fix the pg_proc entry */
1383 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1384 NameListToString(procname), format_type_be(typeOid))));
1385 SetFunctionArgType(procOid, 0, typeOid);
1388 * Need CommandCounterIncrement since DefineType will likely try to
1389 * alter the pg_proc tuple again.
1391 CommandCounterIncrement();
1396 /* Use type name, not OPAQUE, in the failure message. */
1397 argList[0] = typeOid;
1400 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1401 errmsg("function %s does not exist",
1402 func_signature_string(procname, 1, NIL, argList))));
1404 return InvalidOid; /* keep compiler quiet */
1408 findTypeReceiveFunction(List *procname, Oid typeOid)
1414 * Receive functions can take a single argument of type INTERNAL, or three
1415 * arguments (internal, typioparam OID, typmod).
1417 argList[0] = INTERNALOID;
1419 procOid = LookupFuncName(procname, 1, argList, true);
1420 if (OidIsValid(procOid))
1423 argList[1] = OIDOID;
1424 argList[2] = INT4OID;
1426 procOid = LookupFuncName(procname, 3, argList, true);
1427 if (OidIsValid(procOid))
1431 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1432 errmsg("function %s does not exist",
1433 func_signature_string(procname, 1, NIL, argList))));
1435 return InvalidOid; /* keep compiler quiet */
1439 findTypeSendFunction(List *procname, Oid typeOid)
1445 * Send functions can take a single argument of the type.
1447 argList[0] = typeOid;
1449 procOid = LookupFuncName(procname, 1, argList, true);
1450 if (OidIsValid(procOid))
1454 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1455 errmsg("function %s does not exist",
1456 func_signature_string(procname, 1, NIL, argList))));
1458 return InvalidOid; /* keep compiler quiet */
1462 findTypeTypmodinFunction(List *procname)
1468 * typmodin functions always take one cstring[] argument and return int4.
1470 argList[0] = CSTRINGARRAYOID;
1472 procOid = LookupFuncName(procname, 1, argList, true);
1473 if (!OidIsValid(procOid))
1475 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1476 errmsg("function %s does not exist",
1477 func_signature_string(procname, 1, NIL, argList))));
1479 if (get_func_rettype(procOid) != INT4OID)
1481 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1482 errmsg("typmod_in function %s must return type \"integer\"",
1483 NameListToString(procname))));
1489 findTypeTypmodoutFunction(List *procname)
1495 * typmodout functions always take one int4 argument and return cstring.
1497 argList[0] = INT4OID;
1499 procOid = LookupFuncName(procname, 1, argList, true);
1500 if (!OidIsValid(procOid))
1502 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1503 errmsg("function %s does not exist",
1504 func_signature_string(procname, 1, NIL, argList))));
1506 if (get_func_rettype(procOid) != CSTRINGOID)
1508 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1509 errmsg("typmod_out function %s must return type \"cstring\"",
1510 NameListToString(procname))));
1516 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1522 * Analyze functions always take one INTERNAL argument and return bool.
1524 argList[0] = INTERNALOID;
1526 procOid = LookupFuncName(procname, 1, argList, true);
1527 if (!OidIsValid(procOid))
1529 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1530 errmsg("function %s does not exist",
1531 func_signature_string(procname, 1, NIL, argList))));
1533 if (get_func_rettype(procOid) != BOOLOID)
1535 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1536 errmsg("type analyze function %s must return type \"boolean\"",
1537 NameListToString(procname))));
1543 * AssignTypeArrayOid
1545 * Pre-assign the type's array OID for use in pg_type.typarray
1548 AssignTypeArrayOid(void)
1552 /* Use binary-upgrade override for pg_type.typarray, if supplied. */
1553 if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_array_pg_type_oid))
1555 type_array_oid = binary_upgrade_next_array_pg_type_oid;
1556 binary_upgrade_next_array_pg_type_oid = InvalidOid;
1560 Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
1562 type_array_oid = GetNewOid(pg_type);
1563 heap_close(pg_type, AccessShareLock);
1566 return type_array_oid;
1570 /*-------------------------------------------------------------------
1571 * DefineCompositeType
1573 * Create a Composite Type relation.
1574 * `DefineRelation' does all the work, we just provide the correct
1577 * If the relation already exists, then 'DefineRelation' will abort
1580 * DefineCompositeType returns relid for use when creating
1581 * an implicit composite type during function creation
1582 *-------------------------------------------------------------------
1585 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1587 CreateStmt *createStmt = makeNode(CreateStmt);
1593 * now set the parameters for keys/inheritance etc. All of these are
1594 * uninteresting for composite types...
1596 createStmt->relation = (RangeVar *) typevar;
1597 createStmt->tableElts = coldeflist;
1598 createStmt->inhRelations = NIL;
1599 createStmt->constraints = NIL;
1600 createStmt->options = list_make1(defWithOids(false));
1601 createStmt->oncommit = ONCOMMIT_NOOP;
1602 createStmt->tablespacename = NULL;
1603 createStmt->if_not_exists = false;
1606 * Check for collision with an existing type name. If there is one and
1607 * it's an autogenerated array, we can rename it out of the way. This
1608 * check is here mainly to get a better error message about a "type"
1609 * instead of below about a "relation".
1611 typeNamespace = RangeVarGetCreationNamespace(createStmt->relation);
1613 GetSysCacheOid2(TYPENAMENSP,
1614 CStringGetDatum(createStmt->relation->relname),
1615 ObjectIdGetDatum(typeNamespace));
1616 if (OidIsValid(old_type_oid))
1618 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
1620 (errcode(ERRCODE_DUPLICATE_OBJECT),
1621 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
1625 * Finally create the relation. This also creates the type.
1627 relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
1628 Assert(relid != InvalidOid);
1633 * AlterDomainDefault
1635 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
1638 AlterDomainDefault(List *names, Node *defaultRaw)
1646 Node *defaultExpr = NULL; /* NULL if no default specified */
1647 Datum new_record[Natts_pg_type];
1648 bool new_record_nulls[Natts_pg_type];
1649 bool new_record_repl[Natts_pg_type];
1651 Form_pg_type typTup;
1653 /* Make a TypeName so we can use standard type lookup machinery */
1654 typename = makeTypeNameFromNameList(names);
1655 domainoid = typenameTypeId(NULL, typename);
1657 /* Look up the domain in the type table */
1658 rel = heap_open(TypeRelationId, RowExclusiveLock);
1660 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1661 if (!HeapTupleIsValid(tup))
1662 elog(ERROR, "cache lookup failed for type %u", domainoid);
1663 typTup = (Form_pg_type) GETSTRUCT(tup);
1665 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1666 checkDomainOwner(tup);
1668 /* Setup new tuple */
1669 MemSet(new_record, (Datum) 0, sizeof(new_record));
1670 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1671 MemSet(new_record_repl, false, sizeof(new_record_repl));
1673 /* Store the new default into the tuple */
1676 /* Create a dummy ParseState for transformExpr */
1677 pstate = make_parsestate(NULL);
1680 * Cook the colDef->raw_expr into an expression. Note: Name is
1681 * strictly for error message
1683 defaultExpr = cookDefault(pstate, defaultRaw,
1684 typTup->typbasetype,
1686 NameStr(typTup->typname));
1689 * If the expression is just a NULL constant, we treat the command
1690 * like ALTER ... DROP DEFAULT. (But see note for same test in
1693 if (defaultExpr == NULL ||
1694 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
1696 /* Default is NULL, drop it */
1697 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
1698 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1699 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
1700 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1705 * Expression must be stored as a nodeToString result, but we also
1706 * require a valid textual representation (mainly to make life
1707 * easier for pg_dump).
1709 defaultValue = deparse_expression(defaultExpr,
1710 deparse_context_for(NameStr(typTup->typname),
1715 * Form an updated tuple with the new default and write it back.
1717 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
1719 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1720 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
1721 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1726 /* ALTER ... DROP DEFAULT */
1727 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
1728 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1729 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
1730 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1733 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
1734 new_record, new_record_nulls,
1737 simple_heap_update(rel, &tup->t_self, newtuple);
1739 CatalogUpdateIndexes(rel, newtuple);
1741 /* Rebuild dependencies */
1742 GenerateTypeDependencies(typTup->typnamespace,
1744 InvalidOid, /* typrelid is n/a */
1745 0, /* relation kind is n/a */
1755 false, /* a domain isn't an implicit array */
1756 typTup->typbasetype,
1757 typTup->typcollation,
1759 true); /* Rebuild is true */
1762 heap_close(rel, NoLock);
1763 heap_freetuple(newtuple);
1767 * AlterDomainNotNull
1769 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
1772 AlterDomainNotNull(List *names, bool notNull)
1778 Form_pg_type typTup;
1780 /* Make a TypeName so we can use standard type lookup machinery */
1781 typename = makeTypeNameFromNameList(names);
1782 domainoid = typenameTypeId(NULL, typename);
1784 /* Look up the domain in the type table */
1785 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1787 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1788 if (!HeapTupleIsValid(tup))
1789 elog(ERROR, "cache lookup failed for type %u", domainoid);
1790 typTup = (Form_pg_type) GETSTRUCT(tup);
1792 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1793 checkDomainOwner(tup);
1795 /* Is the domain already set to the desired constraint? */
1796 if (typTup->typnotnull == notNull)
1798 heap_close(typrel, RowExclusiveLock);
1802 /* Adding a NOT NULL constraint requires checking existing columns */
1808 /* Fetch relation list with attributes based on this domain */
1809 /* ShareLock is sufficient to prevent concurrent data changes */
1811 rels = get_rels_with_domain(domainoid, ShareLock);
1815 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1816 Relation testrel = rtc->rel;
1817 TupleDesc tupdesc = RelationGetDescr(testrel);
1821 /* Scan all tuples in this relation */
1822 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1823 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1827 /* Test attributes that are of the domain */
1828 for (i = 0; i < rtc->natts; i++)
1830 int attnum = rtc->atts[i];
1832 if (heap_attisnull(tuple, attnum))
1834 (errcode(ERRCODE_NOT_NULL_VIOLATION),
1835 errmsg("column \"%s\" of table \"%s\" contains null values",
1836 NameStr(tupdesc->attrs[attnum - 1]->attname),
1837 RelationGetRelationName(testrel))));
1842 /* Close each rel after processing, but keep lock */
1843 heap_close(testrel, NoLock);
1848 * Okay to update pg_type row. We can scribble on typTup because it's a
1851 typTup->typnotnull = notNull;
1853 simple_heap_update(typrel, &tup->t_self, tup);
1855 CatalogUpdateIndexes(typrel, tup);
1858 heap_freetuple(tup);
1859 heap_close(typrel, RowExclusiveLock);
1863 * AlterDomainDropConstraint
1865 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
1868 AlterDomainDropConstraint(List *names, const char *constrName,
1869 DropBehavior behavior)
1876 SysScanDesc conscan;
1880 /* Make a TypeName so we can use standard type lookup machinery */
1881 typename = makeTypeNameFromNameList(names);
1882 domainoid = typenameTypeId(NULL, typename);
1884 /* Look up the domain in the type table */
1885 rel = heap_open(TypeRelationId, RowExclusiveLock);
1887 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1888 if (!HeapTupleIsValid(tup))
1889 elog(ERROR, "cache lookup failed for type %u", domainoid);
1891 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1892 checkDomainOwner(tup);
1894 /* Grab an appropriate lock on the pg_constraint relation */
1895 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
1897 /* Use the index to scan only constraints of the target relation */
1898 ScanKeyInit(&key[0],
1899 Anum_pg_constraint_contypid,
1900 BTEqualStrategyNumber, F_OIDEQ,
1901 ObjectIdGetDatum(HeapTupleGetOid(tup)));
1903 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
1904 SnapshotNow, 1, key);
1907 * Scan over the result set, removing any matching entries.
1909 while ((contup = systable_getnext(conscan)) != NULL)
1911 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
1913 if (strcmp(NameStr(con->conname), constrName) == 0)
1915 ObjectAddress conobj;
1917 conobj.classId = ConstraintRelationId;
1918 conobj.objectId = HeapTupleGetOid(contup);
1919 conobj.objectSubId = 0;
1921 performDeletion(&conobj, behavior);
1924 /* Clean up after the scan */
1925 systable_endscan(conscan);
1926 heap_close(conrel, RowExclusiveLock);
1928 heap_close(rel, NoLock);
1932 * AlterDomainAddConstraint
1934 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
1937 AlterDomainAddConstraint(List *names, Node *newConstraint)
1943 Form_pg_type typTup;
1947 ExprContext *econtext;
1950 ExprState *exprstate;
1953 /* Make a TypeName so we can use standard type lookup machinery */
1954 typename = makeTypeNameFromNameList(names);
1955 domainoid = typenameTypeId(NULL, typename);
1957 /* Look up the domain in the type table */
1958 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1960 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1961 if (!HeapTupleIsValid(tup))
1962 elog(ERROR, "cache lookup failed for type %u", domainoid);
1963 typTup = (Form_pg_type) GETSTRUCT(tup);
1965 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1966 checkDomainOwner(tup);
1968 if (!IsA(newConstraint, Constraint))
1969 elog(ERROR, "unrecognized node type: %d",
1970 (int) nodeTag(newConstraint));
1972 constr = (Constraint *) newConstraint;
1974 switch (constr->contype)
1977 /* processed below */
1982 (errcode(ERRCODE_SYNTAX_ERROR),
1983 errmsg("unique constraints not possible for domains")));
1986 case CONSTR_PRIMARY:
1988 (errcode(ERRCODE_SYNTAX_ERROR),
1989 errmsg("primary key constraints not possible for domains")));
1992 case CONSTR_EXCLUSION:
1994 (errcode(ERRCODE_SYNTAX_ERROR),
1995 errmsg("exclusion constraints not possible for domains")));
1998 case CONSTR_FOREIGN:
2000 (errcode(ERRCODE_SYNTAX_ERROR),
2001 errmsg("foreign key constraints not possible for domains")));
2004 case CONSTR_ATTR_DEFERRABLE:
2005 case CONSTR_ATTR_NOT_DEFERRABLE:
2006 case CONSTR_ATTR_DEFERRED:
2007 case CONSTR_ATTR_IMMEDIATE:
2009 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2010 errmsg("specifying constraint deferrability not supported for domains")));
2014 elog(ERROR, "unrecognized constraint subtype: %d",
2015 (int) constr->contype);
2020 * Since all other constraint types throw errors, this must be a check
2021 * constraint. First, process the constraint expression and add an entry
2025 ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
2026 typTup->typbasetype, typTup->typtypmod,
2027 constr, NameStr(typTup->typname));
2030 * Test all values stored in the attributes based on the domain the
2031 * constraint is being added to.
2033 expr = (Expr *) stringToNode(ccbin);
2035 /* Need an EState to run ExecEvalExpr */
2036 estate = CreateExecutorState();
2037 econtext = GetPerTupleExprContext(estate);
2039 /* build execution state for expr */
2040 exprstate = ExecPrepareExpr(expr, estate);
2042 /* Fetch relation list with attributes based on this domain */
2043 /* ShareLock is sufficient to prevent concurrent data changes */
2045 rels = get_rels_with_domain(domainoid, ShareLock);
2049 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2050 Relation testrel = rtc->rel;
2051 TupleDesc tupdesc = RelationGetDescr(testrel);
2055 /* Scan all tuples in this relation */
2056 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2057 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2061 /* Test attributes that are of the domain */
2062 for (i = 0; i < rtc->natts; i++)
2064 int attnum = rtc->atts[i];
2069 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2071 econtext->domainValue_datum = d;
2072 econtext->domainValue_isNull = isNull;
2074 conResult = ExecEvalExprSwitchContext(exprstate,
2078 if (!isNull && !DatumGetBool(conResult))
2080 (errcode(ERRCODE_CHECK_VIOLATION),
2081 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2082 NameStr(tupdesc->attrs[attnum - 1]->attname),
2083 RelationGetRelationName(testrel))));
2086 ResetExprContext(econtext);
2090 /* Hold relation lock till commit (XXX bad for concurrency) */
2091 heap_close(testrel, NoLock);
2094 FreeExecutorState(estate);
2097 heap_close(typrel, RowExclusiveLock);
2101 * get_rels_with_domain
2103 * Fetch all relations / attributes which are using the domain
2105 * The result is a list of RelToCheck structs, one for each distinct
2106 * relation, each containing one or more attribute numbers that are of
2107 * the domain type. We have opened each rel and acquired the specified lock
2110 * We support nested domains by including attributes that are of derived
2111 * domain types. Current callers do not need to distinguish between attributes
2112 * that are of exactly the given domain and those that are of derived domains.
2114 * XXX this is completely broken because there is no way to lock the domain
2115 * to prevent columns from being added or dropped while our command runs.
2116 * We can partially protect against column drops by locking relations as we
2117 * come across them, but there is still a race condition (the window between
2118 * seeing a pg_depend entry and acquiring lock on the relation it references).
2119 * Also, holding locks on all these relations simultaneously creates a non-
2120 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2121 * risk by using the weakest suitable lock (ShareLock for most callers).
2123 * XXX the API for this is not sufficient to support checking domain values
2124 * that are inside composite types or arrays. Currently we just error out
2125 * if a composite type containing the target domain is stored anywhere.
2126 * There are not currently arrays of domains; if there were, we could take
2127 * the same approach, but it'd be nicer to fix it properly.
2129 * Generally used for retrieving a list of tests when adding
2130 * new constraints to a domain.
2133 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2138 SysScanDesc depScan;
2141 Assert(lockmode != NoLock);
2144 * We scan pg_depend to find those things that depend on the domain. (We
2145 * assume we can ignore refobjsubid for a domain.)
2147 depRel = heap_open(DependRelationId, AccessShareLock);
2149 ScanKeyInit(&key[0],
2150 Anum_pg_depend_refclassid,
2151 BTEqualStrategyNumber, F_OIDEQ,
2152 ObjectIdGetDatum(TypeRelationId));
2153 ScanKeyInit(&key[1],
2154 Anum_pg_depend_refobjid,
2155 BTEqualStrategyNumber, F_OIDEQ,
2156 ObjectIdGetDatum(domainOid));
2158 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2159 SnapshotNow, 2, key);
2161 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2163 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2164 RelToCheck *rtc = NULL;
2166 Form_pg_attribute pg_att;
2169 /* Check for directly dependent types --- must be domains */
2170 if (pg_depend->classid == TypeRelationId)
2172 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2175 * Recursively add dependent columns to the output list. This is
2176 * a bit inefficient since we may fail to combine RelToCheck
2177 * entries when attributes of the same rel have different derived
2178 * domain types, but it's probably not worth improving.
2180 result = list_concat(result,
2181 get_rels_with_domain(pg_depend->objid,
2186 /* Else, ignore dependees that aren't user columns of relations */
2187 /* (we assume system columns are never of domain types) */
2188 if (pg_depend->classid != RelationRelationId ||
2189 pg_depend->objsubid <= 0)
2192 /* See if we already have an entry for this relation */
2193 foreach(rellist, result)
2195 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2197 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2206 /* First attribute found for this relation */
2209 /* Acquire requested lock on relation */
2210 rel = relation_open(pg_depend->objid, lockmode);
2213 * Check to see if rowtype is stored anyplace as a composite-type
2214 * column; if so we have to fail, for now anyway.
2216 if (OidIsValid(rel->rd_rel->reltype))
2217 find_composite_type_dependencies(rel->rd_rel->reltype,
2219 format_type_be(domainOid));
2221 /* Otherwise we can ignore views, composite types, etc */
2222 if (rel->rd_rel->relkind != RELKIND_RELATION)
2224 relation_close(rel, lockmode);
2228 /* Build the RelToCheck entry with enough space for all atts */
2229 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2232 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2233 result = lcons(rtc, result);
2237 * Confirm column has not been dropped, and is of the expected type.
2238 * This defends against an ALTER DROP COLUMN occuring just before we
2239 * acquired lock ... but if the whole table were dropped, we'd still
2242 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2244 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2245 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2249 * Okay, add column to result. We store the columns in column-number
2250 * order; this is just a hack to improve predictability of regression
2253 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2256 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2258 rtc->atts[ptr] = rtc->atts[ptr - 1];
2261 rtc->atts[ptr] = pg_depend->objsubid;
2264 systable_endscan(depScan);
2266 relation_close(depRel, AccessShareLock);
2274 * Check that the type is actually a domain and that the current user
2275 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2278 checkDomainOwner(HeapTuple tup)
2280 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2282 /* Check that this is actually a domain */
2283 if (typTup->typtype != TYPTYPE_DOMAIN)
2285 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2286 errmsg("%s is not a domain",
2287 format_type_be(HeapTupleGetOid(tup)))));
2289 /* Permission check: must own type */
2290 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2291 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2292 format_type_be(HeapTupleGetOid(tup)));
2296 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2299 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2300 int typMod, Constraint *constr,
2307 CoerceToDomainValue *domVal;
2310 * Assign or validate constraint name
2312 if (constr->conname)
2314 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2319 (errcode(ERRCODE_DUPLICATE_OBJECT),
2320 errmsg("constraint \"%s\" for domain \"%s\" already exists",
2321 constr->conname, domainName)));
2324 constr->conname = ChooseConstraintName(domainName,
2331 * Convert the A_EXPR in raw_expr into an EXPR
2333 pstate = make_parsestate(NULL);
2336 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2337 * the expression. Note that it will appear to have the type of the base
2338 * type, not the domain. This seems correct since within the check
2339 * expression, we should not assume the input value can be considered a
2340 * member of the domain.
2342 domVal = makeNode(CoerceToDomainValue);
2343 domVal->typeId = baseTypeOid;
2344 domVal->typeMod = typMod;
2345 domVal->collation = get_typcollation(baseTypeOid);
2346 domVal->location = -1; /* will be set when/if used */
2348 pstate->p_value_substitute = (Node *) domVal;
2350 expr = transformExpr(pstate, constr->raw_expr);
2353 * Make sure it yields a boolean result.
2355 expr = coerce_to_boolean(pstate, expr, "CHECK");
2358 * Fix up collation information.
2360 assign_expr_collations(pstate, expr);
2363 * Make sure no outside relations are referred to.
2365 if (list_length(pstate->p_rtable) != 0)
2367 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2368 errmsg("cannot use table references in domain check constraint")));
2371 * Domains don't allow var clauses (this should be redundant with the
2372 * above check, but make it anyway)
2374 if (contain_var_clause(expr))
2376 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2377 errmsg("cannot use table references in domain check constraint")));
2380 * No subplans or aggregates, either...
2382 if (pstate->p_hasSubLinks)
2384 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2385 errmsg("cannot use subquery in check constraint")));
2386 if (pstate->p_hasAggs)
2388 (errcode(ERRCODE_GROUPING_ERROR),
2389 errmsg("cannot use aggregate function in check constraint")));
2390 if (pstate->p_hasWindowFuncs)
2392 (errcode(ERRCODE_WINDOWING_ERROR),
2393 errmsg("cannot use window function in check constraint")));
2396 * Convert to string form for storage.
2398 ccbin = nodeToString(expr);
2401 * Deparse it to produce text for consrc.
2403 * Since VARNOs aren't allowed in domain constraints, relation context
2404 * isn't required as anything other than a shell.
2406 ccsrc = deparse_expression(expr,
2407 deparse_context_for(domainName,
2412 * Store the constraint in pg_constraint
2414 CreateConstraintEntry(constr->conname, /* Constraint Name */
2415 domainNamespace, /* namespace */
2416 CONSTRAINT_CHECK, /* Constraint Type */
2417 false, /* Is Deferrable */
2418 false, /* Is Deferred */
2419 true, /* Is Validated */
2420 InvalidOid, /* not a relation constraint */
2423 domainOid, /* domain constraint */
2424 InvalidOid, /* no associated index */
2425 InvalidOid, /* Foreign key fields */
2434 NULL, /* not an exclusion constraint */
2435 expr, /* Tree form of check constraint */
2436 ccbin, /* Binary form of check constraint */
2437 ccsrc, /* Source form of check constraint */
2438 true, /* is local */
2442 * Return the compiled constraint expression so the calling routine can
2443 * perform any additional required tests.
2449 * GetDomainConstraints - get a list of the current constraints of domain
2451 * Returns a possibly-empty list of DomainConstraintState nodes.
2453 * This is called by the executor during plan startup for a CoerceToDomain
2454 * expression node. The given constraints will be checked for each value
2455 * passed through the node.
2457 * We allow this to be called for non-domain types, in which case the result
2461 GetDomainConstraints(Oid typeOid)
2464 bool notNull = false;
2467 conRel = heap_open(ConstraintRelationId, AccessShareLock);
2473 Form_pg_type typTup;
2477 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
2478 if (!HeapTupleIsValid(tup))
2479 elog(ERROR, "cache lookup failed for type %u", typeOid);
2480 typTup = (Form_pg_type) GETSTRUCT(tup);
2482 if (typTup->typtype != TYPTYPE_DOMAIN)
2484 /* Not a domain, so done */
2485 ReleaseSysCache(tup);
2489 /* Test for NOT NULL Constraint */
2490 if (typTup->typnotnull)
2493 /* Look for CHECK Constraints on this domain */
2494 ScanKeyInit(&key[0],
2495 Anum_pg_constraint_contypid,
2496 BTEqualStrategyNumber, F_OIDEQ,
2497 ObjectIdGetDatum(typeOid));
2499 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
2500 SnapshotNow, 1, key);
2502 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
2504 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
2508 DomainConstraintState *r;
2510 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
2511 if (c->contype != CONSTRAINT_CHECK)
2515 * Not expecting conbin to be NULL, but we'll test for it anyway
2517 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
2518 conRel->rd_att, &isNull);
2520 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
2521 NameStr(typTup->typname), NameStr(c->conname));
2523 check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
2525 /* ExecInitExpr assumes we've planned the expression */
2526 check_expr = expression_planner(check_expr);
2528 r = makeNode(DomainConstraintState);
2529 r->constrainttype = DOM_CONSTRAINT_CHECK;
2530 r->name = pstrdup(NameStr(c->conname));
2531 r->check_expr = ExecInitExpr(check_expr, NULL);
2534 * use lcons() here because constraints of lower domains should be
2537 result = lcons(r, result);
2540 systable_endscan(scan);
2542 /* loop to next domain in stack */
2543 typeOid = typTup->typbasetype;
2544 ReleaseSysCache(tup);
2547 heap_close(conRel, AccessShareLock);
2550 * Only need to add one NOT NULL check regardless of how many domains in
2551 * the stack request it.
2555 DomainConstraintState *r = makeNode(DomainConstraintState);
2557 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
2558 r->name = pstrdup("NOT NULL");
2559 r->check_expr = NULL;
2561 /* lcons to apply the nullness check FIRST */
2562 result = lcons(r, result);
2570 * Execute ALTER TYPE RENAME
2573 RenameType(List *names, const char *newTypeName)
2579 Form_pg_type typTup;
2581 /* Make a TypeName so we can use standard type lookup machinery */
2582 typename = makeTypeNameFromNameList(names);
2583 typeOid = typenameTypeId(NULL, typename);
2585 /* Look up the type in the type table */
2586 rel = heap_open(TypeRelationId, RowExclusiveLock);
2588 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
2589 if (!HeapTupleIsValid(tup))
2590 elog(ERROR, "cache lookup failed for type %u", typeOid);
2591 typTup = (Form_pg_type) GETSTRUCT(tup);
2593 /* check permissions on type */
2594 if (!pg_type_ownercheck(typeOid, GetUserId()))
2595 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2596 format_type_be(typeOid));
2599 * If it's a composite type, we need to check that it really is a
2600 * free-standing composite type, and not a table's rowtype. We want people
2601 * to use ALTER TABLE not ALTER TYPE for that case.
2603 if (typTup->typtype == TYPTYPE_COMPOSITE &&
2604 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2606 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2607 errmsg("%s is a table's row type",
2608 format_type_be(typeOid)),
2609 errhint("Use ALTER TABLE instead.")));
2611 /* don't allow direct alteration of array types, either */
2612 if (OidIsValid(typTup->typelem) &&
2613 get_array_type(typTup->typelem) == typeOid)
2615 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2616 errmsg("cannot alter array type %s",
2617 format_type_be(typeOid)),
2618 errhint("You can alter type %s, which will alter the array type as well.",
2619 format_type_be(typTup->typelem))));
2622 * If type is composite we need to rename associated pg_class entry too.
2623 * RenameRelationInternal will call RenameTypeInternal automatically.
2625 if (typTup->typtype == TYPTYPE_COMPOSITE)
2626 RenameRelationInternal(typTup->typrelid, newTypeName,
2627 typTup->typnamespace);
2629 RenameTypeInternal(typeOid, newTypeName,
2630 typTup->typnamespace);
2633 heap_close(rel, RowExclusiveLock);
2637 * Change the owner of a type.
2640 AlterTypeOwner(List *names, Oid newOwnerId)
2647 Form_pg_type typTup;
2648 AclResult aclresult;
2650 rel = heap_open(TypeRelationId, RowExclusiveLock);
2652 /* Make a TypeName so we can use standard type lookup machinery */
2653 typename = makeTypeNameFromNameList(names);
2655 /* Use LookupTypeName here so that shell types can be processed */
2656 tup = LookupTypeName(NULL, typename, NULL);
2659 (errcode(ERRCODE_UNDEFINED_OBJECT),
2660 errmsg("type \"%s\" does not exist",
2661 TypeNameToString(typename))));
2662 typeOid = typeTypeId(tup);
2664 /* Copy the syscache entry so we can scribble on it below */
2665 newtup = heap_copytuple(tup);
2666 ReleaseSysCache(tup);
2668 typTup = (Form_pg_type) GETSTRUCT(tup);
2671 * If it's a composite type, we need to check that it really is a
2672 * free-standing composite type, and not a table's rowtype. We want people
2673 * to use ALTER TABLE not ALTER TYPE for that case.
2675 if (typTup->typtype == TYPTYPE_COMPOSITE &&
2676 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2678 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2679 errmsg("%s is a table's row type",
2680 format_type_be(typeOid)),
2681 errhint("Use ALTER TABLE instead.")));
2683 /* don't allow direct alteration of array types, either */
2684 if (OidIsValid(typTup->typelem) &&
2685 get_array_type(typTup->typelem) == typeOid)
2687 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2688 errmsg("cannot alter array type %s",
2689 format_type_be(typeOid)),
2690 errhint("You can alter type %s, which will alter the array type as well.",
2691 format_type_be(typTup->typelem))));
2694 * If the new owner is the same as the existing owner, consider the
2695 * command to have succeeded. This is for dump restoration purposes.
2697 if (typTup->typowner != newOwnerId)
2699 /* Superusers can always do it */
2702 /* Otherwise, must be owner of the existing object */
2703 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2704 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2705 format_type_be(HeapTupleGetOid(tup)));
2707 /* Must be able to become new owner */
2708 check_is_member_of_role(GetUserId(), newOwnerId);
2710 /* New owner must have CREATE privilege on namespace */
2711 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
2714 if (aclresult != ACLCHECK_OK)
2715 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
2716 get_namespace_name(typTup->typnamespace));
2720 * If it's a composite type, invoke ATExecChangeOwner so that we fix
2721 * up the pg_class entry properly. That will call back to
2722 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
2724 if (typTup->typtype == TYPTYPE_COMPOSITE)
2725 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
2729 * We can just apply the modification directly.
2731 * okay to scribble on typTup because it's a copy
2733 typTup->typowner = newOwnerId;
2735 simple_heap_update(rel, &tup->t_self, tup);
2737 CatalogUpdateIndexes(rel, tup);
2739 /* Update owner dependency reference */
2740 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2742 /* If it has an array type, update that too */
2743 if (OidIsValid(typTup->typarray))
2744 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
2749 heap_close(rel, RowExclusiveLock);
2753 * AlterTypeOwnerInternal - change type owner unconditionally
2755 * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
2756 * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
2757 * It assumes the caller has done all needed checks. The function will
2758 * automatically recurse to an array type if the type has one.
2760 * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
2761 * entry (ie, it's not a table rowtype nor an array type).
2764 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
2765 bool hasDependEntry)
2769 Form_pg_type typTup;
2771 rel = heap_open(TypeRelationId, RowExclusiveLock);
2773 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
2774 if (!HeapTupleIsValid(tup))
2775 elog(ERROR, "cache lookup failed for type %u", typeOid);
2776 typTup = (Form_pg_type) GETSTRUCT(tup);
2779 * Modify the owner --- okay to scribble on typTup because it's a copy
2781 typTup->typowner = newOwnerId;
2783 simple_heap_update(rel, &tup->t_self, tup);
2785 CatalogUpdateIndexes(rel, tup);
2787 /* Update owner dependency reference, if it has one */
2789 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2791 /* If it has an array type, update that too */
2792 if (OidIsValid(typTup->typarray))
2793 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
2796 heap_close(rel, RowExclusiveLock);
2800 * Execute ALTER TYPE SET SCHEMA
2803 AlterTypeNamespace(List *names, const char *newschema)
2809 /* Make a TypeName so we can use standard type lookup machinery */
2810 typename = makeTypeNameFromNameList(names);
2811 typeOid = typenameTypeId(NULL, typename);
2813 /* get schema OID and check its permissions */
2814 nspOid = LookupCreationNamespace(newschema);
2816 AlterTypeNamespace_oid(typeOid, nspOid);
2820 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid)
2824 /* check permissions on type */
2825 if (!pg_type_ownercheck(typeOid, GetUserId()))
2826 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2827 format_type_be(typeOid));
2829 /* don't allow direct alteration of array types */
2830 elemOid = get_element_type(typeOid);
2831 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
2833 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2834 errmsg("cannot alter array type %s",
2835 format_type_be(typeOid)),
2836 errhint("You can alter type %s, which will alter the array type as well.",
2837 format_type_be(elemOid))));
2839 /* and do the work */
2840 return AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
2844 * Move specified type to new namespace.
2846 * Caller must have already checked privileges.
2848 * The function automatically recurses to process the type's array type,
2849 * if any. isImplicitArray should be TRUE only when doing this internal
2850 * recursion (outside callers must never try to move an array type directly).
2852 * If errorOnTableType is TRUE, the function errors out if the type is
2853 * a table type. ALTER TABLE has to be used to move a table to a new
2856 * Returns the type's old namespace OID.
2859 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
2860 bool isImplicitArray,
2861 bool errorOnTableType)
2865 Form_pg_type typform;
2868 bool isCompositeType;
2870 rel = heap_open(TypeRelationId, RowExclusiveLock);
2872 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
2873 if (!HeapTupleIsValid(tup))
2874 elog(ERROR, "cache lookup failed for type %u", typeOid);
2875 typform = (Form_pg_type) GETSTRUCT(tup);
2877 oldNspOid = typform->typnamespace;
2878 arrayOid = typform->typarray;
2880 /* common checks on switching namespaces */
2881 CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
2883 /* check for duplicate name (more friendly than unique-index failure) */
2884 if (SearchSysCacheExists2(TYPENAMENSP,
2885 CStringGetDatum(NameStr(typform->typname)),
2886 ObjectIdGetDatum(nspOid)))
2888 (errcode(ERRCODE_DUPLICATE_OBJECT),
2889 errmsg("type \"%s\" already exists in schema \"%s\"",
2890 NameStr(typform->typname),
2891 get_namespace_name(nspOid))));
2893 /* Detect whether type is a composite type (but not a table rowtype) */
2895 (typform->typtype == TYPTYPE_COMPOSITE &&
2896 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
2898 /* Enforce not-table-type if requested */
2899 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
2902 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2903 errmsg("%s is a table's row type",
2904 format_type_be(typeOid)),
2905 errhint("Use ALTER TABLE instead.")));
2907 /* OK, modify the pg_type row */
2909 /* tup is a copy, so we can scribble directly on it */
2910 typform->typnamespace = nspOid;
2912 simple_heap_update(rel, &tup->t_self, tup);
2913 CatalogUpdateIndexes(rel, tup);
2916 * Composite types have pg_class entries.
2918 * We need to modify the pg_class tuple as well to reflect the change of
2921 if (isCompositeType)
2925 classRel = heap_open(RelationRelationId, RowExclusiveLock);
2927 AlterRelationNamespaceInternal(classRel, typform->typrelid,
2931 heap_close(classRel, RowExclusiveLock);
2934 * Check for constraints associated with the composite type (we don't
2935 * currently support this, but probably will someday).
2937 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
2942 /* If it's a domain, it might have constraints */
2943 if (typform->typtype == TYPTYPE_DOMAIN)
2944 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
2948 * Update dependency on schema, if any --- a table rowtype has not got
2949 * one, and neither does an implicit array.
2951 if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
2953 if (changeDependencyFor(TypeRelationId, typeOid,
2954 NamespaceRelationId, oldNspOid, nspOid) != 1)
2955 elog(ERROR, "failed to change schema dependency for type %s",
2956 format_type_be(typeOid));
2958 heap_freetuple(tup);
2960 heap_close(rel, RowExclusiveLock);
2962 /* Recursively alter the associated array type, if any */
2963 if (OidIsValid(arrayOid))
2964 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);