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