]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_type.c
Change parameters to func_error().
[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.24 1998/05/09 23:43:00 thomas 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/lmgr.h"
25 #include "utils/builtins.h"
26 #include "utils/syscache.h"
27 #include "utils/tqual.h"
28
29 #ifndef HAVE_MEMMOVE
30 #include <regex/utils.h>
31 #else
32 #include <string.h>
33 #endif
34
35 static Oid
36 TypeShellMakeWithOpenRelation(Relation pg_type_desc,
37                                                           char *typeName);
38
39 /* ----------------------------------------------------------------
40  *              TypeGetWithOpenRelation
41  *
42  *              preforms a scan on pg_type for a type tuple with the
43  *              given type name.
44  * ----------------------------------------------------------------
45  *              pg_type_desc                     -- reldesc for pg_type
46  *              typeName                                 -- name of type to be fetched
47  *              defined                                  -- has the type been defined?
48  */
49 static Oid
50 TypeGetWithOpenRelation(Relation pg_type_desc,
51                                                 char *typeName,
52                                                 bool *defined)
53 {
54         HeapScanDesc scan;
55         HeapTuple       tup;
56
57         static ScanKeyData typeKey[1] = {
58                 {0, Anum_pg_type_typname, F_NAMEEQ}
59         };
60
61         /* ----------------
62          *      initialize the scan key and begin a scan of pg_type
63          * ----------------
64          */
65         fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
66         typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
67         typeKey[0].sk_argument = PointerGetDatum(typeName);
68
69         scan = heap_beginscan(pg_type_desc,
70                                                   0,
71                                                   true,
72                                                   1,
73                                                   typeKey);
74
75         /* ----------------
76          *      get the type tuple, if it exists.
77          * ----------------
78          */
79         tup = heap_getnext(scan, 0, (Buffer *) 0);
80
81         /* ----------------
82          *      if no type tuple exists for the given type name, then
83          *      end the scan and return appropriate information.
84          * ----------------
85          */
86         if (!HeapTupleIsValid(tup))
87         {
88                 heap_endscan(scan);
89                 *defined = false;
90                 return InvalidOid;
91         }
92
93         /* ----------------
94          *      here, the type tuple does exist so we pull information from
95          *      the typisdefined field of the tuple and return the tuple's
96          *      oid, which is the oid of the type.
97          * ----------------
98          */
99         heap_endscan(scan);
100         *defined = (bool) ((TypeTupleForm) GETSTRUCT(tup))->typisdefined;
101
102         return
103                 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
147                 typeoid;
148 }
149
150 /* ----------------------------------------------------------------
151  *              TypeShellMakeWithOpenRelation
152  *
153  * ----------------------------------------------------------------
154  */
155 static Oid
156 TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
157 {
158         int                     i;
159         HeapTuple       tup;
160         Datum           values[Natts_pg_type];
161         char            nulls[Natts_pg_type];
162         Oid                     typoid;
163         NameData        name;
164         TupleDesc       tupDesc;
165
166         /* ----------------
167          *      initialize our nulls[] and values[] arrays
168          * ----------------
169          */
170         for (i = 0; i < Natts_pg_type; ++i)
171         {
172                 nulls[i] = ' ';
173                 values[i] = (Datum) NULL;               /* redundant, but safe */
174         }
175
176         /* ----------------
177          *      initialize values[] with the type name and
178          * ----------------
179          */
180         i = 0;
181         namestrcpy(&name, typeName);
182         values[i++] = NameGetDatum(&name);              /* 1 */
183         values[i++] = (Datum) InvalidOid;       /* 2 */
184         values[i++] = (Datum) (int16) 0;        /* 3 */
185         values[i++] = (Datum) (int16) 0;        /* 4 */
186         values[i++] = (Datum) (bool) 0;         /* 5 */
187         values[i++] = (Datum) (bool) 0;         /* 6 */
188         values[i++] = (Datum) (bool) 0;         /* 7 */
189         values[i++] = (Datum) (bool) 0;         /* 8 */
190         values[i++] = (Datum) InvalidOid;       /* 9 */
191         values[i++] = (Datum) InvalidOid;       /* 10 */
192         values[i++] = (Datum) InvalidOid;       /* 11 */
193         values[i++] = (Datum) InvalidOid;       /* 12 */
194         values[i++] = (Datum) InvalidOid;       /* 13 */
195         values[i++] = (Datum) InvalidOid;       /* 14 */
196         values[i++] = (Datum) 'i';      /* 15 */
197
198         /*
199          * ... and fill typdefault with a bogus value
200          */
201         values[i++] =
202                 (Datum) fmgr(F_TEXTIN, typeName);               /* 15 */
203
204         /* ----------------
205          *      create a new type tuple with FormHeapTuple
206          * ----------------
207          */
208         tupDesc = pg_type_desc->rd_att;
209
210         tup = heap_formtuple(tupDesc, values, nulls);
211
212         /* ----------------
213          *      insert the tuple in the relation and get the tuple's oid.
214          * ----------------
215          */
216         heap_insert(pg_type_desc, tup);
217         typoid = tup->t_oid;
218
219         if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
220         {
221                 Relation        idescs[Num_pg_type_indices];
222
223                 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
224                 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
225                 CatalogCloseIndices(Num_pg_type_indices, idescs);
226         }
227         /* ----------------
228          *      free the tuple and return the type-oid
229          * ----------------
230          */
231         pfree(tup);
232
233         return
234                 typoid;
235 }
236
237 /* ----------------------------------------------------------------
238  *              TypeShellMake
239  *
240  *              This procedure inserts a "shell" tuple into the type
241  *              relation.  The type tuple inserted has invalid values
242  *              and in particular, the "typisdefined" field is false.
243  *
244  *              This is used so that a tuple exists in the catalogs.
245  *              The invalid fields should be fixed up sometime after
246  *              this routine is called, and then the "typeisdefined"
247  *              field is set to true. -cim 6/15/90
248  * ----------------------------------------------------------------
249  */
250 Oid
251 TypeShellMake(char *typeName)
252 {
253         Relation        pg_type_desc;
254         Oid                     typoid;
255
256         Assert(PointerIsValid(typeName));
257
258         /* ----------------
259          *      open pg_type
260          * ----------------
261          */
262         pg_type_desc = heap_openr(TypeRelationName);
263
264         /* ----------------
265          *      insert the shell tuple
266          * ----------------
267          */
268         typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
269
270         /* ----------------
271          *      close pg_type and return the tuple's oid.
272          * ----------------
273          */
274         heap_close(pg_type_desc);
275
276         return
277                 typoid;
278 }
279
280 /* ----------------------------------------------------------------
281  *              TypeCreate
282  *
283  *              This does all the necessary work needed to define a new type.
284  * ----------------------------------------------------------------
285  */
286 Oid
287 TypeCreate(char *typeName,
288                    Oid relationOid,             /* only for 'c'atalog typeTypes */
289                    int16 internalSize,
290                    int16 externalSize,
291                    char typeType,
292                    char typDelim,
293                    char *inputProcedure,
294                    char *outputProcedure,
295                    char *receiveProcedure,
296                    char *sendProcedure,
297                    char *elementTypeName,
298                    char *defaultTypeValue,              /* internal rep */
299                    bool passedByValue,
300                    char alignment)
301 {
302         int                     i,
303                                 j;
304         Relation        pg_type_desc;
305         HeapScanDesc pg_type_scan;
306
307         Oid                     typeObjectId;
308         Oid                     elementObjectId = InvalidOid;
309
310         HeapTuple       tup;
311         char            nulls[Natts_pg_type];
312         char            replaces[Natts_pg_type];
313         Datum           values[Natts_pg_type];
314
315         Buffer          buffer;
316         char       *procname;
317         char       *procs[4];
318         bool            defined;
319         ItemPointerData itemPointerData;
320         NameData        name;
321         TupleDesc       tupDesc;
322         Oid                     argList[8];
323
324         static ScanKeyData typeKey[1] = {
325                 {0, Anum_pg_type_typname, F_NAMEEQ}
326         };
327
328         fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
329         typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
330
331         /* ----------------
332          *      check that the type is not already defined.
333          * ----------------
334          */
335         typeObjectId = TypeGet(typeName, &defined);
336         if (OidIsValid(typeObjectId) && defined)
337         {
338                 elog(ERROR, "TypeCreate: type %s already defined", typeName);
339         }
340
341         /* ----------------
342          *      if this type has an associated elementType, then we check that
343          *      it is defined.
344          * ----------------
345          */
346         if (elementTypeName)
347         {
348                 elementObjectId = TypeGet(elementTypeName, &defined);
349                 if (!defined)
350                 {
351                         elog(ERROR, "TypeCreate: type %s is not defined", elementTypeName);
352                 }
353         }
354
355         /* ----------------
356          *      XXX comment me
357          * ----------------
358          */
359         if (externalSize == 0)
360         {
361                 externalSize = -1;              /* variable length */
362         }
363
364         /* ----------------
365          *      initialize arrays needed by FormHeapTuple
366          * ----------------
367          */
368         for (i = 0; i < Natts_pg_type; ++i)
369         {
370                 nulls[i] = ' ';
371                 replaces[i] = 'r';
372                 values[i] = (Datum) NULL;               /* redundant, but nice */
373         }
374
375         /*
376          * XXX
377          *
378          * Do this so that user-defined types have size -1 instead of zero if
379          * they are variable-length - this is so that everything else in the
380          * backend works.
381          */
382
383         if (internalSize == 0)
384                 internalSize = -1;
385
386         /* ----------------
387          *      initialize the values[] information
388          * ----------------
389          */
390         i = 0;
391         namestrcpy(&name,typeName);
392         values[i++] = NameGetDatum(&name);      /* 1 */
393         values[i++] = (Datum) GetUserId();      /* 2 */
394         values[i++] = (Datum) internalSize; /* 3 */
395         values[i++] = (Datum) externalSize; /* 4 */
396         values[i++] = (Datum) passedByValue;            /* 5 */
397         values[i++] = (Datum) typeType;         /* 6 */
398         values[i++] = (Datum) (bool) 1;         /* 7 */
399         values[i++] = (Datum) typDelim;         /* 8 */
400         values[i++] = (Datum) (typeType == 'c' ? relationOid : InvalidOid); /* 9 */
401         values[i++] = (Datum) elementObjectId;          /* 10 */
402
403         /*
404          * arguments to type input and output functions must be 0
405          */
406         MemSet(argList, 0, 8 * sizeof(Oid));
407
408         procs[0] = inputProcedure;
409         procs[1] = outputProcedure;
410         procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure;
411         procs[3] = (sendProcedure) ? sendProcedure : outputProcedure;
412
413         for (j = 0; j < 4; ++j)
414         {
415                 procname = procs[j];
416
417                 tup = SearchSysCacheTuple(PRONAME,
418                                                                   PointerGetDatum(procname),
419                                                                   Int32GetDatum(1),
420                                                                   PointerGetDatum(argList),
421                                                                   0);
422
423                 if (!HeapTupleIsValid(tup))
424                 {
425
426                         /*
427                          * it is possible for the input/output procedure to take two
428                          * arguments, where the second argument is the element type
429                          * (eg array_in/array_out)
430                          */
431                         if (OidIsValid(elementObjectId))
432                         {
433                                 tup = SearchSysCacheTuple(PRONAME,
434                                                                                   PointerGetDatum(procname),
435                                                                                   Int32GetDatum(2),
436                                                                                   PointerGetDatum(argList),
437                                                                                   0);
438                         }
439                         if (!HeapTupleIsValid(tup))
440                         {
441                                 func_error("TypeCreate", procname, 1, argList, NULL);
442                         }
443                 }
444
445                 values[i++] = (Datum) tup->t_oid;               /* 11 - 14 */
446         }
447
448         /* ----------------
449          * set default alignment
450          * ----------------
451          */
452         values[i++] = (Datum) alignment;        /* 15 */
453
454         /* ----------------
455          *      initialize the default value for this type.
456          * ----------------
457          */
458         values[i] = (Datum) fmgr(F_TEXTIN,              /* 16 */
459                                                          PointerIsValid(defaultTypeValue)
460                                                          ? defaultTypeValue : "-"); /* XXX default
461                                                                                                                  * typdefault */
462
463         /* ----------------
464          *      open pg_type and begin a scan for the type name.
465          * ----------------
466          */
467         pg_type_desc = heap_openr(TypeRelationName);
468
469         /* -----------------
470          * Set a write lock initially so as not upgrade a read to a write
471          * when the heap_insert() or heap_replace() is called.
472          * -----------------
473          */
474         RelationSetLockForWrite(pg_type_desc);
475
476         typeKey[0].sk_argument = PointerGetDatum(typeName);
477         pg_type_scan = heap_beginscan(pg_type_desc,
478                                                                   0,
479                                                                   true,
480                                                                   1,
481                                                                   typeKey);
482
483         /* ----------------
484          *      define the type either by adding a tuple to the type
485          *      relation, or by updating the fields of the "shell" tuple
486          *      already there.
487          * ----------------
488          */
489         tup = heap_getnext(pg_type_scan, 0, &buffer);
490         if (HeapTupleIsValid(tup))
491         {
492                 tup = heap_modifytuple(tup,
493                                                            buffer,
494                                                            pg_type_desc,
495                                                            values,
496                                                            nulls,
497                                                            replaces);
498
499                 /* XXX may not be necessary */
500                 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
501
502                 setheapoverride(true);
503                 heap_replace(pg_type_desc, &itemPointerData, tup);
504                 setheapoverride(false);
505
506                 typeObjectId = tup->t_oid;
507         }
508         else
509         {
510                 tupDesc = pg_type_desc->rd_att;
511
512                 tup = heap_formtuple(tupDesc,
513                                                          values,
514                                                          nulls);
515
516                 heap_insert(pg_type_desc, tup);
517
518                 typeObjectId = tup->t_oid;
519         }
520
521         /* ----------------
522          *      finish up
523          * ----------------
524          */
525         heap_endscan(pg_type_scan);
526
527         if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
528         {
529                 Relation        idescs[Num_pg_type_indices];
530
531                 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
532                 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
533                 CatalogCloseIndices(Num_pg_type_indices, idescs);
534         }
535         RelationUnsetLockForWrite(pg_type_desc);
536         heap_close(pg_type_desc);
537
538
539         return
540                 typeObjectId;
541 }
542
543 /* ----------------------------------------------------------------
544  *              TypeRename
545  *
546  *              This renames a type
547  * ----------------------------------------------------------------
548  */
549 void
550 TypeRename(char *oldTypeName, char *newTypeName)
551 {
552         Relation        pg_type_desc;
553         Relation        idescs[Num_pg_type_indices];
554         Oid                     type_oid;
555         HeapTuple       tup;
556         bool            defined;
557         ItemPointerData itemPointerData;
558
559         /* check that that the new type is not already defined */
560         type_oid = TypeGet(newTypeName, &defined);
561         if (OidIsValid(type_oid) && defined)
562         {
563                 elog(ERROR, "TypeRename: type %s already defined", newTypeName);
564         }
565
566         /* get the type tuple from the catalog index scan manager */
567         pg_type_desc = heap_openr(TypeRelationName);
568         tup = TypeNameIndexScan(pg_type_desc, oldTypeName);
569
570         /* ----------------
571          *      change the name of the type
572          * ----------------
573          */
574         if (HeapTupleIsValid(tup))
575         {
576
577                 namestrcpy(&(((TypeTupleForm) GETSTRUCT(tup))->typname), newTypeName);
578
579                 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
580
581                 setheapoverride(true);
582                 heap_replace(pg_type_desc, &itemPointerData, tup);
583                 setheapoverride(false);
584
585                 /* update the system catalog indices */
586                 CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
587                 CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
588                 CatalogCloseIndices(Num_pg_type_indices, idescs);
589
590                 /* all done */
591                 pfree(tup);
592
593         }
594         else
595         {
596                 elog(ERROR, "TypeRename: type %s not defined", oldTypeName);
597         }
598
599         /* finish up */
600         heap_close(pg_type_desc);
601 }
602
603 /*
604  * makeArrayTypeName(typeName);
605  *        - given a base type name, make an array of type name out of it
606  *
607  * the CALLER is responsible for pfreeing the
608  */
609
610 char *
611 makeArrayTypeName(char *typeName)
612 {
613         char       *arr;
614
615         if (!typeName)
616                 return NULL;
617         arr = palloc(strlen(typeName) + 2);
618         arr[0] = '_';
619         strcpy(arr + 1, typeName);
620
621         return arr;
622
623 }