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.10 1997/09/08 21:42:24 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>
22 #include <parser/catalog_utils.h>
23 #include <catalog/catname.h>
24 #include <catalog/indexing.h>
25 #include <storage/lmgr.h>
26 #include <miscadmin.h>
28 #include <regex/utils.h>
34 TypeShellMakeWithOpenRelation(Relation pg_type_desc,
37 /* ----------------------------------------------------------------
38 * TypeGetWithOpenRelation
40 * preforms a scan on pg_type for a type tuple with the
42 * ----------------------------------------------------------------
43 * pg_type_desc -- reldesc for pg_type
44 * typeName -- name of type to be fetched
45 * defined -- has the type been defined?
48 TypeGetWithOpenRelation(Relation pg_type_desc,
55 static ScanKeyData typeKey[1] = {
56 {0, Anum_pg_type_typname, NameEqualRegProcedure}
60 * initialize the scan key and begin a scan of pg_type
63 fmgr_info(NameEqualRegProcedure,
64 &typeKey[0].sk_func, &typeKey[0].sk_nargs);
65 typeKey[0].sk_argument = PointerGetDatum(typeName);
67 scan = heap_beginscan(pg_type_desc,
74 * get the type tuple, if it exists.
77 tup = heap_getnext(scan, 0, (Buffer *) 0);
80 * if no type tuple exists for the given type name, then
81 * end the scan and return appropriate information.
84 if (!HeapTupleIsValid(tup))
92 * here, the type tuple does exist so we pull information from
93 * the typisdefined field of the tuple and return the tuple's
94 * oid, which is the oid of the type.
98 *defined = (bool) ((TypeTupleForm) GETSTRUCT(tup))->typisdefined;
104 /* ----------------------------------------------------------------
107 * Finds the ObjectId of a type, even if uncommitted; "defined"
108 * is only set if the type has actually been defined, i.e., if
109 * the type tuple is not a shell.
111 * Note: the meat of this function is now in the function
112 * TypeGetWithOpenRelation(). -cim 6/15/90
114 * Also called from util/remove.c
115 * ----------------------------------------------------------------
118 TypeGet(char *typeName, /* name of type to be fetched */
119 bool *defined) /* has the type been defined? */
121 Relation pg_type_desc;
125 * open the pg_type relation
128 pg_type_desc = heap_openr(TypeRelationName);
131 * scan the type relation for the information we want
134 typeoid = TypeGetWithOpenRelation(pg_type_desc,
139 * close the type relation and return the type oid.
142 heap_close(pg_type_desc);
148 /* ----------------------------------------------------------------
149 * TypeShellMakeWithOpenRelation
151 * ----------------------------------------------------------------
154 TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
158 Datum values[Natts_pg_type];
159 char nulls[Natts_pg_type];
164 * initialize our nulls[] and values[] arrays
167 for (i = 0; i < Natts_pg_type; ++i)
170 values[i] = (Datum) NULL; /* redundant, but safe */
174 * initialize values[] with the type name and
178 values[i++] = (Datum) typeName; /* 1 */
179 values[i++] = (Datum) InvalidOid; /* 2 */
180 values[i++] = (Datum) (int16) 0; /* 3 */
181 values[i++] = (Datum) (int16) 0; /* 4 */
182 values[i++] = (Datum) (bool) 0; /* 5 */
183 values[i++] = (Datum) (bool) 0; /* 6 */
184 values[i++] = (Datum) (bool) 0; /* 7 */
185 values[i++] = (Datum) (bool) 0; /* 8 */
186 values[i++] = (Datum) InvalidOid; /* 9 */
187 values[i++] = (Datum) InvalidOid; /* 10 */
188 values[i++] = (Datum) InvalidOid; /* 11 */
189 values[i++] = (Datum) InvalidOid; /* 12 */
190 values[i++] = (Datum) InvalidOid; /* 13 */
191 values[i++] = (Datum) InvalidOid; /* 14 */
192 values[i++] = (Datum) 'i'; /* 15 */
195 * ... and fill typdefault with a bogus value
198 (Datum) fmgr(TextInRegProcedure, typeName); /* 15 */
201 * create a new type tuple with FormHeapTuple
204 tupDesc = pg_type_desc->rd_att;
206 tup = heap_formtuple(tupDesc, values, nulls);
209 * insert the tuple in the relation and get the tuple's oid.
212 heap_insert(pg_type_desc, tup);
215 if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
217 Relation idescs[Num_pg_type_indices];
219 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
220 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
221 CatalogCloseIndices(Num_pg_type_indices, idescs);
224 * free the tuple and return the type-oid
233 /* ----------------------------------------------------------------
236 * This procedure inserts a "shell" tuple into the type
237 * relation. The type tuple inserted has invalid values
238 * and in particular, the "typisdefined" field is false.
240 * This is used so that a tuple exists in the catalogs.
241 * The invalid fields should be fixed up sometime after
242 * this routine is called, and then the "typeisdefined"
243 * field is set to true. -cim 6/15/90
244 * ----------------------------------------------------------------
247 TypeShellMake(char *typeName)
249 Relation pg_type_desc;
252 Assert(PointerIsValid(typeName));
258 pg_type_desc = heap_openr(TypeRelationName);
261 * insert the shell tuple
264 typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
267 * close pg_type and return the tuple's oid.
270 heap_close(pg_type_desc);
276 /* ----------------------------------------------------------------
279 * This does all the necessary work needed to define a new type.
280 * ----------------------------------------------------------------
283 TypeCreate(char *typeName,
284 Oid relationOid, /* only for 'c'atalog typeTypes */
289 char *inputProcedure,
290 char *outputProcedure,
292 char *receiveProcedure,
293 char *elementTypeName,
294 char *defaultTypeValue, /* internal rep */
300 Relation pg_type_desc;
301 HeapScanDesc pg_type_scan;
304 Oid elementObjectId = InvalidOid;
307 char nulls[Natts_pg_type];
308 char replaces[Natts_pg_type];
309 Datum values[Natts_pg_type];
315 ItemPointerData itemPointerData;
321 static ScanKeyData typeKey[1] = {
322 {0, Anum_pg_type_typname, NameEqualRegProcedure}
325 fmgr_info(NameEqualRegProcedure,
326 &typeKey[0].sk_func, &typeKey[0].sk_nargs);
329 * check that the type is not already defined.
332 typeObjectId = TypeGet(typeName, &defined);
333 if (OidIsValid(typeObjectId) && defined)
335 elog(WARN, "TypeCreate: type %s already defined", typeName);
339 * if this type has an associated elementType, then we check that
345 elementObjectId = TypeGet(elementTypeName, &defined);
348 elog(WARN, "TypeCreate: type %s is not defined", elementTypeName);
356 if (externalSize == 0)
358 externalSize = -1; /* variable length */
362 * initialize arrays needed by FormHeapTuple
365 for (i = 0; i < Natts_pg_type; ++i)
369 values[i] = (Datum) NULL; /* redundant, but nice */
375 * Do this so that user-defined types have size -1 instead of zero if
376 * they are variable-length - this is so that everything else in the
380 if (internalSize == 0)
384 * initialize the values[] information
388 values[i++] = PointerGetDatum(typeName); /* 1 */
389 values[i++] = (Datum) GetUserId(); /* 2 */
390 values[i++] = (Datum) internalSize; /* 3 */
391 values[i++] = (Datum) externalSize; /* 4 */
392 values[i++] = (Datum) passedByValue; /* 5 */
393 values[i++] = (Datum) typeType; /* 6 */
394 values[i++] = (Datum) (bool) 1; /* 7 */
395 values[i++] = (Datum) typDelim; /* 8 */
396 values[i++] = (Datum) (typeType == 'c' ? relationOid : InvalidOid); /* 9 */
397 values[i++] = (Datum) elementObjectId; /* 10 */
400 * arguments to type input and output functions must be 0
402 memset(argList, 0, 8 * sizeof(Oid));
404 procs[0] = inputProcedure;
405 procs[1] = outputProcedure;
406 procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure;
407 procs[3] = (sendProcedure) ? sendProcedure : outputProcedure;
409 for (j = 0; j < 4; ++j)
413 tup = SearchSysCacheTuple(PRONAME,
414 PointerGetDatum(procname),
416 PointerGetDatum(argList),
419 if (!HeapTupleIsValid(tup))
423 * it is possible for the input/output procedure to take two
424 * arguments, where the second argument is the element type
425 * (eg array_in/array_out)
427 if (OidIsValid(elementObjectId))
429 tup = SearchSysCacheTuple(PRONAME,
430 PointerGetDatum(procname),
432 PointerGetDatum(argList),
435 if (!HeapTupleIsValid(tup))
437 func_error("TypeCreate", procname, 1, argList);
441 values[i++] = (Datum) tup->t_oid; /* 11 - 14 */
445 * set default alignment
448 values[i++] = (Datum) alignment; /* 15 */
451 * initialize the default value for this type.
454 values[i] = (Datum) fmgr(TextInRegProcedure, /* 16 */
455 PointerIsValid(defaultTypeValue)
456 ? defaultTypeValue : "-"); /* XXX default
460 * open pg_type and begin a scan for the type name.
463 pg_type_desc = heap_openr(TypeRelationName);
466 * Set a write lock initially so as not upgrade a read to a write
467 * when the heap_insert() or heap_replace() is called.
470 RelationSetLockForWrite(pg_type_desc);
472 typeKey[0].sk_argument = PointerGetDatum(typeName);
473 pg_type_scan = heap_beginscan(pg_type_desc,
480 * define the type either by adding a tuple to the type
481 * relation, or by updating the fields of the "shell" tuple
485 tup = heap_getnext(pg_type_scan, 0, &buffer);
486 if (HeapTupleIsValid(tup))
488 tup = heap_modifytuple(tup,
495 /* XXX may not be necessary */
496 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
498 setheapoverride(true);
499 heap_replace(pg_type_desc, &itemPointerData, tup);
500 setheapoverride(false);
502 typeObjectId = tup->t_oid;
506 tupDesc = pg_type_desc->rd_att;
508 tup = heap_formtuple(tupDesc,
512 heap_insert(pg_type_desc, tup);
514 typeObjectId = tup->t_oid;
521 heap_endscan(pg_type_scan);
523 if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
525 Relation idescs[Num_pg_type_indices];
527 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
528 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
529 CatalogCloseIndices(Num_pg_type_indices, idescs);
531 RelationUnsetLockForWrite(pg_type_desc);
532 heap_close(pg_type_desc);
539 /* ----------------------------------------------------------------
542 * This renames a type
543 * ----------------------------------------------------------------
546 TypeRename(char *oldTypeName, char *newTypeName)
548 Relation pg_type_desc;
549 Relation idescs[Num_pg_type_indices];
553 ItemPointerData itemPointerData;
555 /* check that that the new type is not already defined */
556 type_oid = TypeGet(newTypeName, &defined);
557 if (OidIsValid(type_oid) && defined)
559 elog(WARN, "TypeRename: type %s already defined", newTypeName);
562 /* get the type tuple from the catalog index scan manager */
563 pg_type_desc = heap_openr(TypeRelationName);
564 tup = TypeNameIndexScan(pg_type_desc, oldTypeName);
567 * change the name of the type
570 if (HeapTupleIsValid(tup))
573 namestrcpy(&(((TypeTupleForm) GETSTRUCT(tup))->typname), newTypeName);
575 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
577 setheapoverride(true);
578 heap_replace(pg_type_desc, &itemPointerData, tup);
579 setheapoverride(false);
581 /* update the system catalog indices */
582 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
583 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
584 CatalogCloseIndices(Num_pg_type_indices, idescs);
592 elog(WARN, "TypeRename: type %s not defined", oldTypeName);
596 heap_close(pg_type_desc);
600 * makeArrayTypeName(typeName);
601 * - given a base type name, make an array of type name out of it
603 * the CALLER is responsible for pfreeing the
607 makeArrayTypeName(char *typeName)
613 arr = palloc(strlen(typeName) + 2);
615 strcpy(arr + 1, typeName);