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_language.h"
46 #include "catalog/pg_namespace.h"
47 #include "catalog/pg_proc.h"
48 #include "catalog/pg_proc_fn.h"
49 #include "catalog/pg_range.h"
50 #include "catalog/pg_type.h"
51 #include "catalog/pg_type_fn.h"
52 #include "commands/defrem.h"
53 #include "commands/tablecmds.h"
54 #include "commands/typecmds.h"
55 #include "executor/executor.h"
56 #include "miscadmin.h"
57 #include "nodes/makefuncs.h"
58 #include "optimizer/planner.h"
59 #include "optimizer/var.h"
60 #include "parser/parse_coerce.h"
61 #include "parser/parse_collate.h"
62 #include "parser/parse_expr.h"
63 #include "parser/parse_func.h"
64 #include "parser/parse_type.h"
65 #include "utils/acl.h"
66 #include "utils/builtins.h"
67 #include "utils/fmgroids.h"
68 #include "utils/lsyscache.h"
69 #include "utils/memutils.h"
70 #include "utils/rel.h"
71 #include "utils/syscache.h"
72 #include "utils/tqual.h"
75 /* result structure for get_rels_with_domain() */
78 Relation rel; /* opened and locked relation */
79 int natts; /* number of attributes of interest */
80 int *atts; /* attribute numbers */
81 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
84 /* Potentially set by contrib/pg_upgrade_support functions */
85 Oid binary_upgrade_next_array_pg_type_oid = InvalidOid;
87 static void makeRangeConstructors(const char *name, Oid namespace,
88 Oid rangeOid, Oid subtype);
89 static Oid findTypeInputFunction(List *procname, Oid typeOid);
90 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
91 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
92 static Oid findTypeSendFunction(List *procname, Oid typeOid);
93 static Oid findTypeTypmodinFunction(List *procname);
94 static Oid findTypeTypmodoutFunction(List *procname);
95 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
96 static Oid findRangeSubOpclass(List *opcname, Oid subtype);
97 static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
98 static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
99 static void validateDomainConstraint(Oid domainoid, char *ccbin);
100 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
101 static void checkDomainOwner(HeapTuple tup);
102 static void checkEnumOwner(HeapTuple tup);
103 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
105 int typMod, Constraint *constr,
111 * Registers a new base type.
114 DefineType(List *names, List *parameters)
118 int16 internalLength = -1; /* default: variable-length */
119 List *inputName = NIL;
120 List *outputName = NIL;
121 List *receiveName = NIL;
122 List *sendName = NIL;
123 List *typmodinName = NIL;
124 List *typmodoutName = NIL;
125 List *analyzeName = NIL;
126 char category = TYPCATEGORY_USER;
127 bool preferred = false;
128 char delimiter = DEFAULT_TYPDELIM;
129 Oid elemType = InvalidOid;
130 char *defaultValue = NULL;
131 bool byValue = false;
132 char alignment = 'i'; /* default alignment */
133 char storage = 'p'; /* default TOAST storage method */
134 Oid collation = InvalidOid;
135 DefElem *likeTypeEl = NULL;
136 DefElem *internalLengthEl = NULL;
137 DefElem *inputNameEl = NULL;
138 DefElem *outputNameEl = NULL;
139 DefElem *receiveNameEl = NULL;
140 DefElem *sendNameEl = NULL;
141 DefElem *typmodinNameEl = NULL;
142 DefElem *typmodoutNameEl = NULL;
143 DefElem *analyzeNameEl = NULL;
144 DefElem *categoryEl = NULL;
145 DefElem *preferredEl = NULL;
146 DefElem *delimiterEl = NULL;
147 DefElem *elemTypeEl = NULL;
148 DefElem *defaultValueEl = NULL;
149 DefElem *byValueEl = NULL;
150 DefElem *alignmentEl = NULL;
151 DefElem *storageEl = NULL;
152 DefElem *collatableEl = NULL;
155 Oid receiveOid = InvalidOid;
156 Oid sendOid = InvalidOid;
157 Oid typmodinOid = InvalidOid;
158 Oid typmodoutOid = InvalidOid;
159 Oid analyzeOid = InvalidOid;
167 * As of Postgres 8.4, we require superuser privilege to create a base
168 * type. This is simple paranoia: there are too many ways to mess up the
169 * system with an incorrect type definition (for instance, representation
170 * parameters that don't match what the C code expects). In practice it
171 * takes superuser privilege to create the I/O functions, and so the
172 * former requirement that you own the I/O functions pretty much forced
173 * superuserness anyway. We're just making doubly sure here.
175 * XXX re-enable NOT_USED code sections below if you remove this test.
179 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
180 errmsg("must be superuser to create a base type")));
182 /* Convert list of names to a name and namespace */
183 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
186 /* XXX this is unnecessary given the superuser check above */
187 /* Check we have creation rights in target namespace */
188 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
189 if (aclresult != ACLCHECK_OK)
190 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
191 get_namespace_name(typeNamespace));
195 * Look to see if type already exists (presumably as a shell; if not,
196 * TypeCreate will complain).
198 typoid = GetSysCacheOid2(TYPENAMENSP,
199 CStringGetDatum(typeName),
200 ObjectIdGetDatum(typeNamespace));
203 * If it's not a shell, see if it's an autogenerated array type, and if so
204 * rename it out of the way.
206 if (OidIsValid(typoid) && get_typisdefined(typoid))
208 if (moveArrayTypeName(typoid, typeName, typeNamespace))
213 * If it doesn't exist, create it as a shell, so that the OID is known for
214 * use in the I/O function definitions.
216 if (!OidIsValid(typoid))
218 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
219 /* Make new shell type visible for modification below */
220 CommandCounterIncrement();
223 * If the command was a parameterless CREATE TYPE, we're done ---
224 * creating the shell type was all we're supposed to do.
226 if (parameters == NIL)
231 /* Complain if dummy CREATE TYPE and entry already exists */
232 if (parameters == NIL)
234 (errcode(ERRCODE_DUPLICATE_OBJECT),
235 errmsg("type \"%s\" already exists", typeName)));
238 /* Extract the parameters from the parameter list */
239 foreach(pl, parameters)
241 DefElem *defel = (DefElem *) lfirst(pl);
244 if (pg_strcasecmp(defel->defname, "like") == 0)
245 defelp = &likeTypeEl;
246 else if (pg_strcasecmp(defel->defname, "internallength") == 0)
247 defelp = &internalLengthEl;
248 else if (pg_strcasecmp(defel->defname, "input") == 0)
249 defelp = &inputNameEl;
250 else if (pg_strcasecmp(defel->defname, "output") == 0)
251 defelp = &outputNameEl;
252 else if (pg_strcasecmp(defel->defname, "receive") == 0)
253 defelp = &receiveNameEl;
254 else if (pg_strcasecmp(defel->defname, "send") == 0)
255 defelp = &sendNameEl;
256 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
257 defelp = &typmodinNameEl;
258 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
259 defelp = &typmodoutNameEl;
260 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
261 pg_strcasecmp(defel->defname, "analyse") == 0)
262 defelp = &analyzeNameEl;
263 else if (pg_strcasecmp(defel->defname, "category") == 0)
264 defelp = &categoryEl;
265 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
266 defelp = &preferredEl;
267 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
268 defelp = &delimiterEl;
269 else if (pg_strcasecmp(defel->defname, "element") == 0)
270 defelp = &elemTypeEl;
271 else if (pg_strcasecmp(defel->defname, "default") == 0)
272 defelp = &defaultValueEl;
273 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
275 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
276 defelp = &alignmentEl;
277 else if (pg_strcasecmp(defel->defname, "storage") == 0)
279 else if (pg_strcasecmp(defel->defname, "collatable") == 0)
280 defelp = &collatableEl;
283 /* WARNING, not ERROR, for historical backwards-compatibility */
285 (errcode(ERRCODE_SYNTAX_ERROR),
286 errmsg("type attribute \"%s\" not recognized",
292 (errcode(ERRCODE_SYNTAX_ERROR),
293 errmsg("conflicting or redundant options")));
298 * Now interpret the options; we do this separately so that LIKE can be
299 * overridden by other options regardless of the ordering in the parameter
305 Form_pg_type likeForm;
307 likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
308 likeForm = (Form_pg_type) GETSTRUCT(likeType);
309 internalLength = likeForm->typlen;
310 byValue = likeForm->typbyval;
311 alignment = likeForm->typalign;
312 storage = likeForm->typstorage;
313 ReleaseSysCache(likeType);
315 if (internalLengthEl)
316 internalLength = defGetTypeLength(internalLengthEl);
318 inputName = defGetQualifiedName(inputNameEl);
320 outputName = defGetQualifiedName(outputNameEl);
322 receiveName = defGetQualifiedName(receiveNameEl);
324 sendName = defGetQualifiedName(sendNameEl);
326 typmodinName = defGetQualifiedName(typmodinNameEl);
328 typmodoutName = defGetQualifiedName(typmodoutNameEl);
330 analyzeName = defGetQualifiedName(analyzeNameEl);
333 char *p = defGetString(categoryEl);
336 /* restrict to non-control ASCII */
337 if (category < 32 || category > 126)
339 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
340 errmsg("invalid type category \"%s\": must be simple ASCII",
344 preferred = defGetBoolean(preferredEl);
347 char *p = defGetString(delimiterEl);
350 /* XXX shouldn't we restrict the delimiter? */
354 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
355 /* disallow arrays of pseudotypes */
356 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
358 (errcode(ERRCODE_DATATYPE_MISMATCH),
359 errmsg("array element type cannot be %s",
360 format_type_be(elemType))));
363 defaultValue = defGetString(defaultValueEl);
365 byValue = defGetBoolean(byValueEl);
368 char *a = defGetString(alignmentEl);
371 * Note: if argument was an unquoted identifier, parser will have
372 * applied translations to it, so be prepared to recognize translated
373 * type names as well as the nominal form.
375 if (pg_strcasecmp(a, "double") == 0 ||
376 pg_strcasecmp(a, "float8") == 0 ||
377 pg_strcasecmp(a, "pg_catalog.float8") == 0)
379 else if (pg_strcasecmp(a, "int4") == 0 ||
380 pg_strcasecmp(a, "pg_catalog.int4") == 0)
382 else if (pg_strcasecmp(a, "int2") == 0 ||
383 pg_strcasecmp(a, "pg_catalog.int2") == 0)
385 else if (pg_strcasecmp(a, "char") == 0 ||
386 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
390 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
391 errmsg("alignment \"%s\" not recognized", a)));
395 char *a = defGetString(storageEl);
397 if (pg_strcasecmp(a, "plain") == 0)
399 else if (pg_strcasecmp(a, "external") == 0)
401 else if (pg_strcasecmp(a, "extended") == 0)
403 else if (pg_strcasecmp(a, "main") == 0)
407 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
408 errmsg("storage \"%s\" not recognized", a)));
411 collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
414 * make sure we have our required definitions
416 if (inputName == NIL)
418 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
419 errmsg("type input function must be specified")));
420 if (outputName == NIL)
422 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
423 errmsg("type output function must be specified")));
425 if (typmodinName == NIL && typmodoutName != NIL)
427 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
428 errmsg("type modifier output function is useless without a type modifier input function")));
431 * Convert I/O proc names to OIDs
433 inputOid = findTypeInputFunction(inputName, typoid);
434 outputOid = findTypeOutputFunction(outputName, typoid);
436 receiveOid = findTypeReceiveFunction(receiveName, typoid);
438 sendOid = findTypeSendFunction(sendName, typoid);
441 * Verify that I/O procs return the expected thing. If we see OPAQUE,
442 * complain and change it to the correct type-safe choice.
444 resulttype = get_func_rettype(inputOid);
445 if (resulttype != typoid)
447 if (resulttype == OPAQUEOID)
449 /* backwards-compatibility hack */
451 (errmsg("changing return type of function %s from \"opaque\" to %s",
452 NameListToString(inputName), typeName)));
453 SetFunctionReturnType(inputOid, typoid);
457 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
458 errmsg("type input function %s must return type %s",
459 NameListToString(inputName), typeName)));
461 resulttype = get_func_rettype(outputOid);
462 if (resulttype != CSTRINGOID)
464 if (resulttype == OPAQUEOID)
466 /* backwards-compatibility hack */
468 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
469 NameListToString(outputName))));
470 SetFunctionReturnType(outputOid, CSTRINGOID);
474 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
475 errmsg("type output function %s must return type \"cstring\"",
476 NameListToString(outputName))));
480 resulttype = get_func_rettype(receiveOid);
481 if (resulttype != typoid)
483 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
484 errmsg("type receive function %s must return type %s",
485 NameListToString(receiveName), typeName)));
489 resulttype = get_func_rettype(sendOid);
490 if (resulttype != BYTEAOID)
492 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
493 errmsg("type send function %s must return type \"bytea\"",
494 NameListToString(sendName))));
498 * Convert typmodin/out function proc names to OIDs.
501 typmodinOid = findTypeTypmodinFunction(typmodinName);
503 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
506 * Convert analysis function proc name to an OID. If no analysis function
507 * is specified, we'll use zero to select the built-in default algorithm.
510 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
513 * Check permissions on functions. We choose to require the creator/owner
514 * of a type to also own the underlying functions. Since creating a type
515 * is tantamount to granting public execute access on the functions, the
516 * minimum sane check would be for execute-with-grant-option. But we
517 * don't have a way to make the type go away if the grant option is
518 * revoked, so ownership seems better.
521 /* XXX this is unnecessary given the superuser check above */
522 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
523 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
524 NameListToString(inputName));
525 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
526 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
527 NameListToString(outputName));
528 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
529 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
530 NameListToString(receiveName));
531 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
532 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
533 NameListToString(sendName));
534 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
535 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
536 NameListToString(typmodinName));
537 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
538 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
539 NameListToString(typmodoutName));
540 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
541 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
542 NameListToString(analyzeName));
545 array_oid = AssignTypeArrayOid();
548 * now have TypeCreate do all the real work.
550 * Note: the pg_type.oid is stored in user tables as array elements (base
551 * types) in ArrayType and in composite types in DatumTupleFields. This
552 * oid must be preserved by binary upgrades.
555 TypeCreate(InvalidOid, /* no predetermined type OID */
556 typeName, /* type name */
557 typeNamespace, /* namespace */
558 InvalidOid, /* relation oid (n/a here) */
559 0, /* relation kind (ditto) */
560 GetUserId(), /* owner's ID */
561 internalLength, /* internal size */
562 TYPTYPE_BASE, /* type-type (base type) */
563 category, /* type-category */
564 preferred, /* is it a preferred type? */
565 delimiter, /* array element delimiter */
566 inputOid, /* input procedure */
567 outputOid, /* output procedure */
568 receiveOid, /* receive procedure */
569 sendOid, /* send procedure */
570 typmodinOid, /* typmodin procedure */
571 typmodoutOid, /* typmodout procedure */
572 analyzeOid, /* analyze procedure */
573 elemType, /* element type ID */
574 false, /* this is not an array type */
575 array_oid, /* array type we are about to create */
576 InvalidOid, /* base type ID (only for domains) */
577 defaultValue, /* default type value */
578 NULL, /* no binary form available */
579 byValue, /* passed by value */
580 alignment, /* required alignment */
581 storage, /* TOAST strategy */
582 -1, /* typMod (Domains only) */
583 0, /* Array Dimensions of typbasetype */
584 false, /* Type NOT NULL */
585 collation); /* type's collation */
588 * Create the array type that goes with it.
590 array_type = makeArrayTypeName(typeName, typeNamespace);
592 /* alignment must be 'i' or 'd' for arrays */
593 alignment = (alignment == 'd') ? 'd' : 'i';
595 TypeCreate(array_oid, /* force assignment of this type OID */
596 array_type, /* type name */
597 typeNamespace, /* namespace */
598 InvalidOid, /* relation oid (n/a here) */
599 0, /* relation kind (ditto) */
600 GetUserId(), /* owner's ID */
601 -1, /* internal size (always varlena) */
602 TYPTYPE_BASE, /* type-type (base type) */
603 TYPCATEGORY_ARRAY, /* type-category (array) */
604 false, /* array types are never preferred */
605 delimiter, /* array element delimiter */
606 F_ARRAY_IN, /* input procedure */
607 F_ARRAY_OUT, /* output procedure */
608 F_ARRAY_RECV, /* receive procedure */
609 F_ARRAY_SEND, /* send procedure */
610 typmodinOid, /* typmodin procedure */
611 typmodoutOid, /* typmodout procedure */
612 InvalidOid, /* analyze procedure - default */
613 typoid, /* element type ID */
614 true, /* yes this is an array type */
615 InvalidOid, /* no further array type */
616 InvalidOid, /* base type ID */
617 NULL, /* never a default type value */
618 NULL, /* binary default isn't sent either */
619 false, /* never passed by value */
620 alignment, /* see above */
621 'x', /* ARRAY is always toastable */
622 -1, /* typMod (Domains only) */
623 0, /* Array dimensions of typbasetype */
624 false, /* Type NOT NULL */
625 collation); /* type's collation */
631 * Guts of type deletion.
634 RemoveTypeById(Oid typeOid)
639 relation = heap_open(TypeRelationId, RowExclusiveLock);
641 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
642 if (!HeapTupleIsValid(tup))
643 elog(ERROR, "cache lookup failed for type %u", typeOid);
645 simple_heap_delete(relation, &tup->t_self);
648 * If it is an enum, delete the pg_enum entries too; we don't bother with
649 * making dependency entries for those, so it has to be done "by hand"
652 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
653 EnumValuesDelete(typeOid);
656 * If it is a range type, delete the pg_range entry too; we don't bother
657 * with making a dependency entry for that, so it has to be done "by hand"
660 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
661 RangeDelete(typeOid);
663 ReleaseSysCache(tup);
665 heap_close(relation, RowExclusiveLock);
671 * Registers a new domain.
674 DefineDomain(CreateDomainStmt *stmt)
679 int16 internalLength;
682 Oid receiveProcedure;
684 Oid analyzeProcedure;
693 char *defaultValue = NULL;
694 char *defaultValueBin = NULL;
695 bool saw_default = false;
696 bool typNotNull = false;
697 bool nullDefined = false;
698 int32 typNDims = list_length(stmt->typeName->arrayBounds);
700 List *schema = stmt->constraints;
706 Form_pg_type baseType;
710 /* Convert list of names to a name and namespace */
711 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
714 /* Check we have creation rights in target namespace */
715 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
717 if (aclresult != ACLCHECK_OK)
718 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
719 get_namespace_name(domainNamespace));
722 * Check for collision with an existing type name. If there is one and
723 * it's an autogenerated array, we can rename it out of the way.
725 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
726 CStringGetDatum(domainName),
727 ObjectIdGetDatum(domainNamespace));
728 if (OidIsValid(old_type_oid))
730 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
732 (errcode(ERRCODE_DUPLICATE_OBJECT),
733 errmsg("type \"%s\" already exists", domainName)));
737 * Look up the base type.
739 typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
740 baseType = (Form_pg_type) GETSTRUCT(typeTup);
741 basetypeoid = HeapTupleGetOid(typeTup);
744 * Base type must be a plain base type, another domain, an enum or a range
745 * type. Domains over pseudotypes would create a security hole. Domains
746 * over composite types might be made to work in the future, but not
749 typtype = baseType->typtype;
750 if (typtype != TYPTYPE_BASE &&
751 typtype != TYPTYPE_DOMAIN &&
752 typtype != TYPTYPE_ENUM &&
753 typtype != TYPTYPE_RANGE)
755 (errcode(ERRCODE_DATATYPE_MISMATCH),
756 errmsg("\"%s\" is not a valid base type for a domain",
757 TypeNameToString(stmt->typeName))));
760 * Identify the collation if any
762 baseColl = baseType->typcollation;
763 if (stmt->collClause)
764 domaincoll = get_collation_oid(stmt->collClause->collname, false);
766 domaincoll = baseColl;
768 /* Complain if COLLATE is applied to an uncollatable type */
769 if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
771 (errcode(ERRCODE_DATATYPE_MISMATCH),
772 errmsg("collations are not supported by type %s",
773 format_type_be(basetypeoid))));
775 /* passed by value */
776 byValue = baseType->typbyval;
778 /* Required Alignment */
779 alignment = baseType->typalign;
782 storage = baseType->typstorage;
785 internalLength = baseType->typlen;
788 category = baseType->typcategory;
790 /* Array element Delimiter */
791 delimiter = baseType->typdelim;
794 inputProcedure = F_DOMAIN_IN;
795 outputProcedure = baseType->typoutput;
796 receiveProcedure = F_DOMAIN_RECV;
797 sendProcedure = baseType->typsend;
799 /* Domains never accept typmods, so no typmodin/typmodout needed */
801 /* Analysis function */
802 analyzeProcedure = baseType->typanalyze;
804 /* Inherited default value */
805 datum = SysCacheGetAttr(TYPEOID, typeTup,
806 Anum_pg_type_typdefault, &isnull);
808 defaultValue = TextDatumGetCString(datum);
810 /* Inherited default binary value */
811 datum = SysCacheGetAttr(TYPEOID, typeTup,
812 Anum_pg_type_typdefaultbin, &isnull);
814 defaultValueBin = TextDatumGetCString(datum);
817 * Run through constraints manually to avoid the additional processing
818 * conducted by DefineRelation() and friends.
820 foreach(listptr, schema)
822 Constraint *constr = lfirst(listptr);
824 if (!IsA(constr, Constraint))
825 elog(ERROR, "unrecognized node type: %d",
826 (int) nodeTag(constr));
827 switch (constr->contype)
832 * The inherited default value may be overridden by the user
833 * with the DEFAULT <expr> clause ... but only once.
837 (errcode(ERRCODE_SYNTAX_ERROR),
838 errmsg("multiple default expressions")));
841 if (constr->raw_expr)
846 /* Create a dummy ParseState for transformExpr */
847 pstate = make_parsestate(NULL);
850 * Cook the constr->raw_expr into an expression. Note:
851 * name is strictly for error message
853 defaultExpr = cookDefault(pstate, constr->raw_expr,
859 * If the expression is just a NULL constant, we treat it
860 * like not having a default.
862 * Note that if the basetype is another domain, we'll see
863 * a CoerceToDomain expr here and not discard the default.
864 * This is critical because the domain default needs to be
865 * retained to override any default that the base domain
868 if (defaultExpr == NULL ||
869 (IsA(defaultExpr, Const) &&
870 ((Const *) defaultExpr)->constisnull))
873 defaultValueBin = NULL;
878 * Expression must be stored as a nodeToString result,
879 * but we also require a valid textual representation
880 * (mainly to make life easier for pg_dump).
883 deparse_expression(defaultExpr,
884 deparse_context_for(domainName,
887 defaultValueBin = nodeToString(defaultExpr);
892 /* No default (can this still happen?) */
894 defaultValueBin = NULL;
899 if (nullDefined && !typNotNull)
901 (errcode(ERRCODE_SYNTAX_ERROR),
902 errmsg("conflicting NULL/NOT NULL constraints")));
908 if (nullDefined && typNotNull)
910 (errcode(ERRCODE_SYNTAX_ERROR),
911 errmsg("conflicting NULL/NOT NULL constraints")));
919 * Check constraints are handled after domain creation, as
920 * they require the Oid of the domain
925 * All else are error cases
929 (errcode(ERRCODE_SYNTAX_ERROR),
930 errmsg("unique constraints not possible for domains")));
935 (errcode(ERRCODE_SYNTAX_ERROR),
936 errmsg("primary key constraints not possible for domains")));
939 case CONSTR_EXCLUSION:
941 (errcode(ERRCODE_SYNTAX_ERROR),
942 errmsg("exclusion constraints not possible for domains")));
947 (errcode(ERRCODE_SYNTAX_ERROR),
948 errmsg("foreign key constraints not possible for domains")));
951 case CONSTR_ATTR_DEFERRABLE:
952 case CONSTR_ATTR_NOT_DEFERRABLE:
953 case CONSTR_ATTR_DEFERRED:
954 case CONSTR_ATTR_IMMEDIATE:
956 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
957 errmsg("specifying constraint deferrability not supported for domains")));
961 elog(ERROR, "unrecognized constraint subtype: %d",
962 (int) constr->contype);
968 * Have TypeCreate do all the real work.
971 TypeCreate(InvalidOid, /* no predetermined type OID */
972 domainName, /* type name */
973 domainNamespace, /* namespace */
974 InvalidOid, /* relation oid (n/a here) */
975 0, /* relation kind (ditto) */
976 GetUserId(), /* owner's ID */
977 internalLength, /* internal size */
978 TYPTYPE_DOMAIN, /* type-type (domain type) */
979 category, /* type-category */
980 false, /* domain types are never preferred */
981 delimiter, /* array element delimiter */
982 inputProcedure, /* input procedure */
983 outputProcedure, /* output procedure */
984 receiveProcedure, /* receive procedure */
985 sendProcedure, /* send procedure */
986 InvalidOid, /* typmodin procedure - none */
987 InvalidOid, /* typmodout procedure - none */
988 analyzeProcedure, /* analyze procedure */
989 InvalidOid, /* no array element type */
990 false, /* this isn't an array */
991 InvalidOid, /* no arrays for domains (yet) */
992 basetypeoid, /* base type ID */
993 defaultValue, /* default type value (text) */
994 defaultValueBin, /* default type value (binary) */
995 byValue, /* passed by value */
996 alignment, /* required alignment */
997 storage, /* TOAST strategy */
998 basetypeMod, /* typeMod value */
999 typNDims, /* Array dimensions for base type */
1000 typNotNull, /* Type NOT NULL */
1001 domaincoll); /* type's collation */
1004 * Process constraints which refer to the domain ID returned by TypeCreate
1006 foreach(listptr, schema)
1008 Constraint *constr = lfirst(listptr);
1010 /* it must be a Constraint, per check above */
1012 switch (constr->contype)
1015 domainAddConstraint(domainoid, domainNamespace,
1016 basetypeoid, basetypeMod,
1017 constr, domainName);
1020 /* Other constraint types were fully processed above */
1026 /* CCI so we can detect duplicate constraint names */
1027 CommandCounterIncrement();
1031 * Now we can clean up.
1033 ReleaseSysCache(typeTup);
1039 * Registers a new enum.
1042 DefineEnum(CreateEnumStmt *stmt)
1045 char *enumArrayName;
1048 AclResult aclresult;
1052 /* Convert list of names to a name and namespace */
1053 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1056 /* Check we have creation rights in target namespace */
1057 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1058 if (aclresult != ACLCHECK_OK)
1059 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1060 get_namespace_name(enumNamespace));
1063 * Check for collision with an existing type name. If there is one and
1064 * it's an autogenerated array, we can rename it out of the way.
1066 old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1067 CStringGetDatum(enumName),
1068 ObjectIdGetDatum(enumNamespace));
1069 if (OidIsValid(old_type_oid))
1071 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1073 (errcode(ERRCODE_DUPLICATE_OBJECT),
1074 errmsg("type \"%s\" already exists", enumName)));
1077 enumArrayOid = AssignTypeArrayOid();
1079 /* Create the pg_type entry */
1081 TypeCreate(InvalidOid, /* no predetermined type OID */
1082 enumName, /* type name */
1083 enumNamespace, /* namespace */
1084 InvalidOid, /* relation oid (n/a here) */
1085 0, /* relation kind (ditto) */
1086 GetUserId(), /* owner's ID */
1087 sizeof(Oid), /* internal size */
1088 TYPTYPE_ENUM, /* type-type (enum type) */
1089 TYPCATEGORY_ENUM, /* type-category (enum type) */
1090 false, /* enum types are never preferred */
1091 DEFAULT_TYPDELIM, /* array element delimiter */
1092 F_ENUM_IN, /* input procedure */
1093 F_ENUM_OUT, /* output procedure */
1094 F_ENUM_RECV, /* receive procedure */
1095 F_ENUM_SEND, /* send procedure */
1096 InvalidOid, /* typmodin procedure - none */
1097 InvalidOid, /* typmodout procedure - none */
1098 InvalidOid, /* analyze procedure - default */
1099 InvalidOid, /* element type ID */
1100 false, /* this is not an array type */
1101 enumArrayOid, /* array type we are about to create */
1102 InvalidOid, /* base type ID (only for domains) */
1103 NULL, /* never a default type value */
1104 NULL, /* binary default isn't sent either */
1105 true, /* always passed by value */
1106 'i', /* int alignment */
1107 'p', /* TOAST strategy always plain */
1108 -1, /* typMod (Domains only) */
1109 0, /* Array dimensions of typbasetype */
1110 false, /* Type NOT NULL */
1111 InvalidOid); /* type's collation */
1113 /* Enter the enum's values into pg_enum */
1114 EnumValuesCreate(enumTypeOid, stmt->vals);
1117 * Create the array type that goes with it.
1119 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1121 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1122 enumArrayName, /* type name */
1123 enumNamespace, /* namespace */
1124 InvalidOid, /* relation oid (n/a here) */
1125 0, /* relation kind (ditto) */
1126 GetUserId(), /* owner's ID */
1127 -1, /* internal size (always varlena) */
1128 TYPTYPE_BASE, /* type-type (base type) */
1129 TYPCATEGORY_ARRAY, /* type-category (array) */
1130 false, /* array types are never preferred */
1131 DEFAULT_TYPDELIM, /* array element delimiter */
1132 F_ARRAY_IN, /* input procedure */
1133 F_ARRAY_OUT, /* output procedure */
1134 F_ARRAY_RECV, /* receive procedure */
1135 F_ARRAY_SEND, /* send procedure */
1136 InvalidOid, /* typmodin procedure - none */
1137 InvalidOid, /* typmodout procedure - none */
1138 InvalidOid, /* analyze procedure - default */
1139 enumTypeOid, /* element type ID */
1140 true, /* yes this is an array type */
1141 InvalidOid, /* no further array type */
1142 InvalidOid, /* base type ID */
1143 NULL, /* never a default type value */
1144 NULL, /* binary default isn't sent either */
1145 false, /* never passed by value */
1146 'i', /* enums have align i, so do their arrays */
1147 'x', /* ARRAY is always toastable */
1148 -1, /* typMod (Domains only) */
1149 0, /* Array dimensions of typbasetype */
1150 false, /* Type NOT NULL */
1151 InvalidOid); /* type's collation */
1153 pfree(enumArrayName);
1158 * Adds a new label to an existing enum.
1161 AlterEnum(AlterEnumStmt *stmt)
1167 /* Make a TypeName so we can use standard type lookup machinery */
1168 typename = makeTypeNameFromNameList(stmt->typeName);
1169 enum_type_oid = typenameTypeId(NULL, typename);
1171 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1172 if (!HeapTupleIsValid(tup))
1173 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1175 /* Check it's an enum and check user has permission to ALTER the enum */
1176 checkEnumOwner(tup);
1178 /* Add the new label */
1179 AddEnumLabel(enum_type_oid, stmt->newVal,
1180 stmt->newValNeighbor, stmt->newValIsAfter);
1182 ReleaseSysCache(tup);
1189 * Check that the type is actually an enum and that the current user
1190 * has permission to do ALTER TYPE on it. Throw an error if not.
1193 checkEnumOwner(HeapTuple tup)
1195 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1197 /* Check that this is actually an enum */
1198 if (typTup->typtype != TYPTYPE_ENUM)
1200 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1201 errmsg("%s is not an enum",
1202 format_type_be(HeapTupleGetOid(tup)))));
1204 /* Permission check: must own type */
1205 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1206 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
1207 format_type_be(HeapTupleGetOid(tup)));
1213 * Registers a new range type.
1216 DefineRange(CreateRangeStmt *stmt)
1221 char *rangeArrayName;
1223 Oid rangeSubtype = InvalidOid;
1224 List *rangeSubOpclassName = NIL;
1225 List *rangeCollationName = NIL;
1226 List *rangeCanonicalName = NIL;
1227 List *rangeSubtypeDiffName = NIL;
1228 Oid rangeSubOpclass;
1230 regproc rangeCanonical;
1231 regproc rangeSubtypeDiff;
1236 AclResult aclresult;
1239 /* Convert list of names to a name and namespace */
1240 typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1243 /* Check we have creation rights in target namespace */
1244 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1245 if (aclresult != ACLCHECK_OK)
1246 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1247 get_namespace_name(typeNamespace));
1250 * Look to see if type already exists.
1252 typoid = GetSysCacheOid2(TYPENAMENSP,
1253 CStringGetDatum(typeName),
1254 ObjectIdGetDatum(typeNamespace));
1257 * If it's not a shell, see if it's an autogenerated array type, and if so
1258 * rename it out of the way.
1260 if (OidIsValid(typoid) && get_typisdefined(typoid))
1262 if (moveArrayTypeName(typoid, typeName, typeNamespace))
1263 typoid = InvalidOid;
1266 (errcode(ERRCODE_DUPLICATE_OBJECT),
1267 errmsg("type \"%s\" already exists", typeName)));
1271 * If it doesn't exist, create it as a shell, so that the OID is known for
1272 * use in the range function definitions.
1274 if (!OidIsValid(typoid))
1276 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
1277 /* Make new shell type visible for modification below */
1278 CommandCounterIncrement();
1281 /* Extract the parameters from the parameter list */
1282 foreach(lc, stmt->params)
1284 DefElem *defel = (DefElem *) lfirst(lc);
1286 if (pg_strcasecmp(defel->defname, "subtype") == 0)
1288 if (OidIsValid(rangeSubtype))
1290 (errcode(ERRCODE_SYNTAX_ERROR),
1291 errmsg("conflicting or redundant options")));
1292 /* we can look up the subtype name immediately */
1293 rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1295 else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
1297 if (rangeSubOpclassName != NIL)
1299 (errcode(ERRCODE_SYNTAX_ERROR),
1300 errmsg("conflicting or redundant options")));
1301 rangeSubOpclassName = defGetQualifiedName(defel);
1303 else if (pg_strcasecmp(defel->defname, "collation") == 0)
1305 if (rangeCollationName != NIL)
1307 (errcode(ERRCODE_SYNTAX_ERROR),
1308 errmsg("conflicting or redundant options")));
1309 rangeCollationName = defGetQualifiedName(defel);
1311 else if (pg_strcasecmp(defel->defname, "canonical") == 0)
1313 if (rangeCanonicalName != NIL)
1315 (errcode(ERRCODE_SYNTAX_ERROR),
1316 errmsg("conflicting or redundant options")));
1317 rangeCanonicalName = defGetQualifiedName(defel);
1319 else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
1321 if (rangeSubtypeDiffName != NIL)
1323 (errcode(ERRCODE_SYNTAX_ERROR),
1324 errmsg("conflicting or redundant options")));
1325 rangeSubtypeDiffName = defGetQualifiedName(defel);
1329 (errcode(ERRCODE_SYNTAX_ERROR),
1330 errmsg("type attribute \"%s\" not recognized",
1334 /* Must have a subtype */
1335 if (!OidIsValid(rangeSubtype))
1337 (errcode(ERRCODE_SYNTAX_ERROR),
1338 errmsg("type attribute \"subtype\" is required")));
1339 /* disallow ranges of pseudotypes */
1340 if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
1342 (errcode(ERRCODE_DATATYPE_MISMATCH),
1343 errmsg("range subtype cannot be %s",
1344 format_type_be(rangeSubtype))));
1346 /* Identify subopclass */
1347 rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1349 /* Identify collation to use, if any */
1350 if (type_is_collatable(rangeSubtype))
1352 if (rangeCollationName != NIL)
1353 rangeCollation = get_collation_oid(rangeCollationName, false);
1355 rangeCollation = get_typcollation(rangeSubtype);
1359 if (rangeCollationName != NIL)
1361 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1362 errmsg("range collation specified but subtype does not support collation")));
1363 rangeCollation = InvalidOid;
1366 /* Identify support functions, if provided */
1367 if (rangeCanonicalName != NIL)
1368 rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1371 rangeCanonical = InvalidOid;
1373 if (rangeSubtypeDiffName != NIL)
1374 rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1377 rangeSubtypeDiff = InvalidOid;
1379 get_typlenbyvalalign(rangeSubtype,
1380 &subtyplen, &subtypbyval, &subtypalign);
1382 /* alignment must be 'i' or 'd' for ranges */
1383 alignment = (subtypalign == 'd') ? 'd' : 'i';
1385 /* Allocate OID for array type */
1386 rangeArrayOid = AssignTypeArrayOid();
1388 /* Create the pg_type entry */
1390 TypeCreate(InvalidOid, /* no predetermined type OID */
1391 typeName, /* type name */
1392 typeNamespace, /* namespace */
1393 InvalidOid, /* relation oid (n/a here) */
1394 0, /* relation kind (ditto) */
1395 GetUserId(), /* owner's ID */
1396 -1, /* internal size (always varlena) */
1397 TYPTYPE_RANGE, /* type-type (range type) */
1398 TYPCATEGORY_RANGE, /* type-category (range type) */
1399 false, /* range types are never preferred */
1400 DEFAULT_TYPDELIM, /* array element delimiter */
1401 F_RANGE_IN, /* input procedure */
1402 F_RANGE_OUT, /* output procedure */
1403 F_RANGE_RECV, /* receive procedure */
1404 F_RANGE_SEND, /* send procedure */
1405 InvalidOid, /* typmodin procedure - none */
1406 InvalidOid, /* typmodout procedure - none */
1407 F_RANGE_TYPANALYZE, /* analyze procedure */
1408 InvalidOid, /* element type ID - none */
1409 false, /* this is not an array type */
1410 rangeArrayOid, /* array type we are about to create */
1411 InvalidOid, /* base type ID (only for domains) */
1412 NULL, /* never a default type value */
1413 NULL, /* no binary form available either */
1414 false, /* never passed by value */
1415 alignment, /* alignment */
1416 'x', /* TOAST strategy (always extended) */
1417 -1, /* typMod (Domains only) */
1418 0, /* Array dimensions of typbasetype */
1419 false, /* Type NOT NULL */
1420 InvalidOid); /* type's collation (ranges never have one) */
1422 /* Create the entry in pg_range */
1423 RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1424 rangeCanonical, rangeSubtypeDiff);
1427 * Create the array type that goes with it.
1429 rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1431 TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1432 rangeArrayName, /* type name */
1433 typeNamespace, /* namespace */
1434 InvalidOid, /* relation oid (n/a here) */
1435 0, /* relation kind (ditto) */
1436 GetUserId(), /* owner's ID */
1437 -1, /* internal size (always varlena) */
1438 TYPTYPE_BASE, /* type-type (base type) */
1439 TYPCATEGORY_ARRAY, /* type-category (array) */
1440 false, /* array types are never preferred */
1441 DEFAULT_TYPDELIM, /* array element delimiter */
1442 F_ARRAY_IN, /* input procedure */
1443 F_ARRAY_OUT, /* output procedure */
1444 F_ARRAY_RECV, /* receive procedure */
1445 F_ARRAY_SEND, /* send procedure */
1446 InvalidOid, /* typmodin procedure - none */
1447 InvalidOid, /* typmodout procedure - none */
1448 InvalidOid, /* analyze procedure - default */
1449 typoid, /* element type ID */
1450 true, /* yes this is an array type */
1451 InvalidOid, /* no further array type */
1452 InvalidOid, /* base type ID */
1453 NULL, /* never a default type value */
1454 NULL, /* binary default isn't sent either */
1455 false, /* never passed by value */
1456 alignment, /* alignment - same as range's */
1457 'x', /* ARRAY is always toastable */
1458 -1, /* typMod (Domains only) */
1459 0, /* Array dimensions of typbasetype */
1460 false, /* Type NOT NULL */
1461 InvalidOid); /* typcollation */
1463 pfree(rangeArrayName);
1465 /* And create the constructor functions for this range type */
1466 makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1470 * Because there may exist several range types over the same subtype, the
1471 * range type can't be uniquely determined from the subtype. So it's
1472 * impossible to define a polymorphic constructor; we have to generate new
1473 * constructor functions explicitly for each range type.
1475 * We actually define 4 functions, with 0 through 3 arguments. This is just
1476 * to offer more convenience for the user.
1479 makeRangeConstructors(const char *name, Oid namespace,
1480 Oid rangeOid, Oid subtype)
1482 static const char * const prosrc[2] = {"range_constructor2",
1483 "range_constructor3"};
1484 static const int pronargs[2] = {2, 3};
1486 Oid constructorArgTypes[3];
1487 ObjectAddress myself,
1491 constructorArgTypes[0] = subtype;
1492 constructorArgTypes[1] = subtype;
1493 constructorArgTypes[2] = TEXTOID;
1495 referenced.classId = TypeRelationId;
1496 referenced.objectId = rangeOid;
1497 referenced.objectSubId = 0;
1499 for (i = 0; i < lengthof(prosrc); i++)
1501 oidvector *constructorArgTypesVector;
1504 constructorArgTypesVector = buildoidvector(constructorArgTypes,
1507 procOid = ProcedureCreate(name, /* name: same as range type */
1508 namespace, /* namespace */
1509 false, /* replace */
1510 false, /* returns set */
1511 rangeOid, /* return type */
1512 INTERNALlanguageId, /* language */
1513 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1514 prosrc[i], /* prosrc */
1517 false, /* isWindowFunc */
1518 false, /* security_definer */
1519 false, /* isStrict */
1520 PROVOLATILE_IMMUTABLE, /* volatility */
1521 constructorArgTypesVector, /* parameterTypes */
1522 PointerGetDatum(NULL), /* allParameterTypes */
1523 PointerGetDatum(NULL), /* parameterModes */
1524 PointerGetDatum(NULL), /* parameterNames */
1525 NIL, /* parameterDefaults */
1526 PointerGetDatum(NULL), /* proconfig */
1531 * Make the constructors internally-dependent on the range type so
1532 * that they go away silently when the type is dropped. Note that
1533 * pg_dump depends on this choice to avoid dumping the constructors.
1535 myself.classId = ProcedureRelationId;
1536 myself.objectId = procOid;
1537 myself.objectSubId = 0;
1539 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1545 * Find suitable I/O functions for a type.
1547 * typeOid is the type's OID (which will already exist, if only as a shell
1552 findTypeInputFunction(List *procname, Oid typeOid)
1558 * Input functions can take a single argument of type CSTRING, or three
1559 * arguments (string, typioparam OID, typmod).
1561 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1562 * see this, we issue a warning and fix up the pg_proc entry.
1564 argList[0] = CSTRINGOID;
1566 procOid = LookupFuncName(procname, 1, argList, true);
1567 if (OidIsValid(procOid))
1570 argList[1] = OIDOID;
1571 argList[2] = INT4OID;
1573 procOid = LookupFuncName(procname, 3, argList, true);
1574 if (OidIsValid(procOid))
1577 /* No luck, try it with OPAQUE */
1578 argList[0] = OPAQUEOID;
1580 procOid = LookupFuncName(procname, 1, argList, true);
1582 if (!OidIsValid(procOid))
1584 argList[1] = OIDOID;
1585 argList[2] = INT4OID;
1587 procOid = LookupFuncName(procname, 3, argList, true);
1590 if (OidIsValid(procOid))
1592 /* Found, but must complain and fix the pg_proc entry */
1594 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1595 NameListToString(procname))));
1596 SetFunctionArgType(procOid, 0, CSTRINGOID);
1599 * Need CommandCounterIncrement since DefineType will likely try to
1600 * alter the pg_proc tuple again.
1602 CommandCounterIncrement();
1607 /* Use CSTRING (preferred) in the error message */
1608 argList[0] = CSTRINGOID;
1611 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1612 errmsg("function %s does not exist",
1613 func_signature_string(procname, 1, NIL, argList))));
1615 return InvalidOid; /* keep compiler quiet */
1619 findTypeOutputFunction(List *procname, Oid typeOid)
1625 * Output functions can take a single argument of the type.
1627 * For backwards compatibility we allow OPAQUE in place of the actual type
1628 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1630 argList[0] = typeOid;
1632 procOid = LookupFuncName(procname, 1, argList, true);
1633 if (OidIsValid(procOid))
1636 /* No luck, try it with OPAQUE */
1637 argList[0] = OPAQUEOID;
1639 procOid = LookupFuncName(procname, 1, argList, true);
1641 if (OidIsValid(procOid))
1643 /* Found, but must complain and fix the pg_proc entry */
1645 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1646 NameListToString(procname), format_type_be(typeOid))));
1647 SetFunctionArgType(procOid, 0, typeOid);
1650 * Need CommandCounterIncrement since DefineType will likely try to
1651 * alter the pg_proc tuple again.
1653 CommandCounterIncrement();
1658 /* Use type name, not OPAQUE, in the failure message. */
1659 argList[0] = typeOid;
1662 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1663 errmsg("function %s does not exist",
1664 func_signature_string(procname, 1, NIL, argList))));
1666 return InvalidOid; /* keep compiler quiet */
1670 findTypeReceiveFunction(List *procname, Oid typeOid)
1676 * Receive functions can take a single argument of type INTERNAL, or three
1677 * arguments (internal, typioparam OID, typmod).
1679 argList[0] = INTERNALOID;
1681 procOid = LookupFuncName(procname, 1, argList, true);
1682 if (OidIsValid(procOid))
1685 argList[1] = OIDOID;
1686 argList[2] = INT4OID;
1688 procOid = LookupFuncName(procname, 3, argList, true);
1689 if (OidIsValid(procOid))
1693 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1694 errmsg("function %s does not exist",
1695 func_signature_string(procname, 1, NIL, argList))));
1697 return InvalidOid; /* keep compiler quiet */
1701 findTypeSendFunction(List *procname, Oid typeOid)
1707 * Send functions can take a single argument of the type.
1709 argList[0] = typeOid;
1711 procOid = LookupFuncName(procname, 1, argList, true);
1712 if (OidIsValid(procOid))
1716 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1717 errmsg("function %s does not exist",
1718 func_signature_string(procname, 1, NIL, argList))));
1720 return InvalidOid; /* keep compiler quiet */
1724 findTypeTypmodinFunction(List *procname)
1730 * typmodin functions always take one cstring[] argument and return int4.
1732 argList[0] = CSTRINGARRAYOID;
1734 procOid = LookupFuncName(procname, 1, argList, true);
1735 if (!OidIsValid(procOid))
1737 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1738 errmsg("function %s does not exist",
1739 func_signature_string(procname, 1, NIL, argList))));
1741 if (get_func_rettype(procOid) != INT4OID)
1743 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1744 errmsg("typmod_in function %s must return type \"integer\"",
1745 NameListToString(procname))));
1751 findTypeTypmodoutFunction(List *procname)
1757 * typmodout functions always take one int4 argument and return cstring.
1759 argList[0] = INT4OID;
1761 procOid = LookupFuncName(procname, 1, argList, true);
1762 if (!OidIsValid(procOid))
1764 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1765 errmsg("function %s does not exist",
1766 func_signature_string(procname, 1, NIL, argList))));
1768 if (get_func_rettype(procOid) != CSTRINGOID)
1770 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1771 errmsg("typmod_out function %s must return type \"cstring\"",
1772 NameListToString(procname))));
1778 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1784 * Analyze functions always take one INTERNAL argument and return bool.
1786 argList[0] = INTERNALOID;
1788 procOid = LookupFuncName(procname, 1, argList, true);
1789 if (!OidIsValid(procOid))
1791 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1792 errmsg("function %s does not exist",
1793 func_signature_string(procname, 1, NIL, argList))));
1795 if (get_func_rettype(procOid) != BOOLOID)
1797 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1798 errmsg("type analyze function %s must return type \"boolean\"",
1799 NameListToString(procname))));
1805 * Find suitable support functions and opclasses for a range type.
1809 * Find named btree opclass for subtype, or default btree opclass if
1813 findRangeSubOpclass(List *opcname, Oid subtype)
1820 opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
1823 * Verify that the operator class accepts this datatype. Note we will
1824 * accept binary compatibility.
1826 opInputType = get_opclass_input_type(opcid);
1827 if (!IsBinaryCoercible(subtype, opInputType))
1829 (errcode(ERRCODE_DATATYPE_MISMATCH),
1830 errmsg("operator class \"%s\" does not accept data type %s",
1831 NameListToString(opcname),
1832 format_type_be(subtype))));
1836 opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
1837 if (!OidIsValid(opcid))
1839 /* We spell the error message identically to GetIndexOpClass */
1841 (errcode(ERRCODE_UNDEFINED_OBJECT),
1842 errmsg("data type %s has no default operator class for access method \"%s\"",
1843 format_type_be(subtype), "btree"),
1844 errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
1852 findRangeCanonicalFunction(List *procname, Oid typeOid)
1858 * Range canonical functions must take and return the range type, and must
1861 argList[0] = typeOid;
1863 procOid = LookupFuncName(procname, 1, argList, true);
1865 if (!OidIsValid(procOid))
1867 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1868 errmsg("function %s does not exist",
1869 func_signature_string(procname, 1, NIL, argList))));
1871 if (get_func_rettype(procOid) != typeOid)
1873 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1874 errmsg("range canonical function %s must return range type",
1875 func_signature_string(procname, 1, NIL, argList))));
1877 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1879 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1880 errmsg("range canonical function %s must be immutable",
1881 func_signature_string(procname, 1, NIL, argList))));
1887 findRangeSubtypeDiffFunction(List *procname, Oid subtype)
1893 * Range subtype diff functions must take two arguments of the subtype,
1894 * must return float8, and must be immutable.
1896 argList[0] = subtype;
1897 argList[1] = subtype;
1899 procOid = LookupFuncName(procname, 2, argList, true);
1901 if (!OidIsValid(procOid))
1903 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1904 errmsg("function %s does not exist",
1905 func_signature_string(procname, 2, NIL, argList))));
1907 if (get_func_rettype(procOid) != FLOAT8OID)
1909 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1910 errmsg("range subtype diff function %s must return type double precision",
1911 func_signature_string(procname, 2, NIL, argList))));
1913 if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1915 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1916 errmsg("range subtype diff function %s must be immutable",
1917 func_signature_string(procname, 2, NIL, argList))));
1923 * AssignTypeArrayOid
1925 * Pre-assign the type's array OID for use in pg_type.typarray
1928 AssignTypeArrayOid(void)
1932 /* Use binary-upgrade override for pg_type.typarray, if supplied. */
1933 if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_array_pg_type_oid))
1935 type_array_oid = binary_upgrade_next_array_pg_type_oid;
1936 binary_upgrade_next_array_pg_type_oid = InvalidOid;
1940 Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
1942 type_array_oid = GetNewOid(pg_type);
1943 heap_close(pg_type, AccessShareLock);
1946 return type_array_oid;
1950 /*-------------------------------------------------------------------
1951 * DefineCompositeType
1953 * Create a Composite Type relation.
1954 * `DefineRelation' does all the work, we just provide the correct
1957 * If the relation already exists, then 'DefineRelation' will abort
1960 * DefineCompositeType returns relid for use when creating
1961 * an implicit composite type during function creation
1962 *-------------------------------------------------------------------
1965 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1967 CreateStmt *createStmt = makeNode(CreateStmt);
1973 * now set the parameters for keys/inheritance etc. All of these are
1974 * uninteresting for composite types...
1976 createStmt->relation = (RangeVar *) typevar;
1977 createStmt->tableElts = coldeflist;
1978 createStmt->inhRelations = NIL;
1979 createStmt->constraints = NIL;
1980 createStmt->options = list_make1(defWithOids(false));
1981 createStmt->oncommit = ONCOMMIT_NOOP;
1982 createStmt->tablespacename = NULL;
1983 createStmt->if_not_exists = false;
1986 * Check for collision with an existing type name. If there is one and
1987 * it's an autogenerated array, we can rename it out of the way. This
1988 * check is here mainly to get a better error message about a "type"
1989 * instead of below about a "relation".
1991 typeNamespace = RangeVarGetCreationNamespace(createStmt->relation);
1992 RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
1994 GetSysCacheOid2(TYPENAMENSP,
1995 CStringGetDatum(createStmt->relation->relname),
1996 ObjectIdGetDatum(typeNamespace));
1997 if (OidIsValid(old_type_oid))
1999 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2001 (errcode(ERRCODE_DUPLICATE_OBJECT),
2002 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2006 * Finally create the relation. This also creates the type.
2008 relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
2009 Assert(relid != InvalidOid);
2014 * AlterDomainDefault
2016 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
2019 AlterDomainDefault(List *names, Node *defaultRaw)
2027 Node *defaultExpr = NULL; /* NULL if no default specified */
2028 Datum new_record[Natts_pg_type];
2029 bool new_record_nulls[Natts_pg_type];
2030 bool new_record_repl[Natts_pg_type];
2032 Form_pg_type typTup;
2034 /* Make a TypeName so we can use standard type lookup machinery */
2035 typename = makeTypeNameFromNameList(names);
2036 domainoid = typenameTypeId(NULL, typename);
2038 /* Look up the domain in the type table */
2039 rel = heap_open(TypeRelationId, RowExclusiveLock);
2041 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2042 if (!HeapTupleIsValid(tup))
2043 elog(ERROR, "cache lookup failed for type %u", domainoid);
2044 typTup = (Form_pg_type) GETSTRUCT(tup);
2046 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2047 checkDomainOwner(tup);
2049 /* Setup new tuple */
2050 MemSet(new_record, (Datum) 0, sizeof(new_record));
2051 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2052 MemSet(new_record_repl, false, sizeof(new_record_repl));
2054 /* Store the new default into the tuple */
2057 /* Create a dummy ParseState for transformExpr */
2058 pstate = make_parsestate(NULL);
2061 * Cook the colDef->raw_expr into an expression. Note: Name is
2062 * strictly for error message
2064 defaultExpr = cookDefault(pstate, defaultRaw,
2065 typTup->typbasetype,
2067 NameStr(typTup->typname));
2070 * If the expression is just a NULL constant, we treat the command
2071 * like ALTER ... DROP DEFAULT. (But see note for same test in
2074 if (defaultExpr == NULL ||
2075 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
2077 /* Default is NULL, drop it */
2078 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2079 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2080 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2081 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2086 * Expression must be stored as a nodeToString result, but we also
2087 * require a valid textual representation (mainly to make life
2088 * easier for pg_dump).
2090 defaultValue = deparse_expression(defaultExpr,
2091 deparse_context_for(NameStr(typTup->typname),
2096 * Form an updated tuple with the new default and write it back.
2098 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2100 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2101 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2102 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2107 /* ALTER ... DROP DEFAULT */
2108 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2109 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2110 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2111 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2114 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2115 new_record, new_record_nulls,
2118 simple_heap_update(rel, &tup->t_self, newtuple);
2120 CatalogUpdateIndexes(rel, newtuple);
2122 /* Rebuild dependencies */
2123 GenerateTypeDependencies(typTup->typnamespace,
2125 InvalidOid, /* typrelid is n/a */
2126 0, /* relation kind is n/a */
2136 false, /* a domain isn't an implicit array */
2137 typTup->typbasetype,
2138 typTup->typcollation,
2140 true); /* Rebuild is true */
2143 heap_close(rel, NoLock);
2144 heap_freetuple(newtuple);
2148 * AlterDomainNotNull
2150 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2153 AlterDomainNotNull(List *names, bool notNull)
2159 Form_pg_type typTup;
2161 /* Make a TypeName so we can use standard type lookup machinery */
2162 typename = makeTypeNameFromNameList(names);
2163 domainoid = typenameTypeId(NULL, typename);
2165 /* Look up the domain in the type table */
2166 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2168 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2169 if (!HeapTupleIsValid(tup))
2170 elog(ERROR, "cache lookup failed for type %u", domainoid);
2171 typTup = (Form_pg_type) GETSTRUCT(tup);
2173 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2174 checkDomainOwner(tup);
2176 /* Is the domain already set to the desired constraint? */
2177 if (typTup->typnotnull == notNull)
2179 heap_close(typrel, RowExclusiveLock);
2183 /* Adding a NOT NULL constraint requires checking existing columns */
2189 /* Fetch relation list with attributes based on this domain */
2190 /* ShareLock is sufficient to prevent concurrent data changes */
2192 rels = get_rels_with_domain(domainoid, ShareLock);
2196 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2197 Relation testrel = rtc->rel;
2198 TupleDesc tupdesc = RelationGetDescr(testrel);
2202 /* Scan all tuples in this relation */
2203 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2204 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2208 /* Test attributes that are of the domain */
2209 for (i = 0; i < rtc->natts; i++)
2211 int attnum = rtc->atts[i];
2213 if (heap_attisnull(tuple, attnum))
2215 (errcode(ERRCODE_NOT_NULL_VIOLATION),
2216 errmsg("column \"%s\" of table \"%s\" contains null values",
2217 NameStr(tupdesc->attrs[attnum - 1]->attname),
2218 RelationGetRelationName(testrel))));
2223 /* Close each rel after processing, but keep lock */
2224 heap_close(testrel, NoLock);
2229 * Okay to update pg_type row. We can scribble on typTup because it's a
2232 typTup->typnotnull = notNull;
2234 simple_heap_update(typrel, &tup->t_self, tup);
2236 CatalogUpdateIndexes(typrel, tup);
2239 heap_freetuple(tup);
2240 heap_close(typrel, RowExclusiveLock);
2244 * AlterDomainDropConstraint
2246 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2249 AlterDomainDropConstraint(List *names, const char *constrName,
2250 DropBehavior behavior)
2257 SysScanDesc conscan;
2261 /* Make a TypeName so we can use standard type lookup machinery */
2262 typename = makeTypeNameFromNameList(names);
2263 domainoid = typenameTypeId(NULL, typename);
2265 /* Look up the domain in the type table */
2266 rel = heap_open(TypeRelationId, RowExclusiveLock);
2268 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2269 if (!HeapTupleIsValid(tup))
2270 elog(ERROR, "cache lookup failed for type %u", domainoid);
2272 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2273 checkDomainOwner(tup);
2275 /* Grab an appropriate lock on the pg_constraint relation */
2276 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2278 /* Use the index to scan only constraints of the target relation */
2279 ScanKeyInit(&key[0],
2280 Anum_pg_constraint_contypid,
2281 BTEqualStrategyNumber, F_OIDEQ,
2282 ObjectIdGetDatum(HeapTupleGetOid(tup)));
2284 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2285 SnapshotNow, 1, key);
2288 * Scan over the result set, removing any matching entries.
2290 while ((contup = systable_getnext(conscan)) != NULL)
2292 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
2294 if (strcmp(NameStr(con->conname), constrName) == 0)
2296 ObjectAddress conobj;
2298 conobj.classId = ConstraintRelationId;
2299 conobj.objectId = HeapTupleGetOid(contup);
2300 conobj.objectSubId = 0;
2302 performDeletion(&conobj, behavior);
2305 /* Clean up after the scan */
2306 systable_endscan(conscan);
2307 heap_close(conrel, RowExclusiveLock);
2309 heap_close(rel, NoLock);
2313 * AlterDomainAddConstraint
2315 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2318 AlterDomainAddConstraint(List *names, Node *newConstraint)
2324 Form_pg_type typTup;
2328 /* Make a TypeName so we can use standard type lookup machinery */
2329 typename = makeTypeNameFromNameList(names);
2330 domainoid = typenameTypeId(NULL, typename);
2332 /* Look up the domain in the type table */
2333 typrel = heap_open(TypeRelationId, RowExclusiveLock);
2335 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2336 if (!HeapTupleIsValid(tup))
2337 elog(ERROR, "cache lookup failed for type %u", domainoid);
2338 typTup = (Form_pg_type) GETSTRUCT(tup);
2340 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2341 checkDomainOwner(tup);
2343 if (!IsA(newConstraint, Constraint))
2344 elog(ERROR, "unrecognized node type: %d",
2345 (int) nodeTag(newConstraint));
2347 constr = (Constraint *) newConstraint;
2349 switch (constr->contype)
2352 /* processed below */
2357 (errcode(ERRCODE_SYNTAX_ERROR),
2358 errmsg("unique constraints not possible for domains")));
2361 case CONSTR_PRIMARY:
2363 (errcode(ERRCODE_SYNTAX_ERROR),
2364 errmsg("primary key constraints not possible for domains")));
2367 case CONSTR_EXCLUSION:
2369 (errcode(ERRCODE_SYNTAX_ERROR),
2370 errmsg("exclusion constraints not possible for domains")));
2373 case CONSTR_FOREIGN:
2375 (errcode(ERRCODE_SYNTAX_ERROR),
2376 errmsg("foreign key constraints not possible for domains")));
2379 case CONSTR_ATTR_DEFERRABLE:
2380 case CONSTR_ATTR_NOT_DEFERRABLE:
2381 case CONSTR_ATTR_DEFERRED:
2382 case CONSTR_ATTR_IMMEDIATE:
2384 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2385 errmsg("specifying constraint deferrability not supported for domains")));
2389 elog(ERROR, "unrecognized constraint subtype: %d",
2390 (int) constr->contype);
2395 * Since all other constraint types throw errors, this must be a check
2396 * constraint. First, process the constraint expression and add an entry
2400 ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
2401 typTup->typbasetype, typTup->typtypmod,
2402 constr, NameStr(typTup->typname));
2405 * If requested to validate the constraint, test all values stored in the
2406 * attributes based on the domain the constraint is being added to.
2408 if (!constr->skip_validation)
2409 validateDomainConstraint(domainoid, ccbin);
2412 heap_close(typrel, RowExclusiveLock);
2416 * AlterDomainValidateConstraint
2418 * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
2421 AlterDomainValidateConstraint(List *names, char *constrName)
2428 Form_pg_constraint con = NULL;
2429 Form_pg_constraint copy_con;
2436 HeapTuple copyTuple;
2439 /* Make a TypeName so we can use standard type lookup machinery */
2440 typename = makeTypeNameFromNameList(names);
2441 domainoid = typenameTypeId(NULL, typename);
2443 /* Look up the domain in the type table */
2444 typrel = heap_open(TypeRelationId, AccessShareLock);
2446 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2447 if (!HeapTupleIsValid(tup))
2448 elog(ERROR, "cache lookup failed for type %u", domainoid);
2450 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2451 checkDomainOwner(tup);
2454 * Find and check the target constraint
2456 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2458 Anum_pg_constraint_contypid,
2459 BTEqualStrategyNumber, F_OIDEQ,
2460 ObjectIdGetDatum(domainoid));
2461 scan = systable_beginscan(conrel, ConstraintTypidIndexId,
2462 true, SnapshotNow, 1, &key);
2464 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2466 con = (Form_pg_constraint) GETSTRUCT(tuple);
2467 if (strcmp(NameStr(con->conname), constrName) == 0)
2476 (errcode(ERRCODE_UNDEFINED_OBJECT),
2477 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2478 constrName, TypeNameToString(typename))));
2480 if (con->contype != CONSTRAINT_CHECK)
2482 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2483 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2484 constrName, TypeNameToString(typename))));
2486 val = SysCacheGetAttr(CONSTROID, tuple,
2487 Anum_pg_constraint_conbin,
2490 elog(ERROR, "null conbin for constraint %u",
2491 HeapTupleGetOid(tuple));
2492 conbin = TextDatumGetCString(val);
2494 validateDomainConstraint(domainoid, conbin);
2497 * Now update the catalog, while we have the door open.
2499 copyTuple = heap_copytuple(tuple);
2500 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2501 copy_con->convalidated = true;
2502 simple_heap_update(conrel, ©Tuple->t_self, copyTuple);
2503 CatalogUpdateIndexes(conrel, copyTuple);
2504 heap_freetuple(copyTuple);
2506 systable_endscan(scan);
2508 heap_close(typrel, AccessShareLock);
2509 heap_close(conrel, RowExclusiveLock);
2511 ReleaseSysCache(tup);
2515 validateDomainConstraint(Oid domainoid, char *ccbin)
2517 Expr *expr = (Expr *) stringToNode(ccbin);
2521 ExprContext *econtext;
2522 ExprState *exprstate;
2524 /* Need an EState to run ExecEvalExpr */
2525 estate = CreateExecutorState();
2526 econtext = GetPerTupleExprContext(estate);
2528 /* build execution state for expr */
2529 exprstate = ExecPrepareExpr(expr, estate);
2531 /* Fetch relation list with attributes based on this domain */
2532 /* ShareLock is sufficient to prevent concurrent data changes */
2534 rels = get_rels_with_domain(domainoid, ShareLock);
2538 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2539 Relation testrel = rtc->rel;
2540 TupleDesc tupdesc = RelationGetDescr(testrel);
2544 /* Scan all tuples in this relation */
2545 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2546 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2550 /* Test attributes that are of the domain */
2551 for (i = 0; i < rtc->natts; i++)
2553 int attnum = rtc->atts[i];
2558 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2560 econtext->domainValue_datum = d;
2561 econtext->domainValue_isNull = isNull;
2563 conResult = ExecEvalExprSwitchContext(exprstate,
2567 if (!isNull && !DatumGetBool(conResult))
2569 (errcode(ERRCODE_CHECK_VIOLATION),
2570 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2571 NameStr(tupdesc->attrs[attnum - 1]->attname),
2572 RelationGetRelationName(testrel))));
2575 ResetExprContext(econtext);
2579 /* Hold relation lock till commit (XXX bad for concurrency) */
2580 heap_close(testrel, NoLock);
2583 FreeExecutorState(estate);
2587 * get_rels_with_domain
2589 * Fetch all relations / attributes which are using the domain
2591 * The result is a list of RelToCheck structs, one for each distinct
2592 * relation, each containing one or more attribute numbers that are of
2593 * the domain type. We have opened each rel and acquired the specified lock
2596 * We support nested domains by including attributes that are of derived
2597 * domain types. Current callers do not need to distinguish between attributes
2598 * that are of exactly the given domain and those that are of derived domains.
2600 * XXX this is completely broken because there is no way to lock the domain
2601 * to prevent columns from being added or dropped while our command runs.
2602 * We can partially protect against column drops by locking relations as we
2603 * come across them, but there is still a race condition (the window between
2604 * seeing a pg_depend entry and acquiring lock on the relation it references).
2605 * Also, holding locks on all these relations simultaneously creates a non-
2606 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2607 * risk by using the weakest suitable lock (ShareLock for most callers).
2609 * XXX the API for this is not sufficient to support checking domain values
2610 * that are inside composite types or arrays. Currently we just error out
2611 * if a composite type containing the target domain is stored anywhere.
2612 * There are not currently arrays of domains; if there were, we could take
2613 * the same approach, but it'd be nicer to fix it properly.
2615 * Generally used for retrieving a list of tests when adding
2616 * new constraints to a domain.
2619 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2624 SysScanDesc depScan;
2627 Assert(lockmode != NoLock);
2630 * We scan pg_depend to find those things that depend on the domain. (We
2631 * assume we can ignore refobjsubid for a domain.)
2633 depRel = heap_open(DependRelationId, AccessShareLock);
2635 ScanKeyInit(&key[0],
2636 Anum_pg_depend_refclassid,
2637 BTEqualStrategyNumber, F_OIDEQ,
2638 ObjectIdGetDatum(TypeRelationId));
2639 ScanKeyInit(&key[1],
2640 Anum_pg_depend_refobjid,
2641 BTEqualStrategyNumber, F_OIDEQ,
2642 ObjectIdGetDatum(domainOid));
2644 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2645 SnapshotNow, 2, key);
2647 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2649 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2650 RelToCheck *rtc = NULL;
2652 Form_pg_attribute pg_att;
2655 /* Check for directly dependent types --- must be domains */
2656 if (pg_depend->classid == TypeRelationId)
2658 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2661 * Recursively add dependent columns to the output list. This is
2662 * a bit inefficient since we may fail to combine RelToCheck
2663 * entries when attributes of the same rel have different derived
2664 * domain types, but it's probably not worth improving.
2666 result = list_concat(result,
2667 get_rels_with_domain(pg_depend->objid,
2672 /* Else, ignore dependees that aren't user columns of relations */
2673 /* (we assume system columns are never of domain types) */
2674 if (pg_depend->classid != RelationRelationId ||
2675 pg_depend->objsubid <= 0)
2678 /* See if we already have an entry for this relation */
2679 foreach(rellist, result)
2681 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2683 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2692 /* First attribute found for this relation */
2695 /* Acquire requested lock on relation */
2696 rel = relation_open(pg_depend->objid, lockmode);
2699 * Check to see if rowtype is stored anyplace as a composite-type
2700 * column; if so we have to fail, for now anyway.
2702 if (OidIsValid(rel->rd_rel->reltype))
2703 find_composite_type_dependencies(rel->rd_rel->reltype,
2705 format_type_be(domainOid));
2707 /* Otherwise we can ignore views, composite types, etc */
2708 if (rel->rd_rel->relkind != RELKIND_RELATION)
2710 relation_close(rel, lockmode);
2714 /* Build the RelToCheck entry with enough space for all atts */
2715 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2718 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2719 result = lcons(rtc, result);
2723 * Confirm column has not been dropped, and is of the expected type.
2724 * This defends against an ALTER DROP COLUMN occuring just before we
2725 * acquired lock ... but if the whole table were dropped, we'd still
2728 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2730 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2731 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2735 * Okay, add column to result. We store the columns in column-number
2736 * order; this is just a hack to improve predictability of regression
2739 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2742 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2744 rtc->atts[ptr] = rtc->atts[ptr - 1];
2747 rtc->atts[ptr] = pg_depend->objsubid;
2750 systable_endscan(depScan);
2752 relation_close(depRel, AccessShareLock);
2760 * Check that the type is actually a domain and that the current user
2761 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2764 checkDomainOwner(HeapTuple tup)
2766 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2768 /* Check that this is actually a domain */
2769 if (typTup->typtype != TYPTYPE_DOMAIN)
2771 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2772 errmsg("%s is not a domain",
2773 format_type_be(HeapTupleGetOid(tup)))));
2775 /* Permission check: must own type */
2776 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2777 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2778 format_type_be(HeapTupleGetOid(tup)));
2782 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2785 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2786 int typMod, Constraint *constr,
2793 CoerceToDomainValue *domVal;
2796 * Assign or validate constraint name
2798 if (constr->conname)
2800 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2805 (errcode(ERRCODE_DUPLICATE_OBJECT),
2806 errmsg("constraint \"%s\" for domain \"%s\" already exists",
2807 constr->conname, domainName)));
2810 constr->conname = ChooseConstraintName(domainName,
2817 * Convert the A_EXPR in raw_expr into an EXPR
2819 pstate = make_parsestate(NULL);
2822 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2823 * the expression. Note that it will appear to have the type of the base
2824 * type, not the domain. This seems correct since within the check
2825 * expression, we should not assume the input value can be considered a
2826 * member of the domain.
2828 domVal = makeNode(CoerceToDomainValue);
2829 domVal->typeId = baseTypeOid;
2830 domVal->typeMod = typMod;
2831 domVal->collation = get_typcollation(baseTypeOid);
2832 domVal->location = -1; /* will be set when/if used */
2834 pstate->p_value_substitute = (Node *) domVal;
2836 expr = transformExpr(pstate, constr->raw_expr);
2839 * Make sure it yields a boolean result.
2841 expr = coerce_to_boolean(pstate, expr, "CHECK");
2844 * Fix up collation information.
2846 assign_expr_collations(pstate, expr);
2849 * Make sure no outside relations are referred to.
2851 if (list_length(pstate->p_rtable) != 0)
2853 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2854 errmsg("cannot use table references in domain check constraint")));
2857 * Domains don't allow var clauses (this should be redundant with the
2858 * above check, but make it anyway)
2860 if (contain_var_clause(expr))
2862 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2863 errmsg("cannot use table references in domain check constraint")));
2866 * No subplans or aggregates, either...
2868 if (pstate->p_hasSubLinks)
2870 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2871 errmsg("cannot use subquery in check constraint")));
2872 if (pstate->p_hasAggs)
2874 (errcode(ERRCODE_GROUPING_ERROR),
2875 errmsg("cannot use aggregate function in check constraint")));
2876 if (pstate->p_hasWindowFuncs)
2878 (errcode(ERRCODE_WINDOWING_ERROR),
2879 errmsg("cannot use window function in check constraint")));
2882 * Convert to string form for storage.
2884 ccbin = nodeToString(expr);
2887 * Deparse it to produce text for consrc.
2889 * Since VARNOs aren't allowed in domain constraints, relation context
2890 * isn't required as anything other than a shell.
2892 ccsrc = deparse_expression(expr,
2893 deparse_context_for(domainName,
2898 * Store the constraint in pg_constraint
2900 CreateConstraintEntry(constr->conname, /* Constraint Name */
2901 domainNamespace, /* namespace */
2902 CONSTRAINT_CHECK, /* Constraint Type */
2903 false, /* Is Deferrable */
2904 false, /* Is Deferred */
2905 !constr->skip_validation, /* Is Validated */
2906 InvalidOid, /* not a relation constraint */
2909 domainOid, /* domain constraint */
2910 InvalidOid, /* no associated index */
2911 InvalidOid, /* Foreign key fields */
2920 NULL, /* not an exclusion constraint */
2921 expr, /* Tree form of check constraint */
2922 ccbin, /* Binary form of check constraint */
2923 ccsrc, /* Source form of check constraint */
2924 true, /* is local */
2928 * Return the compiled constraint expression so the calling routine can
2929 * perform any additional required tests.
2935 * GetDomainConstraints - get a list of the current constraints of domain
2937 * Returns a possibly-empty list of DomainConstraintState nodes.
2939 * This is called by the executor during plan startup for a CoerceToDomain
2940 * expression node. The given constraints will be checked for each value
2941 * passed through the node.
2943 * We allow this to be called for non-domain types, in which case the result
2947 GetDomainConstraints(Oid typeOid)
2950 bool notNull = false;
2953 conRel = heap_open(ConstraintRelationId, AccessShareLock);
2959 Form_pg_type typTup;
2963 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
2964 if (!HeapTupleIsValid(tup))
2965 elog(ERROR, "cache lookup failed for type %u", typeOid);
2966 typTup = (Form_pg_type) GETSTRUCT(tup);
2968 if (typTup->typtype != TYPTYPE_DOMAIN)
2970 /* Not a domain, so done */
2971 ReleaseSysCache(tup);
2975 /* Test for NOT NULL Constraint */
2976 if (typTup->typnotnull)
2979 /* Look for CHECK Constraints on this domain */
2980 ScanKeyInit(&key[0],
2981 Anum_pg_constraint_contypid,
2982 BTEqualStrategyNumber, F_OIDEQ,
2983 ObjectIdGetDatum(typeOid));
2985 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
2986 SnapshotNow, 1, key);
2988 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
2990 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
2994 DomainConstraintState *r;
2996 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
2997 if (c->contype != CONSTRAINT_CHECK)
3001 * Not expecting conbin to be NULL, but we'll test for it anyway
3003 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
3004 conRel->rd_att, &isNull);
3006 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
3007 NameStr(typTup->typname), NameStr(c->conname));
3009 check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
3011 /* ExecInitExpr assumes we've planned the expression */
3012 check_expr = expression_planner(check_expr);
3014 r = makeNode(DomainConstraintState);
3015 r->constrainttype = DOM_CONSTRAINT_CHECK;
3016 r->name = pstrdup(NameStr(c->conname));
3017 r->check_expr = ExecInitExpr(check_expr, NULL);
3020 * use lcons() here because constraints of lower domains should be
3023 result = lcons(r, result);
3026 systable_endscan(scan);
3028 /* loop to next domain in stack */
3029 typeOid = typTup->typbasetype;
3030 ReleaseSysCache(tup);
3033 heap_close(conRel, AccessShareLock);
3036 * Only need to add one NOT NULL check regardless of how many domains in
3037 * the stack request it.
3041 DomainConstraintState *r = makeNode(DomainConstraintState);
3043 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
3044 r->name = pstrdup("NOT NULL");
3045 r->check_expr = NULL;
3047 /* lcons to apply the nullness check FIRST */
3048 result = lcons(r, result);
3056 * Execute ALTER TYPE RENAME
3059 RenameType(List *names, const char *newTypeName)
3065 Form_pg_type typTup;
3067 /* Make a TypeName so we can use standard type lookup machinery */
3068 typename = makeTypeNameFromNameList(names);
3069 typeOid = typenameTypeId(NULL, typename);
3071 /* Look up the type in the type table */
3072 rel = heap_open(TypeRelationId, RowExclusiveLock);
3074 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3075 if (!HeapTupleIsValid(tup))
3076 elog(ERROR, "cache lookup failed for type %u", typeOid);
3077 typTup = (Form_pg_type) GETSTRUCT(tup);
3079 /* check permissions on type */
3080 if (!pg_type_ownercheck(typeOid, GetUserId()))
3081 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
3082 format_type_be(typeOid));
3085 * If it's a composite type, we need to check that it really is a
3086 * free-standing composite type, and not a table's rowtype. We want people
3087 * to use ALTER TABLE not ALTER TYPE for that case.
3089 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3090 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3092 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3093 errmsg("%s is a table's row type",
3094 format_type_be(typeOid)),
3095 errhint("Use ALTER TABLE instead.")));
3097 /* don't allow direct alteration of array types, either */
3098 if (OidIsValid(typTup->typelem) &&
3099 get_array_type(typTup->typelem) == typeOid)
3101 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3102 errmsg("cannot alter array type %s",
3103 format_type_be(typeOid)),
3104 errhint("You can alter type %s, which will alter the array type as well.",
3105 format_type_be(typTup->typelem))));
3108 * If type is composite we need to rename associated pg_class entry too.
3109 * RenameRelationInternal will call RenameTypeInternal automatically.
3111 if (typTup->typtype == TYPTYPE_COMPOSITE)
3112 RenameRelationInternal(typTup->typrelid, newTypeName,
3113 typTup->typnamespace);
3115 RenameTypeInternal(typeOid, newTypeName,
3116 typTup->typnamespace);
3119 heap_close(rel, RowExclusiveLock);
3123 * Change the owner of a type.
3126 AlterTypeOwner(List *names, Oid newOwnerId)
3133 Form_pg_type typTup;
3134 AclResult aclresult;
3136 rel = heap_open(TypeRelationId, RowExclusiveLock);
3138 /* Make a TypeName so we can use standard type lookup machinery */
3139 typename = makeTypeNameFromNameList(names);
3141 /* Use LookupTypeName here so that shell types can be processed */
3142 tup = LookupTypeName(NULL, typename, NULL);
3145 (errcode(ERRCODE_UNDEFINED_OBJECT),
3146 errmsg("type \"%s\" does not exist",
3147 TypeNameToString(typename))));
3148 typeOid = typeTypeId(tup);
3150 /* Copy the syscache entry so we can scribble on it below */
3151 newtup = heap_copytuple(tup);
3152 ReleaseSysCache(tup);
3154 typTup = (Form_pg_type) GETSTRUCT(tup);
3157 * If it's a composite type, we need to check that it really is a
3158 * free-standing composite type, and not a table's rowtype. We want people
3159 * to use ALTER TABLE not ALTER TYPE for that case.
3161 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3162 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3164 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3165 errmsg("%s is a table's row type",
3166 format_type_be(typeOid)),
3167 errhint("Use ALTER TABLE instead.")));
3169 /* don't allow direct alteration of array types, either */
3170 if (OidIsValid(typTup->typelem) &&
3171 get_array_type(typTup->typelem) == typeOid)
3173 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3174 errmsg("cannot alter array type %s",
3175 format_type_be(typeOid)),
3176 errhint("You can alter type %s, which will alter the array type as well.",
3177 format_type_be(typTup->typelem))));
3180 * If the new owner is the same as the existing owner, consider the
3181 * command to have succeeded. This is for dump restoration purposes.
3183 if (typTup->typowner != newOwnerId)
3185 /* Superusers can always do it */
3188 /* Otherwise, must be owner of the existing object */
3189 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
3190 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
3191 format_type_be(HeapTupleGetOid(tup)));
3193 /* Must be able to become new owner */
3194 check_is_member_of_role(GetUserId(), newOwnerId);
3196 /* New owner must have CREATE privilege on namespace */
3197 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3200 if (aclresult != ACLCHECK_OK)
3201 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
3202 get_namespace_name(typTup->typnamespace));
3206 * If it's a composite type, invoke ATExecChangeOwner so that we fix
3207 * up the pg_class entry properly. That will call back to
3208 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3210 if (typTup->typtype == TYPTYPE_COMPOSITE)
3211 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3215 * We can just apply the modification directly.
3217 * okay to scribble on typTup because it's a copy
3219 typTup->typowner = newOwnerId;
3221 simple_heap_update(rel, &tup->t_self, tup);
3223 CatalogUpdateIndexes(rel, tup);
3225 /* Update owner dependency reference */
3226 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3228 /* If it has an array type, update that too */
3229 if (OidIsValid(typTup->typarray))
3230 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3235 heap_close(rel, RowExclusiveLock);
3239 * AlterTypeOwnerInternal - change type owner unconditionally
3241 * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
3242 * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
3243 * It assumes the caller has done all needed checks. The function will
3244 * automatically recurse to an array type if the type has one.
3246 * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
3247 * entry (ie, it's not a table rowtype nor an array type).
3250 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
3251 bool hasDependEntry)
3255 Form_pg_type typTup;
3257 rel = heap_open(TypeRelationId, RowExclusiveLock);
3259 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3260 if (!HeapTupleIsValid(tup))
3261 elog(ERROR, "cache lookup failed for type %u", typeOid);
3262 typTup = (Form_pg_type) GETSTRUCT(tup);
3265 * Modify the owner --- okay to scribble on typTup because it's a copy
3267 typTup->typowner = newOwnerId;
3269 simple_heap_update(rel, &tup->t_self, tup);
3271 CatalogUpdateIndexes(rel, tup);
3273 /* Update owner dependency reference, if it has one */
3275 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3277 /* If it has an array type, update that too */
3278 if (OidIsValid(typTup->typarray))
3279 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3282 heap_close(rel, RowExclusiveLock);
3286 * Execute ALTER TYPE SET SCHEMA
3289 AlterTypeNamespace(List *names, const char *newschema)
3295 /* Make a TypeName so we can use standard type lookup machinery */
3296 typename = makeTypeNameFromNameList(names);
3297 typeOid = typenameTypeId(NULL, typename);
3299 /* get schema OID and check its permissions */
3300 nspOid = LookupCreationNamespace(newschema);
3302 AlterTypeNamespace_oid(typeOid, nspOid);
3306 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid)
3310 /* check permissions on type */
3311 if (!pg_type_ownercheck(typeOid, GetUserId()))
3312 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
3313 format_type_be(typeOid));
3315 /* don't allow direct alteration of array types */
3316 elemOid = get_element_type(typeOid);
3317 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3319 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3320 errmsg("cannot alter array type %s",
3321 format_type_be(typeOid)),
3322 errhint("You can alter type %s, which will alter the array type as well.",
3323 format_type_be(elemOid))));
3325 /* and do the work */
3326 return AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
3330 * Move specified type to new namespace.
3332 * Caller must have already checked privileges.
3334 * The function automatically recurses to process the type's array type,
3335 * if any. isImplicitArray should be TRUE only when doing this internal
3336 * recursion (outside callers must never try to move an array type directly).
3338 * If errorOnTableType is TRUE, the function errors out if the type is
3339 * a table type. ALTER TABLE has to be used to move a table to a new
3342 * Returns the type's old namespace OID.
3345 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
3346 bool isImplicitArray,
3347 bool errorOnTableType)
3351 Form_pg_type typform;
3354 bool isCompositeType;
3356 rel = heap_open(TypeRelationId, RowExclusiveLock);
3358 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3359 if (!HeapTupleIsValid(tup))
3360 elog(ERROR, "cache lookup failed for type %u", typeOid);
3361 typform = (Form_pg_type) GETSTRUCT(tup);
3363 oldNspOid = typform->typnamespace;
3364 arrayOid = typform->typarray;
3366 /* common checks on switching namespaces */
3367 CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
3369 /* check for duplicate name (more friendly than unique-index failure) */
3370 if (SearchSysCacheExists2(TYPENAMENSP,
3371 CStringGetDatum(NameStr(typform->typname)),
3372 ObjectIdGetDatum(nspOid)))
3374 (errcode(ERRCODE_DUPLICATE_OBJECT),
3375 errmsg("type \"%s\" already exists in schema \"%s\"",
3376 NameStr(typform->typname),
3377 get_namespace_name(nspOid))));
3379 /* Detect whether type is a composite type (but not a table rowtype) */
3381 (typform->typtype == TYPTYPE_COMPOSITE &&
3382 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3384 /* Enforce not-table-type if requested */
3385 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3388 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3389 errmsg("%s is a table's row type",
3390 format_type_be(typeOid)),
3391 errhint("Use ALTER TABLE instead.")));
3393 /* OK, modify the pg_type row */
3395 /* tup is a copy, so we can scribble directly on it */
3396 typform->typnamespace = nspOid;
3398 simple_heap_update(rel, &tup->t_self, tup);
3399 CatalogUpdateIndexes(rel, tup);
3402 * Composite types have pg_class entries.
3404 * We need to modify the pg_class tuple as well to reflect the change of
3407 if (isCompositeType)
3411 classRel = heap_open(RelationRelationId, RowExclusiveLock);
3413 AlterRelationNamespaceInternal(classRel, typform->typrelid,
3417 heap_close(classRel, RowExclusiveLock);
3420 * Check for constraints associated with the composite type (we don't
3421 * currently support this, but probably will someday).
3423 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3428 /* If it's a domain, it might have constraints */
3429 if (typform->typtype == TYPTYPE_DOMAIN)
3430 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
3434 * Update dependency on schema, if any --- a table rowtype has not got
3435 * one, and neither does an implicit array.
3437 if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3439 if (changeDependencyFor(TypeRelationId, typeOid,
3440 NamespaceRelationId, oldNspOid, nspOid) != 1)
3441 elog(ERROR, "failed to change schema dependency for type %s",
3442 format_type_be(typeOid));
3444 heap_freetuple(tup);
3446 heap_close(rel, RowExclusiveLock);
3448 /* Recursively alter the associated array type, if any */
3449 if (OidIsValid(arrayOid))
3450 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);