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