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