Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / src / backend / commands / typecmds.c
blob528a9172346d2f21cb12a9072be11f2da0161fec
1 /*-------------------------------------------------------------------------
3 * typecmds.c
4 * Routines for SQL commands that manipulate types (and domains).
6 * Portions Copyright (c) 1996-2009, 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/planner.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 List *inputName = NIL;
104 List *outputName = NIL;
105 List *receiveName = NIL;
106 List *sendName = NIL;
107 List *typmodinName = NIL;
108 List *typmodoutName = NIL;
109 List *analyzeName = NIL;
110 char category = TYPCATEGORY_USER;
111 bool preferred = false;
112 char delimiter = DEFAULT_TYPDELIM;
113 Oid elemType = InvalidOid;
114 char *defaultValue = NULL;
115 bool byValue = false;
116 char alignment = 'i'; /* default alignment */
117 char storage = 'p'; /* default TOAST storage method */
118 DefElem *likeTypeEl = NULL;
119 DefElem *internalLengthEl = NULL;
120 DefElem *inputNameEl = NULL;
121 DefElem *outputNameEl = NULL;
122 DefElem *receiveNameEl = NULL;
123 DefElem *sendNameEl = NULL;
124 DefElem *typmodinNameEl = NULL;
125 DefElem *typmodoutNameEl = NULL;
126 DefElem *analyzeNameEl = NULL;
127 DefElem *categoryEl = NULL;
128 DefElem *preferredEl = NULL;
129 DefElem *delimiterEl = NULL;
130 DefElem *elemTypeEl = NULL;
131 DefElem *defaultValueEl = NULL;
132 DefElem *byValueEl = NULL;
133 DefElem *alignmentEl = NULL;
134 DefElem *storageEl = NULL;
135 Oid inputOid;
136 Oid outputOid;
137 Oid receiveOid = InvalidOid;
138 Oid sendOid = InvalidOid;
139 Oid typmodinOid = InvalidOid;
140 Oid typmodoutOid = InvalidOid;
141 Oid analyzeOid = InvalidOid;
142 char *array_type;
143 Oid array_oid;
144 Oid typoid;
145 Oid resulttype;
146 Relation pg_type;
147 ListCell *pl;
150 * As of Postgres 8.4, we require superuser privilege to create a base
151 * type. This is simple paranoia: there are too many ways to mess up the
152 * system with an incorrect type definition (for instance, representation
153 * parameters that don't match what the C code expects). In practice it
154 * takes superuser privilege to create the I/O functions, and so the
155 * former requirement that you own the I/O functions pretty much forced
156 * superuserness anyway. We're just making doubly sure here.
158 * XXX re-enable NOT_USED code sections below if you remove this test.
160 if (!superuser())
161 ereport(ERROR,
162 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
163 errmsg("must be superuser to create a base type")));
165 /* Convert list of names to a name and namespace */
166 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
168 #ifdef NOT_USED
169 /* XXX this is unnecessary given the superuser check above */
170 /* Check we have creation rights in target namespace */
171 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
172 if (aclresult != ACLCHECK_OK)
173 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
174 get_namespace_name(typeNamespace));
175 #endif
178 * Look to see if type already exists (presumably as a shell; if not,
179 * TypeCreate will complain).
181 typoid = GetSysCacheOid(TYPENAMENSP,
182 CStringGetDatum(typeName),
183 ObjectIdGetDatum(typeNamespace),
184 0, 0);
187 * If it's not a shell, see if it's an autogenerated array type, and if so
188 * rename it out of the way.
190 if (OidIsValid(typoid) && get_typisdefined(typoid))
192 if (moveArrayTypeName(typoid, typeName, typeNamespace))
193 typoid = InvalidOid;
197 * If it doesn't exist, create it as a shell, so that the OID is known for
198 * use in the I/O function definitions.
200 if (!OidIsValid(typoid))
202 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
203 /* Make new shell type visible for modification below */
204 CommandCounterIncrement();
207 * If the command was a parameterless CREATE TYPE, we're done ---
208 * creating the shell type was all we're supposed to do.
210 if (parameters == NIL)
211 return;
213 else
215 /* Complain if dummy CREATE TYPE and entry already exists */
216 if (parameters == NIL)
217 ereport(ERROR,
218 (errcode(ERRCODE_DUPLICATE_OBJECT),
219 errmsg("type \"%s\" already exists", typeName)));
222 /* Extract the parameters from the parameter list */
223 foreach(pl, parameters)
225 DefElem *defel = (DefElem *) lfirst(pl);
226 DefElem **defelp;
228 if (pg_strcasecmp(defel->defname, "like") == 0)
229 defelp = &likeTypeEl;
230 else if (pg_strcasecmp(defel->defname, "internallength") == 0)
231 defelp = &internalLengthEl;
232 else if (pg_strcasecmp(defel->defname, "input") == 0)
233 defelp = &inputNameEl;
234 else if (pg_strcasecmp(defel->defname, "output") == 0)
235 defelp = &outputNameEl;
236 else if (pg_strcasecmp(defel->defname, "receive") == 0)
237 defelp = &receiveNameEl;
238 else if (pg_strcasecmp(defel->defname, "send") == 0)
239 defelp = &sendNameEl;
240 else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
241 defelp = &typmodinNameEl;
242 else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
243 defelp = &typmodoutNameEl;
244 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
245 pg_strcasecmp(defel->defname, "analyse") == 0)
246 defelp = &analyzeNameEl;
247 else if (pg_strcasecmp(defel->defname, "category") == 0)
248 defelp = &categoryEl;
249 else if (pg_strcasecmp(defel->defname, "preferred") == 0)
250 defelp = &preferredEl;
251 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
252 defelp = &delimiterEl;
253 else if (pg_strcasecmp(defel->defname, "element") == 0)
254 defelp = &elemTypeEl;
255 else if (pg_strcasecmp(defel->defname, "default") == 0)
256 defelp = &defaultValueEl;
257 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
258 defelp = &byValueEl;
259 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
260 defelp = &alignmentEl;
261 else if (pg_strcasecmp(defel->defname, "storage") == 0)
262 defelp = &storageEl;
263 else
265 /* WARNING, not ERROR, for historical backwards-compatibility */
266 ereport(WARNING,
267 (errcode(ERRCODE_SYNTAX_ERROR),
268 errmsg("type attribute \"%s\" not recognized",
269 defel->defname)));
270 continue;
272 if (*defelp != NULL)
273 ereport(ERROR,
274 (errcode(ERRCODE_SYNTAX_ERROR),
275 errmsg("conflicting or redundant options")));
276 *defelp = defel;
280 * Now interpret the options; we do this separately so that LIKE can be
281 * overridden by other options regardless of the ordering in the parameter
282 * list.
284 if (likeTypeEl)
286 Type likeType;
287 Form_pg_type likeForm;
289 likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
290 likeForm = (Form_pg_type) GETSTRUCT(likeType);
291 internalLength = likeForm->typlen;
292 byValue = likeForm->typbyval;
293 alignment = likeForm->typalign;
294 storage = likeForm->typstorage;
295 ReleaseSysCache(likeType);
297 if (internalLengthEl)
298 internalLength = defGetTypeLength(internalLengthEl);
299 if (inputNameEl)
300 inputName = defGetQualifiedName(inputNameEl);
301 if (outputNameEl)
302 outputName = defGetQualifiedName(outputNameEl);
303 if (receiveNameEl)
304 receiveName = defGetQualifiedName(receiveNameEl);
305 if (sendNameEl)
306 sendName = defGetQualifiedName(sendNameEl);
307 if (typmodinNameEl)
308 typmodinName = defGetQualifiedName(typmodinNameEl);
309 if (typmodoutNameEl)
310 typmodoutName = defGetQualifiedName(typmodoutNameEl);
311 if (analyzeNameEl)
312 analyzeName = defGetQualifiedName(analyzeNameEl);
313 if (categoryEl)
315 char *p = defGetString(categoryEl);
317 category = p[0];
318 /* restrict to non-control ASCII */
319 if (category < 32 || category > 126)
320 ereport(ERROR,
321 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
322 errmsg("invalid type category \"%s\": must be simple ASCII",
323 p)));
325 if (preferredEl)
326 preferred = defGetBoolean(preferredEl);
327 if (delimiterEl)
329 char *p = defGetString(delimiterEl);
331 delimiter = p[0];
332 /* XXX shouldn't we restrict the delimiter? */
334 if (elemTypeEl)
336 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl), NULL);
337 /* disallow arrays of pseudotypes */
338 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
339 ereport(ERROR,
340 (errcode(ERRCODE_DATATYPE_MISMATCH),
341 errmsg("array element type cannot be %s",
342 format_type_be(elemType))));
344 if (defaultValueEl)
345 defaultValue = defGetString(defaultValueEl);
346 if (byValueEl)
347 byValue = defGetBoolean(byValueEl);
348 if (alignmentEl)
350 char *a = defGetString(alignmentEl);
353 * Note: if argument was an unquoted identifier, parser will have
354 * applied translations to it, so be prepared to recognize translated
355 * type names as well as the nominal form.
357 if (pg_strcasecmp(a, "double") == 0 ||
358 pg_strcasecmp(a, "float8") == 0 ||
359 pg_strcasecmp(a, "pg_catalog.float8") == 0)
360 alignment = 'd';
361 else if (pg_strcasecmp(a, "int4") == 0 ||
362 pg_strcasecmp(a, "pg_catalog.int4") == 0)
363 alignment = 'i';
364 else if (pg_strcasecmp(a, "int2") == 0 ||
365 pg_strcasecmp(a, "pg_catalog.int2") == 0)
366 alignment = 's';
367 else if (pg_strcasecmp(a, "char") == 0 ||
368 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
369 alignment = 'c';
370 else
371 ereport(ERROR,
372 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
373 errmsg("alignment \"%s\" not recognized", a)));
375 if (storageEl)
377 char *a = defGetString(storageEl);
379 if (pg_strcasecmp(a, "plain") == 0)
380 storage = 'p';
381 else if (pg_strcasecmp(a, "external") == 0)
382 storage = 'e';
383 else if (pg_strcasecmp(a, "extended") == 0)
384 storage = 'x';
385 else if (pg_strcasecmp(a, "main") == 0)
386 storage = 'm';
387 else
388 ereport(ERROR,
389 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
390 errmsg("storage \"%s\" not recognized", a)));
394 * make sure we have our required definitions
396 if (inputName == NIL)
397 ereport(ERROR,
398 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
399 errmsg("type input function must be specified")));
400 if (outputName == NIL)
401 ereport(ERROR,
402 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
403 errmsg("type output function must be specified")));
405 if (typmodinName == NIL && typmodoutName != NIL)
406 ereport(ERROR,
407 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
408 errmsg("type modifier output function is useless without a type modifier input function")));
411 * Convert I/O proc names to OIDs
413 inputOid = findTypeInputFunction(inputName, typoid);
414 outputOid = findTypeOutputFunction(outputName, typoid);
415 if (receiveName)
416 receiveOid = findTypeReceiveFunction(receiveName, typoid);
417 if (sendName)
418 sendOid = findTypeSendFunction(sendName, typoid);
421 * Verify that I/O procs return the expected thing. If we see OPAQUE,
422 * complain and change it to the correct type-safe choice.
424 resulttype = get_func_rettype(inputOid);
425 if (resulttype != typoid)
427 if (resulttype == OPAQUEOID)
429 /* backwards-compatibility hack */
430 ereport(WARNING,
431 (errmsg("changing return type of function %s from \"opaque\" to %s",
432 NameListToString(inputName), typeName)));
433 SetFunctionReturnType(inputOid, typoid);
435 else
436 ereport(ERROR,
437 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
438 errmsg("type input function %s must return type %s",
439 NameListToString(inputName), typeName)));
441 resulttype = get_func_rettype(outputOid);
442 if (resulttype != CSTRINGOID)
444 if (resulttype == OPAQUEOID)
446 /* backwards-compatibility hack */
447 ereport(WARNING,
448 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
449 NameListToString(outputName))));
450 SetFunctionReturnType(outputOid, CSTRINGOID);
452 else
453 ereport(ERROR,
454 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
455 errmsg("type output function %s must return type \"cstring\"",
456 NameListToString(outputName))));
458 if (receiveOid)
460 resulttype = get_func_rettype(receiveOid);
461 if (resulttype != typoid)
462 ereport(ERROR,
463 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
464 errmsg("type receive function %s must return type %s",
465 NameListToString(receiveName), typeName)));
467 if (sendOid)
469 resulttype = get_func_rettype(sendOid);
470 if (resulttype != BYTEAOID)
471 ereport(ERROR,
472 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
473 errmsg("type send function %s must return type \"bytea\"",
474 NameListToString(sendName))));
478 * Convert typmodin/out function proc names to OIDs.
480 if (typmodinName)
481 typmodinOid = findTypeTypmodinFunction(typmodinName);
482 if (typmodoutName)
483 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
486 * Convert analysis function proc name to an OID. If no analysis function
487 * is specified, we'll use zero to select the built-in default algorithm.
489 if (analyzeName)
490 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
493 * Check permissions on functions. We choose to require the creator/owner
494 * of a type to also own the underlying functions. Since creating a type
495 * is tantamount to granting public execute access on the functions, the
496 * minimum sane check would be for execute-with-grant-option. But we
497 * don't have a way to make the type go away if the grant option is
498 * revoked, so ownership seems better.
500 #ifdef NOT_USED
501 /* XXX this is unnecessary given the superuser check above */
502 if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
503 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
504 NameListToString(inputName));
505 if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
506 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
507 NameListToString(outputName));
508 if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
509 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
510 NameListToString(receiveName));
511 if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
512 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
513 NameListToString(sendName));
514 if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
515 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
516 NameListToString(typmodinName));
517 if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
518 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
519 NameListToString(typmodoutName));
520 if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
521 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
522 NameListToString(analyzeName));
523 #endif
525 /* Preassign array type OID so we can insert it in pg_type.typarray */
526 pg_type = heap_open(TypeRelationId, AccessShareLock);
527 array_oid = GetNewOid(pg_type);
528 heap_close(pg_type, AccessShareLock);
531 * now have TypeCreate do all the real work.
533 typoid =
534 TypeCreate(InvalidOid, /* no predetermined type OID */
535 typeName, /* type name */
536 typeNamespace, /* namespace */
537 InvalidOid, /* relation oid (n/a here) */
538 0, /* relation kind (ditto) */
539 GetUserId(), /* owner's ID */
540 internalLength, /* internal size */
541 TYPTYPE_BASE, /* type-type (base type) */
542 category, /* type-category */
543 preferred, /* is it a preferred type? */
544 delimiter, /* array element delimiter */
545 inputOid, /* input procedure */
546 outputOid, /* output procedure */
547 receiveOid, /* receive procedure */
548 sendOid, /* send procedure */
549 typmodinOid, /* typmodin procedure */
550 typmodoutOid, /* typmodout procedure */
551 analyzeOid, /* analyze procedure */
552 elemType, /* element type ID */
553 false, /* this is not an array type */
554 array_oid, /* array type we are about to create */
555 InvalidOid, /* base type ID (only for domains) */
556 defaultValue, /* default type value */
557 NULL, /* no binary form available */
558 byValue, /* passed by value */
559 alignment, /* required alignment */
560 storage, /* TOAST strategy */
561 -1, /* typMod (Domains only) */
562 0, /* Array Dimensions of typbasetype */
563 false); /* Type NOT NULL */
566 * Create the array type that goes with it.
568 array_type = makeArrayTypeName(typeName, typeNamespace);
570 /* alignment must be 'i' or 'd' for arrays */
571 alignment = (alignment == 'd') ? 'd' : 'i';
573 TypeCreate(array_oid, /* force assignment of this type OID */
574 array_type, /* type name */
575 typeNamespace, /* namespace */
576 InvalidOid, /* relation oid (n/a here) */
577 0, /* relation kind (ditto) */
578 GetUserId(), /* owner's ID */
579 -1, /* internal size (always varlena) */
580 TYPTYPE_BASE, /* type-type (base type) */
581 TYPCATEGORY_ARRAY, /* type-category (array) */
582 false, /* array types are never preferred */
583 delimiter, /* array element delimiter */
584 F_ARRAY_IN, /* input procedure */
585 F_ARRAY_OUT, /* output procedure */
586 F_ARRAY_RECV, /* receive procedure */
587 F_ARRAY_SEND, /* send procedure */
588 typmodinOid, /* typmodin procedure */
589 typmodoutOid, /* typmodout procedure */
590 InvalidOid, /* analyze procedure - default */
591 typoid, /* element type ID */
592 true, /* yes this is an array type */
593 InvalidOid, /* no further array type */
594 InvalidOid, /* base type ID */
595 NULL, /* never a default type value */
596 NULL, /* binary default isn't sent either */
597 false, /* never passed by value */
598 alignment, /* see above */
599 'x', /* ARRAY is always toastable */
600 -1, /* typMod (Domains only) */
601 0, /* Array dimensions of typbasetype */
602 false); /* Type NOT NULL */
604 pfree(array_type);
609 * RemoveTypes
610 * Implements DROP TYPE and DROP DOMAIN
612 * Note: if DOMAIN is specified, we enforce that each type is a domain, but
613 * we don't enforce the converse for DROP TYPE
615 void
616 RemoveTypes(DropStmt *drop)
618 ObjectAddresses *objects;
619 ListCell *cell;
622 * First we identify all the types, then we delete them in a single
623 * performMultipleDeletions() call. This is to avoid unwanted DROP
624 * RESTRICT errors if one of the types depends on another.
626 objects = new_object_addresses();
628 foreach(cell, drop->objects)
630 List *names = (List *) lfirst(cell);
631 TypeName *typename;
632 Oid typeoid;
633 HeapTuple tup;
634 ObjectAddress object;
635 Form_pg_type typ;
637 /* Make a TypeName so we can use standard type lookup machinery */
638 typename = makeTypeNameFromNameList(names);
640 /* Use LookupTypeName here so that shell types can be removed. */
641 tup = LookupTypeName(NULL, typename, NULL);
642 if (tup == NULL)
644 if (!drop->missing_ok)
646 ereport(ERROR,
647 (errcode(ERRCODE_UNDEFINED_OBJECT),
648 errmsg("type \"%s\" does not exist",
649 TypeNameToString(typename))));
651 else
653 ereport(NOTICE,
654 (errmsg("type \"%s\" does not exist, skipping",
655 TypeNameToString(typename))));
657 continue;
660 typeoid = typeTypeId(tup);
661 typ = (Form_pg_type) GETSTRUCT(tup);
663 /* Permission check: must own type or its namespace */
664 if (!pg_type_ownercheck(typeoid, GetUserId()) &&
665 !pg_namespace_ownercheck(typ->typnamespace, GetUserId()))
666 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
667 format_type_be(typeoid));
669 if (drop->removeType == OBJECT_DOMAIN)
671 /* Check that this is actually a domain */
672 if (typ->typtype != TYPTYPE_DOMAIN)
673 ereport(ERROR,
674 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
675 errmsg("\"%s\" is not a domain",
676 TypeNameToString(typename))));
680 * Note: we need no special check for array types here, as the normal
681 * treatment of internal dependencies handles it just fine
684 object.classId = TypeRelationId;
685 object.objectId = typeoid;
686 object.objectSubId = 0;
688 add_exact_object_address(&object, objects);
690 ReleaseSysCache(tup);
693 performMultipleDeletions(objects, drop->behavior);
695 free_object_addresses(objects);
700 * Guts of type deletion.
702 void
703 RemoveTypeById(Oid typeOid)
705 Relation relation;
706 HeapTuple tup;
708 relation = heap_open(TypeRelationId, RowExclusiveLock);
710 tup = SearchSysCache(TYPEOID,
711 ObjectIdGetDatum(typeOid),
712 0, 0, 0);
713 if (!HeapTupleIsValid(tup))
714 elog(ERROR, "cache lookup failed for type %u", typeOid);
716 simple_heap_delete(relation, &tup->t_self);
719 * If it is an enum, delete the pg_enum entries too; we don't bother with
720 * making dependency entries for those, so it has to be done "by hand"
721 * here.
723 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
724 EnumValuesDelete(typeOid);
726 ReleaseSysCache(tup);
728 heap_close(relation, RowExclusiveLock);
733 * DefineDomain
734 * Registers a new domain.
736 void
737 DefineDomain(CreateDomainStmt *stmt)
739 char *domainName;
740 Oid domainNamespace;
741 AclResult aclresult;
742 int16 internalLength;
743 Oid inputProcedure;
744 Oid outputProcedure;
745 Oid receiveProcedure;
746 Oid sendProcedure;
747 Oid analyzeProcedure;
748 bool byValue;
749 Oid typelem;
750 char category;
751 char delimiter;
752 char alignment;
753 char storage;
754 char typtype;
755 Datum datum;
756 bool isnull;
757 char *defaultValue = NULL;
758 char *defaultValueBin = NULL;
759 bool saw_default = false;
760 bool typNotNull = false;
761 bool nullDefined = false;
762 int32 typNDims = list_length(stmt->typename->arrayBounds);
763 HeapTuple typeTup;
764 List *schema = stmt->constraints;
765 ListCell *listptr;
766 Oid basetypeoid;
767 Oid domainoid;
768 Oid old_type_oid;
769 Form_pg_type baseType;
770 int32 basetypeMod;
772 /* Convert list of names to a name and namespace */
773 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
774 &domainName);
776 /* Check we have creation rights in target namespace */
777 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
778 ACL_CREATE);
779 if (aclresult != ACLCHECK_OK)
780 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
781 get_namespace_name(domainNamespace));
784 * Check for collision with an existing type name. If there is one and
785 * it's an autogenerated array, we can rename it out of the way.
787 old_type_oid = GetSysCacheOid(TYPENAMENSP,
788 CStringGetDatum(domainName),
789 ObjectIdGetDatum(domainNamespace),
790 0, 0);
791 if (OidIsValid(old_type_oid))
793 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
794 ereport(ERROR,
795 (errcode(ERRCODE_DUPLICATE_OBJECT),
796 errmsg("type \"%s\" already exists", domainName)));
800 * Look up the base type.
802 typeTup = typenameType(NULL, stmt->typename, &basetypeMod);
803 baseType = (Form_pg_type) GETSTRUCT(typeTup);
804 basetypeoid = HeapTupleGetOid(typeTup);
807 * Base type must be a plain base type, another domain or an enum. Domains
808 * over pseudotypes would create a security hole. Domains over composite
809 * types might be made to work in the future, but not today.
811 typtype = baseType->typtype;
812 if (typtype != TYPTYPE_BASE &&
813 typtype != TYPTYPE_DOMAIN &&
814 typtype != TYPTYPE_ENUM)
815 ereport(ERROR,
816 (errcode(ERRCODE_DATATYPE_MISMATCH),
817 errmsg("\"%s\" is not a valid base type for a domain",
818 TypeNameToString(stmt->typename))));
820 /* passed by value */
821 byValue = baseType->typbyval;
823 /* Required Alignment */
824 alignment = baseType->typalign;
826 /* TOAST Strategy */
827 storage = baseType->typstorage;
829 /* Storage Length */
830 internalLength = baseType->typlen;
832 /* Type Category */
833 category = baseType->typcategory;
835 /* Array element type (in case base type is an array) */
836 typelem = baseType->typelem;
838 /* Array element Delimiter */
839 delimiter = baseType->typdelim;
841 /* I/O Functions */
842 inputProcedure = F_DOMAIN_IN;
843 outputProcedure = baseType->typoutput;
844 receiveProcedure = F_DOMAIN_RECV;
845 sendProcedure = baseType->typsend;
847 /* Domains never accept typmods, so no typmodin/typmodout needed */
849 /* Analysis function */
850 analyzeProcedure = baseType->typanalyze;
852 /* Inherited default value */
853 datum = SysCacheGetAttr(TYPEOID, typeTup,
854 Anum_pg_type_typdefault, &isnull);
855 if (!isnull)
856 defaultValue = TextDatumGetCString(datum);
858 /* Inherited default binary value */
859 datum = SysCacheGetAttr(TYPEOID, typeTup,
860 Anum_pg_type_typdefaultbin, &isnull);
861 if (!isnull)
862 defaultValueBin = TextDatumGetCString(datum);
865 * Run through constraints manually to avoid the additional processing
866 * conducted by DefineRelation() and friends.
868 foreach(listptr, schema)
870 Node *newConstraint = lfirst(listptr);
871 Constraint *constr;
873 /* Check for unsupported constraint types */
874 if (IsA(newConstraint, FkConstraint))
875 ereport(ERROR,
876 (errcode(ERRCODE_SYNTAX_ERROR),
877 errmsg("foreign key constraints not possible for domains")));
879 /* otherwise it should be a plain Constraint */
880 if (!IsA(newConstraint, Constraint))
881 elog(ERROR, "unrecognized node type: %d",
882 (int) nodeTag(newConstraint));
884 constr = (Constraint *) newConstraint;
886 switch (constr->contype)
888 case CONSTR_DEFAULT:
891 * The inherited default value may be overridden by the user
892 * with the DEFAULT <expr> clause ... but only once.
894 if (saw_default)
895 ereport(ERROR,
896 (errcode(ERRCODE_SYNTAX_ERROR),
897 errmsg("multiple default expressions")));
898 saw_default = true;
900 if (constr->raw_expr)
902 ParseState *pstate;
903 Node *defaultExpr;
905 /* Create a dummy ParseState for transformExpr */
906 pstate = make_parsestate(NULL);
909 * Cook the constr->raw_expr into an expression. Note:
910 * name is strictly for error message
912 defaultExpr = cookDefault(pstate, constr->raw_expr,
913 basetypeoid,
914 basetypeMod,
915 domainName);
918 * If the expression is just a NULL constant, we treat it
919 * like not having a default.
921 * Note that if the basetype is another domain, we'll see
922 * a CoerceToDomain expr here and not discard the default.
923 * This is critical because the domain default needs to be
924 * retained to override any default that the base domain
925 * might have.
927 if (defaultExpr == NULL ||
928 (IsA(defaultExpr, Const) &&
929 ((Const *) defaultExpr)->constisnull))
931 defaultValue = NULL;
932 defaultValueBin = NULL;
934 else
937 * Expression must be stored as a nodeToString result,
938 * but we also require a valid textual representation
939 * (mainly to make life easier for pg_dump).
941 defaultValue =
942 deparse_expression(defaultExpr,
943 deparse_context_for(domainName,
944 InvalidOid),
945 false, false);
946 defaultValueBin = nodeToString(defaultExpr);
949 else
951 /* No default (can this still happen?) */
952 defaultValue = NULL;
953 defaultValueBin = NULL;
955 break;
957 case CONSTR_NOTNULL:
958 if (nullDefined && !typNotNull)
959 ereport(ERROR,
960 (errcode(ERRCODE_SYNTAX_ERROR),
961 errmsg("conflicting NULL/NOT NULL constraints")));
962 typNotNull = true;
963 nullDefined = true;
964 break;
966 case CONSTR_NULL:
967 if (nullDefined && typNotNull)
968 ereport(ERROR,
969 (errcode(ERRCODE_SYNTAX_ERROR),
970 errmsg("conflicting NULL/NOT NULL constraints")));
971 typNotNull = false;
972 nullDefined = true;
973 break;
975 case CONSTR_CHECK:
978 * Check constraints are handled after domain creation, as
979 * they require the Oid of the domain
981 break;
984 * All else are error cases
986 case CONSTR_UNIQUE:
987 ereport(ERROR,
988 (errcode(ERRCODE_SYNTAX_ERROR),
989 errmsg("unique constraints not possible for domains")));
990 break;
992 case CONSTR_PRIMARY:
993 ereport(ERROR,
994 (errcode(ERRCODE_SYNTAX_ERROR),
995 errmsg("primary key constraints not possible for domains")));
996 break;
998 case CONSTR_ATTR_DEFERRABLE:
999 case CONSTR_ATTR_NOT_DEFERRABLE:
1000 case CONSTR_ATTR_DEFERRED:
1001 case CONSTR_ATTR_IMMEDIATE:
1002 ereport(ERROR,
1003 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1004 errmsg("specifying constraint deferrability not supported for domains")));
1005 break;
1007 default:
1008 elog(ERROR, "unrecognized constraint subtype: %d",
1009 (int) constr->contype);
1010 break;
1015 * Have TypeCreate do all the real work.
1017 domainoid =
1018 TypeCreate(InvalidOid, /* no predetermined type OID */
1019 domainName, /* type name */
1020 domainNamespace, /* namespace */
1021 InvalidOid, /* relation oid (n/a here) */
1022 0, /* relation kind (ditto) */
1023 GetUserId(), /* owner's ID */
1024 internalLength, /* internal size */
1025 TYPTYPE_DOMAIN, /* type-type (domain type) */
1026 category, /* type-category */
1027 false, /* domain types are never preferred */
1028 delimiter, /* array element delimiter */
1029 inputProcedure, /* input procedure */
1030 outputProcedure, /* output procedure */
1031 receiveProcedure, /* receive procedure */
1032 sendProcedure, /* send procedure */
1033 InvalidOid, /* typmodin procedure - none */
1034 InvalidOid, /* typmodout procedure - none */
1035 analyzeProcedure, /* analyze procedure */
1036 typelem, /* element type ID */
1037 false, /* this isn't an array */
1038 InvalidOid, /* no arrays for domains (yet) */
1039 basetypeoid, /* base type ID */
1040 defaultValue, /* default type value (text) */
1041 defaultValueBin, /* default type value (binary) */
1042 byValue, /* passed by value */
1043 alignment, /* required alignment */
1044 storage, /* TOAST strategy */
1045 basetypeMod, /* typeMod value */
1046 typNDims, /* Array dimensions for base type */
1047 typNotNull); /* Type NOT NULL */
1050 * Process constraints which refer to the domain ID returned by TypeCreate
1052 foreach(listptr, schema)
1054 Constraint *constr = lfirst(listptr);
1056 /* it must be a Constraint, per check above */
1058 switch (constr->contype)
1060 case CONSTR_CHECK:
1061 domainAddConstraint(domainoid, domainNamespace,
1062 basetypeoid, basetypeMod,
1063 constr, domainName);
1064 break;
1066 /* Other constraint types were fully processed above */
1068 default:
1069 break;
1072 /* CCI so we can detect duplicate constraint names */
1073 CommandCounterIncrement();
1077 * Now we can clean up.
1079 ReleaseSysCache(typeTup);
1084 * DefineEnum
1085 * Registers a new enum.
1087 void
1088 DefineEnum(CreateEnumStmt *stmt)
1090 char *enumName;
1091 char *enumArrayName;
1092 Oid enumNamespace;
1093 Oid enumTypeOid;
1094 AclResult aclresult;
1095 Oid old_type_oid;
1096 Oid enumArrayOid;
1097 Relation pg_type;
1099 /* Convert list of names to a name and namespace */
1100 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typename,
1101 &enumName);
1103 /* Check we have creation rights in target namespace */
1104 aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1105 if (aclresult != ACLCHECK_OK)
1106 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1107 get_namespace_name(enumNamespace));
1110 * Check for collision with an existing type name. If there is one and
1111 * it's an autogenerated array, we can rename it out of the way.
1113 old_type_oid = GetSysCacheOid(TYPENAMENSP,
1114 CStringGetDatum(enumName),
1115 ObjectIdGetDatum(enumNamespace),
1116 0, 0);
1117 if (OidIsValid(old_type_oid))
1119 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1120 ereport(ERROR,
1121 (errcode(ERRCODE_DUPLICATE_OBJECT),
1122 errmsg("type \"%s\" already exists", enumName)));
1125 /* Preassign array type OID so we can insert it in pg_type.typarray */
1126 pg_type = heap_open(TypeRelationId, AccessShareLock);
1127 enumArrayOid = GetNewOid(pg_type);
1128 heap_close(pg_type, AccessShareLock);
1130 /* Create the pg_type entry */
1131 enumTypeOid =
1132 TypeCreate(InvalidOid, /* no predetermined type OID */
1133 enumName, /* type name */
1134 enumNamespace, /* namespace */
1135 InvalidOid, /* relation oid (n/a here) */
1136 0, /* relation kind (ditto) */
1137 GetUserId(), /* owner's ID */
1138 sizeof(Oid), /* internal size */
1139 TYPTYPE_ENUM, /* type-type (enum type) */
1140 TYPCATEGORY_ENUM, /* type-category (enum type) */
1141 false, /* enum types are never preferred */
1142 DEFAULT_TYPDELIM, /* array element delimiter */
1143 F_ENUM_IN, /* input procedure */
1144 F_ENUM_OUT, /* output procedure */
1145 F_ENUM_RECV, /* receive procedure */
1146 F_ENUM_SEND, /* send procedure */
1147 InvalidOid, /* typmodin procedure - none */
1148 InvalidOid, /* typmodout procedure - none */
1149 InvalidOid, /* analyze procedure - default */
1150 InvalidOid, /* element type ID */
1151 false, /* this is not an array type */
1152 enumArrayOid, /* array type we are about to create */
1153 InvalidOid, /* base type ID (only for domains) */
1154 NULL, /* never a default type value */
1155 NULL, /* binary default isn't sent either */
1156 true, /* always passed by value */
1157 'i', /* int alignment */
1158 'p', /* TOAST strategy always plain */
1159 -1, /* typMod (Domains only) */
1160 0, /* Array dimensions of typbasetype */
1161 false); /* Type NOT NULL */
1163 /* Enter the enum's values into pg_enum */
1164 EnumValuesCreate(enumTypeOid, stmt->vals);
1167 * Create the array type that goes with it.
1169 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1171 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1172 enumArrayName, /* type name */
1173 enumNamespace, /* namespace */
1174 InvalidOid, /* relation oid (n/a here) */
1175 0, /* relation kind (ditto) */
1176 GetUserId(), /* owner's ID */
1177 -1, /* internal size (always varlena) */
1178 TYPTYPE_BASE, /* type-type (base type) */
1179 TYPCATEGORY_ARRAY, /* type-category (array) */
1180 false, /* array types are never preferred */
1181 DEFAULT_TYPDELIM, /* array element delimiter */
1182 F_ARRAY_IN, /* input procedure */
1183 F_ARRAY_OUT, /* output procedure */
1184 F_ARRAY_RECV, /* receive procedure */
1185 F_ARRAY_SEND, /* send procedure */
1186 InvalidOid, /* typmodin procedure - none */
1187 InvalidOid, /* typmodout procedure - none */
1188 InvalidOid, /* analyze procedure - default */
1189 enumTypeOid, /* element type ID */
1190 true, /* yes this is an array type */
1191 InvalidOid, /* no further array type */
1192 InvalidOid, /* base type ID */
1193 NULL, /* never a default type value */
1194 NULL, /* binary default isn't sent either */
1195 false, /* never passed by value */
1196 'i', /* enums have align i, so do their arrays */
1197 'x', /* ARRAY is always toastable */
1198 -1, /* typMod (Domains only) */
1199 0, /* Array dimensions of typbasetype */
1200 false); /* Type NOT NULL */
1202 pfree(enumArrayName);
1207 * Find suitable I/O functions for a type.
1209 * typeOid is the type's OID (which will already exist, if only as a shell
1210 * type).
1213 static Oid
1214 findTypeInputFunction(List *procname, Oid typeOid)
1216 Oid argList[3];
1217 Oid procOid;
1220 * Input functions can take a single argument of type CSTRING, or three
1221 * arguments (string, typioparam OID, typmod).
1223 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1224 * see this, we issue a warning and fix up the pg_proc entry.
1226 argList[0] = CSTRINGOID;
1228 procOid = LookupFuncName(procname, 1, argList, true);
1229 if (OidIsValid(procOid))
1230 return procOid;
1232 argList[1] = OIDOID;
1233 argList[2] = INT4OID;
1235 procOid = LookupFuncName(procname, 3, argList, true);
1236 if (OidIsValid(procOid))
1237 return procOid;
1239 /* No luck, try it with OPAQUE */
1240 argList[0] = OPAQUEOID;
1242 procOid = LookupFuncName(procname, 1, argList, true);
1244 if (!OidIsValid(procOid))
1246 argList[1] = OIDOID;
1247 argList[2] = INT4OID;
1249 procOid = LookupFuncName(procname, 3, argList, true);
1252 if (OidIsValid(procOid))
1254 /* Found, but must complain and fix the pg_proc entry */
1255 ereport(WARNING,
1256 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1257 NameListToString(procname))));
1258 SetFunctionArgType(procOid, 0, CSTRINGOID);
1261 * Need CommandCounterIncrement since DefineType will likely try to
1262 * alter the pg_proc tuple again.
1264 CommandCounterIncrement();
1266 return procOid;
1269 /* Use CSTRING (preferred) in the error message */
1270 argList[0] = CSTRINGOID;
1272 ereport(ERROR,
1273 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1274 errmsg("function %s does not exist",
1275 func_signature_string(procname, 1, argList))));
1277 return InvalidOid; /* keep compiler quiet */
1280 static Oid
1281 findTypeOutputFunction(List *procname, Oid typeOid)
1283 Oid argList[1];
1284 Oid procOid;
1287 * Output functions can take a single argument of the type.
1289 * For backwards compatibility we allow OPAQUE in place of the actual type
1290 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1292 argList[0] = typeOid;
1294 procOid = LookupFuncName(procname, 1, argList, true);
1295 if (OidIsValid(procOid))
1296 return procOid;
1298 /* No luck, try it with OPAQUE */
1299 argList[0] = OPAQUEOID;
1301 procOid = LookupFuncName(procname, 1, argList, true);
1303 if (OidIsValid(procOid))
1305 /* Found, but must complain and fix the pg_proc entry */
1306 ereport(WARNING,
1307 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1308 NameListToString(procname), format_type_be(typeOid))));
1309 SetFunctionArgType(procOid, 0, typeOid);
1312 * Need CommandCounterIncrement since DefineType will likely try to
1313 * alter the pg_proc tuple again.
1315 CommandCounterIncrement();
1317 return procOid;
1320 /* Use type name, not OPAQUE, in the failure message. */
1321 argList[0] = typeOid;
1323 ereport(ERROR,
1324 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1325 errmsg("function %s does not exist",
1326 func_signature_string(procname, 1, argList))));
1328 return InvalidOid; /* keep compiler quiet */
1331 static Oid
1332 findTypeReceiveFunction(List *procname, Oid typeOid)
1334 Oid argList[3];
1335 Oid procOid;
1338 * Receive functions can take a single argument of type INTERNAL, or three
1339 * arguments (internal, typioparam OID, typmod).
1341 argList[0] = INTERNALOID;
1343 procOid = LookupFuncName(procname, 1, argList, true);
1344 if (OidIsValid(procOid))
1345 return procOid;
1347 argList[1] = OIDOID;
1348 argList[2] = INT4OID;
1350 procOid = LookupFuncName(procname, 3, argList, true);
1351 if (OidIsValid(procOid))
1352 return procOid;
1354 ereport(ERROR,
1355 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1356 errmsg("function %s does not exist",
1357 func_signature_string(procname, 1, argList))));
1359 return InvalidOid; /* keep compiler quiet */
1362 static Oid
1363 findTypeSendFunction(List *procname, Oid typeOid)
1365 Oid argList[1];
1366 Oid procOid;
1369 * Send functions can take a single argument of the type.
1371 argList[0] = typeOid;
1373 procOid = LookupFuncName(procname, 1, argList, true);
1374 if (OidIsValid(procOid))
1375 return procOid;
1377 ereport(ERROR,
1378 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1379 errmsg("function %s does not exist",
1380 func_signature_string(procname, 1, argList))));
1382 return InvalidOid; /* keep compiler quiet */
1385 static Oid
1386 findTypeTypmodinFunction(List *procname)
1388 Oid argList[1];
1389 Oid procOid;
1392 * typmodin functions always take one cstring[] argument and return int4.
1394 argList[0] = CSTRINGARRAYOID;
1396 procOid = LookupFuncName(procname, 1, argList, true);
1397 if (!OidIsValid(procOid))
1398 ereport(ERROR,
1399 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1400 errmsg("function %s does not exist",
1401 func_signature_string(procname, 1, argList))));
1403 if (get_func_rettype(procOid) != INT4OID)
1404 ereport(ERROR,
1405 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1406 errmsg("typmod_in function %s must return type \"integer\"",
1407 NameListToString(procname))));
1409 return procOid;
1412 static Oid
1413 findTypeTypmodoutFunction(List *procname)
1415 Oid argList[1];
1416 Oid procOid;
1419 * typmodout functions always take one int4 argument and return cstring.
1421 argList[0] = INT4OID;
1423 procOid = LookupFuncName(procname, 1, argList, true);
1424 if (!OidIsValid(procOid))
1425 ereport(ERROR,
1426 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1427 errmsg("function %s does not exist",
1428 func_signature_string(procname, 1, argList))));
1430 if (get_func_rettype(procOid) != CSTRINGOID)
1431 ereport(ERROR,
1432 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1433 errmsg("typmod_out function %s must return type \"cstring\"",
1434 NameListToString(procname))));
1436 return procOid;
1439 static Oid
1440 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1442 Oid argList[1];
1443 Oid procOid;
1446 * Analyze functions always take one INTERNAL argument and return bool.
1448 argList[0] = INTERNALOID;
1450 procOid = LookupFuncName(procname, 1, argList, true);
1451 if (!OidIsValid(procOid))
1452 ereport(ERROR,
1453 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1454 errmsg("function %s does not exist",
1455 func_signature_string(procname, 1, argList))));
1457 if (get_func_rettype(procOid) != BOOLOID)
1458 ereport(ERROR,
1459 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1460 errmsg("type analyze function %s must return type \"boolean\"",
1461 NameListToString(procname))));
1463 return procOid;
1467 /*-------------------------------------------------------------------
1468 * DefineCompositeType
1470 * Create a Composite Type relation.
1471 * `DefineRelation' does all the work, we just provide the correct
1472 * arguments!
1474 * If the relation already exists, then 'DefineRelation' will abort
1475 * the xact...
1477 * DefineCompositeType returns relid for use when creating
1478 * an implicit composite type during function creation
1479 *-------------------------------------------------------------------
1482 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1484 CreateStmt *createStmt = makeNode(CreateStmt);
1486 if (coldeflist == NIL)
1487 ereport(ERROR,
1488 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1489 errmsg("composite type must have at least one attribute")));
1492 * now set the parameters for keys/inheritance etc. All of these are
1493 * uninteresting for composite types...
1495 createStmt->relation = (RangeVar *) typevar;
1496 createStmt->tableElts = coldeflist;
1497 createStmt->inhRelations = NIL;
1498 createStmt->constraints = NIL;
1499 createStmt->options = list_make1(defWithOids(false));
1500 createStmt->oncommit = ONCOMMIT_NOOP;
1501 createStmt->tablespacename = NULL;
1504 * finally create the relation...
1506 return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);
1510 * AlterDomainDefault
1512 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
1514 void
1515 AlterDomainDefault(List *names, Node *defaultRaw)
1517 TypeName *typename;
1518 Oid domainoid;
1519 HeapTuple tup;
1520 ParseState *pstate;
1521 Relation rel;
1522 char *defaultValue;
1523 Node *defaultExpr = NULL; /* NULL if no default specified */
1524 Datum new_record[Natts_pg_type];
1525 bool new_record_nulls[Natts_pg_type];
1526 bool new_record_repl[Natts_pg_type];
1527 HeapTuple newtuple;
1528 Form_pg_type typTup;
1530 /* Make a TypeName so we can use standard type lookup machinery */
1531 typename = makeTypeNameFromNameList(names);
1532 domainoid = typenameTypeId(NULL, typename, NULL);
1534 /* Look up the domain in the type table */
1535 rel = heap_open(TypeRelationId, RowExclusiveLock);
1537 tup = SearchSysCacheCopy(TYPEOID,
1538 ObjectIdGetDatum(domainoid),
1539 0, 0, 0);
1540 if (!HeapTupleIsValid(tup))
1541 elog(ERROR, "cache lookup failed for type %u", domainoid);
1542 typTup = (Form_pg_type) GETSTRUCT(tup);
1544 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1545 checkDomainOwner(tup, typename);
1547 /* Setup new tuple */
1548 MemSet(new_record, (Datum) 0, sizeof(new_record));
1549 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1550 MemSet(new_record_repl, false, sizeof(new_record_repl));
1552 /* Store the new default into the tuple */
1553 if (defaultRaw)
1555 /* Create a dummy ParseState for transformExpr */
1556 pstate = make_parsestate(NULL);
1559 * Cook the colDef->raw_expr into an expression. Note: Name is
1560 * strictly for error message
1562 defaultExpr = cookDefault(pstate, defaultRaw,
1563 typTup->typbasetype,
1564 typTup->typtypmod,
1565 NameStr(typTup->typname));
1568 * If the expression is just a NULL constant, we treat the command
1569 * like ALTER ... DROP DEFAULT. (But see note for same test in
1570 * DefineDomain.)
1572 if (defaultExpr == NULL ||
1573 (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
1575 /* Default is NULL, drop it */
1576 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
1577 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1578 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
1579 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1581 else
1584 * Expression must be stored as a nodeToString result, but we also
1585 * require a valid textual representation (mainly to make life
1586 * easier for pg_dump).
1588 defaultValue = deparse_expression(defaultExpr,
1589 deparse_context_for(NameStr(typTup->typname),
1590 InvalidOid),
1591 false, false);
1594 * Form an updated tuple with the new default and write it back.
1596 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
1598 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1599 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
1600 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1603 else
1605 /* ALTER ... DROP DEFAULT */
1606 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
1607 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
1608 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
1609 new_record_repl[Anum_pg_type_typdefault - 1] = true;
1612 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
1613 new_record, new_record_nulls,
1614 new_record_repl);
1616 simple_heap_update(rel, &tup->t_self, newtuple);
1618 CatalogUpdateIndexes(rel, newtuple);
1620 /* Rebuild dependencies */
1621 GenerateTypeDependencies(typTup->typnamespace,
1622 domainoid,
1623 InvalidOid, /* typrelid is n/a */
1624 0, /* relation kind is n/a */
1625 typTup->typowner,
1626 typTup->typinput,
1627 typTup->typoutput,
1628 typTup->typreceive,
1629 typTup->typsend,
1630 typTup->typmodin,
1631 typTup->typmodout,
1632 typTup->typanalyze,
1633 typTup->typelem,
1634 false, /* a domain isn't an implicit array */
1635 typTup->typbasetype,
1636 defaultExpr,
1637 true); /* Rebuild is true */
1639 /* Clean up */
1640 heap_close(rel, NoLock);
1641 heap_freetuple(newtuple);
1645 * AlterDomainNotNull
1647 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
1649 void
1650 AlterDomainNotNull(List *names, bool notNull)
1652 TypeName *typename;
1653 Oid domainoid;
1654 Relation typrel;
1655 HeapTuple tup;
1656 Form_pg_type typTup;
1658 /* Make a TypeName so we can use standard type lookup machinery */
1659 typename = makeTypeNameFromNameList(names);
1660 domainoid = typenameTypeId(NULL, typename, NULL);
1662 /* Look up the domain in the type table */
1663 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1665 tup = SearchSysCacheCopy(TYPEOID,
1666 ObjectIdGetDatum(domainoid),
1667 0, 0, 0);
1668 if (!HeapTupleIsValid(tup))
1669 elog(ERROR, "cache lookup failed for type %u", domainoid);
1670 typTup = (Form_pg_type) GETSTRUCT(tup);
1672 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1673 checkDomainOwner(tup, typename);
1675 /* Is the domain already set to the desired constraint? */
1676 if (typTup->typnotnull == notNull)
1678 heap_close(typrel, RowExclusiveLock);
1679 return;
1682 /* Adding a NOT NULL constraint requires checking existing columns */
1683 if (notNull)
1685 List *rels;
1686 ListCell *rt;
1688 /* Fetch relation list with attributes based on this domain */
1689 /* ShareLock is sufficient to prevent concurrent data changes */
1691 rels = get_rels_with_domain(domainoid, ShareLock);
1693 foreach(rt, rels)
1695 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1696 Relation testrel = rtc->rel;
1697 TupleDesc tupdesc = RelationGetDescr(testrel);
1698 HeapScanDesc scan;
1699 HeapTuple tuple;
1701 /* Scan all tuples in this relation */
1702 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1703 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1705 int i;
1707 /* Test attributes that are of the domain */
1708 for (i = 0; i < rtc->natts; i++)
1710 int attnum = rtc->atts[i];
1712 if (heap_attisnull(tuple, attnum))
1713 ereport(ERROR,
1714 (errcode(ERRCODE_NOT_NULL_VIOLATION),
1715 errmsg("column \"%s\" of table \"%s\" contains null values",
1716 NameStr(tupdesc->attrs[attnum - 1]->attname),
1717 RelationGetRelationName(testrel))));
1720 heap_endscan(scan);
1722 /* Close each rel after processing, but keep lock */
1723 heap_close(testrel, NoLock);
1728 * Okay to update pg_type row. We can scribble on typTup because it's a
1729 * copy.
1731 typTup->typnotnull = notNull;
1733 simple_heap_update(typrel, &tup->t_self, tup);
1735 CatalogUpdateIndexes(typrel, tup);
1737 /* Clean up */
1738 heap_freetuple(tup);
1739 heap_close(typrel, RowExclusiveLock);
1743 * AlterDomainDropConstraint
1745 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
1747 void
1748 AlterDomainDropConstraint(List *names, const char *constrName,
1749 DropBehavior behavior)
1751 TypeName *typename;
1752 Oid domainoid;
1753 HeapTuple tup;
1754 Relation rel;
1755 Relation conrel;
1756 SysScanDesc conscan;
1757 ScanKeyData key[1];
1758 HeapTuple contup;
1760 /* Make a TypeName so we can use standard type lookup machinery */
1761 typename = makeTypeNameFromNameList(names);
1762 domainoid = typenameTypeId(NULL, typename, NULL);
1764 /* Look up the domain in the type table */
1765 rel = heap_open(TypeRelationId, RowExclusiveLock);
1767 tup = SearchSysCacheCopy(TYPEOID,
1768 ObjectIdGetDatum(domainoid),
1769 0, 0, 0);
1770 if (!HeapTupleIsValid(tup))
1771 elog(ERROR, "cache lookup failed for type %u", domainoid);
1773 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1774 checkDomainOwner(tup, typename);
1776 /* Grab an appropriate lock on the pg_constraint relation */
1777 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
1779 /* Use the index to scan only constraints of the target relation */
1780 ScanKeyInit(&key[0],
1781 Anum_pg_constraint_contypid,
1782 BTEqualStrategyNumber, F_OIDEQ,
1783 ObjectIdGetDatum(HeapTupleGetOid(tup)));
1785 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
1786 SnapshotNow, 1, key);
1789 * Scan over the result set, removing any matching entries.
1791 while ((contup = systable_getnext(conscan)) != NULL)
1793 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
1795 if (strcmp(NameStr(con->conname), constrName) == 0)
1797 ObjectAddress conobj;
1799 conobj.classId = ConstraintRelationId;
1800 conobj.objectId = HeapTupleGetOid(contup);
1801 conobj.objectSubId = 0;
1803 performDeletion(&conobj, behavior);
1806 /* Clean up after the scan */
1807 systable_endscan(conscan);
1808 heap_close(conrel, RowExclusiveLock);
1810 heap_close(rel, NoLock);
1814 * AlterDomainAddConstraint
1816 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
1818 void
1819 AlterDomainAddConstraint(List *names, Node *newConstraint)
1821 TypeName *typename;
1822 Oid domainoid;
1823 Relation typrel;
1824 HeapTuple tup;
1825 Form_pg_type typTup;
1826 List *rels;
1827 ListCell *rt;
1828 EState *estate;
1829 ExprContext *econtext;
1830 char *ccbin;
1831 Expr *expr;
1832 ExprState *exprstate;
1833 Constraint *constr;
1835 /* Make a TypeName so we can use standard type lookup machinery */
1836 typename = makeTypeNameFromNameList(names);
1837 domainoid = typenameTypeId(NULL, typename, NULL);
1839 /* Look up the domain in the type table */
1840 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1842 tup = SearchSysCacheCopy(TYPEOID,
1843 ObjectIdGetDatum(domainoid),
1844 0, 0, 0);
1845 if (!HeapTupleIsValid(tup))
1846 elog(ERROR, "cache lookup failed for type %u", domainoid);
1847 typTup = (Form_pg_type) GETSTRUCT(tup);
1849 /* Check it's a domain and check user has permission for ALTER DOMAIN */
1850 checkDomainOwner(tup, typename);
1852 /* Check for unsupported constraint types */
1853 if (IsA(newConstraint, FkConstraint))
1854 ereport(ERROR,
1855 (errcode(ERRCODE_SYNTAX_ERROR),
1856 errmsg("foreign key constraints not possible for domains")));
1858 /* otherwise it should be a plain Constraint */
1859 if (!IsA(newConstraint, Constraint))
1860 elog(ERROR, "unrecognized node type: %d",
1861 (int) nodeTag(newConstraint));
1863 constr = (Constraint *) newConstraint;
1865 switch (constr->contype)
1867 case CONSTR_CHECK:
1868 /* processed below */
1869 break;
1871 case CONSTR_UNIQUE:
1872 ereport(ERROR,
1873 (errcode(ERRCODE_SYNTAX_ERROR),
1874 errmsg("unique constraints not possible for domains")));
1875 break;
1877 case CONSTR_PRIMARY:
1878 ereport(ERROR,
1879 (errcode(ERRCODE_SYNTAX_ERROR),
1880 errmsg("primary key constraints not possible for domains")));
1881 break;
1883 case CONSTR_ATTR_DEFERRABLE:
1884 case CONSTR_ATTR_NOT_DEFERRABLE:
1885 case CONSTR_ATTR_DEFERRED:
1886 case CONSTR_ATTR_IMMEDIATE:
1887 ereport(ERROR,
1888 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1889 errmsg("specifying constraint deferrability not supported for domains")));
1890 break;
1892 default:
1893 elog(ERROR, "unrecognized constraint subtype: %d",
1894 (int) constr->contype);
1895 break;
1899 * Since all other constraint types throw errors, this must be a check
1900 * constraint. First, process the constraint expression and add an entry
1901 * to pg_constraint.
1904 ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
1905 typTup->typbasetype, typTup->typtypmod,
1906 constr, NameStr(typTup->typname));
1909 * Test all values stored in the attributes based on the domain the
1910 * constraint is being added to.
1912 expr = (Expr *) stringToNode(ccbin);
1914 /* Need an EState to run ExecEvalExpr */
1915 estate = CreateExecutorState();
1916 econtext = GetPerTupleExprContext(estate);
1918 /* build execution state for expr */
1919 exprstate = ExecPrepareExpr(expr, estate);
1921 /* Fetch relation list with attributes based on this domain */
1922 /* ShareLock is sufficient to prevent concurrent data changes */
1924 rels = get_rels_with_domain(domainoid, ShareLock);
1926 foreach(rt, rels)
1928 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1929 Relation testrel = rtc->rel;
1930 TupleDesc tupdesc = RelationGetDescr(testrel);
1931 HeapScanDesc scan;
1932 HeapTuple tuple;
1934 /* Scan all tuples in this relation */
1935 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1936 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1938 int i;
1940 /* Test attributes that are of the domain */
1941 for (i = 0; i < rtc->natts; i++)
1943 int attnum = rtc->atts[i];
1944 Datum d;
1945 bool isNull;
1946 Datum conResult;
1948 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
1950 econtext->domainValue_datum = d;
1951 econtext->domainValue_isNull = isNull;
1953 conResult = ExecEvalExprSwitchContext(exprstate,
1954 econtext,
1955 &isNull, NULL);
1957 if (!isNull && !DatumGetBool(conResult))
1958 ereport(ERROR,
1959 (errcode(ERRCODE_CHECK_VIOLATION),
1960 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
1961 NameStr(tupdesc->attrs[attnum - 1]->attname),
1962 RelationGetRelationName(testrel))));
1965 ResetExprContext(econtext);
1967 heap_endscan(scan);
1969 /* Hold relation lock till commit (XXX bad for concurrency) */
1970 heap_close(testrel, NoLock);
1973 FreeExecutorState(estate);
1975 /* Clean up */
1976 heap_close(typrel, RowExclusiveLock);
1980 * get_rels_with_domain
1982 * Fetch all relations / attributes which are using the domain
1984 * The result is a list of RelToCheck structs, one for each distinct
1985 * relation, each containing one or more attribute numbers that are of
1986 * the domain type. We have opened each rel and acquired the specified lock
1987 * type on it.
1989 * We support nested domains by including attributes that are of derived
1990 * domain types. Current callers do not need to distinguish between attributes
1991 * that are of exactly the given domain and those that are of derived domains.
1993 * XXX this is completely broken because there is no way to lock the domain
1994 * to prevent columns from being added or dropped while our command runs.
1995 * We can partially protect against column drops by locking relations as we
1996 * come across them, but there is still a race condition (the window between
1997 * seeing a pg_depend entry and acquiring lock on the relation it references).
1998 * Also, holding locks on all these relations simultaneously creates a non-
1999 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
2000 * risk by using the weakest suitable lock (ShareLock for most callers).
2002 * XXX the API for this is not sufficient to support checking domain values
2003 * that are inside composite types or arrays. Currently we just error out
2004 * if a composite type containing the target domain is stored anywhere.
2005 * There are not currently arrays of domains; if there were, we could take
2006 * the same approach, but it'd be nicer to fix it properly.
2008 * Generally used for retrieving a list of tests when adding
2009 * new constraints to a domain.
2011 static List *
2012 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2014 List *result = NIL;
2015 Relation depRel;
2016 ScanKeyData key[2];
2017 SysScanDesc depScan;
2018 HeapTuple depTup;
2020 Assert(lockmode != NoLock);
2023 * We scan pg_depend to find those things that depend on the domain. (We
2024 * assume we can ignore refobjsubid for a domain.)
2026 depRel = heap_open(DependRelationId, AccessShareLock);
2028 ScanKeyInit(&key[0],
2029 Anum_pg_depend_refclassid,
2030 BTEqualStrategyNumber, F_OIDEQ,
2031 ObjectIdGetDatum(TypeRelationId));
2032 ScanKeyInit(&key[1],
2033 Anum_pg_depend_refobjid,
2034 BTEqualStrategyNumber, F_OIDEQ,
2035 ObjectIdGetDatum(domainOid));
2037 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2038 SnapshotNow, 2, key);
2040 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2042 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2043 RelToCheck *rtc = NULL;
2044 ListCell *rellist;
2045 Form_pg_attribute pg_att;
2046 int ptr;
2048 /* Check for directly dependent types --- must be domains */
2049 if (pg_depend->classid == TypeRelationId)
2051 Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2054 * Recursively add dependent columns to the output list. This is
2055 * a bit inefficient since we may fail to combine RelToCheck
2056 * entries when attributes of the same rel have different derived
2057 * domain types, but it's probably not worth improving.
2059 result = list_concat(result,
2060 get_rels_with_domain(pg_depend->objid,
2061 lockmode));
2062 continue;
2065 /* Else, ignore dependees that aren't user columns of relations */
2066 /* (we assume system columns are never of domain types) */
2067 if (pg_depend->classid != RelationRelationId ||
2068 pg_depend->objsubid <= 0)
2069 continue;
2071 /* See if we already have an entry for this relation */
2072 foreach(rellist, result)
2074 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2076 if (RelationGetRelid(rt->rel) == pg_depend->objid)
2078 rtc = rt;
2079 break;
2083 if (rtc == NULL)
2085 /* First attribute found for this relation */
2086 Relation rel;
2088 /* Acquire requested lock on relation */
2089 rel = relation_open(pg_depend->objid, lockmode);
2092 * Check to see if rowtype is stored anyplace as a composite-type
2093 * column; if so we have to fail, for now anyway.
2095 if (OidIsValid(rel->rd_rel->reltype))
2096 find_composite_type_dependencies(rel->rd_rel->reltype,
2097 NULL,
2098 format_type_be(domainOid));
2100 /* Otherwise we can ignore views, composite types, etc */
2101 if (rel->rd_rel->relkind != RELKIND_RELATION)
2103 relation_close(rel, lockmode);
2104 continue;
2107 /* Build the RelToCheck entry with enough space for all atts */
2108 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2109 rtc->rel = rel;
2110 rtc->natts = 0;
2111 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2112 result = lcons(rtc, result);
2116 * Confirm column has not been dropped, and is of the expected type.
2117 * This defends against an ALTER DROP COLUMN occuring just before we
2118 * acquired lock ... but if the whole table were dropped, we'd still
2119 * have a problem.
2121 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2122 continue;
2123 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2124 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2125 continue;
2128 * Okay, add column to result. We store the columns in column-number
2129 * order; this is just a hack to improve predictability of regression
2130 * test output ...
2132 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2134 ptr = rtc->natts++;
2135 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2137 rtc->atts[ptr] = rtc->atts[ptr - 1];
2138 ptr--;
2140 rtc->atts[ptr] = pg_depend->objsubid;
2143 systable_endscan(depScan);
2145 relation_close(depRel, AccessShareLock);
2147 return result;
2151 * checkDomainOwner
2153 * Check that the type is actually a domain and that the current user
2154 * has permission to do ALTER DOMAIN on it. Throw an error if not.
2156 static void
2157 checkDomainOwner(HeapTuple tup, TypeName *typename)
2159 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2161 /* Check that this is actually a domain */
2162 if (typTup->typtype != TYPTYPE_DOMAIN)
2163 ereport(ERROR,
2164 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2165 errmsg("\"%s\" is not a domain",
2166 TypeNameToString(typename))));
2168 /* Permission check: must own type */
2169 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2170 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2171 format_type_be(HeapTupleGetOid(tup)));
2175 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2177 static char *
2178 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2179 int typMod, Constraint *constr,
2180 char *domainName)
2182 Node *expr;
2183 char *ccsrc;
2184 char *ccbin;
2185 ParseState *pstate;
2186 CoerceToDomainValue *domVal;
2189 * Assign or validate constraint name
2191 if (constr->name)
2193 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2194 domainOid,
2195 domainNamespace,
2196 constr->name))
2197 ereport(ERROR,
2198 (errcode(ERRCODE_DUPLICATE_OBJECT),
2199 errmsg("constraint \"%s\" for domain \"%s\" already exists",
2200 constr->name, domainName)));
2202 else
2203 constr->name = ChooseConstraintName(domainName,
2204 NULL,
2205 "check",
2206 domainNamespace,
2207 NIL);
2210 * Convert the A_EXPR in raw_expr into an EXPR
2212 pstate = make_parsestate(NULL);
2215 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2216 * the expression. Note that it will appear to have the type of the base
2217 * type, not the domain. This seems correct since within the check
2218 * expression, we should not assume the input value can be considered a
2219 * member of the domain.
2221 domVal = makeNode(CoerceToDomainValue);
2222 domVal->typeId = baseTypeOid;
2223 domVal->typeMod = typMod;
2224 domVal->location = -1; /* will be set when/if used */
2226 pstate->p_value_substitute = (Node *) domVal;
2228 expr = transformExpr(pstate, constr->raw_expr);
2231 * Make sure it yields a boolean result.
2233 expr = coerce_to_boolean(pstate, expr, "CHECK");
2236 * Make sure no outside relations are referred to.
2238 if (list_length(pstate->p_rtable) != 0)
2239 ereport(ERROR,
2240 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2241 errmsg("cannot use table references in domain check constraint")));
2244 * Domains don't allow var clauses (this should be redundant with the
2245 * above check, but make it anyway)
2247 if (contain_var_clause(expr))
2248 ereport(ERROR,
2249 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2250 errmsg("cannot use table references in domain check constraint")));
2253 * No subplans or aggregates, either...
2255 if (pstate->p_hasSubLinks)
2256 ereport(ERROR,
2257 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2258 errmsg("cannot use subquery in check constraint")));
2259 if (pstate->p_hasAggs)
2260 ereport(ERROR,
2261 (errcode(ERRCODE_GROUPING_ERROR),
2262 errmsg("cannot use aggregate function in check constraint")));
2263 if (pstate->p_hasWindowFuncs)
2264 ereport(ERROR,
2265 (errcode(ERRCODE_WINDOWING_ERROR),
2266 errmsg("cannot use window function in check constraint")));
2269 * Convert to string form for storage.
2271 ccbin = nodeToString(expr);
2274 * Deparse it to produce text for consrc.
2276 * Since VARNOs aren't allowed in domain constraints, relation context
2277 * isn't required as anything other than a shell.
2279 ccsrc = deparse_expression(expr,
2280 deparse_context_for(domainName,
2281 InvalidOid),
2282 false, false);
2285 * Store the constraint in pg_constraint
2287 CreateConstraintEntry(constr->name, /* Constraint Name */
2288 domainNamespace, /* namespace */
2289 CONSTRAINT_CHECK, /* Constraint Type */
2290 false, /* Is Deferrable */
2291 false, /* Is Deferred */
2292 InvalidOid, /* not a relation constraint */
2293 NULL,
2295 domainOid, /* domain constraint */
2296 InvalidOid, /* Foreign key fields */
2297 NULL,
2298 NULL,
2299 NULL,
2300 NULL,
2302 ' ',
2303 ' ',
2304 ' ',
2305 InvalidOid,
2306 expr, /* Tree form check constraint */
2307 ccbin, /* Binary form check constraint */
2308 ccsrc, /* Source form check constraint */
2309 true, /* is local */
2310 0); /* inhcount */
2313 * Return the compiled constraint expression so the calling routine can
2314 * perform any additional required tests.
2316 return ccbin;
2320 * GetDomainConstraints - get a list of the current constraints of domain
2322 * Returns a possibly-empty list of DomainConstraintState nodes.
2324 * This is called by the executor during plan startup for a CoerceToDomain
2325 * expression node. The given constraints will be checked for each value
2326 * passed through the node.
2328 * We allow this to be called for non-domain types, in which case the result
2329 * is always NIL.
2331 List *
2332 GetDomainConstraints(Oid typeOid)
2334 List *result = NIL;
2335 bool notNull = false;
2336 Relation conRel;
2338 conRel = heap_open(ConstraintRelationId, AccessShareLock);
2340 for (;;)
2342 HeapTuple tup;
2343 HeapTuple conTup;
2344 Form_pg_type typTup;
2345 ScanKeyData key[1];
2346 SysScanDesc scan;
2348 tup = SearchSysCache(TYPEOID,
2349 ObjectIdGetDatum(typeOid),
2350 0, 0, 0);
2351 if (!HeapTupleIsValid(tup))
2352 elog(ERROR, "cache lookup failed for type %u", typeOid);
2353 typTup = (Form_pg_type) GETSTRUCT(tup);
2355 if (typTup->typtype != TYPTYPE_DOMAIN)
2357 /* Not a domain, so done */
2358 ReleaseSysCache(tup);
2359 break;
2362 /* Test for NOT NULL Constraint */
2363 if (typTup->typnotnull)
2364 notNull = true;
2366 /* Look for CHECK Constraints on this domain */
2367 ScanKeyInit(&key[0],
2368 Anum_pg_constraint_contypid,
2369 BTEqualStrategyNumber, F_OIDEQ,
2370 ObjectIdGetDatum(typeOid));
2372 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
2373 SnapshotNow, 1, key);
2375 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
2377 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
2378 Datum val;
2379 bool isNull;
2380 Expr *check_expr;
2381 DomainConstraintState *r;
2383 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
2384 if (c->contype != CONSTRAINT_CHECK)
2385 continue;
2388 * Not expecting conbin to be NULL, but we'll test for it anyway
2390 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
2391 conRel->rd_att, &isNull);
2392 if (isNull)
2393 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
2394 NameStr(typTup->typname), NameStr(c->conname));
2396 check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
2398 /* ExecInitExpr assumes we've planned the expression */
2399 check_expr = expression_planner(check_expr);
2401 r = makeNode(DomainConstraintState);
2402 r->constrainttype = DOM_CONSTRAINT_CHECK;
2403 r->name = pstrdup(NameStr(c->conname));
2404 r->check_expr = ExecInitExpr(check_expr, NULL);
2407 * use lcons() here because constraints of lower domains should be
2408 * applied earlier.
2410 result = lcons(r, result);
2413 systable_endscan(scan);
2415 /* loop to next domain in stack */
2416 typeOid = typTup->typbasetype;
2417 ReleaseSysCache(tup);
2420 heap_close(conRel, AccessShareLock);
2423 * Only need to add one NOT NULL check regardless of how many domains in
2424 * the stack request it.
2426 if (notNull)
2428 DomainConstraintState *r = makeNode(DomainConstraintState);
2430 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
2431 r->name = pstrdup("NOT NULL");
2432 r->check_expr = NULL;
2434 /* lcons to apply the nullness check FIRST */
2435 result = lcons(r, result);
2438 return result;
2443 * Execute ALTER TYPE RENAME
2445 void
2446 RenameType(List *names, const char *newTypeName)
2448 TypeName *typename;
2449 Oid typeOid;
2450 Relation rel;
2451 HeapTuple tup;
2452 Form_pg_type typTup;
2454 /* Make a TypeName so we can use standard type lookup machinery */
2455 typename = makeTypeNameFromNameList(names);
2456 typeOid = typenameTypeId(NULL, typename, NULL);
2458 /* Look up the type in the type table */
2459 rel = heap_open(TypeRelationId, RowExclusiveLock);
2461 tup = SearchSysCacheCopy(TYPEOID,
2462 ObjectIdGetDatum(typeOid),
2463 0, 0, 0);
2464 if (!HeapTupleIsValid(tup))
2465 elog(ERROR, "cache lookup failed for type %u", typeOid);
2466 typTup = (Form_pg_type) GETSTRUCT(tup);
2468 /* check permissions on type */
2469 if (!pg_type_ownercheck(typeOid, GetUserId()))
2470 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2471 format_type_be(typeOid));
2474 * If it's a composite type, we need to check that it really is a
2475 * free-standing composite type, and not a table's rowtype. We want people
2476 * to use ALTER TABLE not ALTER TYPE for that case.
2478 if (typTup->typtype == TYPTYPE_COMPOSITE &&
2479 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2480 ereport(ERROR,
2481 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2482 errmsg("%s is a table's row type",
2483 format_type_be(typeOid)),
2484 errhint("Use ALTER TABLE instead.")));
2486 /* don't allow direct alteration of array types, either */
2487 if (OidIsValid(typTup->typelem) &&
2488 get_array_type(typTup->typelem) == typeOid)
2489 ereport(ERROR,
2490 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2491 errmsg("cannot alter array type %s",
2492 format_type_be(typeOid)),
2493 errhint("You can alter type %s, which will alter the array type as well.",
2494 format_type_be(typTup->typelem))));
2497 * If type is composite we need to rename associated pg_class entry too.
2498 * RenameRelationInternal will call RenameTypeInternal automatically.
2500 if (typTup->typtype == TYPTYPE_COMPOSITE)
2501 RenameRelationInternal(typTup->typrelid, newTypeName,
2502 typTup->typnamespace);
2503 else
2504 RenameTypeInternal(typeOid, newTypeName,
2505 typTup->typnamespace);
2507 /* Clean up */
2508 heap_close(rel, RowExclusiveLock);
2512 * Change the owner of a type.
2514 void
2515 AlterTypeOwner(List *names, Oid newOwnerId)
2517 TypeName *typename;
2518 Oid typeOid;
2519 Relation rel;
2520 HeapTuple tup;
2521 HeapTuple newtup;
2522 Form_pg_type typTup;
2523 AclResult aclresult;
2525 rel = heap_open(TypeRelationId, RowExclusiveLock);
2527 /* Make a TypeName so we can use standard type lookup machinery */
2528 typename = makeTypeNameFromNameList(names);
2530 /* Use LookupTypeName here so that shell types can be processed */
2531 tup = LookupTypeName(NULL, typename, NULL);
2532 if (tup == NULL)
2533 ereport(ERROR,
2534 (errcode(ERRCODE_UNDEFINED_OBJECT),
2535 errmsg("type \"%s\" does not exist",
2536 TypeNameToString(typename))));
2537 typeOid = typeTypeId(tup);
2539 /* Copy the syscache entry so we can scribble on it below */
2540 newtup = heap_copytuple(tup);
2541 ReleaseSysCache(tup);
2542 tup = newtup;
2543 typTup = (Form_pg_type) GETSTRUCT(tup);
2546 * If it's a composite type, we need to check that it really is a
2547 * free-standing composite type, and not a table's rowtype. We want people
2548 * to use ALTER TABLE not ALTER TYPE for that case.
2550 if (typTup->typtype == TYPTYPE_COMPOSITE &&
2551 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2552 ereport(ERROR,
2553 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2554 errmsg("%s is a table's row type",
2555 format_type_be(typeOid)),
2556 errhint("Use ALTER TABLE instead.")));
2558 /* don't allow direct alteration of array types, either */
2559 if (OidIsValid(typTup->typelem) &&
2560 get_array_type(typTup->typelem) == typeOid)
2561 ereport(ERROR,
2562 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2563 errmsg("cannot alter array type %s",
2564 format_type_be(typeOid)),
2565 errhint("You can alter type %s, which will alter the array type as well.",
2566 format_type_be(typTup->typelem))));
2569 * If the new owner is the same as the existing owner, consider the
2570 * command to have succeeded. This is for dump restoration purposes.
2572 if (typTup->typowner != newOwnerId)
2574 /* Superusers can always do it */
2575 if (!superuser())
2577 /* Otherwise, must be owner of the existing object */
2578 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2579 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2580 format_type_be(HeapTupleGetOid(tup)));
2582 /* Must be able to become new owner */
2583 check_is_member_of_role(GetUserId(), newOwnerId);
2585 /* New owner must have CREATE privilege on namespace */
2586 aclresult = pg_namespace_aclcheck(typTup->typnamespace,
2587 newOwnerId,
2588 ACL_CREATE);
2589 if (aclresult != ACLCHECK_OK)
2590 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
2591 get_namespace_name(typTup->typnamespace));
2595 * If it's a composite type, invoke ATExecChangeOwner so that we fix
2596 * up the pg_class entry properly. That will call back to
2597 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
2599 if (typTup->typtype == TYPTYPE_COMPOSITE)
2600 ATExecChangeOwner(typTup->typrelid, newOwnerId, true);
2601 else
2604 * We can just apply the modification directly.
2606 * okay to scribble on typTup because it's a copy
2608 typTup->typowner = newOwnerId;
2610 simple_heap_update(rel, &tup->t_self, tup);
2612 CatalogUpdateIndexes(rel, tup);
2614 /* Update owner dependency reference */
2615 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2617 /* If it has an array type, update that too */
2618 if (OidIsValid(typTup->typarray))
2619 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
2623 /* Clean up */
2624 heap_close(rel, RowExclusiveLock);
2628 * AlterTypeOwnerInternal - change type owner unconditionally
2630 * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
2631 * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
2632 * It assumes the caller has done all needed checks. The function will
2633 * automatically recurse to an array type if the type has one.
2635 * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
2636 * entry (ie, it's not a table rowtype nor an array type).
2638 void
2639 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
2640 bool hasDependEntry)
2642 Relation rel;
2643 HeapTuple tup;
2644 Form_pg_type typTup;
2646 rel = heap_open(TypeRelationId, RowExclusiveLock);
2648 tup = SearchSysCacheCopy(TYPEOID,
2649 ObjectIdGetDatum(typeOid),
2650 0, 0, 0);
2651 if (!HeapTupleIsValid(tup))
2652 elog(ERROR, "cache lookup failed for type %u", typeOid);
2653 typTup = (Form_pg_type) GETSTRUCT(tup);
2656 * Modify the owner --- okay to scribble on typTup because it's a copy
2658 typTup->typowner = newOwnerId;
2660 simple_heap_update(rel, &tup->t_self, tup);
2662 CatalogUpdateIndexes(rel, tup);
2664 /* Update owner dependency reference, if it has one */
2665 if (hasDependEntry)
2666 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2668 /* If it has an array type, update that too */
2669 if (OidIsValid(typTup->typarray))
2670 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
2672 /* Clean up */
2673 heap_close(rel, RowExclusiveLock);
2677 * Execute ALTER TYPE SET SCHEMA
2679 void
2680 AlterTypeNamespace(List *names, const char *newschema)
2682 TypeName *typename;
2683 Oid typeOid;
2684 Oid nspOid;
2685 Oid elemOid;
2687 /* Make a TypeName so we can use standard type lookup machinery */
2688 typename = makeTypeNameFromNameList(names);
2689 typeOid = typenameTypeId(NULL, typename, NULL);
2691 /* check permissions on type */
2692 if (!pg_type_ownercheck(typeOid, GetUserId()))
2693 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2694 format_type_be(typeOid));
2696 /* get schema OID and check its permissions */
2697 nspOid = LookupCreationNamespace(newschema);
2699 /* don't allow direct alteration of array types */
2700 elemOid = get_element_type(typeOid);
2701 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
2702 ereport(ERROR,
2703 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2704 errmsg("cannot alter array type %s",
2705 format_type_be(typeOid)),
2706 errhint("You can alter type %s, which will alter the array type as well.",
2707 format_type_be(elemOid))));
2709 /* and do the work */
2710 AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
2714 * Move specified type to new namespace.
2716 * Caller must have already checked privileges.
2718 * The function automatically recurses to process the type's array type,
2719 * if any. isImplicitArray should be TRUE only when doing this internal
2720 * recursion (outside callers must never try to move an array type directly).
2722 * If errorOnTableType is TRUE, the function errors out if the type is
2723 * a table type. ALTER TABLE has to be used to move a table to a new
2724 * namespace.
2726 void
2727 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
2728 bool isImplicitArray,
2729 bool errorOnTableType)
2731 Relation rel;
2732 HeapTuple tup;
2733 Form_pg_type typform;
2734 Oid oldNspOid;
2735 Oid arrayOid;
2736 bool isCompositeType;
2738 rel = heap_open(TypeRelationId, RowExclusiveLock);
2740 tup = SearchSysCacheCopy(TYPEOID,
2741 ObjectIdGetDatum(typeOid),
2742 0, 0, 0);
2743 if (!HeapTupleIsValid(tup))
2744 elog(ERROR, "cache lookup failed for type %u", typeOid);
2745 typform = (Form_pg_type) GETSTRUCT(tup);
2747 oldNspOid = typform->typnamespace;
2748 arrayOid = typform->typarray;
2750 if (oldNspOid == nspOid)
2751 ereport(ERROR,
2752 (errcode(ERRCODE_DUPLICATE_OBJECT),
2753 errmsg("type %s is already in schema \"%s\"",
2754 format_type_be(typeOid),
2755 get_namespace_name(nspOid))));
2757 /* disallow renaming into or out of temp schemas */
2758 if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
2759 ereport(ERROR,
2760 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2761 errmsg("cannot move objects into or out of temporary schemas")));
2763 /* same for TOAST schema */
2764 if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
2765 ereport(ERROR,
2766 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2767 errmsg("cannot move objects into or out of TOAST schema")));
2769 /* check for duplicate name (more friendly than unique-index failure) */
2770 if (SearchSysCacheExists(TYPENAMENSP,
2771 CStringGetDatum(NameStr(typform->typname)),
2772 ObjectIdGetDatum(nspOid),
2773 0, 0))
2774 ereport(ERROR,
2775 (errcode(ERRCODE_DUPLICATE_OBJECT),
2776 errmsg("type \"%s\" already exists in schema \"%s\"",
2777 NameStr(typform->typname),
2778 get_namespace_name(nspOid))));
2780 /* Detect whether type is a composite type (but not a table rowtype) */
2781 isCompositeType =
2782 (typform->typtype == TYPTYPE_COMPOSITE &&
2783 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
2785 /* Enforce not-table-type if requested */
2786 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
2787 errorOnTableType)
2788 ereport(ERROR,
2789 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2790 errmsg("%s is a table's row type",
2791 format_type_be(typeOid)),
2792 errhint("Use ALTER TABLE instead.")));
2794 /* OK, modify the pg_type row */
2796 /* tup is a copy, so we can scribble directly on it */
2797 typform->typnamespace = nspOid;
2799 simple_heap_update(rel, &tup->t_self, tup);
2800 CatalogUpdateIndexes(rel, tup);
2803 * Composite types have pg_class entries.
2805 * We need to modify the pg_class tuple as well to reflect the change of
2806 * schema.
2808 if (isCompositeType)
2810 Relation classRel;
2812 classRel = heap_open(RelationRelationId, RowExclusiveLock);
2814 AlterRelationNamespaceInternal(classRel, typform->typrelid,
2815 oldNspOid, nspOid,
2816 false);
2818 heap_close(classRel, RowExclusiveLock);
2821 * Check for constraints associated with the composite type (we don't
2822 * currently support this, but probably will someday).
2824 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
2825 nspOid, false);
2827 else
2829 /* If it's a domain, it might have constraints */
2830 if (typform->typtype == TYPTYPE_DOMAIN)
2831 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
2835 * Update dependency on schema, if any --- a table rowtype has not got
2836 * one, and neither does an implicit array.
2838 if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
2839 !isImplicitArray)
2840 if (changeDependencyFor(TypeRelationId, typeOid,
2841 NamespaceRelationId, oldNspOid, nspOid) != 1)
2842 elog(ERROR, "failed to change schema dependency for type %s",
2843 format_type_be(typeOid));
2845 heap_freetuple(tup);
2847 heap_close(rel, RowExclusiveLock);
2849 /* Recursively alter the associated array type, if any */
2850 if (OidIsValid(arrayOid))
2851 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);