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