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