PostgreSQL Source Code  git master
pg_type.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_type.c
4  * routines to support manipulation of the pg_type relation
5  *
6  * Portions Copyright (c) 1996-2020, 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/typecmds.h"
30 #include "miscadmin.h"
31 #include "parser/scansup.h"
32 #include "utils/acl.h"
33 #include "utils/builtins.h"
34 #include "utils/fmgroids.h"
35 #include "utils/lsyscache.h"
36 #include "utils/rel.h"
37 #include "utils/syscache.h"
38 
39 /* Potentially set by pg_upgrade_support functions */
41 
42 /* ----------------------------------------------------------------
43  * TypeShellMake
44  *
45  * This procedure inserts a "shell" tuple into the pg_type relation.
46  * The type tuple inserted has valid but dummy values, and its
47  * "typisdefined" field is false indicating it's not really defined.
48  *
49  * This is used so that a tuple exists in the catalogs. The I/O
50  * functions for the type will link to this tuple. When the full
51  * CREATE TYPE command is issued, the bogus values will be replaced
52  * with correct ones, and "typisdefined" will be set to true.
53  * ----------------------------------------------------------------
54  */
56 TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
57 {
58  Relation pg_type_desc;
59  TupleDesc tupDesc;
60  int i;
61  HeapTuple tup;
62  Datum values[Natts_pg_type];
63  bool nulls[Natts_pg_type];
64  Oid typoid;
65  NameData name;
66  ObjectAddress address;
67 
68  Assert(PointerIsValid(typeName));
69 
70  /*
71  * open pg_type
72  */
73  pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
74  tupDesc = pg_type_desc->rd_att;
75 
76  /*
77  * initialize our *nulls and *values arrays
78  */
79  for (i = 0; i < Natts_pg_type; ++i)
80  {
81  nulls[i] = false;
82  values[i] = (Datum) NULL; /* redundant, but safe */
83  }
84 
85  /*
86  * initialize *values with the type name and dummy values
87  *
88  * The representational details are the same as int4 ... it doesn't really
89  * matter what they are so long as they are consistent. Also note that we
90  * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
91  * mistaken for a usable type.
92  */
93  namestrcpy(&name, typeName);
94  values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
95  values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
96  values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
97  values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32));
98  values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true);
99  values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO);
100  values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE);
101  values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false);
102  values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false);
103  values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM);
104  values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid);
105  values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid);
106  values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid);
107  values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN);
108  values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT);
109  values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid);
110  values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid);
111  values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid);
112  values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid);
113  values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid);
114  values[Anum_pg_type_typalign - 1] = CharGetDatum(TYPALIGN_INT);
115  values[Anum_pg_type_typstorage - 1] = CharGetDatum(TYPSTORAGE_PLAIN);
116  values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false);
117  values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid);
118  values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
119  values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
120  values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
121  nulls[Anum_pg_type_typdefaultbin - 1] = true;
122  nulls[Anum_pg_type_typdefault - 1] = true;
123  nulls[Anum_pg_type_typacl - 1] = true;
124 
125  /* Use binary-upgrade override for pg_type.oid? */
126  if (IsBinaryUpgrade)
127  {
129  ereport(ERROR,
130  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
131  errmsg("pg_type OID value not set when in binary upgrade mode")));
132 
135  }
136  else
137  {
138  typoid = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
139  Anum_pg_type_oid);
140  }
141 
142  values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typoid);
143 
144  /*
145  * create a new type tuple
146  */
147  tup = heap_form_tuple(tupDesc, values, nulls);
148 
149  /*
150  * insert the tuple in the relation and get the tuple's oid.
151  */
152  CatalogTupleInsert(pg_type_desc, tup);
153 
154  /*
155  * Create dependencies. We can/must skip this in bootstrap mode.
156  */
159  pg_type_desc,
160  NULL,
161  NULL,
162  0,
163  false,
164  false,
165  false);
166 
167  /* Post creation hook for new shell type */
168  InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
169 
170  ObjectAddressSet(address, TypeRelationId, typoid);
171 
172  /*
173  * clean up and return the type-oid
174  */
175  heap_freetuple(tup);
176  table_close(pg_type_desc, RowExclusiveLock);
177 
178  return address;
179 }
180 
181 /* ----------------------------------------------------------------
182  * TypeCreate
183  *
184  * This does all the necessary work needed to define a new type.
185  *
186  * Returns the ObjectAddress assigned to the new type.
187  * If newTypeOid is zero (the normal case), a new OID is created;
188  * otherwise we use exactly that OID.
189  * ----------------------------------------------------------------
190  */
192 TypeCreate(Oid newTypeOid,
193  const char *typeName,
194  Oid typeNamespace,
195  Oid relationOid, /* only for relation rowtypes */
196  char relationKind, /* ditto */
197  Oid ownerId,
198  int16 internalSize,
199  char typeType,
200  char typeCategory,
201  bool typePreferred,
202  char typDelim,
203  Oid inputProcedure,
204  Oid outputProcedure,
205  Oid receiveProcedure,
206  Oid sendProcedure,
207  Oid typmodinProcedure,
208  Oid typmodoutProcedure,
209  Oid analyzeProcedure,
210  Oid elementType,
211  bool isImplicitArray,
212  Oid arrayType,
213  Oid baseType,
214  const char *defaultTypeValue, /* human readable rep */
215  char *defaultTypeBin, /* cooked rep */
216  bool passedByValue,
217  char alignment,
218  char storage,
219  int32 typeMod,
220  int32 typNDims, /* Array dimensions for baseType */
221  bool typeNotNull,
222  Oid typeCollation)
223 {
224  Relation pg_type_desc;
225  Oid typeObjectId;
226  bool isDependentType;
227  bool rebuildDeps = false;
228  Acl *typacl;
229  HeapTuple tup;
230  bool nulls[Natts_pg_type];
231  bool replaces[Natts_pg_type];
232  Datum values[Natts_pg_type];
233  NameData name;
234  int i;
235  ObjectAddress address;
236 
237  /*
238  * We assume that the caller validated the arguments individually, but did
239  * not check for bad combinations.
240  *
241  * Validate size specifications: either positive (fixed-length) or -1
242  * (varlena) or -2 (cstring).
243  */
244  if (!(internalSize > 0 ||
245  internalSize == -1 ||
246  internalSize == -2))
247  ereport(ERROR,
248  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
249  errmsg("invalid type internal size %d",
250  internalSize)));
251 
252  if (passedByValue)
253  {
254  /*
255  * Pass-by-value types must have a fixed length that is one of the
256  * values supported by fetch_att() and store_att_byval(); and the
257  * alignment had better agree, too. All this code must match
258  * access/tupmacs.h!
259  */
260  if (internalSize == (int16) sizeof(char))
261  {
262  if (alignment != TYPALIGN_CHAR)
263  ereport(ERROR,
264  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
265  errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
266  alignment, internalSize)));
267  }
268  else if (internalSize == (int16) sizeof(int16))
269  {
270  if (alignment != TYPALIGN_SHORT)
271  ereport(ERROR,
272  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
273  errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
274  alignment, internalSize)));
275  }
276  else if (internalSize == (int16) sizeof(int32))
277  {
278  if (alignment != TYPALIGN_INT)
279  ereport(ERROR,
280  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
281  errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
282  alignment, internalSize)));
283  }
284 #if SIZEOF_DATUM == 8
285  else if (internalSize == (int16) sizeof(Datum))
286  {
287  if (alignment != TYPALIGN_DOUBLE)
288  ereport(ERROR,
289  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
290  errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
291  alignment, internalSize)));
292  }
293 #endif
294  else
295  ereport(ERROR,
296  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
297  errmsg("internal size %d is invalid for passed-by-value type",
298  internalSize)));
299  }
300  else
301  {
302  /* varlena types must have int align or better */
303  if (internalSize == -1 &&
304  !(alignment == TYPALIGN_INT || alignment == TYPALIGN_DOUBLE))
305  ereport(ERROR,
306  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
307  errmsg("alignment \"%c\" is invalid for variable-length type",
308  alignment)));
309  /* cstring must have char alignment */
310  if (internalSize == -2 && !(alignment == TYPALIGN_CHAR))
311  ereport(ERROR,
312  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
313  errmsg("alignment \"%c\" is invalid for variable-length type",
314  alignment)));
315  }
316 
317  /* Only varlena types can be toasted */
318  if (storage != TYPSTORAGE_PLAIN && internalSize != -1)
319  ereport(ERROR,
320  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
321  errmsg("fixed-size types must have storage PLAIN")));
322 
323  /*
324  * This is a dependent type if it's an implicitly-created array type, or
325  * if it's a relation rowtype that's not a composite type. For such types
326  * we'll leave the ACL empty, and we'll skip creating some dependency
327  * records because there will be a dependency already through the
328  * depended-on type or relation. (Caution: this is closely intertwined
329  * with some behavior in GenerateTypeDependencies.)
330  */
331  isDependentType = isImplicitArray ||
332  (OidIsValid(relationOid) && relationKind != RELKIND_COMPOSITE_TYPE);
333 
334  /*
335  * initialize arrays needed for heap_form_tuple or heap_modify_tuple
336  */
337  for (i = 0; i < Natts_pg_type; ++i)
338  {
339  nulls[i] = false;
340  replaces[i] = true;
341  values[i] = (Datum) 0;
342  }
343 
344  /*
345  * insert data values
346  */
347  namestrcpy(&name, typeName);
348  values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
349  values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
350  values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
351  values[Anum_pg_type_typlen - 1] = Int16GetDatum(internalSize);
352  values[Anum_pg_type_typbyval - 1] = BoolGetDatum(passedByValue);
353  values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType);
354  values[Anum_pg_type_typcategory - 1] = CharGetDatum(typeCategory);
355  values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(typePreferred);
356  values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(true);
357  values[Anum_pg_type_typdelim - 1] = CharGetDatum(typDelim);
358  values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(relationOid);
359  values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(elementType);
360  values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(arrayType);
361  values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(inputProcedure);
362  values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(outputProcedure);
363  values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(receiveProcedure);
364  values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(sendProcedure);
365  values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(typmodinProcedure);
366  values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(typmodoutProcedure);
367  values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(analyzeProcedure);
368  values[Anum_pg_type_typalign - 1] = CharGetDatum(alignment);
369  values[Anum_pg_type_typstorage - 1] = CharGetDatum(storage);
370  values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(typeNotNull);
371  values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(baseType);
372  values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod);
373  values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims);
374  values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation);
375 
376  /*
377  * initialize the default binary value for this type. Check for nulls of
378  * course.
379  */
380  if (defaultTypeBin)
381  values[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(defaultTypeBin);
382  else
383  nulls[Anum_pg_type_typdefaultbin - 1] = true;
384 
385  /*
386  * initialize the default value for this type.
387  */
388  if (defaultTypeValue)
389  values[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultTypeValue);
390  else
391  nulls[Anum_pg_type_typdefault - 1] = true;
392 
393  /*
394  * Initialize the type's ACL, too. But dependent types don't get one.
395  */
396  if (isDependentType)
397  typacl = NULL;
398  else
399  typacl = get_user_default_acl(OBJECT_TYPE, ownerId,
400  typeNamespace);
401  if (typacl != NULL)
402  values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
403  else
404  nulls[Anum_pg_type_typacl - 1] = true;
405 
406  /*
407  * open pg_type and prepare to insert or update a row.
408  *
409  * NOTE: updating will not work correctly in bootstrap mode; but we don't
410  * expect to be overwriting any shell types in bootstrap mode.
411  */
412  pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
413 
415  CStringGetDatum(typeName),
416  ObjectIdGetDatum(typeNamespace));
417  if (HeapTupleIsValid(tup))
418  {
419  Form_pg_type typform = (Form_pg_type) GETSTRUCT(tup);
420 
421  /*
422  * check that the type is not already defined. It may exist as a
423  * shell type, however.
424  */
425  if (typform->typisdefined)
426  ereport(ERROR,
428  errmsg("type \"%s\" already exists", typeName)));
429 
430  /*
431  * shell type must have been created by same owner
432  */
433  if (typform->typowner != ownerId)
435 
436  /* trouble if caller wanted to force the OID */
437  if (OidIsValid(newTypeOid))
438  elog(ERROR, "cannot assign new OID to existing shell type");
439 
440  replaces[Anum_pg_type_oid - 1] = false;
441 
442  /*
443  * Okay to update existing shell type tuple
444  */
445  tup = heap_modify_tuple(tup,
446  RelationGetDescr(pg_type_desc),
447  values,
448  nulls,
449  replaces);
450 
451  CatalogTupleUpdate(pg_type_desc, &tup->t_self, tup);
452 
453  typeObjectId = typform->oid;
454 
455  rebuildDeps = true; /* get rid of shell type's dependencies */
456  }
457  else
458  {
459  /* Force the OID if requested by caller */
460  if (OidIsValid(newTypeOid))
461  typeObjectId = newTypeOid;
462  /* Use binary-upgrade override for pg_type.oid, if supplied. */
463  else if (IsBinaryUpgrade)
464  {
466  ereport(ERROR,
467  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
468  errmsg("pg_type OID value not set when in binary upgrade mode")));
469 
470  typeObjectId = binary_upgrade_next_pg_type_oid;
472  }
473  else
474  {
475  typeObjectId = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
476  Anum_pg_type_oid);
477  }
478 
479  values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typeObjectId);
480 
481  tup = heap_form_tuple(RelationGetDescr(pg_type_desc),
482  values, nulls);
483 
484  CatalogTupleInsert(pg_type_desc, tup);
485  }
486 
487  /*
488  * Create dependencies. We can/must skip this in bootstrap mode.
489  */
492  pg_type_desc,
493  (defaultTypeBin ?
494  stringToNode(defaultTypeBin) :
495  NULL),
496  typacl,
497  relationKind,
498  isImplicitArray,
499  isDependentType,
500  rebuildDeps);
501 
502  /* Post creation hook for new type */
503  InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
504 
505  ObjectAddressSet(address, TypeRelationId, typeObjectId);
506 
507  /*
508  * finish up
509  */
510  table_close(pg_type_desc, RowExclusiveLock);
511 
512  return address;
513 }
514 
515 /*
516  * GenerateTypeDependencies: build the dependencies needed for a type
517  *
518  * Most of what this function needs to know about the type is passed as the
519  * new pg_type row, typeTuple. We make callers pass the pg_type Relation
520  * as well, so that we have easy access to a tuple descriptor for the row.
521  *
522  * While this is able to extract the defaultExpr and typacl from the tuple,
523  * doing so is relatively expensive, and callers may have those values at
524  * hand already. Pass those if handy, otherwise pass NULL. (typacl is really
525  * "Acl *", but we declare it "void *" to avoid including acl.h in pg_type.h.)
526  *
527  * relationKind and isImplicitArray are likewise somewhat expensive to deduce
528  * from the tuple, so we make callers pass those (they're not optional).
529  *
530  * isDependentType is true if this is an implicit array or relation rowtype;
531  * that means it doesn't need its own dependencies on owner etc.
532  *
533  * If rebuild is true, we remove existing dependencies and rebuild them
534  * from scratch. This is needed for ALTER TYPE, and also when replacing
535  * a shell type. We don't remove an existing extension dependency, though.
536  * (That means an extension can't absorb a shell type created in another
537  * extension, nor ALTER a type created by another extension. Also, if it
538  * replaces a free-standing shell type or ALTERs a free-standing type,
539  * that type will become a member of the extension.)
540  */
541 void
543  Relation typeCatalog,
544  Node *defaultExpr,
545  void *typacl,
546  char relationKind, /* only for relation rowtypes */
547  bool isImplicitArray,
548  bool isDependentType,
549  bool rebuild)
550 {
551  Form_pg_type typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
552  Oid typeObjectId = typeForm->oid;
553  Datum datum;
554  bool isNull;
555  ObjectAddress myself,
556  referenced;
557  ObjectAddresses *addrs_normal;
558 
559  /* Extract defaultExpr if caller didn't pass it */
560  if (defaultExpr == NULL)
561  {
562  datum = heap_getattr(typeTuple, Anum_pg_type_typdefaultbin,
563  RelationGetDescr(typeCatalog), &isNull);
564  if (!isNull)
565  defaultExpr = stringToNode(TextDatumGetCString(datum));
566  }
567  /* Extract typacl if caller didn't pass it */
568  if (typacl == NULL)
569  {
570  datum = heap_getattr(typeTuple, Anum_pg_type_typacl,
571  RelationGetDescr(typeCatalog), &isNull);
572  if (!isNull)
573  typacl = DatumGetAclPCopy(datum);
574  }
575 
576  /* If rebuild, first flush old dependencies, except extension deps */
577  if (rebuild)
578  {
579  deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true);
580  deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
581  }
582 
583  ObjectAddressSet(myself, TypeRelationId, typeObjectId);
584 
585  /*
586  * Make dependencies on namespace, owner, ACL, extension.
587  *
588  * Skip these for a dependent type, since it will have such dependencies
589  * indirectly through its depended-on type or relation.
590  */
591 
592  /* placeholder for all normal dependencies */
593  addrs_normal = new_object_addresses();
594 
595  if (!isDependentType)
596  {
597  ObjectAddressSet(referenced, NamespaceRelationId,
598  typeForm->typnamespace);
599  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
600 
601  recordDependencyOnOwner(TypeRelationId, typeObjectId,
602  typeForm->typowner);
603 
604  recordDependencyOnNewAcl(TypeRelationId, typeObjectId, 0,
605  typeForm->typowner, typacl);
606 
607  recordDependencyOnCurrentExtension(&myself, rebuild);
608  }
609 
610  /* Normal dependencies on the I/O functions */
611  if (OidIsValid(typeForm->typinput))
612  {
613  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typinput);
614  add_exact_object_address(&referenced, addrs_normal);
615  }
616 
617  if (OidIsValid(typeForm->typoutput))
618  {
619  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typoutput);
620  add_exact_object_address(&referenced, addrs_normal);
621  }
622 
623  if (OidIsValid(typeForm->typreceive))
624  {
625  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typreceive);
626  add_exact_object_address(&referenced, addrs_normal);
627  }
628 
629  if (OidIsValid(typeForm->typsend))
630  {
631  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsend);
632  add_exact_object_address(&referenced, addrs_normal);
633  }
634 
635  if (OidIsValid(typeForm->typmodin))
636  {
637  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodin);
638  add_exact_object_address(&referenced, addrs_normal);
639  }
640 
641  if (OidIsValid(typeForm->typmodout))
642  {
643  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodout);
644  add_exact_object_address(&referenced, addrs_normal);
645  }
646 
647  if (OidIsValid(typeForm->typanalyze))
648  {
649  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typanalyze);
650  add_exact_object_address(&referenced, addrs_normal);
651  }
652 
653  /* Normal dependency from a domain to its base type. */
654  if (OidIsValid(typeForm->typbasetype))
655  {
656  ObjectAddressSet(referenced, TypeRelationId, typeForm->typbasetype);
657  add_exact_object_address(&referenced, addrs_normal);
658  }
659 
660  /*
661  * Normal dependency from a domain to its collation. We know the default
662  * collation is pinned, so don't bother recording it.
663  */
664  if (OidIsValid(typeForm->typcollation) &&
665  typeForm->typcollation != DEFAULT_COLLATION_OID)
666  {
667  ObjectAddressSet(referenced, CollationRelationId, typeForm->typcollation);
668  add_exact_object_address(&referenced, addrs_normal);
669  }
670 
672  free_object_addresses(addrs_normal);
673 
674  /* Normal dependency on the default expression. */
675  if (defaultExpr)
676  recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
677 
678  /*
679  * If the type is a rowtype for a relation, mark it as internally
680  * dependent on the relation, *unless* it is a stand-alone composite type
681  * relation. For the latter case, we have to reverse the dependency.
682  *
683  * In the former case, this allows the type to be auto-dropped when the
684  * relation is, and not otherwise. And in the latter, of course we get the
685  * opposite effect.
686  */
687  if (OidIsValid(typeForm->typrelid))
688  {
689  ObjectAddressSet(referenced, RelationRelationId, typeForm->typrelid);
690 
691  if (relationKind != RELKIND_COMPOSITE_TYPE)
692  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
693  else
694  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
695  }
696 
697  /*
698  * If the type is an implicitly-created array type, mark it as internally
699  * dependent on the element type. Otherwise, if it has an element type,
700  * the dependency is a normal one.
701  */
702  if (OidIsValid(typeForm->typelem))
703  {
704  ObjectAddressSet(referenced, TypeRelationId, typeForm->typelem);
705  recordDependencyOn(&myself, &referenced,
706  isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
707  }
708 }
709 
710 /*
711  * RenameTypeInternal
712  * This renames a type, as well as any associated array type.
713  *
714  * Caller must have already checked privileges.
715  *
716  * Currently this is used for renaming table rowtypes and for
717  * ALTER TYPE RENAME TO command.
718  */
719 void
720 RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
721 {
722  Relation pg_type_desc;
723  HeapTuple tuple;
724  Form_pg_type typ;
725  Oid arrayOid;
726  Oid oldTypeOid;
727 
728  pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
729 
730  tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
731  if (!HeapTupleIsValid(tuple))
732  elog(ERROR, "cache lookup failed for type %u", typeOid);
733  typ = (Form_pg_type) GETSTRUCT(tuple);
734 
735  /* We are not supposed to be changing schemas here */
736  Assert(typeNamespace == typ->typnamespace);
737 
738  arrayOid = typ->typarray;
739 
740  /* Check for a conflicting type name. */
741  oldTypeOid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
742  CStringGetDatum(newTypeName),
743  ObjectIdGetDatum(typeNamespace));
744 
745  /*
746  * If there is one, see if it's an autogenerated array type, and if so
747  * rename it out of the way. (But we must skip that for a shell type
748  * because moveArrayTypeName will do the wrong thing in that case.)
749  * Otherwise, we can at least give a more friendly error than unique-index
750  * violation.
751  */
752  if (OidIsValid(oldTypeOid))
753  {
754  if (get_typisdefined(oldTypeOid) &&
755  moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace))
756  /* successfully dodged the problem */ ;
757  else
758  ereport(ERROR,
760  errmsg("type \"%s\" already exists", newTypeName)));
761  }
762 
763  /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
764  namestrcpy(&(typ->typname), newTypeName);
765 
766  CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple);
767 
768  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
769 
770  heap_freetuple(tuple);
771  table_close(pg_type_desc, RowExclusiveLock);
772 
773  /*
774  * If the type has an array type, recurse to handle that. But we don't
775  * need to do anything more if we already renamed that array type above
776  * (which would happen when, eg, renaming "foo" to "_foo").
777  */
778  if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
779  {
780  char *arrname = makeArrayTypeName(newTypeName, typeNamespace);
781 
782  RenameTypeInternal(arrayOid, arrname, typeNamespace);
783  pfree(arrname);
784  }
785 }
786 
787 
788 /*
789  * makeArrayTypeName
790  * - given a base type name, make an array type name for it
791  *
792  * the caller is responsible for pfreeing the result
793  */
794 char *
795 makeArrayTypeName(const char *typeName, Oid typeNamespace)
796 {
797  char *arr = (char *) palloc(NAMEDATALEN);
798  int namelen = strlen(typeName);
799  int i;
800 
801  /*
802  * The idea is to prepend underscores as needed until we make a name that
803  * doesn't collide with anything...
804  */
805  for (i = 1; i < NAMEDATALEN - 1; i++)
806  {
807  arr[i - 1] = '_';
808  if (i + namelen < NAMEDATALEN)
809  strcpy(arr + i, typeName);
810  else
811  {
812  memcpy(arr + i, typeName, NAMEDATALEN - i);
813  truncate_identifier(arr, NAMEDATALEN, false);
814  }
816  CStringGetDatum(arr),
817  ObjectIdGetDatum(typeNamespace)))
818  break;
819  }
820 
821  if (i >= NAMEDATALEN - 1)
822  ereport(ERROR,
824  errmsg("could not form array type name for type \"%s\"",
825  typeName)));
826 
827  return arr;
828 }
829 
830 
831 /*
832  * moveArrayTypeName
833  * - try to reassign an array type name that the user wants to use.
834  *
835  * The given type name has been discovered to already exist (with the given
836  * OID). If it is an autogenerated array type, change the array type's name
837  * to not conflict. This allows the user to create type "foo" followed by
838  * type "_foo" without problems. (Of course, there are race conditions if
839  * two backends try to create similarly-named types concurrently, but the
840  * worst that can happen is an unnecessary failure --- anything we do here
841  * will be rolled back if the type creation fails due to conflicting names.)
842  *
843  * Note that this must be called *before* calling makeArrayTypeName to
844  * determine the new type's own array type name; else the latter will
845  * certainly pick the same name.
846  *
847  * Returns true if successfully moved the type, false if not.
848  *
849  * We also return true if the given type is a shell type. In this case
850  * the type has not been renamed out of the way, but nonetheless it can
851  * be expected that TypeCreate will succeed. This behavior is convenient
852  * for most callers --- those that need to distinguish the shell-type case
853  * must do their own typisdefined test.
854  */
855 bool
856 moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
857 {
858  Oid elemOid;
859  char *newname;
860 
861  /* We need do nothing if it's a shell type. */
862  if (!get_typisdefined(typeOid))
863  return true;
864 
865  /* Can't change it if it's not an autogenerated array type. */
866  elemOid = get_element_type(typeOid);
867  if (!OidIsValid(elemOid) ||
868  get_array_type(elemOid) != typeOid)
869  return false;
870 
871  /*
872  * OK, use makeArrayTypeName to pick an unused modification of the name.
873  * Note that since makeArrayTypeName is an iterative process, this will
874  * produce a name that it might have produced the first time, had the
875  * conflicting type we are about to create already existed.
876  */
877  newname = makeArrayTypeName(typeName, typeNamespace);
878 
879  /* Apply the rename */
880  RenameTypeInternal(typeOid, newname, typeNamespace);
881 
882  /*
883  * We must bump the command counter so that any subsequent use of
884  * makeArrayTypeName sees what we just did and doesn't pick the same name.
885  */
887 
888  pfree(newname);
889 
890  return true;
891 }
signed short int16
Definition: c.h:362
#define NIL
Definition: pg_list.h:65
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
#define NameGetDatum(X)
Definition: postgres.h:595
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:795
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
#define RelationGetDescr(relation)
Definition: rel.h:482
void namestrcpy(Name name, const char *str)
Definition: name.c:233
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2636
#define PointerGetDatum(X)
Definition: postgres.h:556
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2664
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2676
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:232
#define Int16GetDatum(X)
Definition: postgres.h:451
Definition: nodes.h:528
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:2061
int errcode(int sqlerrcode)
Definition: elog.c:610
void * stringToNode(const char *str)
Definition: read.c:89
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2467
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2412
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2707
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
ObjectAddress TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
Definition: pg_type.c:56
#define OidIsValid(objectId)
Definition: c.h:652
bool IsBinaryUpgrade
Definition: globals.c:110
signed int int32
Definition: c.h:363
#define NAMEDATALEN
void truncate_identifier(char *ident, int len, bool warn)
Definition: scansup.c:93
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Definition: c.h:617
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:856
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1584
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:945
Oid binary_upgrade_next_pg_type_oid
Definition: pg_type.c:40
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:720
#define TextDatumGetCString(d)
Definition: builtins.h:87
uintptr_t Datum
Definition: postgres.h:367
void CommandCounterIncrement(void)
Definition: xact.c:1021
TupleDesc rd_att
Definition: rel.h:110
#define BoolGetDatum(X)
Definition: postgres.h:402
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:746
void GenerateTypeDependencies(HeapTuple typeTuple, Relation typeCatalog, Node *defaultExpr, void *typacl, char relationKind, bool isImplicitArray, bool isDependentType, bool rebuild)
Definition: pg_type.c:542
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:180
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:194
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:185
const char * name
Definition: encode.c:561
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define CharGetDatum(X)
Definition: postgres.h:416
void recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, Acl *acl)
Definition: aclchk.c:5466
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:393
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
#define Int32GetDatum(X)
Definition: postgres.h:479
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:821
ObjectAddress TypeCreate(Oid newTypeOid, const char *typeName, Oid typeNamespace, Oid relationOid, char relationKind, Oid ownerId, int16 internalSize, char typeType, char typeCategory, bool typePreferred, char typDelim, Oid inputProcedure, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, Oid typmodinProcedure, Oid typmodoutProcedure, Oid analyzeProcedure, Oid elementType, bool isImplicitArray, Oid arrayType, Oid baseType, const char *defaultTypeValue, char *defaultTypeBin, bool passedByValue, char alignment, char storage, int32 typeMod, int32 typNDims, bool typeNotNull, Oid typeCollation)
Definition: pg_type.c:192
#define elog(elevel,...)
Definition: elog.h:214
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:86
#define SearchSysCacheCopy2(cacheId, key1, key2)
Definition: syscache.h:176
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
#define PointerIsValid(pointer)
Definition: c.h:640
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
#define TypeOidIndexId
Definition: indexing.h:297
Acl * get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
Definition: aclchk.c:5390
#define DatumGetAclPCopy(X)
Definition: acl.h:121