1 /*-------------------------------------------------------------------------
4 * Routines for SQL commands that manipulate types (and domains).
6 * Portions Copyright (c) 1996-2004, 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.63 2004/08/29 05:06:41 momjian 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 = RelOid_pg_type;
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 = RelOid_pg_type;
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)
857 Oid argList[FUNC_MAX_ARGS];
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 MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
869 argList[0] = CSTRINGOID;
871 procOid = LookupFuncName(procname, 1, argList, true);
872 if (OidIsValid(procOid))
876 argList[2] = INT4OID;
878 procOid = LookupFuncName(procname, 3, argList, true);
879 if (OidIsValid(procOid))
882 /* No luck, try it with OPAQUE */
883 MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
885 argList[0] = OPAQUEOID;
887 procOid = LookupFuncName(procname, 1, argList, true);
889 if (!OidIsValid(procOid))
892 argList[2] = INT4OID;
894 procOid = LookupFuncName(procname, 3, argList, true);
897 if (OidIsValid(procOid))
899 /* Found, but must complain and fix the pg_proc entry */
901 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
902 NameListToString(procname))));
903 SetFunctionArgType(procOid, 0, CSTRINGOID);
906 * Need CommandCounterIncrement since DefineType will likely try
907 * to alter the pg_proc tuple again.
909 CommandCounterIncrement();
914 /* Use CSTRING (preferred) in the error message */
915 argList[0] = CSTRINGOID;
918 (errcode(ERRCODE_UNDEFINED_FUNCTION),
919 errmsg("function %s does not exist",
920 func_signature_string(procname, 1, argList))));
922 return InvalidOid; /* keep compiler quiet */
926 findTypeOutputFunction(List *procname, Oid typeOid)
928 Oid argList[FUNC_MAX_ARGS];
932 * Output functions can take a single argument of the type, or two
933 * arguments (data value, element OID).
935 * For backwards compatibility we allow OPAQUE in place of the actual
936 * type name; if we see this, we issue a warning and fix up the
939 MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
941 argList[0] = typeOid;
943 procOid = LookupFuncName(procname, 1, argList, true);
944 if (OidIsValid(procOid))
949 procOid = LookupFuncName(procname, 2, argList, true);
950 if (OidIsValid(procOid))
953 /* No luck, try it with OPAQUE */
954 MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
956 argList[0] = OPAQUEOID;
958 procOid = LookupFuncName(procname, 1, argList, true);
960 if (!OidIsValid(procOid))
964 procOid = LookupFuncName(procname, 2, argList, true);
967 if (OidIsValid(procOid))
969 /* Found, but must complain and fix the pg_proc entry */
971 (errmsg("changing argument type of function %s from \"opaque\" to %s",
972 NameListToString(procname), format_type_be(typeOid))));
973 SetFunctionArgType(procOid, 0, typeOid);
976 * Need CommandCounterIncrement since DefineType will likely try
977 * to alter the pg_proc tuple again.
979 CommandCounterIncrement();
984 /* Use type name, not OPAQUE, in the failure message. */
985 argList[0] = typeOid;
988 (errcode(ERRCODE_UNDEFINED_FUNCTION),
989 errmsg("function %s does not exist",
990 func_signature_string(procname, 1, argList))));
992 return InvalidOid; /* keep compiler quiet */
996 findTypeReceiveFunction(List *procname, Oid typeOid)
998 Oid argList[FUNC_MAX_ARGS];
1002 * Receive functions can take a single argument of type INTERNAL, or
1003 * two arguments (internal, oid).
1005 MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
1007 argList[0] = INTERNALOID;
1009 procOid = LookupFuncName(procname, 1, argList, true);
1010 if (OidIsValid(procOid))
1013 argList[1] = OIDOID;
1015 procOid = LookupFuncName(procname, 2, argList, true);
1016 if (OidIsValid(procOid))
1020 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1021 errmsg("function %s does not exist",
1022 func_signature_string(procname, 1, argList))));
1024 return InvalidOid; /* keep compiler quiet */
1028 findTypeSendFunction(List *procname, Oid typeOid)
1030 Oid argList[FUNC_MAX_ARGS];
1034 * Send functions can take a single argument of the type, or two
1035 * arguments (data value, element OID).
1037 MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
1039 argList[0] = typeOid;
1041 procOid = LookupFuncName(procname, 1, argList, true);
1042 if (OidIsValid(procOid))
1045 argList[1] = OIDOID;
1047 procOid = LookupFuncName(procname, 2, argList, true);
1048 if (OidIsValid(procOid))
1052 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1053 errmsg("function %s does not exist",
1054 func_signature_string(procname, 1, argList))));
1056 return InvalidOid; /* keep compiler quiet */
1060 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1062 Oid argList[FUNC_MAX_ARGS];
1066 * Analyze functions always take one INTERNAL argument and return
1069 MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
1071 argList[0] = INTERNALOID;
1073 procOid = LookupFuncName(procname, 1, argList, true);
1074 if (!OidIsValid(procOid))
1076 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1077 errmsg("function %s does not exist",
1078 func_signature_string(procname, 1, argList))));
1080 if (get_func_rettype(procOid) != BOOLOID)
1082 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1083 errmsg("type analyze function %s must return type \"boolean\"",
1084 NameListToString(procname))));
1090 /*-------------------------------------------------------------------
1091 * DefineCompositeType
1093 * Create a Composite Type relation.
1094 * `DefineRelation' does all the work, we just provide the correct
1097 * If the relation already exists, then 'DefineRelation' will abort
1100 * DefineCompositeType returns relid for use when creating
1101 * an implicit composite type during function creation
1102 *-------------------------------------------------------------------
1105 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1107 CreateStmt *createStmt = makeNode(CreateStmt);
1109 if (coldeflist == NIL)
1111 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1112 errmsg("composite type must have at least one attribute")));
1115 * now set the parameters for keys/inheritance etc. All of these are
1116 * uninteresting for composite types...
1118 createStmt->relation = (RangeVar *) typevar;
1119 createStmt->tableElts = coldeflist;
1120 createStmt->inhRelations = NIL;
1121 createStmt->constraints = NIL;
1122 createStmt->hasoids = MUST_NOT_HAVE_OIDS;
1123 createStmt->oncommit = ONCOMMIT_NOOP;
1124 createStmt->tablespacename = NULL;
1127 * finally create the relation...
1129 return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);
1133 * AlterDomainDefault
1135 * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
1138 AlterDomainDefault(List *names, Node *defaultRaw)
1146 Node *defaultExpr = NULL; /* NULL if no default specified */
1147 Datum new_record[Natts_pg_type];
1148 char new_record_nulls[Natts_pg_type];
1149 char new_record_repl[Natts_pg_type];
1151 Form_pg_type typTup;
1153 /* Make a TypeName so we can use standard type lookup machinery */
1154 typename = makeNode(TypeName);
1155 typename->names = names;
1156 typename->typmod = -1;
1157 typename->arrayBounds = NIL;
1159 /* Lock the domain in the type table */
1160 rel = heap_openr(TypeRelationName, RowExclusiveLock);
1162 /* Use LookupTypeName here so that shell types can be removed. */
1163 domainoid = LookupTypeName(typename);
1164 if (!OidIsValid(domainoid))
1166 (errcode(ERRCODE_UNDEFINED_OBJECT),
1167 errmsg("type \"%s\" does not exist",
1168 TypeNameToString(typename))));
1170 tup = SearchSysCacheCopy(TYPEOID,
1171 ObjectIdGetDatum(domainoid),
1173 if (!HeapTupleIsValid(tup))
1174 elog(ERROR, "cache lookup failed for type %u", domainoid);
1176 /* Doesn't return if user isn't allowed to alter the domain */
1177 domainOwnerCheck(tup, typename);
1179 /* Setup new tuple */
1180 MemSet(new_record, (Datum) 0, sizeof(new_record));
1181 MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
1182 MemSet(new_record_repl, ' ', sizeof(new_record_repl));
1185 typTup = (Form_pg_type) GETSTRUCT(tup);
1187 /* Store the new default, if null then skip this step */
1190 /* Create a dummy ParseState for transformExpr */
1191 pstate = make_parsestate(NULL);
1194 * Cook the colDef->raw_expr into an expression. Note: Name is
1195 * strictly for error message
1197 defaultExpr = cookDefault(pstate, defaultRaw,
1198 typTup->typbasetype,
1200 NameStr(typTup->typname));
1203 * Expression must be stored as a nodeToString result, but we also
1204 * require a valid textual representation (mainly to make life
1205 * easier for pg_dump).
1207 defaultValue = deparse_expression(defaultExpr,
1208 deparse_context_for(NameStr(typTup->typname),
1213 * Form an updated tuple with the new default and write it back.
1215 new_record[Anum_pg_type_typdefaultbin - 1] = DirectFunctionCall1(textin,
1217 nodeToString(defaultExpr)));
1219 new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
1220 new_record[Anum_pg_type_typdefault - 1] = DirectFunctionCall1(textin,
1221 CStringGetDatum(defaultValue));
1222 new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
1225 /* Default is NULL, drop it */
1227 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = 'n';
1228 new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
1229 new_record_nulls[Anum_pg_type_typdefault - 1] = 'n';
1230 new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
1233 newtuple = heap_modifytuple(tup, rel,
1234 new_record, new_record_nulls, new_record_repl);
1236 simple_heap_update(rel, &tup->t_self, newtuple);
1238 CatalogUpdateIndexes(rel, newtuple);
1240 /* Rebuild dependencies */
1241 GenerateTypeDependencies(typTup->typnamespace,
1244 0, /* relation kind is n/a */
1251 typTup->typbasetype,
1253 true); /* Rebuild is true */
1256 heap_close(rel, NoLock);
1257 heap_freetuple(newtuple);
1261 * AlterDomainNotNull
1263 * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
1266 AlterDomainNotNull(List *names, bool notNull)
1272 Form_pg_type typTup;
1274 /* Make a TypeName so we can use standard type lookup machinery */
1275 typename = makeNode(TypeName);
1276 typename->names = names;
1277 typename->typmod = -1;
1278 typename->arrayBounds = NIL;
1280 /* Lock the type table */
1281 typrel = heap_openr(TypeRelationName, RowExclusiveLock);
1283 /* Use LookupTypeName here so that shell types can be found (why?). */
1284 domainoid = LookupTypeName(typename);
1285 if (!OidIsValid(domainoid))
1287 (errcode(ERRCODE_UNDEFINED_OBJECT),
1288 errmsg("type \"%s\" does not exist",
1289 TypeNameToString(typename))));
1291 tup = SearchSysCacheCopy(TYPEOID,
1292 ObjectIdGetDatum(domainoid),
1294 if (!HeapTupleIsValid(tup))
1295 elog(ERROR, "cache lookup failed for type %u", domainoid);
1296 typTup = (Form_pg_type) GETSTRUCT(tup);
1298 /* Doesn't return if user isn't allowed to alter the domain */
1299 domainOwnerCheck(tup, typename);
1301 /* Is the domain already set to the desired constraint? */
1302 if (typTup->typnotnull == notNull)
1304 heap_close(typrel, RowExclusiveLock);
1308 /* Adding a NOT NULL constraint requires checking existing columns */
1314 /* Fetch relation list with attributes based on this domain */
1315 /* ShareLock is sufficient to prevent concurrent data changes */
1317 rels = get_rels_with_domain(domainoid, ShareLock);
1321 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1322 Relation testrel = rtc->rel;
1323 TupleDesc tupdesc = RelationGetDescr(testrel);
1327 /* Scan all tuples in this relation */
1328 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1329 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1333 /* Test attributes that are of the domain */
1334 for (i = 0; i < rtc->natts; i++)
1336 int attnum = rtc->atts[i];
1338 if (heap_attisnull(tuple, attnum))
1340 (errcode(ERRCODE_NOT_NULL_VIOLATION),
1341 errmsg("column \"%s\" of table \"%s\" contains null values",
1342 NameStr(tupdesc->attrs[attnum - 1]->attname),
1343 RelationGetRelationName(testrel))));
1348 /* Close each rel after processing, but keep lock */
1349 heap_close(testrel, NoLock);
1354 * Okay to update pg_type row. We can scribble on typTup because it's
1357 typTup->typnotnull = notNull;
1359 simple_heap_update(typrel, &tup->t_self, tup);
1361 CatalogUpdateIndexes(typrel, tup);
1364 heap_freetuple(tup);
1365 heap_close(typrel, RowExclusiveLock);
1369 * AlterDomainDropConstraint
1371 * Implements the ALTER DOMAIN DROP CONSTRAINT statement
1374 AlterDomainDropConstraint(List *names, const char *constrName, DropBehavior behavior)
1380 Form_pg_type typTup;
1382 SysScanDesc conscan;
1386 /* Make a TypeName so we can use standard type lookup machinery */
1387 typename = makeNode(TypeName);
1388 typename->names = names;
1389 typename->typmod = -1;
1390 typename->arrayBounds = NIL;
1392 /* Lock the type table */
1393 rel = heap_openr(TypeRelationName, RowExclusiveLock);
1395 /* Use LookupTypeName here so that shell types can be removed. */
1396 domainoid = LookupTypeName(typename);
1397 if (!OidIsValid(domainoid))
1399 (errcode(ERRCODE_UNDEFINED_OBJECT),
1400 errmsg("type \"%s\" does not exist",
1401 TypeNameToString(typename))));
1403 tup = SearchSysCacheCopy(TYPEOID,
1404 ObjectIdGetDatum(domainoid),
1406 if (!HeapTupleIsValid(tup))
1407 elog(ERROR, "cache lookup failed for type %u", domainoid);
1409 /* Doesn't return if user isn't allowed to alter the domain */
1410 domainOwnerCheck(tup, typename);
1412 /* Grab an appropriate lock on the pg_constraint relation */
1413 conrel = heap_openr(ConstraintRelationName, RowExclusiveLock);
1415 /* Use the index to scan only constraints of the target relation */
1416 ScanKeyInit(&key[0],
1417 Anum_pg_constraint_contypid,
1418 BTEqualStrategyNumber, F_OIDEQ,
1419 ObjectIdGetDatum(HeapTupleGetOid(tup)));
1421 conscan = systable_beginscan(conrel, ConstraintTypidIndex, true,
1422 SnapshotNow, 1, key);
1424 typTup = (Form_pg_type) GETSTRUCT(tup);
1427 * Scan over the result set, removing any matching entries.
1429 while ((contup = systable_getnext(conscan)) != NULL)
1431 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
1433 if (strcmp(NameStr(con->conname), constrName) == 0)
1435 ObjectAddress conobj;
1437 conobj.classId = RelationGetRelid(conrel);
1438 conobj.objectId = HeapTupleGetOid(contup);
1439 conobj.objectSubId = 0;
1441 performDeletion(&conobj, behavior);
1444 /* Clean up after the scan */
1445 systable_endscan(conscan);
1446 heap_close(conrel, RowExclusiveLock);
1448 heap_close(rel, NoLock);
1452 * AlterDomainAddConstraint
1454 * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
1457 AlterDomainAddConstraint(List *names, Node *newConstraint)
1463 Form_pg_type typTup;
1467 ExprContext *econtext;
1470 ExprState *exprstate;
1473 /* Make a TypeName so we can use standard type lookup machinery */
1474 typename = makeNode(TypeName);
1475 typename->names = names;
1476 typename->typmod = -1;
1477 typename->arrayBounds = NIL;
1479 /* Lock the type table */
1480 typrel = heap_openr(TypeRelationName, RowExclusiveLock);
1482 /* Use LookupTypeName here so that shell types can be found (why?). */
1483 domainoid = LookupTypeName(typename);
1484 if (!OidIsValid(domainoid))
1486 (errcode(ERRCODE_UNDEFINED_OBJECT),
1487 errmsg("type \"%s\" does not exist",
1488 TypeNameToString(typename))));
1490 tup = SearchSysCacheCopy(TYPEOID,
1491 ObjectIdGetDatum(domainoid),
1493 if (!HeapTupleIsValid(tup))
1494 elog(ERROR, "cache lookup failed for type %u", domainoid);
1495 typTup = (Form_pg_type) GETSTRUCT(tup);
1497 /* Doesn't return if user isn't allowed to alter the domain */
1498 domainOwnerCheck(tup, typename);
1500 /* Check for unsupported constraint types */
1501 if (IsA(newConstraint, FkConstraint))
1503 (errcode(ERRCODE_SYNTAX_ERROR),
1504 errmsg("foreign key constraints not possible for domains")));
1506 /* otherwise it should be a plain Constraint */
1507 if (!IsA(newConstraint, Constraint))
1508 elog(ERROR, "unrecognized node type: %d",
1509 (int) nodeTag(newConstraint));
1511 constr = (Constraint *) newConstraint;
1513 switch (constr->contype)
1516 /* processed below */
1521 (errcode(ERRCODE_SYNTAX_ERROR),
1522 errmsg("unique constraints not possible for domains")));
1525 case CONSTR_PRIMARY:
1527 (errcode(ERRCODE_SYNTAX_ERROR),
1528 errmsg("primary key constraints not possible for domains")));
1531 case CONSTR_ATTR_DEFERRABLE:
1532 case CONSTR_ATTR_NOT_DEFERRABLE:
1533 case CONSTR_ATTR_DEFERRED:
1534 case CONSTR_ATTR_IMMEDIATE:
1536 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1537 errmsg("specifying constraint deferrability not supported for domains")));
1541 elog(ERROR, "unrecognized constraint subtype: %d",
1542 (int) constr->contype);
1547 * Since all other constraint types throw errors, this must be a check
1548 * constraint. First, process the constraint expression and add an
1549 * entry to pg_constraint.
1552 ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
1553 typTup->typbasetype, typTup->typtypmod,
1554 constr, NameStr(typTup->typname));
1557 * Test all values stored in the attributes based on the domain the
1558 * constraint is being added to.
1560 expr = (Expr *) stringToNode(ccbin);
1562 /* Need an EState to run ExecEvalExpr */
1563 estate = CreateExecutorState();
1564 econtext = GetPerTupleExprContext(estate);
1566 /* build execution state for expr */
1567 exprstate = ExecPrepareExpr(expr, estate);
1569 /* Fetch relation list with attributes based on this domain */
1570 /* ShareLock is sufficient to prevent concurrent data changes */
1572 rels = get_rels_with_domain(domainoid, ShareLock);
1576 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1577 Relation testrel = rtc->rel;
1578 TupleDesc tupdesc = RelationGetDescr(testrel);
1582 /* Scan all tuples in this relation */
1583 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1584 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1588 /* Test attributes that are of the domain */
1589 for (i = 0; i < rtc->natts; i++)
1591 int attnum = rtc->atts[i];
1596 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
1598 econtext->domainValue_datum = d;
1599 econtext->domainValue_isNull = isNull;
1601 conResult = ExecEvalExprSwitchContext(exprstate,
1605 if (!isNull && !DatumGetBool(conResult))
1607 (errcode(ERRCODE_CHECK_VIOLATION),
1608 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
1609 NameStr(tupdesc->attrs[attnum - 1]->attname),
1610 RelationGetRelationName(testrel))));
1613 ResetExprContext(econtext);
1617 /* Hold relation lock till commit (XXX bad for concurrency) */
1618 heap_close(testrel, NoLock);
1621 FreeExecutorState(estate);
1624 heap_close(typrel, RowExclusiveLock);
1628 * get_rels_with_domain
1630 * Fetch all relations / attributes which are using the domain
1632 * The result is a list of RelToCheck structs, one for each distinct
1633 * relation, each containing one or more attribute numbers that are of
1634 * the domain type. We have opened each rel and acquired the specified lock
1637 * XXX this is completely broken because there is no way to lock the domain
1638 * to prevent columns from being added or dropped while our command runs.
1639 * We can partially protect against column drops by locking relations as we
1640 * come across them, but there is still a race condition (the window between
1641 * seeing a pg_depend entry and acquiring lock on the relation it references).
1642 * Also, holding locks on all these relations simultaneously creates a non-
1643 * trivial risk of deadlock. We can minimize but not eliminate the deadlock
1644 * risk by using the weakest suitable lock (ShareLock for most callers).
1646 * XXX to support domains over domains, we'd need to make this smarter,
1647 * or make its callers smarter, so that we could find columns of derived
1648 * domains. Arrays of domains would be a problem too.
1650 * Generally used for retrieving a list of tests when adding
1651 * new constraints to a domain.
1654 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
1659 SysScanDesc depScan;
1663 * We scan pg_depend to find those things that depend on the domain.
1664 * (We assume we can ignore refobjsubid for a domain.)
1666 depRel = relation_openr(DependRelationName, AccessShareLock);
1668 ScanKeyInit(&key[0],
1669 Anum_pg_depend_refclassid,
1670 BTEqualStrategyNumber, F_OIDEQ,
1671 ObjectIdGetDatum(RelOid_pg_type));
1672 ScanKeyInit(&key[1],
1673 Anum_pg_depend_refobjid,
1674 BTEqualStrategyNumber, F_OIDEQ,
1675 ObjectIdGetDatum(domainOid));
1677 depScan = systable_beginscan(depRel, DependReferenceIndex, true,
1678 SnapshotNow, 2, key);
1680 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
1682 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
1683 RelToCheck *rtc = NULL;
1685 Form_pg_attribute pg_att;
1688 /* Ignore dependees that aren't user columns of relations */
1689 /* (we assume system columns are never of domain types) */
1690 if (pg_depend->classid != RelOid_pg_class ||
1691 pg_depend->objsubid <= 0)
1694 /* See if we already have an entry for this relation */
1695 foreach(rellist, result)
1697 RelToCheck *rt = (RelToCheck *) lfirst(rellist);
1699 if (RelationGetRelid(rt->rel) == pg_depend->objid)
1708 /* First attribute found for this relation */
1711 /* Acquire requested lock on relation */
1712 rel = relation_open(pg_depend->objid, lockmode);
1714 /* It could be a view or composite type; if so ignore it */
1715 if (rel->rd_rel->relkind != RELKIND_RELATION)
1717 relation_close(rel, lockmode);
1721 /* Build the RelToCheck entry with enough space for all atts */
1722 rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
1725 rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
1726 result = lcons(rtc, result);
1730 * Confirm column has not been dropped, and is of the expected
1731 * type. This defends against an ALTER DROP COLUMN occuring just
1732 * before we acquired lock ... but if the whole table were
1733 * dropped, we'd still have a problem.
1735 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
1737 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
1738 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
1742 * Okay, add column to result. We store the columns in
1743 * column-number order; this is just a hack to improve
1744 * predictability of regression test output ...
1746 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
1749 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
1751 rtc->atts[ptr] = rtc->atts[ptr - 1];
1754 rtc->atts[ptr] = pg_depend->objsubid;
1757 systable_endscan(depScan);
1759 relation_close(depRel, AccessShareLock);
1767 * Throw an error if the current user doesn't have permission to modify
1768 * the domain in an ALTER DOMAIN statement, or if the type isn't actually
1772 domainOwnerCheck(HeapTuple tup, TypeName *typename)
1774 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1776 /* Check that this is actually a domain */
1777 if (typTup->typtype != 'd')
1779 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1780 errmsg("\"%s\" is not a domain",
1781 TypeNameToString(typename))));
1783 /* Permission check: must own type */
1784 if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1785 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
1786 TypeNameToString(typename));
1790 * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
1793 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
1794 int typMod, Constraint *constr,
1801 CoerceToDomainValue *domVal;
1804 * Assign or validate constraint name
1808 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
1813 (errcode(ERRCODE_DUPLICATE_OBJECT),
1814 errmsg("constraint \"%s\" for domain \"%s\" already exists",
1815 constr->name, domainName)));
1818 constr->name = ChooseConstraintName(domainName,
1825 * Convert the A_EXPR in raw_expr into an EXPR
1827 pstate = make_parsestate(NULL);
1830 * Set up a CoerceToDomainValue to represent the occurrence of VALUE
1831 * in the expression. Note that it will appear to have the type of
1832 * the base type, not the domain. This seems correct since within the
1833 * check expression, we should not assume the input value can be
1834 * considered a member of the domain.
1836 domVal = makeNode(CoerceToDomainValue);
1837 domVal->typeId = baseTypeOid;
1838 domVal->typeMod = typMod;
1840 pstate->p_value_substitute = (Node *) domVal;
1842 expr = transformExpr(pstate, constr->raw_expr);
1845 * Make sure it yields a boolean result.
1847 expr = coerce_to_boolean(pstate, expr, "CHECK");
1850 * Make sure no outside relations are referred to.
1852 if (list_length(pstate->p_rtable) != 0)
1854 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1855 errmsg("cannot use table references in domain check constraint")));
1858 * Domains don't allow var clauses (this should be redundant with the
1859 * above check, but make it anyway)
1861 if (contain_var_clause(expr))
1863 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1864 errmsg("cannot use table references in domain check constraint")));
1867 * No subplans or aggregates, either...
1869 if (pstate->p_hasSubLinks)
1871 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1872 errmsg("cannot use subquery in check constraint")));
1873 if (pstate->p_hasAggs)
1875 (errcode(ERRCODE_GROUPING_ERROR),
1876 errmsg("cannot use aggregate in check constraint")));
1879 * Convert to string form for storage.
1881 ccbin = nodeToString(expr);
1884 * Deparse it to produce text for consrc.
1886 * Since VARNOs aren't allowed in domain constraints, relation context
1887 * isn't required as anything other than a shell.
1889 ccsrc = deparse_expression(expr,
1890 deparse_context_for(domainName,
1895 * Store the constraint in pg_constraint
1897 CreateConstraintEntry(constr->name, /* Constraint Name */
1898 domainNamespace, /* namespace */
1899 CONSTRAINT_CHECK, /* Constraint Type */
1900 false, /* Is Deferrable */
1901 false, /* Is Deferred */
1902 InvalidOid, /* not a relation constraint */
1905 domainOid, /* domain constraint */
1906 InvalidOid, /* Foreign key fields */
1913 expr, /* Tree form check constraint */
1914 ccbin, /* Binary form check constraint */
1915 ccsrc); /* Source form check constraint */
1918 * Return the compiled constraint expression so the calling routine
1919 * can perform any additional required tests.
1925 * GetDomainConstraints - get a list of the current constraints of domain
1927 * Returns a possibly-empty list of DomainConstraintState nodes.
1929 * This is called by the executor during plan startup for a CoerceToDomain
1930 * expression node. The given constraints will be checked for each value
1931 * passed through the node.
1934 GetDomainConstraints(Oid typeOid)
1937 bool notNull = false;
1940 conRel = heap_openr(ConstraintRelationName, AccessShareLock);
1946 Form_pg_type typTup;
1950 tup = SearchSysCache(TYPEOID,
1951 ObjectIdGetDatum(typeOid),
1953 if (!HeapTupleIsValid(tup))
1954 elog(ERROR, "cache lookup failed for type %u", typeOid);
1955 typTup = (Form_pg_type) GETSTRUCT(tup);
1957 /* Test for NOT NULL Constraint */
1958 if (typTup->typnotnull)
1961 /* Look for CHECK Constraints on this domain */
1962 ScanKeyInit(&key[0],
1963 Anum_pg_constraint_contypid,
1964 BTEqualStrategyNumber, F_OIDEQ,
1965 ObjectIdGetDatum(typeOid));
1967 scan = systable_beginscan(conRel, ConstraintTypidIndex, true,
1968 SnapshotNow, 1, key);
1970 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
1972 Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
1976 DomainConstraintState *r;
1978 /* Ignore non-CHECK constraints (presently, shouldn't be any) */
1979 if (c->contype != CONSTRAINT_CHECK)
1983 * Not expecting conbin to be NULL, but we'll test for it
1986 val = fastgetattr(conTup, Anum_pg_constraint_conbin,
1987 conRel->rd_att, &isNull);
1989 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
1990 NameStr(typTup->typname), NameStr(c->conname));
1992 check_expr = (Expr *)
1993 stringToNode(DatumGetCString(DirectFunctionCall1(textout,
1996 /* ExecInitExpr assumes we already fixed opfuncids */
1997 fix_opfuncids((Node *) check_expr);
1999 r = makeNode(DomainConstraintState);
2000 r->constrainttype = DOM_CONSTRAINT_CHECK;
2001 r->name = pstrdup(NameStr(c->conname));
2002 r->check_expr = ExecInitExpr(check_expr, NULL);
2005 * use lcons() here because constraints of lower domains
2006 * should be applied earlier.
2008 result = lcons(r, result);
2011 systable_endscan(scan);
2013 if (typTup->typtype != 'd')
2015 /* Not a domain, so done */
2016 ReleaseSysCache(tup);
2020 /* else loop to next domain in stack */
2021 typeOid = typTup->typbasetype;
2022 ReleaseSysCache(tup);
2025 heap_close(conRel, AccessShareLock);
2028 * Only need to add one NOT NULL check regardless of how many domains
2029 * in the stack request it.
2033 DomainConstraintState *r = makeNode(DomainConstraintState);
2035 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
2036 r->name = pstrdup("NOT NULL");
2037 r->check_expr = NULL;
2039 /* lcons to apply the nullness check FIRST */
2040 result = lcons(r, result);
2047 * Change the owner of a type.
2050 AlterTypeOwner(List *names, AclId newOwnerSysId)
2056 Form_pg_type typTup;
2058 /* Make a TypeName so we can use standard type lookup machinery */
2059 typename = makeNode(TypeName);
2060 typename->names = names;
2061 typename->typmod = -1;
2062 typename->arrayBounds = NIL;
2064 /* Lock the type table */
2065 rel = heap_openr(TypeRelationName, RowExclusiveLock);
2067 /* Use LookupTypeName here so that shell types can be processed (why?) */
2068 typeOid = LookupTypeName(typename);
2069 if (!OidIsValid(typeOid))
2071 (errcode(ERRCODE_UNDEFINED_OBJECT),
2072 errmsg("type \"%s\" does not exist",
2073 TypeNameToString(typename))));
2075 tup = SearchSysCacheCopy(TYPEOID,
2076 ObjectIdGetDatum(typeOid),
2078 if (!HeapTupleIsValid(tup))
2079 elog(ERROR, "cache lookup failed for type %u", typeOid);
2080 typTup = (Form_pg_type) GETSTRUCT(tup);
2083 * If it's a composite type, we need to check that it really is a
2084 * free-standing composite type, and not a table's underlying type. We
2085 * want people to use ALTER TABLE not ALTER TYPE for that case.
2087 if (typTup->typtype == 'c' && get_rel_relkind(typTup->typrelid) != 'c')
2089 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2090 errmsg("\"%s\" is a table's row type",
2091 TypeNameToString(typename))));
2094 * If the new owner is the same as the existing owner, consider the
2095 * command to have succeeded. This is for dump restoration purposes.
2097 if (typTup->typowner != newOwnerSysId)
2099 /* Otherwise, must be superuser to change object ownership */
2102 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2103 errmsg("must be superuser to change owner")));
2106 * Modify the owner --- okay to scribble on typTup because it's a
2109 typTup->typowner = newOwnerSysId;
2111 simple_heap_update(rel, &tup->t_self, tup);
2113 CatalogUpdateIndexes(rel, tup);
2117 heap_close(rel, RowExclusiveLock);