1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_type relation
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.58 2001/01/24 19:42:52 momjian Exp $
13 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "catalog/catname.h"
19 #include "catalog/indexing.h"
20 #include "catalog/pg_type.h"
21 #include "miscadmin.h"
22 #include "parser/parse_func.h"
23 #include "utils/builtins.h"
24 #include "utils/fmgroids.h"
25 #include "utils/syscache.h"
28 static Oid TypeShellMakeWithOpenRelation(Relation pg_type_desc,
31 /* ----------------------------------------------------------------
32 * TypeGetWithOpenRelation
34 * preforms a scan on pg_type for a type tuple with the
36 * ----------------------------------------------------------------
37 * pg_type_desc -- reldesc for pg_type
38 * typeName -- name of type to be fetched
39 * defined -- has the type been defined?
42 TypeGetWithOpenRelation(Relation pg_type_desc,
50 static ScanKeyData typeKey[1] = {
51 {0, Anum_pg_type_typname, F_NAMEEQ}
55 * initialize the scan key and begin a scan of pg_type
58 fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
59 typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
60 typeKey[0].sk_argument = PointerGetDatum(typeName);
62 scan = heap_beginscan(pg_type_desc,
64 SnapshotSelf, /* cache? */
69 * get the type tuple, if it exists.
72 tup = heap_getnext(scan, 0);
75 * if no type tuple exists for the given type name, then
76 * end the scan and return appropriate information.
79 if (!HeapTupleIsValid(tup))
87 * here, the type tuple does exist so we pull information from
88 * the typisdefined field of the tuple and return the tuple's
89 * oid, which is the oid of the type.
92 *defined = (bool) ((Form_pg_type) GETSTRUCT(tup))->typisdefined;
93 typoid = tup->t_data->t_oid;
100 /* ----------------------------------------------------------------
103 * Finds the ObjectId of a type, even if uncommitted; "defined"
104 * is only set if the type has actually been defined, i.e., if
105 * the type tuple is not a shell.
107 * Note: the meat of this function is now in the function
108 * TypeGetWithOpenRelation(). -cim 6/15/90
110 * Also called from util/remove.c
111 * ----------------------------------------------------------------
114 TypeGet(char *typeName, /* name of type to be fetched */
115 bool *defined) /* has the type been defined? */
117 Relation pg_type_desc;
121 * open the pg_type relation
124 pg_type_desc = heap_openr(TypeRelationName, AccessShareLock);
127 * scan the type relation for the information we want
130 typeoid = TypeGetWithOpenRelation(pg_type_desc,
135 * close the type relation and return the type oid.
138 heap_close(pg_type_desc, AccessShareLock);
143 /* ----------------------------------------------------------------
144 * TypeShellMakeWithOpenRelation
146 * ----------------------------------------------------------------
149 TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
153 Datum values[Natts_pg_type];
154 char nulls[Natts_pg_type];
160 * initialize our *nulls and *values arrays
163 for (i = 0; i < Natts_pg_type; ++i)
166 values[i] = (Datum) NULL; /* redundant, but safe */
170 * initialize *values with the type name and dummy values
174 namestrcpy(&name, typeName);
175 values[i++] = NameGetDatum(&name); /* 1 */
176 values[i++] = ObjectIdGetDatum(InvalidOid); /* 2 */
177 values[i++] = Int16GetDatum(0); /* 3 */
178 values[i++] = Int16GetDatum(0); /* 4 */
179 values[i++] = BoolGetDatum(false); /* 5 */
180 values[i++] = CharGetDatum(0); /* 6 */
181 values[i++] = BoolGetDatum(false); /* 7 */
182 values[i++] = CharGetDatum(0); /* 8 */
183 values[i++] = ObjectIdGetDatum(InvalidOid); /* 9 */
184 values[i++] = ObjectIdGetDatum(InvalidOid); /* 10 */
185 values[i++] = ObjectIdGetDatum(InvalidOid); /* 11 */
186 values[i++] = ObjectIdGetDatum(InvalidOid); /* 12 */
187 values[i++] = ObjectIdGetDatum(InvalidOid); /* 13 */
188 values[i++] = ObjectIdGetDatum(InvalidOid); /* 14 */
189 values[i++] = CharGetDatum('i'); /* 15 */
190 values[i++] = CharGetDatum('p'); /* 16 */
191 values[i++] = DirectFunctionCall1(textin,
192 CStringGetDatum(typeName)); /* 17 */
195 * create a new type tuple with FormHeapTuple
198 tupDesc = pg_type_desc->rd_att;
200 tup = heap_formtuple(tupDesc, values, nulls);
203 * insert the tuple in the relation and get the tuple's oid.
206 heap_insert(pg_type_desc, tup);
207 typoid = tup->t_data->t_oid;
209 if (RelationGetForm(pg_type_desc)->relhasindex)
211 Relation idescs[Num_pg_type_indices];
213 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
214 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
215 CatalogCloseIndices(Num_pg_type_indices, idescs);
218 * free the tuple and return the type-oid
226 /* ----------------------------------------------------------------
229 * This procedure inserts a "shell" tuple into the type
230 * relation. The type tuple inserted has invalid values
231 * and in particular, the "typisdefined" field is false.
233 * This is used so that a tuple exists in the catalogs.
234 * The invalid fields should be fixed up sometime after
235 * this routine is called, and then the "typeisdefined"
236 * field is set to true. -cim 6/15/90
237 * ----------------------------------------------------------------
240 TypeShellMake(char *typeName)
242 Relation pg_type_desc;
245 Assert(PointerIsValid(typeName));
251 pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
254 * insert the shell tuple
257 typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
260 * close pg_type and return the tuple's oid.
263 heap_close(pg_type_desc, RowExclusiveLock);
268 /* ----------------------------------------------------------------
271 * This does all the necessary work needed to define a new type.
272 * ----------------------------------------------------------------
275 TypeCreate(char *typeName,
276 Oid relationOid, /* only for 'c'atalog typeTypes */
281 char *inputProcedure,
282 char *outputProcedure,
283 char *receiveProcedure,
285 char *elementTypeName,
286 char *defaultTypeValue, /* internal rep */
293 Relation pg_type_desc;
294 HeapScanDesc pg_type_scan;
297 Oid elementObjectId = InvalidOid;
300 char nulls[Natts_pg_type];
301 char replaces[Natts_pg_type];
302 Datum values[Natts_pg_type];
309 Oid argList[FUNC_MAX_ARGS];
311 static ScanKeyData typeKey[1] = {
312 {0, Anum_pg_type_typname, F_NAMEEQ}
315 fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
316 typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
319 * check that the type is not already defined.
322 typeObjectId = TypeGet(typeName, &defined);
323 if (OidIsValid(typeObjectId) && defined)
324 elog(ERROR, "TypeCreate: type %s already defined", typeName);
327 * if this type has an associated elementType, then we check that
333 elementObjectId = TypeGet(elementTypeName, &defined);
335 elog(ERROR, "TypeCreate: type %s is not defined", elementTypeName);
342 if (externalSize == 0)
343 externalSize = -1; /* variable length */
346 * initialize arrays needed by FormHeapTuple
349 for (i = 0; i < Natts_pg_type; ++i)
353 values[i] = (Datum) NULL; /* redundant, but nice */
359 * Do this so that user-defined types have size -1 instead of zero if
360 * they are variable-length - this is so that everything else in the
364 if (internalSize == 0)
368 * initialize the *values information
372 namestrcpy(&name, typeName);
373 values[i++] = NameGetDatum(&name); /* 1 */
374 values[i++] = Int32GetDatum(GetUserId()); /* 2 */
375 values[i++] = Int16GetDatum(internalSize); /* 3 */
376 values[i++] = Int16GetDatum(externalSize); /* 4 */
377 values[i++] = BoolGetDatum(passedByValue); /* 5 */
378 values[i++] = CharGetDatum(typeType); /* 6 */
379 values[i++] = BoolGetDatum(true); /* 7 */
380 values[i++] = CharGetDatum(typDelim); /* 8 */
381 values[i++] = ObjectIdGetDatum(typeType == 'c' ? relationOid : InvalidOid); /* 9 */
382 values[i++] = ObjectIdGetDatum(elementObjectId); /* 10 */
384 procs[0] = inputProcedure;
385 procs[1] = outputProcedure;
386 procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure;
387 procs[3] = (sendProcedure) ? sendProcedure : outputProcedure;
389 for (j = 0; j < 4; ++j)
396 * First look for a 1-argument func with all argtypes 0. This is
397 * valid for all four kinds of procedure.
399 MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
401 procOid = GetSysCacheOid(PROCNAME,
402 PointerGetDatum(procname),
404 PointerGetDatum(argList),
407 if (!OidIsValid(procOid))
411 * For array types, the input procedures may take 3 args (data
412 * value, element OID, atttypmod); the pg_proc argtype
413 * signature is 0,OIDOID,INT4OID. The output procedures may
414 * take 2 args (data value, element OID).
416 if (OidIsValid(elementObjectId))
431 argList[2] = INT4OID;
433 procOid = GetSysCacheOid(PROCNAME,
434 PointerGetDatum(procname),
435 Int32GetDatum(nargs),
436 PointerGetDatum(argList),
439 if (!OidIsValid(procOid))
440 func_error("TypeCreate", procname, 1, argList, NULL);
443 values[i++] = ObjectIdGetDatum(procOid); /* 11 - 14 */
447 * set default alignment
450 values[i++] = CharGetDatum(alignment); /* 15 */
453 * set default storage for TOAST
456 values[i++] = CharGetDatum(storage); /* 16 */
459 * initialize the default value for this type.
462 values[i] = DirectFunctionCall1(textin, /* 17 */
463 CStringGetDatum(defaultTypeValue ? defaultTypeValue : "-"));
466 * open pg_type and begin a scan for the type name.
469 pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
471 typeKey[0].sk_argument = PointerGetDatum(typeName);
472 pg_type_scan = heap_beginscan(pg_type_desc,
474 SnapshotSelf, /* cache? */
479 * define the type either by adding a tuple to the type
480 * relation, or by updating the fields of the "shell" tuple
484 tup = heap_getnext(pg_type_scan, 0);
485 if (HeapTupleIsValid(tup))
487 tup = heap_modifytuple(tup,
493 simple_heap_update(pg_type_desc, &tup->t_self, tup);
495 typeObjectId = tup->t_data->t_oid;
499 tupDesc = pg_type_desc->rd_att;
501 tup = heap_formtuple(tupDesc,
505 heap_insert(pg_type_desc, tup);
507 typeObjectId = tup->t_data->t_oid;
514 heap_endscan(pg_type_scan);
516 if (RelationGetForm(pg_type_desc)->relhasindex)
518 Relation idescs[Num_pg_type_indices];
520 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
521 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
522 CatalogCloseIndices(Num_pg_type_indices, idescs);
525 heap_close(pg_type_desc, RowExclusiveLock);
530 /* ----------------------------------------------------------------
533 * This renames a type
534 * ----------------------------------------------------------------
537 TypeRename(const char *oldTypeName, const char *newTypeName)
539 Relation pg_type_desc;
540 Relation idescs[Num_pg_type_indices];
543 pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
545 tuple = SearchSysCacheCopy(TYPENAME,
546 PointerGetDatum(oldTypeName),
548 if (!HeapTupleIsValid(tuple))
549 elog(ERROR, "TypeRename: type \"%s\" not defined", oldTypeName);
551 if (SearchSysCacheExists(TYPENAME,
552 PointerGetDatum(newTypeName),
554 elog(ERROR, "TypeRename: type \"%s\" already defined", newTypeName);
556 namestrcpy(&(((Form_pg_type) GETSTRUCT(tuple))->typname), newTypeName);
558 simple_heap_update(pg_type_desc, &tuple->t_self, tuple);
560 /* update the system catalog indices */
561 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
562 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tuple);
563 CatalogCloseIndices(Num_pg_type_indices, idescs);
565 heap_freetuple(tuple);
566 heap_close(pg_type_desc, RowExclusiveLock);
570 * makeArrayTypeName(typeName);
571 * - given a base type name, make an array of type name out of it
573 * the CALLER is responsible for pfreeing the
577 makeArrayTypeName(char *typeName)
583 arr = palloc(strlen(typeName) + 2);
585 strcpy(arr + 1, typeName);