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.29 1998/09/01 03:21:49 momjian 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/bufmgr.h"
25 #include "storage/lmgr.h"
26 #include "utils/builtins.h"
27 #include "utils/syscache.h"
28 #include "utils/tqual.h"
31 #include <regex/utils.h>
37 TypeShellMakeWithOpenRelation(Relation pg_type_desc,
40 /* ----------------------------------------------------------------
41 * TypeGetWithOpenRelation
43 * preforms a scan on pg_type for a type tuple with the
45 * ----------------------------------------------------------------
46 * pg_type_desc -- reldesc for pg_type
47 * typeName -- name of type to be fetched
48 * defined -- has the type been defined?
51 TypeGetWithOpenRelation(Relation pg_type_desc,
58 static ScanKeyData typeKey[1] = {
59 {0, Anum_pg_type_typname, F_NAMEEQ}
63 * initialize the scan key and begin a scan of pg_type
66 fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
67 typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
68 typeKey[0].sk_argument = PointerGetDatum(typeName);
70 scan = heap_beginscan(pg_type_desc,
72 SnapshotSelf, /* cache? */
77 * get the type tuple, if it exists.
80 tup = heap_getnext(scan, 0);
83 * if no type tuple exists for the given type name, then
84 * end the scan and return appropriate information.
87 if (!HeapTupleIsValid(tup))
95 * here, the type tuple does exist so we pull information from
96 * the typisdefined field of the tuple and return the tuple's
97 * oid, which is the oid of the type.
101 *defined = (bool) ((Form_pg_type) 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);
149 /* ----------------------------------------------------------------
150 * TypeShellMakeWithOpenRelation
152 * ----------------------------------------------------------------
155 TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
159 Datum values[Natts_pg_type];
160 char nulls[Natts_pg_type];
166 * initialize our *nulls and *values arrays
169 for (i = 0; i < Natts_pg_type; ++i)
172 values[i] = (Datum) NULL; /* redundant, but safe */
176 * initialize *values with the type name and
180 namestrcpy(&name, typeName);
181 values[i++] = NameGetDatum(&name); /* 1 */
182 values[i++] = (Datum) InvalidOid; /* 2 */
183 values[i++] = (Datum) (int16) 0; /* 3 */
184 values[i++] = (Datum) (int16) 0; /* 4 */
185 values[i++] = (Datum) (bool) 0; /* 5 */
186 values[i++] = (Datum) (bool) 0; /* 6 */
187 values[i++] = (Datum) (bool) 0; /* 7 */
188 values[i++] = (Datum) (bool) 0; /* 8 */
189 values[i++] = (Datum) InvalidOid; /* 9 */
190 values[i++] = (Datum) InvalidOid; /* 10 */
191 values[i++] = (Datum) InvalidOid; /* 11 */
192 values[i++] = (Datum) InvalidOid; /* 12 */
193 values[i++] = (Datum) InvalidOid; /* 13 */
194 values[i++] = (Datum) InvalidOid; /* 14 */
195 values[i++] = (Datum) 'i'; /* 15 */
198 * ... and fill typdefault with a bogus value
201 (Datum) fmgr(F_TEXTIN, typeName); /* 15 */
204 * create a new type tuple with FormHeapTuple
207 tupDesc = pg_type_desc->rd_att;
209 tup = heap_formtuple(tupDesc, values, nulls);
212 * insert the tuple in the relation and get the tuple's oid.
215 heap_insert(pg_type_desc, tup);
218 if (RelationGetForm(pg_type_desc)->relhasindex)
220 Relation idescs[Num_pg_type_indices];
222 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
223 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
224 CatalogCloseIndices(Num_pg_type_indices, idescs);
227 * free the tuple and return the type-oid
236 /* ----------------------------------------------------------------
239 * This procedure inserts a "shell" tuple into the type
240 * relation. The type tuple inserted has invalid values
241 * and in particular, the "typisdefined" field is false.
243 * This is used so that a tuple exists in the catalogs.
244 * The invalid fields should be fixed up sometime after
245 * this routine is called, and then the "typeisdefined"
246 * field is set to true. -cim 6/15/90
247 * ----------------------------------------------------------------
250 TypeShellMake(char *typeName)
252 Relation pg_type_desc;
255 Assert(PointerIsValid(typeName));
261 pg_type_desc = heap_openr(TypeRelationName);
264 * insert the shell tuple
267 typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
270 * close pg_type and return the tuple's oid.
273 heap_close(pg_type_desc);
279 /* ----------------------------------------------------------------
282 * This does all the necessary work needed to define a new type.
283 * ----------------------------------------------------------------
286 TypeCreate(char *typeName,
287 Oid relationOid, /* only for 'c'atalog typeTypes */
292 char *inputProcedure,
293 char *outputProcedure,
294 char *receiveProcedure,
296 char *elementTypeName,
297 char *defaultTypeValue, /* internal rep */
303 Relation pg_type_desc;
304 HeapScanDesc pg_type_scan;
307 Oid elementObjectId = InvalidOid;
310 char nulls[Natts_pg_type];
311 char replaces[Natts_pg_type];
312 Datum values[Natts_pg_type];
321 static ScanKeyData typeKey[1] = {
322 {0, Anum_pg_type_typname, F_NAMEEQ}
325 fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
326 typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
329 * check that the type is not already defined.
332 typeObjectId = TypeGet(typeName, &defined);
333 if (OidIsValid(typeObjectId) && defined)
334 elog(ERROR, "TypeCreate: type %s already defined", typeName);
337 * if this type has an associated elementType, then we check that
343 elementObjectId = TypeGet(elementTypeName, &defined);
345 elog(ERROR, "TypeCreate: type %s is not defined", elementTypeName);
352 if (externalSize == 0)
353 externalSize = -1; /* variable length */
356 * initialize arrays needed by FormHeapTuple
359 for (i = 0; i < Natts_pg_type; ++i)
363 values[i] = (Datum) NULL; /* redundant, but nice */
369 * Do this so that user-defined types have size -1 instead of zero if
370 * they are variable-length - this is so that everything else in the
374 if (internalSize == 0)
378 * initialize the *values information
382 namestrcpy(&name,typeName);
383 values[i++] = NameGetDatum(&name); /* 1 */
384 values[i++] = (Datum) GetUserId(); /* 2 */
385 values[i++] = (Datum) internalSize; /* 3 */
386 values[i++] = (Datum) externalSize; /* 4 */
387 values[i++] = (Datum) passedByValue;/* 5 */
388 values[i++] = (Datum) typeType; /* 6 */
389 values[i++] = (Datum) (bool) 1; /* 7 */
390 values[i++] = (Datum) typDelim; /* 8 */
391 values[i++] = (Datum) (typeType == 'c' ? relationOid : InvalidOid); /* 9 */
392 values[i++] = (Datum) elementObjectId;/* 10 */
395 * arguments to type input and output functions must be 0
397 MemSet(argList, 0, 8 * sizeof(Oid));
399 procs[0] = inputProcedure;
400 procs[1] = outputProcedure;
401 procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure;
402 procs[3] = (sendProcedure) ? sendProcedure : outputProcedure;
404 for (j = 0; j < 4; ++j)
408 tup = SearchSysCacheTuple(PRONAME,
409 PointerGetDatum(procname),
411 PointerGetDatum(argList),
414 if (!HeapTupleIsValid(tup))
418 * it is possible for the input/output procedure to take two
419 * arguments, where the second argument is the element type
420 * (eg array_in/array_out)
422 if (OidIsValid(elementObjectId))
424 tup = SearchSysCacheTuple(PRONAME,
425 PointerGetDatum(procname),
427 PointerGetDatum(argList),
430 if (!HeapTupleIsValid(tup))
431 func_error("TypeCreate", procname, 1, argList, NULL);
434 values[i++] = (Datum) tup->t_oid; /* 11 - 14 */
438 * set default alignment
441 values[i++] = (Datum) alignment; /* 15 */
444 * initialize the default value for this type.
447 values[i] = (Datum) fmgr(F_TEXTIN, /* 16 */
448 PointerIsValid(defaultTypeValue)
449 ? defaultTypeValue : "-"); /* XXX default
453 * open pg_type and begin a scan for the type name.
456 pg_type_desc = heap_openr(TypeRelationName);
459 * Set a write lock initially so as not upgrade a read to a write
460 * when the heap_insert() or heap_replace() is called.
463 RelationSetLockForWrite(pg_type_desc);
465 typeKey[0].sk_argument = PointerGetDatum(typeName);
466 pg_type_scan = heap_beginscan(pg_type_desc,
468 SnapshotSelf, /* cache? */
473 * define the type either by adding a tuple to the type
474 * relation, or by updating the fields of the "shell" tuple
478 tup = heap_getnext(pg_type_scan, 0);
479 if (HeapTupleIsValid(tup))
481 tup = heap_modifytuple(tup,
487 setheapoverride(true);
488 heap_replace(pg_type_desc, &tup->t_ctid, tup);
489 setheapoverride(false);
491 typeObjectId = tup->t_oid;
495 tupDesc = pg_type_desc->rd_att;
497 tup = heap_formtuple(tupDesc,
501 heap_insert(pg_type_desc, tup);
503 typeObjectId = tup->t_oid;
510 heap_endscan(pg_type_scan);
512 if (RelationGetForm(pg_type_desc)->relhasindex)
514 Relation idescs[Num_pg_type_indices];
516 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
517 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
518 CatalogCloseIndices(Num_pg_type_indices, idescs);
520 RelationUnsetLockForWrite(pg_type_desc);
521 heap_close(pg_type_desc);
526 /* ----------------------------------------------------------------
529 * This renames a type
530 * ----------------------------------------------------------------
533 TypeRename(char *oldTypeName, char *newTypeName)
535 Relation pg_type_desc;
536 Relation idescs[Num_pg_type_indices];
537 HeapTuple oldtup, newtup;
539 pg_type_desc = heap_openr(TypeRelationName);
541 oldtup = SearchSysCacheTupleCopy(TYPNAME,
542 PointerGetDatum(oldTypeName),
545 if (!HeapTupleIsValid(oldtup))
547 heap_close(pg_type_desc);
548 elog(ERROR, "TypeRename: type %s not defined", oldTypeName);
551 newtup = SearchSysCacheTuple(TYPNAME,
552 PointerGetDatum(newTypeName),
554 if (HeapTupleIsValid(newtup))
557 heap_close(pg_type_desc);
558 elog(ERROR, "TypeRename: type %s already defined", newTypeName);
561 namestrcpy(&(((Form_pg_type) GETSTRUCT(oldtup))->typname), newTypeName);
563 setheapoverride(true);
564 heap_replace(pg_type_desc, &oldtup->t_ctid, oldtup);
565 setheapoverride(false);
567 /* update the system catalog indices */
568 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
569 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, oldtup);
570 CatalogCloseIndices(Num_pg_type_indices, idescs);
573 heap_close(pg_type_desc);
577 * makeArrayTypeName(typeName);
578 * - given a base type name, make an array of type name out of it
580 * the CALLER is responsible for pfreeing the
584 makeArrayTypeName(char *typeName)
590 arr = palloc(strlen(typeName) + 2);
592 strcpy(arr + 1, typeName);