~ubuntu-branches/ubuntu/precise/postgresql-9.1/precise-security

« back to all changes in this revision

Viewing changes to src/backend/catalog/pg_type.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * pg_type.c
 
4
 *        routines to support manipulation of the pg_type relation
 
5
 *
 
6
 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        src/backend/catalog/pg_type.c
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
#include "postgres.h"
 
16
 
 
17
#include "access/heapam.h"
 
18
#include "access/xact.h"
 
19
#include "catalog/dependency.h"
 
20
#include "catalog/indexing.h"
 
21
#include "catalog/objectaccess.h"
 
22
#include "catalog/pg_collation.h"
 
23
#include "catalog/pg_namespace.h"
 
24
#include "catalog/pg_proc.h"
 
25
#include "catalog/pg_type.h"
 
26
#include "catalog/pg_type_fn.h"
 
27
#include "commands/typecmds.h"
 
28
#include "miscadmin.h"
 
29
#include "parser/scansup.h"
 
30
#include "utils/acl.h"
 
31
#include "utils/builtins.h"
 
32
#include "utils/fmgroids.h"
 
33
#include "utils/lsyscache.h"
 
34
#include "utils/rel.h"
 
35
#include "utils/syscache.h"
 
36
 
 
37
/* Potentially set by contrib/pg_upgrade_support functions */
 
38
Oid                     binary_upgrade_next_pg_type_oid = InvalidOid;
 
39
 
 
40
/* ----------------------------------------------------------------
 
41
 *              TypeShellMake
 
42
 *
 
43
 *              This procedure inserts a "shell" tuple into the pg_type relation.
 
44
 *              The type tuple inserted has valid but dummy values, and its
 
45
 *              "typisdefined" field is false indicating it's not really defined.
 
46
 *
 
47
 *              This is used so that a tuple exists in the catalogs.  The I/O
 
48
 *              functions for the type will link to this tuple.  When the full
 
49
 *              CREATE TYPE command is issued, the bogus values will be replaced
 
50
 *              with correct ones, and "typisdefined" will be set to true.
 
51
 * ----------------------------------------------------------------
 
52
 */
 
53
Oid
 
54
TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
 
55
{
 
56
        Relation        pg_type_desc;
 
57
        TupleDesc       tupDesc;
 
58
        int                     i;
 
59
        HeapTuple       tup;
 
60
        Datum           values[Natts_pg_type];
 
61
        bool            nulls[Natts_pg_type];
 
62
        Oid                     typoid;
 
63
        NameData        name;
 
64
 
 
65
        Assert(PointerIsValid(typeName));
 
66
 
 
67
        /*
 
68
         * open pg_type
 
69
         */
 
70
        pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
 
71
        tupDesc = pg_type_desc->rd_att;
 
72
 
 
73
        /*
 
74
         * initialize our *nulls and *values arrays
 
75
         */
 
76
        for (i = 0; i < Natts_pg_type; ++i)
 
77
        {
 
78
                nulls[i] = false;
 
79
                values[i] = (Datum) NULL;               /* redundant, but safe */
 
80
        }
 
81
 
 
82
        /*
 
83
         * initialize *values with the type name and dummy values
 
84
         *
 
85
         * The representational details are the same as int4 ... it doesn't really
 
86
         * matter what they are so long as they are consistent.  Also note that we
 
87
         * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
 
88
         * mistaken for a usable type.
 
89
         */
 
90
        i = 0;
 
91
        namestrcpy(&name, typeName);
 
92
        values[i++] = NameGetDatum(&name);      /* typname */
 
93
        values[i++] = ObjectIdGetDatum(typeNamespace);          /* typnamespace */
 
94
        values[i++] = ObjectIdGetDatum(ownerId);        /* typowner */
 
95
        values[i++] = Int16GetDatum(sizeof(int4));      /* typlen */
 
96
        values[i++] = BoolGetDatum(true);       /* typbyval */
 
97
        values[i++] = CharGetDatum(TYPTYPE_PSEUDO); /* typtype */
 
98
        values[i++] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE); /* typcategory */
 
99
        values[i++] = BoolGetDatum(false);      /* typispreferred */
 
100
        values[i++] = BoolGetDatum(false);      /* typisdefined */
 
101
        values[i++] = CharGetDatum(DEFAULT_TYPDELIM);           /* typdelim */
 
102
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
 
103
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */
 
104
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typarray */
 
105
        values[i++] = ObjectIdGetDatum(F_SHELL_IN); /* typinput */
 
106
        values[i++] = ObjectIdGetDatum(F_SHELL_OUT);            /* typoutput */
 
107
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */
 
108
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typsend */
 
109
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typmodin */
 
110
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typmodout */
 
111
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typanalyze */
 
112
        values[i++] = CharGetDatum('i');        /* typalign */
 
113
        values[i++] = CharGetDatum('p');        /* typstorage */
 
114
        values[i++] = BoolGetDatum(false);      /* typnotnull */
 
115
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typbasetype */
 
116
        values[i++] = Int32GetDatum(-1);        /* typtypmod */
 
117
        values[i++] = Int32GetDatum(0);         /* typndims */
 
118
        values[i++] = ObjectIdGetDatum(InvalidOid); /* typcollation */
 
119
        nulls[i++] = true;                      /* typdefaultbin */
 
120
        nulls[i++] = true;                      /* typdefault */
 
121
 
 
122
        /*
 
123
         * create a new type tuple
 
124
         */
 
125
        tup = heap_form_tuple(tupDesc, values, nulls);
 
126
 
 
127
        /* Use binary-upgrade override for pg_type.oid, if supplied. */
 
128
        if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_pg_type_oid))
 
129
        {
 
130
                HeapTupleSetOid(tup, binary_upgrade_next_pg_type_oid);
 
131
                binary_upgrade_next_pg_type_oid = InvalidOid;
 
132
        }
 
133
 
 
134
        /*
 
135
         * insert the tuple in the relation and get the tuple's oid.
 
136
         */
 
137
        typoid = simple_heap_insert(pg_type_desc, tup);
 
138
 
 
139
        CatalogUpdateIndexes(pg_type_desc, tup);
 
140
 
 
141
        /*
 
142
         * Create dependencies.  We can/must skip this in bootstrap mode.
 
143
         */
 
144
        if (!IsBootstrapProcessingMode())
 
145
                GenerateTypeDependencies(typeNamespace,
 
146
                                                                 typoid,
 
147
                                                                 InvalidOid,
 
148
                                                                 0,
 
149
                                                                 ownerId,
 
150
                                                                 F_SHELL_IN,
 
151
                                                                 F_SHELL_OUT,
 
152
                                                                 InvalidOid,
 
153
                                                                 InvalidOid,
 
154
                                                                 InvalidOid,
 
155
                                                                 InvalidOid,
 
156
                                                                 InvalidOid,
 
157
                                                                 InvalidOid,
 
158
                                                                 false,
 
159
                                                                 InvalidOid,
 
160
                                                                 InvalidOid,
 
161
                                                                 NULL,
 
162
                                                                 false);
 
163
 
 
164
        /* Post creation hook for new shell type */
 
165
        InvokeObjectAccessHook(OAT_POST_CREATE, TypeRelationId, typoid, 0);
 
166
 
 
167
        /*
 
168
         * clean up and return the type-oid
 
169
         */
 
170
        heap_freetuple(tup);
 
171
        heap_close(pg_type_desc, RowExclusiveLock);
 
172
 
 
173
        return typoid;
 
174
}
 
175
 
 
176
/* ----------------------------------------------------------------
 
177
 *              TypeCreate
 
178
 *
 
179
 *              This does all the necessary work needed to define a new type.
 
180
 *
 
181
 *              Returns the OID assigned to the new type.  If newTypeOid is
 
182
 *              zero (the normal case), a new OID is created; otherwise we
 
183
 *              use exactly that OID.
 
184
 * ----------------------------------------------------------------
 
185
 */
 
186
Oid
 
187
TypeCreate(Oid newTypeOid,
 
188
                   const char *typeName,
 
189
                   Oid typeNamespace,
 
190
                   Oid relationOid,             /* only for relation rowtypes */
 
191
                   char relationKind,   /* ditto */
 
192
                   Oid ownerId,
 
193
                   int16 internalSize,
 
194
                   char typeType,
 
195
                   char typeCategory,
 
196
                   bool typePreferred,
 
197
                   char typDelim,
 
198
                   Oid inputProcedure,
 
199
                   Oid outputProcedure,
 
200
                   Oid receiveProcedure,
 
201
                   Oid sendProcedure,
 
202
                   Oid typmodinProcedure,
 
203
                   Oid typmodoutProcedure,
 
204
                   Oid analyzeProcedure,
 
205
                   Oid elementType,
 
206
                   bool isImplicitArray,
 
207
                   Oid arrayType,
 
208
                   Oid baseType,
 
209
                   const char *defaultTypeValue,                /* human readable rep */
 
210
                   char *defaultTypeBin,        /* cooked rep */
 
211
                   bool passedByValue,
 
212
                   char alignment,
 
213
                   char storage,
 
214
                   int32 typeMod,
 
215
                   int32 typNDims,              /* Array dimensions for baseType */
 
216
                   bool typeNotNull,
 
217
                   Oid typeCollation)
 
218
{
 
219
        Relation        pg_type_desc;
 
220
        Oid                     typeObjectId;
 
221
        bool            rebuildDeps = false;
 
222
        HeapTuple       tup;
 
223
        bool            nulls[Natts_pg_type];
 
224
        bool            replaces[Natts_pg_type];
 
225
        Datum           values[Natts_pg_type];
 
226
        NameData        name;
 
227
        int                     i;
 
228
 
 
229
        /*
 
230
         * We assume that the caller validated the arguments individually, but did
 
231
         * not check for bad combinations.
 
232
         *
 
233
         * Validate size specifications: either positive (fixed-length) or -1
 
234
         * (varlena) or -2 (cstring).
 
235
         */
 
236
        if (!(internalSize > 0 ||
 
237
                  internalSize == -1 ||
 
238
                  internalSize == -2))
 
239
                ereport(ERROR,
 
240
                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 
241
                                 errmsg("invalid type internal size %d",
 
242
                                                internalSize)));
 
243
 
 
244
        if (passedByValue)
 
245
        {
 
246
                /*
 
247
                 * Pass-by-value types must have a fixed length that is one of the
 
248
                 * values supported by fetch_att() and store_att_byval(); and the
 
249
                 * alignment had better agree, too.  All this code must match
 
250
                 * access/tupmacs.h!
 
251
                 */
 
252
                if (internalSize == (int16) sizeof(char))
 
253
                {
 
254
                        if (alignment != 'c')
 
255
                                ereport(ERROR,
 
256
                                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 
257
                                                 errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
 
258
                                                                alignment, internalSize)));
 
259
                }
 
260
                else if (internalSize == (int16) sizeof(int16))
 
261
                {
 
262
                        if (alignment != 's')
 
263
                                ereport(ERROR,
 
264
                                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 
265
                                                 errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
 
266
                                                                alignment, internalSize)));
 
267
                }
 
268
                else if (internalSize == (int16) sizeof(int32))
 
269
                {
 
270
                        if (alignment != 'i')
 
271
                                ereport(ERROR,
 
272
                                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 
273
                                                 errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
 
274
                                                                alignment, internalSize)));
 
275
                }
 
276
#if SIZEOF_DATUM == 8
 
277
                else if (internalSize == (int16) sizeof(Datum))
 
278
                {
 
279
                        if (alignment != 'd')
 
280
                                ereport(ERROR,
 
281
                                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 
282
                                                 errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
 
283
                                                                alignment, internalSize)));
 
284
                }
 
285
#endif
 
286
                else
 
287
                        ereport(ERROR,
 
288
                                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 
289
                           errmsg("internal size %d is invalid for passed-by-value type",
 
290
                                          internalSize)));
 
291
        }
 
292
        else
 
293
        {
 
294
                /* varlena types must have int align or better */
 
295
                if (internalSize == -1 && !(alignment == 'i' || alignment == 'd'))
 
296
                        ereport(ERROR,
 
297
                                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 
298
                           errmsg("alignment \"%c\" is invalid for variable-length type",
 
299
                                          alignment)));
 
300
                /* cstring must have char alignment */
 
301
                if (internalSize == -2 && !(alignment == 'c'))
 
302
                        ereport(ERROR,
 
303
                                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 
304
                           errmsg("alignment \"%c\" is invalid for variable-length type",
 
305
                                          alignment)));
 
306
        }
 
307
 
 
308
        /* Only varlena types can be toasted */
 
309
        if (storage != 'p' && internalSize != -1)
 
310
                ereport(ERROR,
 
311
                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 
312
                                 errmsg("fixed-size types must have storage PLAIN")));
 
313
 
 
314
        /*
 
315
         * initialize arrays needed for heap_form_tuple or heap_modify_tuple
 
316
         */
 
317
        for (i = 0; i < Natts_pg_type; ++i)
 
318
        {
 
319
                nulls[i] = false;
 
320
                replaces[i] = true;
 
321
                values[i] = (Datum) 0;
 
322
        }
 
323
 
 
324
        /*
 
325
         * initialize the *values information
 
326
         */
 
327
        i = 0;
 
328
        namestrcpy(&name, typeName);
 
329
        values[i++] = NameGetDatum(&name);      /* typname */
 
330
        values[i++] = ObjectIdGetDatum(typeNamespace);          /* typnamespace */
 
331
        values[i++] = ObjectIdGetDatum(ownerId);        /* typowner */
 
332
        values[i++] = Int16GetDatum(internalSize);      /* typlen */
 
333
        values[i++] = BoolGetDatum(passedByValue);      /* typbyval */
 
334
        values[i++] = CharGetDatum(typeType);           /* typtype */
 
335
        values[i++] = CharGetDatum(typeCategory);       /* typcategory */
 
336
        values[i++] = BoolGetDatum(typePreferred);      /* typispreferred */
 
337
        values[i++] = BoolGetDatum(true);       /* typisdefined */
 
338
        values[i++] = CharGetDatum(typDelim);           /* typdelim */
 
339
        values[i++] = ObjectIdGetDatum(relationOid);            /* typrelid */
 
340
        values[i++] = ObjectIdGetDatum(elementType);            /* typelem */
 
341
        values[i++] = ObjectIdGetDatum(arrayType);      /* typarray */
 
342
        values[i++] = ObjectIdGetDatum(inputProcedure);         /* typinput */
 
343
        values[i++] = ObjectIdGetDatum(outputProcedure);        /* typoutput */
 
344
        values[i++] = ObjectIdGetDatum(receiveProcedure);       /* typreceive */
 
345
        values[i++] = ObjectIdGetDatum(sendProcedure);          /* typsend */
 
346
        values[i++] = ObjectIdGetDatum(typmodinProcedure);      /* typmodin */
 
347
        values[i++] = ObjectIdGetDatum(typmodoutProcedure); /* typmodout */
 
348
        values[i++] = ObjectIdGetDatum(analyzeProcedure);       /* typanalyze */
 
349
        values[i++] = CharGetDatum(alignment);          /* typalign */
 
350
        values[i++] = CharGetDatum(storage);            /* typstorage */
 
351
        values[i++] = BoolGetDatum(typeNotNull);        /* typnotnull */
 
352
        values[i++] = ObjectIdGetDatum(baseType);       /* typbasetype */
 
353
        values[i++] = Int32GetDatum(typeMod);           /* typtypmod */
 
354
        values[i++] = Int32GetDatum(typNDims);          /* typndims */
 
355
        values[i++] = ObjectIdGetDatum(typeCollation);          /* typcollation */
 
356
 
 
357
        /*
 
358
         * initialize the default binary value for this type.  Check for nulls of
 
359
         * course.
 
360
         */
 
361
        if (defaultTypeBin)
 
362
                values[i] = CStringGetTextDatum(defaultTypeBin);
 
363
        else
 
364
                nulls[i] = true;
 
365
        i++;                                            /* typdefaultbin */
 
366
 
 
367
        /*
 
368
         * initialize the default value for this type.
 
369
         */
 
370
        if (defaultTypeValue)
 
371
                values[i] = CStringGetTextDatum(defaultTypeValue);
 
372
        else
 
373
                nulls[i] = true;
 
374
        i++;                                            /* typdefault */
 
375
 
 
376
        /*
 
377
         * open pg_type and prepare to insert or update a row.
 
378
         *
 
379
         * NOTE: updating will not work correctly in bootstrap mode; but we don't
 
380
         * expect to be overwriting any shell types in bootstrap mode.
 
381
         */
 
382
        pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
 
383
 
 
384
        tup = SearchSysCacheCopy2(TYPENAMENSP,
 
385
                                                          CStringGetDatum(typeName),
 
386
                                                          ObjectIdGetDatum(typeNamespace));
 
387
        if (HeapTupleIsValid(tup))
 
388
        {
 
389
                /*
 
390
                 * check that the type is not already defined.  It may exist as a
 
391
                 * shell type, however.
 
392
                 */
 
393
                if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
 
394
                        ereport(ERROR,
 
395
                                        (errcode(ERRCODE_DUPLICATE_OBJECT),
 
396
                                         errmsg("type \"%s\" already exists", typeName)));
 
397
 
 
398
                /*
 
399
                 * shell type must have been created by same owner
 
400
                 */
 
401
                if (((Form_pg_type) GETSTRUCT(tup))->typowner != ownerId)
 
402
                        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName);
 
403
 
 
404
                /* trouble if caller wanted to force the OID */
 
405
                if (OidIsValid(newTypeOid))
 
406
                        elog(ERROR, "cannot assign new OID to existing shell type");
 
407
 
 
408
                /*
 
409
                 * Okay to update existing shell type tuple
 
410
                 */
 
411
                tup = heap_modify_tuple(tup,
 
412
                                                                RelationGetDescr(pg_type_desc),
 
413
                                                                values,
 
414
                                                                nulls,
 
415
                                                                replaces);
 
416
 
 
417
                simple_heap_update(pg_type_desc, &tup->t_self, tup);
 
418
 
 
419
                typeObjectId = HeapTupleGetOid(tup);
 
420
 
 
421
                rebuildDeps = true;             /* get rid of shell type's dependencies */
 
422
        }
 
423
        else
 
424
        {
 
425
                tup = heap_form_tuple(RelationGetDescr(pg_type_desc),
 
426
                                                          values,
 
427
                                                          nulls);
 
428
 
 
429
                /* Force the OID if requested by caller */
 
430
                if (OidIsValid(newTypeOid))
 
431
                        HeapTupleSetOid(tup, newTypeOid);
 
432
                /* Use binary-upgrade override for pg_type.oid, if supplied. */
 
433
                else if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_pg_type_oid))
 
434
                {
 
435
                        HeapTupleSetOid(tup, binary_upgrade_next_pg_type_oid);
 
436
                        binary_upgrade_next_pg_type_oid = InvalidOid;
 
437
                }
 
438
                /* else allow system to assign oid */
 
439
 
 
440
                typeObjectId = simple_heap_insert(pg_type_desc, tup);
 
441
        }
 
442
 
 
443
        /* Update indexes */
 
444
        CatalogUpdateIndexes(pg_type_desc, tup);
 
445
 
 
446
        /*
 
447
         * Create dependencies.  We can/must skip this in bootstrap mode.
 
448
         */
 
449
        if (!IsBootstrapProcessingMode())
 
450
                GenerateTypeDependencies(typeNamespace,
 
451
                                                                 typeObjectId,
 
452
                                                                 relationOid,
 
453
                                                                 relationKind,
 
454
                                                                 ownerId,
 
455
                                                                 inputProcedure,
 
456
                                                                 outputProcedure,
 
457
                                                                 receiveProcedure,
 
458
                                                                 sendProcedure,
 
459
                                                                 typmodinProcedure,
 
460
                                                                 typmodoutProcedure,
 
461
                                                                 analyzeProcedure,
 
462
                                                                 elementType,
 
463
                                                                 isImplicitArray,
 
464
                                                                 baseType,
 
465
                                                                 typeCollation,
 
466
                                                                 (defaultTypeBin ?
 
467
                                                                  stringToNode(defaultTypeBin) :
 
468
                                                                  NULL),
 
469
                                                                 rebuildDeps);
 
470
 
 
471
        /* Post creation hook for new type */
 
472
        InvokeObjectAccessHook(OAT_POST_CREATE, TypeRelationId, typeObjectId, 0);
 
473
 
 
474
        /*
 
475
         * finish up
 
476
         */
 
477
        heap_close(pg_type_desc, RowExclusiveLock);
 
478
 
 
479
        return typeObjectId;
 
480
}
 
481
 
 
482
/*
 
483
 * GenerateTypeDependencies: build the dependencies needed for a type
 
484
 *
 
485
 * If rebuild is true, we remove existing dependencies and rebuild them
 
486
 * from scratch.  This is needed for ALTER TYPE, and also when replacing
 
487
 * a shell type.  We don't remove/rebuild extension dependencies, though.
 
488
 */
 
489
void
 
490
GenerateTypeDependencies(Oid typeNamespace,
 
491
                                                 Oid typeObjectId,
 
492
                                                 Oid relationOid,               /* only for relation rowtypes */
 
493
                                                 char relationKind,             /* ditto */
 
494
                                                 Oid owner,
 
495
                                                 Oid inputProcedure,
 
496
                                                 Oid outputProcedure,
 
497
                                                 Oid receiveProcedure,
 
498
                                                 Oid sendProcedure,
 
499
                                                 Oid typmodinProcedure,
 
500
                                                 Oid typmodoutProcedure,
 
501
                                                 Oid analyzeProcedure,
 
502
                                                 Oid elementType,
 
503
                                                 bool isImplicitArray,
 
504
                                                 Oid baseType,
 
505
                                                 Oid typeCollation,
 
506
                                                 Node *defaultExpr,
 
507
                                                 bool rebuild)
 
508
{
 
509
        ObjectAddress myself,
 
510
                                referenced;
 
511
 
 
512
        if (rebuild)
 
513
        {
 
514
                deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true);
 
515
                deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
 
516
        }
 
517
 
 
518
        myself.classId = TypeRelationId;
 
519
        myself.objectId = typeObjectId;
 
520
        myself.objectSubId = 0;
 
521
 
 
522
        /*
 
523
         * Make dependency on namespace and shared dependency on owner.
 
524
         *
 
525
         * For a relation rowtype (that's not a composite type), we should skip
 
526
         * these because we'll depend on them indirectly through the pg_class
 
527
         * entry.  Likewise, skip for implicit arrays since we'll depend on them
 
528
         * through the element type.  The same goes for extension membership.
 
529
         */
 
530
        if ((!OidIsValid(relationOid) || relationKind == RELKIND_COMPOSITE_TYPE) &&
 
531
                !isImplicitArray)
 
532
        {
 
533
                referenced.classId = NamespaceRelationId;
 
534
                referenced.objectId = typeNamespace;
 
535
                referenced.objectSubId = 0;
 
536
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
537
 
 
538
                recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
 
539
 
 
540
                /* dependency on extension */
 
541
                if (!rebuild)
 
542
                        recordDependencyOnCurrentExtension(&myself);
 
543
        }
 
544
 
 
545
        /* Normal dependencies on the I/O functions */
 
546
        if (OidIsValid(inputProcedure))
 
547
        {
 
548
                referenced.classId = ProcedureRelationId;
 
549
                referenced.objectId = inputProcedure;
 
550
                referenced.objectSubId = 0;
 
551
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
552
        }
 
553
 
 
554
        if (OidIsValid(outputProcedure))
 
555
        {
 
556
                referenced.classId = ProcedureRelationId;
 
557
                referenced.objectId = outputProcedure;
 
558
                referenced.objectSubId = 0;
 
559
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
560
        }
 
561
 
 
562
        if (OidIsValid(receiveProcedure))
 
563
        {
 
564
                referenced.classId = ProcedureRelationId;
 
565
                referenced.objectId = receiveProcedure;
 
566
                referenced.objectSubId = 0;
 
567
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
568
        }
 
569
 
 
570
        if (OidIsValid(sendProcedure))
 
571
        {
 
572
                referenced.classId = ProcedureRelationId;
 
573
                referenced.objectId = sendProcedure;
 
574
                referenced.objectSubId = 0;
 
575
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
576
        }
 
577
 
 
578
        if (OidIsValid(typmodinProcedure))
 
579
        {
 
580
                referenced.classId = ProcedureRelationId;
 
581
                referenced.objectId = typmodinProcedure;
 
582
                referenced.objectSubId = 0;
 
583
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
584
        }
 
585
 
 
586
        if (OidIsValid(typmodoutProcedure))
 
587
        {
 
588
                referenced.classId = ProcedureRelationId;
 
589
                referenced.objectId = typmodoutProcedure;
 
590
                referenced.objectSubId = 0;
 
591
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
592
        }
 
593
 
 
594
        if (OidIsValid(analyzeProcedure))
 
595
        {
 
596
                referenced.classId = ProcedureRelationId;
 
597
                referenced.objectId = analyzeProcedure;
 
598
                referenced.objectSubId = 0;
 
599
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
600
        }
 
601
 
 
602
        /*
 
603
         * If the type is a rowtype for a relation, mark it as internally
 
604
         * dependent on the relation, *unless* it is a stand-alone composite type
 
605
         * relation. For the latter case, we have to reverse the dependency.
 
606
         *
 
607
         * In the former case, this allows the type to be auto-dropped when the
 
608
         * relation is, and not otherwise. And in the latter, of course we get the
 
609
         * opposite effect.
 
610
         */
 
611
        if (OidIsValid(relationOid))
 
612
        {
 
613
                referenced.classId = RelationRelationId;
 
614
                referenced.objectId = relationOid;
 
615
                referenced.objectSubId = 0;
 
616
 
 
617
                if (relationKind != RELKIND_COMPOSITE_TYPE)
 
618
                        recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
 
619
                else
 
620
                        recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
 
621
        }
 
622
 
 
623
        /*
 
624
         * If the type is an implicitly-created array type, mark it as internally
 
625
         * dependent on the element type.  Otherwise, if it has an element type,
 
626
         * the dependency is a normal one.
 
627
         */
 
628
        if (OidIsValid(elementType))
 
629
        {
 
630
                referenced.classId = TypeRelationId;
 
631
                referenced.objectId = elementType;
 
632
                referenced.objectSubId = 0;
 
633
                recordDependencyOn(&myself, &referenced,
 
634
                                  isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
 
635
        }
 
636
 
 
637
        /* Normal dependency from a domain to its base type. */
 
638
        if (OidIsValid(baseType))
 
639
        {
 
640
                referenced.classId = TypeRelationId;
 
641
                referenced.objectId = baseType;
 
642
                referenced.objectSubId = 0;
 
643
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
644
        }
 
645
 
 
646
        /* Normal dependency from a domain to its collation. */
 
647
        /* We know the default collation is pinned, so don't bother recording it */
 
648
        if (OidIsValid(typeCollation) && typeCollation != DEFAULT_COLLATION_OID)
 
649
        {
 
650
                referenced.classId = CollationRelationId;
 
651
                referenced.objectId = typeCollation;
 
652
                referenced.objectSubId = 0;
 
653
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
654
        }
 
655
 
 
656
        /* Normal dependency on the default expression. */
 
657
        if (defaultExpr)
 
658
                recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
 
659
}
 
660
 
 
661
/*
 
662
 * RenameTypeInternal
 
663
 *              This renames a type, as well as any associated array type.
 
664
 *
 
665
 * Caller must have already checked privileges.
 
666
 *
 
667
 * Currently this is used for renaming table rowtypes and for
 
668
 * ALTER TYPE RENAME TO command.
 
669
 */
 
670
void
 
671
RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
 
672
{
 
673
        Relation        pg_type_desc;
 
674
        HeapTuple       tuple;
 
675
        Form_pg_type typ;
 
676
        Oid                     arrayOid;
 
677
 
 
678
        pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
 
679
 
 
680
        tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
 
681
        if (!HeapTupleIsValid(tuple))
 
682
                elog(ERROR, "cache lookup failed for type %u", typeOid);
 
683
        typ = (Form_pg_type) GETSTRUCT(tuple);
 
684
 
 
685
        /* We are not supposed to be changing schemas here */
 
686
        Assert(typeNamespace == typ->typnamespace);
 
687
 
 
688
        arrayOid = typ->typarray;
 
689
 
 
690
        /* Just to give a more friendly error than unique-index violation */
 
691
        if (SearchSysCacheExists2(TYPENAMENSP,
 
692
                                                          CStringGetDatum(newTypeName),
 
693
                                                          ObjectIdGetDatum(typeNamespace)))
 
694
                ereport(ERROR,
 
695
                                (errcode(ERRCODE_DUPLICATE_OBJECT),
 
696
                                 errmsg("type \"%s\" already exists", newTypeName)));
 
697
 
 
698
        /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
 
699
        namestrcpy(&(typ->typname), newTypeName);
 
700
 
 
701
        simple_heap_update(pg_type_desc, &tuple->t_self, tuple);
 
702
 
 
703
        /* update the system catalog indexes */
 
704
        CatalogUpdateIndexes(pg_type_desc, tuple);
 
705
 
 
706
        heap_freetuple(tuple);
 
707
        heap_close(pg_type_desc, RowExclusiveLock);
 
708
 
 
709
        /* If the type has an array type, recurse to handle that */
 
710
        if (OidIsValid(arrayOid))
 
711
        {
 
712
                char       *arrname = makeArrayTypeName(newTypeName, typeNamespace);
 
713
 
 
714
                RenameTypeInternal(arrayOid, arrname, typeNamespace);
 
715
                pfree(arrname);
 
716
        }
 
717
}
 
718
 
 
719
 
 
720
/*
 
721
 * makeArrayTypeName
 
722
 *        - given a base type name, make an array type name for it
 
723
 *
 
724
 * the caller is responsible for pfreeing the result
 
725
 */
 
726
char *
 
727
makeArrayTypeName(const char *typeName, Oid typeNamespace)
 
728
{
 
729
        char       *arr = (char *) palloc(NAMEDATALEN);
 
730
        int                     namelen = strlen(typeName);
 
731
        Relation        pg_type_desc;
 
732
        int                     i;
 
733
 
 
734
        /*
 
735
         * The idea is to prepend underscores as needed until we make a name that
 
736
         * doesn't collide with anything...
 
737
         */
 
738
        pg_type_desc = heap_open(TypeRelationId, AccessShareLock);
 
739
 
 
740
        for (i = 1; i < NAMEDATALEN - 1; i++)
 
741
        {
 
742
                arr[i - 1] = '_';
 
743
                if (i + namelen < NAMEDATALEN)
 
744
                        strcpy(arr + i, typeName);
 
745
                else
 
746
                {
 
747
                        memcpy(arr + i, typeName, NAMEDATALEN - i);
 
748
                        truncate_identifier(arr, NAMEDATALEN, false);
 
749
                }
 
750
                if (!SearchSysCacheExists2(TYPENAMENSP,
 
751
                                                                   CStringGetDatum(arr),
 
752
                                                                   ObjectIdGetDatum(typeNamespace)))
 
753
                        break;
 
754
        }
 
755
 
 
756
        heap_close(pg_type_desc, AccessShareLock);
 
757
 
 
758
        if (i >= NAMEDATALEN - 1)
 
759
                ereport(ERROR,
 
760
                                (errcode(ERRCODE_DUPLICATE_OBJECT),
 
761
                                 errmsg("could not form array type name for type \"%s\"",
 
762
                                                typeName)));
 
763
 
 
764
        return arr;
 
765
}
 
766
 
 
767
 
 
768
/*
 
769
 * moveArrayTypeName
 
770
 *        - try to reassign an array type name that the user wants to use.
 
771
 *
 
772
 * The given type name has been discovered to already exist (with the given
 
773
 * OID).  If it is an autogenerated array type, change the array type's name
 
774
 * to not conflict.  This allows the user to create type "foo" followed by
 
775
 * type "_foo" without problems.  (Of course, there are race conditions if
 
776
 * two backends try to create similarly-named types concurrently, but the
 
777
 * worst that can happen is an unnecessary failure --- anything we do here
 
778
 * will be rolled back if the type creation fails due to conflicting names.)
 
779
 *
 
780
 * Note that this must be called *before* calling makeArrayTypeName to
 
781
 * determine the new type's own array type name; else the latter will
 
782
 * certainly pick the same name.
 
783
 *
 
784
 * Returns TRUE if successfully moved the type, FALSE if not.
 
785
 *
 
786
 * We also return TRUE if the given type is a shell type.  In this case
 
787
 * the type has not been renamed out of the way, but nonetheless it can
 
788
 * be expected that TypeCreate will succeed.  This behavior is convenient
 
789
 * for most callers --- those that need to distinguish the shell-type case
 
790
 * must do their own typisdefined test.
 
791
 */
 
792
bool
 
793
moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
 
794
{
 
795
        Oid                     elemOid;
 
796
        char       *newname;
 
797
 
 
798
        /* We need do nothing if it's a shell type. */
 
799
        if (!get_typisdefined(typeOid))
 
800
                return true;
 
801
 
 
802
        /* Can't change it if it's not an autogenerated array type. */
 
803
        elemOid = get_element_type(typeOid);
 
804
        if (!OidIsValid(elemOid) ||
 
805
                get_array_type(elemOid) != typeOid)
 
806
                return false;
 
807
 
 
808
        /*
 
809
         * OK, use makeArrayTypeName to pick an unused modification of the name.
 
810
         * Note that since makeArrayTypeName is an iterative process, this will
 
811
         * produce a name that it might have produced the first time, had the
 
812
         * conflicting type we are about to create already existed.
 
813
         */
 
814
        newname = makeArrayTypeName(typeName, typeNamespace);
 
815
 
 
816
        /* Apply the rename */
 
817
        RenameTypeInternal(typeOid, newname, typeNamespace);
 
818
 
 
819
        /*
 
820
         * We must bump the command counter so that any subsequent use of
 
821
         * makeArrayTypeName sees what we just did and doesn't pick the same name.
 
822
         */
 
823
        CommandCounterIncrement();
 
824
 
 
825
        pfree(newname);
 
826
 
 
827
        return true;
 
828
}