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 void validateDomainConstraint(Oid domainoid, char *ccbin);
90 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
91 static void checkDomainOwner(HeapTuple tup);
92 static void checkEnumOwner(HeapTuple tup);
93 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
95 int typMod, Constraint *constr,
101 * Registers a new base type.
104 DefineType(List *names, List *parameters)
108 int16 internalLength = -1; /* default: variable-length */
109 List *inputName = NIL;
110 List *outputName = NIL;
111 List *receiveName = NIL;
112 List *sendName = NIL;
113 List *typmodinName = NIL;
114 List *typmodoutName = NIL;
115 List *analyzeName = NIL;
116 char category = TYPCATEGORY_USER;
117 bool preferred = false;
118 char delimiter = DEFAULT_TYPDELIM;
119 Oid elemType = InvalidOid;
120 char *defaultValue = NULL;
121 bool byValue = false;
122 char alignment = 'i'; /* default alignment */
123 char storage = 'p'; /* default TOAST storage method */
124 Oid collation = InvalidOid;
125 DefElem *likeTypeEl = NULL;
126 DefElem *internalLengthEl = NULL;
127 DefElem *inputNameEl = NULL;
128 DefElem *outputNameEl = NULL;
129 DefElem *receiveNameEl = NULL;
130 DefElem *sendNameEl = NULL;
131 DefElem *typmodinNameEl = NULL;
132 DefElem *typmodoutNameEl = NULL;
133 DefElem *analyzeNameEl = NULL;
134 DefElem *categoryEl = NULL;
135 DefElem *preferredEl = NULL;
136 DefElem *delimiterEl = NULL;
137 DefElem *elemTypeEl = NULL;
138 DefElem *defaultValueEl = NULL;
139 DefElem *byValueEl = NULL;
140 DefElem *alignmentEl = NULL;
141 DefElem *storageEl = NULL;
142 DefElem *collatableEl = NULL;
145 Oid receiveOid = InvalidOid;
146 Oid sendOid = InvalidOid;
147 Oid typmodinOid = InvalidOid;
148 Oid typmodoutOid = InvalidOid;
149 Oid analyzeOid = InvalidOid;
157 * As of Postgres 8.4, we require superuser privilege to create a base
158 * type. This is simple paranoia: there are too many ways to mess up the
159 * system with an incorrect type definition (for instance, representation
160 * parameters that don't match what the C code expects). In practice it
161 * takes superuser privilege to create the I/O functions, and so the
162 * former requirement that you own the I/O functions pretty much forced
163 * superuserness anyway. We're just making doubly sure here.
165 * XXX re-enable NOT_USED code sections below if you remove this test.
169 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
170 errmsg("must be superuser to create a base type")));
172 /* Convert list of names to a name and namespace */
173 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
176 /* XXX this is unnecessary given the superuser check above */
177 /* Check we have creation rights in target namespace */
178 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
179 if (aclresult != ACLCHECK_OK)
180 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
181 get_namespace_name(typeNamespace));
185 * Look to see if type already exists (presumably as a shell; if not,
186 * TypeCreate will complain).
188 typoid = GetSysCacheOid2(TYPENAMENSP,
189 CStringGetDatum(typeName),
190 ObjectIdGetDatum(typeNamespace));
193 * If it's not a shell, see if it's an autogenerated array type, and if so
194 * rename it out of the way.
196 if (OidIsValid(typoid) && get_typisdefined(typoid))
198 if (moveArrayTypeName(typoid, typeName, typeNamespace))
203 * If it doesn't exist, create it as a shell, so that the OID is known for
204 * use in the I/O function definitions.
206 if (!OidIsValid(typoid))
208 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
209 /* Make new shell type visible for modification below */
210 CommandCounterIncrement();
213 * If the command was a parameterless CREATE TYPE, we're done ---
214 * creating the shell type was all we're supposed to do.
216 if (parameters == NIL)
221 /* Complain if dummy CREATE TYPE and entry already exists */
222 if (parameters == NIL)
224 (errcode(ERRCODE_DUPLICATE_OBJECT),
225 errmsg("type \"%s\" already exists", typeName)));
228 /* Extract the parameters from the parameter list */
229 foreach(pl, parameters)
231 DefElem *defel = (DefElem *) lfirst(pl);
234 if (pg_strcasecmp(defel->defname, "like") == 0)
235 defelp = &likeTypeEl;
236 else if (pg_strcasecmp(defel->defname, "internallength") == 0)
237 defelp = &internalLengthEl;
238 else if (pg_strcasecmp(defel->defname, "input") == 0)
239 defelp = &inputNameEl;
240 else if (pg_strcasecmp(defel->defname, "output") == 0)
241 defelp = &outputNameEl;
242 else if (pg_strcasecmp(defel->defname, "receive") == 0)
243 defelp = &receiveNameEl;
244 else if (pg_strcasecmp(defel->defname, "send") == 0)
245 defelp = &sendNameEl;
246 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
247 defelp = &typmodinNameEl;
248 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
249 defelp = &typmodoutNameEl;
250 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
251 pg_strcasecmp(defel->defname, "analyse") == 0)
252 defelp = &analyzeNameEl;
253 else if (pg_strcasecmp(defel->defname, "category") == 0)
254 defelp = &categoryEl;
255 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
256 defelp = &preferredEl;
257 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
258 defelp = &delimiterEl;
259 else if (pg_strcasecmp(defel->defname, "element") == 0)
260 defelp = &elemTypeEl;
261 else if (pg_strcasecmp(defel->defname, "default") == 0)
262 defelp = &defaultValueEl;
263 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
265 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
266 defelp = &alignmentEl;
267 else if (pg_strcasecmp(defel->defname, "storage") == 0)
269 else if (pg_strcasecmp(defel->defname, "collatable") == 0)
270 defelp = &collatableEl;
273 /* WARNING, not ERROR, for historical backwards-compatibility */
275 (errcode(ERRCODE_SYNTAX_ERROR),
276 errmsg("type attribute \"%s\" not recognized",
282 (errcode(ERRCODE_SYNTAX_ERROR),
283 errmsg("conflicting or redundant options")));
288 * Now interpret the options; we do this separately so that LIKE can be
289 * overridden by other options regardless of the ordering in the parameter
295 Form_pg_type likeForm;
297 likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
298 likeForm = (Form_pg_type) GETSTRUCT(likeType);
299 internalLength = likeForm->typlen;
300 byValue = likeForm->typbyval;
301 alignment = likeForm->typalign;
302 storage = likeForm->typstorage;
303 ReleaseSysCache(likeType);
305 if (internalLengthEl)
306 internalLength = defGetTypeLength(internalLengthEl);
308 inputName = defGetQualifiedName(inputNameEl);
310 outputName = defGetQualifiedName(outputNameEl);
312 receiveName = defGetQualifiedName(receiveNameEl);
314 sendName = defGetQualifiedName(sendNameEl);
316 typmodinName = defGetQualifiedName(typmodinNameEl);
318 typmodoutName = defGetQualifiedName(typmodoutNameEl);
320 analyzeName = defGetQualifiedName(analyzeNameEl);
323 char *p = defGetString(categoryEl);
326 /* restrict to non-control ASCII */
327 if (category < 32 || category > 126)
329 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
330 errmsg("invalid type category \"%s\": must be simple ASCII",
334 preferred = defGetBoolean(preferredEl);
337 char *p = defGetString(delimiterEl);
340 /* XXX shouldn't we restrict the delimiter? */
344 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
345 /* disallow arrays of pseudotypes */
346 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
348 (errcode(ERRCODE_DATATYPE_MISMATCH),
349 errmsg("array element type cannot be %s",
350 format_type_be(elemType))));
353 defaultValue = defGetString(defaultValueEl);
355 byValue = defGetBoolean(byValueEl);
358 char *a = defGetString(alignmentEl);
361 * Note: if argument was an unquoted identifier, parser will have
362 * applied translations to it, so be prepared to recognize translated
363 * type names as well as the nominal form.
365 if (pg_strcasecmp(a, "double") == 0 ||
366 pg_strcasecmp(a, "float8") == 0 ||
367 pg_strcasecmp(a, "pg_catalog.float8") == 0)
369 else if (pg_strcasecmp(a, "int4") == 0 ||
370 pg_strcasecmp(a, "pg_catalog.int4") == 0)
372 else if (pg_strcasecmp(a, "int2") == 0 ||
373 pg_strcasecmp(a, "pg_catalog.int2") == 0)
375 else if (pg_strcasecmp(a, "char") == 0 ||
376 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
380 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
381 errmsg("alignment \"%s\" not recognized", a)));
385 char *a = defGetString(storageEl);
387 if (pg_strcasecmp(a, "plain") == 0)
389 else if (pg_strcasecmp(a, "external") == 0)
391 else if (pg_strcasecmp(a, "extended") == 0)
393 else if (pg_strcasecmp(a, "main") == 0)
397 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
398 errmsg("storage \"%s\" not recognized", a)));
401 collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
404 * make sure we have our required definitions
406 if (inputName == NIL)
408 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
409 errmsg("type input function must be specified")));
410 if (outputName == NIL)
412 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
413 errmsg("type output function must be specified")));
415 if (typmodinName == NIL && typmodoutName != NIL)
417 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
418 errmsg("type modifier output function is useless without a type modifier input function")));
421 * Convert I/O proc names to OIDs
423 inputOid = findTypeInputFunction(inputName, typoid);
424 outputOid = findTypeOutputFunction(outputName, typoid);
426 receiveOid = findTypeReceiveFunction(receiveName, typoid);
428 sendOid = findTypeSendFunction(sendName, typoid);
431 * Verify that I/O procs return the expected thing. If we see OPAQUE,
432 * complain and change it to the correct type-safe choice.
434 resulttype = get_func_rettype(inputOid);
435 if (resulttype != typoid)
437 if (resulttype == OPAQUEOID)
439 /* backwards-compatibility hack */
441 (errmsg("changing return type of function %s from \"opaque\" to %s",
442 NameListToString(inputName), typeName)));
443 SetFunctionReturnType(inputOid, typoid);
447 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
448 errmsg("type input function %s must return type %s",
449 NameListToString(inputName), typeName)));
451 resulttype = get_func_rettype(outputOid);
452 if (resulttype != CSTRINGOID)
454 if (resulttype == OPAQUEOID)
456 /* backwards-compatibility hack */
458 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
459 NameListToString(outputName))));
460 SetFunctionReturnType(outputOid, CSTRINGOID);
464 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
465 errmsg("type output function %s must return type \"cstring\"",
466 NameListToString(outputName))));
470 resulttype = get_func_rettype(receiveOid);
471 if (resulttype != typoid)
473 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
474 errmsg("type receive function %s must return type %s",
475 NameListToString(receiveName), typeName)));
479 resulttype = get_func_rettype(sendOid);
480 if (resulttype != BYTEAOID)
482 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
483 errmsg("type send function %s must return type \"bytea\"",
484 NameListToString(sendName))));
488 * Convert typmodin/out function proc names to OIDs.
491 typmodinOid = findTypeTypmodinFunction(typmodinName);
493 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
496 * Convert analysis function proc name to an OID. If no analysis function
497 * is specified, we'll use zero to select the built-in default algorithm.
500 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
503 * Check permissions on functions. We choose to require the creator/owner
504 * of a type to also own the underlying functions. Since creating a type
505 * is tantamount to granting public execute access on the functions, the
506 * minimum sane check would be for execute-with-grant-option. But we
507 * don't have a way to make the type go away if the grant option is
508 * revoked, so ownership seems better.
511 /* XXX this is unnecessary given the superuser check above */
512 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
513 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
514 NameListToString(inputName));
515 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
516 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
517 NameListToString(outputName));
518 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
519 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
520 NameListToString(receiveName));
521 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
522 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
523 NameListToString(sendName));
524 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
525 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
526 NameListToString(typmodinName));
527 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
528 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
529 NameListToString(typmodoutName));
530 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
531 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
532 NameListToString(analyzeName));
535 array_oid = AssignTypeArrayOid();
538 * now have TypeCreate do all the real work.
540 * Note: the pg_type.oid is stored in user tables as array elements (base
541 * types) in ArrayType and in composite types in DatumTupleFields. This
542 * oid must be preserved by binary upgrades.
545 TypeCreate(InvalidOid, /* no predetermined type OID */
546 typeName, /* type name */
547 typeNamespace, /* namespace */
548 InvalidOid, /* relation oid (n/a here) */
549 0, /* relation kind (ditto) */
550 GetUserId(), /* owner's ID */
551 internalLength, /* internal size */
552 TYPTYPE_BASE, /* type-type (base type) */
553 category, /* type-category */
554 preferred, /* is it a preferred type? */
555 delimiter, /* array element delimiter */
556 inputOid, /* input procedure */
557 outputOid, /* output procedure */
558 receiveOid, /* receive procedure */
559 sendOid, /* send procedure */
560 typmodinOid, /* typmodin procedure */
561 typmodoutOid, /* typmodout procedure */
562 analyzeOid, /* analyze procedure */
563 elemType, /* element type ID */
564 false, /* this is not an array type */
565 array_oid, /* array type we are about to create */
566 InvalidOid, /* base type ID (only for domains) */
567 defaultValue, /* default type value */
568 NULL, /* no binary form available */
569 byValue, /* passed by value */
570 alignment, /* required alignment */
571 storage, /* TOAST strategy */
572 -1, /* typMod (Domains only) */
573 0, /* Array Dimensions of typbasetype */
574 false, /* Type NOT NULL */
575 collation); /* type's collation */
578 * Create the array type that goes with it.
580 array_type = makeArrayTypeName(typeName, typeNamespace);
582 /* alignment must be 'i' or 'd' for arrays */
583 alignment = (alignment == 'd') ? 'd' : 'i';
585 TypeCreate(array_oid, /* force assignment of this type OID */
586 array_type, /* type name */
587 typeNamespace, /* namespace */
588 InvalidOid, /* relation oid (n/a here) */
589 0, /* relation kind (ditto) */
590 GetUserId(), /* owner's ID */
591 -1, /* internal size (always varlena) */
592 TYPTYPE_BASE, /* type-type (base type) */
593 TYPCATEGORY_ARRAY, /* type-category (array) */
594 false, /* array types are never preferred */
595 delimiter, /* array element delimiter */
596 F_ARRAY_IN, /* input procedure */
597 F_ARRAY_OUT, /* output procedure */
598 F_ARRAY_RECV, /* receive procedure */
599 F_ARRAY_SEND, /* send procedure */
600 typmodinOid, /* typmodin procedure */
601 typmodoutOid, /* typmodout procedure */
602 InvalidOid, /* analyze procedure - default */
603 typoid, /* element type ID */
604 true, /* yes this is an array type */
605 InvalidOid, /* no further array type */
606 InvalidOid, /* base type ID */
607 NULL, /* never a default type value */
608 NULL, /* binary default isn't sent either */
609 false, /* never passed by value */
610 alignment, /* see above */
611 'x', /* ARRAY is always toastable */
612 -1, /* typMod (Domains only) */
613 0, /* Array dimensions of typbasetype */
614 false, /* Type NOT NULL */
615 collation); /* type's collation */
623 * Implements DROP TYPE and DROP DOMAIN
625 * Note: if DOMAIN is specified, we enforce that each type is a domain, but
626 * we don't enforce the converse for DROP TYPE
629 RemoveTypes(DropStmt *drop)
631 ObjectAddresses *objects;
635 * First we identify all the types, then we delete them in a single
636 * performMultipleDeletions() call. This is to avoid unwanted DROP
637 * RESTRICT errors if one of the types depends on another.
639 objects = new_object_addresses();
641 foreach(cell, drop->objects)
643 List *names = (List *) lfirst(cell);
647 ObjectAddress object;
650 /* Make a TypeName so we can use standard type lookup machinery */
651 typename = makeTypeNameFromNameList(names);
653 /* Use LookupTypeName here so that shell types can be removed. */
654 tup = LookupTypeName(NULL, typename, NULL);
657 if (!drop->missing_ok)
660 (errcode(ERRCODE_UNDEFINED_OBJECT),
661 errmsg("type \"%s\" does not exist",
662 TypeNameToString(typename))));
667 (errmsg("type \"%s\" does not exist, skipping",
668 TypeNameToString(typename))));
673 typeoid = typeTypeId(tup);
674 typ = (Form_pg_type) GETSTRUCT(tup);
676 /* Permission check: must own type or its namespace */
677 if (!pg_type_ownercheck(typeoid, GetUserId()) &&
678 !pg_namespace_ownercheck(typ->typnamespace, GetUserId()))
679 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
680 format_type_be(typeoid));
682 if (drop->removeType == OBJECT_DOMAIN)
684 /* Check that this is actually a domain */
685 if (typ->typtype != TYPTYPE_DOMAIN)
687 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
688 errmsg("\"%s\" is not a domain",
689 TypeNameToString(typename))));
693 * Note: we need no special check for array types here, as the normal
694 * treatment of internal dependencies handles it just fine
697 object.classId = TypeRelationId;
698 object.objectId = typeoid;
699 object.objectSubId = 0;
701 add_exact_object_address(&object, objects);
703 ReleaseSysCache(tup);
706 performMultipleDeletions(objects, drop->behavior);
708 free_object_addresses(objects);
713 * Guts of type deletion.
716 RemoveTypeById(Oid typeOid)
721 relation = heap_open(TypeRelationId, RowExclusiveLock);
723 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
724 if (!HeapTupleIsValid(tup))
725 elog(ERROR, "cache lookup failed for type %u", typeOid);
727 simple_heap_delete(relation, &tup->t_self);
730 * If it is an enum, delete the pg_enum entries too; we don't bother with
731 * making dependency entries for those, so it has to be done "by hand"
734 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
735 EnumValuesDelete(typeOid);
737 ReleaseSysCache(tup);
739 heap_close(relation, RowExclusiveLock);
745 * Registers a new domain.
748 DefineDomain(CreateDomainStmt *stmt)
753 int16 internalLength;
756 Oid receiveProcedure;
758 Oid analyzeProcedure;
767 char *defaultValue = NULL;
768 char *defaultValueBin = NULL;
769 bool saw_default = false;
770 bool typNotNull = false;
771 bool nullDefined = false;
772 int32 typNDims = list_length(stmt->typeName->arrayBounds);
774 List *schema = stmt->constraints;
780 Form_pg_type baseType;
784 /* Convert list of names to a name and namespace */
785 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
788 /* Check we have creation rights in target namespace */
789 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
791 if (aclresult != ACLCHECK_OK)
792 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
793 get_namespace_name(domainNamespace));
796 * Check for collision with an existing type name. If there is one and
797 * it's an autogenerated array, we can rename it out of the way.
799 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
800 CStringGetDatum(domainName),
801 ObjectIdGetDatum(domainNamespace));
802 if (OidIsValid(old_type_oid))
804 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
806 (errcode(ERRCODE_DUPLICATE_OBJECT),
807 errmsg("type \"%s\" already exists", domainName)));
811 * Look up the base type.
813 typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
814 baseType = (Form_pg_type) GETSTRUCT(typeTup);
815 basetypeoid = HeapTupleGetOid(typeTup);
818 * Base type must be a plain base type, another domain or an enum. Domains
819 * over pseudotypes would create a security hole. Domains over composite
820 * types might be made to work in the future, but not today.
822 typtype = baseType->typtype;
823 if (typtype != TYPTYPE_BASE &&
824 typtype != TYPTYPE_DOMAIN &&
825 typtype != TYPTYPE_ENUM)
827 (errcode(ERRCODE_DATATYPE_MISMATCH),
828 errmsg("\"%s\" is not a valid base type for a domain",
829 TypeNameToString(stmt->typeName))));
832 * Identify the collation if any
834 baseColl = baseType->typcollation;
835 if (stmt->collClause)
836 domaincoll = get_collation_oid(stmt->collClause->collname, false);
838 domaincoll = baseColl;
840 /* Complain if COLLATE is applied to an uncollatable type */
841 if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
843 (errcode(ERRCODE_DATATYPE_MISMATCH),
844 errmsg("collations are not supported by type %s",
845 format_type_be(basetypeoid))));
847 /* passed by value */
848 byValue = baseType->typbyval;
850 /* Required Alignment */
851 alignment = baseType->typalign;
854 storage = baseType->typstorage;
857 internalLength = baseType->typlen;
860 category = baseType->typcategory;
862 /* Array element Delimiter */
863 delimiter = baseType->typdelim;
866 inputProcedure = F_DOMAIN_IN;
867 outputProcedure = baseType->typoutput;
868 receiveProcedure = F_DOMAIN_RECV;
869 sendProcedure = baseType->typsend;
871 /* Domains never accept typmods, so no typmodin/typmodout needed */
873 /* Analysis function */
874 analyzeProcedure = baseType->typanalyze;
876 /* Inherited default value */
877 datum = SysCacheGetAttr(TYPEOID, typeTup,
878 Anum_pg_type_typdefault, &isnull);
880 defaultValue = TextDatumGetCString(datum);
882 /* Inherited default binary value */
883 datum = SysCacheGetAttr(TYPEOID, typeTup,
884 Anum_pg_type_typdefaultbin, &isnull);
886 defaultValueBin = TextDatumGetCString(datum);
889 * Run through constraints manually to avoid the additional processing
890 * conducted by DefineRelation() and friends.
892 foreach(listptr, schema)
894 Constraint *constr = lfirst(listptr);
896 if (!IsA(constr, Constraint))
897 elog(ERROR, "unrecognized node type: %d",
898 (int) nodeTag(constr));
899 switch (constr->contype)
904 * The inherited default value may be overridden by the user
905 * with the DEFAULT <expr> clause ... but only once.
909 (errcode(ERRCODE_SYNTAX_ERROR),
910 errmsg("multiple default expressions")));
913 if (constr->raw_expr)
918 /* Create a dummy ParseState for transformExpr */
919 pstate = make_parsestate(NULL);
922 * Cook the constr->raw_expr into an expression. Note:
923 * name is strictly for error message
925 defaultExpr = cookDefault(pstate, constr->raw_expr,
931 * If the expression is just a NULL constant, we treat it
932 * like not having a default.
934 * Note that if the basetype is another domain, we'll see
935 * a CoerceToDomain expr here and not discard the default.
936 * This is critical because the domain default needs to be
937 * retained to override any default that the base domain
940 if (defaultExpr == NULL ||
941 (IsA(defaultExpr, Const) &&
942 ((Const *) defaultExpr)->constisnull))
945 defaultValueBin = NULL;
950 * Expression must be stored as a nodeToString result,
951 * but we also require a valid textual representation
952 * (mainly to make life easier for pg_dump).
955 deparse_expression(defaultExpr,
956 deparse_context_for(domainName,
959 defaultValueBin = nodeToString(defaultExpr);
964 /* No default (can this still happen?) */
966 defaultValueBin = NULL;
971 if (nullDefined && !typNotNull)
973 (errcode(ERRCODE_SYNTAX_ERROR),
974 errmsg("conflicting NULL/NOT NULL constraints")));
980 if (nullDefined && typNotNull)
982 (errcode(ERRCODE_SYNTAX_ERROR),
983 errmsg("conflicting NULL/NOT NULL constraints")));
991 * Check constraints are handled after domain creation, as
992 * they require the Oid of the domain
997 * All else are error cases
1001 (errcode(ERRCODE_SYNTAX_ERROR),
1002 errmsg("unique constraints not possible for domains")));
1005 case CONSTR_PRIMARY:
1007 (errcode(ERRCODE_SYNTAX_ERROR),
1008 errmsg("primary key constraints not possible for domains")));
1011 case CONSTR_EXCLUSION:
1013 (errcode(ERRCODE_SYNTAX_ERROR),
1014 errmsg("exclusion constraints not possible for domains")));
1017 case CONSTR_FOREIGN:
1019 (errcode(ERRCODE_SYNTAX_ERROR),
1020 errmsg("foreign key constraints not possible for domains")));
1023 case CONSTR_ATTR_DEFERRABLE:
1024 case CONSTR_ATTR_NOT_DEFERRABLE:
1025 case CONSTR_ATTR_DEFERRED:
1026 case CONSTR_ATTR_IMMEDIATE:
1028 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1029 errmsg("specifying constraint deferrability not supported for domains")));
1033 elog(ERROR, "unrecognized constraint subtype: %d",
1034 (int) constr->contype);
1040 * Have TypeCreate do all the real work.
1043 TypeCreate(InvalidOid, /* no predetermined type OID */
1044 domainName, /* type name */
1045 domainNamespace, /* namespace */
1046 InvalidOid, /* relation oid (n/a here) */
1047 0, /* relation kind (ditto) */
1048 GetUserId(), /* owner's ID */
1049 internalLength, /* internal size */
1050 TYPTYPE_DOMAIN, /* type-type (domain type) */
1051 category, /* type-category */
1052 false, /* domain types are never preferred */
1053 delimiter, /* array element delimiter */
1054 inputProcedure, /* input procedure */
1055 outputProcedure, /* output procedure */
1056 receiveProcedure, /* receive procedure */
1057 sendProcedure, /* send procedure */
1058 InvalidOid, /* typmodin procedure - none */
1059 InvalidOid, /* typmodout procedure - none */
1060 analyzeProcedure, /* analyze procedure */
1061 InvalidOid, /* no array element type */
1062 false, /* this isn't an array */
1063 InvalidOid, /* no arrays for domains (yet) */
1064 basetypeoid, /* base type ID */
1065 defaultValue, /* default type value (text) */
1066 defaultValueBin, /* default type value (binary) */
1067 byValue, /* passed by value */
1068 alignment, /* required alignment */
1069 storage, /* TOAST strategy */
1070 basetypeMod, /* typeMod value */
1071 typNDims, /* Array dimensions for base type */
1072 typNotNull, /* Type NOT NULL */
1073 domaincoll); /* type's collation */
1076 * Process constraints which refer to the domain ID returned by TypeCreate
1078 foreach(listptr, schema)
1080 Constraint *constr = lfirst(listptr);
1082 /* it must be a Constraint, per check above */
1084 switch (constr->contype)
1087 domainAddConstraint(domainoid, domainNamespace,
1088 basetypeoid, basetypeMod,
1089 constr, domainName);
1092 /* Other constraint types were fully processed above */
1098 /* CCI so we can detect duplicate constraint names */
1099 CommandCounterIncrement();
1103 * Now we can clean up.
1105 ReleaseSysCache(typeTup);
1111 * Registers a new enum.
1114 DefineEnum(CreateEnumStmt *stmt)
1117 char *enumArrayName;
1120 AclResult aclresult;
1124 /* Convert list of names to a name and namespace */
1125 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1128 /* Check we have creation rights in target namespace */
1129 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1130 if (aclresult != ACLCHECK_OK)
1131 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1132 get_namespace_name(enumNamespace));
1135 * Check for collision with an existing type name. If there is one and
1136 * it's an autogenerated array, we can rename it out of the way.
1138 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1139 CStringGetDatum(enumName),
1140 ObjectIdGetDatum(enumNamespace));
1141 if (OidIsValid(old_type_oid))
1143 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1145 (errcode(ERRCODE_DUPLICATE_OBJECT),
1146 errmsg("type \"%s\" already exists", enumName)));
1149 enumArrayOid = AssignTypeArrayOid();
1151 /* Create the pg_type entry */
1153 TypeCreate(InvalidOid, /* no predetermined type OID */
1154 enumName, /* type name */
1155 enumNamespace, /* namespace */
1156 InvalidOid, /* relation oid (n/a here) */
1157 0, /* relation kind (ditto) */
1158 GetUserId(), /* owner's ID */
1159 sizeof(Oid), /* internal size */
1160 TYPTYPE_ENUM, /* type-type (enum type) */
1161 TYPCATEGORY_ENUM, /* type-category (enum type) */
1162 false, /* enum types are never preferred */
1163 DEFAULT_TYPDELIM, /* array element delimiter */
1164 F_ENUM_IN, /* input procedure */
1165 F_ENUM_OUT, /* output procedure */
1166 F_ENUM_RECV, /* receive procedure */
1167 F_ENUM_SEND, /* send procedure */
1168 InvalidOid, /* typmodin procedure - none */
1169 InvalidOid, /* typmodout procedure - none */
1170 InvalidOid, /* analyze procedure - default */
1171 InvalidOid, /* element type ID */
1172 false, /* this is not an array type */
1173 enumArrayOid, /* array type we are about to create */
1174 InvalidOid, /* base type ID (only for domains) */
1175 NULL, /* never a default type value */
1176 NULL, /* binary default isn't sent either */
1177 true, /* always passed by value */
1178 'i', /* int alignment */
1179 'p', /* TOAST strategy always plain */
1180 -1, /* typMod (Domains only) */
1181 0, /* Array dimensions of typbasetype */
1182 false, /* Type NOT NULL */
1183 InvalidOid); /* type's collation */
1185 /* Enter the enum's values into pg_enum */
1186 EnumValuesCreate(enumTypeOid, stmt->vals);
1189 * Create the array type that goes with it.
1191 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1193 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1194 enumArrayName, /* type name */
1195 enumNamespace, /* namespace */
1196 InvalidOid, /* relation oid (n/a here) */
1197 0, /* relation kind (ditto) */
1198 GetUserId(), /* owner's ID */
1199 -1, /* internal size (always varlena) */
1200 TYPTYPE_BASE, /* type-type (base type) */
1201 TYPCATEGORY_ARRAY, /* type-category (array) */
1202 false, /* array types are never preferred */
1203 DEFAULT_TYPDELIM, /* array element delimiter */
1204 F_ARRAY_IN, /* input procedure */
1205 F_ARRAY_OUT, /* output procedure */
1206 F_ARRAY_RECV, /* receive procedure */
1207 F_ARRAY_SEND, /* send procedure */
1208 InvalidOid, /* typmodin procedure - none */
1209 InvalidOid, /* typmodout procedure - none */
1210 InvalidOid, /* analyze procedure - default */
1211 enumTypeOid, /* element type ID */
1212 true, /* yes this is an array type */
1213 InvalidOid, /* no further array type */
1214 InvalidOid, /* base type ID */
1215 NULL, /* never a default type value */
1216 NULL, /* binary default isn't sent either */
1217 false, /* never passed by value */
1218 'i', /* enums have align i, so do their arrays */
1219 'x', /* ARRAY is always toastable */
1220 -1, /* typMod (Domains only) */
1221 0, /* Array dimensions of typbasetype */
1222 false, /* Type NOT NULL */
1223 InvalidOid); /* type's collation */
1225 pfree(enumArrayName);
1230 * Adds a new label to an existing enum.
1233 AlterEnum(AlterEnumStmt *stmt)
1239 /* Make a TypeName so we can use standard type lookup machinery */
1240 typename = makeTypeNameFromNameList(stmt->typeName);
1241 enum_type_oid = typenameTypeId(NULL, typename);
1243 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1244 if (!HeapTupleIsValid(tup))
1245 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1247 /* Check it's an enum and check user has permission to ALTER the enum */
1248 checkEnumOwner(tup);
1250 /* Add the new label */
1251 AddEnumLabel(enum_type_oid, stmt->newVal,
1252 stmt->newValNeighbor, stmt->newValIsAfter);
1254 ReleaseSysCache(tup);
1261 * Check that the type is actually an enum and that the current user
1262 * has permission to do ALTER TYPE on it. Throw an error if not.
1265 checkEnumOwner(HeapTuple tup)
1267 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1269 /* Check that this is actually an enum */
1270 if (typTup->typtype != TYPTYPE_ENUM)
1272 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1273 errmsg("%s is not an enum",
1274 format_type_be(HeapTupleGetOid(tup)))));
1276 /* Permission check: must own type */
1277 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1278 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
1279 format_type_be(HeapTupleGetOid(tup)));
1284 * Find suitable I/O functions for a type.
1286 * typeOid is the type's OID (which will already exist, if only as a shell
1291 findTypeInputFunction(List *procname, Oid typeOid)
1297 * Input functions can take a single argument of type CSTRING, or three
1298 * arguments (string, typioparam OID, typmod).
1300 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1301 * see this, we issue a warning and fix up the pg_proc entry.
1303 argList[0] = CSTRINGOID;
1305 procOid = LookupFuncName(procname, 1, argList, true);
1306 if (OidIsValid(procOid))
1309 argList[1] = OIDOID;
1310 argList[2] = INT4OID;
1312 procOid = LookupFuncName(procname, 3, argList, true);
1313 if (OidIsValid(procOid))
1316 /* No luck, try it with OPAQUE */
1317 argList[0] = OPAQUEOID;
1319 procOid = LookupFuncName(procname, 1, argList, true);
1321 if (!OidIsValid(procOid))
1323 argList[1] = OIDOID;
1324 argList[2] = INT4OID;
1326 procOid = LookupFuncName(procname, 3, argList, true);
1329 if (OidIsValid(procOid))
1331 /* Found, but must complain and fix the pg_proc entry */
1333 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1334 NameListToString(procname))));
1335 SetFunctionArgType(procOid, 0, CSTRINGOID);
1338 * Need CommandCounterIncrement since DefineType will likely try to
1339 * alter the pg_proc tuple again.
1341 CommandCounterIncrement();
1346 /* Use CSTRING (preferred) in the error message */
1347 argList[0] = CSTRINGOID;
1350 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1351 errmsg("function %s does not exist",
1352 func_signature_string(procname, 1, NIL, argList))));
1354 return InvalidOid; /* keep compiler quiet */
1358 findTypeOutputFunction(List *procname, Oid typeOid)
1364 * Output functions can take a single argument of the type.
1366 * For backwards compatibility we allow OPAQUE in place of the actual type
1367 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1369 argList[0] = typeOid;
1371 procOid = LookupFuncName(procname, 1, argList, true);
1372 if (OidIsValid(procOid))
1375 /* No luck, try it with OPAQUE */
1376 argList[0] = OPAQUEOID;
1378 procOid = LookupFuncName(procname, 1, argList, true);
1380 if (OidIsValid(procOid))
1382 /* Found, but must complain and fix the pg_proc entry */
1384 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1385 NameListToString(procname), format_type_be(typeOid))));
1386 SetFunctionArgType(procOid, 0, typeOid);
1389 * Need CommandCounterIncrement since DefineType will likely try to
1390 * alter the pg_proc tuple again.
1392 CommandCounterIncrement();
1397 /* Use type name, not OPAQUE, in the failure message. */
1398 argList[0] = typeOid;
1401 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1402 errmsg("function %s does not exist",
1403 func_signature_string(procname, 1, NIL, argList))));
1405 return InvalidOid; /* keep compiler quiet */
1409 findTypeReceiveFunction(List *procname, Oid typeOid)
1415 * Receive functions can take a single argument of type INTERNAL, or three
1416 * arguments (internal, typioparam OID, typmod).
1418 argList[0] = INTERNALOID;
1420 procOid = LookupFuncName(procname, 1, argList, true);
1421 if (OidIsValid(procOid))
1424 argList[1] = OIDOID;
1425 argList[2] = INT4OID;
1427 procOid = LookupFuncName(procname, 3, argList, true);
1428 if (OidIsValid(procOid))
1432 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1433 errmsg("function %s does not exist",
1434 func_signature_string(procname, 1, NIL, argList))));
1436 return InvalidOid; /* keep compiler quiet */
1440 findTypeSendFunction(List *procname, Oid typeOid)
1446 * Send functions can take a single argument of the type.
1448 argList[0] = typeOid;
1450 procOid = LookupFuncName(procname, 1, argList, true);
1451 if (OidIsValid(procOid))
1455 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1456 errmsg("function %s does not exist",
1457 func_signature_string(procname, 1, NIL, argList))));
1459 return InvalidOid; /* keep compiler quiet */
1463 findTypeTypmodinFunction(List *procname)
1469 * typmodin functions always take one cstring[] argument and return int4.
1471 argList[0] = CSTRINGARRAYOID;
1473 procOid = LookupFuncName(procname, 1, argList, true);
1474 if (!OidIsValid(procOid))
1476 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1477 errmsg("function %s does not exist",
1478 func_signature_string(procname, 1, NIL, argList))));
1480 if (get_func_rettype(procOid) != INT4OID)
1482 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1483 errmsg("typmod_in function %s must return type \"integer\"",
1484 NameListToString(procname))));
1490 findTypeTypmodoutFunction(List *procname)
1496 * typmodout functions always take one int4 argument and return cstring.
1498 argList[0] = INT4OID;
1500 procOid = LookupFuncName(procname, 1, argList, true);
1501 if (!OidIsValid(procOid))
1503 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1504 errmsg("function %s does not exist",
1505 func_signature_string(procname, 1, NIL, argList))));
1507 if (get_func_rettype(procOid) != CSTRINGOID)
1509 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1510 errmsg("typmod_out function %s must return type \"cstring\"",
1511 NameListToString(procname))));
1517 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1523 * Analyze functions always take one INTERNAL argument and return bool.
1525 argList[0] = INTERNALOID;
1527 procOid = LookupFuncName(procname, 1, argList, true);
1528 if (!OidIsValid(procOid))
1530 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1531 errmsg("function %s does not exist",
1532 func_signature_string(procname, 1, NIL, argList))));
1534 if (get_func_rettype(procOid) != BOOLOID)
1536 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1537 errmsg("type analyze function %s must return type \"boolean\"",
1538 NameListToString(procname))));
1544 * AssignTypeArrayOid
1546 * Pre-assign the type's array OID for use in pg_type.typarray
1549 AssignTypeArrayOid(void)
1553 /* Use binary-upgrade override for pg_type.typarray, if supplied. */
1554 if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_array_pg_type_oid))
1556 type_array_oid = binary_upgrade_next_array_pg_type_oid;
1557 binary_upgrade_next_array_pg_type_oid = InvalidOid;
1561 Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
1563 type_array_oid = GetNewOid(pg_type);
1564 heap_close(pg_type, AccessShareLock);
1567 return type_array_oid;
1571 /*-------------------------------------------------------------------
1572 * DefineCompositeType
1574 * Create a Composite Type relation.
1575 * `DefineRelation' does all the work, we just provide the correct
1578 * If the relation already exists, then 'DefineRelation' will abort
1581 * DefineCompositeType returns relid for use when creating
1582 * an implicit composite type during function creation
1583 *-------------------------------------------------------------------
1586 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1588 CreateStmt *createStmt = makeNode(CreateStmt);
1594 * now set the parameters for keys/inheritance etc. All of these are
1595 * uninteresting for composite types...
1597 createStmt->relation = (RangeVar *) typevar;
1598 createStmt->tableElts = coldeflist;
1599 createStmt->inhRelations = NIL;
1600 createStmt->constraints = NIL;
1601 createStmt->options = list_make1(defWithOids(false));
1602 createStmt->oncommit = ONCOMMIT_NOOP;
1603 createStmt->tablespacename = NULL;
1604 createStmt->if_not_exists = false;
1607 * Check for collision with an existing type name. If there is one and
1608 * it's an autogenerated array, we can rename it out of the way. This
1609 * check is here mainly to get a better error message about a "type"
1610 * instead of below about a "relation".
1612 typeNamespace = RangeVarGetCreationNamespace(createStmt->relation);
1614 GetSysCacheOid2(TYPENAMENSP,
1615 CStringGetDatum(createStmt->relation->relname),
1616 ObjectIdGetDatum(typeNamespace));
1617 if (OidIsValid(old_type_oid))
1619 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
1621 (errcode(ERRCODE_DUPLICATE_OBJECT),
1622 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
1626 * Finally create the relation. This also creates the type.
1628 relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
1629 Assert(relid != InvalidOid);
1634 * AlterDomainDefault
1636 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
1639 AlterDomainDefault(List *names, Node *defaultRaw)
1647 Node *defaultExpr = NULL; /* NULL if no default specified */
1648 Datum new_record[Natts_pg_type];
1649 bool new_record_nulls[Natts_pg_type];
1650 bool new_record_repl[Natts_pg_type];
1652 Form_pg_type typTup;
1654 /* Make a TypeName so we can use standard type lookup machinery */
1655 typename = makeTypeNameFromNameList(names);
1656 domainoid = typenameTypeId(NULL, typename);
1658 /* Look up the domain in the type table */
1659 rel = heap_open(TypeRelationId, RowExclusiveLock);
1661 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1662 if (!HeapTupleIsValid(tup))
1663 elog(ERROR, "cache lookup failed for type %u", domainoid);
1664 typTup = (Form_pg_type) GETSTRUCT(tup);
1666 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1667 checkDomainOwner(tup);
1669 /* Setup new tuple */
1670 MemSet(new_record, (Datum) 0, sizeof(new_record));
1671 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1672 MemSet(new_record_repl, false, sizeof(new_record_repl));
1674 /* Store the new default into the tuple */
1677 /* Create a dummy ParseState for transformExpr */
1678 pstate = make_parsestate(NULL);
1681 * Cook the colDef->raw_expr into an expression. Note: Name is
1682 * strictly for error message
1684 defaultExpr = cookDefault(pstate, defaultRaw,
1685 typTup->typbasetype,
1687 NameStr(typTup->typname));
1690 * If the expression is just a NULL constant, we treat the command
1691 * like ALTER ... DROP DEFAULT. (But see note for same test in
1694 if (defaultExpr == NULL ||
1695 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
1697 /* Default is NULL, drop it */
1698 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
1699 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1700 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
1701 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1706 * Expression must be stored as a nodeToString result, but we also
1707 * require a valid textual representation (mainly to make life
1708 * easier for pg_dump).
1710 defaultValue = deparse_expression(defaultExpr,
1711 deparse_context_for(NameStr(typTup->typname),
1716 * Form an updated tuple with the new default and write it back.
1718 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
1720 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1721 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
1722 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1727 /* ALTER ... DROP DEFAULT */
1728 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
1729 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1730 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
1731 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1734 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
1735 new_record, new_record_nulls,
1738 simple_heap_update(rel, &tup->t_self, newtuple);
1740 CatalogUpdateIndexes(rel, newtuple);
1742 /* Rebuild dependencies */
1743 GenerateTypeDependencies(typTup->typnamespace,
1745 InvalidOid, /* typrelid is n/a */
1746 0, /* relation kind is n/a */
1756 false, /* a domain isn't an implicit array */
1757 typTup->typbasetype,
1758 typTup->typcollation,
1760 true); /* Rebuild is true */
1763 heap_close(rel, NoLock);
1764 heap_freetuple(newtuple);
1768 * AlterDomainNotNull
1770 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
1773 AlterDomainNotNull(List *names, bool notNull)
1779 Form_pg_type typTup;
1781 /* Make a TypeName so we can use standard type lookup machinery */
1782 typename = makeTypeNameFromNameList(names);
1783 domainoid = typenameTypeId(NULL, typename);
1785 /* Look up the domain in the type table */
1786 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1788 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1789 if (!HeapTupleIsValid(tup))
1790 elog(ERROR, "cache lookup failed for type %u", domainoid);
1791 typTup = (Form_pg_type) GETSTRUCT(tup);
1793 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1794 checkDomainOwner(tup);
1796 /* Is the domain already set to the desired constraint? */
1797 if (typTup->typnotnull == notNull)
1799 heap_close(typrel, RowExclusiveLock);
1803 /* Adding a NOT NULL constraint requires checking existing columns */
1809 /* Fetch relation list with attributes based on this domain */
1810 /* ShareLock is sufficient to prevent concurrent data changes */
1812 rels = get_rels_with_domain(domainoid, ShareLock);
1816 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1817 Relation testrel = rtc->rel;
1818 TupleDesc tupdesc = RelationGetDescr(testrel);
1822 /* Scan all tuples in this relation */
1823 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1824 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1828 /* Test attributes that are of the domain */
1829 for (i = 0; i < rtc->natts; i++)
1831 int attnum = rtc->atts[i];
1833 if (heap_attisnull(tuple, attnum))
1835 (errcode(ERRCODE_NOT_NULL_VIOLATION),
1836 errmsg("column \"%s\" of table \"%s\" contains null values",
1837 NameStr(tupdesc->attrs[attnum - 1]->attname),
1838 RelationGetRelationName(testrel))));
1843 /* Close each rel after processing, but keep lock */
1844 heap_close(testrel, NoLock);
1849 * Okay to update pg_type row. We can scribble on typTup because it's a
1852 typTup->typnotnull = notNull;
1854 simple_heap_update(typrel, &tup->t_self, tup);
1856 CatalogUpdateIndexes(typrel, tup);
1859 heap_freetuple(tup);
1860 heap_close(typrel, RowExclusiveLock);
1864 * AlterDomainDropConstraint
1866 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
1869 AlterDomainDropConstraint(List *names, const char *constrName,
1870 DropBehavior behavior)
1877 SysScanDesc conscan;
1881 /* Make a TypeName so we can use standard type lookup machinery */
1882 typename = makeTypeNameFromNameList(names);
1883 domainoid = typenameTypeId(NULL, typename);
1885 /* Look up the domain in the type table */
1886 rel = heap_open(TypeRelationId, RowExclusiveLock);
1888 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1889 if (!HeapTupleIsValid(tup))
1890 elog(ERROR, "cache lookup failed for type %u", domainoid);
1892 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1893 checkDomainOwner(tup);
1895 /* Grab an appropriate lock on the pg_constraint relation */
1896 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
1898 /* Use the index to scan only constraints of the target relation */
1899 ScanKeyInit(&key[0],
1900 Anum_pg_constraint_contypid,
1901 BTEqualStrategyNumber, F_OIDEQ,
1902 ObjectIdGetDatum(HeapTupleGetOid(tup)));
1904 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
1905 SnapshotNow, 1, key);
1908 * Scan over the result set, removing any matching entries.
1910 while ((contup = systable_getnext(conscan)) != NULL)
1912 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
1914 if (strcmp(NameStr(con->conname), constrName) == 0)
1916 ObjectAddress conobj;
1918 conobj.classId = ConstraintRelationId;
1919 conobj.objectId = HeapTupleGetOid(contup);
1920 conobj.objectSubId = 0;
1922 performDeletion(&conobj, behavior);
1925 /* Clean up after the scan */
1926 systable_endscan(conscan);
1927 heap_close(conrel, RowExclusiveLock);
1929 heap_close(rel, NoLock);
1933 * AlterDomainAddConstraint
1935 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
1938 AlterDomainAddConstraint(List *names, Node *newConstraint)
1944 Form_pg_type typTup;
1948 /* Make a TypeName so we can use standard type lookup machinery */
1949 typename = makeTypeNameFromNameList(names);
1950 domainoid = typenameTypeId(NULL, typename);
1952 /* Look up the domain in the type table */
1953 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1955 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1956 if (!HeapTupleIsValid(tup))
1957 elog(ERROR, "cache lookup failed for type %u", domainoid);
1958 typTup = (Form_pg_type) GETSTRUCT(tup);
1960 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1961 checkDomainOwner(tup);
1963 if (!IsA(newConstraint, Constraint))
1964 elog(ERROR, "unrecognized node type: %d",
1965 (int) nodeTag(newConstraint));
1967 constr = (Constraint *) newConstraint;
1969 switch (constr->contype)
1972 /* processed below */
1977 (errcode(ERRCODE_SYNTAX_ERROR),
1978 errmsg("unique constraints not possible for domains")));
1981 case CONSTR_PRIMARY:
1983 (errcode(ERRCODE_SYNTAX_ERROR),
1984 errmsg("primary key constraints not possible for domains")));
1987 case CONSTR_EXCLUSION:
1989 (errcode(ERRCODE_SYNTAX_ERROR),
1990 errmsg("exclusion constraints not possible for domains")));
1993 case CONSTR_FOREIGN:
1995 (errcode(ERRCODE_SYNTAX_ERROR),
1996 errmsg("foreign key constraints not possible for domains")));
1999 case CONSTR_ATTR_DEFERRABLE:
2000 case CONSTR_ATTR_NOT_DEFERRABLE:
2001 case CONSTR_ATTR_DEFERRED:
2002 case CONSTR_ATTR_IMMEDIATE:
2004 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2005 errmsg("specifying constraint deferrability not supported for domains")));
2009 elog(ERROR, "unrecognized constraint subtype: %d",
2010 (int) constr->contype);
2015 * Since all other constraint types throw errors, this must be a check
2016 * constraint. First, process the constraint expression and add an entry
2020 ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
2021 typTup->typbasetype, typTup->typtypmod,
2022 constr, NameStr(typTup->typname));
2025 * If requested to validate the constraint, test all values stored in the
2026 * attributes based on the domain the constraint is being added to.
2028 if (!constr->skip_validation)
2029 validateDomainConstraint(domainoid, ccbin);
2032 heap_close(typrel, RowExclusiveLock);
2036 * AlterDomainValidateConstraint
2038 * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
2041 AlterDomainValidateConstraint(List *names, char *constrName)
2048 Form_pg_type typTup;
2049 Form_pg_constraint con;
2050 Form_pg_constraint copy_con;
2057 HeapTuple copyTuple;
2060 /* Make a TypeName so we can use standard type lookup machinery */
2061 typename = makeTypeNameFromNameList(names);
2062 domainoid = typenameTypeId(NULL, typename);
2064 /* Look up the domain in the type table */
2065 typrel = heap_open(TypeRelationId, AccessShareLock);
2067 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2068 if (!HeapTupleIsValid(tup))
2069 elog(ERROR, "cache lookup failed for type %u", domainoid);
2070 typTup = (Form_pg_type) GETSTRUCT(tup);
2072 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2073 checkDomainOwner(tup);
2076 * Find and check the target constraint
2078 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2080 Anum_pg_constraint_contypid,
2081 BTEqualStrategyNumber, F_OIDEQ,
2082 ObjectIdGetDatum(domainoid));
2083 scan = systable_beginscan(conrel, ConstraintTypidIndexId,
2084 true, SnapshotNow, 1, &key);
2086 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2088 con = (Form_pg_constraint) GETSTRUCT(tuple);
2089 if (strcmp(NameStr(con->conname), constrName) == 0)
2098 con = NULL; /* keep compiler quiet */
2100 (errcode(ERRCODE_UNDEFINED_OBJECT),
2101 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2102 constrName, NameStr(con->conname))));
2105 if (con->contype != CONSTRAINT_CHECK)
2107 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2108 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2109 constrName, NameStr(con->conname))));
2111 val = SysCacheGetAttr(CONSTROID, tuple,
2112 Anum_pg_constraint_conbin,
2115 elog(ERROR, "null conbin for constraint %u",
2116 HeapTupleGetOid(tuple));
2117 conbin = TextDatumGetCString(val);
2119 validateDomainConstraint(domainoid, conbin);
2122 * Now update the catalog, while we have the door open.
2124 copyTuple = heap_copytuple(tuple);
2125 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2126 copy_con->convalidated = true;
2127 simple_heap_update(conrel, ©Tuple->t_self, copyTuple);
2128 CatalogUpdateIndexes(conrel, copyTuple);
2129 heap_freetuple(copyTuple);
2131 systable_endscan(scan);
2133 heap_close(typrel, AccessShareLock);
2134 heap_close(conrel, RowExclusiveLock);
2136 ReleaseSysCache(tup);
2140 validateDomainConstraint(Oid domainoid, char *ccbin)
2142 Expr *expr = (Expr *) stringToNode(ccbin);
2146 ExprContext *econtext;
2147 ExprState *exprstate;
2149 /* Need an EState to run ExecEvalExpr */
2150 estate = CreateExecutorState();
2151 econtext = GetPerTupleExprContext(estate);
2153 /* build execution state for expr */
2154 exprstate = ExecPrepareExpr(expr, estate);
2156 /* Fetch relation list with attributes based on this domain */
2157 /* ShareLock is sufficient to prevent concurrent data changes */
2159 rels = get_rels_with_domain(domainoid, ShareLock);
2163 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2164 Relation testrel = rtc->rel;
2165 TupleDesc tupdesc = RelationGetDescr(testrel);
2169 /* Scan all tuples in this relation */
2170 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2171 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2175 /* Test attributes that are of the domain */
2176 for (i = 0; i < rtc->natts; i++)
2178 int attnum = rtc->atts[i];
2183 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2185 econtext->domainValue_datum = d;
2186 econtext->domainValue_isNull = isNull;
2188 conResult = ExecEvalExprSwitchContext(exprstate,
2192 if (!isNull && !DatumGetBool(conResult))
2194 (errcode(ERRCODE_CHECK_VIOLATION),
2195 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2196 NameStr(tupdesc->attrs[attnum - 1]->attname),
2197 RelationGetRelationName(testrel))));
2200 ResetExprContext(econtext);
2204 /* Hold relation lock till commit (XXX bad for concurrency) */
2205 heap_close(testrel, NoLock);
2208 FreeExecutorState(estate);
2211 * get_rels_with_domain
2213 * Fetch all relations / attributes which are using the domain
2215 * The result is a list of RelToCheck structs, one for each distinct
2216 * relation, each containing one or more attribute numbers that are of
2217 * the domain type. We have opened each rel and acquired the specified lock
2220 * We support nested domains by including attributes that are of derived
2221 * domain types. Current callers do not need to distinguish between attributes
2222 * that are of exactly the given domain and those that are of derived domains.
2224 * XXX this is completely broken because there is no way to lock the domain
2225 * to prevent columns from being added or dropped while our command runs.
2226 * We can partially protect against column drops by locking relations as we
2227 * come across them, but there is still a race condition (the window between
2228 * seeing a pg_depend entry and acquiring lock on the relation it references).
2229 * Also, holding locks on all these relations simultaneously creates a non-
2230 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2231 * risk by using the weakest suitable lock (ShareLock for most callers).
2233 * XXX the API for this is not sufficient to support checking domain values
2234 * that are inside composite types or arrays. Currently we just error out
2235 * if a composite type containing the target domain is stored anywhere.
2236 * There are not currently arrays of domains; if there were, we could take
2237 * the same approach, but it'd be nicer to fix it properly.
2239 * Generally used for retrieving a list of tests when adding
2240 * new constraints to a domain.
2243 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2248 SysScanDesc depScan;
2251 Assert(lockmode != NoLock);
2254 * We scan pg_depend to find those things that depend on the domain. (We
2255 * assume we can ignore refobjsubid for a domain.)
2257 depRel = heap_open(DependRelationId, AccessShareLock);
2259 ScanKeyInit(&key[0],
2260 Anum_pg_depend_refclassid,
2261 BTEqualStrategyNumber, F_OIDEQ,
2262 ObjectIdGetDatum(TypeRelationId));
2263 ScanKeyInit(&key[1],
2264 Anum_pg_depend_refobjid,
2265 BTEqualStrategyNumber, F_OIDEQ,
2266 ObjectIdGetDatum(domainOid));
2268 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2269 SnapshotNow, 2, key);
2271 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2273 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2274 RelToCheck *rtc = NULL;
2276 Form_pg_attribute pg_att;
2279 /* Check for directly dependent types --- must be domains */
2280 if (pg_depend->classid == TypeRelationId)
2282 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2285 * Recursively add dependent columns to the output list. This is
2286 * a bit inefficient since we may fail to combine RelToCheck
2287 * entries when attributes of the same rel have different derived
2288 * domain types, but it's probably not worth improving.
2290 result = list_concat(result,
2291 get_rels_with_domain(pg_depend->objid,
2296 /* Else, ignore dependees that aren't user columns of relations */
2297 /* (we assume system columns are never of domain types) */
2298 if (pg_depend->classid != RelationRelationId ||
2299 pg_depend->objsubid <= 0)
2302 /* See if we already have an entry for this relation */
2303 foreach(rellist, result)
2305 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2307 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2316 /* First attribute found for this relation */
2319 /* Acquire requested lock on relation */
2320 rel = relation_open(pg_depend->objid, lockmode);
2323 * Check to see if rowtype is stored anyplace as a composite-type
2324 * column; if so we have to fail, for now anyway.
2326 if (OidIsValid(rel->rd_rel->reltype))
2327 find_composite_type_dependencies(rel->rd_rel->reltype,
2329 format_type_be(domainOid));
2331 /* Otherwise we can ignore views, composite types, etc */
2332 if (rel->rd_rel->relkind != RELKIND_RELATION)
2334 relation_close(rel, lockmode);
2338 /* Build the RelToCheck entry with enough space for all atts */
2339 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2342 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2343 result = lcons(rtc, result);
2347 * Confirm column has not been dropped, and is of the expected type.
2348 * This defends against an ALTER DROP COLUMN occuring just before we
2349 * acquired lock ... but if the whole table were dropped, we'd still
2352 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2354 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2355 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2359 * Okay, add column to result. We store the columns in column-number
2360 * order; this is just a hack to improve predictability of regression
2363 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2366 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2368 rtc->atts[ptr] = rtc->atts[ptr - 1];
2371 rtc->atts[ptr] = pg_depend->objsubid;
2374 systable_endscan(depScan);
2376 relation_close(depRel, AccessShareLock);
2384 * Check that the type is actually a domain and that the current user
2385 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2388 checkDomainOwner(HeapTuple tup)
2390 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2392 /* Check that this is actually a domain */
2393 if (typTup->typtype != TYPTYPE_DOMAIN)
2395 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2396 errmsg("%s is not a domain",
2397 format_type_be(HeapTupleGetOid(tup)))));
2399 /* Permission check: must own type */
2400 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2401 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2402 format_type_be(HeapTupleGetOid(tup)));
2406 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2409 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2410 int typMod, Constraint *constr,
2417 CoerceToDomainValue *domVal;
2420 * Assign or validate constraint name
2422 if (constr->conname)
2424 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2429 (errcode(ERRCODE_DUPLICATE_OBJECT),
2430 errmsg("constraint \"%s\" for domain \"%s\" already exists",
2431 constr->conname, domainName)));
2434 constr->conname = ChooseConstraintName(domainName,
2441 * Convert the A_EXPR in raw_expr into an EXPR
2443 pstate = make_parsestate(NULL);
2446 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2447 * the expression. Note that it will appear to have the type of the base
2448 * type, not the domain. This seems correct since within the check
2449 * expression, we should not assume the input value can be considered a
2450 * member of the domain.
2452 domVal = makeNode(CoerceToDomainValue);
2453 domVal->typeId = baseTypeOid;
2454 domVal->typeMod = typMod;
2455 domVal->collation = get_typcollation(baseTypeOid);
2456 domVal->location = -1; /* will be set when/if used */
2458 pstate->p_value_substitute = (Node *) domVal;
2460 expr = transformExpr(pstate, constr->raw_expr);
2463 * Make sure it yields a boolean result.
2465 expr = coerce_to_boolean(pstate, expr, "CHECK");
2468 * Fix up collation information.
2470 assign_expr_collations(pstate, expr);
2473 * Make sure no outside relations are referred to.
2475 if (list_length(pstate->p_rtable) != 0)
2477 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2478 errmsg("cannot use table references in domain check constraint")));
2481 * Domains don't allow var clauses (this should be redundant with the
2482 * above check, but make it anyway)
2484 if (contain_var_clause(expr))
2486 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2487 errmsg("cannot use table references in domain check constraint")));
2490 * No subplans or aggregates, either...
2492 if (pstate->p_hasSubLinks)
2494 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2495 errmsg("cannot use subquery in check constraint")));
2496 if (pstate->p_hasAggs)
2498 (errcode(ERRCODE_GROUPING_ERROR),
2499 errmsg("cannot use aggregate function in check constraint")));
2500 if (pstate->p_hasWindowFuncs)
2502 (errcode(ERRCODE_WINDOWING_ERROR),
2503 errmsg("cannot use window function in check constraint")));
2506 * Convert to string form for storage.
2508 ccbin = nodeToString(expr);
2511 * Deparse it to produce text for consrc.
2513 * Since VARNOs aren't allowed in domain constraints, relation context
2514 * isn't required as anything other than a shell.
2516 ccsrc = deparse_expression(expr,
2517 deparse_context_for(domainName,
2522 * Store the constraint in pg_constraint
2524 CreateConstraintEntry(constr->conname, /* Constraint Name */
2525 domainNamespace, /* namespace */
2526 CONSTRAINT_CHECK, /* Constraint Type */
2527 false, /* Is Deferrable */
2528 false, /* Is Deferred */
2529 !constr->skip_validation, /* Is Validated */
2530 InvalidOid, /* not a relation constraint */
2533 domainOid, /* domain constraint */
2534 InvalidOid, /* no associated index */
2535 InvalidOid, /* Foreign key fields */
2544 NULL, /* not an exclusion constraint */
2545 expr, /* Tree form of check constraint */
2546 ccbin, /* Binary form of check constraint */
2547 ccsrc, /* Source form of check constraint */
2548 true, /* is local */
2552 * Return the compiled constraint expression so the calling routine can
2553 * perform any additional required tests.
2559 * GetDomainConstraints - get a list of the current constraints of domain
2561 * Returns a possibly-empty list of DomainConstraintState nodes.
2563 * This is called by the executor during plan startup for a CoerceToDomain
2564 * expression node. The given constraints will be checked for each value
2565 * passed through the node.
2567 * We allow this to be called for non-domain types, in which case the result
2571 GetDomainConstraints(Oid typeOid)
2574 bool notNull = false;
2577 conRel = heap_open(ConstraintRelationId, AccessShareLock);
2583 Form_pg_type typTup;
2587 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
2588 if (!HeapTupleIsValid(tup))
2589 elog(ERROR, "cache lookup failed for type %u", typeOid);
2590 typTup = (Form_pg_type) GETSTRUCT(tup);
2592 if (typTup->typtype != TYPTYPE_DOMAIN)
2594 /* Not a domain, so done */
2595 ReleaseSysCache(tup);
2599 /* Test for NOT NULL Constraint */
2600 if (typTup->typnotnull)
2603 /* Look for CHECK Constraints on this domain */
2604 ScanKeyInit(&key[0],
2605 Anum_pg_constraint_contypid,
2606 BTEqualStrategyNumber, F_OIDEQ,
2607 ObjectIdGetDatum(typeOid));
2609 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
2610 SnapshotNow, 1, key);
2612 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
2614 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
2618 DomainConstraintState *r;
2620 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
2621 if (c->contype != CONSTRAINT_CHECK)
2625 * Not expecting conbin to be NULL, but we'll test for it anyway
2627 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
2628 conRel->rd_att, &isNull);
2630 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
2631 NameStr(typTup->typname), NameStr(c->conname));
2633 check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
2635 /* ExecInitExpr assumes we've planned the expression */
2636 check_expr = expression_planner(check_expr);
2638 r = makeNode(DomainConstraintState);
2639 r->constrainttype = DOM_CONSTRAINT_CHECK;
2640 r->name = pstrdup(NameStr(c->conname));
2641 r->check_expr = ExecInitExpr(check_expr, NULL);
2644 * use lcons() here because constraints of lower domains should be
2647 result = lcons(r, result);
2650 systable_endscan(scan);
2652 /* loop to next domain in stack */
2653 typeOid = typTup->typbasetype;
2654 ReleaseSysCache(tup);
2657 heap_close(conRel, AccessShareLock);
2660 * Only need to add one NOT NULL check regardless of how many domains in
2661 * the stack request it.
2665 DomainConstraintState *r = makeNode(DomainConstraintState);
2667 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
2668 r->name = pstrdup("NOT NULL");
2669 r->check_expr = NULL;
2671 /* lcons to apply the nullness check FIRST */
2672 result = lcons(r, result);
2680 * Execute ALTER TYPE RENAME
2683 RenameType(List *names, const char *newTypeName)
2689 Form_pg_type typTup;
2691 /* Make a TypeName so we can use standard type lookup machinery */
2692 typename = makeTypeNameFromNameList(names);
2693 typeOid = typenameTypeId(NULL, typename);
2695 /* Look up the type in the type table */
2696 rel = heap_open(TypeRelationId, RowExclusiveLock);
2698 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
2699 if (!HeapTupleIsValid(tup))
2700 elog(ERROR, "cache lookup failed for type %u", typeOid);
2701 typTup = (Form_pg_type) GETSTRUCT(tup);
2703 /* check permissions on type */
2704 if (!pg_type_ownercheck(typeOid, GetUserId()))
2705 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2706 format_type_be(typeOid));
2709 * If it's a composite type, we need to check that it really is a
2710 * free-standing composite type, and not a table's rowtype. We want people
2711 * to use ALTER TABLE not ALTER TYPE for that case.
2713 if (typTup->typtype == TYPTYPE_COMPOSITE &&
2714 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2716 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2717 errmsg("%s is a table's row type",
2718 format_type_be(typeOid)),
2719 errhint("Use ALTER TABLE instead.")));
2721 /* don't allow direct alteration of array types, either */
2722 if (OidIsValid(typTup->typelem) &&
2723 get_array_type(typTup->typelem) == typeOid)
2725 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2726 errmsg("cannot alter array type %s",
2727 format_type_be(typeOid)),
2728 errhint("You can alter type %s, which will alter the array type as well.",
2729 format_type_be(typTup->typelem))));
2732 * If type is composite we need to rename associated pg_class entry too.
2733 * RenameRelationInternal will call RenameTypeInternal automatically.
2735 if (typTup->typtype == TYPTYPE_COMPOSITE)
2736 RenameRelationInternal(typTup->typrelid, newTypeName,
2737 typTup->typnamespace);
2739 RenameTypeInternal(typeOid, newTypeName,
2740 typTup->typnamespace);
2743 heap_close(rel, RowExclusiveLock);
2747 * Change the owner of a type.
2750 AlterTypeOwner(List *names, Oid newOwnerId)
2757 Form_pg_type typTup;
2758 AclResult aclresult;
2760 rel = heap_open(TypeRelationId, RowExclusiveLock);
2762 /* Make a TypeName so we can use standard type lookup machinery */
2763 typename = makeTypeNameFromNameList(names);
2765 /* Use LookupTypeName here so that shell types can be processed */
2766 tup = LookupTypeName(NULL, typename, NULL);
2769 (errcode(ERRCODE_UNDEFINED_OBJECT),
2770 errmsg("type \"%s\" does not exist",
2771 TypeNameToString(typename))));
2772 typeOid = typeTypeId(tup);
2774 /* Copy the syscache entry so we can scribble on it below */
2775 newtup = heap_copytuple(tup);
2776 ReleaseSysCache(tup);
2778 typTup = (Form_pg_type) GETSTRUCT(tup);
2781 * If it's a composite type, we need to check that it really is a
2782 * free-standing composite type, and not a table's rowtype. We want people
2783 * to use ALTER TABLE not ALTER TYPE for that case.
2785 if (typTup->typtype == TYPTYPE_COMPOSITE &&
2786 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2788 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2789 errmsg("%s is a table's row type",
2790 format_type_be(typeOid)),
2791 errhint("Use ALTER TABLE instead.")));
2793 /* don't allow direct alteration of array types, either */
2794 if (OidIsValid(typTup->typelem) &&
2795 get_array_type(typTup->typelem) == typeOid)
2797 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2798 errmsg("cannot alter array type %s",
2799 format_type_be(typeOid)),
2800 errhint("You can alter type %s, which will alter the array type as well.",
2801 format_type_be(typTup->typelem))));
2804 * If the new owner is the same as the existing owner, consider the
2805 * command to have succeeded. This is for dump restoration purposes.
2807 if (typTup->typowner != newOwnerId)
2809 /* Superusers can always do it */
2812 /* Otherwise, must be owner of the existing object */
2813 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2814 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2815 format_type_be(HeapTupleGetOid(tup)));
2817 /* Must be able to become new owner */
2818 check_is_member_of_role(GetUserId(), newOwnerId);
2820 /* New owner must have CREATE privilege on namespace */
2821 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
2824 if (aclresult != ACLCHECK_OK)
2825 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
2826 get_namespace_name(typTup->typnamespace));
2830 * If it's a composite type, invoke ATExecChangeOwner so that we fix
2831 * up the pg_class entry properly. That will call back to
2832 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
2834 if (typTup->typtype == TYPTYPE_COMPOSITE)
2835 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
2839 * We can just apply the modification directly.
2841 * okay to scribble on typTup because it's a copy
2843 typTup->typowner = newOwnerId;
2845 simple_heap_update(rel, &tup->t_self, tup);
2847 CatalogUpdateIndexes(rel, tup);
2849 /* Update owner dependency reference */
2850 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2852 /* If it has an array type, update that too */
2853 if (OidIsValid(typTup->typarray))
2854 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
2859 heap_close(rel, RowExclusiveLock);
2863 * AlterTypeOwnerInternal - change type owner unconditionally
2865 * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
2866 * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
2867 * It assumes the caller has done all needed checks. The function will
2868 * automatically recurse to an array type if the type has one.
2870 * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
2871 * entry (ie, it's not a table rowtype nor an array type).
2874 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
2875 bool hasDependEntry)
2879 Form_pg_type typTup;
2881 rel = heap_open(TypeRelationId, RowExclusiveLock);
2883 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
2884 if (!HeapTupleIsValid(tup))
2885 elog(ERROR, "cache lookup failed for type %u", typeOid);
2886 typTup = (Form_pg_type) GETSTRUCT(tup);
2889 * Modify the owner --- okay to scribble on typTup because it's a copy
2891 typTup->typowner = newOwnerId;
2893 simple_heap_update(rel, &tup->t_self, tup);
2895 CatalogUpdateIndexes(rel, tup);
2897 /* Update owner dependency reference, if it has one */
2899 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2901 /* If it has an array type, update that too */
2902 if (OidIsValid(typTup->typarray))
2903 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
2906 heap_close(rel, RowExclusiveLock);
2910 * Execute ALTER TYPE SET SCHEMA
2913 AlterTypeNamespace(List *names, const char *newschema)
2919 /* Make a TypeName so we can use standard type lookup machinery */
2920 typename = makeTypeNameFromNameList(names);
2921 typeOid = typenameTypeId(NULL, typename);
2923 /* get schema OID and check its permissions */
2924 nspOid = LookupCreationNamespace(newschema);
2926 AlterTypeNamespace_oid(typeOid, nspOid);
2930 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid)
2934 /* check permissions on type */
2935 if (!pg_type_ownercheck(typeOid, GetUserId()))
2936 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2937 format_type_be(typeOid));
2939 /* don't allow direct alteration of array types */
2940 elemOid = get_element_type(typeOid);
2941 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
2943 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2944 errmsg("cannot alter array type %s",
2945 format_type_be(typeOid)),
2946 errhint("You can alter type %s, which will alter the array type as well.",
2947 format_type_be(elemOid))));
2949 /* and do the work */
2950 return AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
2954 * Move specified type to new namespace.
2956 * Caller must have already checked privileges.
2958 * The function automatically recurses to process the type's array type,
2959 * if any. isImplicitArray should be TRUE only when doing this internal
2960 * recursion (outside callers must never try to move an array type directly).
2962 * If errorOnTableType is TRUE, the function errors out if the type is
2963 * a table type. ALTER TABLE has to be used to move a table to a new
2966 * Returns the type's old namespace OID.
2969 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
2970 bool isImplicitArray,
2971 bool errorOnTableType)
2975 Form_pg_type typform;
2978 bool isCompositeType;
2980 rel = heap_open(TypeRelationId, RowExclusiveLock);
2982 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
2983 if (!HeapTupleIsValid(tup))
2984 elog(ERROR, "cache lookup failed for type %u", typeOid);
2985 typform = (Form_pg_type) GETSTRUCT(tup);
2987 oldNspOid = typform->typnamespace;
2988 arrayOid = typform->typarray;
2990 /* common checks on switching namespaces */
2991 CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
2993 /* check for duplicate name (more friendly than unique-index failure) */
2994 if (SearchSysCacheExists2(TYPENAMENSP,
2995 CStringGetDatum(NameStr(typform->typname)),
2996 ObjectIdGetDatum(nspOid)))
2998 (errcode(ERRCODE_DUPLICATE_OBJECT),
2999 errmsg("type \"%s\" already exists in schema \"%s\"",
3000 NameStr(typform->typname),
3001 get_namespace_name(nspOid))));
3003 /* Detect whether type is a composite type (but not a table rowtype) */
3005 (typform->typtype == TYPTYPE_COMPOSITE &&
3006 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3008 /* Enforce not-table-type if requested */
3009 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3012 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3013 errmsg("%s is a table's row type",
3014 format_type_be(typeOid)),
3015 errhint("Use ALTER TABLE instead.")));
3017 /* OK, modify the pg_type row */
3019 /* tup is a copy, so we can scribble directly on it */
3020 typform->typnamespace = nspOid;
3022 simple_heap_update(rel, &tup->t_self, tup);
3023 CatalogUpdateIndexes(rel, tup);
3026 * Composite types have pg_class entries.
3028 * We need to modify the pg_class tuple as well to reflect the change of
3031 if (isCompositeType)
3035 classRel = heap_open(RelationRelationId, RowExclusiveLock);
3037 AlterRelationNamespaceInternal(classRel, typform->typrelid,
3041 heap_close(classRel, RowExclusiveLock);
3044 * Check for constraints associated with the composite type (we don't
3045 * currently support this, but probably will someday).
3047 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3052 /* If it's a domain, it might have constraints */
3053 if (typform->typtype == TYPTYPE_DOMAIN)
3054 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
3058 * Update dependency on schema, if any --- a table rowtype has not got
3059 * one, and neither does an implicit array.
3061 if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3063 if (changeDependencyFor(TypeRelationId, typeOid,
3064 NamespaceRelationId, oldNspOid, nspOid) != 1)
3065 elog(ERROR, "failed to change schema dependency for type %s",
3066 format_type_be(typeOid));
3068 heap_freetuple(tup);
3070 heap_close(rel, RowExclusiveLock);
3072 /* Recursively alter the associated array type, if any */
3073 if (OidIsValid(arrayOid))
3074 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);