]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_type.c
b6fe76bc1f7c53d92907d729ddbbb4c5f7af2f84
[postgresql] / src / backend / catalog / pg_type.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_type.c--
4  *        routines to support manipulation of the pg_type relation
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.10 1997/09/08 21:42:24 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <postgres.h>
15
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 <fmgr.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>
27 #ifndef HAVE_MEMMOVE
28 #include <regex/utils.h>
29 #else
30 #include <string.h>
31 #endif
32
33 static Oid
34 TypeShellMakeWithOpenRelation(Relation pg_type_desc,
35                                                           char *typeName);
36
37 /* ----------------------------------------------------------------
38  *              TypeGetWithOpenRelation
39  *
40  *              preforms a scan on pg_type for a type tuple with the
41  *              given type name.
42  * ----------------------------------------------------------------
43  *              pg_type_desc                     -- reldesc for pg_type
44  *              typeName                                 -- name of type to be fetched
45  *              defined                                  -- has the type been defined?
46  */
47 static Oid
48 TypeGetWithOpenRelation(Relation pg_type_desc,
49                                                 char *typeName,
50                                                 bool *defined)
51 {
52         HeapScanDesc scan;
53         HeapTuple       tup;
54
55         static ScanKeyData typeKey[1] = {
56                 {0, Anum_pg_type_typname, NameEqualRegProcedure}
57         };
58
59         /* ----------------
60          *      initialize the scan key and begin a scan of pg_type
61          * ----------------
62          */
63         fmgr_info(NameEqualRegProcedure,
64                           &typeKey[0].sk_func, &typeKey[0].sk_nargs);
65         typeKey[0].sk_argument = PointerGetDatum(typeName);
66
67         scan = heap_beginscan(pg_type_desc,
68                                                   0,
69                                                   SelfTimeQual,
70                                                   1,
71                                                   typeKey);
72
73         /* ----------------
74          *      get the type tuple, if it exists.
75          * ----------------
76          */
77         tup = heap_getnext(scan, 0, (Buffer *) 0);
78
79         /* ----------------
80          *      if no type tuple exists for the given type name, then
81          *      end the scan and return appropriate information.
82          * ----------------
83          */
84         if (!HeapTupleIsValid(tup))
85         {
86                 heap_endscan(scan);
87                 *defined = false;
88                 return InvalidOid;
89         }
90
91         /* ----------------
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.
95          * ----------------
96          */
97         heap_endscan(scan);
98         *defined = (bool) ((TypeTupleForm) GETSTRUCT(tup))->typisdefined;
99
100         return
101                 tup->t_oid;
102 }
103
104 /* ----------------------------------------------------------------
105  *              TypeGet
106  *
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.
110  *
111  *              Note: the meat of this function is now in the function
112  *                        TypeGetWithOpenRelation().  -cim 6/15/90
113  *
114  *              Also called from util/remove.c
115  * ----------------------------------------------------------------
116  */
117 Oid
118 TypeGet(char *typeName,                 /* name of type to be fetched */
119                 bool *defined)                  /* has the type been defined? */
120 {
121         Relation        pg_type_desc;
122         Oid                     typeoid;
123
124         /* ----------------
125          *      open the pg_type relation
126          * ----------------
127          */
128         pg_type_desc = heap_openr(TypeRelationName);
129
130         /* ----------------
131          *      scan the type relation for the information we want
132          * ----------------
133          */
134         typeoid = TypeGetWithOpenRelation(pg_type_desc,
135                                                                           typeName,
136                                                                           defined);
137
138         /* ----------------
139          *      close the type relation and return the type oid.
140          * ----------------
141          */
142         heap_close(pg_type_desc);
143
144         return
145                 typeoid;
146 }
147
148 /* ----------------------------------------------------------------
149  *              TypeShellMakeWithOpenRelation
150  *
151  * ----------------------------------------------------------------
152  */
153 static Oid
154 TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
155 {
156         register int i;
157         HeapTuple       tup;
158         Datum           values[Natts_pg_type];
159         char            nulls[Natts_pg_type];
160         Oid                     typoid;
161         TupleDesc       tupDesc;
162
163         /* ----------------
164          *      initialize our nulls[] and values[] arrays
165          * ----------------
166          */
167         for (i = 0; i < Natts_pg_type; ++i)
168         {
169                 nulls[i] = ' ';
170                 values[i] = (Datum) NULL;               /* redundant, but safe */
171         }
172
173         /* ----------------
174          *      initialize values[] with the type name and
175          * ----------------
176          */
177         i = 0;
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 */
193
194         /*
195          * ... and fill typdefault with a bogus value
196          */
197         values[i++] =
198                 (Datum) fmgr(TextInRegProcedure, typeName);             /* 15 */
199
200         /* ----------------
201          *      create a new type tuple with FormHeapTuple
202          * ----------------
203          */
204         tupDesc = pg_type_desc->rd_att;
205
206         tup = heap_formtuple(tupDesc, values, nulls);
207
208         /* ----------------
209          *      insert the tuple in the relation and get the tuple's oid.
210          * ----------------
211          */
212         heap_insert(pg_type_desc, tup);
213         typoid = tup->t_oid;
214
215         if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
216         {
217                 Relation        idescs[Num_pg_type_indices];
218
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);
222         }
223         /* ----------------
224          *      free the tuple and return the type-oid
225          * ----------------
226          */
227         pfree(tup);
228
229         return
230                 typoid;
231 }
232
233 /* ----------------------------------------------------------------
234  *              TypeShellMake
235  *
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.
239  *
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  * ----------------------------------------------------------------
245  */
246 Oid
247 TypeShellMake(char *typeName)
248 {
249         Relation        pg_type_desc;
250         Oid                     typoid;
251
252         Assert(PointerIsValid(typeName));
253
254         /* ----------------
255          *      open pg_type
256          * ----------------
257          */
258         pg_type_desc = heap_openr(TypeRelationName);
259
260         /* ----------------
261          *      insert the shell tuple
262          * ----------------
263          */
264         typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
265
266         /* ----------------
267          *      close pg_type and return the tuple's oid.
268          * ----------------
269          */
270         heap_close(pg_type_desc);
271
272         return
273                 typoid;
274 }
275
276 /* ----------------------------------------------------------------
277  *              TypeCreate
278  *
279  *              This does all the necessary work needed to define a new type.
280  * ----------------------------------------------------------------
281  */
282 Oid
283 TypeCreate(char *typeName,
284                    Oid relationOid,             /* only for 'c'atalog typeTypes */
285                    int16 internalSize,
286                    int16 externalSize,
287                    char typeType,
288                    char typDelim,
289                    char *inputProcedure,
290                    char *outputProcedure,
291                    char *sendProcedure,
292                    char *receiveProcedure,
293                    char *elementTypeName,
294                    char *defaultTypeValue,              /* internal rep */
295                    bool passedByValue,
296                    char alignment)
297 {
298         register        i,
299                                 j;
300         Relation        pg_type_desc;
301         HeapScanDesc pg_type_scan;
302
303         Oid                     typeObjectId;
304         Oid                     elementObjectId = InvalidOid;
305
306         HeapTuple       tup;
307         char            nulls[Natts_pg_type];
308         char            replaces[Natts_pg_type];
309         Datum           values[Natts_pg_type];
310
311         Buffer          buffer;
312         char       *procname;
313         char       *procs[4];
314         bool            defined;
315         ItemPointerData itemPointerData;
316         TupleDesc       tupDesc;
317
318         Oid                     argList[8];
319
320
321         static ScanKeyData typeKey[1] = {
322                 {0, Anum_pg_type_typname, NameEqualRegProcedure}
323         };
324
325         fmgr_info(NameEqualRegProcedure,
326                           &typeKey[0].sk_func, &typeKey[0].sk_nargs);
327
328         /* ----------------
329          *      check that the type is not already defined.
330          * ----------------
331          */
332         typeObjectId = TypeGet(typeName, &defined);
333         if (OidIsValid(typeObjectId) && defined)
334         {
335                 elog(WARN, "TypeCreate: type %s already defined", typeName);
336         }
337
338         /* ----------------
339          *      if this type has an associated elementType, then we check that
340          *      it is defined.
341          * ----------------
342          */
343         if (elementTypeName)
344         {
345                 elementObjectId = TypeGet(elementTypeName, &defined);
346                 if (!defined)
347                 {
348                         elog(WARN, "TypeCreate: type %s is not defined", elementTypeName);
349                 }
350         }
351
352         /* ----------------
353          *      XXX comment me
354          * ----------------
355          */
356         if (externalSize == 0)
357         {
358                 externalSize = -1;              /* variable length */
359         }
360
361         /* ----------------
362          *      initialize arrays needed by FormHeapTuple
363          * ----------------
364          */
365         for (i = 0; i < Natts_pg_type; ++i)
366         {
367                 nulls[i] = ' ';
368                 replaces[i] = 'r';
369                 values[i] = (Datum) NULL;               /* redundant, but nice */
370         }
371
372         /*
373          * XXX
374          *
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
377          * backend works.
378          */
379
380         if (internalSize == 0)
381                 internalSize = -1;
382
383         /* ----------------
384          *      initialize the values[] information
385          * ----------------
386          */
387         i = 0;
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 */
398
399         /*
400          * arguments to type input and output functions must be 0
401          */
402         memset(argList, 0, 8 * sizeof(Oid));
403
404         procs[0] = inputProcedure;
405         procs[1] = outputProcedure;
406         procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure;
407         procs[3] = (sendProcedure) ? sendProcedure : outputProcedure;
408
409         for (j = 0; j < 4; ++j)
410         {
411                 procname = procs[j];
412
413                 tup = SearchSysCacheTuple(PRONAME,
414                                                                   PointerGetDatum(procname),
415                                                                   Int32GetDatum(1),
416                                                                   PointerGetDatum(argList),
417                                                                   0);
418
419                 if (!HeapTupleIsValid(tup))
420                 {
421
422                         /*
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)
426                          */
427                         if (OidIsValid(elementObjectId))
428                         {
429                                 tup = SearchSysCacheTuple(PRONAME,
430                                                                                   PointerGetDatum(procname),
431                                                                                   Int32GetDatum(2),
432                                                                                   PointerGetDatum(argList),
433                                                                                   0);
434                         }
435                         if (!HeapTupleIsValid(tup))
436                         {
437                                 func_error("TypeCreate", procname, 1, argList);
438                         }
439                 }
440
441                 values[i++] = (Datum) tup->t_oid;               /* 11 - 14 */
442         }
443
444         /* ----------------
445          * set default alignment
446          * ----------------
447          */
448         values[i++] = (Datum) alignment;        /* 15 */
449
450         /* ----------------
451          *      initialize the default value for this type.
452          * ----------------
453          */
454         values[i] = (Datum) fmgr(TextInRegProcedure,            /* 16 */
455                                                          PointerIsValid(defaultTypeValue)
456                                                          ? defaultTypeValue : "-"); /* XXX default
457                                                                                                                  * typdefault */
458
459         /* ----------------
460          *      open pg_type and begin a scan for the type name.
461          * ----------------
462          */
463         pg_type_desc = heap_openr(TypeRelationName);
464
465         /* -----------------
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.
468          * -----------------
469          */
470         RelationSetLockForWrite(pg_type_desc);
471
472         typeKey[0].sk_argument = PointerGetDatum(typeName);
473         pg_type_scan = heap_beginscan(pg_type_desc,
474                                                                   0,
475                                                                   SelfTimeQual,
476                                                                   1,
477                                                                   typeKey);
478
479         /* ----------------
480          *      define the type either by adding a tuple to the type
481          *      relation, or by updating the fields of the "shell" tuple
482          *      already there.
483          * ----------------
484          */
485         tup = heap_getnext(pg_type_scan, 0, &buffer);
486         if (HeapTupleIsValid(tup))
487         {
488                 tup = heap_modifytuple(tup,
489                                                            buffer,
490                                                            pg_type_desc,
491                                                            values,
492                                                            nulls,
493                                                            replaces);
494
495                 /* XXX may not be necessary */
496                 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
497
498                 setheapoverride(true);
499                 heap_replace(pg_type_desc, &itemPointerData, tup);
500                 setheapoverride(false);
501
502                 typeObjectId = tup->t_oid;
503         }
504         else
505         {
506                 tupDesc = pg_type_desc->rd_att;
507
508                 tup = heap_formtuple(tupDesc,
509                                                          values,
510                                                          nulls);
511
512                 heap_insert(pg_type_desc, tup);
513
514                 typeObjectId = tup->t_oid;
515         }
516
517         /* ----------------
518          *      finish up
519          * ----------------
520          */
521         heap_endscan(pg_type_scan);
522
523         if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
524         {
525                 Relation        idescs[Num_pg_type_indices];
526
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);
530         }
531         RelationUnsetLockForWrite(pg_type_desc);
532         heap_close(pg_type_desc);
533
534
535         return
536                 typeObjectId;
537 }
538
539 /* ----------------------------------------------------------------
540  *              TypeRename
541  *
542  *              This renames a type
543  * ----------------------------------------------------------------
544  */
545 void
546 TypeRename(char *oldTypeName, char *newTypeName)
547 {
548         Relation        pg_type_desc;
549         Relation        idescs[Num_pg_type_indices];
550         Oid                     type_oid;
551         HeapTuple       tup;
552         bool            defined;
553         ItemPointerData itemPointerData;
554
555         /* check that that the new type is not already defined */
556         type_oid = TypeGet(newTypeName, &defined);
557         if (OidIsValid(type_oid) && defined)
558         {
559                 elog(WARN, "TypeRename: type %s already defined", newTypeName);
560         }
561
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);
565
566         /* ----------------
567          *      change the name of the type
568          * ----------------
569          */
570         if (HeapTupleIsValid(tup))
571         {
572
573                 namestrcpy(&(((TypeTupleForm) GETSTRUCT(tup))->typname), newTypeName);
574
575                 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
576
577                 setheapoverride(true);
578                 heap_replace(pg_type_desc, &itemPointerData, tup);
579                 setheapoverride(false);
580
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);
585
586                 /* all done */
587                 pfree(tup);
588
589         }
590         else
591         {
592                 elog(WARN, "TypeRename: type %s not defined", oldTypeName);
593         }
594
595         /* finish up */
596         heap_close(pg_type_desc);
597 }
598
599 /*
600  * makeArrayTypeName(typeName);
601  *        - given a base type name, make an array of type name out of it
602  *
603  * the CALLER is responsible for pfreeing the
604  */
605
606 char       *
607 makeArrayTypeName(char *typeName)
608 {
609         char       *arr;
610
611         if (!typeName)
612                 return NULL;
613         arr = palloc(strlen(typeName) + 2);
614         arr[0] = '_';
615         strcpy(arr + 1, typeName);
616
617         return arr;
618
619 }