1 /*-------------------------------------------------------------------------
4 * Routines for SQL commands that manipulate types (and domains).
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.3 2002/05/03 00:32:16 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 procedures
30 *-------------------------------------------------------------------------
34 #include "access/heapam.h"
35 #include "catalog/catname.h"
36 #include "catalog/heap.h"
37 #include "catalog/namespace.h"
38 #include "catalog/pg_type.h"
39 #include "commands/comment.h"
40 #include "commands/defrem.h"
41 #include "miscadmin.h"
42 #include "parser/parse.h"
43 #include "parser/parse_func.h"
44 #include "parser/parse_type.h"
45 #include "utils/acl.h"
46 #include "utils/builtins.h"
47 #include "utils/fmgroids.h"
48 #include "utils/lsyscache.h"
49 #include "utils/syscache.h"
52 static Oid findTypeIOFunction(List *procname, bool isOutput);
57 * Registers a new type.
60 DefineType(List *names, List *parameters)
65 int16 internalLength = -1; /* int2 */
66 int16 externalLength = -1; /* int2 */
67 Oid elemType = InvalidOid;
68 List *inputName = NIL;
69 List *outputName = NIL;
71 List *receiveName = NIL;
72 char *defaultValue = NULL;
74 char delimiter = DEFAULT_TYPDELIM;
75 char alignment = 'i'; /* default alignment */
76 char storage = 'p'; /* default TOAST storage method */
85 /* Convert list of names to a name and namespace */
86 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
88 /* Check we have creation rights in target namespace */
89 aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
90 if (aclresult != ACLCHECK_OK)
91 aclcheck_error(aclresult, get_namespace_name(typeNamespace));
94 * Type names must be one character shorter than other names, allowing
95 * room to create the corresponding array type name with prepended
98 if (strlen(typeName) > (NAMEDATALEN - 2))
99 elog(ERROR, "DefineType: type names must be %d characters or less",
102 foreach(pl, parameters)
104 DefElem *defel = (DefElem *) lfirst(pl);
106 if (strcasecmp(defel->defname, "internallength") == 0)
107 internalLength = defGetTypeLength(defel);
108 else if (strcasecmp(defel->defname, "externallength") == 0)
109 externalLength = defGetTypeLength(defel);
110 else if (strcasecmp(defel->defname, "input") == 0)
111 inputName = defGetQualifiedName(defel);
112 else if (strcasecmp(defel->defname, "output") == 0)
113 outputName = defGetQualifiedName(defel);
114 else if (strcasecmp(defel->defname, "send") == 0)
115 sendName = defGetQualifiedName(defel);
116 else if (strcasecmp(defel->defname, "receive") == 0)
117 receiveName = defGetQualifiedName(defel);
118 else if (strcasecmp(defel->defname, "delimiter") == 0)
120 char *p = defGetString(defel);
124 else if (strcasecmp(defel->defname, "element") == 0)
125 elemType = typenameTypeId(defGetTypeName(defel));
126 else if (strcasecmp(defel->defname, "default") == 0)
127 defaultValue = defGetString(defel);
128 else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
130 else if (strcasecmp(defel->defname, "alignment") == 0)
132 char *a = defGetString(defel);
135 * Note: if argument was an unquoted identifier, parser will
136 * have applied translations to it, so be prepared to
137 * recognize translated type names as well as the nominal
140 if (strcasecmp(a, "double") == 0 ||
141 strcasecmp(a, "float8") == 0 ||
142 strcasecmp(a, "pg_catalog.float8") == 0)
144 else if (strcasecmp(a, "int4") == 0 ||
145 strcasecmp(a, "pg_catalog.int4") == 0)
147 else if (strcasecmp(a, "int2") == 0 ||
148 strcasecmp(a, "pg_catalog.int2") == 0)
150 else if (strcasecmp(a, "char") == 0 ||
151 strcasecmp(a, "pg_catalog.bpchar") == 0)
154 elog(ERROR, "DefineType: \"%s\" alignment not recognized",
157 else if (strcasecmp(defel->defname, "storage") == 0)
159 char *a = defGetString(defel);
161 if (strcasecmp(a, "plain") == 0)
163 else if (strcasecmp(a, "external") == 0)
165 else if (strcasecmp(a, "extended") == 0)
167 else if (strcasecmp(a, "main") == 0)
170 elog(ERROR, "DefineType: \"%s\" storage not recognized",
175 elog(WARNING, "DefineType: attribute \"%s\" not recognized",
181 * make sure we have our required definitions
183 if (inputName == NIL)
184 elog(ERROR, "Define: \"input\" unspecified");
185 if (outputName == NIL)
186 elog(ERROR, "Define: \"output\" unspecified");
188 /* Convert I/O proc names to OIDs */
189 inputOid = findTypeIOFunction(inputName, false);
190 outputOid = findTypeIOFunction(outputName, true);
192 sendOid = findTypeIOFunction(sendName, true);
196 receiveOid = findTypeIOFunction(receiveName, false);
198 receiveOid = inputOid;
201 * now have TypeCreate do all the real work.
204 TypeCreate(typeName, /* type name */
205 typeNamespace, /* namespace */
206 InvalidOid, /* preassigned type oid (not done here) */
207 InvalidOid, /* relation oid (n/a here) */
208 internalLength, /* internal size */
209 externalLength, /* external size */
210 'b', /* type-type (base type) */
211 delimiter, /* array element delimiter */
212 inputOid, /* input procedure */
213 outputOid, /* output procedure */
214 receiveOid, /* receive procedure */
215 sendOid, /* send procedure */
216 elemType, /* element type ID */
217 InvalidOid, /* base type ID (only for domains) */
218 defaultValue, /* default type value */
219 NULL, /* no binary form available */
220 byValue, /* passed by value */
221 alignment, /* required alignment */
222 storage, /* TOAST strategy */
223 -1, /* typMod (Domains only) */
224 0, /* Array Dimensions of typbasetype */
225 false); /* Type NOT NULL */
228 * When we create a base type (as opposed to a complex type) we need
229 * to have an array entry for it in pg_type as well.
231 shadow_type = makeArrayTypeName(typeName);
233 /* alignment must be 'i' or 'd' for arrays */
234 alignment = (alignment == 'd') ? 'd' : 'i';
236 TypeCreate(shadow_type, /* type name */
237 typeNamespace, /* namespace */
238 InvalidOid, /* preassigned type oid (not done here) */
239 InvalidOid, /* relation oid (n/a here) */
240 -1, /* internal size */
241 -1, /* external size */
242 'b', /* type-type (base type) */
243 DEFAULT_TYPDELIM, /* array element delimiter */
244 F_ARRAY_IN, /* input procedure */
245 F_ARRAY_OUT, /* output procedure */
246 F_ARRAY_IN, /* receive procedure */
247 F_ARRAY_OUT, /* send procedure */
248 typoid, /* element type ID */
249 InvalidOid, /* base type ID */
250 NULL, /* never a default type value */
251 NULL, /* binary default isn't sent either */
252 false, /* never passed by value */
253 alignment, /* see above */
254 'x', /* ARRAY is always toastable */
255 -1, /* typMod (Domains only) */
256 0, /* Array dimensions of typbasetype */
257 false); /* Type NOT NULL */
265 * Removes a datatype.
267 * NOTE: since this tries to remove the associated array type too, it'll
268 * only work on scalar types.
271 RemoveType(List *names)
278 /* Make a TypeName so we can use standard type lookup machinery */
279 typename = makeNode(TypeName);
280 typename->names = names;
281 typename->typmod = -1;
282 typename->arrayBounds = NIL;
284 relation = heap_openr(TypeRelationName, RowExclusiveLock);
286 /* Use LookupTypeName here so that shell types can be removed. */
287 typeoid = LookupTypeName(typename);
288 if (!OidIsValid(typeoid))
289 elog(ERROR, "Type \"%s\" does not exist",
290 TypeNameToString(typename));
292 tup = SearchSysCache(TYPEOID,
293 ObjectIdGetDatum(typeoid),
295 if (!HeapTupleIsValid(tup))
296 elog(ERROR, "Type \"%s\" does not exist",
297 TypeNameToString(typename));
299 /* Permission check: must own type or its namespace */
300 if (!pg_type_ownercheck(typeoid, GetUserId()) &&
301 !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace,
303 aclcheck_error(ACLCHECK_NOT_OWNER, TypeNameToString(typename));
305 /* Delete any comments associated with this type */
306 DeleteComments(typeoid, RelationGetRelid(relation));
308 /* Remove the type tuple from pg_type */
309 simple_heap_delete(relation, &tup->t_self);
311 ReleaseSysCache(tup);
313 /* Now, delete the "array of" that type */
314 typename->arrayBounds = makeList1(makeInteger(1));
316 typeoid = LookupTypeName(typename);
317 if (!OidIsValid(typeoid))
318 elog(ERROR, "Type \"%s\" does not exist",
319 TypeNameToString(typename));
321 tup = SearchSysCache(TYPEOID,
322 ObjectIdGetDatum(typeoid),
324 if (!HeapTupleIsValid(tup))
325 elog(ERROR, "Type \"%s\" does not exist",
326 TypeNameToString(typename));
328 DeleteComments(typeoid, RelationGetRelid(relation));
330 simple_heap_delete(relation, &tup->t_self);
332 ReleaseSysCache(tup);
334 heap_close(relation, RowExclusiveLock);
340 * Registers a new domain.
343 DefineDomain(CreateDomainStmt *stmt)
348 int16 internalLength;
349 int16 externalLength;
352 Oid receiveProcedure;
361 char *defaultValue = NULL;
362 char *defaultValueBin = NULL;
363 bool typNotNull = false;
365 int32 typNDims = length(stmt->typename->arrayBounds);
367 List *schema = stmt->constraints;
370 /* Convert list of names to a name and namespace */
371 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
374 /* Check we have creation rights in target namespace */
375 aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
377 if (aclresult != ACLCHECK_OK)
378 aclcheck_error(aclresult, get_namespace_name(domainNamespace));
381 * Domainnames, unlike typenames don't need to account for the '_'
382 * prefix. So they can be one character longer.
384 if (strlen(domainName) > (NAMEDATALEN - 1))
385 elog(ERROR, "CREATE DOMAIN: domain names must be %d characters or less",
389 * Look up the base type.
391 typeTup = typenameType(stmt->typename);
394 * What we really don't want is domains of domains. This could cause all sorts
395 * of neat issues if we allow that.
397 * With testing, we may determine complex types should be allowed
399 typtype = ((Form_pg_type) GETSTRUCT(typeTup))->typtype;
401 elog(ERROR, "DefineDomain: %s is not a basetype",
402 TypeNameToString(stmt->typename));
404 /* passed by value */
405 byValue = ((Form_pg_type) GETSTRUCT(typeTup))->typbyval;
407 /* Required Alignment */
408 alignment = ((Form_pg_type) GETSTRUCT(typeTup))->typalign;
411 storage = ((Form_pg_type) GETSTRUCT(typeTup))->typstorage;
414 internalLength = ((Form_pg_type) GETSTRUCT(typeTup))->typlen;
416 /* External Length (unused) */
417 externalLength = ((Form_pg_type) GETSTRUCT(typeTup))->typprtlen;
419 /* Array element Delimiter */
420 delimiter = ((Form_pg_type) GETSTRUCT(typeTup))->typdelim;
423 inputProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typinput;
424 outputProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
425 receiveProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typreceive;
426 sendProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typsend;
428 /* Inherited default value */
429 datum = SysCacheGetAttr(TYPEOID, typeTup,
430 Anum_pg_type_typdefault, &isnull);
432 defaultValue = DatumGetCString(DirectFunctionCall1(textout, datum));
434 /* Inherited default binary value */
435 datum = SysCacheGetAttr(TYPEOID, typeTup,
436 Anum_pg_type_typdefaultbin, &isnull);
438 defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum));
441 * Pull out the typelem name of the parent OID.
443 * This is what enables us to make a domain of an array
445 basetypelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
448 * Run through constraints manually to avoid the additional
449 * processing conducted by DefineRelation() and friends.
451 * Besides, we don't want any constraints to be cooked. We'll
452 * do that when the table is created via MergeDomainAttributes().
454 foreach(listptr, schema)
456 Constraint *colDef = lfirst(listptr);
457 bool nullDefined = false;
461 switch (colDef->contype)
464 * The inherited default value may be overridden by the user
465 * with the DEFAULT <expr> statement.
467 * We have to search the entire constraint tree returned as we
468 * don't want to cook or fiddle too much.
471 /* Create a dummy ParseState for transformExpr */
472 pstate = make_parsestate(NULL);
474 * Cook the colDef->raw_expr into an expression.
475 * Note: Name is strictly for error message
477 expr = cookDefault(pstate, colDef->raw_expr,
478 typeTup->t_data->t_oid,
479 stmt->typename->typmod,
482 * Expression must be stored as a nodeToString result,
483 * but we also require a valid textual representation
484 * (mainly to make life easier for pg_dump).
486 defaultValue = deparse_expression(expr,
487 deparse_context_for(domainName,
490 defaultValueBin = nodeToString(expr);
494 * Find the NULL constraint.
498 elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
507 elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
515 elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported");
519 elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes not supported");
523 elog(ERROR, "DefineDomain: CHECK Constraints not supported");
526 case CONSTR_ATTR_DEFERRABLE:
527 case CONSTR_ATTR_NOT_DEFERRABLE:
528 case CONSTR_ATTR_DEFERRED:
529 case CONSTR_ATTR_IMMEDIATE:
530 elog(ERROR, "DefineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
534 elog(ERROR, "DefineDomain: unrecognized constraint node type");
540 * Have TypeCreate do all the real work.
542 TypeCreate(domainName, /* type name */
543 domainNamespace, /* namespace */
544 InvalidOid, /* preassigned type oid (not done here) */
545 InvalidOid, /* relation oid (n/a here) */
546 internalLength, /* internal size */
547 externalLength, /* external size */
548 'd', /* type-type (domain type) */
549 delimiter, /* array element delimiter */
550 inputProcedure, /* input procedure */
551 outputProcedure, /* output procedure */
552 receiveProcedure, /* receive procedure */
553 sendProcedure, /* send procedure */
554 basetypelem, /* element type ID */
555 typeTup->t_data->t_oid, /* base type ID */
556 defaultValue, /* default type value (text) */
557 defaultValueBin, /* default type value (binary) */
558 byValue, /* passed by value */
559 alignment, /* required alignment */
560 storage, /* TOAST strategy */
561 stmt->typename->typmod, /* typeMod value */
562 typNDims, /* Array dimensions for base type */
563 typNotNull); /* Type NOT NULL */
566 * Now we can clean up.
568 ReleaseSysCache(typeTup);
577 RemoveDomain(List *names, int behavior)
585 /* CASCADE unsupported */
586 if (behavior == CASCADE)
587 elog(ERROR, "DROP DOMAIN does not support the CASCADE keyword");
589 /* Make a TypeName so we can use standard type lookup machinery */
590 typename = makeNode(TypeName);
591 typename->names = names;
592 typename->typmod = -1;
593 typename->arrayBounds = NIL;
595 relation = heap_openr(TypeRelationName, RowExclusiveLock);
597 typeoid = typenameTypeId(typename);
599 tup = SearchSysCache(TYPEOID,
600 ObjectIdGetDatum(typeoid),
602 if (!HeapTupleIsValid(tup))
603 elog(ERROR, "RemoveDomain: type '%s' does not exist",
604 TypeNameToString(typename));
606 /* Permission check: must own type or its namespace */
607 if (!pg_type_ownercheck(typeoid, GetUserId()) &&
608 !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace,
610 aclcheck_error(ACLCHECK_NOT_OWNER, TypeNameToString(typename));
612 /* Check that this is actually a domain */
613 typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
616 elog(ERROR, "%s is not a domain",
617 TypeNameToString(typename));
619 /* Delete any comments associated with this type */
620 DeleteComments(typeoid, RelationGetRelid(relation));
622 /* Remove the type tuple from pg_type */
623 simple_heap_delete(relation, &tup->t_self);
625 ReleaseSysCache(tup);
627 /* At present, domains don't have associated array types */
629 heap_close(relation, RowExclusiveLock);
634 * Find a suitable I/O function for a type.
637 findTypeIOFunction(List *procname, bool isOutput)
639 Oid argList[FUNC_MAX_ARGS];
644 * First look for a 1-argument func with all argtypes 0. This is
645 * valid for all kinds of procedure.
647 MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
649 procOid = LookupFuncName(procname, 1, argList);
651 if (!OidIsValid(procOid))
654 * Alternatively, input procedures may take 3 args (data
655 * value, element OID, atttypmod); the pg_proc argtype
656 * signature is 0,OIDOID,INT4OID. Output procedures may
657 * take 2 args (data value, element OID).
670 argList[2] = INT4OID;
672 procOid = LookupFuncName(procname, nargs, argList);
674 if (!OidIsValid(procOid))
675 func_error("TypeCreate", procname, 1, argList, NULL);