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.70 2005/04/14 20:03:24 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/dependency.h"
37 #include "catalog/heap.h"
38 #include "catalog/indexing.h"
39 #include "catalog/namespace.h"
40 #include "catalog/pg_constraint.h"
41 #include "catalog/pg_depend.h"
42 #include "catalog/pg_type.h"
43 #include "commands/defrem.h"
44 #include "commands/tablecmds.h"
45 #include "commands/typecmds.h"
46 #include "executor/executor.h"
47 #include "miscadmin.h"
48 #include "nodes/execnodes.h"
49 #include "nodes/nodes.h"
50 #include "optimizer/clauses.h"
51 #include "optimizer/planmain.h"
52 #include "optimizer/var.h"
53 #include "parser/parse_coerce.h"
54 #include "parser/parse_expr.h"
55 #include "parser/parse_func.h"
56 #include "parser/parse_relation.h"
57 #include "parser/parse_type.h"
58 #include "utils/acl.h"
59 #include "utils/builtins.h"
60 #include "utils/fmgroids.h"
61 #include "utils/lsyscache.h"
62 #include "utils/syscache.h"
65 /* result structure for get_rels_with_domain() */
68 Relation rel; /* opened and locked relation */
69 int natts; /* number of attributes of interest */
70 int *atts; /* attribute numbers */
71 /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
75 static Oid findTypeInputFunction(List *procname, Oid typeOid);
76 static Oid findTypeOutputFunction(List *procname, Oid typeOid);
77 static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
78 static Oid findTypeSendFunction(List *procname, Oid typeOid);
79 static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
80 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
81 static void domainOwnerCheck(HeapTuple tup, TypeName *typename);
82 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
84 int typMod, Constraint *constr,
90 * Registers a new type.
93 DefineType(List *names, List *parameters)
98 int16 internalLength = -1; /* default: variable-length */
99 Oid elemType = InvalidOid;
100 List *inputName = NIL;
101 List *outputName = NIL;
102 List *receiveName = NIL;
103 List *sendName = NIL;
104 List *analyzeName = NIL;
105 char *defaultValue = NULL;
106 bool byValue = false;
107 char delimiter = DEFAULT_TYPDELIM;
108 char alignment = 'i'; /* default alignment */
109 char storage = 'p'; /* default TOAST storage method */
112 Oid receiveOid = InvalidOid;
113 Oid sendOid = InvalidOid;
114 Oid analyzeOid = InvalidOid;
120 /* Convert list of names to a name and namespace */
121 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
123 /* Check we have creation rights in target namespace */
124 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
125 if (aclresult != ACLCHECK_OK)
126 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
127 get_namespace_name(typeNamespace));
130 * Type names must be one character shorter than other names, allowing
131 * room to create the corresponding array type name with prepended
134 if (strlen(typeName) > (NAMEDATALEN - 2))
136 (errcode(ERRCODE_INVALID_NAME),
137 errmsg("type names must be %d characters or less",
140 foreach(pl, parameters)
142 DefElem *defel = (DefElem *) lfirst(pl);
144 if (pg_strcasecmp(defel->defname, "internallength") == 0)
145 internalLength = defGetTypeLength(defel);
146 else if (pg_strcasecmp(defel->defname, "externallength") == 0)
147 ; /* ignored -- remove after 7.3 */
148 else if (pg_strcasecmp(defel->defname, "input") == 0)
149 inputName = defGetQualifiedName(defel);
150 else if (pg_strcasecmp(defel->defname, "output") == 0)
151 outputName = defGetQualifiedName(defel);
152 else if (pg_strcasecmp(defel->defname, "receive") == 0)
153 receiveName = defGetQualifiedName(defel);
154 else if (pg_strcasecmp(defel->defname, "send") == 0)
155 sendName = defGetQualifiedName(defel);
156 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
157 pg_strcasecmp(defel->defname, "analyse") == 0)
158 analyzeName = defGetQualifiedName(defel);
159 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
161 char *p = defGetString(defel);
165 else if (pg_strcasecmp(defel->defname, "element") == 0)
167 elemType = typenameTypeId(defGetTypeName(defel));
168 /* disallow arrays of pseudotypes */
169 if (get_typtype(elemType) == 'p')
171 (errcode(ERRCODE_DATATYPE_MISMATCH),
172 errmsg("array element type cannot be %s",
173 format_type_be(elemType))));
175 else if (pg_strcasecmp(defel->defname, "default") == 0)
176 defaultValue = defGetString(defel);
177 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
178 byValue = defGetBoolean(defel);
179 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
181 char *a = defGetString(defel);
184 * Note: if argument was an unquoted identifier, parser will
185 * have applied translations to it, so be prepared to
186 * recognize translated type names as well as the nominal
189 if (pg_strcasecmp(a, "double") == 0 ||
190 pg_strcasecmp(a, "float8") == 0 ||
191 pg_strcasecmp(a, "pg_catalog.float8") == 0)
193 else if (pg_strcasecmp(a, "int4") == 0 ||
194 pg_strcasecmp(a, "pg_catalog.int4") == 0)
196 else if (pg_strcasecmp(a, "int2") == 0 ||
197 pg_strcasecmp(a, "pg_catalog.int2") == 0)
199 else if (pg_strcasecmp(a, "char") == 0 ||
200 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
204 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
205 errmsg("alignment \"%s\" not recognized", a)));
207 else if (pg_strcasecmp(defel->defname, "storage") == 0)
209 char *a = defGetString(defel);
211 if (pg_strcasecmp(a, "plain") == 0)
213 else if (pg_strcasecmp(a, "external") == 0)
215 else if (pg_strcasecmp(a, "extended") == 0)
217 else if (pg_strcasecmp(a, "main") == 0)
221 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
222 errmsg("storage \"%s\" not recognized", a)));
226 (errcode(ERRCODE_SYNTAX_ERROR),
227 errmsg("type attribute \"%s\" not recognized",
232 * make sure we have our required definitions
234 if (inputName == NIL)
236 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
237 errmsg("type input function must be specified")));
238 if (outputName == NIL)
240 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
241 errmsg("type output function must be specified")));
244 * Look to see if type already exists (presumably as a shell; if not,
245 * TypeCreate will complain). If it doesn't, create it as a shell, so
246 * that the OID is known for use in the I/O function definitions.
248 typoid = GetSysCacheOid(TYPENAMENSP,
249 CStringGetDatum(typeName),
250 ObjectIdGetDatum(typeNamespace),
252 if (!OidIsValid(typoid))
254 typoid = TypeShellMake(typeName, typeNamespace);
255 /* Make new shell type visible for modification below */
256 CommandCounterIncrement();
260 * Convert I/O proc names to OIDs
262 inputOid = findTypeInputFunction(inputName, typoid);
263 outputOid = findTypeOutputFunction(outputName, typoid);
265 receiveOid = findTypeReceiveFunction(receiveName, typoid);
267 sendOid = findTypeSendFunction(sendName, typoid);
270 * Verify that I/O procs return the expected thing. If we see OPAQUE,
271 * complain and change it to the correct type-safe choice.
273 resulttype = get_func_rettype(inputOid);
274 if (resulttype != typoid)
276 if (resulttype == OPAQUEOID)
278 /* backwards-compatibility hack */
280 (errmsg("changing return type of function %s from \"opaque\" to %s",
281 NameListToString(inputName), typeName)));
282 SetFunctionReturnType(inputOid, typoid);
286 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
287 errmsg("type input function %s must return type %s",
288 NameListToString(inputName), typeName)));
290 resulttype = get_func_rettype(outputOid);
291 if (resulttype != CSTRINGOID)
293 if (resulttype == OPAQUEOID)
295 /* backwards-compatibility hack */
297 (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
298 NameListToString(outputName))));
299 SetFunctionReturnType(outputOid, CSTRINGOID);
303 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
304 errmsg("type output function %s must return type \"cstring\"",
305 NameListToString(outputName))));
309 resulttype = get_func_rettype(receiveOid);
310 if (resulttype != typoid)
312 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
313 errmsg("type receive function %s must return type %s",
314 NameListToString(receiveName), typeName)));
318 resulttype = get_func_rettype(sendOid);
319 if (resulttype != BYTEAOID)
321 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
322 errmsg("type send function %s must return type \"bytea\"",
323 NameListToString(sendName))));
327 * Convert analysis function proc name to an OID. If no analysis
328 * function is specified, we'll use zero to select the built-in
332 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
335 * now have TypeCreate do all the real work.
338 TypeCreate(typeName, /* type name */
339 typeNamespace, /* namespace */
340 InvalidOid, /* preassigned type oid (not done here) */
341 InvalidOid, /* relation oid (n/a here) */
342 0, /* relation kind (ditto) */
343 internalLength, /* internal size */
344 'b', /* type-type (base type) */
345 delimiter, /* array element delimiter */
346 inputOid, /* input procedure */
347 outputOid, /* output procedure */
348 receiveOid, /* receive procedure */
349 sendOid, /* send procedure */
350 analyzeOid, /* analyze procedure */
351 elemType, /* element type ID */
352 InvalidOid, /* base type ID (only for domains) */
353 defaultValue, /* default type value */
354 NULL, /* no binary form available */
355 byValue, /* passed by value */
356 alignment, /* required alignment */
357 storage, /* TOAST strategy */
358 -1, /* typMod (Domains only) */
359 0, /* Array Dimensions of typbasetype */
360 false); /* Type NOT NULL */
363 * When we create a base type (as opposed to a complex type) we need
364 * to have an array entry for it in pg_type as well.
366 shadow_type = makeArrayTypeName(typeName);
368 /* alignment must be 'i' or 'd' for arrays */
369 alignment = (alignment == 'd') ? 'd' : 'i';
371 TypeCreate(shadow_type, /* type name */
372 typeNamespace, /* namespace */
373 InvalidOid, /* preassigned type oid (not done here) */
374 InvalidOid, /* relation oid (n/a here) */
375 0, /* relation kind (ditto) */
376 -1, /* internal size */
377 'b', /* type-type (base type) */
378 DEFAULT_TYPDELIM, /* array element delimiter */
379 F_ARRAY_IN, /* input procedure */
380 F_ARRAY_OUT, /* output procedure */
381 F_ARRAY_RECV, /* receive procedure */
382 F_ARRAY_SEND, /* send procedure */
383 InvalidOid, /* analyze procedure - default */
384 typoid, /* element type ID */
385 InvalidOid, /* base type ID */
386 NULL, /* never a default type value */
387 NULL, /* binary default isn't sent either */
388 false, /* never passed by value */
389 alignment, /* see above */
390 'x', /* ARRAY is always toastable */
391 -1, /* typMod (Domains only) */
392 0, /* Array dimensions of typbasetype */
393 false); /* Type NOT NULL */
401 * Removes a datatype.
404 RemoveType(List *names, DropBehavior behavior)
409 ObjectAddress object;
411 /* Make a TypeName so we can use standard type lookup machinery */
412 typename = makeNode(TypeName);
413 typename->names = names;
414 typename->typmod = -1;
415 typename->arrayBounds = NIL;
417 /* Use LookupTypeName here so that shell types can be removed. */
418 typeoid = LookupTypeName(typename);
419 if (!OidIsValid(typeoid))
421 (errcode(ERRCODE_UNDEFINED_OBJECT),
422 errmsg("type \"%s\" does not exist",
423 TypeNameToString(typename))));
425 tup = SearchSysCache(TYPEOID,
426 ObjectIdGetDatum(typeoid),
428 if (!HeapTupleIsValid(tup))
429 elog(ERROR, "cache lookup failed for type %u", typeoid);
431 /* Permission check: must own type or its namespace */
432 if (!pg_type_ownercheck(typeoid, GetUserId()) &&
433 !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace,
435 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
436 TypeNameToString(typename));
438 ReleaseSysCache(tup);
443 object.classId = TypeRelationId;
444 object.objectId = typeoid;
445 object.objectSubId = 0;
447 performDeletion(&object, behavior);
452 * Guts of type deletion.
455 RemoveTypeById(Oid typeOid)
460 relation = heap_open(TypeRelationId, RowExclusiveLock);
462 tup = SearchSysCache(TYPEOID,
463 ObjectIdGetDatum(typeOid),
465 if (!HeapTupleIsValid(tup))
466 elog(ERROR, "cache lookup failed for type %u", typeOid);
468 simple_heap_delete(relation, &tup->t_self);
470 ReleaseSysCache(tup);
472 heap_close(relation, RowExclusiveLock);
478 * Registers a new domain.
481 DefineDomain(CreateDomainStmt *stmt)
486 int16 internalLength;
489 Oid receiveProcedure;
491 Oid analyzeProcedure;
499 Node *defaultExpr = NULL;
500 char *defaultValue = NULL;
501 char *defaultValueBin = NULL;
502 bool typNotNull = false;
503 bool nullDefined = false;
505 int32 typNDims = list_length(stmt->typename->arrayBounds);
507 List *schema = stmt->constraints;
511 Form_pg_type baseType;
513 /* Convert list of names to a name and namespace */
514 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
517 /* Check we have creation rights in target namespace */
518 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
520 if (aclresult != ACLCHECK_OK)
521 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
522 get_namespace_name(domainNamespace));
525 * Domainnames, unlike typenames don't need to account for the '_'
526 * prefix. So they can be one character longer. (This test is
527 * presently useless since the parser will have truncated the name to
528 * fit. But leave it here since we may someday support arrays of
529 * domains, in which case we'll be back to needing to enforce
532 if (strlen(domainName) > (NAMEDATALEN - 1))
534 (errcode(ERRCODE_INVALID_NAME),
535 errmsg("domain names must be %d characters or less",
539 * Look up the base type.
541 typeTup = typenameType(stmt->typename);
543 baseType = (Form_pg_type) GETSTRUCT(typeTup);
544 basetypeoid = HeapTupleGetOid(typeTup);
547 * Base type must be a plain base type. Domains over pseudo types
548 * would create a security hole. Domains of domains might be made to
549 * work in the future, but not today. Ditto for domains over complex
552 typtype = baseType->typtype;
555 (errcode(ERRCODE_DATATYPE_MISMATCH),
556 errmsg("\"%s\" is not a valid base type for a domain",
557 TypeNameToString(stmt->typename))));
559 /* passed by value */
560 byValue = baseType->typbyval;
562 /* Required Alignment */
563 alignment = baseType->typalign;
566 storage = baseType->typstorage;
569 internalLength = baseType->typlen;
571 /* Array element Delimiter */
572 delimiter = baseType->typdelim;
575 inputProcedure = baseType->typinput;
576 outputProcedure = baseType->typoutput;
577 receiveProcedure = baseType->typreceive;
578 sendProcedure = baseType->typsend;
580 /* Analysis function */
581 analyzeProcedure = baseType->typanalyze;
583 /* Inherited default value */
584 datum = SysCacheGetAttr(TYPEOID, typeTup,
585 Anum_pg_type_typdefault, &isnull);
587 defaultValue = DatumGetCString(DirectFunctionCall1(textout, datum));
589 /* Inherited default binary value */
590 datum = SysCacheGetAttr(TYPEOID, typeTup,
591 Anum_pg_type_typdefaultbin, &isnull);
593 defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum));
596 * Pull out the typelem name of the parent OID.
598 * This is what enables us to make a domain of an array
600 basetypelem = baseType->typelem;
603 * Run through constraints manually to avoid the additional processing
604 * conducted by DefineRelation() and friends.
606 foreach(listptr, schema)
608 Node *newConstraint = lfirst(listptr);
612 /* Check for unsupported constraint types */
613 if (IsA(newConstraint, FkConstraint))
615 (errcode(ERRCODE_SYNTAX_ERROR),
616 errmsg("foreign key constraints not possible for domains")));
618 /* otherwise it should be a plain Constraint */
619 if (!IsA(newConstraint, Constraint))
620 elog(ERROR, "unrecognized node type: %d",
621 (int) nodeTag(newConstraint));
623 constr = (Constraint *) newConstraint;
625 switch (constr->contype)
630 * The inherited default value may be overridden by the
631 * user with the DEFAULT <expr> statement.
635 (errcode(ERRCODE_SYNTAX_ERROR),
636 errmsg("multiple default expressions")));
638 /* Create a dummy ParseState for transformExpr */
639 pstate = make_parsestate(NULL);
642 * Cook the constr->raw_expr into an expression. Note:
643 * Name is strictly for error message
645 defaultExpr = cookDefault(pstate, constr->raw_expr,
647 stmt->typename->typmod,
651 * Expression must be stored as a nodeToString result, but
652 * we also require a valid textual representation (mainly
653 * to make life easier for pg_dump).
655 defaultValue = deparse_expression(defaultExpr,
656 deparse_context_for(domainName,
659 defaultValueBin = nodeToString(defaultExpr);
663 if (nullDefined && !typNotNull)
665 (errcode(ERRCODE_SYNTAX_ERROR),
666 errmsg("conflicting NULL/NOT NULL constraints")));
672 if (nullDefined && typNotNull)
674 (errcode(ERRCODE_SYNTAX_ERROR),
675 errmsg("conflicting NULL/NOT NULL constraints")));
683 * Check constraints are handled after domain creation, as
684 * they require the Oid of the domain
689 * All else are error cases
693 (errcode(ERRCODE_SYNTAX_ERROR),
694 errmsg("unique constraints not possible for domains")));
699 (errcode(ERRCODE_SYNTAX_ERROR),
700 errmsg("primary key constraints not possible for domains")));
703 case CONSTR_ATTR_DEFERRABLE:
704 case CONSTR_ATTR_NOT_DEFERRABLE:
705 case CONSTR_ATTR_DEFERRED:
706 case CONSTR_ATTR_IMMEDIATE:
708 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
709 errmsg("specifying constraint deferrability not supported for domains")));
713 elog(ERROR, "unrecognized constraint subtype: %d",
714 (int) constr->contype);
720 * Have TypeCreate do all the real work.
723 TypeCreate(domainName, /* type name */
724 domainNamespace, /* namespace */
725 InvalidOid, /* preassigned type oid (none here) */
726 InvalidOid, /* relation oid (n/a here) */
727 0, /* relation kind (ditto) */
728 internalLength, /* internal size */
729 'd', /* type-type (domain type) */
730 delimiter, /* array element delimiter */
731 inputProcedure, /* input procedure */
732 outputProcedure, /* output procedure */
733 receiveProcedure, /* receive procedure */
734 sendProcedure, /* send procedure */
735 analyzeProcedure, /* analyze procedure */
736 basetypelem, /* element type ID */
737 basetypeoid, /* base type ID */
738 defaultValue, /* default type value (text) */
739 defaultValueBin, /* default type value (binary) */
740 byValue, /* passed by value */
741 alignment, /* required alignment */
742 storage, /* TOAST strategy */
743 stmt->typename->typmod, /* typeMod value */
744 typNDims, /* Array dimensions for base type */
745 typNotNull); /* Type NOT NULL */
748 * Process constraints which refer to the domain ID returned by
751 foreach(listptr, schema)
753 Constraint *constr = lfirst(listptr);
755 /* it must be a Constraint, per check above */
757 switch (constr->contype)
760 domainAddConstraint(domainoid, domainNamespace,
761 basetypeoid, stmt->typename->typmod,
765 /* Other constraint types were fully processed above */
771 /* CCI so we can detect duplicate constraint names */
772 CommandCounterIncrement();
776 * Now we can clean up.
778 ReleaseSysCache(typeTup);
786 * This is identical to RemoveType except we insist it be a domain.
789 RemoveDomain(List *names, DropBehavior behavior)
795 ObjectAddress object;
797 /* Make a TypeName so we can use standard type lookup machinery */
798 typename = makeNode(TypeName);
799 typename->names = names;
800 typename->typmod = -1;
801 typename->arrayBounds = NIL;
803 /* Use LookupTypeName here so that shell types can be removed. */
804 typeoid = LookupTypeName(typename);
805 if (!OidIsValid(typeoid))
807 (errcode(ERRCODE_UNDEFINED_OBJECT),
808 errmsg("type \"%s\" does not exist",
809 TypeNameToString(typename))));
811 tup = SearchSysCache(TYPEOID,
812 ObjectIdGetDatum(typeoid),
814 if (!HeapTupleIsValid(tup))
815 elog(ERROR, "cache lookup failed for type %u", typeoid);
817 /* Permission check: must own type or its namespace */
818 if (!pg_type_ownercheck(typeoid, GetUserId()) &&
819 !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace,
821 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
822 TypeNameToString(typename));
824 /* Check that this is actually a domain */
825 typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
829 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
830 errmsg("\"%s\" is not a domain",
831 TypeNameToString(typename))));
833 ReleaseSysCache(tup);
838 object.classId = TypeRelationId;
839 object.objectId = typeoid;
840 object.objectSubId = 0;
842 performDeletion(&object, behavior);
847 * Find suitable I/O functions for a type.
849 * typeOid is the type's OID (which will already exist, if only as a shell
854 findTypeInputFunction(List *procname, Oid typeOid)
860 * Input functions can take a single argument of type CSTRING, or
861 * three arguments (string, element OID, typmod).
863 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
864 * see this, we issue a warning and fix up the pg_proc entry.
866 argList[0] = CSTRINGOID;
868 procOid = LookupFuncName(procname, 1, argList, true);
869 if (OidIsValid(procOid))
873 argList[2] = INT4OID;
875 procOid = LookupFuncName(procname, 3, argList, true);
876 if (OidIsValid(procOid))
879 /* No luck, try it with OPAQUE */
880 argList[0] = OPAQUEOID;
882 procOid = LookupFuncName(procname, 1, argList, true);
884 if (!OidIsValid(procOid))
887 argList[2] = INT4OID;
889 procOid = LookupFuncName(procname, 3, argList, true);
892 if (OidIsValid(procOid))
894 /* Found, but must complain and fix the pg_proc entry */
896 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
897 NameListToString(procname))));
898 SetFunctionArgType(procOid, 0, CSTRINGOID);
901 * Need CommandCounterIncrement since DefineType will likely try
902 * to alter the pg_proc tuple again.
904 CommandCounterIncrement();
909 /* Use CSTRING (preferred) in the error message */
910 argList[0] = CSTRINGOID;
913 (errcode(ERRCODE_UNDEFINED_FUNCTION),
914 errmsg("function %s does not exist",
915 func_signature_string(procname, 1, argList))));
917 return InvalidOid; /* keep compiler quiet */
921 findTypeOutputFunction(List *procname, Oid typeOid)
927 * Output functions can take a single argument of the type, or two
928 * arguments (data value, element OID).
930 * For backwards compatibility we allow OPAQUE in place of the actual
931 * type name; if we see this, we issue a warning and fix up the
934 argList[0] = typeOid;
936 procOid = LookupFuncName(procname, 1, argList, true);
937 if (OidIsValid(procOid))
942 procOid = LookupFuncName(procname, 2, argList, true);
943 if (OidIsValid(procOid))
946 /* No luck, try it with OPAQUE */
947 argList[0] = OPAQUEOID;
949 procOid = LookupFuncName(procname, 1, argList, true);
951 if (!OidIsValid(procOid))
955 procOid = LookupFuncName(procname, 2, argList, true);
958 if (OidIsValid(procOid))
960 /* Found, but must complain and fix the pg_proc entry */
962 (errmsg("changing argument type of function %s from \"opaque\" to %s",
963 NameListToString(procname), format_type_be(typeOid))));
964 SetFunctionArgType(procOid, 0, typeOid);
967 * Need CommandCounterIncrement since DefineType will likely try
968 * to alter the pg_proc tuple again.
970 CommandCounterIncrement();
975 /* Use type name, not OPAQUE, in the failure message. */
976 argList[0] = typeOid;
979 (errcode(ERRCODE_UNDEFINED_FUNCTION),
980 errmsg("function %s does not exist",
981 func_signature_string(procname, 1, argList))));
983 return InvalidOid; /* keep compiler quiet */
987 findTypeReceiveFunction(List *procname, Oid typeOid)
993 * Receive functions can take a single argument of type INTERNAL, or
994 * two arguments (internal, oid).
996 argList[0] = INTERNALOID;
998 procOid = LookupFuncName(procname, 1, argList, true);
999 if (OidIsValid(procOid))
1002 argList[1] = OIDOID;
1004 procOid = LookupFuncName(procname, 2, argList, true);
1005 if (OidIsValid(procOid))
1009 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1010 errmsg("function %s does not exist",
1011 func_signature_string(procname, 1, argList))));
1013 return InvalidOid; /* keep compiler quiet */
1017 findTypeSendFunction(List *procname, Oid typeOid)
1023 * Send functions can take a single argument of the type, or two
1024 * arguments (data value, element OID).
1026 argList[0] = typeOid;
1028 procOid = LookupFuncName(procname, 1, argList, true);
1029 if (OidIsValid(procOid))
1032 argList[1] = OIDOID;
1034 procOid = LookupFuncName(procname, 2, argList, true);
1035 if (OidIsValid(procOid))
1039 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1040 errmsg("function %s does not exist",
1041 func_signature_string(procname, 1, argList))));
1043 return InvalidOid; /* keep compiler quiet */
1047 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1053 * Analyze functions always take one INTERNAL argument and return
1056 argList[0] = INTERNALOID;
1058 procOid = LookupFuncName(procname, 1, argList, true);
1059 if (!OidIsValid(procOid))
1061 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1062 errmsg("function %s does not exist",
1063 func_signature_string(procname, 1, argList))));
1065 if (get_func_rettype(procOid) != BOOLOID)
1067 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1068 errmsg("type analyze function %s must return type \"boolean\"",
1069 NameListToString(procname))));
1075 /*-------------------------------------------------------------------
1076 * DefineCompositeType
1078 * Create a Composite Type relation.
1079 * `DefineRelation' does all the work, we just provide the correct
1082 * If the relation already exists, then 'DefineRelation' will abort
1085 * DefineCompositeType returns relid for use when creating
1086 * an implicit composite type during function creation
1087 *-------------------------------------------------------------------
1090 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1092 CreateStmt *createStmt = makeNode(CreateStmt);
1094 if (coldeflist == NIL)
1096 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1097 errmsg("composite type must have at least one attribute")));
1100 * now set the parameters for keys/inheritance etc. All of these are
1101 * uninteresting for composite types...
1103 createStmt->relation = (RangeVar *) typevar;
1104 createStmt->tableElts = coldeflist;
1105 createStmt->inhRelations = NIL;
1106 createStmt->constraints = NIL;
1107 createStmt->hasoids = MUST_NOT_HAVE_OIDS;
1108 createStmt->oncommit = ONCOMMIT_NOOP;
1109 createStmt->tablespacename = NULL;
1112 * finally create the relation...
1114 return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);
1118 * AlterDomainDefault
1120 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
1123 AlterDomainDefault(List *names, Node *defaultRaw)
1131 Node *defaultExpr = NULL; /* NULL if no default specified */
1132 Datum new_record[Natts_pg_type];
1133 char new_record_nulls[Natts_pg_type];
1134 char new_record_repl[Natts_pg_type];
1136 Form_pg_type typTup;
1138 /* Make a TypeName so we can use standard type lookup machinery */
1139 typename = makeNode(TypeName);
1140 typename->names = names;
1141 typename->typmod = -1;
1142 typename->arrayBounds = NIL;
1144 /* Lock the domain in the type table */
1145 rel = heap_open(TypeRelationId, RowExclusiveLock);
1147 /* Use LookupTypeName here so that shell types can be removed. */
1148 domainoid = LookupTypeName(typename);
1149 if (!OidIsValid(domainoid))
1151 (errcode(ERRCODE_UNDEFINED_OBJECT),
1152 errmsg("type \"%s\" does not exist",
1153 TypeNameToString(typename))));
1155 tup = SearchSysCacheCopy(TYPEOID,
1156 ObjectIdGetDatum(domainoid),
1158 if (!HeapTupleIsValid(tup))
1159 elog(ERROR, "cache lookup failed for type %u", domainoid);
1161 /* Doesn't return if user isn't allowed to alter the domain */
1162 domainOwnerCheck(tup, typename);
1164 /* Setup new tuple */
1165 MemSet(new_record, (Datum) 0, sizeof(new_record));
1166 MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
1167 MemSet(new_record_repl, ' ', sizeof(new_record_repl));
1170 typTup = (Form_pg_type) GETSTRUCT(tup);
1172 /* Store the new default, if null then skip this step */
1175 /* Create a dummy ParseState for transformExpr */
1176 pstate = make_parsestate(NULL);
1179 * Cook the colDef->raw_expr into an expression. Note: Name is
1180 * strictly for error message
1182 defaultExpr = cookDefault(pstate, defaultRaw,
1183 typTup->typbasetype,
1185 NameStr(typTup->typname));
1188 * Expression must be stored as a nodeToString result, but we also
1189 * require a valid textual representation (mainly to make life
1190 * easier for pg_dump).
1192 defaultValue = deparse_expression(defaultExpr,
1193 deparse_context_for(NameStr(typTup->typname),
1198 * Form an updated tuple with the new default and write it back.
1200 new_record[Anum_pg_type_typdefaultbin - 1] = DirectFunctionCall1(textin,
1202 nodeToString(defaultExpr)));
1204 new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
1205 new_record[Anum_pg_type_typdefault - 1] = DirectFunctionCall1(textin,
1206 CStringGetDatum(defaultValue));
1207 new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
1210 /* Default is NULL, drop it */
1212 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = 'n';
1213 new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
1214 new_record_nulls[Anum_pg_type_typdefault - 1] = 'n';
1215 new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
1218 newtuple = heap_modifytuple(tup, RelationGetDescr(rel),
1219 new_record, new_record_nulls,
1222 simple_heap_update(rel, &tup->t_self, newtuple);
1224 CatalogUpdateIndexes(rel, newtuple);
1226 /* Rebuild dependencies */
1227 GenerateTypeDependencies(typTup->typnamespace,
1230 0, /* relation kind is n/a */
1237 typTup->typbasetype,
1239 true); /* Rebuild is true */
1242 heap_close(rel, NoLock);
1243 heap_freetuple(newtuple);
1247 * AlterDomainNotNull
1249 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
1252 AlterDomainNotNull(List *names, bool notNull)
1258 Form_pg_type typTup;
1260 /* Make a TypeName so we can use standard type lookup machinery */
1261 typename = makeNode(TypeName);
1262 typename->names = names;
1263 typename->typmod = -1;
1264 typename->arrayBounds = NIL;
1266 /* Lock the type table */
1267 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1269 /* Use LookupTypeName here so that shell types can be found (why?). */
1270 domainoid = LookupTypeName(typename);
1271 if (!OidIsValid(domainoid))
1273 (errcode(ERRCODE_UNDEFINED_OBJECT),
1274 errmsg("type \"%s\" does not exist",
1275 TypeNameToString(typename))));
1277 tup = SearchSysCacheCopy(TYPEOID,
1278 ObjectIdGetDatum(domainoid),
1280 if (!HeapTupleIsValid(tup))
1281 elog(ERROR, "cache lookup failed for type %u", domainoid);
1282 typTup = (Form_pg_type) GETSTRUCT(tup);
1284 /* Doesn't return if user isn't allowed to alter the domain */
1285 domainOwnerCheck(tup, typename);
1287 /* Is the domain already set to the desired constraint? */
1288 if (typTup->typnotnull == notNull)
1290 heap_close(typrel, RowExclusiveLock);
1294 /* Adding a NOT NULL constraint requires checking existing columns */
1300 /* Fetch relation list with attributes based on this domain */
1301 /* ShareLock is sufficient to prevent concurrent data changes */
1303 rels = get_rels_with_domain(domainoid, ShareLock);
1307 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1308 Relation testrel = rtc->rel;
1309 TupleDesc tupdesc = RelationGetDescr(testrel);
1313 /* Scan all tuples in this relation */
1314 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1315 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1319 /* Test attributes that are of the domain */
1320 for (i = 0; i < rtc->natts; i++)
1322 int attnum = rtc->atts[i];
1324 if (heap_attisnull(tuple, attnum))
1326 (errcode(ERRCODE_NOT_NULL_VIOLATION),
1327 errmsg("column \"%s\" of table \"%s\" contains null values",
1328 NameStr(tupdesc->attrs[attnum - 1]->attname),
1329 RelationGetRelationName(testrel))));
1334 /* Close each rel after processing, but keep lock */
1335 heap_close(testrel, NoLock);
1340 * Okay to update pg_type row. We can scribble on typTup because it's
1343 typTup->typnotnull = notNull;
1345 simple_heap_update(typrel, &tup->t_self, tup);
1347 CatalogUpdateIndexes(typrel, tup);
1350 heap_freetuple(tup);
1351 heap_close(typrel, RowExclusiveLock);
1355 * AlterDomainDropConstraint
1357 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
1360 AlterDomainDropConstraint(List *names, const char *constrName, DropBehavior behavior)
1366 Form_pg_type typTup;
1368 SysScanDesc conscan;
1372 /* Make a TypeName so we can use standard type lookup machinery */
1373 typename = makeNode(TypeName);
1374 typename->names = names;
1375 typename->typmod = -1;
1376 typename->arrayBounds = NIL;
1378 /* Lock the type table */
1379 rel = heap_open(TypeRelationId, RowExclusiveLock);
1381 /* Use LookupTypeName here so that shell types can be removed. */
1382 domainoid = LookupTypeName(typename);
1383 if (!OidIsValid(domainoid))
1385 (errcode(ERRCODE_UNDEFINED_OBJECT),
1386 errmsg("type \"%s\" does not exist",
1387 TypeNameToString(typename))));
1389 tup = SearchSysCacheCopy(TYPEOID,
1390 ObjectIdGetDatum(domainoid),
1392 if (!HeapTupleIsValid(tup))
1393 elog(ERROR, "cache lookup failed for type %u", domainoid);
1395 /* Doesn't return if user isn't allowed to alter the domain */
1396 domainOwnerCheck(tup, typename);
1398 /* Grab an appropriate lock on the pg_constraint relation */
1399 conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
1401 /* Use the index to scan only constraints of the target relation */
1402 ScanKeyInit(&key[0],
1403 Anum_pg_constraint_contypid,
1404 BTEqualStrategyNumber, F_OIDEQ,
1405 ObjectIdGetDatum(HeapTupleGetOid(tup)));
1407 conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
1408 SnapshotNow, 1, key);
1410 typTup = (Form_pg_type) GETSTRUCT(tup);
1413 * Scan over the result set, removing any matching entries.
1415 while ((contup = systable_getnext(conscan)) != NULL)
1417 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
1419 if (strcmp(NameStr(con->conname), constrName) == 0)
1421 ObjectAddress conobj;
1423 conobj.classId = ConstraintRelationId;
1424 conobj.objectId = HeapTupleGetOid(contup);
1425 conobj.objectSubId = 0;
1427 performDeletion(&conobj, behavior);
1430 /* Clean up after the scan */
1431 systable_endscan(conscan);
1432 heap_close(conrel, RowExclusiveLock);
1434 heap_close(rel, NoLock);
1438 * AlterDomainAddConstraint
1440 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
1443 AlterDomainAddConstraint(List *names, Node *newConstraint)
1449 Form_pg_type typTup;
1453 ExprContext *econtext;
1456 ExprState *exprstate;
1459 /* Make a TypeName so we can use standard type lookup machinery */
1460 typename = makeNode(TypeName);
1461 typename->names = names;
1462 typename->typmod = -1;
1463 typename->arrayBounds = NIL;
1465 /* Lock the type table */
1466 typrel = heap_open(TypeRelationId, RowExclusiveLock);
1468 /* Use LookupTypeName here so that shell types can be found (why?). */
1469 domainoid = LookupTypeName(typename);
1470 if (!OidIsValid(domainoid))
1472 (errcode(ERRCODE_UNDEFINED_OBJECT),
1473 errmsg("type \"%s\" does not exist",
1474 TypeNameToString(typename))));
1476 tup = SearchSysCacheCopy(TYPEOID,
1477 ObjectIdGetDatum(domainoid),
1479 if (!HeapTupleIsValid(tup))
1480 elog(ERROR, "cache lookup failed for type %u", domainoid);
1481 typTup = (Form_pg_type) GETSTRUCT(tup);
1483 /* Doesn't return if user isn't allowed to alter the domain */
1484 domainOwnerCheck(tup, typename);
1486 /* Check for unsupported constraint types */
1487 if (IsA(newConstraint, FkConstraint))
1489 (errcode(ERRCODE_SYNTAX_ERROR),
1490 errmsg("foreign key constraints not possible for domains")));
1492 /* otherwise it should be a plain Constraint */
1493 if (!IsA(newConstraint, Constraint))
1494 elog(ERROR, "unrecognized node type: %d",
1495 (int) nodeTag(newConstraint));
1497 constr = (Constraint *) newConstraint;
1499 switch (constr->contype)
1502 /* processed below */
1507 (errcode(ERRCODE_SYNTAX_ERROR),
1508 errmsg("unique constraints not possible for domains")));
1511 case CONSTR_PRIMARY:
1513 (errcode(ERRCODE_SYNTAX_ERROR),
1514 errmsg("primary key constraints not possible for domains")));
1517 case CONSTR_ATTR_DEFERRABLE:
1518 case CONSTR_ATTR_NOT_DEFERRABLE:
1519 case CONSTR_ATTR_DEFERRED:
1520 case CONSTR_ATTR_IMMEDIATE:
1522 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1523 errmsg("specifying constraint deferrability not supported for domains")));
1527 elog(ERROR, "unrecognized constraint subtype: %d",
1528 (int) constr->contype);
1533 * Since all other constraint types throw errors, this must be a check
1534 * constraint. First, process the constraint expression and add an
1535 * entry to pg_constraint.
1538 ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
1539 typTup->typbasetype, typTup->typtypmod,
1540 constr, NameStr(typTup->typname));
1543 * Test all values stored in the attributes based on the domain the
1544 * constraint is being added to.
1546 expr = (Expr *) stringToNode(ccbin);
1548 /* Need an EState to run ExecEvalExpr */
1549 estate = CreateExecutorState();
1550 econtext = GetPerTupleExprContext(estate);
1552 /* build execution state for expr */
1553 exprstate = ExecPrepareExpr(expr, estate);
1555 /* Fetch relation list with attributes based on this domain */
1556 /* ShareLock is sufficient to prevent concurrent data changes */
1558 rels = get_rels_with_domain(domainoid, ShareLock);
1562 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1563 Relation testrel = rtc->rel;
1564 TupleDesc tupdesc = RelationGetDescr(testrel);
1568 /* Scan all tuples in this relation */
1569 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1570 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1574 /* Test attributes that are of the domain */
1575 for (i = 0; i < rtc->natts; i++)
1577 int attnum = rtc->atts[i];
1582 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
1584 econtext->domainValue_datum = d;
1585 econtext->domainValue_isNull = isNull;
1587 conResult = ExecEvalExprSwitchContext(exprstate,
1591 if (!isNull && !DatumGetBool(conResult))
1593 (errcode(ERRCODE_CHECK_VIOLATION),
1594 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
1595 NameStr(tupdesc->attrs[attnum - 1]->attname),
1596 RelationGetRelationName(testrel))));
1599 ResetExprContext(econtext);
1603 /* Hold relation lock till commit (XXX bad for concurrency) */
1604 heap_close(testrel, NoLock);
1607 FreeExecutorState(estate);
1610 heap_close(typrel, RowExclusiveLock);
1614 * get_rels_with_domain
1616 * Fetch all relations / attributes which are using the domain
1618 * The result is a list of RelToCheck structs, one for each distinct
1619 * relation, each containing one or more attribute numbers that are of
1620 * the domain type. We have opened each rel and acquired the specified lock
1623 * XXX this is completely broken because there is no way to lock the domain
1624 * to prevent columns from being added or dropped while our command runs.
1625 * We can partially protect against column drops by locking relations as we
1626 * come across them, but there is still a race condition (the window between
1627 * seeing a pg_depend entry and acquiring lock on the relation it references).
1628 * Also, holding locks on all these relations simultaneously creates a non-
1629 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
1630 * risk by using the weakest suitable lock (ShareLock for most callers).
1632 * XXX to support domains over domains, we'd need to make this smarter,
1633 * or make its callers smarter, so that we could find columns of derived
1634 * domains. Arrays of domains would be a problem too.
1636 * Generally used for retrieving a list of tests when adding
1637 * new constraints to a domain.
1640 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
1645 SysScanDesc depScan;
1649 * We scan pg_depend to find those things that depend on the domain.
1650 * (We assume we can ignore refobjsubid for a domain.)
1652 depRel = heap_open(DependRelationId, AccessShareLock);
1654 ScanKeyInit(&key[0],
1655 Anum_pg_depend_refclassid,
1656 BTEqualStrategyNumber, F_OIDEQ,
1657 ObjectIdGetDatum(TypeRelationId));
1658 ScanKeyInit(&key[1],
1659 Anum_pg_depend_refobjid,
1660 BTEqualStrategyNumber, F_OIDEQ,
1661 ObjectIdGetDatum(domainOid));
1663 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
1664 SnapshotNow, 2, key);
1666 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
1668 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
1669 RelToCheck *rtc = NULL;
1671 Form_pg_attribute pg_att;
1674 /* Ignore dependees that aren't user columns of relations */
1675 /* (we assume system columns are never of domain types) */
1676 if (pg_depend->classid != RelationRelationId ||
1677 pg_depend->objsubid <= 0)
1680 /* See if we already have an entry for this relation */
1681 foreach(rellist, result)
1683 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
1685 if (RelationGetRelid(rt->rel) == pg_depend->objid)
1694 /* First attribute found for this relation */
1697 /* Acquire requested lock on relation */
1698 rel = relation_open(pg_depend->objid, lockmode);
1700 /* It could be a view or composite type; if so ignore it */
1701 if (rel->rd_rel->relkind != RELKIND_RELATION)
1703 relation_close(rel, lockmode);
1707 /* Build the RelToCheck entry with enough space for all atts */
1708 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
1711 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
1712 result = lcons(rtc, result);
1716 * Confirm column has not been dropped, and is of the expected
1717 * type. This defends against an ALTER DROP COLUMN occuring just
1718 * before we acquired lock ... but if the whole table were
1719 * dropped, we'd still have a problem.
1721 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
1723 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
1724 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
1728 * Okay, add column to result. We store the columns in
1729 * column-number order; this is just a hack to improve
1730 * predictability of regression test output ...
1732 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
1735 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
1737 rtc->atts[ptr] = rtc->atts[ptr - 1];
1740 rtc->atts[ptr] = pg_depend->objsubid;
1743 systable_endscan(depScan);
1745 relation_close(depRel, AccessShareLock);
1753 * Throw an error if the current user doesn't have permission to modify
1754 * the domain in an ALTER DOMAIN statement, or if the type isn't actually
1758 domainOwnerCheck(HeapTuple tup, TypeName *typename)
1760 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1762 /* Check that this is actually a domain */
1763 if (typTup->typtype != 'd')
1765 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1766 errmsg("\"%s\" is not a domain",
1767 TypeNameToString(typename))));
1769 /* Permission check: must own type */
1770 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1771 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
1772 TypeNameToString(typename));
1776 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
1779 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
1780 int typMod, Constraint *constr,
1787 CoerceToDomainValue *domVal;
1790 * Assign or validate constraint name
1794 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
1799 (errcode(ERRCODE_DUPLICATE_OBJECT),
1800 errmsg("constraint \"%s\" for domain \"%s\" already exists",
1801 constr->name, domainName)));
1804 constr->name = ChooseConstraintName(domainName,
1811 * Convert the A_EXPR in raw_expr into an EXPR
1813 pstate = make_parsestate(NULL);
1816 * Set up a CoerceToDomainValue to represent the occurrence of VALUE
1817 * in the expression. Note that it will appear to have the type of
1818 * the base type, not the domain. This seems correct since within the
1819 * check expression, we should not assume the input value can be
1820 * considered a member of the domain.
1822 domVal = makeNode(CoerceToDomainValue);
1823 domVal->typeId = baseTypeOid;
1824 domVal->typeMod = typMod;
1826 pstate->p_value_substitute = (Node *) domVal;
1828 expr = transformExpr(pstate, constr->raw_expr);
1831 * Make sure it yields a boolean result.
1833 expr = coerce_to_boolean(pstate, expr, "CHECK");
1836 * Make sure no outside relations are referred to.
1838 if (list_length(pstate->p_rtable) != 0)
1840 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1841 errmsg("cannot use table references in domain check constraint")));
1844 * Domains don't allow var clauses (this should be redundant with the
1845 * above check, but make it anyway)
1847 if (contain_var_clause(expr))
1849 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1850 errmsg("cannot use table references in domain check constraint")));
1853 * No subplans or aggregates, either...
1855 if (pstate->p_hasSubLinks)
1857 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1858 errmsg("cannot use subquery in check constraint")));
1859 if (pstate->p_hasAggs)
1861 (errcode(ERRCODE_GROUPING_ERROR),
1862 errmsg("cannot use aggregate in check constraint")));
1865 * Convert to string form for storage.
1867 ccbin = nodeToString(expr);
1870 * Deparse it to produce text for consrc.
1872 * Since VARNOs aren't allowed in domain constraints, relation context
1873 * isn't required as anything other than a shell.
1875 ccsrc = deparse_expression(expr,
1876 deparse_context_for(domainName,
1881 * Store the constraint in pg_constraint
1883 CreateConstraintEntry(constr->name, /* Constraint Name */
1884 domainNamespace, /* namespace */
1885 CONSTRAINT_CHECK, /* Constraint Type */
1886 false, /* Is Deferrable */
1887 false, /* Is Deferred */
1888 InvalidOid, /* not a relation constraint */
1891 domainOid, /* domain constraint */
1892 InvalidOid, /* Foreign key fields */
1899 expr, /* Tree form check constraint */
1900 ccbin, /* Binary form check constraint */
1901 ccsrc); /* Source form check constraint */
1904 * Return the compiled constraint expression so the calling routine
1905 * can perform any additional required tests.
1911 * GetDomainConstraints - get a list of the current constraints of domain
1913 * Returns a possibly-empty list of DomainConstraintState nodes.
1915 * This is called by the executor during plan startup for a CoerceToDomain
1916 * expression node. The given constraints will be checked for each value
1917 * passed through the node.
1919 * We allow this to be called for non-domain types, in which case the result
1923 GetDomainConstraints(Oid typeOid)
1926 bool notNull = false;
1929 conRel = heap_open(ConstraintRelationId, AccessShareLock);
1935 Form_pg_type typTup;
1939 tup = SearchSysCache(TYPEOID,
1940 ObjectIdGetDatum(typeOid),
1942 if (!HeapTupleIsValid(tup))
1943 elog(ERROR, "cache lookup failed for type %u", typeOid);
1944 typTup = (Form_pg_type) GETSTRUCT(tup);
1946 if (typTup->typtype != 'd')
1948 /* Not a domain, so done */
1949 ReleaseSysCache(tup);
1953 /* Test for NOT NULL Constraint */
1954 if (typTup->typnotnull)
1957 /* Look for CHECK Constraints on this domain */
1958 ScanKeyInit(&key[0],
1959 Anum_pg_constraint_contypid,
1960 BTEqualStrategyNumber, F_OIDEQ,
1961 ObjectIdGetDatum(typeOid));
1963 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
1964 SnapshotNow, 1, key);
1966 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
1968 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
1972 DomainConstraintState *r;
1974 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
1975 if (c->contype != CONSTRAINT_CHECK)
1979 * Not expecting conbin to be NULL, but we'll test for it
1982 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
1983 conRel->rd_att, &isNull);
1985 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
1986 NameStr(typTup->typname), NameStr(c->conname));
1988 check_expr = (Expr *)
1989 stringToNode(DatumGetCString(DirectFunctionCall1(textout,
1992 /* ExecInitExpr assumes we already fixed opfuncids */
1993 fix_opfuncids((Node *) check_expr);
1995 r = makeNode(DomainConstraintState);
1996 r->constrainttype = DOM_CONSTRAINT_CHECK;
1997 r->name = pstrdup(NameStr(c->conname));
1998 r->check_expr = ExecInitExpr(check_expr, NULL);
2001 * use lcons() here because constraints of lower domains
2002 * should be applied earlier.
2004 result = lcons(r, result);
2007 systable_endscan(scan);
2009 /* loop to next domain in stack */
2010 typeOid = typTup->typbasetype;
2011 ReleaseSysCache(tup);
2014 heap_close(conRel, AccessShareLock);
2017 * Only need to add one NOT NULL check regardless of how many domains
2018 * in the stack request it.
2022 DomainConstraintState *r = makeNode(DomainConstraintState);
2024 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
2025 r->name = pstrdup("NOT NULL");
2026 r->check_expr = NULL;
2028 /* lcons to apply the nullness check FIRST */
2029 result = lcons(r, result);
2036 * Change the owner of a type.
2039 AlterTypeOwner(List *names, AclId newOwnerSysId)
2045 Form_pg_type typTup;
2047 /* Make a TypeName so we can use standard type lookup machinery */
2048 typename = makeNode(TypeName);
2049 typename->names = names;
2050 typename->typmod = -1;
2051 typename->arrayBounds = NIL;
2053 /* Lock the type table */
2054 rel = heap_open(TypeRelationId, RowExclusiveLock);
2056 /* Use LookupTypeName here so that shell types can be processed (why?) */
2057 typeOid = LookupTypeName(typename);
2058 if (!OidIsValid(typeOid))
2060 (errcode(ERRCODE_UNDEFINED_OBJECT),
2061 errmsg("type \"%s\" does not exist",
2062 TypeNameToString(typename))));
2064 tup = SearchSysCacheCopy(TYPEOID,
2065 ObjectIdGetDatum(typeOid),
2067 if (!HeapTupleIsValid(tup))
2068 elog(ERROR, "cache lookup failed for type %u", typeOid);
2069 typTup = (Form_pg_type) GETSTRUCT(tup);
2072 * If it's a composite type, we need to check that it really is a
2073 * free-standing composite type, and not a table's underlying type. We
2074 * want people to use ALTER TABLE not ALTER TYPE for that case.
2076 if (typTup->typtype == 'c' && get_rel_relkind(typTup->typrelid) != 'c')
2078 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2079 errmsg("\"%s\" is a table's row type",
2080 TypeNameToString(typename))));
2083 * If the new owner is the same as the existing owner, consider the
2084 * command to have succeeded. This is for dump restoration purposes.
2086 if (typTup->typowner != newOwnerSysId)
2088 /* Otherwise, must be superuser to change object ownership */
2091 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2092 errmsg("must be superuser to change owner")));
2095 * Modify the owner --- okay to scribble on typTup because it's a
2098 typTup->typowner = newOwnerSysId;
2100 simple_heap_update(rel, &tup->t_self, tup);
2102 CatalogUpdateIndexes(rel, tup);
2106 heap_close(rel, RowExclusiveLock);