Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_type.c
4 : * routines to support manipulation of the pg_type relation
5 : *
6 : * Portions Copyright (c) 1996-2024, 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/htup_details.h"
18 : #include "access/table.h"
19 : #include "access/xact.h"
20 : #include "catalog/binary_upgrade.h"
21 : #include "catalog/catalog.h"
22 : #include "catalog/dependency.h"
23 : #include "catalog/indexing.h"
24 : #include "catalog/objectaccess.h"
25 : #include "catalog/pg_collation.h"
26 : #include "catalog/pg_namespace.h"
27 : #include "catalog/pg_proc.h"
28 : #include "catalog/pg_type.h"
29 : #include "commands/defrem.h"
30 : #include "commands/typecmds.h"
31 : #include "mb/pg_wchar.h"
32 : #include "miscadmin.h"
33 : #include "utils/acl.h"
34 : #include "utils/builtins.h"
35 : #include "utils/fmgroids.h"
36 : #include "utils/lsyscache.h"
37 : #include "utils/rel.h"
38 : #include "utils/syscache.h"
39 :
40 : /* Potentially set by pg_upgrade_support functions */
41 : Oid binary_upgrade_next_pg_type_oid = InvalidOid;
42 :
43 : /* ----------------------------------------------------------------
44 : * TypeShellMake
45 : *
46 : * This procedure inserts a "shell" tuple into the pg_type relation.
47 : * The type tuple inserted has valid but dummy values, and its
48 : * "typisdefined" field is false indicating it's not really defined.
49 : *
50 : * This is used so that a tuple exists in the catalogs. The I/O
51 : * functions for the type will link to this tuple. When the full
52 : * CREATE TYPE command is issued, the bogus values will be replaced
53 : * with correct ones, and "typisdefined" will be set to true.
54 : * ----------------------------------------------------------------
55 : */
56 : ObjectAddress
57 216 : TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
58 : {
59 : Relation pg_type_desc;
60 : TupleDesc tupDesc;
61 : int i;
62 : HeapTuple tup;
63 : Datum values[Natts_pg_type];
64 : bool nulls[Natts_pg_type];
65 : Oid typoid;
66 : NameData name;
67 : ObjectAddress address;
68 :
69 : Assert(PointerIsValid(typeName));
70 :
71 : /*
72 : * open pg_type
73 : */
74 216 : pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
75 216 : tupDesc = pg_type_desc->rd_att;
76 :
77 : /*
78 : * initialize our *nulls and *values arrays
79 : */
80 7128 : for (i = 0; i < Natts_pg_type; ++i)
81 : {
82 6912 : nulls[i] = false;
83 6912 : values[i] = (Datum) NULL; /* redundant, but safe */
84 : }
85 :
86 : /*
87 : * initialize *values with the type name and dummy values
88 : *
89 : * The representational details are the same as int4 ... it doesn't really
90 : * matter what they are so long as they are consistent. Also note that we
91 : * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
92 : * mistaken for a usable type.
93 : */
94 216 : namestrcpy(&name, typeName);
95 216 : values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
96 216 : values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
97 216 : values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
98 216 : values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32));
99 216 : values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true);
100 216 : values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO);
101 216 : values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE);
102 216 : values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false);
103 216 : values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false);
104 216 : values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM);
105 216 : values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid);
106 216 : values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(InvalidOid);
107 216 : values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid);
108 216 : values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid);
109 216 : values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN);
110 216 : values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT);
111 216 : values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid);
112 216 : values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid);
113 216 : values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid);
114 216 : values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid);
115 216 : values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid);
116 216 : values[Anum_pg_type_typalign - 1] = CharGetDatum(TYPALIGN_INT);
117 216 : values[Anum_pg_type_typstorage - 1] = CharGetDatum(TYPSTORAGE_PLAIN);
118 216 : values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false);
119 216 : values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid);
120 216 : values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
121 216 : values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
122 216 : values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
123 216 : nulls[Anum_pg_type_typdefaultbin - 1] = true;
124 216 : nulls[Anum_pg_type_typdefault - 1] = true;
125 216 : nulls[Anum_pg_type_typacl - 1] = true;
126 :
127 : /* Use binary-upgrade override for pg_type.oid? */
128 216 : if (IsBinaryUpgrade)
129 : {
130 16 : if (!OidIsValid(binary_upgrade_next_pg_type_oid))
131 0 : ereport(ERROR,
132 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
133 : errmsg("pg_type OID value not set when in binary upgrade mode")));
134 :
135 16 : typoid = binary_upgrade_next_pg_type_oid;
136 16 : binary_upgrade_next_pg_type_oid = InvalidOid;
137 : }
138 : else
139 : {
140 200 : typoid = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
141 : Anum_pg_type_oid);
142 : }
143 :
144 216 : values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typoid);
145 :
146 : /*
147 : * create a new type tuple
148 : */
149 216 : tup = heap_form_tuple(tupDesc, values, nulls);
150 :
151 : /*
152 : * insert the tuple in the relation and get the tuple's oid.
153 : */
154 216 : CatalogTupleInsert(pg_type_desc, tup);
155 :
156 : /*
157 : * Create dependencies. We can/must skip this in bootstrap mode.
158 : */
159 216 : if (!IsBootstrapProcessingMode())
160 216 : GenerateTypeDependencies(tup,
161 : pg_type_desc,
162 : NULL,
163 : NULL,
164 : 0,
165 : false,
166 : false,
167 : true, /* make extension dependency */
168 : false);
169 :
170 : /* Post creation hook for new shell type */
171 216 : InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
172 :
173 216 : ObjectAddressSet(address, TypeRelationId, typoid);
174 :
175 : /*
176 : * clean up and return the type-oid
177 : */
178 216 : heap_freetuple(tup);
179 216 : table_close(pg_type_desc, RowExclusiveLock);
180 :
181 216 : return address;
182 : }
183 :
184 : /* ----------------------------------------------------------------
185 : * TypeCreate
186 : *
187 : * This does all the necessary work needed to define a new type.
188 : *
189 : * Returns the ObjectAddress assigned to the new type.
190 : * If newTypeOid is zero (the normal case), a new OID is created;
191 : * otherwise we use exactly that OID.
192 : * ----------------------------------------------------------------
193 : */
194 : ObjectAddress
195 128864 : TypeCreate(Oid newTypeOid,
196 : const char *typeName,
197 : Oid typeNamespace,
198 : Oid relationOid, /* only for relation rowtypes */
199 : char relationKind, /* ditto */
200 : Oid ownerId,
201 : int16 internalSize,
202 : char typeType,
203 : char typeCategory,
204 : bool typePreferred,
205 : char typDelim,
206 : Oid inputProcedure,
207 : Oid outputProcedure,
208 : Oid receiveProcedure,
209 : Oid sendProcedure,
210 : Oid typmodinProcedure,
211 : Oid typmodoutProcedure,
212 : Oid analyzeProcedure,
213 : Oid subscriptProcedure,
214 : Oid elementType,
215 : bool isImplicitArray,
216 : Oid arrayType,
217 : Oid baseType,
218 : const char *defaultTypeValue, /* human-readable rep */
219 : char *defaultTypeBin, /* cooked rep */
220 : bool passedByValue,
221 : char alignment,
222 : char storage,
223 : int32 typeMod,
224 : int32 typNDims, /* Array dimensions for baseType */
225 : bool typeNotNull,
226 : Oid typeCollation)
227 : {
228 : Relation pg_type_desc;
229 : Oid typeObjectId;
230 : bool isDependentType;
231 128864 : bool rebuildDeps = false;
232 : Acl *typacl;
233 : HeapTuple tup;
234 : bool nulls[Natts_pg_type];
235 : bool replaces[Natts_pg_type];
236 : Datum values[Natts_pg_type];
237 : NameData name;
238 : int i;
239 : ObjectAddress address;
240 :
241 : /*
242 : * We assume that the caller validated the arguments individually, but did
243 : * not check for bad combinations.
244 : *
245 : * Validate size specifications: either positive (fixed-length) or -1
246 : * (varlena) or -2 (cstring).
247 : */
248 128864 : if (!(internalSize > 0 ||
249 : internalSize == -1 ||
250 : internalSize == -2))
251 0 : ereport(ERROR,
252 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
253 : errmsg("invalid type internal size %d",
254 : internalSize)));
255 :
256 128864 : if (passedByValue)
257 : {
258 : /*
259 : * Pass-by-value types must have a fixed length that is one of the
260 : * values supported by fetch_att() and store_att_byval(); and the
261 : * alignment had better agree, too. All this code must match
262 : * access/tupmacs.h!
263 : */
264 1008 : if (internalSize == (int16) sizeof(char))
265 : {
266 12 : if (alignment != TYPALIGN_CHAR)
267 0 : ereport(ERROR,
268 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
269 : errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
270 : alignment, internalSize)));
271 : }
272 996 : else if (internalSize == (int16) sizeof(int16))
273 : {
274 4 : if (alignment != TYPALIGN_SHORT)
275 0 : ereport(ERROR,
276 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
277 : errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
278 : alignment, internalSize)));
279 : }
280 992 : else if (internalSize == (int16) sizeof(int32))
281 : {
282 858 : if (alignment != TYPALIGN_INT)
283 0 : ereport(ERROR,
284 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
285 : errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
286 : alignment, internalSize)));
287 : }
288 : #if SIZEOF_DATUM == 8
289 134 : else if (internalSize == (int16) sizeof(Datum))
290 : {
291 134 : if (alignment != TYPALIGN_DOUBLE)
292 0 : ereport(ERROR,
293 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
294 : errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
295 : alignment, internalSize)));
296 : }
297 : #endif
298 : else
299 0 : ereport(ERROR,
300 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
301 : errmsg("internal size %d is invalid for passed-by-value type",
302 : internalSize)));
303 : }
304 : else
305 : {
306 : /* varlena types must have int align or better */
307 127856 : if (internalSize == -1 &&
308 124990 : !(alignment == TYPALIGN_INT || alignment == TYPALIGN_DOUBLE))
309 0 : ereport(ERROR,
310 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
311 : errmsg("alignment \"%c\" is invalid for variable-length type",
312 : alignment)));
313 : /* cstring must have char alignment */
314 127856 : if (internalSize == -2 && !(alignment == TYPALIGN_CHAR))
315 0 : ereport(ERROR,
316 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
317 : errmsg("alignment \"%c\" is invalid for variable-length type",
318 : alignment)));
319 : }
320 :
321 : /* Only varlena types can be toasted */
322 128864 : if (storage != TYPSTORAGE_PLAIN && internalSize != -1)
323 0 : ereport(ERROR,
324 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
325 : errmsg("fixed-size types must have storage PLAIN")));
326 :
327 : /*
328 : * This is a dependent type if it's an implicitly-created array type or
329 : * multirange type, or if it's a relation rowtype that's not a composite
330 : * type. For such types we'll leave the ACL empty, and we'll skip
331 : * creating some dependency records because there will be a dependency
332 : * already through the depended-on type or relation. (Caution: this is
333 : * closely intertwined with some behavior in GenerateTypeDependencies.)
334 : */
335 64442 : isDependentType = isImplicitArray ||
336 255596 : typeType == TYPTYPE_MULTIRANGE ||
337 62290 : (OidIsValid(relationOid) && relationKind != RELKIND_COMPOSITE_TYPE);
338 :
339 : /*
340 : * initialize arrays needed for heap_form_tuple or heap_modify_tuple
341 : */
342 4252512 : for (i = 0; i < Natts_pg_type; ++i)
343 : {
344 4123648 : nulls[i] = false;
345 4123648 : replaces[i] = true;
346 4123648 : values[i] = (Datum) 0;
347 : }
348 :
349 : /*
350 : * insert data values
351 : */
352 128864 : namestrcpy(&name, typeName);
353 128864 : values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
354 128864 : values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
355 128864 : values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
356 128864 : values[Anum_pg_type_typlen - 1] = Int16GetDatum(internalSize);
357 128864 : values[Anum_pg_type_typbyval - 1] = BoolGetDatum(passedByValue);
358 128864 : values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType);
359 128864 : values[Anum_pg_type_typcategory - 1] = CharGetDatum(typeCategory);
360 128864 : values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(typePreferred);
361 128864 : values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(true);
362 128864 : values[Anum_pg_type_typdelim - 1] = CharGetDatum(typDelim);
363 128864 : values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(relationOid);
364 128864 : values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(subscriptProcedure);
365 128864 : values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(elementType);
366 128864 : values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(arrayType);
367 128864 : values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(inputProcedure);
368 128864 : values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(outputProcedure);
369 128864 : values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(receiveProcedure);
370 128864 : values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(sendProcedure);
371 128864 : values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(typmodinProcedure);
372 128864 : values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(typmodoutProcedure);
373 128864 : values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(analyzeProcedure);
374 128864 : values[Anum_pg_type_typalign - 1] = CharGetDatum(alignment);
375 128864 : values[Anum_pg_type_typstorage - 1] = CharGetDatum(storage);
376 128864 : values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(typeNotNull);
377 128864 : values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(baseType);
378 128864 : values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod);
379 128864 : values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims);
380 128864 : values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation);
381 :
382 : /*
383 : * initialize the default binary value for this type. Check for nulls of
384 : * course.
385 : */
386 128864 : if (defaultTypeBin)
387 128 : values[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(defaultTypeBin);
388 : else
389 128736 : nulls[Anum_pg_type_typdefaultbin - 1] = true;
390 :
391 : /*
392 : * initialize the default value for this type.
393 : */
394 128864 : if (defaultTypeValue)
395 146 : values[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultTypeValue);
396 : else
397 128718 : nulls[Anum_pg_type_typdefault - 1] = true;
398 :
399 : /*
400 : * Initialize the type's ACL, too. But dependent types don't get one.
401 : */
402 128864 : if (isDependentType)
403 123382 : typacl = NULL;
404 : else
405 5482 : typacl = get_user_default_acl(OBJECT_TYPE, ownerId,
406 : typeNamespace);
407 128864 : if (typacl != NULL)
408 6 : values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
409 : else
410 128858 : nulls[Anum_pg_type_typacl - 1] = true;
411 :
412 : /*
413 : * open pg_type and prepare to insert or update a row.
414 : *
415 : * NOTE: updating will not work correctly in bootstrap mode; but we don't
416 : * expect to be overwriting any shell types in bootstrap mode.
417 : */
418 128864 : pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
419 :
420 128864 : tup = SearchSysCacheCopy2(TYPENAMENSP,
421 : CStringGetDatum(typeName),
422 : ObjectIdGetDatum(typeNamespace));
423 128864 : if (HeapTupleIsValid(tup))
424 : {
425 192 : Form_pg_type typform = (Form_pg_type) GETSTRUCT(tup);
426 :
427 : /*
428 : * check that the type is not already defined. It may exist as a
429 : * shell type, however.
430 : */
431 192 : if (typform->typisdefined)
432 0 : ereport(ERROR,
433 : (errcode(ERRCODE_DUPLICATE_OBJECT),
434 : errmsg("type \"%s\" already exists", typeName)));
435 :
436 : /*
437 : * shell type must have been created by same owner
438 : */
439 192 : if (typform->typowner != ownerId)
440 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TYPE, typeName);
441 :
442 : /* trouble if caller wanted to force the OID */
443 192 : if (OidIsValid(newTypeOid))
444 0 : elog(ERROR, "cannot assign new OID to existing shell type");
445 :
446 192 : replaces[Anum_pg_type_oid - 1] = false;
447 :
448 : /*
449 : * Okay to update existing shell type tuple
450 : */
451 192 : tup = heap_modify_tuple(tup,
452 : RelationGetDescr(pg_type_desc),
453 : values,
454 : nulls,
455 : replaces);
456 :
457 192 : CatalogTupleUpdate(pg_type_desc, &tup->t_self, tup);
458 :
459 192 : typeObjectId = typform->oid;
460 :
461 192 : rebuildDeps = true; /* get rid of shell type's dependencies */
462 : }
463 : else
464 : {
465 : /* Force the OID if requested by caller */
466 128672 : if (OidIsValid(newTypeOid))
467 65016 : typeObjectId = newTypeOid;
468 : /* Use binary-upgrade override for pg_type.oid, if supplied. */
469 63656 : else if (IsBinaryUpgrade)
470 : {
471 1510 : if (!OidIsValid(binary_upgrade_next_pg_type_oid))
472 0 : ereport(ERROR,
473 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
474 : errmsg("pg_type OID value not set when in binary upgrade mode")));
475 :
476 1510 : typeObjectId = binary_upgrade_next_pg_type_oid;
477 1510 : binary_upgrade_next_pg_type_oid = InvalidOid;
478 : }
479 : else
480 : {
481 62146 : typeObjectId = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
482 : Anum_pg_type_oid);
483 : }
484 :
485 128672 : values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typeObjectId);
486 :
487 128672 : tup = heap_form_tuple(RelationGetDescr(pg_type_desc),
488 : values, nulls);
489 :
490 128672 : CatalogTupleInsert(pg_type_desc, tup);
491 : }
492 :
493 : /*
494 : * Create dependencies. We can/must skip this in bootstrap mode.
495 : */
496 128864 : if (!IsBootstrapProcessingMode())
497 118192 : GenerateTypeDependencies(tup,
498 : pg_type_desc,
499 : (defaultTypeBin ?
500 128 : stringToNode(defaultTypeBin) :
501 : NULL),
502 : typacl,
503 : relationKind,
504 : isImplicitArray,
505 : isDependentType,
506 : true, /* make extension dependency */
507 : rebuildDeps);
508 :
509 : /* Post creation hook for new type */
510 128862 : InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
511 :
512 128862 : ObjectAddressSet(address, TypeRelationId, typeObjectId);
513 :
514 : /*
515 : * finish up
516 : */
517 128862 : table_close(pg_type_desc, RowExclusiveLock);
518 :
519 128862 : return address;
520 : }
521 :
522 : /*
523 : * GenerateTypeDependencies: build the dependencies needed for a type
524 : *
525 : * Most of what this function needs to know about the type is passed as the
526 : * new pg_type row, typeTuple. We make callers pass the pg_type Relation
527 : * as well, so that we have easy access to a tuple descriptor for the row.
528 : *
529 : * While this is able to extract the defaultExpr and typacl from the tuple,
530 : * doing so is relatively expensive, and callers may have those values at
531 : * hand already. Pass those if handy, otherwise pass NULL. (typacl is really
532 : * "Acl *", but we declare it "void *" to avoid including acl.h in pg_type.h.)
533 : *
534 : * relationKind and isImplicitArray are likewise somewhat expensive to deduce
535 : * from the tuple, so we make callers pass those (they're not optional).
536 : *
537 : * isDependentType is true if this is an implicit array, multirange, or
538 : * relation rowtype; that means it doesn't need its own dependencies on owner
539 : * etc.
540 : *
541 : * We make an extension-membership dependency if we're in an extension
542 : * script and makeExtensionDep is true.
543 : * makeExtensionDep should be true when creating a new type or replacing a
544 : * shell type, but not for ALTER TYPE on an existing type. Passing false
545 : * causes the type's extension membership to be left alone.
546 : *
547 : * rebuild should be true if this is a pre-existing type. We will remove
548 : * existing dependencies and rebuild them from scratch. This is needed for
549 : * ALTER TYPE, and also when replacing a shell type. We don't remove any
550 : * existing extension dependency, though; hence, if makeExtensionDep is also
551 : * true and we're in an extension script, an error will occur unless the
552 : * type already belongs to the current extension. That's the behavior we
553 : * want when replacing a shell type, which is the only case where both flags
554 : * are true.
555 : */
556 : void
557 118360 : GenerateTypeDependencies(HeapTuple typeTuple,
558 : Relation typeCatalog,
559 : Node *defaultExpr,
560 : void *typacl,
561 : char relationKind, /* only for relation rowtypes */
562 : bool isImplicitArray,
563 : bool isDependentType,
564 : bool makeExtensionDep,
565 : bool rebuild)
566 : {
567 118360 : Form_pg_type typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
568 118360 : Oid typeObjectId = typeForm->oid;
569 : Datum datum;
570 : bool isNull;
571 : ObjectAddress myself,
572 : referenced;
573 : ObjectAddresses *addrs_normal;
574 :
575 : /* Extract defaultExpr if caller didn't pass it */
576 118360 : if (defaultExpr == NULL)
577 : {
578 118224 : datum = heap_getattr(typeTuple, Anum_pg_type_typdefaultbin,
579 : RelationGetDescr(typeCatalog), &isNull);
580 118224 : if (!isNull)
581 0 : defaultExpr = stringToNode(TextDatumGetCString(datum));
582 : }
583 : /* Extract typacl if caller didn't pass it */
584 118360 : if (typacl == NULL)
585 : {
586 118354 : datum = heap_getattr(typeTuple, Anum_pg_type_typacl,
587 : RelationGetDescr(typeCatalog), &isNull);
588 118354 : if (!isNull)
589 0 : typacl = DatumGetAclPCopy(datum);
590 : }
591 :
592 : /* If rebuild, first flush old dependencies, except extension deps */
593 118360 : if (rebuild)
594 : {
595 272 : deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true);
596 272 : deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
597 : }
598 :
599 118360 : ObjectAddressSet(myself, TypeRelationId, typeObjectId);
600 :
601 : /*
602 : * Make dependencies on namespace, owner, ACL.
603 : *
604 : * Skip these for a dependent type, since it will have such dependencies
605 : * indirectly through its depended-on type or relation. An exception is
606 : * that multiranges need their own namespace dependency, since we don't
607 : * force them to be in the same schema as their range type.
608 : */
609 :
610 : /* collects normal dependencies for bulk recording */
611 118360 : addrs_normal = new_object_addresses();
612 :
613 118360 : if (!isDependentType || typeForm->typtype == TYPTYPE_MULTIRANGE)
614 : {
615 5916 : ObjectAddressSet(referenced, NamespaceRelationId,
616 : typeForm->typnamespace);
617 5916 : add_exact_object_address(&referenced, addrs_normal);
618 : }
619 :
620 118360 : if (!isDependentType)
621 : {
622 5772 : recordDependencyOnOwner(TypeRelationId, typeObjectId,
623 : typeForm->typowner);
624 :
625 5772 : recordDependencyOnNewAcl(TypeRelationId, typeObjectId, 0,
626 : typeForm->typowner, typacl);
627 : }
628 :
629 : /*
630 : * Make extension dependency if requested.
631 : *
632 : * We used to skip this for dependent types, but it seems better to record
633 : * their extension membership explicitly; otherwise code such as
634 : * postgres_fdw's shippability test will be fooled.
635 : */
636 118360 : if (makeExtensionDep)
637 118280 : recordDependencyOnCurrentExtension(&myself, rebuild);
638 :
639 : /* Normal dependencies on the I/O and support functions */
640 118358 : if (OidIsValid(typeForm->typinput))
641 : {
642 118358 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typinput);
643 118358 : add_exact_object_address(&referenced, addrs_normal);
644 : }
645 :
646 118358 : if (OidIsValid(typeForm->typoutput))
647 : {
648 118358 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typoutput);
649 118358 : add_exact_object_address(&referenced, addrs_normal);
650 : }
651 :
652 118358 : if (OidIsValid(typeForm->typreceive))
653 : {
654 117964 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typreceive);
655 117964 : add_exact_object_address(&referenced, addrs_normal);
656 : }
657 :
658 118358 : if (OidIsValid(typeForm->typsend))
659 : {
660 117952 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsend);
661 117952 : add_exact_object_address(&referenced, addrs_normal);
662 : }
663 :
664 118358 : if (OidIsValid(typeForm->typmodin))
665 : {
666 28 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodin);
667 28 : add_exact_object_address(&referenced, addrs_normal);
668 : }
669 :
670 118358 : if (OidIsValid(typeForm->typmodout))
671 : {
672 28 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodout);
673 28 : add_exact_object_address(&referenced, addrs_normal);
674 : }
675 :
676 118358 : if (OidIsValid(typeForm->typanalyze))
677 : {
678 59486 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typanalyze);
679 59486 : add_exact_object_address(&referenced, addrs_normal);
680 : }
681 :
682 118358 : if (OidIsValid(typeForm->typsubscript))
683 : {
684 59056 : ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsubscript);
685 59056 : add_exact_object_address(&referenced, addrs_normal);
686 : }
687 :
688 : /* Normal dependency from a domain to its base type. */
689 118358 : if (OidIsValid(typeForm->typbasetype))
690 : {
691 1252 : ObjectAddressSet(referenced, TypeRelationId, typeForm->typbasetype);
692 1252 : add_exact_object_address(&referenced, addrs_normal);
693 : }
694 :
695 : /*
696 : * Normal dependency from a domain to its collation. We know the default
697 : * collation is pinned, so don't bother recording it.
698 : */
699 118358 : if (OidIsValid(typeForm->typcollation) &&
700 956 : typeForm->typcollation != DEFAULT_COLLATION_OID)
701 : {
702 556 : ObjectAddressSet(referenced, CollationRelationId, typeForm->typcollation);
703 556 : add_exact_object_address(&referenced, addrs_normal);
704 : }
705 :
706 118358 : record_object_address_dependencies(&myself, addrs_normal, DEPENDENCY_NORMAL);
707 118358 : free_object_addresses(addrs_normal);
708 :
709 : /* Normal dependency on the default expression. */
710 118358 : if (defaultExpr)
711 136 : recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
712 :
713 : /*
714 : * If the type is a rowtype for a relation, mark it as internally
715 : * dependent on the relation, *unless* it is a stand-alone composite type
716 : * relation. For the latter case, we have to reverse the dependency.
717 : *
718 : * In the former case, this allows the type to be auto-dropped when the
719 : * relation is, and not otherwise. And in the latter, of course we get the
720 : * opposite effect.
721 : */
722 118358 : if (OidIsValid(typeForm->typrelid))
723 : {
724 56890 : ObjectAddressSet(referenced, RelationRelationId, typeForm->typrelid);
725 :
726 56890 : if (relationKind != RELKIND_COMPOSITE_TYPE)
727 53416 : recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
728 : else
729 3474 : recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
730 : }
731 :
732 : /*
733 : * If the type is an implicitly-created array type, mark it as internally
734 : * dependent on the element type. Otherwise, if it has an element type,
735 : * the dependency is a normal one.
736 : */
737 118358 : if (OidIsValid(typeForm->typelem))
738 : {
739 59036 : ObjectAddressSet(referenced, TypeRelationId, typeForm->typelem);
740 59036 : recordDependencyOn(&myself, &referenced,
741 : isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
742 : }
743 :
744 : /*
745 : * Note: you might expect that we should record an internal dependency of
746 : * a multirange on its range type here, by analogy with the cases above.
747 : * But instead, that is done by RangeCreate(), which also handles
748 : * recording of other range-type-specific dependencies. That's pretty
749 : * bogus. It's okay for now, because there are no cases where we need to
750 : * regenerate the dependencies of a range or multirange type. But someday
751 : * we might need to move that logic here to allow such regeneration.
752 : */
753 118358 : }
754 :
755 : /*
756 : * RenameTypeInternal
757 : * This renames a type, as well as any associated array type.
758 : *
759 : * Caller must have already checked privileges.
760 : *
761 : * Currently this is used for renaming table rowtypes and for
762 : * ALTER TYPE RENAME TO command.
763 : */
764 : void
765 328 : RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
766 : {
767 : Relation pg_type_desc;
768 : HeapTuple tuple;
769 : Form_pg_type typ;
770 : Oid arrayOid;
771 : Oid oldTypeOid;
772 :
773 328 : pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
774 :
775 328 : tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
776 328 : if (!HeapTupleIsValid(tuple))
777 0 : elog(ERROR, "cache lookup failed for type %u", typeOid);
778 328 : typ = (Form_pg_type) GETSTRUCT(tuple);
779 :
780 : /* We are not supposed to be changing schemas here */
781 : Assert(typeNamespace == typ->typnamespace);
782 :
783 328 : arrayOid = typ->typarray;
784 :
785 : /* Check for a conflicting type name. */
786 328 : oldTypeOid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
787 : CStringGetDatum(newTypeName),
788 : ObjectIdGetDatum(typeNamespace));
789 :
790 : /*
791 : * If there is one, see if it's an autogenerated array type, and if so
792 : * rename it out of the way. (But we must skip that for a shell type
793 : * because moveArrayTypeName will do the wrong thing in that case.)
794 : * Otherwise, we can at least give a more friendly error than unique-index
795 : * violation.
796 : */
797 328 : if (OidIsValid(oldTypeOid))
798 : {
799 24 : if (get_typisdefined(oldTypeOid) &&
800 12 : moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace))
801 : /* successfully dodged the problem */ ;
802 : else
803 0 : ereport(ERROR,
804 : (errcode(ERRCODE_DUPLICATE_OBJECT),
805 : errmsg("type \"%s\" already exists", newTypeName)));
806 : }
807 :
808 : /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
809 328 : namestrcpy(&(typ->typname), newTypeName);
810 :
811 328 : CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple);
812 :
813 328 : InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
814 :
815 328 : heap_freetuple(tuple);
816 328 : table_close(pg_type_desc, RowExclusiveLock);
817 :
818 : /*
819 : * If the type has an array type, recurse to handle that. But we don't
820 : * need to do anything more if we already renamed that array type above
821 : * (which would happen when, eg, renaming "foo" to "_foo").
822 : */
823 328 : if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
824 : {
825 148 : char *arrname = makeArrayTypeName(newTypeName, typeNamespace);
826 :
827 148 : RenameTypeInternal(arrayOid, arrname, typeNamespace);
828 148 : pfree(arrname);
829 : }
830 328 : }
831 :
832 :
833 : /*
834 : * makeArrayTypeName
835 : * - given a base type name, make an array type name for it
836 : *
837 : * the caller is responsible for pfreeing the result
838 : */
839 : char *
840 64596 : makeArrayTypeName(const char *typeName, Oid typeNamespace)
841 : {
842 : char *arr_name;
843 64596 : int pass = 0;
844 : char suffix[NAMEDATALEN];
845 :
846 : /*
847 : * Per ancient Postgres tradition, array type names are made by prepending
848 : * an underscore to the base type name. Much client code knows that
849 : * convention, so don't muck with it. However, the tradition is less
850 : * clear about what to do in the corner cases where the resulting name is
851 : * too long or conflicts with an existing name. Our current rules are (1)
852 : * truncate the base name on the right as needed, and (2) if there is a
853 : * conflict, append another underscore and some digits chosen to make it
854 : * unique. This is similar to what ChooseRelationName() does.
855 : *
856 : * The actual name generation can be farmed out to makeObjectName() by
857 : * giving it an empty first name component.
858 : */
859 :
860 : /* First, try with no numeric suffix */
861 64596 : arr_name = makeObjectName("", typeName, NULL);
862 :
863 : for (;;)
864 : {
865 64616 : if (!SearchSysCacheExists2(TYPENAMENSP,
866 : CStringGetDatum(arr_name),
867 : ObjectIdGetDatum(typeNamespace)))
868 64596 : break;
869 :
870 : /* That attempt conflicted. Prepare a new name with some digits. */
871 20 : pfree(arr_name);
872 20 : snprintf(suffix, sizeof(suffix), "%d", ++pass);
873 20 : arr_name = makeObjectName("", typeName, suffix);
874 : }
875 :
876 64596 : return arr_name;
877 : }
878 :
879 :
880 : /*
881 : * moveArrayTypeName
882 : * - try to reassign an array type name that the user wants to use.
883 : *
884 : * The given type name has been discovered to already exist (with the given
885 : * OID). If it is an autogenerated array type, change the array type's name
886 : * to not conflict. This allows the user to create type "foo" followed by
887 : * type "_foo" without problems. (Of course, there are race conditions if
888 : * two backends try to create similarly-named types concurrently, but the
889 : * worst that can happen is an unnecessary failure --- anything we do here
890 : * will be rolled back if the type creation fails due to conflicting names.)
891 : *
892 : * Note that this must be called *before* calling makeArrayTypeName to
893 : * determine the new type's own array type name; else the latter will
894 : * certainly pick the same name.
895 : *
896 : * Returns true if successfully moved the type, false if not.
897 : *
898 : * We also return true if the given type is a shell type. In this case
899 : * the type has not been renamed out of the way, but nonetheless it can
900 : * be expected that TypeCreate will succeed. This behavior is convenient
901 : * for most callers --- those that need to distinguish the shell-type case
902 : * must do their own typisdefined test.
903 : */
904 : bool
905 40 : moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
906 : {
907 : Oid elemOid;
908 : char *newname;
909 :
910 : /* We need do nothing if it's a shell type. */
911 40 : if (!get_typisdefined(typeOid))
912 2 : return true;
913 :
914 : /* Can't change it if it's not an autogenerated array type. */
915 38 : elemOid = get_element_type(typeOid);
916 64 : if (!OidIsValid(elemOid) ||
917 26 : get_array_type(elemOid) != typeOid)
918 12 : return false;
919 :
920 : /*
921 : * OK, use makeArrayTypeName to pick an unused modification of the name.
922 : * Note that since makeArrayTypeName is an iterative process, this will
923 : * produce a name that it might have produced the first time, had the
924 : * conflicting type we are about to create already existed.
925 : */
926 26 : newname = makeArrayTypeName(typeName, typeNamespace);
927 :
928 : /* Apply the rename */
929 26 : RenameTypeInternal(typeOid, newname, typeNamespace);
930 :
931 : /*
932 : * We must bump the command counter so that any subsequent use of
933 : * makeArrayTypeName sees what we just did and doesn't pick the same name.
934 : */
935 26 : CommandCounterIncrement();
936 :
937 26 : pfree(newname);
938 :
939 26 : return true;
940 : }
941 :
942 :
943 : /*
944 : * makeMultirangeTypeName
945 : * - given a range type name, make a multirange type name for it
946 : *
947 : * caller is responsible for pfreeing the result
948 : */
949 : char *
950 130 : makeMultirangeTypeName(const char *rangeTypeName, Oid typeNamespace)
951 : {
952 : char *buf;
953 : char *rangestr;
954 :
955 : /*
956 : * If the range type name contains "range" then change that to
957 : * "multirange". Otherwise add "_multirange" to the end.
958 : */
959 130 : rangestr = strstr(rangeTypeName, "range");
960 130 : if (rangestr)
961 : {
962 112 : char *prefix = pnstrdup(rangeTypeName, rangestr - rangeTypeName);
963 :
964 112 : buf = psprintf("%s%s%s", prefix, "multi", rangestr);
965 : }
966 : else
967 18 : buf = psprintf("%s_multirange", pnstrdup(rangeTypeName, NAMEDATALEN - 12));
968 :
969 : /* clip it at NAMEDATALEN-1 bytes */
970 130 : buf[pg_mbcliplen(buf, strlen(buf), NAMEDATALEN - 1)] = '\0';
971 :
972 130 : if (SearchSysCacheExists2(TYPENAMENSP,
973 : CStringGetDatum(buf),
974 : ObjectIdGetDatum(typeNamespace)))
975 12 : ereport(ERROR,
976 : (errcode(ERRCODE_DUPLICATE_OBJECT),
977 : errmsg("type \"%s\" already exists", buf),
978 : errdetail("Failed while creating a multirange type for type \"%s\".", rangeTypeName),
979 : errhint("You can manually specify a multirange type name using the \"multirange_type_name\" attribute.")));
980 :
981 118 : return pstrdup(buf);
982 : }
|