1 /*-------------------------------------------------------------------------
4 * Routines for SQL commands that manipulate types (and domains).
6 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.69 2005/04/14 01:38:17 tgl Exp $
14 * The "DefineFoo" routines take the parse tree and pick out the
15 * appropriate arguments/flags, passing the results to the
16 * corresponding "FooDefine" routines (in src/catalog) that do
17 * the actual catalog-munging. These routines also verify permission
18 * of the user to execute the command.
21 * These things must be defined and committed in the following order:
23 * input/output, recv/send functions
30 *-------------------------------------------------------------------------
34 #include "access/heapam.h"
35 #include "access/genam.h"
36 #include "catalog/catname.h"
37 #include "catalog/dependency.h"
38 #include "catalog/heap.h"
39 #include "catalog/indexing.h"
40 #include "catalog/namespace.h"
41 #include "catalog/pg_constraint.h"
42 #include "catalog/pg_depend.h"
43 #include "catalog/pg_type.h"
44 #include "commands/defrem.h"
45 #include "commands/tablecmds.h"
46 #include "commands/typecmds.h"
47 #include "executor/executor.h"
48 #include "miscadmin.h"
49 #include "nodes/execnodes.h"
50 #include "nodes/nodes.h"
51 #include "optimizer/clauses.h"
52 #include "optimizer/planmain.h"
53 #include "optimizer/var.h"
54 #include "parser/parse_coerce.h"
55 #include "parser/parse_expr.h"
56 #include "parser/parse_func.h"
57 #include "parser/parse_relation.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/syscache.h"
66 /* result structure for get_rels_with_domain() */
69 Relation rel; /* opened and locked relation */
70 int natts; /* number of attributes of interest */
71 int *atts; /* attribute numbers */
72 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
76 static Oid findTypeInputFunction(List *procname, Oid typeOid);
77 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
78 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
79 static Oid findTypeSendFunction(List *procname, Oid typeOid);
80 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
81 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
82 static void domainOwnerCheck(HeapTuple tup, TypeName *typename);
83 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
85 int typMod, Constraint *constr,
91 * Registers a new type.
94 DefineType(List *names, List *parameters)
99 int16 internalLength = -1; /* default: variable-length */
100 Oid elemType = InvalidOid;
101 List *inputName = NIL;
102 List *outputName = NIL;
103 List *receiveName = NIL;
104 List *sendName = NIL;
105 List *analyzeName = NIL;
106 char *defaultValue = NULL;
107 bool byValue = false;
108 char delimiter = DEFAULT_TYPDELIM;
109 char alignment = 'i'; /* default alignment */
110 char storage = 'p'; /* default TOAST storage method */
113 Oid receiveOid = InvalidOid;
114 Oid sendOid = InvalidOid;
115 Oid analyzeOid = InvalidOid;
121 /* Convert list of names to a name and namespace */
122 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
124 /* Check we have creation rights in target namespace */
125 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
126 if (aclresult != ACLCHECK_OK)
127 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
128 get_namespace_name(typeNamespace));
131 * Type names must be one character shorter than other names, allowing
132 * room to create the corresponding array type name with prepended
135 if (strlen(typeName) > (NAMEDATALEN - 2))
137 (errcode(ERRCODE_INVALID_NAME),
138 errmsg("type names must be %d characters or less",
141 foreach(pl, parameters)
143 DefElem *defel = (DefElem *) lfirst(pl);
145 if (pg_strcasecmp(defel->defname, "internallength") == 0)
146 internalLength = defGetTypeLength(defel);
147 else if (pg_strcasecmp(defel->defname, "externallength") == 0)
148 ; /* ignored -- remove after 7.3 */
149 else if (pg_strcasecmp(defel->defname, "input") == 0)
150 inputName = defGetQualifiedName(defel);
151 else if (pg_strcasecmp(defel->defname, "output") == 0)
152 outputName = defGetQualifiedName(defel);
153 else if (pg_strcasecmp(defel->defname, "receive") == 0)
154 receiveName = defGetQualifiedName(defel);
155 else if (pg_strcasecmp(defel->defname, "send") == 0)
156 sendName = defGetQualifiedName(defel);
157 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
158 pg_strcasecmp(defel->defname, "analyse") == 0)
159 analyzeName = defGetQualifiedName(defel);
160 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
162 char *p = defGetString(defel);
166 else if (pg_strcasecmp(defel->defname, "element") == 0)
168 elemType = typenameTypeId(defGetTypeName(defel));
169 /* disallow arrays of pseudotypes */
170 if (get_typtype(elemType) == 'p')
172 (errcode(ERRCODE_DATATYPE_MISMATCH),
173 errmsg("array element type cannot be %s",
174 format_type_be(elemType))));
176 else if (pg_strcasecmp(defel->defname, "default") == 0)
177 defaultValue = defGetString(defel);
178 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
179 byValue = defGetBoolean(defel);
180 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
182 char *a = defGetString(defel);
185 * Note: if argument was an unquoted identifier, parser will
186 * have applied translations to it, so be prepared to
187 * recognize translated type names as well as the nominal
190 if (pg_strcasecmp(a, "double") == 0 ||
191 pg_strcasecmp(a, "float8") == 0 ||
192 pg_strcasecmp(a, "pg_catalog.float8") == 0)
194 else if (pg_strcasecmp(a, "int4") == 0 ||
195 pg_strcasecmp(a, "pg_catalog.int4") == 0)
197 else if (pg_strcasecmp(a, "int2") == 0 ||
198 pg_strcasecmp(a, "pg_catalog.int2") == 0)
200 else if (pg_strcasecmp(a, "char") == 0 ||
201 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
205 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
206 errmsg("alignment \"%s\" not recognized", a)));
208 else if (pg_strcasecmp(defel->defname, "storage") == 0)
210 char *a = defGetString(defel);
212 if (pg_strcasecmp(a, "plain") == 0)
214 else if (pg_strcasecmp(a, "external") == 0)
216 else if (pg_strcasecmp(a, "extended") == 0)
218 else if (pg_strcasecmp(a, "main") == 0)
222 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
223 errmsg("storage \"%s\" not recognized", a)));
227 (errcode(ERRCODE_SYNTAX_ERROR),
228 errmsg("type attribute \"%s\" not recognized",
233 * make sure we have our required definitions
235 if (inputName == NIL)
237 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
238 errmsg("type input function must be specified")));
239 if (outputName == NIL)
241 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
242 errmsg("type output function must be specified")));
245 * Look to see if type already exists (presumably as a shell; if not,
246 * TypeCreate will complain). If it doesn't, create it as a shell, so
247 * that the OID is known for use in the I/O function definitions.
249 typoid = GetSysCacheOid(TYPENAMENSP,
250 CStringGetDatum(typeName),
251 ObjectIdGetDatum(typeNamespace),
253 if (!OidIsValid(typoid))
255 typoid = TypeShellMake(typeName, typeNamespace);
256 /* Make new shell type visible for modification below */
257 CommandCounterIncrement();
261 * Convert I/O proc names to OIDs
263 inputOid = findTypeInputFunction(inputName, typoid);
264 outputOid = findTypeOutputFunction(outputName, typoid);
266 receiveOid = findTypeReceiveFunction(receiveName, typoid);
268 sendOid = findTypeSendFunction(sendName, typoid);
271 * Verify that I/O procs return the expected thing. If we see OPAQUE,
272 * complain and change it to the correct type-safe choice.
274 resulttype = get_func_rettype(inputOid);
275 if (resulttype != typoid)
277 if (resulttype == OPAQUEOID)
279 /* backwards-compatibility hack */
281 (errmsg("changing return type of function %s from \"opaque\" to %s",
282 NameListToString(inputName), typeName)));
283 SetFunctionReturnType(inputOid, typoid);
287 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
288 errmsg("type input function %s must return type %s",
289 NameListToString(inputName), typeName)));
291 resulttype = get_func_rettype(outputOid);
292 if (resulttype != CSTRINGOID)
294 if (resulttype == OPAQUEOID)
296 /* backwards-compatibility hack */
298 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
299 NameListToString(outputName))));
300 SetFunctionReturnType(outputOid, CSTRINGOID);
304 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
305 errmsg("type output function %s must return type \"cstring\"",
306 NameListToString(outputName))));
310 resulttype = get_func_rettype(receiveOid);
311 if (resulttype != typoid)
313 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
314 errmsg("type receive function %s must return type %s",
315 NameListToString(receiveName), typeName)));
319 resulttype = get_func_rettype(sendOid);
320 if (resulttype != BYTEAOID)
322 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
323 errmsg("type send function %s must return type \"bytea\"",
324 NameListToString(sendName))));
328 * Convert analysis function proc name to an OID. If no analysis
329 * function is specified, we'll use zero to select the built-in
333 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
336 * now have TypeCreate do all the real work.
339 TypeCreate(typeName, /* type name */
340 typeNamespace, /* namespace */
341 InvalidOid, /* preassigned type oid (not done here) */
342 InvalidOid, /* relation oid (n/a here) */
343 0, /* relation kind (ditto) */
344 internalLength, /* internal size */
345 'b', /* type-type (base type) */
346 delimiter, /* array element delimiter */
347 inputOid, /* input procedure */
348 outputOid, /* output procedure */
349 receiveOid, /* receive procedure */
350 sendOid, /* send procedure */
351 analyzeOid, /* analyze procedure */
352 elemType, /* element type ID */
353 InvalidOid, /* base type ID (only for domains) */
354 defaultValue, /* default type value */
355 NULL, /* no binary form available */
356 byValue, /* passed by value */
357 alignment, /* required alignment */
358 storage, /* TOAST strategy */
359 -1, /* typMod (Domains only) */
360 0, /* Array Dimensions of typbasetype */
361 false); /* Type NOT NULL */
364 * When we create a base type (as opposed to a complex type) we need
365 * to have an array entry for it in pg_type as well.
367 shadow_type = makeArrayTypeName(typeName);
369 /* alignment must be 'i' or 'd' for arrays */
370 alignment = (alignment == 'd') ? 'd' : 'i';
372 TypeCreate(shadow_type, /* type name */
373 typeNamespace, /* namespace */
374 InvalidOid, /* preassigned type oid (not done here) */
375 InvalidOid, /* relation oid (n/a here) */
376 0, /* relation kind (ditto) */
377 -1, /* internal size */
378 'b', /* type-type (base type) */
379 DEFAULT_TYPDELIM, /* array element delimiter */
380 F_ARRAY_IN, /* input procedure */
381 F_ARRAY_OUT, /* output procedure */
382 F_ARRAY_RECV, /* receive procedure */
383 F_ARRAY_SEND, /* send procedure */
384 InvalidOid, /* analyze procedure - default */
385 typoid, /* element type ID */
386 InvalidOid, /* base type ID */
387 NULL, /* never a default type value */
388 NULL, /* binary default isn't sent either */
389 false, /* never passed by value */
390 alignment, /* see above */
391 'x', /* ARRAY is always toastable */
392 -1, /* typMod (Domains only) */
393 0, /* Array dimensions of typbasetype */
394 false); /* Type NOT NULL */
402 * Removes a datatype.
405 RemoveType(List *names, DropBehavior behavior)
410 ObjectAddress object;
412 /* Make a TypeName so we can use standard type lookup machinery */
413 typename = makeNode(TypeName);
414 typename->names = names;
415 typename->typmod = -1;
416 typename->arrayBounds = NIL;
418 /* Use LookupTypeName here so that shell types can be removed. */
419 typeoid = LookupTypeName(typename);
420 if (!OidIsValid(typeoid))
422 (errcode(ERRCODE_UNDEFINED_OBJECT),
423 errmsg("type \"%s\" does not exist",
424 TypeNameToString(typename))));
426 tup = SearchSysCache(TYPEOID,
427 ObjectIdGetDatum(typeoid),
429 if (!HeapTupleIsValid(tup))
430 elog(ERROR, "cache lookup failed for type %u", typeoid);
432 /* Permission check: must own type or its namespace */
433 if (!pg_type_ownercheck(typeoid, GetUserId()) &&
434 !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace,
436 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
437 TypeNameToString(typename));
439 ReleaseSysCache(tup);
444 object.classId = TypeRelationId;
445 object.objectId = typeoid;
446 object.objectSubId = 0;
448 performDeletion(&object, behavior);
453 * Guts of type deletion.
456 RemoveTypeById(Oid typeOid)
461 relation = heap_openr(TypeRelationName, RowExclusiveLock);
463 tup = SearchSysCache(TYPEOID,
464 ObjectIdGetDatum(typeOid),
466 if (!HeapTupleIsValid(tup))
467 elog(ERROR, "cache lookup failed for type %u", typeOid);
469 simple_heap_delete(relation, &tup->t_self);
471 ReleaseSysCache(tup);
473 heap_close(relation, RowExclusiveLock);
479 * Registers a new domain.
482 DefineDomain(CreateDomainStmt *stmt)
487 int16 internalLength;
490 Oid receiveProcedure;
492 Oid analyzeProcedure;
500 Node *defaultExpr = NULL;
501 char *defaultValue = NULL;
502 char *defaultValueBin = NULL;
503 bool typNotNull = false;
504 bool nullDefined = false;
506 int32 typNDims = list_length(stmt->typename->arrayBounds);
508 List *schema = stmt->constraints;
512 Form_pg_type baseType;
514 /* Convert list of names to a name and namespace */
515 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
518 /* Check we have creation rights in target namespace */
519 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
521 if (aclresult != ACLCHECK_OK)
522 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
523 get_namespace_name(domainNamespace));
526 * Domainnames, unlike typenames don't need to account for the '_'
527 * prefix. So they can be one character longer. (This test is
528 * presently useless since the parser will have truncated the name to
529 * fit. But leave it here since we may someday support arrays of
530 * domains, in which case we'll be back to needing to enforce
533 if (strlen(domainName) > (NAMEDATALEN - 1))
535 (errcode(ERRCODE_INVALID_NAME),
536 errmsg("domain names must be %d characters or less",
540 * Look up the base type.
542 typeTup = typenameType(stmt->typename);
544 baseType = (Form_pg_type) GETSTRUCT(typeTup);
545 basetypeoid = HeapTupleGetOid(typeTup);
548 * Base type must be a plain base type. Domains over pseudo types
549 * would create a security hole. Domains of domains might be made to
550 * work in the future, but not today. Ditto for domains over complex
553 typtype = baseType->typtype;
556 (errcode(ERRCODE_DATATYPE_MISMATCH),
557 errmsg("\"%s\" is not a valid base type for a domain",
558 TypeNameToString(stmt->typename))));
560 /* passed by value */
561 byValue = baseType->typbyval;
563 /* Required Alignment */
564 alignment = baseType->typalign;
567 storage = baseType->typstorage;
570 internalLength = baseType->typlen;
572 /* Array element Delimiter */
573 delimiter = baseType->typdelim;
576 inputProcedure = baseType->typinput;
577 outputProcedure = baseType->typoutput;
578 receiveProcedure = baseType->typreceive;
579 sendProcedure = baseType->typsend;
581 /* Analysis function */
582 analyzeProcedure = baseType->typanalyze;
584 /* Inherited default value */
585 datum = SysCacheGetAttr(TYPEOID, typeTup,
586 Anum_pg_type_typdefault, &isnull);
588 defaultValue = DatumGetCString(DirectFunctionCall1(textout, datum));
590 /* Inherited default binary value */
591 datum = SysCacheGetAttr(TYPEOID, typeTup,
592 Anum_pg_type_typdefaultbin, &isnull);
594 defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum));
597 * Pull out the typelem name of the parent OID.
599 * This is what enables us to make a domain of an array
601 basetypelem = baseType->typelem;
604 * Run through constraints manually to avoid the additional processing
605 * conducted by DefineRelation() and friends.
607 foreach(listptr, schema)
609 Node *newConstraint = lfirst(listptr);
613 /* Check for unsupported constraint types */
614 if (IsA(newConstraint, FkConstraint))
616 (errcode(ERRCODE_SYNTAX_ERROR),
617 errmsg("foreign key constraints not possible for domains")));
619 /* otherwise it should be a plain Constraint */
620 if (!IsA(newConstraint, Constraint))
621 elog(ERROR, "unrecognized node type: %d",
622 (int) nodeTag(newConstraint));
624 constr = (Constraint *) newConstraint;
626 switch (constr->contype)
631 * The inherited default value may be overridden by the
632 * user with the DEFAULT <expr> statement.
636 (errcode(ERRCODE_SYNTAX_ERROR),
637 errmsg("multiple default expressions")));
639 /* Create a dummy ParseState for transformExpr */
640 pstate = make_parsestate(NULL);
643 * Cook the constr->raw_expr into an expression. Note:
644 * Name is strictly for error message
646 defaultExpr = cookDefault(pstate, constr->raw_expr,
648 stmt->typename->typmod,
652 * Expression must be stored as a nodeToString result, but
653 * we also require a valid textual representation (mainly
654 * to make life easier for pg_dump).
656 defaultValue = deparse_expression(defaultExpr,
657 deparse_context_for(domainName,
660 defaultValueBin = nodeToString(defaultExpr);
664 if (nullDefined && !typNotNull)
666 (errcode(ERRCODE_SYNTAX_ERROR),
667 errmsg("conflicting NULL/NOT NULL constraints")));
673 if (nullDefined && typNotNull)
675 (errcode(ERRCODE_SYNTAX_ERROR),
676 errmsg("conflicting NULL/NOT NULL constraints")));
684 * Check constraints are handled after domain creation, as
685 * they require the Oid of the domain
690 * All else are error cases
694 (errcode(ERRCODE_SYNTAX_ERROR),
695 errmsg("unique constraints not possible for domains")));
700 (errcode(ERRCODE_SYNTAX_ERROR),
701 errmsg("primary key constraints not possible for domains")));
704 case CONSTR_ATTR_DEFERRABLE:
705 case CONSTR_ATTR_NOT_DEFERRABLE:
706 case CONSTR_ATTR_DEFERRED:
707 case CONSTR_ATTR_IMMEDIATE:
709 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
710 errmsg("specifying constraint deferrability not supported for domains")));
714 elog(ERROR, "unrecognized constraint subtype: %d",
715 (int) constr->contype);
721 * Have TypeCreate do all the real work.
724 TypeCreate(domainName, /* type name */
725 domainNamespace, /* namespace */
726 InvalidOid, /* preassigned type oid (none here) */
727 InvalidOid, /* relation oid (n/a here) */
728 0, /* relation kind (ditto) */
729 internalLength, /* internal size */
730 'd', /* type-type (domain type) */
731 delimiter, /* array element delimiter */
732 inputProcedure, /* input procedure */
733 outputProcedure, /* output procedure */
734 receiveProcedure, /* receive procedure */
735 sendProcedure, /* send procedure */
736 analyzeProcedure, /* analyze procedure */
737 basetypelem, /* element type ID */
738 basetypeoid, /* base type ID */
739 defaultValue, /* default type value (text) */
740 defaultValueBin, /* default type value (binary) */
741 byValue, /* passed by value */
742 alignment, /* required alignment */
743 storage, /* TOAST strategy */
744 stmt->typename->typmod, /* typeMod value */
745 typNDims, /* Array dimensions for base type */
746 typNotNull); /* Type NOT NULL */
749 * Process constraints which refer to the domain ID returned by
752 foreach(listptr, schema)
754 Constraint *constr = lfirst(listptr);
756 /* it must be a Constraint, per check above */
758 switch (constr->contype)
761 domainAddConstraint(domainoid, domainNamespace,
762 basetypeoid, stmt->typename->typmod,
766 /* Other constraint types were fully processed above */
772 /* CCI so we can detect duplicate constraint names */
773 CommandCounterIncrement();
777 * Now we can clean up.
779 ReleaseSysCache(typeTup);
787 * This is identical to RemoveType except we insist it be a domain.
790 RemoveDomain(List *names, DropBehavior behavior)
796 ObjectAddress object;
798 /* Make a TypeName so we can use standard type lookup machinery */
799 typename = makeNode(TypeName);
800 typename->names = names;
801 typename->typmod = -1;
802 typename->arrayBounds = NIL;
804 /* Use LookupTypeName here so that shell types can be removed. */
805 typeoid = LookupTypeName(typename);
806 if (!OidIsValid(typeoid))
808 (errcode(ERRCODE_UNDEFINED_OBJECT),
809 errmsg("type \"%s\" does not exist",
810 TypeNameToString(typename))));
812 tup = SearchSysCache(TYPEOID,
813 ObjectIdGetDatum(typeoid),
815 if (!HeapTupleIsValid(tup))
816 elog(ERROR, "cache lookup failed for type %u", typeoid);
818 /* Permission check: must own type or its namespace */
819 if (!pg_type_ownercheck(typeoid, GetUserId()) &&
820 !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace,
822 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
823 TypeNameToString(typename));
825 /* Check that this is actually a domain */
826 typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
830 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
831 errmsg("\"%s\" is not a domain",
832 TypeNameToString(typename))));
834 ReleaseSysCache(tup);
839 object.classId = TypeRelationId;
840 object.objectId = typeoid;
841 object.objectSubId = 0;
843 performDeletion(&object, behavior);
848 * Find suitable I/O functions for a type.
850 * typeOid is the type's OID (which will already exist, if only as a shell
855 findTypeInputFunction(List *procname, Oid typeOid)
861 * Input functions can take a single argument of type CSTRING, or
862 * three arguments (string, element OID, typmod).
864 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
865 * see this, we issue a warning and fix up the pg_proc entry.
867 argList[0] = CSTRINGOID;
869 procOid = LookupFuncName(procname, 1, argList, true);
870 if (OidIsValid(procOid))
874 argList[2] = INT4OID;
876 procOid = LookupFuncName(procname, 3, argList, true);
877 if (OidIsValid(procOid))
880 /* No luck, try it with OPAQUE */
881 argList[0] = OPAQUEOID;
883 procOid = LookupFuncName(procname, 1, argList, true);
885 if (!OidIsValid(procOid))
888 argList[2] = INT4OID;
890 procOid = LookupFuncName(procname, 3, argList, true);
893 if (OidIsValid(procOid))
895 /* Found, but must complain and fix the pg_proc entry */
897 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
898 NameListToString(procname))));
899 SetFunctionArgType(procOid, 0, CSTRINGOID);
902 * Need CommandCounterIncrement since DefineType will likely try
903 * to alter the pg_proc tuple again.
905 CommandCounterIncrement();
910 /* Use CSTRING (preferred) in the error message */
911 argList[0] = CSTRINGOID;
914 (errcode(ERRCODE_UNDEFINED_FUNCTION),
915 errmsg("function %s does not exist",
916 func_signature_string(procname, 1, argList))));
918 return InvalidOid; /* keep compiler quiet */
922 findTypeOutputFunction(List *procname, Oid typeOid)
928 * Output functions can take a single argument of the type, or two
929 * arguments (data value, element OID).
931 * For backwards compatibility we allow OPAQUE in place of the actual
932 * type name; if we see this, we issue a warning and fix up the
935 argList[0] = typeOid;
937 procOid = LookupFuncName(procname, 1, argList, true);
938 if (OidIsValid(procOid))
943 procOid = LookupFuncName(procname, 2, argList, true);
944 if (OidIsValid(procOid))
947 /* No luck, try it with OPAQUE */
948 argList[0] = OPAQUEOID;
950 procOid = LookupFuncName(procname, 1, argList, true);
952 if (!OidIsValid(procOid))
956 procOid = LookupFuncName(procname, 2, argList, true);
959 if (OidIsValid(procOid))
961 /* Found, but must complain and fix the pg_proc entry */
963 (errmsg("changing argument type of function %s from \"opaque\" to %s",
964 NameListToString(procname), format_type_be(typeOid))));
965 SetFunctionArgType(procOid, 0, typeOid);
968 * Need CommandCounterIncrement since DefineType will likely try
969 * to alter the pg_proc tuple again.
971 CommandCounterIncrement();
976 /* Use type name, not OPAQUE, in the failure message. */
977 argList[0] = typeOid;
980 (errcode(ERRCODE_UNDEFINED_FUNCTION),
981 errmsg("function %s does not exist",
982 func_signature_string(procname, 1, argList))));
984 return InvalidOid; /* keep compiler quiet */
988 findTypeReceiveFunction(List *procname, Oid typeOid)
994 * Receive functions can take a single argument of type INTERNAL, or
995 * two arguments (internal, oid).
997 argList[0] = INTERNALOID;
999 procOid = LookupFuncName(procname, 1, argList, true);
1000 if (OidIsValid(procOid))
1003 argList[1] = OIDOID;
1005 procOid = LookupFuncName(procname, 2, argList, true);
1006 if (OidIsValid(procOid))
1010 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1011 errmsg("function %s does not exist",
1012 func_signature_string(procname, 1, argList))));
1014 return InvalidOid; /* keep compiler quiet */
1018 findTypeSendFunction(List *procname, Oid typeOid)
1024 * Send functions can take a single argument of the type, or two
1025 * arguments (data value, element OID).
1027 argList[0] = typeOid;
1029 procOid = LookupFuncName(procname, 1, argList, true);
1030 if (OidIsValid(procOid))
1033 argList[1] = OIDOID;
1035 procOid = LookupFuncName(procname, 2, argList, true);
1036 if (OidIsValid(procOid))
1040 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1041 errmsg("function %s does not exist",
1042 func_signature_string(procname, 1, argList))));
1044 return InvalidOid; /* keep compiler quiet */
1048 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1054 * Analyze functions always take one INTERNAL argument and return
1057 argList[0] = INTERNALOID;
1059 procOid = LookupFuncName(procname, 1, argList, true);
1060 if (!OidIsValid(procOid))
1062 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1063 errmsg("function %s does not exist",
1064 func_signature_string(procname, 1, argList))));
1066 if (get_func_rettype(procOid) != BOOLOID)
1068 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1069 errmsg("type analyze function %s must return type \"boolean\"",
1070 NameListToString(procname))));
1076 /*-------------------------------------------------------------------
1077 * DefineCompositeType
1079 * Create a Composite Type relation.
1080 * `DefineRelation' does all the work, we just provide the correct
1083 * If the relation already exists, then 'DefineRelation' will abort
1086 * DefineCompositeType returns relid for use when creating
1087 * an implicit composite type during function creation
1088 *-------------------------------------------------------------------
1091 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1093 CreateStmt *createStmt = makeNode(CreateStmt);
1095 if (coldeflist == NIL)
1097 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1098 errmsg("composite type must have at least one attribute")));
1101 * now set the parameters for keys/inheritance etc. All of these are
1102 * uninteresting for composite types...
1104 createStmt->relation = (RangeVar *) typevar;
1105 createStmt->tableElts = coldeflist;
1106 createStmt->inhRelations = NIL;
1107 createStmt->constraints = NIL;
1108 createStmt->hasoids = MUST_NOT_HAVE_OIDS;
1109 createStmt->oncommit = ONCOMMIT_NOOP;
1110 createStmt->tablespacename = NULL;
1113 * finally create the relation...
1115 return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);
1119 * AlterDomainDefault
1121 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
1124 AlterDomainDefault(List *names, Node *defaultRaw)
1132 Node *defaultExpr = NULL; /* NULL if no default specified */
1133 Datum new_record[Natts_pg_type];
1134 char new_record_nulls[Natts_pg_type];
1135 char new_record_repl[Natts_pg_type];
1137 Form_pg_type typTup;
1139 /* Make a TypeName so we can use standard type lookup machinery */
1140 typename = makeNode(TypeName);
1141 typename->names = names;
1142 typename->typmod = -1;
1143 typename->arrayBounds = NIL;
1145 /* Lock the domain in the type table */
1146 rel = heap_openr(TypeRelationName, RowExclusiveLock);
1148 /* Use LookupTypeName here so that shell types can be removed. */
1149 domainoid = LookupTypeName(typename);
1150 if (!OidIsValid(domainoid))
1152 (errcode(ERRCODE_UNDEFINED_OBJECT),
1153 errmsg("type \"%s\" does not exist",
1154 TypeNameToString(typename))));
1156 tup = SearchSysCacheCopy(TYPEOID,
1157 ObjectIdGetDatum(domainoid),
1159 if (!HeapTupleIsValid(tup))
1160 elog(ERROR, "cache lookup failed for type %u", domainoid);
1162 /* Doesn't return if user isn't allowed to alter the domain */
1163 domainOwnerCheck(tup, typename);
1165 /* Setup new tuple */
1166 MemSet(new_record, (Datum) 0, sizeof(new_record));
1167 MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
1168 MemSet(new_record_repl, ' ', sizeof(new_record_repl));
1171 typTup = (Form_pg_type) GETSTRUCT(tup);
1173 /* Store the new default, if null then skip this step */
1176 /* Create a dummy ParseState for transformExpr */
1177 pstate = make_parsestate(NULL);
1180 * Cook the colDef->raw_expr into an expression. Note: Name is
1181 * strictly for error message
1183 defaultExpr = cookDefault(pstate, defaultRaw,
1184 typTup->typbasetype,
1186 NameStr(typTup->typname));
1189 * Expression must be stored as a nodeToString result, but we also
1190 * require a valid textual representation (mainly to make life
1191 * easier for pg_dump).
1193 defaultValue = deparse_expression(defaultExpr,
1194 deparse_context_for(NameStr(typTup->typname),
1199 * Form an updated tuple with the new default and write it back.
1201 new_record[Anum_pg_type_typdefaultbin - 1] = DirectFunctionCall1(textin,
1203 nodeToString(defaultExpr)));
1205 new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
1206 new_record[Anum_pg_type_typdefault - 1] = DirectFunctionCall1(textin,
1207 CStringGetDatum(defaultValue));
1208 new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
1211 /* Default is NULL, drop it */
1213 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = 'n';
1214 new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
1215 new_record_nulls[Anum_pg_type_typdefault - 1] = 'n';
1216 new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
1219 newtuple = heap_modifytuple(tup, RelationGetDescr(rel),
1220 new_record, new_record_nulls,
1223 simple_heap_update(rel, &tup->t_self, newtuple);
1225 CatalogUpdateIndexes(rel, newtuple);
1227 /* Rebuild dependencies */
1228 GenerateTypeDependencies(typTup->typnamespace,
1231 0, /* relation kind is n/a */
1238 typTup->typbasetype,
1240 true); /* Rebuild is true */
1243 heap_close(rel, NoLock);
1244 heap_freetuple(newtuple);
1248 * AlterDomainNotNull
1250 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
1253 AlterDomainNotNull(List *names, bool notNull)
1259 Form_pg_type typTup;
1261 /* Make a TypeName so we can use standard type lookup machinery */
1262 typename = makeNode(TypeName);
1263 typename->names = names;
1264 typename->typmod = -1;
1265 typename->arrayBounds = NIL;
1267 /* Lock the type table */
1268 typrel = heap_openr(TypeRelationName, RowExclusiveLock);
1270 /* Use LookupTypeName here so that shell types can be found (why?). */
1271 domainoid = LookupTypeName(typename);
1272 if (!OidIsValid(domainoid))
1274 (errcode(ERRCODE_UNDEFINED_OBJECT),
1275 errmsg("type \"%s\" does not exist",
1276 TypeNameToString(typename))));
1278 tup = SearchSysCacheCopy(TYPEOID,
1279 ObjectIdGetDatum(domainoid),
1281 if (!HeapTupleIsValid(tup))
1282 elog(ERROR, "cache lookup failed for type %u", domainoid);
1283 typTup = (Form_pg_type) GETSTRUCT(tup);
1285 /* Doesn't return if user isn't allowed to alter the domain */
1286 domainOwnerCheck(tup, typename);
1288 /* Is the domain already set to the desired constraint? */
1289 if (typTup->typnotnull == notNull)
1291 heap_close(typrel, RowExclusiveLock);
1295 /* Adding a NOT NULL constraint requires checking existing columns */
1301 /* Fetch relation list with attributes based on this domain */
1302 /* ShareLock is sufficient to prevent concurrent data changes */
1304 rels = get_rels_with_domain(domainoid, ShareLock);
1308 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1309 Relation testrel = rtc->rel;
1310 TupleDesc tupdesc = RelationGetDescr(testrel);
1314 /* Scan all tuples in this relation */
1315 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1316 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1320 /* Test attributes that are of the domain */
1321 for (i = 0; i < rtc->natts; i++)
1323 int attnum = rtc->atts[i];
1325 if (heap_attisnull(tuple, attnum))
1327 (errcode(ERRCODE_NOT_NULL_VIOLATION),
1328 errmsg("column \"%s\" of table \"%s\" contains null values",
1329 NameStr(tupdesc->attrs[attnum - 1]->attname),
1330 RelationGetRelationName(testrel))));
1335 /* Close each rel after processing, but keep lock */
1336 heap_close(testrel, NoLock);
1341 * Okay to update pg_type row. We can scribble on typTup because it's
1344 typTup->typnotnull = notNull;
1346 simple_heap_update(typrel, &tup->t_self, tup);
1348 CatalogUpdateIndexes(typrel, tup);
1351 heap_freetuple(tup);
1352 heap_close(typrel, RowExclusiveLock);
1356 * AlterDomainDropConstraint
1358 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
1361 AlterDomainDropConstraint(List *names, const char *constrName, DropBehavior behavior)
1367 Form_pg_type typTup;
1369 SysScanDesc conscan;
1373 /* Make a TypeName so we can use standard type lookup machinery */
1374 typename = makeNode(TypeName);
1375 typename->names = names;
1376 typename->typmod = -1;
1377 typename->arrayBounds = NIL;
1379 /* Lock the type table */
1380 rel = heap_openr(TypeRelationName, RowExclusiveLock);
1382 /* Use LookupTypeName here so that shell types can be removed. */
1383 domainoid = LookupTypeName(typename);
1384 if (!OidIsValid(domainoid))
1386 (errcode(ERRCODE_UNDEFINED_OBJECT),
1387 errmsg("type \"%s\" does not exist",
1388 TypeNameToString(typename))));
1390 tup = SearchSysCacheCopy(TYPEOID,
1391 ObjectIdGetDatum(domainoid),
1393 if (!HeapTupleIsValid(tup))
1394 elog(ERROR, "cache lookup failed for type %u", domainoid);
1396 /* Doesn't return if user isn't allowed to alter the domain */
1397 domainOwnerCheck(tup, typename);
1399 /* Grab an appropriate lock on the pg_constraint relation */
1400 conrel = heap_openr(ConstraintRelationName, RowExclusiveLock);
1402 /* Use the index to scan only constraints of the target relation */
1403 ScanKeyInit(&key[0],
1404 Anum_pg_constraint_contypid,
1405 BTEqualStrategyNumber, F_OIDEQ,
1406 ObjectIdGetDatum(HeapTupleGetOid(tup)));
1408 conscan = systable_beginscan(conrel, ConstraintTypidIndex, true,
1409 SnapshotNow, 1, key);
1411 typTup = (Form_pg_type) GETSTRUCT(tup);
1414 * Scan over the result set, removing any matching entries.
1416 while ((contup = systable_getnext(conscan)) != NULL)
1418 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
1420 if (strcmp(NameStr(con->conname), constrName) == 0)
1422 ObjectAddress conobj;
1424 conobj.classId = RelationGetRelid(conrel);
1425 conobj.objectId = HeapTupleGetOid(contup);
1426 conobj.objectSubId = 0;
1428 performDeletion(&conobj, behavior);
1431 /* Clean up after the scan */
1432 systable_endscan(conscan);
1433 heap_close(conrel, RowExclusiveLock);
1435 heap_close(rel, NoLock);
1439 * AlterDomainAddConstraint
1441 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
1444 AlterDomainAddConstraint(List *names, Node *newConstraint)
1450 Form_pg_type typTup;
1454 ExprContext *econtext;
1457 ExprState *exprstate;
1460 /* Make a TypeName so we can use standard type lookup machinery */
1461 typename = makeNode(TypeName);
1462 typename->names = names;
1463 typename->typmod = -1;
1464 typename->arrayBounds = NIL;
1466 /* Lock the type table */
1467 typrel = heap_openr(TypeRelationName, RowExclusiveLock);
1469 /* Use LookupTypeName here so that shell types can be found (why?). */
1470 domainoid = LookupTypeName(typename);
1471 if (!OidIsValid(domainoid))
1473 (errcode(ERRCODE_UNDEFINED_OBJECT),
1474 errmsg("type \"%s\" does not exist",
1475 TypeNameToString(typename))));
1477 tup = SearchSysCacheCopy(TYPEOID,
1478 ObjectIdGetDatum(domainoid),
1480 if (!HeapTupleIsValid(tup))
1481 elog(ERROR, "cache lookup failed for type %u", domainoid);
1482 typTup = (Form_pg_type) GETSTRUCT(tup);
1484 /* Doesn't return if user isn't allowed to alter the domain */
1485 domainOwnerCheck(tup, typename);
1487 /* Check for unsupported constraint types */
1488 if (IsA(newConstraint, FkConstraint))
1490 (errcode(ERRCODE_SYNTAX_ERROR),
1491 errmsg("foreign key constraints not possible for domains")));
1493 /* otherwise it should be a plain Constraint */
1494 if (!IsA(newConstraint, Constraint))
1495 elog(ERROR, "unrecognized node type: %d",
1496 (int) nodeTag(newConstraint));
1498 constr = (Constraint *) newConstraint;
1500 switch (constr->contype)
1503 /* processed below */
1508 (errcode(ERRCODE_SYNTAX_ERROR),
1509 errmsg("unique constraints not possible for domains")));
1512 case CONSTR_PRIMARY:
1514 (errcode(ERRCODE_SYNTAX_ERROR),
1515 errmsg("primary key constraints not possible for domains")));
1518 case CONSTR_ATTR_DEFERRABLE:
1519 case CONSTR_ATTR_NOT_DEFERRABLE:
1520 case CONSTR_ATTR_DEFERRED:
1521 case CONSTR_ATTR_IMMEDIATE:
1523 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1524 errmsg("specifying constraint deferrability not supported for domains")));
1528 elog(ERROR, "unrecognized constraint subtype: %d",
1529 (int) constr->contype);
1534 * Since all other constraint types throw errors, this must be a check
1535 * constraint. First, process the constraint expression and add an
1536 * entry to pg_constraint.
1539 ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
1540 typTup->typbasetype, typTup->typtypmod,
1541 constr, NameStr(typTup->typname));
1544 * Test all values stored in the attributes based on the domain the
1545 * constraint is being added to.
1547 expr = (Expr *) stringToNode(ccbin);
1549 /* Need an EState to run ExecEvalExpr */
1550 estate = CreateExecutorState();
1551 econtext = GetPerTupleExprContext(estate);
1553 /* build execution state for expr */
1554 exprstate = ExecPrepareExpr(expr, estate);
1556 /* Fetch relation list with attributes based on this domain */
1557 /* ShareLock is sufficient to prevent concurrent data changes */
1559 rels = get_rels_with_domain(domainoid, ShareLock);
1563 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1564 Relation testrel = rtc->rel;
1565 TupleDesc tupdesc = RelationGetDescr(testrel);
1569 /* Scan all tuples in this relation */
1570 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1571 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1575 /* Test attributes that are of the domain */
1576 for (i = 0; i < rtc->natts; i++)
1578 int attnum = rtc->atts[i];
1583 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
1585 econtext->domainValue_datum = d;
1586 econtext->domainValue_isNull = isNull;
1588 conResult = ExecEvalExprSwitchContext(exprstate,
1592 if (!isNull && !DatumGetBool(conResult))
1594 (errcode(ERRCODE_CHECK_VIOLATION),
1595 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
1596 NameStr(tupdesc->attrs[attnum - 1]->attname),
1597 RelationGetRelationName(testrel))));
1600 ResetExprContext(econtext);
1604 /* Hold relation lock till commit (XXX bad for concurrency) */
1605 heap_close(testrel, NoLock);
1608 FreeExecutorState(estate);
1611 heap_close(typrel, RowExclusiveLock);
1615 * get_rels_with_domain
1617 * Fetch all relations / attributes which are using the domain
1619 * The result is a list of RelToCheck structs, one for each distinct
1620 * relation, each containing one or more attribute numbers that are of
1621 * the domain type. We have opened each rel and acquired the specified lock
1624 * XXX this is completely broken because there is no way to lock the domain
1625 * to prevent columns from being added or dropped while our command runs.
1626 * We can partially protect against column drops by locking relations as we
1627 * come across them, but there is still a race condition (the window between
1628 * seeing a pg_depend entry and acquiring lock on the relation it references).
1629 * Also, holding locks on all these relations simultaneously creates a non-
1630 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
1631 * risk by using the weakest suitable lock (ShareLock for most callers).
1633 * XXX to support domains over domains, we'd need to make this smarter,
1634 * or make its callers smarter, so that we could find columns of derived
1635 * domains. Arrays of domains would be a problem too.
1637 * Generally used for retrieving a list of tests when adding
1638 * new constraints to a domain.
1641 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
1646 SysScanDesc depScan;
1650 * We scan pg_depend to find those things that depend on the domain.
1651 * (We assume we can ignore refobjsubid for a domain.)
1653 depRel = relation_openr(DependRelationName, AccessShareLock);
1655 ScanKeyInit(&key[0],
1656 Anum_pg_depend_refclassid,
1657 BTEqualStrategyNumber, F_OIDEQ,
1658 ObjectIdGetDatum(TypeRelationId));
1659 ScanKeyInit(&key[1],
1660 Anum_pg_depend_refobjid,
1661 BTEqualStrategyNumber, F_OIDEQ,
1662 ObjectIdGetDatum(domainOid));
1664 depScan = systable_beginscan(depRel, DependReferenceIndex, true,
1665 SnapshotNow, 2, key);
1667 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
1669 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
1670 RelToCheck *rtc = NULL;
1672 Form_pg_attribute pg_att;
1675 /* Ignore dependees that aren't user columns of relations */
1676 /* (we assume system columns are never of domain types) */
1677 if (pg_depend->classid != RelationRelationId ||
1678 pg_depend->objsubid <= 0)
1681 /* See if we already have an entry for this relation */
1682 foreach(rellist, result)
1684 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
1686 if (RelationGetRelid(rt->rel) == pg_depend->objid)
1695 /* First attribute found for this relation */
1698 /* Acquire requested lock on relation */
1699 rel = relation_open(pg_depend->objid, lockmode);
1701 /* It could be a view or composite type; if so ignore it */
1702 if (rel->rd_rel->relkind != RELKIND_RELATION)
1704 relation_close(rel, lockmode);
1708 /* Build the RelToCheck entry with enough space for all atts */
1709 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
1712 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
1713 result = lcons(rtc, result);
1717 * Confirm column has not been dropped, and is of the expected
1718 * type. This defends against an ALTER DROP COLUMN occuring just
1719 * before we acquired lock ... but if the whole table were
1720 * dropped, we'd still have a problem.
1722 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
1724 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
1725 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
1729 * Okay, add column to result. We store the columns in
1730 * column-number order; this is just a hack to improve
1731 * predictability of regression test output ...
1733 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
1736 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
1738 rtc->atts[ptr] = rtc->atts[ptr - 1];
1741 rtc->atts[ptr] = pg_depend->objsubid;
1744 systable_endscan(depScan);
1746 relation_close(depRel, AccessShareLock);
1754 * Throw an error if the current user doesn't have permission to modify
1755 * the domain in an ALTER DOMAIN statement, or if the type isn't actually
1759 domainOwnerCheck(HeapTuple tup, TypeName *typename)
1761 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1763 /* Check that this is actually a domain */
1764 if (typTup->typtype != 'd')
1766 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1767 errmsg("\"%s\" is not a domain",
1768 TypeNameToString(typename))));
1770 /* Permission check: must own type */
1771 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1772 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
1773 TypeNameToString(typename));
1777 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
1780 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
1781 int typMod, Constraint *constr,
1788 CoerceToDomainValue *domVal;
1791 * Assign or validate constraint name
1795 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
1800 (errcode(ERRCODE_DUPLICATE_OBJECT),
1801 errmsg("constraint \"%s\" for domain \"%s\" already exists",
1802 constr->name, domainName)));
1805 constr->name = ChooseConstraintName(domainName,
1812 * Convert the A_EXPR in raw_expr into an EXPR
1814 pstate = make_parsestate(NULL);
1817 * Set up a CoerceToDomainValue to represent the occurrence of VALUE
1818 * in the expression. Note that it will appear to have the type of
1819 * the base type, not the domain. This seems correct since within the
1820 * check expression, we should not assume the input value can be
1821 * considered a member of the domain.
1823 domVal = makeNode(CoerceToDomainValue);
1824 domVal->typeId = baseTypeOid;
1825 domVal->typeMod = typMod;
1827 pstate->p_value_substitute = (Node *) domVal;
1829 expr = transformExpr(pstate, constr->raw_expr);
1832 * Make sure it yields a boolean result.
1834 expr = coerce_to_boolean(pstate, expr, "CHECK");
1837 * Make sure no outside relations are referred to.
1839 if (list_length(pstate->p_rtable) != 0)
1841 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1842 errmsg("cannot use table references in domain check constraint")));
1845 * Domains don't allow var clauses (this should be redundant with the
1846 * above check, but make it anyway)
1848 if (contain_var_clause(expr))
1850 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1851 errmsg("cannot use table references in domain check constraint")));
1854 * No subplans or aggregates, either...
1856 if (pstate->p_hasSubLinks)
1858 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1859 errmsg("cannot use subquery in check constraint")));
1860 if (pstate->p_hasAggs)
1862 (errcode(ERRCODE_GROUPING_ERROR),
1863 errmsg("cannot use aggregate in check constraint")));
1866 * Convert to string form for storage.
1868 ccbin = nodeToString(expr);
1871 * Deparse it to produce text for consrc.
1873 * Since VARNOs aren't allowed in domain constraints, relation context
1874 * isn't required as anything other than a shell.
1876 ccsrc = deparse_expression(expr,
1877 deparse_context_for(domainName,
1882 * Store the constraint in pg_constraint
1884 CreateConstraintEntry(constr->name, /* Constraint Name */
1885 domainNamespace, /* namespace */
1886 CONSTRAINT_CHECK, /* Constraint Type */
1887 false, /* Is Deferrable */
1888 false, /* Is Deferred */
1889 InvalidOid, /* not a relation constraint */
1892 domainOid, /* domain constraint */
1893 InvalidOid, /* Foreign key fields */
1900 expr, /* Tree form check constraint */
1901 ccbin, /* Binary form check constraint */
1902 ccsrc); /* Source form check constraint */
1905 * Return the compiled constraint expression so the calling routine
1906 * can perform any additional required tests.
1912 * GetDomainConstraints - get a list of the current constraints of domain
1914 * Returns a possibly-empty list of DomainConstraintState nodes.
1916 * This is called by the executor during plan startup for a CoerceToDomain
1917 * expression node. The given constraints will be checked for each value
1918 * passed through the node.
1920 * We allow this to be called for non-domain types, in which case the result
1924 GetDomainConstraints(Oid typeOid)
1927 bool notNull = false;
1930 conRel = heap_openr(ConstraintRelationName, AccessShareLock);
1936 Form_pg_type typTup;
1940 tup = SearchSysCache(TYPEOID,
1941 ObjectIdGetDatum(typeOid),
1943 if (!HeapTupleIsValid(tup))
1944 elog(ERROR, "cache lookup failed for type %u", typeOid);
1945 typTup = (Form_pg_type) GETSTRUCT(tup);
1947 if (typTup->typtype != 'd')
1949 /* Not a domain, so done */
1950 ReleaseSysCache(tup);
1954 /* Test for NOT NULL Constraint */
1955 if (typTup->typnotnull)
1958 /* Look for CHECK Constraints on this domain */
1959 ScanKeyInit(&key[0],
1960 Anum_pg_constraint_contypid,
1961 BTEqualStrategyNumber, F_OIDEQ,
1962 ObjectIdGetDatum(typeOid));
1964 scan = systable_beginscan(conRel, ConstraintTypidIndex, true,
1965 SnapshotNow, 1, key);
1967 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
1969 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
1973 DomainConstraintState *r;
1975 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
1976 if (c->contype != CONSTRAINT_CHECK)
1980 * Not expecting conbin to be NULL, but we'll test for it
1983 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
1984 conRel->rd_att, &isNull);
1986 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
1987 NameStr(typTup->typname), NameStr(c->conname));
1989 check_expr = (Expr *)
1990 stringToNode(DatumGetCString(DirectFunctionCall1(textout,
1993 /* ExecInitExpr assumes we already fixed opfuncids */
1994 fix_opfuncids((Node *) check_expr);
1996 r = makeNode(DomainConstraintState);
1997 r->constrainttype = DOM_CONSTRAINT_CHECK;
1998 r->name = pstrdup(NameStr(c->conname));
1999 r->check_expr = ExecInitExpr(check_expr, NULL);
2002 * use lcons() here because constraints of lower domains
2003 * should be applied earlier.
2005 result = lcons(r, result);
2008 systable_endscan(scan);
2010 /* loop to next domain in stack */
2011 typeOid = typTup->typbasetype;
2012 ReleaseSysCache(tup);
2015 heap_close(conRel, AccessShareLock);
2018 * Only need to add one NOT NULL check regardless of how many domains
2019 * in the stack request it.
2023 DomainConstraintState *r = makeNode(DomainConstraintState);
2025 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
2026 r->name = pstrdup("NOT NULL");
2027 r->check_expr = NULL;
2029 /* lcons to apply the nullness check FIRST */
2030 result = lcons(r, result);
2037 * Change the owner of a type.
2040 AlterTypeOwner(List *names, AclId newOwnerSysId)
2046 Form_pg_type typTup;
2048 /* Make a TypeName so we can use standard type lookup machinery */
2049 typename = makeNode(TypeName);
2050 typename->names = names;
2051 typename->typmod = -1;
2052 typename->arrayBounds = NIL;
2054 /* Lock the type table */
2055 rel = heap_openr(TypeRelationName, RowExclusiveLock);
2057 /* Use LookupTypeName here so that shell types can be processed (why?) */
2058 typeOid = LookupTypeName(typename);
2059 if (!OidIsValid(typeOid))
2061 (errcode(ERRCODE_UNDEFINED_OBJECT),
2062 errmsg("type \"%s\" does not exist",
2063 TypeNameToString(typename))));
2065 tup = SearchSysCacheCopy(TYPEOID,
2066 ObjectIdGetDatum(typeOid),
2068 if (!HeapTupleIsValid(tup))
2069 elog(ERROR, "cache lookup failed for type %u", typeOid);
2070 typTup = (Form_pg_type) GETSTRUCT(tup);
2073 * If it's a composite type, we need to check that it really is a
2074 * free-standing composite type, and not a table's underlying type. We
2075 * want people to use ALTER TABLE not ALTER TYPE for that case.
2077 if (typTup->typtype == 'c' && get_rel_relkind(typTup->typrelid) != 'c')
2079 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2080 errmsg("\"%s\" is a table's row type",
2081 TypeNameToString(typename))));
2084 * If the new owner is the same as the existing owner, consider the
2085 * command to have succeeded. This is for dump restoration purposes.
2087 if (typTup->typowner != newOwnerSysId)
2089 /* Otherwise, must be superuser to change object ownership */
2092 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2093 errmsg("must be superuser to change owner")));
2096 * Modify the owner --- okay to scribble on typTup because it's a
2099 typTup->typowner = newOwnerSysId;
2101 simple_heap_update(rel, &tup->t_self, tup);
2103 CatalogUpdateIndexes(rel, tup);
2107 heap_close(rel, RowExclusiveLock);