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