Force a checkpoint in CREATE DATABASE before starting to copy the files,
[PostgreSQL.git] / src / backend / commands / typecmds.c
bloba1c009d4a9706af23ddd3cc79c1f8bc1bc307482
1 /*-------------------------------------------------------------------------
3 * typecmds.c
4 * Routines for SQL commands that manipulate types (and domains).
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * $PostgreSQL$
13 * DESCRIPTION
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.
20 * NOTES
21 * These things must be defined and committed in the following order:
22 * "create function":
23 * input/output, recv/send functions
24 * "create type":
25 * type
26 * "create operator":
27 * operators
30 *-------------------------------------------------------------------------
32 #include "postgres.h"
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_constraint.h"
42 #include "catalog/pg_depend.h"
43 #include "catalog/pg_enum.h"
44 #include "catalog/pg_namespace.h"
45 #include "catalog/pg_type.h"
46 #include "catalog/pg_type_fn.h"
47 #include "commands/defrem.h"
48 #include "commands/tablecmds.h"
49 #include "commands/typecmds.h"
50 #include "executor/executor.h"
51 #include "miscadmin.h"
52 #include "nodes/makefuncs.h"
53 #include "optimizer/planmain.h"
54 #include "optimizer/var.h"
55 #include "parser/parse_coerce.h"
56 #include "parser/parse_expr.h"
57 #include "parser/parse_func.h"
58 #include "parser/parse_type.h"
59 #include "utils/acl.h"
60 #include "utils/builtins.h"
61 #include "utils/fmgroids.h"
62 #include "utils/lsyscache.h"
63 #include "utils/memutils.h"
64 #include "utils/syscache.h"
65 #include "utils/tqual.h"
68 /* result structure for get_rels_with_domain() */
69 typedef struct
71 Relation rel; /* opened and locked relation */
72 int natts; /* number of attributes of interest */
73 int *atts; /* attribute numbers */
74 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
75 } RelToCheck;
78 static Oid findTypeInputFunction(List *procname, Oid typeOid);
79 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
80 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
81 static Oid findTypeSendFunction(List *procname, Oid typeOid);
82 static Oid findTypeTypmodinFunction(List *procname);
83 static Oid findTypeTypmodoutFunction(List *procname);
84 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
85 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
86 static void checkDomainOwner(HeapTuple tup, TypeName *typename);
87 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
88 Oid baseTypeOid,
89 int typMod, Constraint *constr,
90 char *domainName);
94 * DefineType
95 * Registers a new base type.
97 void
98 DefineType(List *names, List *parameters)
100 char *typeName;
101 Oid typeNamespace;
102 int16 internalLength = -1; /* default: variable-length */
103 Oid elemType = InvalidOid;
104 List *inputName = NIL;
105 List *outputName = NIL;
106 List *receiveName = NIL;
107 List *sendName = NIL;
108 List *typmodinName = NIL;
109 List *typmodoutName = NIL;
110 List *analyzeName = NIL;
111 char *defaultValue = NULL;
112 bool byValue = false;
113 char category = TYPCATEGORY_USER;
114 bool preferred = false;
115 char delimiter = DEFAULT_TYPDELIM;
116 char alignment = 'i'; /* default alignment */
117 char storage = 'p'; /* default TOAST storage method */
118 Oid inputOid;
119 Oid outputOid;
120 Oid receiveOid = InvalidOid;
121 Oid sendOid = InvalidOid;
122 Oid typmodinOid = InvalidOid;
123 Oid typmodoutOid = InvalidOid;
124 Oid analyzeOid = InvalidOid;
125 char *array_type;
126 Oid array_oid;
127 ListCell *pl;
128 Oid typoid;
129 Oid resulttype;
130 Relation pg_type;
133 * As of Postgres 8.4, we require superuser privilege to create a base
134 * type. This is simple paranoia: there are too many ways to mess up the
135 * system with an incorrect type definition (for instance, representation
136 * parameters that don't match what the C code expects). In practice
137 * it takes superuser privilege to create the I/O functions, and so the
138 * former requirement that you own the I/O functions pretty much forced
139 * superuserness anyway. We're just making doubly sure here.
141 * XXX re-enable NOT_USED code sections below if you remove this test.
143 if (!superuser())
144 ereport(ERROR,
145 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
146 errmsg("must be superuser to create a base type")));
148 /* Convert list of names to a name and namespace */
149 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
151 #ifdef NOT_USED
152 /* XXX this is unnecessary given the superuser check above */
153 /* Check we have creation rights in target namespace */
154 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
155 if (aclresult != ACLCHECK_OK)
156 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
157 get_namespace_name(typeNamespace));
158 #endif
161 * Look to see if type already exists (presumably as a shell; if not,
162 * TypeCreate will complain).
164 typoid = GetSysCacheOid(TYPENAMENSP,
165 CStringGetDatum(typeName),
166 ObjectIdGetDatum(typeNamespace),
167 0, 0);
170 * If it's not a shell, see if it's an autogenerated array type, and if so
171 * rename it out of the way.
173 if (OidIsValid(typoid) && get_typisdefined(typoid))
175 if (moveArrayTypeName(typoid, typeName, typeNamespace))
176 typoid = InvalidOid;
180 * If it doesn't exist, create it as a shell, so that the OID is known for
181 * use in the I/O function definitions.
183 if (!OidIsValid(typoid))
185 typoid = TypeShellMake(typeName, typeNamespace);
186 /* Make new shell type visible for modification below */
187 CommandCounterIncrement();
190 * If the command was a parameterless CREATE TYPE, we're done ---
191 * creating the shell type was all we're supposed to do.
193 if (parameters == NIL)
194 return;
196 else
198 /* Complain if dummy CREATE TYPE and entry already exists */
199 if (parameters == NIL)
200 ereport(ERROR,
201 (errcode(ERRCODE_DUPLICATE_OBJECT),
202 errmsg("type \"%s\" already exists", typeName)));
205 foreach(pl, parameters)
207 DefElem *defel = (DefElem *) lfirst(pl);
209 if (pg_strcasecmp(defel->defname, "internallength") == 0)
210 internalLength = defGetTypeLength(defel);
211 else if (pg_strcasecmp(defel->defname, "input") == 0)
212 inputName = defGetQualifiedName(defel);
213 else if (pg_strcasecmp(defel->defname, "output") == 0)
214 outputName = defGetQualifiedName(defel);
215 else if (pg_strcasecmp(defel->defname, "receive") == 0)
216 receiveName = defGetQualifiedName(defel);
217 else if (pg_strcasecmp(defel->defname, "send") == 0)
218 sendName = defGetQualifiedName(defel);
219 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
220 typmodinName = defGetQualifiedName(defel);
221 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
222 typmodoutName = defGetQualifiedName(defel);
223 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
224 pg_strcasecmp(defel->defname, "analyse") == 0)
225 analyzeName = defGetQualifiedName(defel);
226 else if (pg_strcasecmp(defel->defname, "category") == 0)
228 char *p = defGetString(defel);
230 category = p[0];
231 /* restrict to non-control ASCII */
232 if (category < 32 || category > 126)
233 ereport(ERROR,
234 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
235 errmsg("invalid type category \"%s\": must be simple ASCII",
236 p)));
238 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
239 preferred = defGetBoolean(defel);
240 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
242 char *p = defGetString(defel);
244 delimiter = p[0];
245 /* XXX shouldn't we restrict the delimiter? */
247 else if (pg_strcasecmp(defel->defname, "element") == 0)
249 elemType = typenameTypeId(NULL, defGetTypeName(defel), NULL);
250 /* disallow arrays of pseudotypes */
251 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
252 ereport(ERROR,
253 (errcode(ERRCODE_DATATYPE_MISMATCH),
254 errmsg("array element type cannot be %s",
255 format_type_be(elemType))));
257 else if (pg_strcasecmp(defel->defname, "default") == 0)
258 defaultValue = defGetString(defel);
259 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
260 byValue = defGetBoolean(defel);
261 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
263 char *a = defGetString(defel);
266 * Note: if argument was an unquoted identifier, parser will have
267 * applied translations to it, so be prepared to recognize
268 * translated type names as well as the nominal form.
270 if (pg_strcasecmp(a, "double") == 0 ||
271 pg_strcasecmp(a, "float8") == 0 ||
272 pg_strcasecmp(a, "pg_catalog.float8") == 0)
273 alignment = 'd';
274 else if (pg_strcasecmp(a, "int4") == 0 ||
275 pg_strcasecmp(a, "pg_catalog.int4") == 0)
276 alignment = 'i';
277 else if (pg_strcasecmp(a, "int2") == 0 ||
278 pg_strcasecmp(a, "pg_catalog.int2") == 0)
279 alignment = 's';
280 else if (pg_strcasecmp(a, "char") == 0 ||
281 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
282 alignment = 'c';
283 else
284 ereport(ERROR,
285 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
286 errmsg("alignment \"%s\" not recognized", a)));
288 else if (pg_strcasecmp(defel->defname, "storage") == 0)
290 char *a = defGetString(defel);
292 if (pg_strcasecmp(a, "plain") == 0)
293 storage = 'p';
294 else if (pg_strcasecmp(a, "external") == 0)
295 storage = 'e';
296 else if (pg_strcasecmp(a, "extended") == 0)
297 storage = 'x';
298 else if (pg_strcasecmp(a, "main") == 0)
299 storage = 'm';
300 else
301 ereport(ERROR,
302 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
303 errmsg("storage \"%s\" not recognized", a)));
305 else
306 ereport(WARNING,
307 (errcode(ERRCODE_SYNTAX_ERROR),
308 errmsg("type attribute \"%s\" not recognized",
309 defel->defname)));
313 * make sure we have our required definitions
315 if (inputName == NIL)
316 ereport(ERROR,
317 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
318 errmsg("type input function must be specified")));
319 if (outputName == NIL)
320 ereport(ERROR,
321 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
322 errmsg("type output function must be specified")));
324 if (typmodinName == NIL && typmodoutName != NIL)
325 ereport(ERROR,
326 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
327 errmsg("type modifier output function is useless without a type modifier input function")));
330 * Convert I/O proc names to OIDs
332 inputOid = findTypeInputFunction(inputName, typoid);
333 outputOid = findTypeOutputFunction(outputName, typoid);
334 if (receiveName)
335 receiveOid = findTypeReceiveFunction(receiveName, typoid);
336 if (sendName)
337 sendOid = findTypeSendFunction(sendName, typoid);
340 * Verify that I/O procs return the expected thing. If we see OPAQUE,
341 * complain and change it to the correct type-safe choice.
343 resulttype = get_func_rettype(inputOid);
344 if (resulttype != typoid)
346 if (resulttype == OPAQUEOID)
348 /* backwards-compatibility hack */
349 ereport(WARNING,
350 (errmsg("changing return type of function %s from \"opaque\" to %s",
351 NameListToString(inputName), typeName)));
352 SetFunctionReturnType(inputOid, typoid);
354 else
355 ereport(ERROR,
356 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
357 errmsg("type input function %s must return type %s",
358 NameListToString(inputName), typeName)));
360 resulttype = get_func_rettype(outputOid);
361 if (resulttype != CSTRINGOID)
363 if (resulttype == OPAQUEOID)
365 /* backwards-compatibility hack */
366 ereport(WARNING,
367 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
368 NameListToString(outputName))));
369 SetFunctionReturnType(outputOid, CSTRINGOID);
371 else
372 ereport(ERROR,
373 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
374 errmsg("type output function %s must return type \"cstring\"",
375 NameListToString(outputName))));
377 if (receiveOid)
379 resulttype = get_func_rettype(receiveOid);
380 if (resulttype != typoid)
381 ereport(ERROR,
382 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
383 errmsg("type receive function %s must return type %s",
384 NameListToString(receiveName), typeName)));
386 if (sendOid)
388 resulttype = get_func_rettype(sendOid);
389 if (resulttype != BYTEAOID)
390 ereport(ERROR,
391 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
392 errmsg("type send function %s must return type \"bytea\"",
393 NameListToString(sendName))));
397 * Convert typmodin/out function proc names to OIDs.
399 if (typmodinName)
400 typmodinOid = findTypeTypmodinFunction(typmodinName);
401 if (typmodoutName)
402 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
405 * Convert analysis function proc name to an OID. If no analysis function
406 * is specified, we'll use zero to select the built-in default algorithm.
408 if (analyzeName)
409 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
412 * Check permissions on functions. We choose to require the creator/owner
413 * of a type to also own the underlying functions. Since creating a type
414 * is tantamount to granting public execute access on the functions, the
415 * minimum sane check would be for execute-with-grant-option. But we
416 * don't have a way to make the type go away if the grant option is
417 * revoked, so ownership seems better.
419 #ifdef NOT_USED
420 /* XXX this is unnecessary given the superuser check above */
421 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
422 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
423 NameListToString(inputName));
424 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
425 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
426 NameListToString(outputName));
427 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
428 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
429 NameListToString(receiveName));
430 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
431 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
432 NameListToString(sendName));
433 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
434 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
435 NameListToString(typmodinName));
436 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
437 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
438 NameListToString(typmodoutName));
439 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
440 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
441 NameListToString(analyzeName));
442 #endif
444 /* Preassign array type OID so we can insert it in pg_type.typarray */
445 pg_type = heap_open(TypeRelationId, AccessShareLock);
446 array_oid = GetNewOid(pg_type);
447 heap_close(pg_type, AccessShareLock);
450 * now have TypeCreate do all the real work.
452 typoid =
453 TypeCreate(InvalidOid, /* no predetermined type OID */
454 typeName, /* type name */
455 typeNamespace, /* namespace */
456 InvalidOid, /* relation oid (n/a here) */
457 0, /* relation kind (ditto) */
458 internalLength, /* internal size */
459 TYPTYPE_BASE, /* type-type (base type) */
460 category, /* type-category */
461 preferred, /* is it a preferred type? */
462 delimiter, /* array element delimiter */
463 inputOid, /* input procedure */
464 outputOid, /* output procedure */
465 receiveOid, /* receive procedure */
466 sendOid, /* send procedure */
467 typmodinOid, /* typmodin procedure */
468 typmodoutOid, /* typmodout procedure */
469 analyzeOid, /* analyze procedure */
470 elemType, /* element type ID */
471 false, /* this is not an array type */
472 array_oid, /* array type we are about to create */
473 InvalidOid, /* base type ID (only for domains) */
474 defaultValue, /* default type value */
475 NULL, /* no binary form available */
476 byValue, /* passed by value */
477 alignment, /* required alignment */
478 storage, /* TOAST strategy */
479 -1, /* typMod (Domains only) */
480 0, /* Array Dimensions of typbasetype */
481 false); /* Type NOT NULL */
484 * Create the array type that goes with it.
486 array_type = makeArrayTypeName(typeName, typeNamespace);
488 /* alignment must be 'i' or 'd' for arrays */
489 alignment = (alignment == 'd') ? 'd' : 'i';
491 TypeCreate(array_oid, /* force assignment of this type OID */
492 array_type, /* type name */
493 typeNamespace, /* namespace */
494 InvalidOid, /* relation oid (n/a here) */
495 0, /* relation kind (ditto) */
496 -1, /* internal size (always varlena) */
497 TYPTYPE_BASE, /* type-type (base type) */
498 TYPCATEGORY_ARRAY, /* type-category (array) */
499 false, /* array types are never preferred */
500 delimiter, /* array element delimiter */
501 F_ARRAY_IN, /* input procedure */
502 F_ARRAY_OUT, /* output procedure */
503 F_ARRAY_RECV, /* receive procedure */
504 F_ARRAY_SEND, /* send procedure */
505 typmodinOid, /* typmodin procedure */
506 typmodoutOid, /* typmodout procedure */
507 InvalidOid, /* analyze procedure - default */
508 typoid, /* element type ID */
509 true, /* yes this is an array type */
510 InvalidOid, /* no further array type */
511 InvalidOid, /* base type ID */
512 NULL, /* never a default type value */
513 NULL, /* binary default isn't sent either */
514 false, /* never passed by value */
515 alignment, /* see above */
516 'x', /* ARRAY is always toastable */
517 -1, /* typMod (Domains only) */
518 0, /* Array dimensions of typbasetype */
519 false); /* Type NOT NULL */
521 pfree(array_type);
526 * RemoveTypes
527 * Implements DROP TYPE and DROP DOMAIN
529 * Note: if DOMAIN is specified, we enforce that each type is a domain, but
530 * we don't enforce the converse for DROP TYPE
532 void
533 RemoveTypes(DropStmt *drop)
535 ObjectAddresses *objects;
536 ListCell *cell;
539 * First we identify all the types, then we delete them in a single
540 * performMultipleDeletions() call. This is to avoid unwanted
541 * DROP RESTRICT errors if one of the types depends on another.
543 objects = new_object_addresses();
545 foreach(cell, drop->objects)
547 List *names = (List *) lfirst(cell);
548 TypeName *typename;
549 Oid typeoid;
550 HeapTuple tup;
551 ObjectAddress object;
552 Form_pg_type typ;
554 /* Make a TypeName so we can use standard type lookup machinery */
555 typename = makeTypeNameFromNameList(names);
557 /* Use LookupTypeName here so that shell types can be removed. */
558 tup = LookupTypeName(NULL, typename, NULL);
559 if (tup == NULL)
561 if (!drop->missing_ok)
563 ereport(ERROR,
564 (errcode(ERRCODE_UNDEFINED_OBJECT),
565 errmsg("type \"%s\" does not exist",
566 TypeNameToString(typename))));
568 else
570 ereport(NOTICE,
571 (errmsg("type \"%s\" does not exist, skipping",
572 TypeNameToString(typename))));
574 continue;
577 typeoid = typeTypeId(tup);
578 typ = (Form_pg_type) GETSTRUCT(tup);
580 /* Permission check: must own type or its namespace */
581 if (!pg_type_ownercheck(typeoid, GetUserId()) &&
582 !pg_namespace_ownercheck(typ->typnamespace, GetUserId()))
583 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
584 TypeNameToString(typename));
586 if (drop->removeType == OBJECT_DOMAIN)
588 /* Check that this is actually a domain */
589 if (typ->typtype != TYPTYPE_DOMAIN)
590 ereport(ERROR,
591 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
592 errmsg("\"%s\" is not a domain",
593 TypeNameToString(typename))));
597 * Note: we need no special check for array types here, as the normal
598 * treatment of internal dependencies handles it just fine
601 object.classId = TypeRelationId;
602 object.objectId = typeoid;
603 object.objectSubId = 0;
605 add_exact_object_address(&object, objects);
607 ReleaseSysCache(tup);
610 performMultipleDeletions(objects, drop->behavior);
612 free_object_addresses(objects);
617 * Guts of type deletion.
619 void
620 RemoveTypeById(Oid typeOid)
622 Relation relation;
623 HeapTuple tup;
625 relation = heap_open(TypeRelationId, RowExclusiveLock);
627 tup = SearchSysCache(TYPEOID,
628 ObjectIdGetDatum(typeOid),
629 0, 0, 0);
630 if (!HeapTupleIsValid(tup))
631 elog(ERROR, "cache lookup failed for type %u", typeOid);
633 simple_heap_delete(relation, &tup->t_self);
636 * If it is an enum, delete the pg_enum entries too; we don't bother with
637 * making dependency entries for those, so it has to be done "by hand"
638 * here.
640 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
641 EnumValuesDelete(typeOid);
643 ReleaseSysCache(tup);
645 heap_close(relation, RowExclusiveLock);
650 * DefineDomain
651 * Registers a new domain.
653 void
654 DefineDomain(CreateDomainStmt *stmt)
656 char *domainName;
657 Oid domainNamespace;
658 AclResult aclresult;
659 int16 internalLength;
660 Oid inputProcedure;
661 Oid outputProcedure;
662 Oid receiveProcedure;
663 Oid sendProcedure;
664 Oid analyzeProcedure;
665 bool byValue;
666 Oid typelem;
667 char category;
668 char delimiter;
669 char alignment;
670 char storage;
671 char typtype;
672 Datum datum;
673 bool isnull;
674 char *defaultValue = NULL;
675 char *defaultValueBin = NULL;
676 bool saw_default = false;
677 bool typNotNull = false;
678 bool nullDefined = false;
679 int32 typNDims = list_length(stmt->typename->arrayBounds);
680 HeapTuple typeTup;
681 List *schema = stmt->constraints;
682 ListCell *listptr;
683 Oid basetypeoid;
684 Oid domainoid;
685 Oid old_type_oid;
686 Form_pg_type baseType;
687 int32 basetypeMod;
689 /* Convert list of names to a name and namespace */
690 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
691 &domainName);
693 /* Check we have creation rights in target namespace */
694 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
695 ACL_CREATE);
696 if (aclresult != ACLCHECK_OK)
697 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
698 get_namespace_name(domainNamespace));
701 * Check for collision with an existing type name. If there is one and
702 * it's an autogenerated array, we can rename it out of the way.
704 old_type_oid = GetSysCacheOid(TYPENAMENSP,
705 CStringGetDatum(domainName),
706 ObjectIdGetDatum(domainNamespace),
707 0, 0);
708 if (OidIsValid(old_type_oid))
710 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
711 ereport(ERROR,
712 (errcode(ERRCODE_DUPLICATE_OBJECT),
713 errmsg("type \"%s\" already exists", domainName)));
717 * Look up the base type.
719 typeTup = typenameType(NULL, stmt->typename, &basetypeMod);
720 baseType = (Form_pg_type) GETSTRUCT(typeTup);
721 basetypeoid = HeapTupleGetOid(typeTup);
724 * Base type must be a plain base type, another domain or an enum. Domains
725 * over pseudotypes would create a security hole. Domains over composite
726 * types might be made to work in the future, but not today.
728 typtype = baseType->typtype;
729 if (typtype != TYPTYPE_BASE &&
730 typtype != TYPTYPE_DOMAIN &&
731 typtype != TYPTYPE_ENUM)
732 ereport(ERROR,
733 (errcode(ERRCODE_DATATYPE_MISMATCH),
734 errmsg("\"%s\" is not a valid base type for a domain",
735 TypeNameToString(stmt->typename))));
737 /* passed by value */
738 byValue = baseType->typbyval;
740 /* Required Alignment */
741 alignment = baseType->typalign;
743 /* TOAST Strategy */
744 storage = baseType->typstorage;
746 /* Storage Length */
747 internalLength = baseType->typlen;
749 /* Type Category */
750 category = baseType->typcategory;
752 /* Array element type (in case base type is an array) */
753 typelem = baseType->typelem;
755 /* Array element Delimiter */
756 delimiter = baseType->typdelim;
758 /* I/O Functions */
759 inputProcedure = F_DOMAIN_IN;
760 outputProcedure = baseType->typoutput;
761 receiveProcedure = F_DOMAIN_RECV;
762 sendProcedure = baseType->typsend;
764 /* Domains never accept typmods, so no typmodin/typmodout needed */
766 /* Analysis function */
767 analyzeProcedure = baseType->typanalyze;
769 /* Inherited default value */
770 datum = SysCacheGetAttr(TYPEOID, typeTup,
771 Anum_pg_type_typdefault, &isnull);
772 if (!isnull)
773 defaultValue = TextDatumGetCString(datum);
775 /* Inherited default binary value */
776 datum = SysCacheGetAttr(TYPEOID, typeTup,
777 Anum_pg_type_typdefaultbin, &isnull);
778 if (!isnull)
779 defaultValueBin = TextDatumGetCString(datum);
782 * Run through constraints manually to avoid the additional processing
783 * conducted by DefineRelation() and friends.
785 foreach(listptr, schema)
787 Node *newConstraint = lfirst(listptr);
788 Constraint *constr;
790 /* Check for unsupported constraint types */
791 if (IsA(newConstraint, FkConstraint))
792 ereport(ERROR,
793 (errcode(ERRCODE_SYNTAX_ERROR),
794 errmsg("foreign key constraints not possible for domains")));
796 /* otherwise it should be a plain Constraint */
797 if (!IsA(newConstraint, Constraint))
798 elog(ERROR, "unrecognized node type: %d",
799 (int) nodeTag(newConstraint));
801 constr = (Constraint *) newConstraint;
803 switch (constr->contype)
805 case CONSTR_DEFAULT:
808 * The inherited default value may be overridden by the user
809 * with the DEFAULT <expr> clause ... but only once.
811 if (saw_default)
812 ereport(ERROR,
813 (errcode(ERRCODE_SYNTAX_ERROR),
814 errmsg("multiple default expressions")));
815 saw_default = true;
817 if (constr->raw_expr)
819 ParseState *pstate;
820 Node *defaultExpr;
822 /* Create a dummy ParseState for transformExpr */
823 pstate = make_parsestate(NULL);
826 * Cook the constr->raw_expr into an expression. Note:
827 * name is strictly for error message
829 defaultExpr = cookDefault(pstate, constr->raw_expr,
830 basetypeoid,
831 basetypeMod,
832 domainName);
835 * If the expression is just a NULL constant, we treat it
836 * like not having a default.
838 * Note that if the basetype is another domain, we'll see
839 * a CoerceToDomain expr here and not discard the default.
840 * This is critical because the domain default needs to be
841 * retained to override any default that the base domain
842 * might have.
844 if (defaultExpr == NULL ||
845 (IsA(defaultExpr, Const) &&
846 ((Const *) defaultExpr)->constisnull))
848 defaultValue = NULL;
849 defaultValueBin = NULL;
851 else
854 * Expression must be stored as a nodeToString result,
855 * but we also require a valid textual representation
856 * (mainly to make life easier for pg_dump).
858 defaultValue =
859 deparse_expression(defaultExpr,
860 deparse_context_for(domainName,
861 InvalidOid),
862 false, false);
863 defaultValueBin = nodeToString(defaultExpr);
866 else
868 /* No default (can this still happen?) */
869 defaultValue = NULL;
870 defaultValueBin = NULL;
872 break;
874 case CONSTR_NOTNULL:
875 if (nullDefined && !typNotNull)
876 ereport(ERROR,
877 (errcode(ERRCODE_SYNTAX_ERROR),
878 errmsg("conflicting NULL/NOT NULL constraints")));
879 typNotNull = true;
880 nullDefined = true;
881 break;
883 case CONSTR_NULL:
884 if (nullDefined && typNotNull)
885 ereport(ERROR,
886 (errcode(ERRCODE_SYNTAX_ERROR),
887 errmsg("conflicting NULL/NOT NULL constraints")));
888 typNotNull = false;
889 nullDefined = true;
890 break;
892 case CONSTR_CHECK:
895 * Check constraints are handled after domain creation, as
896 * they require the Oid of the domain
898 break;
901 * All else are error cases
903 case CONSTR_UNIQUE:
904 ereport(ERROR,
905 (errcode(ERRCODE_SYNTAX_ERROR),
906 errmsg("unique constraints not possible for domains")));
907 break;
909 case CONSTR_PRIMARY:
910 ereport(ERROR,
911 (errcode(ERRCODE_SYNTAX_ERROR),
912 errmsg("primary key constraints not possible for domains")));
913 break;
915 case CONSTR_ATTR_DEFERRABLE:
916 case CONSTR_ATTR_NOT_DEFERRABLE:
917 case CONSTR_ATTR_DEFERRED:
918 case CONSTR_ATTR_IMMEDIATE:
919 ereport(ERROR,
920 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
921 errmsg("specifying constraint deferrability not supported for domains")));
922 break;
924 default:
925 elog(ERROR, "unrecognized constraint subtype: %d",
926 (int) constr->contype);
927 break;
932 * Have TypeCreate do all the real work.
934 domainoid =
935 TypeCreate(InvalidOid, /* no predetermined type OID */
936 domainName, /* type name */
937 domainNamespace, /* namespace */
938 InvalidOid, /* relation oid (n/a here) */
939 0, /* relation kind (ditto) */
940 internalLength, /* internal size */
941 TYPTYPE_DOMAIN, /* type-type (domain type) */
942 category, /* type-category */
943 false, /* domain types are never preferred */
944 delimiter, /* array element delimiter */
945 inputProcedure, /* input procedure */
946 outputProcedure, /* output procedure */
947 receiveProcedure, /* receive procedure */
948 sendProcedure, /* send procedure */
949 InvalidOid, /* typmodin procedure - none */
950 InvalidOid, /* typmodout procedure - none */
951 analyzeProcedure, /* analyze procedure */
952 typelem, /* element type ID */
953 false, /* this isn't an array */
954 InvalidOid, /* no arrays for domains (yet) */
955 basetypeoid, /* base type ID */
956 defaultValue, /* default type value (text) */
957 defaultValueBin, /* default type value (binary) */
958 byValue, /* passed by value */
959 alignment, /* required alignment */
960 storage, /* TOAST strategy */
961 basetypeMod, /* typeMod value */
962 typNDims, /* Array dimensions for base type */
963 typNotNull); /* Type NOT NULL */
966 * Process constraints which refer to the domain ID returned by TypeCreate
968 foreach(listptr, schema)
970 Constraint *constr = lfirst(listptr);
972 /* it must be a Constraint, per check above */
974 switch (constr->contype)
976 case CONSTR_CHECK:
977 domainAddConstraint(domainoid, domainNamespace,
978 basetypeoid, basetypeMod,
979 constr, domainName);
980 break;
982 /* Other constraint types were fully processed above */
984 default:
985 break;
988 /* CCI so we can detect duplicate constraint names */
989 CommandCounterIncrement();
993 * Now we can clean up.
995 ReleaseSysCache(typeTup);
1000 * DefineEnum
1001 * Registers a new enum.
1003 void
1004 DefineEnum(CreateEnumStmt *stmt)
1006 char *enumName;
1007 char *enumArrayName;
1008 Oid enumNamespace;
1009 Oid enumTypeOid;
1010 AclResult aclresult;
1011 Oid old_type_oid;
1012 Oid enumArrayOid;
1013 Relation pg_type;
1015 /* Convert list of names to a name and namespace */
1016 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typename,
1017 &enumName);
1019 /* Check we have creation rights in target namespace */
1020 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1021 if (aclresult != ACLCHECK_OK)
1022 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1023 get_namespace_name(enumNamespace));
1026 * Check for collision with an existing type name. If there is one and
1027 * it's an autogenerated array, we can rename it out of the way.
1029 old_type_oid = GetSysCacheOid(TYPENAMENSP,
1030 CStringGetDatum(enumName),
1031 ObjectIdGetDatum(enumNamespace),
1032 0, 0);
1033 if (OidIsValid(old_type_oid))
1035 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1036 ereport(ERROR,
1037 (errcode(ERRCODE_DUPLICATE_OBJECT),
1038 errmsg("type \"%s\" already exists", enumName)));
1041 /* Preassign array type OID so we can insert it in pg_type.typarray */
1042 pg_type = heap_open(TypeRelationId, AccessShareLock);
1043 enumArrayOid = GetNewOid(pg_type);
1044 heap_close(pg_type, AccessShareLock);
1046 /* Create the pg_type entry */
1047 enumTypeOid =
1048 TypeCreate(InvalidOid, /* no predetermined type OID */
1049 enumName, /* type name */
1050 enumNamespace, /* namespace */
1051 InvalidOid, /* relation oid (n/a here) */
1052 0, /* relation kind (ditto) */
1053 sizeof(Oid), /* internal size */
1054 TYPTYPE_ENUM, /* type-type (enum type) */
1055 TYPCATEGORY_ENUM, /* type-category (enum type) */
1056 false, /* enum types are never preferred */
1057 DEFAULT_TYPDELIM, /* array element delimiter */
1058 F_ENUM_IN, /* input procedure */
1059 F_ENUM_OUT, /* output procedure */
1060 F_ENUM_RECV, /* receive procedure */
1061 F_ENUM_SEND, /* send procedure */
1062 InvalidOid, /* typmodin procedure - none */
1063 InvalidOid, /* typmodout procedure - none */
1064 InvalidOid, /* analyze procedure - default */
1065 InvalidOid, /* element type ID */
1066 false, /* this is not an array type */
1067 enumArrayOid, /* array type we are about to create */
1068 InvalidOid, /* base type ID (only for domains) */
1069 NULL, /* never a default type value */
1070 NULL, /* binary default isn't sent either */
1071 true, /* always passed by value */
1072 'i', /* int alignment */
1073 'p', /* TOAST strategy always plain */
1074 -1, /* typMod (Domains only) */
1075 0, /* Array dimensions of typbasetype */
1076 false); /* Type NOT NULL */
1078 /* Enter the enum's values into pg_enum */
1079 EnumValuesCreate(enumTypeOid, stmt->vals);
1082 * Create the array type that goes with it.
1084 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1086 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1087 enumArrayName, /* type name */
1088 enumNamespace, /* namespace */
1089 InvalidOid, /* relation oid (n/a here) */
1090 0, /* relation kind (ditto) */
1091 -1, /* internal size (always varlena) */
1092 TYPTYPE_BASE, /* type-type (base type) */
1093 TYPCATEGORY_ARRAY, /* type-category (array) */
1094 false, /* array types are never preferred */
1095 DEFAULT_TYPDELIM, /* array element delimiter */
1096 F_ARRAY_IN, /* input procedure */
1097 F_ARRAY_OUT, /* output procedure */
1098 F_ARRAY_RECV, /* receive procedure */
1099 F_ARRAY_SEND, /* send procedure */
1100 InvalidOid, /* typmodin procedure - none */
1101 InvalidOid, /* typmodout procedure - none */
1102 InvalidOid, /* analyze procedure - default */
1103 enumTypeOid, /* element type ID */
1104 true, /* yes this is an array type */
1105 InvalidOid, /* no further array type */
1106 InvalidOid, /* base type ID */
1107 NULL, /* never a default type value */
1108 NULL, /* binary default isn't sent either */
1109 false, /* never passed by value */
1110 'i', /* enums have align i, so do their arrays */
1111 'x', /* ARRAY is always toastable */
1112 -1, /* typMod (Domains only) */
1113 0, /* Array dimensions of typbasetype */
1114 false); /* Type NOT NULL */
1116 pfree(enumArrayName);
1121 * Find suitable I/O functions for a type.
1123 * typeOid is the type's OID (which will already exist, if only as a shell
1124 * type).
1127 static Oid
1128 findTypeInputFunction(List *procname, Oid typeOid)
1130 Oid argList[3];
1131 Oid procOid;
1134 * Input functions can take a single argument of type CSTRING, or three
1135 * arguments (string, typioparam OID, typmod).
1137 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1138 * see this, we issue a warning and fix up the pg_proc entry.
1140 argList[0] = CSTRINGOID;
1142 procOid = LookupFuncName(procname, 1, argList, true);
1143 if (OidIsValid(procOid))
1144 return procOid;
1146 argList[1] = OIDOID;
1147 argList[2] = INT4OID;
1149 procOid = LookupFuncName(procname, 3, argList, true);
1150 if (OidIsValid(procOid))
1151 return procOid;
1153 /* No luck, try it with OPAQUE */
1154 argList[0] = OPAQUEOID;
1156 procOid = LookupFuncName(procname, 1, argList, true);
1158 if (!OidIsValid(procOid))
1160 argList[1] = OIDOID;
1161 argList[2] = INT4OID;
1163 procOid = LookupFuncName(procname, 3, argList, true);
1166 if (OidIsValid(procOid))
1168 /* Found, but must complain and fix the pg_proc entry */
1169 ereport(WARNING,
1170 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1171 NameListToString(procname))));
1172 SetFunctionArgType(procOid, 0, CSTRINGOID);
1175 * Need CommandCounterIncrement since DefineType will likely try to
1176 * alter the pg_proc tuple again.
1178 CommandCounterIncrement();
1180 return procOid;
1183 /* Use CSTRING (preferred) in the error message */
1184 argList[0] = CSTRINGOID;
1186 ereport(ERROR,
1187 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1188 errmsg("function %s does not exist",
1189 func_signature_string(procname, 1, argList))));
1191 return InvalidOid; /* keep compiler quiet */
1194 static Oid
1195 findTypeOutputFunction(List *procname, Oid typeOid)
1197 Oid argList[1];
1198 Oid procOid;
1201 * Output functions can take a single argument of the type.
1203 * For backwards compatibility we allow OPAQUE in place of the actual type
1204 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1206 argList[0] = typeOid;
1208 procOid = LookupFuncName(procname, 1, argList, true);
1209 if (OidIsValid(procOid))
1210 return procOid;
1212 /* No luck, try it with OPAQUE */
1213 argList[0] = OPAQUEOID;
1215 procOid = LookupFuncName(procname, 1, argList, true);
1217 if (OidIsValid(procOid))
1219 /* Found, but must complain and fix the pg_proc entry */
1220 ereport(WARNING,
1221 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1222 NameListToString(procname), format_type_be(typeOid))));
1223 SetFunctionArgType(procOid, 0, typeOid);
1226 * Need CommandCounterIncrement since DefineType will likely try to
1227 * alter the pg_proc tuple again.
1229 CommandCounterIncrement();
1231 return procOid;
1234 /* Use type name, not OPAQUE, in the failure message. */
1235 argList[0] = typeOid;
1237 ereport(ERROR,
1238 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1239 errmsg("function %s does not exist",
1240 func_signature_string(procname, 1, argList))));
1242 return InvalidOid; /* keep compiler quiet */
1245 static Oid
1246 findTypeReceiveFunction(List *procname, Oid typeOid)
1248 Oid argList[3];
1249 Oid procOid;
1252 * Receive functions can take a single argument of type INTERNAL, or three
1253 * arguments (internal, typioparam OID, typmod).
1255 argList[0] = INTERNALOID;
1257 procOid = LookupFuncName(procname, 1, argList, true);
1258 if (OidIsValid(procOid))
1259 return procOid;
1261 argList[1] = OIDOID;
1262 argList[2] = INT4OID;
1264 procOid = LookupFuncName(procname, 3, argList, true);
1265 if (OidIsValid(procOid))
1266 return procOid;
1268 ereport(ERROR,
1269 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1270 errmsg("function %s does not exist",
1271 func_signature_string(procname, 1, argList))));
1273 return InvalidOid; /* keep compiler quiet */
1276 static Oid
1277 findTypeSendFunction(List *procname, Oid typeOid)
1279 Oid argList[1];
1280 Oid procOid;
1283 * Send functions can take a single argument of the type.
1285 argList[0] = typeOid;
1287 procOid = LookupFuncName(procname, 1, argList, true);
1288 if (OidIsValid(procOid))
1289 return procOid;
1291 ereport(ERROR,
1292 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1293 errmsg("function %s does not exist",
1294 func_signature_string(procname, 1, argList))));
1296 return InvalidOid; /* keep compiler quiet */
1299 static Oid
1300 findTypeTypmodinFunction(List *procname)
1302 Oid argList[1];
1303 Oid procOid;
1306 * typmodin functions always take one cstring[] argument and return int4.
1308 argList[0] = CSTRINGARRAYOID;
1310 procOid = LookupFuncName(procname, 1, argList, true);
1311 if (!OidIsValid(procOid))
1312 ereport(ERROR,
1313 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1314 errmsg("function %s does not exist",
1315 func_signature_string(procname, 1, argList))));
1317 if (get_func_rettype(procOid) != INT4OID)
1318 ereport(ERROR,
1319 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1320 errmsg("typmod_in function %s must return type \"integer\"",
1321 NameListToString(procname))));
1323 return procOid;
1326 static Oid
1327 findTypeTypmodoutFunction(List *procname)
1329 Oid argList[1];
1330 Oid procOid;
1333 * typmodout functions always take one int4 argument and return cstring.
1335 argList[0] = INT4OID;
1337 procOid = LookupFuncName(procname, 1, argList, true);
1338 if (!OidIsValid(procOid))
1339 ereport(ERROR,
1340 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1341 errmsg("function %s does not exist",
1342 func_signature_string(procname, 1, argList))));
1344 if (get_func_rettype(procOid) != CSTRINGOID)
1345 ereport(ERROR,
1346 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1347 errmsg("typmod_out function %s must return type \"cstring\"",
1348 NameListToString(procname))));
1350 return procOid;
1353 static Oid
1354 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1356 Oid argList[1];
1357 Oid procOid;
1360 * Analyze functions always take one INTERNAL argument and return bool.
1362 argList[0] = INTERNALOID;
1364 procOid = LookupFuncName(procname, 1, argList, true);
1365 if (!OidIsValid(procOid))
1366 ereport(ERROR,
1367 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1368 errmsg("function %s does not exist",
1369 func_signature_string(procname, 1, argList))));
1371 if (get_func_rettype(procOid) != BOOLOID)
1372 ereport(ERROR,
1373 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1374 errmsg("type analyze function %s must return type \"boolean\"",
1375 NameListToString(procname))));
1377 return procOid;
1381 /*-------------------------------------------------------------------
1382 * DefineCompositeType
1384 * Create a Composite Type relation.
1385 * `DefineRelation' does all the work, we just provide the correct
1386 * arguments!
1388 * If the relation already exists, then 'DefineRelation' will abort
1389 * the xact...
1391 * DefineCompositeType returns relid for use when creating
1392 * an implicit composite type during function creation
1393 *-------------------------------------------------------------------
1396 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1398 CreateStmt *createStmt = makeNode(CreateStmt);
1400 if (coldeflist == NIL)
1401 ereport(ERROR,
1402 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1403 errmsg("composite type must have at least one attribute")));
1406 * now set the parameters for keys/inheritance etc. All of these are
1407 * uninteresting for composite types...
1409 createStmt->relation = (RangeVar *) typevar;
1410 createStmt->tableElts = coldeflist;
1411 createStmt->inhRelations = NIL;
1412 createStmt->constraints = NIL;
1413 createStmt->options = list_make1(defWithOids(false));
1414 createStmt->oncommit = ONCOMMIT_NOOP;
1415 createStmt->tablespacename = NULL;
1418 * finally create the relation...
1420 return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);
1424 * AlterDomainDefault
1426 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
1428 void
1429 AlterDomainDefault(List *names, Node *defaultRaw)
1431 TypeName *typename;
1432 Oid domainoid;
1433 HeapTuple tup;
1434 ParseState *pstate;
1435 Relation rel;
1436 char *defaultValue;
1437 Node *defaultExpr = NULL; /* NULL if no default specified */
1438 Datum new_record[Natts_pg_type];
1439 char new_record_nulls[Natts_pg_type];
1440 char new_record_repl[Natts_pg_type];
1441 HeapTuple newtuple;
1442 Form_pg_type typTup;
1444 /* Make a TypeName so we can use standard type lookup machinery */
1445 typename = makeTypeNameFromNameList(names);
1446 domainoid = typenameTypeId(NULL, typename, NULL);
1448 /* Look up the domain in the type table */
1449 rel = heap_open(TypeRelationId, RowExclusiveLock);
1451 tup = SearchSysCacheCopy(TYPEOID,
1452 ObjectIdGetDatum(domainoid),
1453 0, 0, 0);
1454 if (!HeapTupleIsValid(tup))
1455 elog(ERROR, "cache lookup failed for type %u", domainoid);
1456 typTup = (Form_pg_type) GETSTRUCT(tup);
1458 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1459 checkDomainOwner(tup, typename);
1461 /* Setup new tuple */
1462 MemSet(new_record, (Datum) 0, sizeof(new_record));
1463 MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
1464 MemSet(new_record_repl, ' ', sizeof(new_record_repl));
1466 /* Store the new default into the tuple */
1467 if (defaultRaw)
1469 /* Create a dummy ParseState for transformExpr */
1470 pstate = make_parsestate(NULL);
1473 * Cook the colDef->raw_expr into an expression. Note: Name is
1474 * strictly for error message
1476 defaultExpr = cookDefault(pstate, defaultRaw,
1477 typTup->typbasetype,
1478 typTup->typtypmod,
1479 NameStr(typTup->typname));
1482 * If the expression is just a NULL constant, we treat the command
1483 * like ALTER ... DROP DEFAULT. (But see note for same test in
1484 * DefineDomain.)
1486 if (defaultExpr == NULL ||
1487 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
1489 /* Default is NULL, drop it */
1490 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = 'n';
1491 new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
1492 new_record_nulls[Anum_pg_type_typdefault - 1] = 'n';
1493 new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
1495 else
1498 * Expression must be stored as a nodeToString result, but we also
1499 * require a valid textual representation (mainly to make life
1500 * easier for pg_dump).
1502 defaultValue = deparse_expression(defaultExpr,
1503 deparse_context_for(NameStr(typTup->typname),
1504 InvalidOid),
1505 false, false);
1508 * Form an updated tuple with the new default and write it back.
1510 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
1512 new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
1513 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
1514 new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
1517 else
1519 /* ALTER ... DROP DEFAULT */
1520 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = 'n';
1521 new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
1522 new_record_nulls[Anum_pg_type_typdefault - 1] = 'n';
1523 new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
1526 newtuple = heap_modifytuple(tup, RelationGetDescr(rel),
1527 new_record, new_record_nulls,
1528 new_record_repl);
1530 simple_heap_update(rel, &tup->t_self, newtuple);
1532 CatalogUpdateIndexes(rel, newtuple);
1534 /* Rebuild dependencies */
1535 GenerateTypeDependencies(typTup->typnamespace,
1536 domainoid,
1537 InvalidOid, /* typrelid is n/a */
1538 0, /* relation kind is n/a */
1539 typTup->typowner,
1540 typTup->typinput,
1541 typTup->typoutput,
1542 typTup->typreceive,
1543 typTup->typsend,
1544 typTup->typmodin,
1545 typTup->typmodout,
1546 typTup->typanalyze,
1547 typTup->typelem,
1548 false, /* a domain isn't an implicit array */
1549 typTup->typbasetype,
1550 defaultExpr,
1551 true); /* Rebuild is true */
1553 /* Clean up */
1554 heap_close(rel, NoLock);
1555 heap_freetuple(newtuple);
1559 * AlterDomainNotNull
1561 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
1563 void
1564 AlterDomainNotNull(List *names, bool notNull)
1566 TypeName *typename;
1567 Oid domainoid;
1568 Relation typrel;
1569 HeapTuple tup;
1570 Form_pg_type typTup;
1572 /* Make a TypeName so we can use standard type lookup machinery */
1573 typename = makeTypeNameFromNameList(names);
1574 domainoid = typenameTypeId(NULL, typename, NULL);
1576 /* Look up the domain in the type table */
1577 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1579 tup = SearchSysCacheCopy(TYPEOID,
1580 ObjectIdGetDatum(domainoid),
1581 0, 0, 0);
1582 if (!HeapTupleIsValid(tup))
1583 elog(ERROR, "cache lookup failed for type %u", domainoid);
1584 typTup = (Form_pg_type) GETSTRUCT(tup);
1586 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1587 checkDomainOwner(tup, typename);
1589 /* Is the domain already set to the desired constraint? */
1590 if (typTup->typnotnull == notNull)
1592 heap_close(typrel, RowExclusiveLock);
1593 return;
1596 /* Adding a NOT NULL constraint requires checking existing columns */
1597 if (notNull)
1599 List *rels;
1600 ListCell *rt;
1602 /* Fetch relation list with attributes based on this domain */
1603 /* ShareLock is sufficient to prevent concurrent data changes */
1605 rels = get_rels_with_domain(domainoid, ShareLock);
1607 foreach(rt, rels)
1609 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1610 Relation testrel = rtc->rel;
1611 TupleDesc tupdesc = RelationGetDescr(testrel);
1612 HeapScanDesc scan;
1613 HeapTuple tuple;
1615 /* Scan all tuples in this relation */
1616 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1617 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1619 int i;
1621 /* Test attributes that are of the domain */
1622 for (i = 0; i < rtc->natts; i++)
1624 int attnum = rtc->atts[i];
1626 if (heap_attisnull(tuple, attnum))
1627 ereport(ERROR,
1628 (errcode(ERRCODE_NOT_NULL_VIOLATION),
1629 errmsg("column \"%s\" of table \"%s\" contains null values",
1630 NameStr(tupdesc->attrs[attnum - 1]->attname),
1631 RelationGetRelationName(testrel))));
1634 heap_endscan(scan);
1636 /* Close each rel after processing, but keep lock */
1637 heap_close(testrel, NoLock);
1642 * Okay to update pg_type row. We can scribble on typTup because it's a
1643 * copy.
1645 typTup->typnotnull = notNull;
1647 simple_heap_update(typrel, &tup->t_self, tup);
1649 CatalogUpdateIndexes(typrel, tup);
1651 /* Clean up */
1652 heap_freetuple(tup);
1653 heap_close(typrel, RowExclusiveLock);
1657 * AlterDomainDropConstraint
1659 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
1661 void
1662 AlterDomainDropConstraint(List *names, const char *constrName,
1663 DropBehavior behavior)
1665 TypeName *typename;
1666 Oid domainoid;
1667 HeapTuple tup;
1668 Relation rel;
1669 Relation conrel;
1670 SysScanDesc conscan;
1671 ScanKeyData key[1];
1672 HeapTuple contup;
1674 /* Make a TypeName so we can use standard type lookup machinery */
1675 typename = makeTypeNameFromNameList(names);
1676 domainoid = typenameTypeId(NULL, typename, NULL);
1678 /* Look up the domain in the type table */
1679 rel = heap_open(TypeRelationId, RowExclusiveLock);
1681 tup = SearchSysCacheCopy(TYPEOID,
1682 ObjectIdGetDatum(domainoid),
1683 0, 0, 0);
1684 if (!HeapTupleIsValid(tup))
1685 elog(ERROR, "cache lookup failed for type %u", domainoid);
1687 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1688 checkDomainOwner(tup, typename);
1690 /* Grab an appropriate lock on the pg_constraint relation */
1691 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
1693 /* Use the index to scan only constraints of the target relation */
1694 ScanKeyInit(&key[0],
1695 Anum_pg_constraint_contypid,
1696 BTEqualStrategyNumber, F_OIDEQ,
1697 ObjectIdGetDatum(HeapTupleGetOid(tup)));
1699 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
1700 SnapshotNow, 1, key);
1703 * Scan over the result set, removing any matching entries.
1705 while ((contup = systable_getnext(conscan)) != NULL)
1707 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
1709 if (strcmp(NameStr(con->conname), constrName) == 0)
1711 ObjectAddress conobj;
1713 conobj.classId = ConstraintRelationId;
1714 conobj.objectId = HeapTupleGetOid(contup);
1715 conobj.objectSubId = 0;
1717 performDeletion(&conobj, behavior);
1720 /* Clean up after the scan */
1721 systable_endscan(conscan);
1722 heap_close(conrel, RowExclusiveLock);
1724 heap_close(rel, NoLock);
1728 * AlterDomainAddConstraint
1730 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
1732 void
1733 AlterDomainAddConstraint(List *names, Node *newConstraint)
1735 TypeName *typename;
1736 Oid domainoid;
1737 Relation typrel;
1738 HeapTuple tup;
1739 Form_pg_type typTup;
1740 List *rels;
1741 ListCell *rt;
1742 EState *estate;
1743 ExprContext *econtext;
1744 char *ccbin;
1745 Expr *expr;
1746 ExprState *exprstate;
1747 Constraint *constr;
1749 /* Make a TypeName so we can use standard type lookup machinery */
1750 typename = makeTypeNameFromNameList(names);
1751 domainoid = typenameTypeId(NULL, typename, NULL);
1753 /* Look up the domain in the type table */
1754 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1756 tup = SearchSysCacheCopy(TYPEOID,
1757 ObjectIdGetDatum(domainoid),
1758 0, 0, 0);
1759 if (!HeapTupleIsValid(tup))
1760 elog(ERROR, "cache lookup failed for type %u", domainoid);
1761 typTup = (Form_pg_type) GETSTRUCT(tup);
1763 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1764 checkDomainOwner(tup, typename);
1766 /* Check for unsupported constraint types */
1767 if (IsA(newConstraint, FkConstraint))
1768 ereport(ERROR,
1769 (errcode(ERRCODE_SYNTAX_ERROR),
1770 errmsg("foreign key constraints not possible for domains")));
1772 /* otherwise it should be a plain Constraint */
1773 if (!IsA(newConstraint, Constraint))
1774 elog(ERROR, "unrecognized node type: %d",
1775 (int) nodeTag(newConstraint));
1777 constr = (Constraint *) newConstraint;
1779 switch (constr->contype)
1781 case CONSTR_CHECK:
1782 /* processed below */
1783 break;
1785 case CONSTR_UNIQUE:
1786 ereport(ERROR,
1787 (errcode(ERRCODE_SYNTAX_ERROR),
1788 errmsg("unique constraints not possible for domains")));
1789 break;
1791 case CONSTR_PRIMARY:
1792 ereport(ERROR,
1793 (errcode(ERRCODE_SYNTAX_ERROR),
1794 errmsg("primary key constraints not possible for domains")));
1795 break;
1797 case CONSTR_ATTR_DEFERRABLE:
1798 case CONSTR_ATTR_NOT_DEFERRABLE:
1799 case CONSTR_ATTR_DEFERRED:
1800 case CONSTR_ATTR_IMMEDIATE:
1801 ereport(ERROR,
1802 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1803 errmsg("specifying constraint deferrability not supported for domains")));
1804 break;
1806 default:
1807 elog(ERROR, "unrecognized constraint subtype: %d",
1808 (int) constr->contype);
1809 break;
1813 * Since all other constraint types throw errors, this must be a check
1814 * constraint. First, process the constraint expression and add an entry
1815 * to pg_constraint.
1818 ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
1819 typTup->typbasetype, typTup->typtypmod,
1820 constr, NameStr(typTup->typname));
1823 * Test all values stored in the attributes based on the domain the
1824 * constraint is being added to.
1826 expr = (Expr *) stringToNode(ccbin);
1828 /* Need an EState to run ExecEvalExpr */
1829 estate = CreateExecutorState();
1830 econtext = GetPerTupleExprContext(estate);
1832 /* build execution state for expr */
1833 exprstate = ExecPrepareExpr(expr, estate);
1835 /* Fetch relation list with attributes based on this domain */
1836 /* ShareLock is sufficient to prevent concurrent data changes */
1838 rels = get_rels_with_domain(domainoid, ShareLock);
1840 foreach(rt, rels)
1842 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1843 Relation testrel = rtc->rel;
1844 TupleDesc tupdesc = RelationGetDescr(testrel);
1845 HeapScanDesc scan;
1846 HeapTuple tuple;
1848 /* Scan all tuples in this relation */
1849 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1850 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1852 int i;
1854 /* Test attributes that are of the domain */
1855 for (i = 0; i < rtc->natts; i++)
1857 int attnum = rtc->atts[i];
1858 Datum d;
1859 bool isNull;
1860 Datum conResult;
1862 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
1864 econtext->domainValue_datum = d;
1865 econtext->domainValue_isNull = isNull;
1867 conResult = ExecEvalExprSwitchContext(exprstate,
1868 econtext,
1869 &isNull, NULL);
1871 if (!isNull && !DatumGetBool(conResult))
1872 ereport(ERROR,
1873 (errcode(ERRCODE_CHECK_VIOLATION),
1874 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
1875 NameStr(tupdesc->attrs[attnum - 1]->attname),
1876 RelationGetRelationName(testrel))));
1879 ResetExprContext(econtext);
1881 heap_endscan(scan);
1883 /* Hold relation lock till commit (XXX bad for concurrency) */
1884 heap_close(testrel, NoLock);
1887 FreeExecutorState(estate);
1889 /* Clean up */
1890 heap_close(typrel, RowExclusiveLock);
1894 * get_rels_with_domain
1896 * Fetch all relations / attributes which are using the domain
1898 * The result is a list of RelToCheck structs, one for each distinct
1899 * relation, each containing one or more attribute numbers that are of
1900 * the domain type. We have opened each rel and acquired the specified lock
1901 * type on it.
1903 * We support nested domains by including attributes that are of derived
1904 * domain types. Current callers do not need to distinguish between attributes
1905 * that are of exactly the given domain and those that are of derived domains.
1907 * XXX this is completely broken because there is no way to lock the domain
1908 * to prevent columns from being added or dropped while our command runs.
1909 * We can partially protect against column drops by locking relations as we
1910 * come across them, but there is still a race condition (the window between
1911 * seeing a pg_depend entry and acquiring lock on the relation it references).
1912 * Also, holding locks on all these relations simultaneously creates a non-
1913 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
1914 * risk by using the weakest suitable lock (ShareLock for most callers).
1916 * XXX the API for this is not sufficient to support checking domain values
1917 * that are inside composite types or arrays. Currently we just error out
1918 * if a composite type containing the target domain is stored anywhere.
1919 * There are not currently arrays of domains; if there were, we could take
1920 * the same approach, but it'd be nicer to fix it properly.
1922 * Generally used for retrieving a list of tests when adding
1923 * new constraints to a domain.
1925 static List *
1926 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
1928 List *result = NIL;
1929 Relation depRel;
1930 ScanKeyData key[2];
1931 SysScanDesc depScan;
1932 HeapTuple depTup;
1934 Assert(lockmode != NoLock);
1937 * We scan pg_depend to find those things that depend on the domain. (We
1938 * assume we can ignore refobjsubid for a domain.)
1940 depRel = heap_open(DependRelationId, AccessShareLock);
1942 ScanKeyInit(&key[0],
1943 Anum_pg_depend_refclassid,
1944 BTEqualStrategyNumber, F_OIDEQ,
1945 ObjectIdGetDatum(TypeRelationId));
1946 ScanKeyInit(&key[1],
1947 Anum_pg_depend_refobjid,
1948 BTEqualStrategyNumber, F_OIDEQ,
1949 ObjectIdGetDatum(domainOid));
1951 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
1952 SnapshotNow, 2, key);
1954 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
1956 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
1957 RelToCheck *rtc = NULL;
1958 ListCell *rellist;
1959 Form_pg_attribute pg_att;
1960 int ptr;
1962 /* Check for directly dependent types --- must be domains */
1963 if (pg_depend->classid == TypeRelationId)
1965 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
1968 * Recursively add dependent columns to the output list. This is
1969 * a bit inefficient since we may fail to combine RelToCheck
1970 * entries when attributes of the same rel have different derived
1971 * domain types, but it's probably not worth improving.
1973 result = list_concat(result,
1974 get_rels_with_domain(pg_depend->objid,
1975 lockmode));
1976 continue;
1979 /* Else, ignore dependees that aren't user columns of relations */
1980 /* (we assume system columns are never of domain types) */
1981 if (pg_depend->classid != RelationRelationId ||
1982 pg_depend->objsubid <= 0)
1983 continue;
1985 /* See if we already have an entry for this relation */
1986 foreach(rellist, result)
1988 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
1990 if (RelationGetRelid(rt->rel) == pg_depend->objid)
1992 rtc = rt;
1993 break;
1997 if (rtc == NULL)
1999 /* First attribute found for this relation */
2000 Relation rel;
2002 /* Acquire requested lock on relation */
2003 rel = relation_open(pg_depend->objid, lockmode);
2006 * Check to see if rowtype is stored anyplace as a composite-type
2007 * column; if so we have to fail, for now anyway.
2009 if (OidIsValid(rel->rd_rel->reltype))
2010 find_composite_type_dependencies(rel->rd_rel->reltype,
2011 NULL,
2012 format_type_be(domainOid));
2014 /* Otherwise we can ignore views, composite types, etc */
2015 if (rel->rd_rel->relkind != RELKIND_RELATION)
2017 relation_close(rel, lockmode);
2018 continue;
2021 /* Build the RelToCheck entry with enough space for all atts */
2022 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2023 rtc->rel = rel;
2024 rtc->natts = 0;
2025 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2026 result = lcons(rtc, result);
2030 * Confirm column has not been dropped, and is of the expected type.
2031 * This defends against an ALTER DROP COLUMN occuring just before we
2032 * acquired lock ... but if the whole table were dropped, we'd still
2033 * have a problem.
2035 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2036 continue;
2037 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2038 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2039 continue;
2042 * Okay, add column to result. We store the columns in column-number
2043 * order; this is just a hack to improve predictability of regression
2044 * test output ...
2046 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2048 ptr = rtc->natts++;
2049 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2051 rtc->atts[ptr] = rtc->atts[ptr - 1];
2052 ptr--;
2054 rtc->atts[ptr] = pg_depend->objsubid;
2057 systable_endscan(depScan);
2059 relation_close(depRel, AccessShareLock);
2061 return result;
2065 * checkDomainOwner
2067 * Check that the type is actually a domain and that the current user
2068 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2070 static void
2071 checkDomainOwner(HeapTuple tup, TypeName *typename)
2073 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2075 /* Check that this is actually a domain */
2076 if (typTup->typtype != TYPTYPE_DOMAIN)
2077 ereport(ERROR,
2078 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2079 errmsg("\"%s\" is not a domain",
2080 TypeNameToString(typename))));
2082 /* Permission check: must own type */
2083 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2084 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2085 TypeNameToString(typename));
2089 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2091 static char *
2092 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2093 int typMod, Constraint *constr,
2094 char *domainName)
2096 Node *expr;
2097 char *ccsrc;
2098 char *ccbin;
2099 ParseState *pstate;
2100 CoerceToDomainValue *domVal;
2103 * Assign or validate constraint name
2105 if (constr->name)
2107 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2108 domainOid,
2109 domainNamespace,
2110 constr->name))
2111 ereport(ERROR,
2112 (errcode(ERRCODE_DUPLICATE_OBJECT),
2113 errmsg("constraint \"%s\" for domain \"%s\" already exists",
2114 constr->name, domainName)));
2116 else
2117 constr->name = ChooseConstraintName(domainName,
2118 NULL,
2119 "check",
2120 domainNamespace,
2121 NIL);
2124 * Convert the A_EXPR in raw_expr into an EXPR
2126 pstate = make_parsestate(NULL);
2129 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2130 * the expression. Note that it will appear to have the type of the base
2131 * type, not the domain. This seems correct since within the check
2132 * expression, we should not assume the input value can be considered a
2133 * member of the domain.
2135 domVal = makeNode(CoerceToDomainValue);
2136 domVal->typeId = baseTypeOid;
2137 domVal->typeMod = typMod;
2138 domVal->location = -1; /* will be set when/if used */
2140 pstate->p_value_substitute = (Node *) domVal;
2142 expr = transformExpr(pstate, constr->raw_expr);
2145 * Make sure it yields a boolean result.
2147 expr = coerce_to_boolean(pstate, expr, "CHECK");
2150 * Make sure no outside relations are referred to.
2152 if (list_length(pstate->p_rtable) != 0)
2153 ereport(ERROR,
2154 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2155 errmsg("cannot use table references in domain check constraint")));
2158 * Domains don't allow var clauses (this should be redundant with the
2159 * above check, but make it anyway)
2161 if (contain_var_clause(expr))
2162 ereport(ERROR,
2163 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2164 errmsg("cannot use table references in domain check constraint")));
2167 * No subplans or aggregates, either...
2169 if (pstate->p_hasSubLinks)
2170 ereport(ERROR,
2171 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2172 errmsg("cannot use subquery in check constraint")));
2173 if (pstate->p_hasAggs)
2174 ereport(ERROR,
2175 (errcode(ERRCODE_GROUPING_ERROR),
2176 errmsg("cannot use aggregate function in check constraint")));
2179 * Convert to string form for storage.
2181 ccbin = nodeToString(expr);
2184 * Deparse it to produce text for consrc.
2186 * Since VARNOs aren't allowed in domain constraints, relation context
2187 * isn't required as anything other than a shell.
2189 ccsrc = deparse_expression(expr,
2190 deparse_context_for(domainName,
2191 InvalidOid),
2192 false, false);
2195 * Store the constraint in pg_constraint
2197 CreateConstraintEntry(constr->name, /* Constraint Name */
2198 domainNamespace, /* namespace */
2199 CONSTRAINT_CHECK, /* Constraint Type */
2200 false, /* Is Deferrable */
2201 false, /* Is Deferred */
2202 InvalidOid, /* not a relation constraint */
2203 NULL,
2205 domainOid, /* domain constraint */
2206 InvalidOid, /* Foreign key fields */
2207 NULL,
2208 NULL,
2209 NULL,
2210 NULL,
2212 ' ',
2213 ' ',
2214 ' ',
2215 InvalidOid,
2216 expr, /* Tree form check constraint */
2217 ccbin, /* Binary form check constraint */
2218 ccsrc, /* Source form check constraint */
2219 true, /* is local */
2220 0); /* inhcount */
2223 * Return the compiled constraint expression so the calling routine can
2224 * perform any additional required tests.
2226 return ccbin;
2230 * GetDomainConstraints - get a list of the current constraints of domain
2232 * Returns a possibly-empty list of DomainConstraintState nodes.
2234 * This is called by the executor during plan startup for a CoerceToDomain
2235 * expression node. The given constraints will be checked for each value
2236 * passed through the node.
2238 * We allow this to be called for non-domain types, in which case the result
2239 * is always NIL.
2241 List *
2242 GetDomainConstraints(Oid typeOid)
2244 List *result = NIL;
2245 bool notNull = false;
2246 Relation conRel;
2248 conRel = heap_open(ConstraintRelationId, AccessShareLock);
2250 for (;;)
2252 HeapTuple tup;
2253 HeapTuple conTup;
2254 Form_pg_type typTup;
2255 ScanKeyData key[1];
2256 SysScanDesc scan;
2258 tup = SearchSysCache(TYPEOID,
2259 ObjectIdGetDatum(typeOid),
2260 0, 0, 0);
2261 if (!HeapTupleIsValid(tup))
2262 elog(ERROR, "cache lookup failed for type %u", typeOid);
2263 typTup = (Form_pg_type) GETSTRUCT(tup);
2265 if (typTup->typtype != TYPTYPE_DOMAIN)
2267 /* Not a domain, so done */
2268 ReleaseSysCache(tup);
2269 break;
2272 /* Test for NOT NULL Constraint */
2273 if (typTup->typnotnull)
2274 notNull = true;
2276 /* Look for CHECK Constraints on this domain */
2277 ScanKeyInit(&key[0],
2278 Anum_pg_constraint_contypid,
2279 BTEqualStrategyNumber, F_OIDEQ,
2280 ObjectIdGetDatum(typeOid));
2282 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
2283 SnapshotNow, 1, key);
2285 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
2287 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
2288 Datum val;
2289 bool isNull;
2290 Expr *check_expr;
2291 DomainConstraintState *r;
2293 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
2294 if (c->contype != CONSTRAINT_CHECK)
2295 continue;
2298 * Not expecting conbin to be NULL, but we'll test for it anyway
2300 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
2301 conRel->rd_att, &isNull);
2302 if (isNull)
2303 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
2304 NameStr(typTup->typname), NameStr(c->conname));
2306 check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
2308 /* ExecInitExpr assumes we already fixed opfuncids */
2309 fix_opfuncids((Node *) check_expr);
2311 r = makeNode(DomainConstraintState);
2312 r->constrainttype = DOM_CONSTRAINT_CHECK;
2313 r->name = pstrdup(NameStr(c->conname));
2314 r->check_expr = ExecInitExpr(check_expr, NULL);
2317 * use lcons() here because constraints of lower domains should be
2318 * applied earlier.
2320 result = lcons(r, result);
2323 systable_endscan(scan);
2325 /* loop to next domain in stack */
2326 typeOid = typTup->typbasetype;
2327 ReleaseSysCache(tup);
2330 heap_close(conRel, AccessShareLock);
2333 * Only need to add one NOT NULL check regardless of how many domains in
2334 * the stack request it.
2336 if (notNull)
2338 DomainConstraintState *r = makeNode(DomainConstraintState);
2340 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
2341 r->name = pstrdup("NOT NULL");
2342 r->check_expr = NULL;
2344 /* lcons to apply the nullness check FIRST */
2345 result = lcons(r, result);
2348 return result;
2353 * Execute ALTER TYPE RENAME
2355 void
2356 RenameType(List *names, const char *newTypeName)
2358 TypeName *typename;
2359 Oid typeOid;
2360 Relation rel;
2361 HeapTuple tup;
2362 Form_pg_type typTup;
2364 /* Make a TypeName so we can use standard type lookup machinery */
2365 typename = makeTypeNameFromNameList(names);
2366 typeOid = typenameTypeId(NULL, typename, NULL);
2368 /* Look up the type in the type table */
2369 rel = heap_open(TypeRelationId, RowExclusiveLock);
2371 tup = SearchSysCacheCopy(TYPEOID,
2372 ObjectIdGetDatum(typeOid),
2373 0, 0, 0);
2374 if (!HeapTupleIsValid(tup))
2375 elog(ERROR, "cache lookup failed for type %u", typeOid);
2376 typTup = (Form_pg_type) GETSTRUCT(tup);
2378 /* check permissions on type */
2379 if (!pg_type_ownercheck(typeOid, GetUserId()))
2380 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2381 format_type_be(typeOid));
2384 * If it's a composite type, we need to check that it really is a
2385 * free-standing composite type, and not a table's rowtype. We
2386 * want people to use ALTER TABLE not ALTER TYPE for that case.
2388 if (typTup->typtype == TYPTYPE_COMPOSITE &&
2389 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2390 ereport(ERROR,
2391 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2392 errmsg("%s is a table's row type",
2393 format_type_be(typeOid)),
2394 errhint("Use ALTER TABLE instead.")));
2396 /* don't allow direct alteration of array types, either */
2397 if (OidIsValid(typTup->typelem) &&
2398 get_array_type(typTup->typelem) == typeOid)
2399 ereport(ERROR,
2400 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2401 errmsg("cannot alter array type %s",
2402 format_type_be(typeOid)),
2403 errhint("You can alter type %s, which will alter the array type as well.",
2404 format_type_be(typTup->typelem))));
2407 * If type is composite we need to rename associated pg_class entry too.
2408 * RenameRelationInternal will call RenameTypeInternal automatically.
2410 if (typTup->typtype == TYPTYPE_COMPOSITE)
2411 RenameRelationInternal(typTup->typrelid, newTypeName,
2412 typTup->typnamespace);
2413 else
2414 RenameTypeInternal(typeOid, newTypeName,
2415 typTup->typnamespace);
2417 /* Clean up */
2418 heap_close(rel, RowExclusiveLock);
2422 * Change the owner of a type.
2424 void
2425 AlterTypeOwner(List *names, Oid newOwnerId)
2427 TypeName *typename;
2428 Oid typeOid;
2429 Relation rel;
2430 HeapTuple tup;
2431 HeapTuple newtup;
2432 Form_pg_type typTup;
2433 AclResult aclresult;
2435 rel = heap_open(TypeRelationId, RowExclusiveLock);
2437 /* Make a TypeName so we can use standard type lookup machinery */
2438 typename = makeTypeNameFromNameList(names);
2440 /* Use LookupTypeName here so that shell types can be processed */
2441 tup = LookupTypeName(NULL, typename, NULL);
2442 if (tup == NULL)
2443 ereport(ERROR,
2444 (errcode(ERRCODE_UNDEFINED_OBJECT),
2445 errmsg("type \"%s\" does not exist",
2446 TypeNameToString(typename))));
2447 typeOid = typeTypeId(tup);
2449 /* Copy the syscache entry so we can scribble on it below */
2450 newtup = heap_copytuple(tup);
2451 ReleaseSysCache(tup);
2452 tup = newtup;
2453 typTup = (Form_pg_type) GETSTRUCT(tup);
2456 * If it's a composite type, we need to check that it really is a
2457 * free-standing composite type, and not a table's rowtype. We want people
2458 * to use ALTER TABLE not ALTER TYPE for that case.
2460 if (typTup->typtype == TYPTYPE_COMPOSITE &&
2461 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2462 ereport(ERROR,
2463 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2464 errmsg("%s is a table's row type",
2465 format_type_be(typeOid)),
2466 errhint("Use ALTER TABLE instead.")));
2468 /* don't allow direct alteration of array types, either */
2469 if (OidIsValid(typTup->typelem) &&
2470 get_array_type(typTup->typelem) == typeOid)
2471 ereport(ERROR,
2472 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2473 errmsg("cannot alter array type %s",
2474 format_type_be(typeOid)),
2475 errhint("You can alter type %s, which will alter the array type as well.",
2476 format_type_be(typTup->typelem))));
2479 * If the new owner is the same as the existing owner, consider the
2480 * command to have succeeded. This is for dump restoration purposes.
2482 if (typTup->typowner != newOwnerId)
2484 /* Superusers can always do it */
2485 if (!superuser())
2487 /* Otherwise, must be owner of the existing object */
2488 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2489 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2490 TypeNameToString(typename));
2492 /* Must be able to become new owner */
2493 check_is_member_of_role(GetUserId(), newOwnerId);
2495 /* New owner must have CREATE privilege on namespace */
2496 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
2497 newOwnerId,
2498 ACL_CREATE);
2499 if (aclresult != ACLCHECK_OK)
2500 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
2501 get_namespace_name(typTup->typnamespace));
2505 * If it's a composite type, invoke ATExecChangeOwner so that we fix
2506 * up the pg_class entry properly. That will call back to
2507 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
2509 if (typTup->typtype == TYPTYPE_COMPOSITE)
2510 ATExecChangeOwner(typTup->typrelid, newOwnerId, true);
2511 else
2514 * We can just apply the modification directly.
2516 * okay to scribble on typTup because it's a copy
2518 typTup->typowner = newOwnerId;
2520 simple_heap_update(rel, &tup->t_self, tup);
2522 CatalogUpdateIndexes(rel, tup);
2524 /* Update owner dependency reference */
2525 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2527 /* If it has an array type, update that too */
2528 if (OidIsValid(typTup->typarray))
2529 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
2533 /* Clean up */
2534 heap_close(rel, RowExclusiveLock);
2538 * AlterTypeOwnerInternal - change type owner unconditionally
2540 * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
2541 * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
2542 * It assumes the caller has done all needed checks. The function will
2543 * automatically recurse to an array type if the type has one.
2545 * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
2546 * entry (ie, it's not a table rowtype nor an array type).
2548 void
2549 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
2550 bool hasDependEntry)
2552 Relation rel;
2553 HeapTuple tup;
2554 Form_pg_type typTup;
2556 rel = heap_open(TypeRelationId, RowExclusiveLock);
2558 tup = SearchSysCacheCopy(TYPEOID,
2559 ObjectIdGetDatum(typeOid),
2560 0, 0, 0);
2561 if (!HeapTupleIsValid(tup))
2562 elog(ERROR, "cache lookup failed for type %u", typeOid);
2563 typTup = (Form_pg_type) GETSTRUCT(tup);
2566 * Modify the owner --- okay to scribble on typTup because it's a copy
2568 typTup->typowner = newOwnerId;
2570 simple_heap_update(rel, &tup->t_self, tup);
2572 CatalogUpdateIndexes(rel, tup);
2574 /* Update owner dependency reference, if it has one */
2575 if (hasDependEntry)
2576 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2578 /* If it has an array type, update that too */
2579 if (OidIsValid(typTup->typarray))
2580 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
2582 /* Clean up */
2583 heap_close(rel, RowExclusiveLock);
2587 * Execute ALTER TYPE SET SCHEMA
2589 void
2590 AlterTypeNamespace(List *names, const char *newschema)
2592 TypeName *typename;
2593 Oid typeOid;
2594 Oid nspOid;
2595 Oid elemOid;
2597 /* Make a TypeName so we can use standard type lookup machinery */
2598 typename = makeTypeNameFromNameList(names);
2599 typeOid = typenameTypeId(NULL, typename, NULL);
2601 /* check permissions on type */
2602 if (!pg_type_ownercheck(typeOid, GetUserId()))
2603 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2604 format_type_be(typeOid));
2606 /* get schema OID and check its permissions */
2607 nspOid = LookupCreationNamespace(newschema);
2609 /* don't allow direct alteration of array types */
2610 elemOid = get_element_type(typeOid);
2611 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
2612 ereport(ERROR,
2613 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2614 errmsg("cannot alter array type %s",
2615 format_type_be(typeOid)),
2616 errhint("You can alter type %s, which will alter the array type as well.",
2617 format_type_be(elemOid))));
2619 /* and do the work */
2620 AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
2624 * Move specified type to new namespace.
2626 * Caller must have already checked privileges.
2628 * The function automatically recurses to process the type's array type,
2629 * if any. isImplicitArray should be TRUE only when doing this internal
2630 * recursion (outside callers must never try to move an array type directly).
2632 * If errorOnTableType is TRUE, the function errors out if the type is
2633 * a table type. ALTER TABLE has to be used to move a table to a new
2634 * namespace.
2636 void
2637 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
2638 bool isImplicitArray,
2639 bool errorOnTableType)
2641 Relation rel;
2642 HeapTuple tup;
2643 Form_pg_type typform;
2644 Oid oldNspOid;
2645 Oid arrayOid;
2646 bool isCompositeType;
2648 rel = heap_open(TypeRelationId, RowExclusiveLock);
2650 tup = SearchSysCacheCopy(TYPEOID,
2651 ObjectIdGetDatum(typeOid),
2652 0, 0, 0);
2653 if (!HeapTupleIsValid(tup))
2654 elog(ERROR, "cache lookup failed for type %u", typeOid);
2655 typform = (Form_pg_type) GETSTRUCT(tup);
2657 oldNspOid = typform->typnamespace;
2658 arrayOid = typform->typarray;
2660 if (oldNspOid == nspOid)
2661 ereport(ERROR,
2662 (errcode(ERRCODE_DUPLICATE_OBJECT),
2663 errmsg("type %s is already in schema \"%s\"",
2664 format_type_be(typeOid),
2665 get_namespace_name(nspOid))));
2667 /* disallow renaming into or out of temp schemas */
2668 if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
2669 ereport(ERROR,
2670 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2671 errmsg("cannot move objects into or out of temporary schemas")));
2673 /* same for TOAST schema */
2674 if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
2675 ereport(ERROR,
2676 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2677 errmsg("cannot move objects into or out of TOAST schema")));
2679 /* check for duplicate name (more friendly than unique-index failure) */
2680 if (SearchSysCacheExists(TYPENAMENSP,
2681 CStringGetDatum(NameStr(typform->typname)),
2682 ObjectIdGetDatum(nspOid),
2683 0, 0))
2684 ereport(ERROR,
2685 (errcode(ERRCODE_DUPLICATE_OBJECT),
2686 errmsg("type \"%s\" already exists in schema \"%s\"",
2687 NameStr(typform->typname),
2688 get_namespace_name(nspOid))));
2690 /* Detect whether type is a composite type (but not a table rowtype) */
2691 isCompositeType =
2692 (typform->typtype == TYPTYPE_COMPOSITE &&
2693 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
2695 /* Enforce not-table-type if requested */
2696 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
2697 errorOnTableType)
2698 ereport(ERROR,
2699 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2700 errmsg("%s is a table's row type",
2701 format_type_be(typeOid)),
2702 errhint("Use ALTER TABLE instead.")));
2704 /* OK, modify the pg_type row */
2706 /* tup is a copy, so we can scribble directly on it */
2707 typform->typnamespace = nspOid;
2709 simple_heap_update(rel, &tup->t_self, tup);
2710 CatalogUpdateIndexes(rel, tup);
2713 * Composite types have pg_class entries.
2715 * We need to modify the pg_class tuple as well to reflect the change of
2716 * schema.
2718 if (isCompositeType)
2720 Relation classRel;
2722 classRel = heap_open(RelationRelationId, RowExclusiveLock);
2724 AlterRelationNamespaceInternal(classRel, typform->typrelid,
2725 oldNspOid, nspOid,
2726 false);
2728 heap_close(classRel, RowExclusiveLock);
2731 * Check for constraints associated with the composite type (we don't
2732 * currently support this, but probably will someday).
2734 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
2735 nspOid, false);
2737 else
2739 /* If it's a domain, it might have constraints */
2740 if (typform->typtype == TYPTYPE_DOMAIN)
2741 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
2745 * Update dependency on schema, if any --- a table rowtype has not got
2746 * one, and neither does an implicit array.
2748 if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
2749 !isImplicitArray)
2750 if (changeDependencyFor(TypeRelationId, typeOid,
2751 NamespaceRelationId, oldNspOid, nspOid) != 1)
2752 elog(ERROR, "failed to change schema dependency for type %s",
2753 format_type_be(typeOid));
2755 heap_freetuple(tup);
2757 heap_close(rel, RowExclusiveLock);
2759 /* Recursively alter the associated array type, if any */
2760 if (OidIsValid(arrayOid))
2761 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);