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.13 1997/11/24 05:08:17 momjian Exp $
12 *-------------------------------------------------------------------------
16 #include <utils/syscache.h>
17 #include <catalog/pg_proc.h>
18 #include <access/heapam.h>
19 #include <access/relscan.h>
20 #include <utils/builtins.h>
21 #include <utils/tqual.h>
23 #include <parser/catalog_utils.h>
24 #include <catalog/catname.h>
25 #include <catalog/indexing.h>
26 #include <storage/lmgr.h>
27 #include <miscadmin.h>
29 #include <regex/utils.h>
35 TypeShellMakeWithOpenRelation(Relation pg_type_desc,
38 /* ----------------------------------------------------------------
39 * TypeGetWithOpenRelation
41 * preforms a scan on pg_type for a type tuple with the
43 * ----------------------------------------------------------------
44 * pg_type_desc -- reldesc for pg_type
45 * typeName -- name of type to be fetched
46 * defined -- has the type been defined?
49 TypeGetWithOpenRelation(Relation pg_type_desc,
56 static ScanKeyData typeKey[1] = {
57 {0, Anum_pg_type_typname, NameEqualRegProcedure}
61 * initialize the scan key and begin a scan of pg_type
64 fmgr_info(NameEqualRegProcedure,
65 &typeKey[0].sk_func, &typeKey[0].sk_nargs);
66 typeKey[0].sk_argument = PointerGetDatum(typeName);
68 scan = heap_beginscan(pg_type_desc,
75 * get the type tuple, if it exists.
78 tup = heap_getnext(scan, 0, (Buffer *) 0);
81 * if no type tuple exists for the given type name, then
82 * end the scan and return appropriate information.
85 if (!HeapTupleIsValid(tup))
93 * here, the type tuple does exist so we pull information from
94 * the typisdefined field of the tuple and return the tuple's
95 * oid, which is the oid of the type.
99 *defined = (bool) ((TypeTupleForm) GETSTRUCT(tup))->typisdefined;
105 /* ----------------------------------------------------------------
108 * Finds the ObjectId of a type, even if uncommitted; "defined"
109 * is only set if the type has actually been defined, i.e., if
110 * the type tuple is not a shell.
112 * Note: the meat of this function is now in the function
113 * TypeGetWithOpenRelation(). -cim 6/15/90
115 * Also called from util/remove.c
116 * ----------------------------------------------------------------
119 TypeGet(char *typeName, /* name of type to be fetched */
120 bool *defined) /* has the type been defined? */
122 Relation pg_type_desc;
126 * open the pg_type relation
129 pg_type_desc = heap_openr(TypeRelationName);
132 * scan the type relation for the information we want
135 typeoid = TypeGetWithOpenRelation(pg_type_desc,
140 * close the type relation and return the type oid.
143 heap_close(pg_type_desc);
149 /* ----------------------------------------------------------------
150 * TypeShellMakeWithOpenRelation
152 * ----------------------------------------------------------------
155 TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
159 Datum values[Natts_pg_type];
160 char nulls[Natts_pg_type];
165 * initialize our nulls[] and values[] arrays
168 for (i = 0; i < Natts_pg_type; ++i)
171 values[i] = (Datum) NULL; /* redundant, but safe */
175 * initialize values[] with the type name and
179 values[i++] = (Datum) typeName; /* 1 */
180 values[i++] = (Datum) InvalidOid; /* 2 */
181 values[i++] = (Datum) (int16) 0; /* 3 */
182 values[i++] = (Datum) (int16) 0; /* 4 */
183 values[i++] = (Datum) (bool) 0; /* 5 */
184 values[i++] = (Datum) (bool) 0; /* 6 */
185 values[i++] = (Datum) (bool) 0; /* 7 */
186 values[i++] = (Datum) (bool) 0; /* 8 */
187 values[i++] = (Datum) InvalidOid; /* 9 */
188 values[i++] = (Datum) InvalidOid; /* 10 */
189 values[i++] = (Datum) InvalidOid; /* 11 */
190 values[i++] = (Datum) InvalidOid; /* 12 */
191 values[i++] = (Datum) InvalidOid; /* 13 */
192 values[i++] = (Datum) InvalidOid; /* 14 */
193 values[i++] = (Datum) 'i'; /* 15 */
196 * ... and fill typdefault with a bogus value
199 (Datum) fmgr(TextInRegProcedure, typeName); /* 15 */
202 * create a new type tuple with FormHeapTuple
205 tupDesc = pg_type_desc->rd_att;
207 tup = heap_formtuple(tupDesc, values, nulls);
210 * insert the tuple in the relation and get the tuple's oid.
213 heap_insert(pg_type_desc, tup);
216 if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
218 Relation idescs[Num_pg_type_indices];
220 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
221 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
222 CatalogCloseIndices(Num_pg_type_indices, idescs);
225 * free the tuple and return the type-oid
234 /* ----------------------------------------------------------------
237 * This procedure inserts a "shell" tuple into the type
238 * relation. The type tuple inserted has invalid values
239 * and in particular, the "typisdefined" field is false.
241 * This is used so that a tuple exists in the catalogs.
242 * The invalid fields should be fixed up sometime after
243 * this routine is called, and then the "typeisdefined"
244 * field is set to true. -cim 6/15/90
245 * ----------------------------------------------------------------
248 TypeShellMake(char *typeName)
250 Relation pg_type_desc;
253 Assert(PointerIsValid(typeName));
259 pg_type_desc = heap_openr(TypeRelationName);
262 * insert the shell tuple
265 typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
268 * close pg_type and return the tuple's oid.
271 heap_close(pg_type_desc);
277 /* ----------------------------------------------------------------
280 * This does all the necessary work needed to define a new type.
281 * ----------------------------------------------------------------
284 TypeCreate(char *typeName,
285 Oid relationOid, /* only for 'c'atalog typeTypes */
290 char *inputProcedure,
291 char *outputProcedure,
293 char *receiveProcedure,
294 char *elementTypeName,
295 char *defaultTypeValue, /* internal rep */
301 Relation pg_type_desc;
302 HeapScanDesc pg_type_scan;
305 Oid elementObjectId = InvalidOid;
308 char nulls[Natts_pg_type];
309 char replaces[Natts_pg_type];
310 Datum values[Natts_pg_type];
316 ItemPointerData itemPointerData;
322 static ScanKeyData typeKey[1] = {
323 {0, Anum_pg_type_typname, NameEqualRegProcedure}
326 fmgr_info(NameEqualRegProcedure,
327 &typeKey[0].sk_func, &typeKey[0].sk_nargs);
330 * check that the type is not already defined.
333 typeObjectId = TypeGet(typeName, &defined);
334 if (OidIsValid(typeObjectId) && defined)
336 elog(WARN, "TypeCreate: type %s already defined", typeName);
340 * if this type has an associated elementType, then we check that
346 elementObjectId = TypeGet(elementTypeName, &defined);
349 elog(WARN, "TypeCreate: type %s is not defined", elementTypeName);
357 if (externalSize == 0)
359 externalSize = -1; /* variable length */
363 * initialize arrays needed by FormHeapTuple
366 for (i = 0; i < Natts_pg_type; ++i)
370 values[i] = (Datum) NULL; /* redundant, but nice */
376 * Do this so that user-defined types have size -1 instead of zero if
377 * they are variable-length - this is so that everything else in the
381 if (internalSize == 0)
385 * initialize the values[] information
389 values[i++] = PointerGetDatum(typeName); /* 1 */
390 values[i++] = (Datum) GetUserId(); /* 2 */
391 values[i++] = (Datum) internalSize; /* 3 */
392 values[i++] = (Datum) externalSize; /* 4 */
393 values[i++] = (Datum) passedByValue; /* 5 */
394 values[i++] = (Datum) typeType; /* 6 */
395 values[i++] = (Datum) (bool) 1; /* 7 */
396 values[i++] = (Datum) typDelim; /* 8 */
397 values[i++] = (Datum) (typeType == 'c' ? relationOid : InvalidOid); /* 9 */
398 values[i++] = (Datum) elementObjectId; /* 10 */
401 * arguments to type input and output functions must be 0
403 MemSet(argList, 0, 8 * sizeof(Oid));
405 procs[0] = inputProcedure;
406 procs[1] = outputProcedure;
407 procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure;
408 procs[3] = (sendProcedure) ? sendProcedure : outputProcedure;
410 for (j = 0; j < 4; ++j)
414 tup = SearchSysCacheTuple(PRONAME,
415 PointerGetDatum(procname),
417 PointerGetDatum(argList),
420 if (!HeapTupleIsValid(tup))
424 * it is possible for the input/output procedure to take two
425 * arguments, where the second argument is the element type
426 * (eg array_in/array_out)
428 if (OidIsValid(elementObjectId))
430 tup = SearchSysCacheTuple(PRONAME,
431 PointerGetDatum(procname),
433 PointerGetDatum(argList),
436 if (!HeapTupleIsValid(tup))
438 func_error("TypeCreate", procname, 1, argList);
442 values[i++] = (Datum) tup->t_oid; /* 11 - 14 */
446 * set default alignment
449 values[i++] = (Datum) alignment; /* 15 */
452 * initialize the default value for this type.
455 values[i] = (Datum) fmgr(TextInRegProcedure, /* 16 */
456 PointerIsValid(defaultTypeValue)
457 ? defaultTypeValue : "-"); /* XXX default
461 * open pg_type and begin a scan for the type name.
464 pg_type_desc = heap_openr(TypeRelationName);
467 * Set a write lock initially so as not upgrade a read to a write
468 * when the heap_insert() or heap_replace() is called.
471 RelationSetLockForWrite(pg_type_desc);
473 typeKey[0].sk_argument = PointerGetDatum(typeName);
474 pg_type_scan = heap_beginscan(pg_type_desc,
481 * define the type either by adding a tuple to the type
482 * relation, or by updating the fields of the "shell" tuple
486 tup = heap_getnext(pg_type_scan, 0, &buffer);
487 if (HeapTupleIsValid(tup))
489 tup = heap_modifytuple(tup,
496 /* XXX may not be necessary */
497 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
499 setheapoverride(true);
500 heap_replace(pg_type_desc, &itemPointerData, tup);
501 setheapoverride(false);
503 typeObjectId = tup->t_oid;
507 tupDesc = pg_type_desc->rd_att;
509 tup = heap_formtuple(tupDesc,
513 heap_insert(pg_type_desc, tup);
515 typeObjectId = tup->t_oid;
522 heap_endscan(pg_type_scan);
524 if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
526 Relation idescs[Num_pg_type_indices];
528 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
529 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
530 CatalogCloseIndices(Num_pg_type_indices, idescs);
532 RelationUnsetLockForWrite(pg_type_desc);
533 heap_close(pg_type_desc);
540 /* ----------------------------------------------------------------
543 * This renames a type
544 * ----------------------------------------------------------------
547 TypeRename(char *oldTypeName, char *newTypeName)
549 Relation pg_type_desc;
550 Relation idescs[Num_pg_type_indices];
554 ItemPointerData itemPointerData;
556 /* check that that the new type is not already defined */
557 type_oid = TypeGet(newTypeName, &defined);
558 if (OidIsValid(type_oid) && defined)
560 elog(WARN, "TypeRename: type %s already defined", newTypeName);
563 /* get the type tuple from the catalog index scan manager */
564 pg_type_desc = heap_openr(TypeRelationName);
565 tup = TypeNameIndexScan(pg_type_desc, oldTypeName);
568 * change the name of the type
571 if (HeapTupleIsValid(tup))
574 namestrcpy(&(((TypeTupleForm) GETSTRUCT(tup))->typname), newTypeName);
576 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
578 setheapoverride(true);
579 heap_replace(pg_type_desc, &itemPointerData, tup);
580 setheapoverride(false);
582 /* update the system catalog indices */
583 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
584 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
585 CatalogCloseIndices(Num_pg_type_indices, idescs);
593 elog(WARN, "TypeRename: type %s not defined", oldTypeName);
597 heap_close(pg_type_desc);
601 * makeArrayTypeName(typeName);
602 * - given a base type name, make an array of type name out of it
604 * the CALLER is responsible for pfreeing the
608 makeArrayTypeName(char *typeName)
614 arr = palloc(strlen(typeName) + 2);
616 strcpy(arr + 1, typeName);