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/rel.h"
67 #include "utils/syscache.h"
68 #include "utils/tqual.h"
71 /* result structure for get_rels_with_domain() */
74 Relation rel; /* opened and locked relation */
75 int natts; /* number of attributes of interest */
76 int *atts; /* attribute numbers */
77 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
80 /* Potentially set by contrib/pg_upgrade_support functions */
81 Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
83 static Oid findTypeInputFunction(List *procname, Oid typeOid);
84 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
85 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
86 static Oid findTypeSendFunction(List *procname, Oid typeOid);
87 static Oid findTypeTypmodinFunction(List *procname);
88 static Oid findTypeTypmodoutFunction(List *procname);
89 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
90 static void validateDomainConstraint(Oid domainoid, char *ccbin);
91 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
92 static void checkDomainOwner(HeapTuple tup);
93 static void checkEnumOwner(HeapTuple tup);
94 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
96 int typMod, Constraint *constr,
102 * Registers a new base type.
105 DefineType(List *names, List *parameters)
109 int16 internalLength = -1; /* default: variable-length */
110 List *inputName = NIL;
111 List *outputName = NIL;
112 List *receiveName = NIL;
113 List *sendName = NIL;
114 List *typmodinName = NIL;
115 List *typmodoutName = NIL;
116 List *analyzeName = NIL;
117 char category = TYPCATEGORY_USER;
118 bool preferred = false;
119 char delimiter = DEFAULT_TYPDELIM;
120 Oid elemType = InvalidOid;
121 char *defaultValue = NULL;
122 bool byValue = false;
123 char alignment = 'i'; /* default alignment */
124 char storage = 'p'; /* default TOAST storage method */
125 Oid collation = InvalidOid;
126 DefElem *likeTypeEl = NULL;
127 DefElem *internalLengthEl = NULL;
128 DefElem *inputNameEl = NULL;
129 DefElem *outputNameEl = NULL;
130 DefElem *receiveNameEl = NULL;
131 DefElem *sendNameEl = NULL;
132 DefElem *typmodinNameEl = NULL;
133 DefElem *typmodoutNameEl = NULL;
134 DefElem *analyzeNameEl = NULL;
135 DefElem *categoryEl = NULL;
136 DefElem *preferredEl = NULL;
137 DefElem *delimiterEl = NULL;
138 DefElem *elemTypeEl = NULL;
139 DefElem *defaultValueEl = NULL;
140 DefElem *byValueEl = NULL;
141 DefElem *alignmentEl = NULL;
142 DefElem *storageEl = NULL;
143 DefElem *collatableEl = NULL;
146 Oid receiveOid = InvalidOid;
147 Oid sendOid = InvalidOid;
148 Oid typmodinOid = InvalidOid;
149 Oid typmodoutOid = InvalidOid;
150 Oid analyzeOid = InvalidOid;
158 * As of Postgres 8.4, we require superuser privilege to create a base
159 * type. This is simple paranoia: there are too many ways to mess up the
160 * system with an incorrect type definition (for instance, representation
161 * parameters that don't match what the C code expects). In practice it
162 * takes superuser privilege to create the I/O functions, and so the
163 * former requirement that you own the I/O functions pretty much forced
164 * superuserness anyway. We're just making doubly sure here.
166 * XXX re-enable NOT_USED code sections below if you remove this test.
170 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
171 errmsg("must be superuser to create a base type")));
173 /* Convert list of names to a name and namespace */
174 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
177 /* XXX this is unnecessary given the superuser check above */
178 /* Check we have creation rights in target namespace */
179 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
180 if (aclresult != ACLCHECK_OK)
181 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
182 get_namespace_name(typeNamespace));
186 * Look to see if type already exists (presumably as a shell; if not,
187 * TypeCreate will complain).
189 typoid = GetSysCacheOid2(TYPENAMENSP,
190 CStringGetDatum(typeName),
191 ObjectIdGetDatum(typeNamespace));
194 * If it's not a shell, see if it's an autogenerated array type, and if so
195 * rename it out of the way.
197 if (OidIsValid(typoid) && get_typisdefined(typoid))
199 if (moveArrayTypeName(typoid, typeName, typeNamespace))
204 * If it doesn't exist, create it as a shell, so that the OID is known for
205 * use in the I/O function definitions.
207 if (!OidIsValid(typoid))
209 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
210 /* Make new shell type visible for modification below */
211 CommandCounterIncrement();
214 * If the command was a parameterless CREATE TYPE, we're done ---
215 * creating the shell type was all we're supposed to do.
217 if (parameters == NIL)
222 /* Complain if dummy CREATE TYPE and entry already exists */
223 if (parameters == NIL)
225 (errcode(ERRCODE_DUPLICATE_OBJECT),
226 errmsg("type \"%s\" already exists", typeName)));
229 /* Extract the parameters from the parameter list */
230 foreach(pl, parameters)
232 DefElem *defel = (DefElem *) lfirst(pl);
235 if (pg_strcasecmp(defel->defname, "like") == 0)
236 defelp = &likeTypeEl;
237 else if (pg_strcasecmp(defel->defname, "internallength") == 0)
238 defelp = &internalLengthEl;
239 else if (pg_strcasecmp(defel->defname, "input") == 0)
240 defelp = &inputNameEl;
241 else if (pg_strcasecmp(defel->defname, "output") == 0)
242 defelp = &outputNameEl;
243 else if (pg_strcasecmp(defel->defname, "receive") == 0)
244 defelp = &receiveNameEl;
245 else if (pg_strcasecmp(defel->defname, "send") == 0)
246 defelp = &sendNameEl;
247 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
248 defelp = &typmodinNameEl;
249 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
250 defelp = &typmodoutNameEl;
251 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
252 pg_strcasecmp(defel->defname, "analyse") == 0)
253 defelp = &analyzeNameEl;
254 else if (pg_strcasecmp(defel->defname, "category") == 0)
255 defelp = &categoryEl;
256 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
257 defelp = &preferredEl;
258 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
259 defelp = &delimiterEl;
260 else if (pg_strcasecmp(defel->defname, "element") == 0)
261 defelp = &elemTypeEl;
262 else if (pg_strcasecmp(defel->defname, "default") == 0)
263 defelp = &defaultValueEl;
264 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
266 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
267 defelp = &alignmentEl;
268 else if (pg_strcasecmp(defel->defname, "storage") == 0)
270 else if (pg_strcasecmp(defel->defname, "collatable") == 0)
271 defelp = &collatableEl;
274 /* WARNING, not ERROR, for historical backwards-compatibility */
276 (errcode(ERRCODE_SYNTAX_ERROR),
277 errmsg("type attribute \"%s\" not recognized",
283 (errcode(ERRCODE_SYNTAX_ERROR),
284 errmsg("conflicting or redundant options")));
289 * Now interpret the options; we do this separately so that LIKE can be
290 * overridden by other options regardless of the ordering in the parameter
296 Form_pg_type likeForm;
298 likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
299 likeForm = (Form_pg_type) GETSTRUCT(likeType);
300 internalLength = likeForm->typlen;
301 byValue = likeForm->typbyval;
302 alignment = likeForm->typalign;
303 storage = likeForm->typstorage;
304 ReleaseSysCache(likeType);
306 if (internalLengthEl)
307 internalLength = defGetTypeLength(internalLengthEl);
309 inputName = defGetQualifiedName(inputNameEl);
311 outputName = defGetQualifiedName(outputNameEl);
313 receiveName = defGetQualifiedName(receiveNameEl);
315 sendName = defGetQualifiedName(sendNameEl);
317 typmodinName = defGetQualifiedName(typmodinNameEl);
319 typmodoutName = defGetQualifiedName(typmodoutNameEl);
321 analyzeName = defGetQualifiedName(analyzeNameEl);
324 char *p = defGetString(categoryEl);
327 /* restrict to non-control ASCII */
328 if (category < 32 || category > 126)
330 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
331 errmsg("invalid type category \"%s\": must be simple ASCII",
335 preferred = defGetBoolean(preferredEl);
338 char *p = defGetString(delimiterEl);
341 /* XXX shouldn't we restrict the delimiter? */
345 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
346 /* disallow arrays of pseudotypes */
347 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
349 (errcode(ERRCODE_DATATYPE_MISMATCH),
350 errmsg("array element type cannot be %s",
351 format_type_be(elemType))));
354 defaultValue = defGetString(defaultValueEl);
356 byValue = defGetBoolean(byValueEl);
359 char *a = defGetString(alignmentEl);
362 * Note: if argument was an unquoted identifier, parser will have
363 * applied translations to it, so be prepared to recognize translated
364 * type names as well as the nominal form.
366 if (pg_strcasecmp(a, "double") == 0 ||
367 pg_strcasecmp(a, "float8") == 0 ||
368 pg_strcasecmp(a, "pg_catalog.float8") == 0)
370 else if (pg_strcasecmp(a, "int4") == 0 ||
371 pg_strcasecmp(a, "pg_catalog.int4") == 0)
373 else if (pg_strcasecmp(a, "int2") == 0 ||
374 pg_strcasecmp(a, "pg_catalog.int2") == 0)
376 else if (pg_strcasecmp(a, "char") == 0 ||
377 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
381 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
382 errmsg("alignment \"%s\" not recognized", a)));
386 char *a = defGetString(storageEl);
388 if (pg_strcasecmp(a, "plain") == 0)
390 else if (pg_strcasecmp(a, "external") == 0)
392 else if (pg_strcasecmp(a, "extended") == 0)
394 else if (pg_strcasecmp(a, "main") == 0)
398 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
399 errmsg("storage \"%s\" not recognized", a)));
402 collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
405 * make sure we have our required definitions
407 if (inputName == NIL)
409 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
410 errmsg("type input function must be specified")));
411 if (outputName == NIL)
413 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
414 errmsg("type output function must be specified")));
416 if (typmodinName == NIL && typmodoutName != NIL)
418 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
419 errmsg("type modifier output function is useless without a type modifier input function")));
422 * Convert I/O proc names to OIDs
424 inputOid = findTypeInputFunction(inputName, typoid);
425 outputOid = findTypeOutputFunction(outputName, typoid);
427 receiveOid = findTypeReceiveFunction(receiveName, typoid);
429 sendOid = findTypeSendFunction(sendName, typoid);
432 * Verify that I/O procs return the expected thing. If we see OPAQUE,
433 * complain and change it to the correct type-safe choice.
435 resulttype = get_func_rettype(inputOid);
436 if (resulttype != typoid)
438 if (resulttype == OPAQUEOID)
440 /* backwards-compatibility hack */
442 (errmsg("changing return type of function %s from \"opaque\" to %s",
443 NameListToString(inputName), typeName)));
444 SetFunctionReturnType(inputOid, typoid);
448 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
449 errmsg("type input function %s must return type %s",
450 NameListToString(inputName), typeName)));
452 resulttype = get_func_rettype(outputOid);
453 if (resulttype != CSTRINGOID)
455 if (resulttype == OPAQUEOID)
457 /* backwards-compatibility hack */
459 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
460 NameListToString(outputName))));
461 SetFunctionReturnType(outputOid, CSTRINGOID);
465 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
466 errmsg("type output function %s must return type \"cstring\"",
467 NameListToString(outputName))));
471 resulttype = get_func_rettype(receiveOid);
472 if (resulttype != typoid)
474 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
475 errmsg("type receive function %s must return type %s",
476 NameListToString(receiveName), typeName)));
480 resulttype = get_func_rettype(sendOid);
481 if (resulttype != BYTEAOID)
483 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
484 errmsg("type send function %s must return type \"bytea\"",
485 NameListToString(sendName))));
489 * Convert typmodin/out function proc names to OIDs.
492 typmodinOid = findTypeTypmodinFunction(typmodinName);
494 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
497 * Convert analysis function proc name to an OID. If no analysis function
498 * is specified, we'll use zero to select the built-in default algorithm.
501 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
504 * Check permissions on functions. We choose to require the creator/owner
505 * of a type to also own the underlying functions. Since creating a type
506 * is tantamount to granting public execute access on the functions, the
507 * minimum sane check would be for execute-with-grant-option. But we
508 * don't have a way to make the type go away if the grant option is
509 * revoked, so ownership seems better.
512 /* XXX this is unnecessary given the superuser check above */
513 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
514 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
515 NameListToString(inputName));
516 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
517 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
518 NameListToString(outputName));
519 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
520 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
521 NameListToString(receiveName));
522 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
523 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
524 NameListToString(sendName));
525 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
526 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
527 NameListToString(typmodinName));
528 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
529 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
530 NameListToString(typmodoutName));
531 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
532 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
533 NameListToString(analyzeName));
536 array_oid = AssignTypeArrayOid();
539 * now have TypeCreate do all the real work.
541 * Note: the pg_type.oid is stored in user tables as array elements (base
542 * types) in ArrayType and in composite types in DatumTupleFields. This
543 * oid must be preserved by binary upgrades.
546 TypeCreate(InvalidOid, /* no predetermined type OID */
547 typeName, /* type name */
548 typeNamespace, /* namespace */
549 InvalidOid, /* relation oid (n/a here) */
550 0, /* relation kind (ditto) */
551 GetUserId(), /* owner's ID */
552 internalLength, /* internal size */
553 TYPTYPE_BASE, /* type-type (base type) */
554 category, /* type-category */
555 preferred, /* is it a preferred type? */
556 delimiter, /* array element delimiter */
557 inputOid, /* input procedure */
558 outputOid, /* output procedure */
559 receiveOid, /* receive procedure */
560 sendOid, /* send procedure */
561 typmodinOid, /* typmodin procedure */
562 typmodoutOid, /* typmodout procedure */
563 analyzeOid, /* analyze procedure */
564 elemType, /* element type ID */
565 false, /* this is not an array type */
566 array_oid, /* array type we are about to create */
567 InvalidOid, /* base type ID (only for domains) */
568 defaultValue, /* default type value */
569 NULL, /* no binary form available */
570 byValue, /* passed by value */
571 alignment, /* required alignment */
572 storage, /* TOAST strategy */
573 -1, /* typMod (Domains only) */
574 0, /* Array Dimensions of typbasetype */
575 false, /* Type NOT NULL */
576 collation); /* type's collation */
579 * Create the array type that goes with it.
581 array_type = makeArrayTypeName(typeName, typeNamespace);
583 /* alignment must be 'i' or 'd' for arrays */
584 alignment = (alignment == 'd') ? 'd' : 'i';
586 TypeCreate(array_oid, /* force assignment of this type OID */
587 array_type, /* type name */
588 typeNamespace, /* namespace */
589 InvalidOid, /* relation oid (n/a here) */
590 0, /* relation kind (ditto) */
591 GetUserId(), /* owner's ID */
592 -1, /* internal size (always varlena) */
593 TYPTYPE_BASE, /* type-type (base type) */
594 TYPCATEGORY_ARRAY, /* type-category (array) */
595 false, /* array types are never preferred */
596 delimiter, /* array element delimiter */
597 F_ARRAY_IN, /* input procedure */
598 F_ARRAY_OUT, /* output procedure */
599 F_ARRAY_RECV, /* receive procedure */
600 F_ARRAY_SEND, /* send procedure */
601 typmodinOid, /* typmodin procedure */
602 typmodoutOid, /* typmodout procedure */
603 InvalidOid, /* analyze procedure - default */
604 typoid, /* element type ID */
605 true, /* yes this is an array type */
606 InvalidOid, /* no further array type */
607 InvalidOid, /* base type ID */
608 NULL, /* never a default type value */
609 NULL, /* binary default isn't sent either */
610 false, /* never passed by value */
611 alignment, /* see above */
612 'x', /* ARRAY is always toastable */
613 -1, /* typMod (Domains only) */
614 0, /* Array dimensions of typbasetype */
615 false, /* Type NOT NULL */
616 collation); /* type's collation */
624 * Implements DROP TYPE and DROP DOMAIN
626 * Note: if DOMAIN is specified, we enforce that each type is a domain, but
627 * we don't enforce the converse for DROP TYPE
630 RemoveTypes(DropStmt *drop)
632 ObjectAddresses *objects;
636 * First we identify all the types, then we delete them in a single
637 * performMultipleDeletions() call. This is to avoid unwanted DROP
638 * RESTRICT errors if one of the types depends on another.
640 objects = new_object_addresses();
642 foreach(cell, drop->objects)
644 List *names = (List *) lfirst(cell);
648 ObjectAddress object;
651 /* Make a TypeName so we can use standard type lookup machinery */
652 typename = makeTypeNameFromNameList(names);
654 /* Use LookupTypeName here so that shell types can be removed. */
655 tup = LookupTypeName(NULL, typename, NULL);
658 if (!drop->missing_ok)
661 (errcode(ERRCODE_UNDEFINED_OBJECT),
662 errmsg("type \"%s\" does not exist",
663 TypeNameToString(typename))));
668 (errmsg("type \"%s\" does not exist, skipping",
669 TypeNameToString(typename))));
674 typeoid = typeTypeId(tup);
675 typ = (Form_pg_type) GETSTRUCT(tup);
677 /* Permission check: must own type or its namespace */
678 if (!pg_type_ownercheck(typeoid, GetUserId()) &&
679 !pg_namespace_ownercheck(typ->typnamespace, GetUserId()))
680 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
681 format_type_be(typeoid));
683 if (drop->removeType == OBJECT_DOMAIN)
685 /* Check that this is actually a domain */
686 if (typ->typtype != TYPTYPE_DOMAIN)
688 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
689 errmsg("\"%s\" is not a domain",
690 TypeNameToString(typename))));
694 * Note: we need no special check for array types here, as the normal
695 * treatment of internal dependencies handles it just fine
698 object.classId = TypeRelationId;
699 object.objectId = typeoid;
700 object.objectSubId = 0;
702 add_exact_object_address(&object, objects);
704 ReleaseSysCache(tup);
707 performMultipleDeletions(objects, drop->behavior);
709 free_object_addresses(objects);
714 * Guts of type deletion.
717 RemoveTypeById(Oid typeOid)
722 relation = heap_open(TypeRelationId, RowExclusiveLock);
724 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
725 if (!HeapTupleIsValid(tup))
726 elog(ERROR, "cache lookup failed for type %u", typeOid);
728 simple_heap_delete(relation, &tup->t_self);
731 * If it is an enum, delete the pg_enum entries too; we don't bother with
732 * making dependency entries for those, so it has to be done "by hand"
735 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
736 EnumValuesDelete(typeOid);
738 ReleaseSysCache(tup);
740 heap_close(relation, RowExclusiveLock);
746 * Registers a new domain.
749 DefineDomain(CreateDomainStmt *stmt)
754 int16 internalLength;
757 Oid receiveProcedure;
759 Oid analyzeProcedure;
768 char *defaultValue = NULL;
769 char *defaultValueBin = NULL;
770 bool saw_default = false;
771 bool typNotNull = false;
772 bool nullDefined = false;
773 int32 typNDims = list_length(stmt->typeName->arrayBounds);
775 List *schema = stmt->constraints;
781 Form_pg_type baseType;
785 /* Convert list of names to a name and namespace */
786 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
789 /* Check we have creation rights in target namespace */
790 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
792 if (aclresult != ACLCHECK_OK)
793 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
794 get_namespace_name(domainNamespace));
797 * Check for collision with an existing type name. If there is one and
798 * it's an autogenerated array, we can rename it out of the way.
800 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
801 CStringGetDatum(domainName),
802 ObjectIdGetDatum(domainNamespace));
803 if (OidIsValid(old_type_oid))
805 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
807 (errcode(ERRCODE_DUPLICATE_OBJECT),
808 errmsg("type \"%s\" already exists", domainName)));
812 * Look up the base type.
814 typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
815 baseType = (Form_pg_type) GETSTRUCT(typeTup);
816 basetypeoid = HeapTupleGetOid(typeTup);
819 * Base type must be a plain base type, another domain or an enum. Domains
820 * over pseudotypes would create a security hole. Domains over composite
821 * types might be made to work in the future, but not today.
823 typtype = baseType->typtype;
824 if (typtype != TYPTYPE_BASE &&
825 typtype != TYPTYPE_DOMAIN &&
826 typtype != TYPTYPE_ENUM)
828 (errcode(ERRCODE_DATATYPE_MISMATCH),
829 errmsg("\"%s\" is not a valid base type for a domain",
830 TypeNameToString(stmt->typeName))));
833 * Identify the collation if any
835 baseColl = baseType->typcollation;
836 if (stmt->collClause)
837 domaincoll = get_collation_oid(stmt->collClause->collname, false);
839 domaincoll = baseColl;
841 /* Complain if COLLATE is applied to an uncollatable type */
842 if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
844 (errcode(ERRCODE_DATATYPE_MISMATCH),
845 errmsg("collations are not supported by type %s",
846 format_type_be(basetypeoid))));
848 /* passed by value */
849 byValue = baseType->typbyval;
851 /* Required Alignment */
852 alignment = baseType->typalign;
855 storage = baseType->typstorage;
858 internalLength = baseType->typlen;
861 category = baseType->typcategory;
863 /* Array element Delimiter */
864 delimiter = baseType->typdelim;
867 inputProcedure = F_DOMAIN_IN;
868 outputProcedure = baseType->typoutput;
869 receiveProcedure = F_DOMAIN_RECV;
870 sendProcedure = baseType->typsend;
872 /* Domains never accept typmods, so no typmodin/typmodout needed */
874 /* Analysis function */
875 analyzeProcedure = baseType->typanalyze;
877 /* Inherited default value */
878 datum = SysCacheGetAttr(TYPEOID, typeTup,
879 Anum_pg_type_typdefault, &isnull);
881 defaultValue = TextDatumGetCString(datum);
883 /* Inherited default binary value */
884 datum = SysCacheGetAttr(TYPEOID, typeTup,
885 Anum_pg_type_typdefaultbin, &isnull);
887 defaultValueBin = TextDatumGetCString(datum);
890 * Run through constraints manually to avoid the additional processing
891 * conducted by DefineRelation() and friends.
893 foreach(listptr, schema)
895 Constraint *constr = lfirst(listptr);
897 if (!IsA(constr, Constraint))
898 elog(ERROR, "unrecognized node type: %d",
899 (int) nodeTag(constr));
900 switch (constr->contype)
905 * The inherited default value may be overridden by the user
906 * with the DEFAULT <expr> clause ... but only once.
910 (errcode(ERRCODE_SYNTAX_ERROR),
911 errmsg("multiple default expressions")));
914 if (constr->raw_expr)
919 /* Create a dummy ParseState for transformExpr */
920 pstate = make_parsestate(NULL);
923 * Cook the constr->raw_expr into an expression. Note:
924 * name is strictly for error message
926 defaultExpr = cookDefault(pstate, constr->raw_expr,
932 * If the expression is just a NULL constant, we treat it
933 * like not having a default.
935 * Note that if the basetype is another domain, we'll see
936 * a CoerceToDomain expr here and not discard the default.
937 * This is critical because the domain default needs to be
938 * retained to override any default that the base domain
941 if (defaultExpr == NULL ||
942 (IsA(defaultExpr, Const) &&
943 ((Const *) defaultExpr)->constisnull))
946 defaultValueBin = NULL;
951 * Expression must be stored as a nodeToString result,
952 * but we also require a valid textual representation
953 * (mainly to make life easier for pg_dump).
956 deparse_expression(defaultExpr,
957 deparse_context_for(domainName,
960 defaultValueBin = nodeToString(defaultExpr);
965 /* No default (can this still happen?) */
967 defaultValueBin = NULL;
972 if (nullDefined && !typNotNull)
974 (errcode(ERRCODE_SYNTAX_ERROR),
975 errmsg("conflicting NULL/NOT NULL constraints")));
981 if (nullDefined && typNotNull)
983 (errcode(ERRCODE_SYNTAX_ERROR),
984 errmsg("conflicting NULL/NOT NULL constraints")));
992 * Check constraints are handled after domain creation, as
993 * they require the Oid of the domain
998 * All else are error cases
1002 (errcode(ERRCODE_SYNTAX_ERROR),
1003 errmsg("unique constraints not possible for domains")));
1006 case CONSTR_PRIMARY:
1008 (errcode(ERRCODE_SYNTAX_ERROR),
1009 errmsg("primary key constraints not possible for domains")));
1012 case CONSTR_EXCLUSION:
1014 (errcode(ERRCODE_SYNTAX_ERROR),
1015 errmsg("exclusion constraints not possible for domains")));
1018 case CONSTR_FOREIGN:
1020 (errcode(ERRCODE_SYNTAX_ERROR),
1021 errmsg("foreign key constraints not possible for domains")));
1024 case CONSTR_ATTR_DEFERRABLE:
1025 case CONSTR_ATTR_NOT_DEFERRABLE:
1026 case CONSTR_ATTR_DEFERRED:
1027 case CONSTR_ATTR_IMMEDIATE:
1029 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1030 errmsg("specifying constraint deferrability not supported for domains")));
1034 elog(ERROR, "unrecognized constraint subtype: %d",
1035 (int) constr->contype);
1041 * Have TypeCreate do all the real work.
1044 TypeCreate(InvalidOid, /* no predetermined type OID */
1045 domainName, /* type name */
1046 domainNamespace, /* namespace */
1047 InvalidOid, /* relation oid (n/a here) */
1048 0, /* relation kind (ditto) */
1049 GetUserId(), /* owner's ID */
1050 internalLength, /* internal size */
1051 TYPTYPE_DOMAIN, /* type-type (domain type) */
1052 category, /* type-category */
1053 false, /* domain types are never preferred */
1054 delimiter, /* array element delimiter */
1055 inputProcedure, /* input procedure */
1056 outputProcedure, /* output procedure */
1057 receiveProcedure, /* receive procedure */
1058 sendProcedure, /* send procedure */
1059 InvalidOid, /* typmodin procedure - none */
1060 InvalidOid, /* typmodout procedure - none */
1061 analyzeProcedure, /* analyze procedure */
1062 InvalidOid, /* no array element type */
1063 false, /* this isn't an array */
1064 InvalidOid, /* no arrays for domains (yet) */
1065 basetypeoid, /* base type ID */
1066 defaultValue, /* default type value (text) */
1067 defaultValueBin, /* default type value (binary) */
1068 byValue, /* passed by value */
1069 alignment, /* required alignment */
1070 storage, /* TOAST strategy */
1071 basetypeMod, /* typeMod value */
1072 typNDims, /* Array dimensions for base type */
1073 typNotNull, /* Type NOT NULL */
1074 domaincoll); /* type's collation */
1077 * Process constraints which refer to the domain ID returned by TypeCreate
1079 foreach(listptr, schema)
1081 Constraint *constr = lfirst(listptr);
1083 /* it must be a Constraint, per check above */
1085 switch (constr->contype)
1088 domainAddConstraint(domainoid, domainNamespace,
1089 basetypeoid, basetypeMod,
1090 constr, domainName);
1093 /* Other constraint types were fully processed above */
1099 /* CCI so we can detect duplicate constraint names */
1100 CommandCounterIncrement();
1104 * Now we can clean up.
1106 ReleaseSysCache(typeTup);
1112 * Registers a new enum.
1115 DefineEnum(CreateEnumStmt *stmt)
1118 char *enumArrayName;
1121 AclResult aclresult;
1125 /* Convert list of names to a name and namespace */
1126 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1129 /* Check we have creation rights in target namespace */
1130 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1131 if (aclresult != ACLCHECK_OK)
1132 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1133 get_namespace_name(enumNamespace));
1136 * Check for collision with an existing type name. If there is one and
1137 * it's an autogenerated array, we can rename it out of the way.
1139 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1140 CStringGetDatum(enumName),
1141 ObjectIdGetDatum(enumNamespace));
1142 if (OidIsValid(old_type_oid))
1144 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1146 (errcode(ERRCODE_DUPLICATE_OBJECT),
1147 errmsg("type \"%s\" already exists", enumName)));
1150 enumArrayOid = AssignTypeArrayOid();
1152 /* Create the pg_type entry */
1154 TypeCreate(InvalidOid, /* no predetermined type OID */
1155 enumName, /* type name */
1156 enumNamespace, /* namespace */
1157 InvalidOid, /* relation oid (n/a here) */
1158 0, /* relation kind (ditto) */
1159 GetUserId(), /* owner's ID */
1160 sizeof(Oid), /* internal size */
1161 TYPTYPE_ENUM, /* type-type (enum type) */
1162 TYPCATEGORY_ENUM, /* type-category (enum type) */
1163 false, /* enum types are never preferred */
1164 DEFAULT_TYPDELIM, /* array element delimiter */
1165 F_ENUM_IN, /* input procedure */
1166 F_ENUM_OUT, /* output procedure */
1167 F_ENUM_RECV, /* receive procedure */
1168 F_ENUM_SEND, /* send procedure */
1169 InvalidOid, /* typmodin procedure - none */
1170 InvalidOid, /* typmodout procedure - none */
1171 InvalidOid, /* analyze procedure - default */
1172 InvalidOid, /* element type ID */
1173 false, /* this is not an array type */
1174 enumArrayOid, /* array type we are about to create */
1175 InvalidOid, /* base type ID (only for domains) */
1176 NULL, /* never a default type value */
1177 NULL, /* binary default isn't sent either */
1178 true, /* always passed by value */
1179 'i', /* int alignment */
1180 'p', /* TOAST strategy always plain */
1181 -1, /* typMod (Domains only) */
1182 0, /* Array dimensions of typbasetype */
1183 false, /* Type NOT NULL */
1184 InvalidOid); /* type's collation */
1186 /* Enter the enum's values into pg_enum */
1187 EnumValuesCreate(enumTypeOid, stmt->vals);
1190 * Create the array type that goes with it.
1192 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1194 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1195 enumArrayName, /* type name */
1196 enumNamespace, /* namespace */
1197 InvalidOid, /* relation oid (n/a here) */
1198 0, /* relation kind (ditto) */
1199 GetUserId(), /* owner's ID */
1200 -1, /* internal size (always varlena) */
1201 TYPTYPE_BASE, /* type-type (base type) */
1202 TYPCATEGORY_ARRAY, /* type-category (array) */
1203 false, /* array types are never preferred */
1204 DEFAULT_TYPDELIM, /* array element delimiter */
1205 F_ARRAY_IN, /* input procedure */
1206 F_ARRAY_OUT, /* output procedure */
1207 F_ARRAY_RECV, /* receive procedure */
1208 F_ARRAY_SEND, /* send procedure */
1209 InvalidOid, /* typmodin procedure - none */
1210 InvalidOid, /* typmodout procedure - none */
1211 InvalidOid, /* analyze procedure - default */
1212 enumTypeOid, /* element type ID */
1213 true, /* yes this is an array type */
1214 InvalidOid, /* no further array type */
1215 InvalidOid, /* base type ID */
1216 NULL, /* never a default type value */
1217 NULL, /* binary default isn't sent either */
1218 false, /* never passed by value */
1219 'i', /* enums have align i, so do their arrays */
1220 'x', /* ARRAY is always toastable */
1221 -1, /* typMod (Domains only) */
1222 0, /* Array dimensions of typbasetype */
1223 false, /* Type NOT NULL */
1224 InvalidOid); /* type's collation */
1226 pfree(enumArrayName);
1231 * Adds a new label to an existing enum.
1234 AlterEnum(AlterEnumStmt *stmt)
1240 /* Make a TypeName so we can use standard type lookup machinery */
1241 typename = makeTypeNameFromNameList(stmt->typeName);
1242 enum_type_oid = typenameTypeId(NULL, typename);
1244 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1245 if (!HeapTupleIsValid(tup))
1246 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1248 /* Check it's an enum and check user has permission to ALTER the enum */
1249 checkEnumOwner(tup);
1251 /* Add the new label */
1252 AddEnumLabel(enum_type_oid, stmt->newVal,
1253 stmt->newValNeighbor, stmt->newValIsAfter);
1255 ReleaseSysCache(tup);
1262 * Check that the type is actually an enum and that the current user
1263 * has permission to do ALTER TYPE on it. Throw an error if not.
1266 checkEnumOwner(HeapTuple tup)
1268 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1270 /* Check that this is actually an enum */
1271 if (typTup->typtype != TYPTYPE_ENUM)
1273 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1274 errmsg("%s is not an enum",
1275 format_type_be(HeapTupleGetOid(tup)))));
1277 /* Permission check: must own type */
1278 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1279 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
1280 format_type_be(HeapTupleGetOid(tup)));
1285 * Find suitable I/O functions for a type.
1287 * typeOid is the type's OID (which will already exist, if only as a shell
1292 findTypeInputFunction(List *procname, Oid typeOid)
1298 * Input functions can take a single argument of type CSTRING, or three
1299 * arguments (string, typioparam OID, typmod).
1301 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1302 * see this, we issue a warning and fix up the pg_proc entry.
1304 argList[0] = CSTRINGOID;
1306 procOid = LookupFuncName(procname, 1, argList, true);
1307 if (OidIsValid(procOid))
1310 argList[1] = OIDOID;
1311 argList[2] = INT4OID;
1313 procOid = LookupFuncName(procname, 3, argList, true);
1314 if (OidIsValid(procOid))
1317 /* No luck, try it with OPAQUE */
1318 argList[0] = OPAQUEOID;
1320 procOid = LookupFuncName(procname, 1, argList, true);
1322 if (!OidIsValid(procOid))
1324 argList[1] = OIDOID;
1325 argList[2] = INT4OID;
1327 procOid = LookupFuncName(procname, 3, argList, true);
1330 if (OidIsValid(procOid))
1332 /* Found, but must complain and fix the pg_proc entry */
1334 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1335 NameListToString(procname))));
1336 SetFunctionArgType(procOid, 0, CSTRINGOID);
1339 * Need CommandCounterIncrement since DefineType will likely try to
1340 * alter the pg_proc tuple again.
1342 CommandCounterIncrement();
1347 /* Use CSTRING (preferred) in the error message */
1348 argList[0] = CSTRINGOID;
1351 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1352 errmsg("function %s does not exist",
1353 func_signature_string(procname, 1, NIL, argList))));
1355 return InvalidOid; /* keep compiler quiet */
1359 findTypeOutputFunction(List *procname, Oid typeOid)
1365 * Output functions can take a single argument of the type.
1367 * For backwards compatibility we allow OPAQUE in place of the actual type
1368 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1370 argList[0] = typeOid;
1372 procOid = LookupFuncName(procname, 1, argList, true);
1373 if (OidIsValid(procOid))
1376 /* No luck, try it with OPAQUE */
1377 argList[0] = OPAQUEOID;
1379 procOid = LookupFuncName(procname, 1, argList, true);
1381 if (OidIsValid(procOid))
1383 /* Found, but must complain and fix the pg_proc entry */
1385 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1386 NameListToString(procname), format_type_be(typeOid))));
1387 SetFunctionArgType(procOid, 0, typeOid);
1390 * Need CommandCounterIncrement since DefineType will likely try to
1391 * alter the pg_proc tuple again.
1393 CommandCounterIncrement();
1398 /* Use type name, not OPAQUE, in the failure message. */
1399 argList[0] = typeOid;
1402 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1403 errmsg("function %s does not exist",
1404 func_signature_string(procname, 1, NIL, argList))));
1406 return InvalidOid; /* keep compiler quiet */
1410 findTypeReceiveFunction(List *procname, Oid typeOid)
1416 * Receive functions can take a single argument of type INTERNAL, or three
1417 * arguments (internal, typioparam OID, typmod).
1419 argList[0] = INTERNALOID;
1421 procOid = LookupFuncName(procname, 1, argList, true);
1422 if (OidIsValid(procOid))
1425 argList[1] = OIDOID;
1426 argList[2] = INT4OID;
1428 procOid = LookupFuncName(procname, 3, argList, true);
1429 if (OidIsValid(procOid))
1433 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1434 errmsg("function %s does not exist",
1435 func_signature_string(procname, 1, NIL, argList))));
1437 return InvalidOid; /* keep compiler quiet */
1441 findTypeSendFunction(List *procname, Oid typeOid)
1447 * Send functions can take a single argument of the type.
1449 argList[0] = typeOid;
1451 procOid = LookupFuncName(procname, 1, argList, true);
1452 if (OidIsValid(procOid))
1456 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1457 errmsg("function %s does not exist",
1458 func_signature_string(procname, 1, NIL, argList))));
1460 return InvalidOid; /* keep compiler quiet */
1464 findTypeTypmodinFunction(List *procname)
1470 * typmodin functions always take one cstring[] argument and return int4.
1472 argList[0] = CSTRINGARRAYOID;
1474 procOid = LookupFuncName(procname, 1, argList, true);
1475 if (!OidIsValid(procOid))
1477 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1478 errmsg("function %s does not exist",
1479 func_signature_string(procname, 1, NIL, argList))));
1481 if (get_func_rettype(procOid) != INT4OID)
1483 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1484 errmsg("typmod_in function %s must return type \"integer\"",
1485 NameListToString(procname))));
1491 findTypeTypmodoutFunction(List *procname)
1497 * typmodout functions always take one int4 argument and return cstring.
1499 argList[0] = INT4OID;
1501 procOid = LookupFuncName(procname, 1, argList, true);
1502 if (!OidIsValid(procOid))
1504 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1505 errmsg("function %s does not exist",
1506 func_signature_string(procname, 1, NIL, argList))));
1508 if (get_func_rettype(procOid) != CSTRINGOID)
1510 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1511 errmsg("typmod_out function %s must return type \"cstring\"",
1512 NameListToString(procname))));
1518 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1524 * Analyze functions always take one INTERNAL argument and return bool.
1526 argList[0] = INTERNALOID;
1528 procOid = LookupFuncName(procname, 1, argList, true);
1529 if (!OidIsValid(procOid))
1531 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1532 errmsg("function %s does not exist",
1533 func_signature_string(procname, 1, NIL, argList))));
1535 if (get_func_rettype(procOid) != BOOLOID)
1537 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1538 errmsg("type analyze function %s must return type \"boolean\"",
1539 NameListToString(procname))));
1545 * AssignTypeArrayOid
1547 * Pre-assign the type's array OID for use in pg_type.typarray
1550 AssignTypeArrayOid(void)
1554 /* Use binary-upgrade override for pg_type.typarray, if supplied. */
1555 if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_array_pg_type_oid))
1557 type_array_oid = binary_upgrade_next_array_pg_type_oid;
1558 binary_upgrade_next_array_pg_type_oid = InvalidOid;
1562 Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
1564 type_array_oid = GetNewOid(pg_type);
1565 heap_close(pg_type, AccessShareLock);
1568 return type_array_oid;
1572 /*-------------------------------------------------------------------
1573 * DefineCompositeType
1575 * Create a Composite Type relation.
1576 * `DefineRelation' does all the work, we just provide the correct
1579 * If the relation already exists, then 'DefineRelation' will abort
1582 * DefineCompositeType returns relid for use when creating
1583 * an implicit composite type during function creation
1584 *-------------------------------------------------------------------
1587 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1589 CreateStmt *createStmt = makeNode(CreateStmt);
1595 * now set the parameters for keys/inheritance etc. All of these are
1596 * uninteresting for composite types...
1598 createStmt->relation = (RangeVar *) typevar;
1599 createStmt->tableElts = coldeflist;
1600 createStmt->inhRelations = NIL;
1601 createStmt->constraints = NIL;
1602 createStmt->options = list_make1(defWithOids(false));
1603 createStmt->oncommit = ONCOMMIT_NOOP;
1604 createStmt->tablespacename = NULL;
1605 createStmt->if_not_exists = false;
1608 * Check for collision with an existing type name. If there is one and
1609 * it's an autogenerated array, we can rename it out of the way. This
1610 * check is here mainly to get a better error message about a "type"
1611 * instead of below about a "relation".
1613 typeNamespace = RangeVarGetCreationNamespace(createStmt->relation);
1614 RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
1616 GetSysCacheOid2(TYPENAMENSP,
1617 CStringGetDatum(createStmt->relation->relname),
1618 ObjectIdGetDatum(typeNamespace));
1619 if (OidIsValid(old_type_oid))
1621 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
1623 (errcode(ERRCODE_DUPLICATE_OBJECT),
1624 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
1628 * Finally create the relation. This also creates the type.
1630 relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
1631 Assert(relid != InvalidOid);
1636 * AlterDomainDefault
1638 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
1641 AlterDomainDefault(List *names, Node *defaultRaw)
1649 Node *defaultExpr = NULL; /* NULL if no default specified */
1650 Datum new_record[Natts_pg_type];
1651 bool new_record_nulls[Natts_pg_type];
1652 bool new_record_repl[Natts_pg_type];
1654 Form_pg_type typTup;
1656 /* Make a TypeName so we can use standard type lookup machinery */
1657 typename = makeTypeNameFromNameList(names);
1658 domainoid = typenameTypeId(NULL, typename);
1660 /* Look up the domain in the type table */
1661 rel = heap_open(TypeRelationId, RowExclusiveLock);
1663 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1664 if (!HeapTupleIsValid(tup))
1665 elog(ERROR, "cache lookup failed for type %u", domainoid);
1666 typTup = (Form_pg_type) GETSTRUCT(tup);
1668 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1669 checkDomainOwner(tup);
1671 /* Setup new tuple */
1672 MemSet(new_record, (Datum) 0, sizeof(new_record));
1673 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1674 MemSet(new_record_repl, false, sizeof(new_record_repl));
1676 /* Store the new default into the tuple */
1679 /* Create a dummy ParseState for transformExpr */
1680 pstate = make_parsestate(NULL);
1683 * Cook the colDef->raw_expr into an expression. Note: Name is
1684 * strictly for error message
1686 defaultExpr = cookDefault(pstate, defaultRaw,
1687 typTup->typbasetype,
1689 NameStr(typTup->typname));
1692 * If the expression is just a NULL constant, we treat the command
1693 * like ALTER ... DROP DEFAULT. (But see note for same test in
1696 if (defaultExpr == NULL ||
1697 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
1699 /* Default is NULL, drop it */
1700 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
1701 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1702 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
1703 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1708 * Expression must be stored as a nodeToString result, but we also
1709 * require a valid textual representation (mainly to make life
1710 * easier for pg_dump).
1712 defaultValue = deparse_expression(defaultExpr,
1713 deparse_context_for(NameStr(typTup->typname),
1718 * Form an updated tuple with the new default and write it back.
1720 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
1722 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1723 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
1724 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1729 /* ALTER ... DROP DEFAULT */
1730 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
1731 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1732 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
1733 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1736 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
1737 new_record, new_record_nulls,
1740 simple_heap_update(rel, &tup->t_self, newtuple);
1742 CatalogUpdateIndexes(rel, newtuple);
1744 /* Rebuild dependencies */
1745 GenerateTypeDependencies(typTup->typnamespace,
1747 InvalidOid, /* typrelid is n/a */
1748 0, /* relation kind is n/a */
1758 false, /* a domain isn't an implicit array */
1759 typTup->typbasetype,
1760 typTup->typcollation,
1762 true); /* Rebuild is true */
1765 heap_close(rel, NoLock);
1766 heap_freetuple(newtuple);
1770 * AlterDomainNotNull
1772 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
1775 AlterDomainNotNull(List *names, bool notNull)
1781 Form_pg_type typTup;
1783 /* Make a TypeName so we can use standard type lookup machinery */
1784 typename = makeTypeNameFromNameList(names);
1785 domainoid = typenameTypeId(NULL, typename);
1787 /* Look up the domain in the type table */
1788 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1790 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1791 if (!HeapTupleIsValid(tup))
1792 elog(ERROR, "cache lookup failed for type %u", domainoid);
1793 typTup = (Form_pg_type) GETSTRUCT(tup);
1795 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1796 checkDomainOwner(tup);
1798 /* Is the domain already set to the desired constraint? */
1799 if (typTup->typnotnull == notNull)
1801 heap_close(typrel, RowExclusiveLock);
1805 /* Adding a NOT NULL constraint requires checking existing columns */
1811 /* Fetch relation list with attributes based on this domain */
1812 /* ShareLock is sufficient to prevent concurrent data changes */
1814 rels = get_rels_with_domain(domainoid, ShareLock);
1818 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1819 Relation testrel = rtc->rel;
1820 TupleDesc tupdesc = RelationGetDescr(testrel);
1824 /* Scan all tuples in this relation */
1825 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1826 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1830 /* Test attributes that are of the domain */
1831 for (i = 0; i < rtc->natts; i++)
1833 int attnum = rtc->atts[i];
1835 if (heap_attisnull(tuple, attnum))
1837 (errcode(ERRCODE_NOT_NULL_VIOLATION),
1838 errmsg("column \"%s\" of table \"%s\" contains null values",
1839 NameStr(tupdesc->attrs[attnum - 1]->attname),
1840 RelationGetRelationName(testrel))));
1845 /* Close each rel after processing, but keep lock */
1846 heap_close(testrel, NoLock);
1851 * Okay to update pg_type row. We can scribble on typTup because it's a
1854 typTup->typnotnull = notNull;
1856 simple_heap_update(typrel, &tup->t_self, tup);
1858 CatalogUpdateIndexes(typrel, tup);
1861 heap_freetuple(tup);
1862 heap_close(typrel, RowExclusiveLock);
1866 * AlterDomainDropConstraint
1868 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
1871 AlterDomainDropConstraint(List *names, const char *constrName,
1872 DropBehavior behavior)
1879 SysScanDesc conscan;
1883 /* Make a TypeName so we can use standard type lookup machinery */
1884 typename = makeTypeNameFromNameList(names);
1885 domainoid = typenameTypeId(NULL, typename);
1887 /* Look up the domain in the type table */
1888 rel = heap_open(TypeRelationId, RowExclusiveLock);
1890 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1891 if (!HeapTupleIsValid(tup))
1892 elog(ERROR, "cache lookup failed for type %u", domainoid);
1894 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1895 checkDomainOwner(tup);
1897 /* Grab an appropriate lock on the pg_constraint relation */
1898 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
1900 /* Use the index to scan only constraints of the target relation */
1901 ScanKeyInit(&key[0],
1902 Anum_pg_constraint_contypid,
1903 BTEqualStrategyNumber, F_OIDEQ,
1904 ObjectIdGetDatum(HeapTupleGetOid(tup)));
1906 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
1907 SnapshotNow, 1, key);
1910 * Scan over the result set, removing any matching entries.
1912 while ((contup = systable_getnext(conscan)) != NULL)
1914 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
1916 if (strcmp(NameStr(con->conname), constrName) == 0)
1918 ObjectAddress conobj;
1920 conobj.classId = ConstraintRelationId;
1921 conobj.objectId = HeapTupleGetOid(contup);
1922 conobj.objectSubId = 0;
1924 performDeletion(&conobj, behavior);
1927 /* Clean up after the scan */
1928 systable_endscan(conscan);
1929 heap_close(conrel, RowExclusiveLock);
1931 heap_close(rel, NoLock);
1935 * AlterDomainAddConstraint
1937 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
1940 AlterDomainAddConstraint(List *names, Node *newConstraint)
1946 Form_pg_type typTup;
1950 /* Make a TypeName so we can use standard type lookup machinery */
1951 typename = makeTypeNameFromNameList(names);
1952 domainoid = typenameTypeId(NULL, typename);
1954 /* Look up the domain in the type table */
1955 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1957 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
1958 if (!HeapTupleIsValid(tup))
1959 elog(ERROR, "cache lookup failed for type %u", domainoid);
1960 typTup = (Form_pg_type) GETSTRUCT(tup);
1962 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1963 checkDomainOwner(tup);
1965 if (!IsA(newConstraint, Constraint))
1966 elog(ERROR, "unrecognized node type: %d",
1967 (int) nodeTag(newConstraint));
1969 constr = (Constraint *) newConstraint;
1971 switch (constr->contype)
1974 /* processed below */
1979 (errcode(ERRCODE_SYNTAX_ERROR),
1980 errmsg("unique constraints not possible for domains")));
1983 case CONSTR_PRIMARY:
1985 (errcode(ERRCODE_SYNTAX_ERROR),
1986 errmsg("primary key constraints not possible for domains")));
1989 case CONSTR_EXCLUSION:
1991 (errcode(ERRCODE_SYNTAX_ERROR),
1992 errmsg("exclusion constraints not possible for domains")));
1995 case CONSTR_FOREIGN:
1997 (errcode(ERRCODE_SYNTAX_ERROR),
1998 errmsg("foreign key constraints not possible for domains")));
2001 case CONSTR_ATTR_DEFERRABLE:
2002 case CONSTR_ATTR_NOT_DEFERRABLE:
2003 case CONSTR_ATTR_DEFERRED:
2004 case CONSTR_ATTR_IMMEDIATE:
2006 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2007 errmsg("specifying constraint deferrability not supported for domains")));
2011 elog(ERROR, "unrecognized constraint subtype: %d",
2012 (int) constr->contype);
2017 * Since all other constraint types throw errors, this must be a check
2018 * constraint. First, process the constraint expression and add an entry
2022 ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
2023 typTup->typbasetype, typTup->typtypmod,
2024 constr, NameStr(typTup->typname));
2027 * If requested to validate the constraint, test all values stored in the
2028 * attributes based on the domain the constraint is being added to.
2030 if (!constr->skip_validation)
2031 validateDomainConstraint(domainoid, ccbin);
2034 heap_close(typrel, RowExclusiveLock);
2038 * AlterDomainValidateConstraint
2040 * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
2043 AlterDomainValidateConstraint(List *names, char *constrName)
2050 Form_pg_constraint con = NULL;
2051 Form_pg_constraint copy_con;
2058 HeapTuple copyTuple;
2061 /* Make a TypeName so we can use standard type lookup machinery */
2062 typename = makeTypeNameFromNameList(names);
2063 domainoid = typenameTypeId(NULL, typename);
2065 /* Look up the domain in the type table */
2066 typrel = heap_open(TypeRelationId, AccessShareLock);
2068 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2069 if (!HeapTupleIsValid(tup))
2070 elog(ERROR, "cache lookup failed for type %u", domainoid);
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 (errcode(ERRCODE_UNDEFINED_OBJECT),
2099 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2100 constrName, TypeNameToString(typename))));
2102 if (con->contype != CONSTRAINT_CHECK)
2104 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2105 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2106 constrName, TypeNameToString(typename))));
2108 val = SysCacheGetAttr(CONSTROID, tuple,
2109 Anum_pg_constraint_conbin,
2112 elog(ERROR, "null conbin for constraint %u",
2113 HeapTupleGetOid(tuple));
2114 conbin = TextDatumGetCString(val);
2116 validateDomainConstraint(domainoid, conbin);
2119 * Now update the catalog, while we have the door open.
2121 copyTuple = heap_copytuple(tuple);
2122 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2123 copy_con->convalidated = true;
2124 simple_heap_update(conrel, ©Tuple->t_self, copyTuple);
2125 CatalogUpdateIndexes(conrel, copyTuple);
2126 heap_freetuple(copyTuple);
2128 systable_endscan(scan);
2130 heap_close(typrel, AccessShareLock);
2131 heap_close(conrel, RowExclusiveLock);
2133 ReleaseSysCache(tup);
2137 validateDomainConstraint(Oid domainoid, char *ccbin)
2139 Expr *expr = (Expr *) stringToNode(ccbin);
2143 ExprContext *econtext;
2144 ExprState *exprstate;
2146 /* Need an EState to run ExecEvalExpr */
2147 estate = CreateExecutorState();
2148 econtext = GetPerTupleExprContext(estate);
2150 /* build execution state for expr */
2151 exprstate = ExecPrepareExpr(expr, estate);
2153 /* Fetch relation list with attributes based on this domain */
2154 /* ShareLock is sufficient to prevent concurrent data changes */
2156 rels = get_rels_with_domain(domainoid, ShareLock);
2160 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2161 Relation testrel = rtc->rel;
2162 TupleDesc tupdesc = RelationGetDescr(testrel);
2166 /* Scan all tuples in this relation */
2167 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2168 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2172 /* Test attributes that are of the domain */
2173 for (i = 0; i < rtc->natts; i++)
2175 int attnum = rtc->atts[i];
2180 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2182 econtext->domainValue_datum = d;
2183 econtext->domainValue_isNull = isNull;
2185 conResult = ExecEvalExprSwitchContext(exprstate,
2189 if (!isNull && !DatumGetBool(conResult))
2191 (errcode(ERRCODE_CHECK_VIOLATION),
2192 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2193 NameStr(tupdesc->attrs[attnum - 1]->attname),
2194 RelationGetRelationName(testrel))));
2197 ResetExprContext(econtext);
2201 /* Hold relation lock till commit (XXX bad for concurrency) */
2202 heap_close(testrel, NoLock);
2205 FreeExecutorState(estate);
2208 * get_rels_with_domain
2210 * Fetch all relations / attributes which are using the domain
2212 * The result is a list of RelToCheck structs, one for each distinct
2213 * relation, each containing one or more attribute numbers that are of
2214 * the domain type. We have opened each rel and acquired the specified lock
2217 * We support nested domains by including attributes that are of derived
2218 * domain types. Current callers do not need to distinguish between attributes
2219 * that are of exactly the given domain and those that are of derived domains.
2221 * XXX this is completely broken because there is no way to lock the domain
2222 * to prevent columns from being added or dropped while our command runs.
2223 * We can partially protect against column drops by locking relations as we
2224 * come across them, but there is still a race condition (the window between
2225 * seeing a pg_depend entry and acquiring lock on the relation it references).
2226 * Also, holding locks on all these relations simultaneously creates a non-
2227 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2228 * risk by using the weakest suitable lock (ShareLock for most callers).
2230 * XXX the API for this is not sufficient to support checking domain values
2231 * that are inside composite types or arrays. Currently we just error out
2232 * if a composite type containing the target domain is stored anywhere.
2233 * There are not currently arrays of domains; if there were, we could take
2234 * the same approach, but it'd be nicer to fix it properly.
2236 * Generally used for retrieving a list of tests when adding
2237 * new constraints to a domain.
2240 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2245 SysScanDesc depScan;
2248 Assert(lockmode != NoLock);
2251 * We scan pg_depend to find those things that depend on the domain. (We
2252 * assume we can ignore refobjsubid for a domain.)
2254 depRel = heap_open(DependRelationId, AccessShareLock);
2256 ScanKeyInit(&key[0],
2257 Anum_pg_depend_refclassid,
2258 BTEqualStrategyNumber, F_OIDEQ,
2259 ObjectIdGetDatum(TypeRelationId));
2260 ScanKeyInit(&key[1],
2261 Anum_pg_depend_refobjid,
2262 BTEqualStrategyNumber, F_OIDEQ,
2263 ObjectIdGetDatum(domainOid));
2265 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2266 SnapshotNow, 2, key);
2268 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2270 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2271 RelToCheck *rtc = NULL;
2273 Form_pg_attribute pg_att;
2276 /* Check for directly dependent types --- must be domains */
2277 if (pg_depend->classid == TypeRelationId)
2279 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2282 * Recursively add dependent columns to the output list. This is
2283 * a bit inefficient since we may fail to combine RelToCheck
2284 * entries when attributes of the same rel have different derived
2285 * domain types, but it's probably not worth improving.
2287 result = list_concat(result,
2288 get_rels_with_domain(pg_depend->objid,
2293 /* Else, ignore dependees that aren't user columns of relations */
2294 /* (we assume system columns are never of domain types) */
2295 if (pg_depend->classid != RelationRelationId ||
2296 pg_depend->objsubid <= 0)
2299 /* See if we already have an entry for this relation */
2300 foreach(rellist, result)
2302 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2304 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2313 /* First attribute found for this relation */
2316 /* Acquire requested lock on relation */
2317 rel = relation_open(pg_depend->objid, lockmode);
2320 * Check to see if rowtype is stored anyplace as a composite-type
2321 * column; if so we have to fail, for now anyway.
2323 if (OidIsValid(rel->rd_rel->reltype))
2324 find_composite_type_dependencies(rel->rd_rel->reltype,
2326 format_type_be(domainOid));
2328 /* Otherwise we can ignore views, composite types, etc */
2329 if (rel->rd_rel->relkind != RELKIND_RELATION)
2331 relation_close(rel, lockmode);
2335 /* Build the RelToCheck entry with enough space for all atts */
2336 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2339 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2340 result = lcons(rtc, result);
2344 * Confirm column has not been dropped, and is of the expected type.
2345 * This defends against an ALTER DROP COLUMN occuring just before we
2346 * acquired lock ... but if the whole table were dropped, we'd still
2349 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2351 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2352 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2356 * Okay, add column to result. We store the columns in column-number
2357 * order; this is just a hack to improve predictability of regression
2360 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2363 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2365 rtc->atts[ptr] = rtc->atts[ptr - 1];
2368 rtc->atts[ptr] = pg_depend->objsubid;
2371 systable_endscan(depScan);
2373 relation_close(depRel, AccessShareLock);
2381 * Check that the type is actually a domain and that the current user
2382 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2385 checkDomainOwner(HeapTuple tup)
2387 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2389 /* Check that this is actually a domain */
2390 if (typTup->typtype != TYPTYPE_DOMAIN)
2392 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2393 errmsg("%s is not a domain",
2394 format_type_be(HeapTupleGetOid(tup)))));
2396 /* Permission check: must own type */
2397 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2398 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2399 format_type_be(HeapTupleGetOid(tup)));
2403 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2406 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2407 int typMod, Constraint *constr,
2414 CoerceToDomainValue *domVal;
2417 * Assign or validate constraint name
2419 if (constr->conname)
2421 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2426 (errcode(ERRCODE_DUPLICATE_OBJECT),
2427 errmsg("constraint \"%s\" for domain \"%s\" already exists",
2428 constr->conname, domainName)));
2431 constr->conname = ChooseConstraintName(domainName,
2438 * Convert the A_EXPR in raw_expr into an EXPR
2440 pstate = make_parsestate(NULL);
2443 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2444 * the expression. Note that it will appear to have the type of the base
2445 * type, not the domain. This seems correct since within the check
2446 * expression, we should not assume the input value can be considered a
2447 * member of the domain.
2449 domVal = makeNode(CoerceToDomainValue);
2450 domVal->typeId = baseTypeOid;
2451 domVal->typeMod = typMod;
2452 domVal->collation = get_typcollation(baseTypeOid);
2453 domVal->location = -1; /* will be set when/if used */
2455 pstate->p_value_substitute = (Node *) domVal;
2457 expr = transformExpr(pstate, constr->raw_expr);
2460 * Make sure it yields a boolean result.
2462 expr = coerce_to_boolean(pstate, expr, "CHECK");
2465 * Fix up collation information.
2467 assign_expr_collations(pstate, expr);
2470 * Make sure no outside relations are referred to.
2472 if (list_length(pstate->p_rtable) != 0)
2474 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2475 errmsg("cannot use table references in domain check constraint")));
2478 * Domains don't allow var clauses (this should be redundant with the
2479 * above check, but make it anyway)
2481 if (contain_var_clause(expr))
2483 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2484 errmsg("cannot use table references in domain check constraint")));
2487 * No subplans or aggregates, either...
2489 if (pstate->p_hasSubLinks)
2491 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2492 errmsg("cannot use subquery in check constraint")));
2493 if (pstate->p_hasAggs)
2495 (errcode(ERRCODE_GROUPING_ERROR),
2496 errmsg("cannot use aggregate function in check constraint")));
2497 if (pstate->p_hasWindowFuncs)
2499 (errcode(ERRCODE_WINDOWING_ERROR),
2500 errmsg("cannot use window function in check constraint")));
2503 * Convert to string form for storage.
2505 ccbin = nodeToString(expr);
2508 * Deparse it to produce text for consrc.
2510 * Since VARNOs aren't allowed in domain constraints, relation context
2511 * isn't required as anything other than a shell.
2513 ccsrc = deparse_expression(expr,
2514 deparse_context_for(domainName,
2519 * Store the constraint in pg_constraint
2521 CreateConstraintEntry(constr->conname, /* Constraint Name */
2522 domainNamespace, /* namespace */
2523 CONSTRAINT_CHECK, /* Constraint Type */
2524 false, /* Is Deferrable */
2525 false, /* Is Deferred */
2526 !constr->skip_validation, /* Is Validated */
2527 InvalidOid, /* not a relation constraint */
2530 domainOid, /* domain constraint */
2531 InvalidOid, /* no associated index */
2532 InvalidOid, /* Foreign key fields */
2541 NULL, /* not an exclusion constraint */
2542 expr, /* Tree form of check constraint */
2543 ccbin, /* Binary form of check constraint */
2544 ccsrc, /* Source form of check constraint */
2545 true, /* is local */
2549 * Return the compiled constraint expression so the calling routine can
2550 * perform any additional required tests.
2556 * GetDomainConstraints - get a list of the current constraints of domain
2558 * Returns a possibly-empty list of DomainConstraintState nodes.
2560 * This is called by the executor during plan startup for a CoerceToDomain
2561 * expression node. The given constraints will be checked for each value
2562 * passed through the node.
2564 * We allow this to be called for non-domain types, in which case the result
2568 GetDomainConstraints(Oid typeOid)
2571 bool notNull = false;
2574 conRel = heap_open(ConstraintRelationId, AccessShareLock);
2580 Form_pg_type typTup;
2584 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
2585 if (!HeapTupleIsValid(tup))
2586 elog(ERROR, "cache lookup failed for type %u", typeOid);
2587 typTup = (Form_pg_type) GETSTRUCT(tup);
2589 if (typTup->typtype != TYPTYPE_DOMAIN)
2591 /* Not a domain, so done */
2592 ReleaseSysCache(tup);
2596 /* Test for NOT NULL Constraint */
2597 if (typTup->typnotnull)
2600 /* Look for CHECK Constraints on this domain */
2601 ScanKeyInit(&key[0],
2602 Anum_pg_constraint_contypid,
2603 BTEqualStrategyNumber, F_OIDEQ,
2604 ObjectIdGetDatum(typeOid));
2606 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
2607 SnapshotNow, 1, key);
2609 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
2611 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
2615 DomainConstraintState *r;
2617 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
2618 if (c->contype != CONSTRAINT_CHECK)
2622 * Not expecting conbin to be NULL, but we'll test for it anyway
2624 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
2625 conRel->rd_att, &isNull);
2627 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
2628 NameStr(typTup->typname), NameStr(c->conname));
2630 check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
2632 /* ExecInitExpr assumes we've planned the expression */
2633 check_expr = expression_planner(check_expr);
2635 r = makeNode(DomainConstraintState);
2636 r->constrainttype = DOM_CONSTRAINT_CHECK;
2637 r->name = pstrdup(NameStr(c->conname));
2638 r->check_expr = ExecInitExpr(check_expr, NULL);
2641 * use lcons() here because constraints of lower domains should be
2644 result = lcons(r, result);
2647 systable_endscan(scan);
2649 /* loop to next domain in stack */
2650 typeOid = typTup->typbasetype;
2651 ReleaseSysCache(tup);
2654 heap_close(conRel, AccessShareLock);
2657 * Only need to add one NOT NULL check regardless of how many domains in
2658 * the stack request it.
2662 DomainConstraintState *r = makeNode(DomainConstraintState);
2664 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
2665 r->name = pstrdup("NOT NULL");
2666 r->check_expr = NULL;
2668 /* lcons to apply the nullness check FIRST */
2669 result = lcons(r, result);
2677 * Execute ALTER TYPE RENAME
2680 RenameType(List *names, const char *newTypeName)
2686 Form_pg_type typTup;
2688 /* Make a TypeName so we can use standard type lookup machinery */
2689 typename = makeTypeNameFromNameList(names);
2690 typeOid = typenameTypeId(NULL, typename);
2692 /* Look up the type in the type table */
2693 rel = heap_open(TypeRelationId, RowExclusiveLock);
2695 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
2696 if (!HeapTupleIsValid(tup))
2697 elog(ERROR, "cache lookup failed for type %u", typeOid);
2698 typTup = (Form_pg_type) GETSTRUCT(tup);
2700 /* check permissions on type */
2701 if (!pg_type_ownercheck(typeOid, GetUserId()))
2702 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2703 format_type_be(typeOid));
2706 * If it's a composite type, we need to check that it really is a
2707 * free-standing composite type, and not a table's rowtype. We want people
2708 * to use ALTER TABLE not ALTER TYPE for that case.
2710 if (typTup->typtype == TYPTYPE_COMPOSITE &&
2711 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2713 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2714 errmsg("%s is a table's row type",
2715 format_type_be(typeOid)),
2716 errhint("Use ALTER TABLE instead.")));
2718 /* don't allow direct alteration of array types, either */
2719 if (OidIsValid(typTup->typelem) &&
2720 get_array_type(typTup->typelem) == typeOid)
2722 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2723 errmsg("cannot alter array type %s",
2724 format_type_be(typeOid)),
2725 errhint("You can alter type %s, which will alter the array type as well.",
2726 format_type_be(typTup->typelem))));
2729 * If type is composite we need to rename associated pg_class entry too.
2730 * RenameRelationInternal will call RenameTypeInternal automatically.
2732 if (typTup->typtype == TYPTYPE_COMPOSITE)
2733 RenameRelationInternal(typTup->typrelid, newTypeName,
2734 typTup->typnamespace);
2736 RenameTypeInternal(typeOid, newTypeName,
2737 typTup->typnamespace);
2740 heap_close(rel, RowExclusiveLock);
2744 * Change the owner of a type.
2747 AlterTypeOwner(List *names, Oid newOwnerId)
2754 Form_pg_type typTup;
2755 AclResult aclresult;
2757 rel = heap_open(TypeRelationId, RowExclusiveLock);
2759 /* Make a TypeName so we can use standard type lookup machinery */
2760 typename = makeTypeNameFromNameList(names);
2762 /* Use LookupTypeName here so that shell types can be processed */
2763 tup = LookupTypeName(NULL, typename, NULL);
2766 (errcode(ERRCODE_UNDEFINED_OBJECT),
2767 errmsg("type \"%s\" does not exist",
2768 TypeNameToString(typename))));
2769 typeOid = typeTypeId(tup);
2771 /* Copy the syscache entry so we can scribble on it below */
2772 newtup = heap_copytuple(tup);
2773 ReleaseSysCache(tup);
2775 typTup = (Form_pg_type) GETSTRUCT(tup);
2778 * If it's a composite type, we need to check that it really is a
2779 * free-standing composite type, and not a table's rowtype. We want people
2780 * to use ALTER TABLE not ALTER TYPE for that case.
2782 if (typTup->typtype == TYPTYPE_COMPOSITE &&
2783 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2785 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2786 errmsg("%s is a table's row type",
2787 format_type_be(typeOid)),
2788 errhint("Use ALTER TABLE instead.")));
2790 /* don't allow direct alteration of array types, either */
2791 if (OidIsValid(typTup->typelem) &&
2792 get_array_type(typTup->typelem) == typeOid)
2794 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2795 errmsg("cannot alter array type %s",
2796 format_type_be(typeOid)),
2797 errhint("You can alter type %s, which will alter the array type as well.",
2798 format_type_be(typTup->typelem))));
2801 * If the new owner is the same as the existing owner, consider the
2802 * command to have succeeded. This is for dump restoration purposes.
2804 if (typTup->typowner != newOwnerId)
2806 /* Superusers can always do it */
2809 /* Otherwise, must be owner of the existing object */
2810 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2811 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2812 format_type_be(HeapTupleGetOid(tup)));
2814 /* Must be able to become new owner */
2815 check_is_member_of_role(GetUserId(), newOwnerId);
2817 /* New owner must have CREATE privilege on namespace */
2818 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
2821 if (aclresult != ACLCHECK_OK)
2822 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
2823 get_namespace_name(typTup->typnamespace));
2827 * If it's a composite type, invoke ATExecChangeOwner so that we fix
2828 * up the pg_class entry properly. That will call back to
2829 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
2831 if (typTup->typtype == TYPTYPE_COMPOSITE)
2832 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
2836 * We can just apply the modification directly.
2838 * okay to scribble on typTup because it's a copy
2840 typTup->typowner = newOwnerId;
2842 simple_heap_update(rel, &tup->t_self, tup);
2844 CatalogUpdateIndexes(rel, tup);
2846 /* Update owner dependency reference */
2847 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2849 /* If it has an array type, update that too */
2850 if (OidIsValid(typTup->typarray))
2851 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
2856 heap_close(rel, RowExclusiveLock);
2860 * AlterTypeOwnerInternal - change type owner unconditionally
2862 * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
2863 * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
2864 * It assumes the caller has done all needed checks. The function will
2865 * automatically recurse to an array type if the type has one.
2867 * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
2868 * entry (ie, it's not a table rowtype nor an array type).
2871 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
2872 bool hasDependEntry)
2876 Form_pg_type typTup;
2878 rel = heap_open(TypeRelationId, RowExclusiveLock);
2880 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
2881 if (!HeapTupleIsValid(tup))
2882 elog(ERROR, "cache lookup failed for type %u", typeOid);
2883 typTup = (Form_pg_type) GETSTRUCT(tup);
2886 * Modify the owner --- okay to scribble on typTup because it's a copy
2888 typTup->typowner = newOwnerId;
2890 simple_heap_update(rel, &tup->t_self, tup);
2892 CatalogUpdateIndexes(rel, tup);
2894 /* Update owner dependency reference, if it has one */
2896 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2898 /* If it has an array type, update that too */
2899 if (OidIsValid(typTup->typarray))
2900 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
2903 heap_close(rel, RowExclusiveLock);
2907 * Execute ALTER TYPE SET SCHEMA
2910 AlterTypeNamespace(List *names, const char *newschema)
2916 /* Make a TypeName so we can use standard type lookup machinery */
2917 typename = makeTypeNameFromNameList(names);
2918 typeOid = typenameTypeId(NULL, typename);
2920 /* get schema OID and check its permissions */
2921 nspOid = LookupCreationNamespace(newschema);
2923 AlterTypeNamespace_oid(typeOid, nspOid);
2927 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid)
2931 /* check permissions on type */
2932 if (!pg_type_ownercheck(typeOid, GetUserId()))
2933 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2934 format_type_be(typeOid));
2936 /* don't allow direct alteration of array types */
2937 elemOid = get_element_type(typeOid);
2938 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
2940 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2941 errmsg("cannot alter array type %s",
2942 format_type_be(typeOid)),
2943 errhint("You can alter type %s, which will alter the array type as well.",
2944 format_type_be(elemOid))));
2946 /* and do the work */
2947 return AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
2951 * Move specified type to new namespace.
2953 * Caller must have already checked privileges.
2955 * The function automatically recurses to process the type's array type,
2956 * if any. isImplicitArray should be TRUE only when doing this internal
2957 * recursion (outside callers must never try to move an array type directly).
2959 * If errorOnTableType is TRUE, the function errors out if the type is
2960 * a table type. ALTER TABLE has to be used to move a table to a new
2963 * Returns the type's old namespace OID.
2966 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
2967 bool isImplicitArray,
2968 bool errorOnTableType)
2972 Form_pg_type typform;
2975 bool isCompositeType;
2977 rel = heap_open(TypeRelationId, RowExclusiveLock);
2979 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
2980 if (!HeapTupleIsValid(tup))
2981 elog(ERROR, "cache lookup failed for type %u", typeOid);
2982 typform = (Form_pg_type) GETSTRUCT(tup);
2984 oldNspOid = typform->typnamespace;
2985 arrayOid = typform->typarray;
2987 /* common checks on switching namespaces */
2988 CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
2990 /* check for duplicate name (more friendly than unique-index failure) */
2991 if (SearchSysCacheExists2(TYPENAMENSP,
2992 CStringGetDatum(NameStr(typform->typname)),
2993 ObjectIdGetDatum(nspOid)))
2995 (errcode(ERRCODE_DUPLICATE_OBJECT),
2996 errmsg("type \"%s\" already exists in schema \"%s\"",
2997 NameStr(typform->typname),
2998 get_namespace_name(nspOid))));
3000 /* Detect whether type is a composite type (but not a table rowtype) */
3002 (typform->typtype == TYPTYPE_COMPOSITE &&
3003 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3005 /* Enforce not-table-type if requested */
3006 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3009 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3010 errmsg("%s is a table's row type",
3011 format_type_be(typeOid)),
3012 errhint("Use ALTER TABLE instead.")));
3014 /* OK, modify the pg_type row */
3016 /* tup is a copy, so we can scribble directly on it */
3017 typform->typnamespace = nspOid;
3019 simple_heap_update(rel, &tup->t_self, tup);
3020 CatalogUpdateIndexes(rel, tup);
3023 * Composite types have pg_class entries.
3025 * We need to modify the pg_class tuple as well to reflect the change of
3028 if (isCompositeType)
3032 classRel = heap_open(RelationRelationId, RowExclusiveLock);
3034 AlterRelationNamespaceInternal(classRel, typform->typrelid,
3038 heap_close(classRel, RowExclusiveLock);
3041 * Check for constraints associated with the composite type (we don't
3042 * currently support this, but probably will someday).
3044 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3049 /* If it's a domain, it might have constraints */
3050 if (typform->typtype == TYPTYPE_DOMAIN)
3051 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
3055 * Update dependency on schema, if any --- a table rowtype has not got
3056 * one, and neither does an implicit array.
3058 if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3060 if (changeDependencyFor(TypeRelationId, typeOid,
3061 NamespaceRelationId, oldNspOid, nspOid) != 1)
3062 elog(ERROR, "failed to change schema dependency for type %s",
3063 format_type_be(typeOid));
3065 heap_freetuple(tup);
3067 heap_close(rel, RowExclusiveLock);
3069 /* Recursively alter the associated array type, if any */
3070 if (OidIsValid(arrayOid))
3071 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);