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_expr.h"
58 #include "parser/parse_func.h"
59 #include "parser/parse_type.h"
60 #include "utils/acl.h"
61 #include "utils/builtins.h"
62 #include "utils/fmgroids.h"
63 #include "utils/lsyscache.h"
64 #include "utils/memutils.h"
65 #include "utils/syscache.h"
66 #include "utils/tqual.h"
69 /* result structure for get_rels_with_domain() */
72 Relation rel; /* opened and locked relation */
73 int natts; /* number of attributes of interest */
74 int *atts; /* attribute numbers */
75 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
78 /* Potentially set by contrib/pg_upgrade_support functions */
79 Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
81 static Oid findTypeInputFunction(List *procname, Oid typeOid);
82 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
83 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
84 static Oid findTypeSendFunction(List *procname, Oid typeOid);
85 static Oid findTypeTypmodinFunction(List *procname);
86 static Oid findTypeTypmodoutFunction(List *procname);
87 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
88 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
89 static void checkDomainOwner(HeapTuple tup);
90 static void checkEnumOwner(HeapTuple tup);
91 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
93 int typMod, Constraint *constr,
99 * Registers a new base type.
102 DefineType(List *names, List *parameters)
106 int16 internalLength = -1; /* default: variable-length */
107 List *inputName = NIL;
108 List *outputName = NIL;
109 List *receiveName = NIL;
110 List *sendName = NIL;
111 List *typmodinName = NIL;
112 List *typmodoutName = NIL;
113 List *analyzeName = NIL;
114 char category = TYPCATEGORY_USER;
115 bool preferred = false;
116 char delimiter = DEFAULT_TYPDELIM;
117 Oid elemType = InvalidOid;
118 char *defaultValue = NULL;
119 bool byValue = false;
120 char alignment = 'i'; /* default alignment */
121 char storage = 'p'; /* default TOAST storage method */
122 Oid collation = InvalidOid;
123 DefElem *likeTypeEl = NULL;
124 DefElem *internalLengthEl = NULL;
125 DefElem *inputNameEl = NULL;
126 DefElem *outputNameEl = NULL;
127 DefElem *receiveNameEl = NULL;
128 DefElem *sendNameEl = NULL;
129 DefElem *typmodinNameEl = NULL;
130 DefElem *typmodoutNameEl = NULL;
131 DefElem *analyzeNameEl = NULL;
132 DefElem *categoryEl = NULL;
133 DefElem *preferredEl = NULL;
134 DefElem *delimiterEl = NULL;
135 DefElem *elemTypeEl = NULL;
136 DefElem *defaultValueEl = NULL;
137 DefElem *byValueEl = NULL;
138 DefElem *alignmentEl = NULL;
139 DefElem *storageEl = NULL;
140 DefElem *collatableEl = NULL;
143 Oid receiveOid = InvalidOid;
144 Oid sendOid = InvalidOid;
145 Oid typmodinOid = InvalidOid;
146 Oid typmodoutOid = InvalidOid;
147 Oid analyzeOid = InvalidOid;
155 * As of Postgres 8.4, we require superuser privilege to create a base
156 * type. This is simple paranoia: there are too many ways to mess up the
157 * system with an incorrect type definition (for instance, representation
158 * parameters that don't match what the C code expects). In practice it
159 * takes superuser privilege to create the I/O functions, and so the
160 * former requirement that you own the I/O functions pretty much forced
161 * superuserness anyway. We're just making doubly sure here.
163 * XXX re-enable NOT_USED code sections below if you remove this test.
167 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
168 errmsg("must be superuser to create a base type")));
170 /* Convert list of names to a name and namespace */
171 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
174 /* XXX this is unnecessary given the superuser check above */
175 /* Check we have creation rights in target namespace */
176 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
177 if (aclresult != ACLCHECK_OK)
178 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
179 get_namespace_name(typeNamespace));
183 * Look to see if type already exists (presumably as a shell; if not,
184 * TypeCreate will complain).
186 typoid = GetSysCacheOid2(TYPENAMENSP,
187 CStringGetDatum(typeName),
188 ObjectIdGetDatum(typeNamespace));
191 * If it's not a shell, see if it's an autogenerated array type, and if so
192 * rename it out of the way.
194 if (OidIsValid(typoid) && get_typisdefined(typoid))
196 if (moveArrayTypeName(typoid, typeName, typeNamespace))
201 * If it doesn't exist, create it as a shell, so that the OID is known for
202 * use in the I/O function definitions.
204 if (!OidIsValid(typoid))
206 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
207 /* Make new shell type visible for modification below */
208 CommandCounterIncrement();
211 * If the command was a parameterless CREATE TYPE, we're done ---
212 * creating the shell type was all we're supposed to do.
214 if (parameters == NIL)
219 /* Complain if dummy CREATE TYPE and entry already exists */
220 if (parameters == NIL)
222 (errcode(ERRCODE_DUPLICATE_OBJECT),
223 errmsg("type \"%s\" already exists", typeName)));
226 /* Extract the parameters from the parameter list */
227 foreach(pl, parameters)
229 DefElem *defel = (DefElem *) lfirst(pl);
232 if (pg_strcasecmp(defel->defname, "like") == 0)
233 defelp = &likeTypeEl;
234 else if (pg_strcasecmp(defel->defname, "internallength") == 0)
235 defelp = &internalLengthEl;
236 else if (pg_strcasecmp(defel->defname, "input") == 0)
237 defelp = &inputNameEl;
238 else if (pg_strcasecmp(defel->defname, "output") == 0)
239 defelp = &outputNameEl;
240 else if (pg_strcasecmp(defel->defname, "receive") == 0)
241 defelp = &receiveNameEl;
242 else if (pg_strcasecmp(defel->defname, "send") == 0)
243 defelp = &sendNameEl;
244 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
245 defelp = &typmodinNameEl;
246 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
247 defelp = &typmodoutNameEl;
248 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
249 pg_strcasecmp(defel->defname, "analyse") == 0)
250 defelp = &analyzeNameEl;
251 else if (pg_strcasecmp(defel->defname, "category") == 0)
252 defelp = &categoryEl;
253 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
254 defelp = &preferredEl;
255 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
256 defelp = &delimiterEl;
257 else if (pg_strcasecmp(defel->defname, "element") == 0)
258 defelp = &elemTypeEl;
259 else if (pg_strcasecmp(defel->defname, "default") == 0)
260 defelp = &defaultValueEl;
261 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
263 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
264 defelp = &alignmentEl;
265 else if (pg_strcasecmp(defel->defname, "storage") == 0)
267 else if (pg_strcasecmp(defel->defname, "collatable") == 0)
268 defelp = &collatableEl;
271 /* WARNING, not ERROR, for historical backwards-compatibility */
273 (errcode(ERRCODE_SYNTAX_ERROR),
274 errmsg("type attribute \"%s\" not recognized",
280 (errcode(ERRCODE_SYNTAX_ERROR),
281 errmsg("conflicting or redundant options")));
286 * Now interpret the options; we do this separately so that LIKE can be
287 * overridden by other options regardless of the ordering in the parameter
293 Form_pg_type likeForm;
295 likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL, NULL);
296 likeForm = (Form_pg_type) GETSTRUCT(likeType);
297 internalLength = likeForm->typlen;
298 byValue = likeForm->typbyval;
299 alignment = likeForm->typalign;
300 storage = likeForm->typstorage;
301 ReleaseSysCache(likeType);
303 if (internalLengthEl)
304 internalLength = defGetTypeLength(internalLengthEl);
306 inputName = defGetQualifiedName(inputNameEl);
308 outputName = defGetQualifiedName(outputNameEl);
310 receiveName = defGetQualifiedName(receiveNameEl);
312 sendName = defGetQualifiedName(sendNameEl);
314 typmodinName = defGetQualifiedName(typmodinNameEl);
316 typmodoutName = defGetQualifiedName(typmodoutNameEl);
318 analyzeName = defGetQualifiedName(analyzeNameEl);
321 char *p = defGetString(categoryEl);
324 /* restrict to non-control ASCII */
325 if (category < 32 || category > 126)
327 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
328 errmsg("invalid type category \"%s\": must be simple ASCII",
332 preferred = defGetBoolean(preferredEl);
335 char *p = defGetString(delimiterEl);
338 /* XXX shouldn't we restrict the delimiter? */
342 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
343 /* disallow arrays of pseudotypes */
344 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
346 (errcode(ERRCODE_DATATYPE_MISMATCH),
347 errmsg("array element type cannot be %s",
348 format_type_be(elemType))));
351 defaultValue = defGetString(defaultValueEl);
353 byValue = defGetBoolean(byValueEl);
356 char *a = defGetString(alignmentEl);
359 * Note: if argument was an unquoted identifier, parser will have
360 * applied translations to it, so be prepared to recognize translated
361 * type names as well as the nominal form.
363 if (pg_strcasecmp(a, "double") == 0 ||
364 pg_strcasecmp(a, "float8") == 0 ||
365 pg_strcasecmp(a, "pg_catalog.float8") == 0)
367 else if (pg_strcasecmp(a, "int4") == 0 ||
368 pg_strcasecmp(a, "pg_catalog.int4") == 0)
370 else if (pg_strcasecmp(a, "int2") == 0 ||
371 pg_strcasecmp(a, "pg_catalog.int2") == 0)
373 else if (pg_strcasecmp(a, "char") == 0 ||
374 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
378 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
379 errmsg("alignment \"%s\" not recognized", a)));
383 char *a = defGetString(storageEl);
385 if (pg_strcasecmp(a, "plain") == 0)
387 else if (pg_strcasecmp(a, "external") == 0)
389 else if (pg_strcasecmp(a, "extended") == 0)
391 else if (pg_strcasecmp(a, "main") == 0)
395 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
396 errmsg("storage \"%s\" not recognized", a)));
399 collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
402 * make sure we have our required definitions
404 if (inputName == NIL)
406 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
407 errmsg("type input function must be specified")));
408 if (outputName == NIL)
410 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
411 errmsg("type output function must be specified")));
413 if (typmodinName == NIL && typmodoutName != NIL)
415 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
416 errmsg("type modifier output function is useless without a type modifier input function")));
419 * Convert I/O proc names to OIDs
421 inputOid = findTypeInputFunction(inputName, typoid);
422 outputOid = findTypeOutputFunction(outputName, typoid);
424 receiveOid = findTypeReceiveFunction(receiveName, typoid);
426 sendOid = findTypeSendFunction(sendName, typoid);
429 * Verify that I/O procs return the expected thing. If we see OPAQUE,
430 * complain and change it to the correct type-safe choice.
432 resulttype = get_func_rettype(inputOid);
433 if (resulttype != typoid)
435 if (resulttype == OPAQUEOID)
437 /* backwards-compatibility hack */
439 (errmsg("changing return type of function %s from \"opaque\" to %s",
440 NameListToString(inputName), typeName)));
441 SetFunctionReturnType(inputOid, typoid);
445 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
446 errmsg("type input function %s must return type %s",
447 NameListToString(inputName), typeName)));
449 resulttype = get_func_rettype(outputOid);
450 if (resulttype != CSTRINGOID)
452 if (resulttype == OPAQUEOID)
454 /* backwards-compatibility hack */
456 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
457 NameListToString(outputName))));
458 SetFunctionReturnType(outputOid, CSTRINGOID);
462 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
463 errmsg("type output function %s must return type \"cstring\"",
464 NameListToString(outputName))));
468 resulttype = get_func_rettype(receiveOid);
469 if (resulttype != typoid)
471 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
472 errmsg("type receive function %s must return type %s",
473 NameListToString(receiveName), typeName)));
477 resulttype = get_func_rettype(sendOid);
478 if (resulttype != BYTEAOID)
480 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
481 errmsg("type send function %s must return type \"bytea\"",
482 NameListToString(sendName))));
486 * Convert typmodin/out function proc names to OIDs.
489 typmodinOid = findTypeTypmodinFunction(typmodinName);
491 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
494 * Convert analysis function proc name to an OID. If no analysis function
495 * is specified, we'll use zero to select the built-in default algorithm.
498 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
501 * Check permissions on functions. We choose to require the creator/owner
502 * of a type to also own the underlying functions. Since creating a type
503 * is tantamount to granting public execute access on the functions, the
504 * minimum sane check would be for execute-with-grant-option. But we
505 * don't have a way to make the type go away if the grant option is
506 * revoked, so ownership seems better.
509 /* XXX this is unnecessary given the superuser check above */
510 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
511 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
512 NameListToString(inputName));
513 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
514 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
515 NameListToString(outputName));
516 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
517 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
518 NameListToString(receiveName));
519 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
520 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
521 NameListToString(sendName));
522 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
523 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
524 NameListToString(typmodinName));
525 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
526 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
527 NameListToString(typmodoutName));
528 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
529 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
530 NameListToString(analyzeName));
533 array_oid = AssignTypeArrayOid();
536 * now have TypeCreate do all the real work.
538 * Note: the pg_type.oid is stored in user tables as array elements (base
539 * types) in ArrayType and in composite types in DatumTupleFields. This
540 * oid must be preserved by binary upgrades.
543 TypeCreate(InvalidOid, /* no predetermined type OID */
544 typeName, /* type name */
545 typeNamespace, /* namespace */
546 InvalidOid, /* relation oid (n/a here) */
547 0, /* relation kind (ditto) */
548 GetUserId(), /* owner's ID */
549 internalLength, /* internal size */
550 TYPTYPE_BASE, /* type-type (base type) */
551 category, /* type-category */
552 preferred, /* is it a preferred type? */
553 delimiter, /* array element delimiter */
554 inputOid, /* input procedure */
555 outputOid, /* output procedure */
556 receiveOid, /* receive procedure */
557 sendOid, /* send procedure */
558 typmodinOid, /* typmodin procedure */
559 typmodoutOid, /* typmodout procedure */
560 analyzeOid, /* analyze procedure */
561 elemType, /* element type ID */
562 false, /* this is not an array type */
563 array_oid, /* array type we are about to create */
564 InvalidOid, /* base type ID (only for domains) */
565 defaultValue, /* default type value */
566 NULL, /* no binary form available */
567 byValue, /* passed by value */
568 alignment, /* required alignment */
569 storage, /* TOAST strategy */
570 -1, /* typMod (Domains only) */
571 0, /* Array Dimensions of typbasetype */
572 false, /* Type NOT NULL */
576 * Create the array type that goes with it.
578 array_type = makeArrayTypeName(typeName, typeNamespace);
580 /* alignment must be 'i' or 'd' for arrays */
581 alignment = (alignment == 'd') ? 'd' : 'i';
583 TypeCreate(array_oid, /* force assignment of this type OID */
584 array_type, /* type name */
585 typeNamespace, /* namespace */
586 InvalidOid, /* relation oid (n/a here) */
587 0, /* relation kind (ditto) */
588 GetUserId(), /* owner's ID */
589 -1, /* internal size (always varlena) */
590 TYPTYPE_BASE, /* type-type (base type) */
591 TYPCATEGORY_ARRAY, /* type-category (array) */
592 false, /* array types are never preferred */
593 delimiter, /* array element delimiter */
594 F_ARRAY_IN, /* input procedure */
595 F_ARRAY_OUT, /* output procedure */
596 F_ARRAY_RECV, /* receive procedure */
597 F_ARRAY_SEND, /* send procedure */
598 typmodinOid, /* typmodin procedure */
599 typmodoutOid, /* typmodout procedure */
600 InvalidOid, /* analyze procedure - default */
601 typoid, /* element type ID */
602 true, /* yes this is an array type */
603 InvalidOid, /* no further array type */
604 InvalidOid, /* base type ID */
605 NULL, /* never a default type value */
606 NULL, /* binary default isn't sent either */
607 false, /* never passed by value */
608 alignment, /* see above */
609 'x', /* ARRAY is always toastable */
610 -1, /* typMod (Domains only) */
611 0, /* Array dimensions of typbasetype */
612 false, /* Type NOT NULL */
621 * Implements DROP TYPE and DROP DOMAIN
623 * Note: if DOMAIN is specified, we enforce that each type is a domain, but
624 * we don't enforce the converse for DROP TYPE
627 RemoveTypes(DropStmt *drop)
629 ObjectAddresses *objects;
633 * First we identify all the types, then we delete them in a single
634 * performMultipleDeletions() call. This is to avoid unwanted DROP
635 * RESTRICT errors if one of the types depends on another.
637 objects = new_object_addresses();
639 foreach(cell, drop->objects)
641 List *names = (List *) lfirst(cell);
645 ObjectAddress object;
648 /* Make a TypeName so we can use standard type lookup machinery */
649 typename = makeTypeNameFromNameList(names);
651 /* Use LookupTypeName here so that shell types can be removed. */
652 tup = LookupTypeName(NULL, typename, NULL, NULL);
655 if (!drop->missing_ok)
658 (errcode(ERRCODE_UNDEFINED_OBJECT),
659 errmsg("type \"%s\" does not exist",
660 TypeNameToString(typename))));
665 (errmsg("type \"%s\" does not exist, skipping",
666 TypeNameToString(typename))));
671 typeoid = typeTypeId(tup);
672 typ = (Form_pg_type) GETSTRUCT(tup);
674 /* Permission check: must own type or its namespace */
675 if (!pg_type_ownercheck(typeoid, GetUserId()) &&
676 !pg_namespace_ownercheck(typ->typnamespace, GetUserId()))
677 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
678 format_type_be(typeoid));
680 if (drop->removeType == OBJECT_DOMAIN)
682 /* Check that this is actually a domain */
683 if (typ->typtype != TYPTYPE_DOMAIN)
685 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
686 errmsg("\"%s\" is not a domain",
687 TypeNameToString(typename))));
691 * Note: we need no special check for array types here, as the normal
692 * treatment of internal dependencies handles it just fine
695 object.classId = TypeRelationId;
696 object.objectId = typeoid;
697 object.objectSubId = 0;
699 add_exact_object_address(&object, objects);
701 ReleaseSysCache(tup);
704 performMultipleDeletions(objects, drop->behavior);
706 free_object_addresses(objects);
711 * Guts of type deletion.
714 RemoveTypeById(Oid typeOid)
719 relation = heap_open(TypeRelationId, RowExclusiveLock);
721 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
722 if (!HeapTupleIsValid(tup))
723 elog(ERROR, "cache lookup failed for type %u", typeOid);
725 simple_heap_delete(relation, &tup->t_self);
728 * If it is an enum, delete the pg_enum entries too; we don't bother with
729 * making dependency entries for those, so it has to be done "by hand"
732 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
733 EnumValuesDelete(typeOid);
735 ReleaseSysCache(tup);
737 heap_close(relation, RowExclusiveLock);
743 * Registers a new domain.
746 DefineDomain(CreateDomainStmt *stmt)
751 int16 internalLength;
754 Oid receiveProcedure;
756 Oid analyzeProcedure;
765 char *defaultValue = NULL;
766 char *defaultValueBin = NULL;
767 bool saw_default = false;
768 bool typNotNull = false;
769 bool nullDefined = false;
770 int32 typNDims = list_length(stmt->typeName->arrayBounds);
772 List *schema = stmt->constraints;
777 Form_pg_type baseType;
781 /* Convert list of names to a name and namespace */
782 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
785 /* Check we have creation rights in target namespace */
786 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
788 if (aclresult != ACLCHECK_OK)
789 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
790 get_namespace_name(domainNamespace));
793 * Check for collision with an existing type name. If there is one and
794 * it's an autogenerated array, we can rename it out of the way.
796 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
797 CStringGetDatum(domainName),
798 ObjectIdGetDatum(domainNamespace));
799 if (OidIsValid(old_type_oid))
801 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
803 (errcode(ERRCODE_DUPLICATE_OBJECT),
804 errmsg("type \"%s\" already exists", domainName)));
808 * Look up the base type.
810 typeTup = typenameType(NULL, stmt->typeName, &basetypeMod, &baseColl);
811 baseType = (Form_pg_type) GETSTRUCT(typeTup);
812 basetypeoid = HeapTupleGetOid(typeTup);
815 * Base type must be a plain base type, another domain or an enum. Domains
816 * over pseudotypes would create a security hole. Domains over composite
817 * types might be made to work in the future, but not today.
819 typtype = baseType->typtype;
820 if (typtype != TYPTYPE_BASE &&
821 typtype != TYPTYPE_DOMAIN &&
822 typtype != TYPTYPE_ENUM)
824 (errcode(ERRCODE_DATATYPE_MISMATCH),
825 errmsg("\"%s\" is not a valid base type for a domain",
826 TypeNameToString(stmt->typeName))));
828 /* passed by value */
829 byValue = baseType->typbyval;
831 /* Required Alignment */
832 alignment = baseType->typalign;
835 storage = baseType->typstorage;
838 internalLength = baseType->typlen;
841 category = baseType->typcategory;
843 /* Array element Delimiter */
844 delimiter = baseType->typdelim;
847 inputProcedure = F_DOMAIN_IN;
848 outputProcedure = baseType->typoutput;
849 receiveProcedure = F_DOMAIN_RECV;
850 sendProcedure = baseType->typsend;
852 /* Domains never accept typmods, so no typmodin/typmodout needed */
854 /* Analysis function */
855 analyzeProcedure = baseType->typanalyze;
857 /* Inherited default value */
858 datum = SysCacheGetAttr(TYPEOID, typeTup,
859 Anum_pg_type_typdefault, &isnull);
861 defaultValue = TextDatumGetCString(datum);
863 /* Inherited default binary value */
864 datum = SysCacheGetAttr(TYPEOID, typeTup,
865 Anum_pg_type_typdefaultbin, &isnull);
867 defaultValueBin = TextDatumGetCString(datum);
870 * Run through constraints manually to avoid the additional processing
871 * conducted by DefineRelation() and friends.
873 foreach(listptr, schema)
875 Constraint *constr = lfirst(listptr);
877 if (!IsA(constr, Constraint))
878 elog(ERROR, "unrecognized node type: %d",
879 (int) nodeTag(constr));
880 switch (constr->contype)
885 * The inherited default value may be overridden by the user
886 * with the DEFAULT <expr> clause ... but only once.
890 (errcode(ERRCODE_SYNTAX_ERROR),
891 errmsg("multiple default expressions")));
894 if (constr->raw_expr)
899 /* Create a dummy ParseState for transformExpr */
900 pstate = make_parsestate(NULL);
903 * Cook the constr->raw_expr into an expression. Note:
904 * name is strictly for error message
906 defaultExpr = cookDefault(pstate, constr->raw_expr,
912 * If the expression is just a NULL constant, we treat it
913 * like not having a default.
915 * Note that if the basetype is another domain, we'll see
916 * a CoerceToDomain expr here and not discard the default.
917 * This is critical because the domain default needs to be
918 * retained to override any default that the base domain
921 if (defaultExpr == NULL ||
922 (IsA(defaultExpr, Const) &&
923 ((Const *) defaultExpr)->constisnull))
926 defaultValueBin = NULL;
931 * Expression must be stored as a nodeToString result,
932 * but we also require a valid textual representation
933 * (mainly to make life easier for pg_dump).
936 deparse_expression(defaultExpr,
937 deparse_context_for(domainName,
940 defaultValueBin = nodeToString(defaultExpr);
945 /* No default (can this still happen?) */
947 defaultValueBin = NULL;
952 if (nullDefined && !typNotNull)
954 (errcode(ERRCODE_SYNTAX_ERROR),
955 errmsg("conflicting NULL/NOT NULL constraints")));
961 if (nullDefined && typNotNull)
963 (errcode(ERRCODE_SYNTAX_ERROR),
964 errmsg("conflicting NULL/NOT NULL constraints")));
972 * Check constraints are handled after domain creation, as
973 * they require the Oid of the domain
978 * All else are error cases
982 (errcode(ERRCODE_SYNTAX_ERROR),
983 errmsg("unique constraints not possible for domains")));
988 (errcode(ERRCODE_SYNTAX_ERROR),
989 errmsg("primary key constraints not possible for domains")));
992 case CONSTR_EXCLUSION:
994 (errcode(ERRCODE_SYNTAX_ERROR),
995 errmsg("exclusion constraints not possible for domains")));
1000 (errcode(ERRCODE_SYNTAX_ERROR),
1001 errmsg("foreign key constraints not possible for domains")));
1004 case CONSTR_ATTR_DEFERRABLE:
1005 case CONSTR_ATTR_NOT_DEFERRABLE:
1006 case CONSTR_ATTR_DEFERRED:
1007 case CONSTR_ATTR_IMMEDIATE:
1009 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1010 errmsg("specifying constraint deferrability not supported for domains")));
1014 elog(ERROR, "unrecognized constraint subtype: %d",
1015 (int) constr->contype);
1021 * Have TypeCreate do all the real work.
1024 TypeCreate(InvalidOid, /* no predetermined type OID */
1025 domainName, /* type name */
1026 domainNamespace, /* namespace */
1027 InvalidOid, /* relation oid (n/a here) */
1028 0, /* relation kind (ditto) */
1029 GetUserId(), /* owner's ID */
1030 internalLength, /* internal size */
1031 TYPTYPE_DOMAIN, /* type-type (domain type) */
1032 category, /* type-category */
1033 false, /* domain types are never preferred */
1034 delimiter, /* array element delimiter */
1035 inputProcedure, /* input procedure */
1036 outputProcedure, /* output procedure */
1037 receiveProcedure, /* receive procedure */
1038 sendProcedure, /* send procedure */
1039 InvalidOid, /* typmodin procedure - none */
1040 InvalidOid, /* typmodout procedure - none */
1041 analyzeProcedure, /* analyze procedure */
1042 InvalidOid, /* no array element type */
1043 false, /* this isn't an array */
1044 InvalidOid, /* no arrays for domains (yet) */
1045 basetypeoid, /* base type ID */
1046 defaultValue, /* default type value (text) */
1047 defaultValueBin, /* default type value (binary) */
1048 byValue, /* passed by value */
1049 alignment, /* required alignment */
1050 storage, /* TOAST strategy */
1051 basetypeMod, /* typeMod value */
1052 typNDims, /* Array dimensions for base type */
1053 typNotNull, /* Type NOT NULL */
1057 * Process constraints which refer to the domain ID returned by TypeCreate
1059 foreach(listptr, schema)
1061 Constraint *constr = lfirst(listptr);
1063 /* it must be a Constraint, per check above */
1065 switch (constr->contype)
1068 domainAddConstraint(domainoid, domainNamespace,
1069 basetypeoid, basetypeMod,
1070 constr, domainName);
1073 /* Other constraint types were fully processed above */
1079 /* CCI so we can detect duplicate constraint names */
1080 CommandCounterIncrement();
1084 * Now we can clean up.
1086 ReleaseSysCache(typeTup);
1092 * Registers a new enum.
1095 DefineEnum(CreateEnumStmt *stmt)
1098 char *enumArrayName;
1101 AclResult aclresult;
1105 /* Convert list of names to a name and namespace */
1106 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1109 /* Check we have creation rights in target namespace */
1110 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1111 if (aclresult != ACLCHECK_OK)
1112 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1113 get_namespace_name(enumNamespace));
1116 * Check for collision with an existing type name. If there is one and
1117 * it's an autogenerated array, we can rename it out of the way.
1119 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1120 CStringGetDatum(enumName),
1121 ObjectIdGetDatum(enumNamespace));
1122 if (OidIsValid(old_type_oid))
1124 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1126 (errcode(ERRCODE_DUPLICATE_OBJECT),
1127 errmsg("type \"%s\" already exists", enumName)));
1130 enumArrayOid = AssignTypeArrayOid();
1132 /* Create the pg_type entry */
1134 TypeCreate(InvalidOid, /* no predetermined type OID */
1135 enumName, /* type name */
1136 enumNamespace, /* namespace */
1137 InvalidOid, /* relation oid (n/a here) */
1138 0, /* relation kind (ditto) */
1139 GetUserId(), /* owner's ID */
1140 sizeof(Oid), /* internal size */
1141 TYPTYPE_ENUM, /* type-type (enum type) */
1142 TYPCATEGORY_ENUM, /* type-category (enum type) */
1143 false, /* enum types are never preferred */
1144 DEFAULT_TYPDELIM, /* array element delimiter */
1145 F_ENUM_IN, /* input procedure */
1146 F_ENUM_OUT, /* output procedure */
1147 F_ENUM_RECV, /* receive procedure */
1148 F_ENUM_SEND, /* send procedure */
1149 InvalidOid, /* typmodin procedure - none */
1150 InvalidOid, /* typmodout procedure - none */
1151 InvalidOid, /* analyze procedure - default */
1152 InvalidOid, /* element type ID */
1153 false, /* this is not an array type */
1154 enumArrayOid, /* array type we are about to create */
1155 InvalidOid, /* base type ID (only for domains) */
1156 NULL, /* never a default type value */
1157 NULL, /* binary default isn't sent either */
1158 true, /* always passed by value */
1159 'i', /* int alignment */
1160 'p', /* TOAST strategy always plain */
1161 -1, /* typMod (Domains only) */
1162 0, /* Array dimensions of typbasetype */
1163 false, /* Type NOT NULL */
1164 InvalidOid); /* typcollation */
1166 /* Enter the enum's values into pg_enum */
1167 EnumValuesCreate(enumTypeOid, stmt->vals);
1170 * Create the array type that goes with it.
1172 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1174 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1175 enumArrayName, /* type name */
1176 enumNamespace, /* namespace */
1177 InvalidOid, /* relation oid (n/a here) */
1178 0, /* relation kind (ditto) */
1179 GetUserId(), /* owner's ID */
1180 -1, /* internal size (always varlena) */
1181 TYPTYPE_BASE, /* type-type (base type) */
1182 TYPCATEGORY_ARRAY, /* type-category (array) */
1183 false, /* array types are never preferred */
1184 DEFAULT_TYPDELIM, /* array element delimiter */
1185 F_ARRAY_IN, /* input procedure */
1186 F_ARRAY_OUT, /* output procedure */
1187 F_ARRAY_RECV, /* receive procedure */
1188 F_ARRAY_SEND, /* send procedure */
1189 InvalidOid, /* typmodin procedure - none */
1190 InvalidOid, /* typmodout procedure - none */
1191 InvalidOid, /* analyze procedure - default */
1192 enumTypeOid, /* element type ID */
1193 true, /* yes this is an array type */
1194 InvalidOid, /* no further array type */
1195 InvalidOid, /* base type ID */
1196 NULL, /* never a default type value */
1197 NULL, /* binary default isn't sent either */
1198 false, /* never passed by value */
1199 'i', /* enums have align i, so do their arrays */
1200 'x', /* ARRAY is always toastable */
1201 -1, /* typMod (Domains only) */
1202 0, /* Array dimensions of typbasetype */
1203 false, /* Type NOT NULL */
1204 InvalidOid); /* typcollation */
1206 pfree(enumArrayName);
1211 * Adds a new label to an existing enum.
1214 AlterEnum(AlterEnumStmt *stmt)
1220 /* Make a TypeName so we can use standard type lookup machinery */
1221 typename = makeTypeNameFromNameList(stmt->typeName);
1222 enum_type_oid = typenameTypeId(NULL, typename);
1224 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1225 if (!HeapTupleIsValid(tup))
1226 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1228 /* Check it's an enum and check user has permission to ALTER the enum */
1229 checkEnumOwner(tup);
1231 /* Add the new label */
1232 AddEnumLabel(enum_type_oid, stmt->newVal,
1233 stmt->newValNeighbor, stmt->newValIsAfter);
1235 ReleaseSysCache(tup);
1242 * Check that the type is actually an enum and that the current user
1243 * has permission to do ALTER TYPE on it. Throw an error if not.
1246 checkEnumOwner(HeapTuple tup)
1248 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1250 /* Check that this is actually an enum */
1251 if (typTup->typtype != TYPTYPE_ENUM)
1253 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1254 errmsg("%s is not an enum",
1255 format_type_be(HeapTupleGetOid(tup)))));
1257 /* Permission check: must own type */
1258 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1259 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
1260 format_type_be(HeapTupleGetOid(tup)));
1265 * Find suitable I/O functions for a type.
1267 * typeOid is the type's OID (which will already exist, if only as a shell
1272 findTypeInputFunction(List *procname, Oid typeOid)
1278 * Input functions can take a single argument of type CSTRING, or three
1279 * arguments (string, typioparam OID, typmod).
1281 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1282 * see this, we issue a warning and fix up the pg_proc entry.
1284 argList[0] = CSTRINGOID;
1286 procOid = LookupFuncName(procname, 1, argList, true);
1287 if (OidIsValid(procOid))
1290 argList[1] = OIDOID;
1291 argList[2] = INT4OID;
1293 procOid = LookupFuncName(procname, 3, argList, true);
1294 if (OidIsValid(procOid))
1297 /* No luck, try it with OPAQUE */
1298 argList[0] = OPAQUEOID;
1300 procOid = LookupFuncName(procname, 1, argList, true);
1302 if (!OidIsValid(procOid))
1304 argList[1] = OIDOID;
1305 argList[2] = INT4OID;
1307 procOid = LookupFuncName(procname, 3, argList, true);
1310 if (OidIsValid(procOid))
1312 /* Found, but must complain and fix the pg_proc entry */
1314 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1315 NameListToString(procname))));
1316 SetFunctionArgType(procOid, 0, CSTRINGOID);
1319 * Need CommandCounterIncrement since DefineType will likely try to
1320 * alter the pg_proc tuple again.
1322 CommandCounterIncrement();
1327 /* Use CSTRING (preferred) in the error message */
1328 argList[0] = CSTRINGOID;
1331 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1332 errmsg("function %s does not exist",
1333 func_signature_string(procname, 1, NIL, argList))));
1335 return InvalidOid; /* keep compiler quiet */
1339 findTypeOutputFunction(List *procname, Oid typeOid)
1345 * Output functions can take a single argument of the type.
1347 * For backwards compatibility we allow OPAQUE in place of the actual type
1348 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1350 argList[0] = typeOid;
1352 procOid = LookupFuncName(procname, 1, argList, true);
1353 if (OidIsValid(procOid))
1356 /* No luck, try it with OPAQUE */
1357 argList[0] = OPAQUEOID;
1359 procOid = LookupFuncName(procname, 1, argList, true);
1361 if (OidIsValid(procOid))
1363 /* Found, but must complain and fix the pg_proc entry */
1365 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1366 NameListToString(procname), format_type_be(typeOid))));
1367 SetFunctionArgType(procOid, 0, typeOid);
1370 * Need CommandCounterIncrement since DefineType will likely try to
1371 * alter the pg_proc tuple again.
1373 CommandCounterIncrement();
1378 /* Use type name, not OPAQUE, in the failure message. */
1379 argList[0] = typeOid;
1382 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1383 errmsg("function %s does not exist",
1384 func_signature_string(procname, 1, NIL, argList))));
1386 return InvalidOid; /* keep compiler quiet */
1390 findTypeReceiveFunction(List *procname, Oid typeOid)
1396 * Receive functions can take a single argument of type INTERNAL, or three
1397 * arguments (internal, typioparam OID, typmod).
1399 argList[0] = INTERNALOID;
1401 procOid = LookupFuncName(procname, 1, argList, true);
1402 if (OidIsValid(procOid))
1405 argList[1] = OIDOID;
1406 argList[2] = INT4OID;
1408 procOid = LookupFuncName(procname, 3, argList, true);
1409 if (OidIsValid(procOid))
1413 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1414 errmsg("function %s does not exist",
1415 func_signature_string(procname, 1, NIL, argList))));
1417 return InvalidOid; /* keep compiler quiet */
1421 findTypeSendFunction(List *procname, Oid typeOid)
1427 * Send functions can take a single argument of the type.
1429 argList[0] = typeOid;
1431 procOid = LookupFuncName(procname, 1, argList, true);
1432 if (OidIsValid(procOid))
1436 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1437 errmsg("function %s does not exist",
1438 func_signature_string(procname, 1, NIL, argList))));
1440 return InvalidOid; /* keep compiler quiet */
1444 findTypeTypmodinFunction(List *procname)
1450 * typmodin functions always take one cstring[] argument and return int4.
1452 argList[0] = CSTRINGARRAYOID;
1454 procOid = LookupFuncName(procname, 1, argList, true);
1455 if (!OidIsValid(procOid))
1457 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1458 errmsg("function %s does not exist",
1459 func_signature_string(procname, 1, NIL, argList))));
1461 if (get_func_rettype(procOid) != INT4OID)
1463 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1464 errmsg("typmod_in function %s must return type \"integer\"",
1465 NameListToString(procname))));
1471 findTypeTypmodoutFunction(List *procname)
1477 * typmodout functions always take one int4 argument and return cstring.
1479 argList[0] = INT4OID;
1481 procOid = LookupFuncName(procname, 1, argList, true);
1482 if (!OidIsValid(procOid))
1484 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1485 errmsg("function %s does not exist",
1486 func_signature_string(procname, 1, NIL, argList))));
1488 if (get_func_rettype(procOid) != CSTRINGOID)
1490 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1491 errmsg("typmod_out function %s must return type \"cstring\"",
1492 NameListToString(procname))));
1498 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1504 * Analyze functions always take one INTERNAL argument and return bool.
1506 argList[0] = INTERNALOID;
1508 procOid = LookupFuncName(procname, 1, argList, true);
1509 if (!OidIsValid(procOid))
1511 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1512 errmsg("function %s does not exist",
1513 func_signature_string(procname, 1, NIL, argList))));
1515 if (get_func_rettype(procOid) != BOOLOID)
1517 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1518 errmsg("type analyze function %s must return type \"boolean\"",
1519 NameListToString(procname))));
1525 * AssignTypeArrayOid
1527 * Pre-assign the type's array OID for use in pg_type.typarray
1530 AssignTypeArrayOid(void)
1534 /* Use binary-upgrade override for pg_type.typarray, if supplied. */
1535 if (OidIsValid(binary_upgrade_next_array_pg_type_oid))
1537 type_array_oid = binary_upgrade_next_array_pg_type_oid;
1538 binary_upgrade_next_array_pg_type_oid = InvalidOid;
1542 Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
1544 type_array_oid = GetNewOid(pg_type);
1545 heap_close(pg_type, AccessShareLock);
1548 return type_array_oid;
1552 /*-------------------------------------------------------------------
1553 * DefineCompositeType
1555 * Create a Composite Type relation.
1556 * `DefineRelation' does all the work, we just provide the correct
1559 * If the relation already exists, then 'DefineRelation' will abort
1562 * DefineCompositeType returns relid for use when creating
1563 * an implicit composite type during function creation
1564 *-------------------------------------------------------------------
1567 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1569 CreateStmt *createStmt = makeNode(CreateStmt);
1575 * now set the parameters for keys/inheritance etc. All of these are
1576 * uninteresting for composite types...
1578 createStmt->relation = (RangeVar *) typevar;
1579 createStmt->tableElts = coldeflist;
1580 createStmt->inhRelations = NIL;
1581 createStmt->constraints = NIL;
1582 createStmt->options = list_make1(defWithOids(false));
1583 createStmt->oncommit = ONCOMMIT_NOOP;
1584 createStmt->tablespacename = NULL;
1585 createStmt->if_not_exists = false;
1588 * Check for collision with an existing type name. If there is one and
1589 * it's an autogenerated array, we can rename it out of the way. This
1590 * check is here mainly to get a better error message about a "type"
1591 * instead of below about a "relation".
1593 typeNamespace = RangeVarGetCreationNamespace(createStmt->relation);
1595 GetSysCacheOid2(TYPENAMENSP,
1596 CStringGetDatum(createStmt->relation->relname),
1597 ObjectIdGetDatum(typeNamespace));
1598 if (OidIsValid(old_type_oid))
1600 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
1602 (errcode(ERRCODE_DUPLICATE_OBJECT),
1603 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
1607 * Finally create the relation. This also creates the type.
1609 relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
1610 Assert(relid != InvalidOid);
1615 * AlterDomainDefault
1617 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
1620 AlterDomainDefault(List *names, Node *defaultRaw)
1628 Node *defaultExpr = NULL; /* NULL if no default specified */
1629 Datum new_record[Natts_pg_type];
1630 bool new_record_nulls[Natts_pg_type];
1631 bool new_record_repl[Natts_pg_type];
1633 Form_pg_type typTup;
1635 /* Make a TypeName so we can use standard type lookup machinery */
1636 typename = makeTypeNameFromNameList(names);
1637 domainoid = typenameTypeId(NULL, typename);
1639 /* Look up the domain in the type table */
1640 rel = heap_open(TypeRelationId, RowExclusiveLock);
1642 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1643 if (!HeapTupleIsValid(tup))
1644 elog(ERROR, "cache lookup failed for type %u", domainoid);
1645 typTup = (Form_pg_type) GETSTRUCT(tup);
1647 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1648 checkDomainOwner(tup);
1650 /* Setup new tuple */
1651 MemSet(new_record, (Datum) 0, sizeof(new_record));
1652 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1653 MemSet(new_record_repl, false, sizeof(new_record_repl));
1655 /* Store the new default into the tuple */
1658 /* Create a dummy ParseState for transformExpr */
1659 pstate = make_parsestate(NULL);
1662 * Cook the colDef->raw_expr into an expression. Note: Name is
1663 * strictly for error message
1665 defaultExpr = cookDefault(pstate, defaultRaw,
1666 typTup->typbasetype,
1668 NameStr(typTup->typname));
1671 * If the expression is just a NULL constant, we treat the command
1672 * like ALTER ... DROP DEFAULT. (But see note for same test in
1675 if (defaultExpr == NULL ||
1676 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
1678 /* Default is NULL, drop it */
1679 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
1680 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1681 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
1682 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1687 * Expression must be stored as a nodeToString result, but we also
1688 * require a valid textual representation (mainly to make life
1689 * easier for pg_dump).
1691 defaultValue = deparse_expression(defaultExpr,
1692 deparse_context_for(NameStr(typTup->typname),
1697 * Form an updated tuple with the new default and write it back.
1699 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
1701 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1702 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
1703 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1708 /* ALTER ... DROP DEFAULT */
1709 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
1710 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1711 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
1712 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1715 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
1716 new_record, new_record_nulls,
1719 simple_heap_update(rel, &tup->t_self, newtuple);
1721 CatalogUpdateIndexes(rel, newtuple);
1723 /* Rebuild dependencies */
1724 GenerateTypeDependencies(typTup->typnamespace,
1726 InvalidOid, /* typrelid is n/a */
1727 0, /* relation kind is n/a */
1737 false, /* a domain isn't an implicit array */
1738 typTup->typbasetype,
1740 true); /* Rebuild is true */
1743 heap_close(rel, NoLock);
1744 heap_freetuple(newtuple);
1748 * AlterDomainNotNull
1750 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
1753 AlterDomainNotNull(List *names, bool notNull)
1759 Form_pg_type typTup;
1761 /* Make a TypeName so we can use standard type lookup machinery */
1762 typename = makeTypeNameFromNameList(names);
1763 domainoid = typenameTypeId(NULL, typename);
1765 /* Look up the domain in the type table */
1766 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1768 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1769 if (!HeapTupleIsValid(tup))
1770 elog(ERROR, "cache lookup failed for type %u", domainoid);
1771 typTup = (Form_pg_type) GETSTRUCT(tup);
1773 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1774 checkDomainOwner(tup);
1776 /* Is the domain already set to the desired constraint? */
1777 if (typTup->typnotnull == notNull)
1779 heap_close(typrel, RowExclusiveLock);
1783 /* Adding a NOT NULL constraint requires checking existing columns */
1789 /* Fetch relation list with attributes based on this domain */
1790 /* ShareLock is sufficient to prevent concurrent data changes */
1792 rels = get_rels_with_domain(domainoid, ShareLock);
1796 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1797 Relation testrel = rtc->rel;
1798 TupleDesc tupdesc = RelationGetDescr(testrel);
1802 /* Scan all tuples in this relation */
1803 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1804 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1808 /* Test attributes that are of the domain */
1809 for (i = 0; i < rtc->natts; i++)
1811 int attnum = rtc->atts[i];
1813 if (heap_attisnull(tuple, attnum))
1815 (errcode(ERRCODE_NOT_NULL_VIOLATION),
1816 errmsg("column \"%s\" of table \"%s\" contains null values",
1817 NameStr(tupdesc->attrs[attnum - 1]->attname),
1818 RelationGetRelationName(testrel))));
1823 /* Close each rel after processing, but keep lock */
1824 heap_close(testrel, NoLock);
1829 * Okay to update pg_type row. We can scribble on typTup because it's a
1832 typTup->typnotnull = notNull;
1834 simple_heap_update(typrel, &tup->t_self, tup);
1836 CatalogUpdateIndexes(typrel, tup);
1839 heap_freetuple(tup);
1840 heap_close(typrel, RowExclusiveLock);
1844 * AlterDomainDropConstraint
1846 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
1849 AlterDomainDropConstraint(List *names, const char *constrName,
1850 DropBehavior behavior)
1857 SysScanDesc conscan;
1861 /* Make a TypeName so we can use standard type lookup machinery */
1862 typename = makeTypeNameFromNameList(names);
1863 domainoid = typenameTypeId(NULL, typename);
1865 /* Look up the domain in the type table */
1866 rel = heap_open(TypeRelationId, RowExclusiveLock);
1868 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1869 if (!HeapTupleIsValid(tup))
1870 elog(ERROR, "cache lookup failed for type %u", domainoid);
1872 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1873 checkDomainOwner(tup);
1875 /* Grab an appropriate lock on the pg_constraint relation */
1876 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
1878 /* Use the index to scan only constraints of the target relation */
1879 ScanKeyInit(&key[0],
1880 Anum_pg_constraint_contypid,
1881 BTEqualStrategyNumber, F_OIDEQ,
1882 ObjectIdGetDatum(HeapTupleGetOid(tup)));
1884 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
1885 SnapshotNow, 1, key);
1888 * Scan over the result set, removing any matching entries.
1890 while ((contup = systable_getnext(conscan)) != NULL)
1892 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
1894 if (strcmp(NameStr(con->conname), constrName) == 0)
1896 ObjectAddress conobj;
1898 conobj.classId = ConstraintRelationId;
1899 conobj.objectId = HeapTupleGetOid(contup);
1900 conobj.objectSubId = 0;
1902 performDeletion(&conobj, behavior);
1905 /* Clean up after the scan */
1906 systable_endscan(conscan);
1907 heap_close(conrel, RowExclusiveLock);
1909 heap_close(rel, NoLock);
1913 * AlterDomainAddConstraint
1915 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
1918 AlterDomainAddConstraint(List *names, Node *newConstraint)
1924 Form_pg_type typTup;
1928 ExprContext *econtext;
1931 ExprState *exprstate;
1934 /* Make a TypeName so we can use standard type lookup machinery */
1935 typename = makeTypeNameFromNameList(names);
1936 domainoid = typenameTypeId(NULL, typename);
1938 /* Look up the domain in the type table */
1939 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1941 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1942 if (!HeapTupleIsValid(tup))
1943 elog(ERROR, "cache lookup failed for type %u", domainoid);
1944 typTup = (Form_pg_type) GETSTRUCT(tup);
1946 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1947 checkDomainOwner(tup);
1949 if (!IsA(newConstraint, Constraint))
1950 elog(ERROR, "unrecognized node type: %d",
1951 (int) nodeTag(newConstraint));
1953 constr = (Constraint *) newConstraint;
1955 switch (constr->contype)
1958 /* processed below */
1963 (errcode(ERRCODE_SYNTAX_ERROR),
1964 errmsg("unique constraints not possible for domains")));
1967 case CONSTR_PRIMARY:
1969 (errcode(ERRCODE_SYNTAX_ERROR),
1970 errmsg("primary key constraints not possible for domains")));
1973 case CONSTR_EXCLUSION:
1975 (errcode(ERRCODE_SYNTAX_ERROR),
1976 errmsg("exclusion constraints not possible for domains")));
1979 case CONSTR_FOREIGN:
1981 (errcode(ERRCODE_SYNTAX_ERROR),
1982 errmsg("foreign key constraints not possible for domains")));
1985 case CONSTR_ATTR_DEFERRABLE:
1986 case CONSTR_ATTR_NOT_DEFERRABLE:
1987 case CONSTR_ATTR_DEFERRED:
1988 case CONSTR_ATTR_IMMEDIATE:
1990 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1991 errmsg("specifying constraint deferrability not supported for domains")));
1995 elog(ERROR, "unrecognized constraint subtype: %d",
1996 (int) constr->contype);
2001 * Since all other constraint types throw errors, this must be a check
2002 * constraint. First, process the constraint expression and add an entry
2006 ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
2007 typTup->typbasetype, typTup->typtypmod,
2008 constr, NameStr(typTup->typname));
2011 * Test all values stored in the attributes based on the domain the
2012 * constraint is being added to.
2014 expr = (Expr *) stringToNode(ccbin);
2016 /* Need an EState to run ExecEvalExpr */
2017 estate = CreateExecutorState();
2018 econtext = GetPerTupleExprContext(estate);
2020 /* build execution state for expr */
2021 exprstate = ExecPrepareExpr(expr, estate);
2023 /* Fetch relation list with attributes based on this domain */
2024 /* ShareLock is sufficient to prevent concurrent data changes */
2026 rels = get_rels_with_domain(domainoid, ShareLock);
2030 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2031 Relation testrel = rtc->rel;
2032 TupleDesc tupdesc = RelationGetDescr(testrel);
2036 /* Scan all tuples in this relation */
2037 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2038 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2042 /* Test attributes that are of the domain */
2043 for (i = 0; i < rtc->natts; i++)
2045 int attnum = rtc->atts[i];
2050 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2052 econtext->domainValue_datum = d;
2053 econtext->domainValue_isNull = isNull;
2055 conResult = ExecEvalExprSwitchContext(exprstate,
2059 if (!isNull && !DatumGetBool(conResult))
2061 (errcode(ERRCODE_CHECK_VIOLATION),
2062 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2063 NameStr(tupdesc->attrs[attnum - 1]->attname),
2064 RelationGetRelationName(testrel))));
2067 ResetExprContext(econtext);
2071 /* Hold relation lock till commit (XXX bad for concurrency) */
2072 heap_close(testrel, NoLock);
2075 FreeExecutorState(estate);
2078 heap_close(typrel, RowExclusiveLock);
2082 * get_rels_with_domain
2084 * Fetch all relations / attributes which are using the domain
2086 * The result is a list of RelToCheck structs, one for each distinct
2087 * relation, each containing one or more attribute numbers that are of
2088 * the domain type. We have opened each rel and acquired the specified lock
2091 * We support nested domains by including attributes that are of derived
2092 * domain types. Current callers do not need to distinguish between attributes
2093 * that are of exactly the given domain and those that are of derived domains.
2095 * XXX this is completely broken because there is no way to lock the domain
2096 * to prevent columns from being added or dropped while our command runs.
2097 * We can partially protect against column drops by locking relations as we
2098 * come across them, but there is still a race condition (the window between
2099 * seeing a pg_depend entry and acquiring lock on the relation it references).
2100 * Also, holding locks on all these relations simultaneously creates a non-
2101 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2102 * risk by using the weakest suitable lock (ShareLock for most callers).
2104 * XXX the API for this is not sufficient to support checking domain values
2105 * that are inside composite types or arrays. Currently we just error out
2106 * if a composite type containing the target domain is stored anywhere.
2107 * There are not currently arrays of domains; if there were, we could take
2108 * the same approach, but it'd be nicer to fix it properly.
2110 * Generally used for retrieving a list of tests when adding
2111 * new constraints to a domain.
2114 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2119 SysScanDesc depScan;
2122 Assert(lockmode != NoLock);
2125 * We scan pg_depend to find those things that depend on the domain. (We
2126 * assume we can ignore refobjsubid for a domain.)
2128 depRel = heap_open(DependRelationId, AccessShareLock);
2130 ScanKeyInit(&key[0],
2131 Anum_pg_depend_refclassid,
2132 BTEqualStrategyNumber, F_OIDEQ,
2133 ObjectIdGetDatum(TypeRelationId));
2134 ScanKeyInit(&key[1],
2135 Anum_pg_depend_refobjid,
2136 BTEqualStrategyNumber, F_OIDEQ,
2137 ObjectIdGetDatum(domainOid));
2139 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2140 SnapshotNow, 2, key);
2142 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2144 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2145 RelToCheck *rtc = NULL;
2147 Form_pg_attribute pg_att;
2150 /* Check for directly dependent types --- must be domains */
2151 if (pg_depend->classid == TypeRelationId)
2153 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2156 * Recursively add dependent columns to the output list. This is
2157 * a bit inefficient since we may fail to combine RelToCheck
2158 * entries when attributes of the same rel have different derived
2159 * domain types, but it's probably not worth improving.
2161 result = list_concat(result,
2162 get_rels_with_domain(pg_depend->objid,
2167 /* Else, ignore dependees that aren't user columns of relations */
2168 /* (we assume system columns are never of domain types) */
2169 if (pg_depend->classid != RelationRelationId ||
2170 pg_depend->objsubid <= 0)
2173 /* See if we already have an entry for this relation */
2174 foreach(rellist, result)
2176 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2178 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2187 /* First attribute found for this relation */
2190 /* Acquire requested lock on relation */
2191 rel = relation_open(pg_depend->objid, lockmode);
2194 * Check to see if rowtype is stored anyplace as a composite-type
2195 * column; if so we have to fail, for now anyway.
2197 if (OidIsValid(rel->rd_rel->reltype))
2198 find_composite_type_dependencies(rel->rd_rel->reltype,
2199 RELKIND_COMPOSITE_TYPE,
2200 format_type_be(domainOid));
2202 /* Otherwise we can ignore views, composite types, etc */
2203 if (rel->rd_rel->relkind != RELKIND_RELATION)
2205 relation_close(rel, lockmode);
2209 /* Build the RelToCheck entry with enough space for all atts */
2210 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2213 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2214 result = lcons(rtc, result);
2218 * Confirm column has not been dropped, and is of the expected type.
2219 * This defends against an ALTER DROP COLUMN occuring just before we
2220 * acquired lock ... but if the whole table were dropped, we'd still
2223 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2225 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2226 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2230 * Okay, add column to result. We store the columns in column-number
2231 * order; this is just a hack to improve predictability of regression
2234 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2237 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2239 rtc->atts[ptr] = rtc->atts[ptr - 1];
2242 rtc->atts[ptr] = pg_depend->objsubid;
2245 systable_endscan(depScan);
2247 relation_close(depRel, AccessShareLock);
2255 * Check that the type is actually a domain and that the current user
2256 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2259 checkDomainOwner(HeapTuple tup)
2261 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2263 /* Check that this is actually a domain */
2264 if (typTup->typtype != TYPTYPE_DOMAIN)
2266 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2267 errmsg("%s is not a domain",
2268 format_type_be(HeapTupleGetOid(tup)))));
2270 /* Permission check: must own type */
2271 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2272 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2273 format_type_be(HeapTupleGetOid(tup)));
2277 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2280 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2281 int typMod, Constraint *constr,
2288 CoerceToDomainValue *domVal;
2291 * Assign or validate constraint name
2293 if (constr->conname)
2295 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2300 (errcode(ERRCODE_DUPLICATE_OBJECT),
2301 errmsg("constraint \"%s\" for domain \"%s\" already exists",
2302 constr->conname, domainName)));
2305 constr->conname = ChooseConstraintName(domainName,
2312 * Convert the A_EXPR in raw_expr into an EXPR
2314 pstate = make_parsestate(NULL);
2317 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2318 * the expression. Note that it will appear to have the type of the base
2319 * type, not the domain. This seems correct since within the check
2320 * expression, we should not assume the input value can be considered a
2321 * member of the domain.
2323 domVal = makeNode(CoerceToDomainValue);
2324 domVal->typeId = baseTypeOid;
2325 domVal->typeMod = typMod;
2326 domVal->location = -1; /* will be set when/if used */
2328 pstate->p_value_substitute = (Node *) domVal;
2330 expr = transformExpr(pstate, constr->raw_expr);
2333 * Make sure it yields a boolean result.
2335 expr = coerce_to_boolean(pstate, expr, "CHECK");
2338 * Make sure no outside relations are referred to.
2340 if (list_length(pstate->p_rtable) != 0)
2342 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2343 errmsg("cannot use table references in domain check constraint")));
2346 * Domains don't allow var clauses (this should be redundant with the
2347 * above check, but make it anyway)
2349 if (contain_var_clause(expr))
2351 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2352 errmsg("cannot use table references in domain check constraint")));
2355 * No subplans or aggregates, either...
2357 if (pstate->p_hasSubLinks)
2359 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2360 errmsg("cannot use subquery in check constraint")));
2361 if (pstate->p_hasAggs)
2363 (errcode(ERRCODE_GROUPING_ERROR),
2364 errmsg("cannot use aggregate function in check constraint")));
2365 if (pstate->p_hasWindowFuncs)
2367 (errcode(ERRCODE_WINDOWING_ERROR),
2368 errmsg("cannot use window function in check constraint")));
2371 * Convert to string form for storage.
2373 ccbin = nodeToString(expr);
2376 * Deparse it to produce text for consrc.
2378 * Since VARNOs aren't allowed in domain constraints, relation context
2379 * isn't required as anything other than a shell.
2381 ccsrc = deparse_expression(expr,
2382 deparse_context_for(domainName,
2387 * Store the constraint in pg_constraint
2389 CreateConstraintEntry(constr->conname, /* Constraint Name */
2390 domainNamespace, /* namespace */
2391 CONSTRAINT_CHECK, /* Constraint Type */
2392 false, /* Is Deferrable */
2393 false, /* Is Deferred */
2394 true, /* Is Validated */
2395 InvalidOid, /* not a relation constraint */
2398 domainOid, /* domain constraint */
2399 InvalidOid, /* no associated index */
2400 InvalidOid, /* Foreign key fields */
2409 NULL, /* not an exclusion constraint */
2410 expr, /* Tree form of check constraint */
2411 ccbin, /* Binary form of check constraint */
2412 ccsrc, /* Source form of check constraint */
2413 true, /* is local */
2417 * Return the compiled constraint expression so the calling routine can
2418 * perform any additional required tests.
2424 * GetDomainConstraints - get a list of the current constraints of domain
2426 * Returns a possibly-empty list of DomainConstraintState nodes.
2428 * This is called by the executor during plan startup for a CoerceToDomain
2429 * expression node. The given constraints will be checked for each value
2430 * passed through the node.
2432 * We allow this to be called for non-domain types, in which case the result
2436 GetDomainConstraints(Oid typeOid)
2439 bool notNull = false;
2442 conRel = heap_open(ConstraintRelationId, AccessShareLock);
2448 Form_pg_type typTup;
2452 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
2453 if (!HeapTupleIsValid(tup))
2454 elog(ERROR, "cache lookup failed for type %u", typeOid);
2455 typTup = (Form_pg_type) GETSTRUCT(tup);
2457 if (typTup->typtype != TYPTYPE_DOMAIN)
2459 /* Not a domain, so done */
2460 ReleaseSysCache(tup);
2464 /* Test for NOT NULL Constraint */
2465 if (typTup->typnotnull)
2468 /* Look for CHECK Constraints on this domain */
2469 ScanKeyInit(&key[0],
2470 Anum_pg_constraint_contypid,
2471 BTEqualStrategyNumber, F_OIDEQ,
2472 ObjectIdGetDatum(typeOid));
2474 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
2475 SnapshotNow, 1, key);
2477 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
2479 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
2483 DomainConstraintState *r;
2485 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
2486 if (c->contype != CONSTRAINT_CHECK)
2490 * Not expecting conbin to be NULL, but we'll test for it anyway
2492 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
2493 conRel->rd_att, &isNull);
2495 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
2496 NameStr(typTup->typname), NameStr(c->conname));
2498 check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
2500 /* ExecInitExpr assumes we've planned the expression */
2501 check_expr = expression_planner(check_expr);
2503 r = makeNode(DomainConstraintState);
2504 r->constrainttype = DOM_CONSTRAINT_CHECK;
2505 r->name = pstrdup(NameStr(c->conname));
2506 r->check_expr = ExecInitExpr(check_expr, NULL);
2509 * use lcons() here because constraints of lower domains should be
2512 result = lcons(r, result);
2515 systable_endscan(scan);
2517 /* loop to next domain in stack */
2518 typeOid = typTup->typbasetype;
2519 ReleaseSysCache(tup);
2522 heap_close(conRel, AccessShareLock);
2525 * Only need to add one NOT NULL check regardless of how many domains in
2526 * the stack request it.
2530 DomainConstraintState *r = makeNode(DomainConstraintState);
2532 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
2533 r->name = pstrdup("NOT NULL");
2534 r->check_expr = NULL;
2536 /* lcons to apply the nullness check FIRST */
2537 result = lcons(r, result);
2545 * Execute ALTER TYPE RENAME
2548 RenameType(List *names, const char *newTypeName)
2554 Form_pg_type typTup;
2556 /* Make a TypeName so we can use standard type lookup machinery */
2557 typename = makeTypeNameFromNameList(names);
2558 typeOid = typenameTypeId(NULL, typename);
2560 /* Look up the type in the type table */
2561 rel = heap_open(TypeRelationId, RowExclusiveLock);
2563 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
2564 if (!HeapTupleIsValid(tup))
2565 elog(ERROR, "cache lookup failed for type %u", typeOid);
2566 typTup = (Form_pg_type) GETSTRUCT(tup);
2568 /* check permissions on type */
2569 if (!pg_type_ownercheck(typeOid, GetUserId()))
2570 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2571 format_type_be(typeOid));
2574 * If it's a composite type, we need to check that it really is a
2575 * free-standing composite type, and not a table's rowtype. We want people
2576 * to use ALTER TABLE not ALTER TYPE for that case.
2578 if (typTup->typtype == TYPTYPE_COMPOSITE &&
2579 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2581 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2582 errmsg("%s is a table's row type",
2583 format_type_be(typeOid)),
2584 errhint("Use ALTER TABLE instead.")));
2586 /* don't allow direct alteration of array types, either */
2587 if (OidIsValid(typTup->typelem) &&
2588 get_array_type(typTup->typelem) == typeOid)
2590 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2591 errmsg("cannot alter array type %s",
2592 format_type_be(typeOid)),
2593 errhint("You can alter type %s, which will alter the array type as well.",
2594 format_type_be(typTup->typelem))));
2597 * If type is composite we need to rename associated pg_class entry too.
2598 * RenameRelationInternal will call RenameTypeInternal automatically.
2600 if (typTup->typtype == TYPTYPE_COMPOSITE)
2601 RenameRelationInternal(typTup->typrelid, newTypeName,
2602 typTup->typnamespace);
2604 RenameTypeInternal(typeOid, newTypeName,
2605 typTup->typnamespace);
2608 heap_close(rel, RowExclusiveLock);
2612 * Change the owner of a type.
2615 AlterTypeOwner(List *names, Oid newOwnerId)
2622 Form_pg_type typTup;
2623 AclResult aclresult;
2625 rel = heap_open(TypeRelationId, RowExclusiveLock);
2627 /* Make a TypeName so we can use standard type lookup machinery */
2628 typename = makeTypeNameFromNameList(names);
2630 /* Use LookupTypeName here so that shell types can be processed */
2631 tup = LookupTypeName(NULL, typename, NULL, NULL);
2634 (errcode(ERRCODE_UNDEFINED_OBJECT),
2635 errmsg("type \"%s\" does not exist",
2636 TypeNameToString(typename))));
2637 typeOid = typeTypeId(tup);
2639 /* Copy the syscache entry so we can scribble on it below */
2640 newtup = heap_copytuple(tup);
2641 ReleaseSysCache(tup);
2643 typTup = (Form_pg_type) GETSTRUCT(tup);
2646 * If it's a composite type, we need to check that it really is a
2647 * free-standing composite type, and not a table's rowtype. We want people
2648 * to use ALTER TABLE not ALTER TYPE for that case.
2650 if (typTup->typtype == TYPTYPE_COMPOSITE &&
2651 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2653 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2654 errmsg("%s is a table's row type",
2655 format_type_be(typeOid)),
2656 errhint("Use ALTER TABLE instead.")));
2658 /* don't allow direct alteration of array types, either */
2659 if (OidIsValid(typTup->typelem) &&
2660 get_array_type(typTup->typelem) == typeOid)
2662 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2663 errmsg("cannot alter array type %s",
2664 format_type_be(typeOid)),
2665 errhint("You can alter type %s, which will alter the array type as well.",
2666 format_type_be(typTup->typelem))));
2669 * If the new owner is the same as the existing owner, consider the
2670 * command to have succeeded. This is for dump restoration purposes.
2672 if (typTup->typowner != newOwnerId)
2674 /* Superusers can always do it */
2677 /* Otherwise, must be owner of the existing object */
2678 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2679 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2680 format_type_be(HeapTupleGetOid(tup)));
2682 /* Must be able to become new owner */
2683 check_is_member_of_role(GetUserId(), newOwnerId);
2685 /* New owner must have CREATE privilege on namespace */
2686 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
2689 if (aclresult != ACLCHECK_OK)
2690 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
2691 get_namespace_name(typTup->typnamespace));
2695 * If it's a composite type, invoke ATExecChangeOwner so that we fix
2696 * up the pg_class entry properly. That will call back to
2697 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
2699 if (typTup->typtype == TYPTYPE_COMPOSITE)
2700 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
2704 * We can just apply the modification directly.
2706 * okay to scribble on typTup because it's a copy
2708 typTup->typowner = newOwnerId;
2710 simple_heap_update(rel, &tup->t_self, tup);
2712 CatalogUpdateIndexes(rel, tup);
2714 /* Update owner dependency reference */
2715 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2717 /* If it has an array type, update that too */
2718 if (OidIsValid(typTup->typarray))
2719 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
2724 heap_close(rel, RowExclusiveLock);
2728 * AlterTypeOwnerInternal - change type owner unconditionally
2730 * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
2731 * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
2732 * It assumes the caller has done all needed checks. The function will
2733 * automatically recurse to an array type if the type has one.
2735 * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
2736 * entry (ie, it's not a table rowtype nor an array type).
2739 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
2740 bool hasDependEntry)
2744 Form_pg_type typTup;
2746 rel = heap_open(TypeRelationId, RowExclusiveLock);
2748 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
2749 if (!HeapTupleIsValid(tup))
2750 elog(ERROR, "cache lookup failed for type %u", typeOid);
2751 typTup = (Form_pg_type) GETSTRUCT(tup);
2754 * Modify the owner --- okay to scribble on typTup because it's a copy
2756 typTup->typowner = newOwnerId;
2758 simple_heap_update(rel, &tup->t_self, tup);
2760 CatalogUpdateIndexes(rel, tup);
2762 /* Update owner dependency reference, if it has one */
2764 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2766 /* If it has an array type, update that too */
2767 if (OidIsValid(typTup->typarray))
2768 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
2771 heap_close(rel, RowExclusiveLock);
2775 * Execute ALTER TYPE SET SCHEMA
2778 AlterTypeNamespace(List *names, const char *newschema)
2784 /* Make a TypeName so we can use standard type lookup machinery */
2785 typename = makeTypeNameFromNameList(names);
2786 typeOid = typenameTypeId(NULL, typename);
2788 /* get schema OID and check its permissions */
2789 nspOid = LookupCreationNamespace(newschema);
2791 AlterTypeNamespace_oid(typeOid, nspOid);
2795 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid)
2799 /* check permissions on type */
2800 if (!pg_type_ownercheck(typeOid, GetUserId()))
2801 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2802 format_type_be(typeOid));
2804 /* don't allow direct alteration of array types */
2805 elemOid = get_element_type(typeOid);
2806 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
2808 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2809 errmsg("cannot alter array type %s",
2810 format_type_be(typeOid)),
2811 errhint("You can alter type %s, which will alter the array type as well.",
2812 format_type_be(elemOid))));
2814 /* and do the work */
2815 return AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
2819 * Move specified type to new namespace.
2821 * Caller must have already checked privileges.
2823 * The function automatically recurses to process the type's array type,
2824 * if any. isImplicitArray should be TRUE only when doing this internal
2825 * recursion (outside callers must never try to move an array type directly).
2827 * If errorOnTableType is TRUE, the function errors out if the type is
2828 * a table type. ALTER TABLE has to be used to move a table to a new
2831 * Returns the type's old namespace OID.
2834 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
2835 bool isImplicitArray,
2836 bool errorOnTableType)
2840 Form_pg_type typform;
2843 bool isCompositeType;
2845 rel = heap_open(TypeRelationId, RowExclusiveLock);
2847 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
2848 if (!HeapTupleIsValid(tup))
2849 elog(ERROR, "cache lookup failed for type %u", typeOid);
2850 typform = (Form_pg_type) GETSTRUCT(tup);
2852 oldNspOid = typform->typnamespace;
2853 arrayOid = typform->typarray;
2855 /* common checks on switching namespaces */
2856 CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
2858 /* check for duplicate name (more friendly than unique-index failure) */
2859 if (SearchSysCacheExists2(TYPENAMENSP,
2860 CStringGetDatum(NameStr(typform->typname)),
2861 ObjectIdGetDatum(nspOid)))
2863 (errcode(ERRCODE_DUPLICATE_OBJECT),
2864 errmsg("type \"%s\" already exists in schema \"%s\"",
2865 NameStr(typform->typname),
2866 get_namespace_name(nspOid))));
2868 /* Detect whether type is a composite type (but not a table rowtype) */
2870 (typform->typtype == TYPTYPE_COMPOSITE &&
2871 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
2873 /* Enforce not-table-type if requested */
2874 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
2877 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2878 errmsg("%s is a table's row type",
2879 format_type_be(typeOid)),
2880 errhint("Use ALTER TABLE instead.")));
2882 /* OK, modify the pg_type row */
2884 /* tup is a copy, so we can scribble directly on it */
2885 typform->typnamespace = nspOid;
2887 simple_heap_update(rel, &tup->t_self, tup);
2888 CatalogUpdateIndexes(rel, tup);
2891 * Composite types have pg_class entries.
2893 * We need to modify the pg_class tuple as well to reflect the change of
2896 if (isCompositeType)
2900 classRel = heap_open(RelationRelationId, RowExclusiveLock);
2902 AlterRelationNamespaceInternal(classRel, typform->typrelid,
2906 heap_close(classRel, RowExclusiveLock);
2909 * Check for constraints associated with the composite type (we don't
2910 * currently support this, but probably will someday).
2912 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
2917 /* If it's a domain, it might have constraints */
2918 if (typform->typtype == TYPTYPE_DOMAIN)
2919 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
2923 * Update dependency on schema, if any --- a table rowtype has not got
2924 * one, and neither does an implicit array.
2926 if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
2928 if (changeDependencyFor(TypeRelationId, typeOid,
2929 NamespaceRelationId, oldNspOid, nspOid) != 1)
2930 elog(ERROR, "failed to change schema dependency for type %s",
2931 format_type_be(typeOid));
2933 heap_freetuple(tup);
2935 heap_close(rel, RowExclusiveLock);
2937 /* Recursively alter the associated array type, if any */
2938 if (OidIsValid(arrayOid))
2939 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);