1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_type relation
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.24 1998/05/09 23:43:00 thomas Exp $
12 *-------------------------------------------------------------------------
16 #include "access/heapam.h"
17 #include "access/relscan.h"
18 #include "catalog/catname.h"
19 #include "catalog/indexing.h"
20 #include "catalog/pg_type.h"
22 #include "miscadmin.h"
23 #include "parser/parse_func.h"
24 #include "storage/lmgr.h"
25 #include "utils/builtins.h"
26 #include "utils/syscache.h"
27 #include "utils/tqual.h"
30 #include <regex/utils.h>
36 TypeShellMakeWithOpenRelation(Relation pg_type_desc,
39 /* ----------------------------------------------------------------
40 * TypeGetWithOpenRelation
42 * preforms a scan on pg_type for a type tuple with the
44 * ----------------------------------------------------------------
45 * pg_type_desc -- reldesc for pg_type
46 * typeName -- name of type to be fetched
47 * defined -- has the type been defined?
50 TypeGetWithOpenRelation(Relation pg_type_desc,
57 static ScanKeyData typeKey[1] = {
58 {0, Anum_pg_type_typname, F_NAMEEQ}
62 * initialize the scan key and begin a scan of pg_type
65 fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
66 typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
67 typeKey[0].sk_argument = PointerGetDatum(typeName);
69 scan = heap_beginscan(pg_type_desc,
76 * get the type tuple, if it exists.
79 tup = heap_getnext(scan, 0, (Buffer *) 0);
82 * if no type tuple exists for the given type name, then
83 * end the scan and return appropriate information.
86 if (!HeapTupleIsValid(tup))
94 * here, the type tuple does exist so we pull information from
95 * the typisdefined field of the tuple and return the tuple's
96 * oid, which is the oid of the type.
100 *defined = (bool) ((TypeTupleForm) GETSTRUCT(tup))->typisdefined;
106 /* ----------------------------------------------------------------
109 * Finds the ObjectId of a type, even if uncommitted; "defined"
110 * is only set if the type has actually been defined, i.e., if
111 * the type tuple is not a shell.
113 * Note: the meat of this function is now in the function
114 * TypeGetWithOpenRelation(). -cim 6/15/90
116 * Also called from util/remove.c
117 * ----------------------------------------------------------------
120 TypeGet(char *typeName, /* name of type to be fetched */
121 bool *defined) /* has the type been defined? */
123 Relation pg_type_desc;
127 * open the pg_type relation
130 pg_type_desc = heap_openr(TypeRelationName);
133 * scan the type relation for the information we want
136 typeoid = TypeGetWithOpenRelation(pg_type_desc,
141 * close the type relation and return the type oid.
144 heap_close(pg_type_desc);
150 /* ----------------------------------------------------------------
151 * TypeShellMakeWithOpenRelation
153 * ----------------------------------------------------------------
156 TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
160 Datum values[Natts_pg_type];
161 char nulls[Natts_pg_type];
167 * initialize our nulls[] and values[] arrays
170 for (i = 0; i < Natts_pg_type; ++i)
173 values[i] = (Datum) NULL; /* redundant, but safe */
177 * initialize values[] with the type name and
181 namestrcpy(&name, typeName);
182 values[i++] = NameGetDatum(&name); /* 1 */
183 values[i++] = (Datum) InvalidOid; /* 2 */
184 values[i++] = (Datum) (int16) 0; /* 3 */
185 values[i++] = (Datum) (int16) 0; /* 4 */
186 values[i++] = (Datum) (bool) 0; /* 5 */
187 values[i++] = (Datum) (bool) 0; /* 6 */
188 values[i++] = (Datum) (bool) 0; /* 7 */
189 values[i++] = (Datum) (bool) 0; /* 8 */
190 values[i++] = (Datum) InvalidOid; /* 9 */
191 values[i++] = (Datum) InvalidOid; /* 10 */
192 values[i++] = (Datum) InvalidOid; /* 11 */
193 values[i++] = (Datum) InvalidOid; /* 12 */
194 values[i++] = (Datum) InvalidOid; /* 13 */
195 values[i++] = (Datum) InvalidOid; /* 14 */
196 values[i++] = (Datum) 'i'; /* 15 */
199 * ... and fill typdefault with a bogus value
202 (Datum) fmgr(F_TEXTIN, typeName); /* 15 */
205 * create a new type tuple with FormHeapTuple
208 tupDesc = pg_type_desc->rd_att;
210 tup = heap_formtuple(tupDesc, values, nulls);
213 * insert the tuple in the relation and get the tuple's oid.
216 heap_insert(pg_type_desc, tup);
219 if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
221 Relation idescs[Num_pg_type_indices];
223 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
224 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
225 CatalogCloseIndices(Num_pg_type_indices, idescs);
228 * free the tuple and return the type-oid
237 /* ----------------------------------------------------------------
240 * This procedure inserts a "shell" tuple into the type
241 * relation. The type tuple inserted has invalid values
242 * and in particular, the "typisdefined" field is false.
244 * This is used so that a tuple exists in the catalogs.
245 * The invalid fields should be fixed up sometime after
246 * this routine is called, and then the "typeisdefined"
247 * field is set to true. -cim 6/15/90
248 * ----------------------------------------------------------------
251 TypeShellMake(char *typeName)
253 Relation pg_type_desc;
256 Assert(PointerIsValid(typeName));
262 pg_type_desc = heap_openr(TypeRelationName);
265 * insert the shell tuple
268 typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
271 * close pg_type and return the tuple's oid.
274 heap_close(pg_type_desc);
280 /* ----------------------------------------------------------------
283 * This does all the necessary work needed to define a new type.
284 * ----------------------------------------------------------------
287 TypeCreate(char *typeName,
288 Oid relationOid, /* only for 'c'atalog typeTypes */
293 char *inputProcedure,
294 char *outputProcedure,
295 char *receiveProcedure,
297 char *elementTypeName,
298 char *defaultTypeValue, /* internal rep */
304 Relation pg_type_desc;
305 HeapScanDesc pg_type_scan;
308 Oid elementObjectId = InvalidOid;
311 char nulls[Natts_pg_type];
312 char replaces[Natts_pg_type];
313 Datum values[Natts_pg_type];
319 ItemPointerData itemPointerData;
324 static ScanKeyData typeKey[1] = {
325 {0, Anum_pg_type_typname, F_NAMEEQ}
328 fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
329 typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
332 * check that the type is not already defined.
335 typeObjectId = TypeGet(typeName, &defined);
336 if (OidIsValid(typeObjectId) && defined)
338 elog(ERROR, "TypeCreate: type %s already defined", typeName);
342 * if this type has an associated elementType, then we check that
348 elementObjectId = TypeGet(elementTypeName, &defined);
351 elog(ERROR, "TypeCreate: type %s is not defined", elementTypeName);
359 if (externalSize == 0)
361 externalSize = -1; /* variable length */
365 * initialize arrays needed by FormHeapTuple
368 for (i = 0; i < Natts_pg_type; ++i)
372 values[i] = (Datum) NULL; /* redundant, but nice */
378 * Do this so that user-defined types have size -1 instead of zero if
379 * they are variable-length - this is so that everything else in the
383 if (internalSize == 0)
387 * initialize the values[] information
391 namestrcpy(&name,typeName);
392 values[i++] = NameGetDatum(&name); /* 1 */
393 values[i++] = (Datum) GetUserId(); /* 2 */
394 values[i++] = (Datum) internalSize; /* 3 */
395 values[i++] = (Datum) externalSize; /* 4 */
396 values[i++] = (Datum) passedByValue; /* 5 */
397 values[i++] = (Datum) typeType; /* 6 */
398 values[i++] = (Datum) (bool) 1; /* 7 */
399 values[i++] = (Datum) typDelim; /* 8 */
400 values[i++] = (Datum) (typeType == 'c' ? relationOid : InvalidOid); /* 9 */
401 values[i++] = (Datum) elementObjectId; /* 10 */
404 * arguments to type input and output functions must be 0
406 MemSet(argList, 0, 8 * sizeof(Oid));
408 procs[0] = inputProcedure;
409 procs[1] = outputProcedure;
410 procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure;
411 procs[3] = (sendProcedure) ? sendProcedure : outputProcedure;
413 for (j = 0; j < 4; ++j)
417 tup = SearchSysCacheTuple(PRONAME,
418 PointerGetDatum(procname),
420 PointerGetDatum(argList),
423 if (!HeapTupleIsValid(tup))
427 * it is possible for the input/output procedure to take two
428 * arguments, where the second argument is the element type
429 * (eg array_in/array_out)
431 if (OidIsValid(elementObjectId))
433 tup = SearchSysCacheTuple(PRONAME,
434 PointerGetDatum(procname),
436 PointerGetDatum(argList),
439 if (!HeapTupleIsValid(tup))
441 func_error("TypeCreate", procname, 1, argList, NULL);
445 values[i++] = (Datum) tup->t_oid; /* 11 - 14 */
449 * set default alignment
452 values[i++] = (Datum) alignment; /* 15 */
455 * initialize the default value for this type.
458 values[i] = (Datum) fmgr(F_TEXTIN, /* 16 */
459 PointerIsValid(defaultTypeValue)
460 ? defaultTypeValue : "-"); /* XXX default
464 * open pg_type and begin a scan for the type name.
467 pg_type_desc = heap_openr(TypeRelationName);
470 * Set a write lock initially so as not upgrade a read to a write
471 * when the heap_insert() or heap_replace() is called.
474 RelationSetLockForWrite(pg_type_desc);
476 typeKey[0].sk_argument = PointerGetDatum(typeName);
477 pg_type_scan = heap_beginscan(pg_type_desc,
484 * define the type either by adding a tuple to the type
485 * relation, or by updating the fields of the "shell" tuple
489 tup = heap_getnext(pg_type_scan, 0, &buffer);
490 if (HeapTupleIsValid(tup))
492 tup = heap_modifytuple(tup,
499 /* XXX may not be necessary */
500 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
502 setheapoverride(true);
503 heap_replace(pg_type_desc, &itemPointerData, tup);
504 setheapoverride(false);
506 typeObjectId = tup->t_oid;
510 tupDesc = pg_type_desc->rd_att;
512 tup = heap_formtuple(tupDesc,
516 heap_insert(pg_type_desc, tup);
518 typeObjectId = tup->t_oid;
525 heap_endscan(pg_type_scan);
527 if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
529 Relation idescs[Num_pg_type_indices];
531 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
532 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
533 CatalogCloseIndices(Num_pg_type_indices, idescs);
535 RelationUnsetLockForWrite(pg_type_desc);
536 heap_close(pg_type_desc);
543 /* ----------------------------------------------------------------
546 * This renames a type
547 * ----------------------------------------------------------------
550 TypeRename(char *oldTypeName, char *newTypeName)
552 Relation pg_type_desc;
553 Relation idescs[Num_pg_type_indices];
557 ItemPointerData itemPointerData;
559 /* check that that the new type is not already defined */
560 type_oid = TypeGet(newTypeName, &defined);
561 if (OidIsValid(type_oid) && defined)
563 elog(ERROR, "TypeRename: type %s already defined", newTypeName);
566 /* get the type tuple from the catalog index scan manager */
567 pg_type_desc = heap_openr(TypeRelationName);
568 tup = TypeNameIndexScan(pg_type_desc, oldTypeName);
571 * change the name of the type
574 if (HeapTupleIsValid(tup))
577 namestrcpy(&(((TypeTupleForm) GETSTRUCT(tup))->typname), newTypeName);
579 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
581 setheapoverride(true);
582 heap_replace(pg_type_desc, &itemPointerData, tup);
583 setheapoverride(false);
585 /* update the system catalog indices */
586 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
587 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
588 CatalogCloseIndices(Num_pg_type_indices, idescs);
596 elog(ERROR, "TypeRename: type %s not defined", oldTypeName);
600 heap_close(pg_type_desc);
604 * makeArrayTypeName(typeName);
605 * - given a base type name, make an array of type name out of it
607 * the CALLER is responsible for pfreeing the
611 makeArrayTypeName(char *typeName)
617 arr = palloc(strlen(typeName) + 2);
619 strcpy(arr + 1, typeName);