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 
699  pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
700 
701  tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
702  if (!HeapTupleIsValid(tuple))
703  elog(ERROR, "cache lookup failed for type %u", typeOid);
704  typ = (Form_pg_type) GETSTRUCT(tuple);
705 
706  /* We are not supposed to be changing schemas here */
707  Assert(typeNamespace == typ->typnamespace);
708 
709  arrayOid = typ->typarray;
710 
711  /* Just to give a more friendly error than unique-index violation */
713  CStringGetDatum(newTypeName),
714  ObjectIdGetDatum(typeNamespace)))
715  ereport(ERROR,
717  errmsg("type \"%s\" already exists", newTypeName)));
718 
719  /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
720  namestrcpy(&(typ->typname), newTypeName);
721 
722  CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple);
723 
725 
726  heap_freetuple(tuple);
727  heap_close(pg_type_desc, RowExclusiveLock);
728 
729  /* If the type has an array type, recurse to handle that */
730  if (OidIsValid(arrayOid))
731  {
732  char *arrname = makeArrayTypeName(newTypeName, typeNamespace);
733 
734  RenameTypeInternal(arrayOid, arrname, typeNamespace);
735  pfree(arrname);
736  }
737 }
738 
739 
740 /*
741  * makeArrayTypeName
742  * - given a base type name, make an array type name for it
743  *
744  * the caller is responsible for pfreeing the result
745  */
746 char *
747 makeArrayTypeName(const char *typeName, Oid typeNamespace)
748 {
749  char *arr = (char *) palloc(NAMEDATALEN);
750  int namelen = strlen(typeName);
751  Relation pg_type_desc;
752  int i;
753 
754  /*
755  * The idea is to prepend underscores as needed until we make a name that
756  * doesn't collide with anything...
757  */
758  pg_type_desc = heap_open(TypeRelationId, AccessShareLock);
759 
760  for (i = 1; i < NAMEDATALEN - 1; i++)
761  {
762  arr[i - 1] = '_';
763  if (i + namelen < NAMEDATALEN)
764  strcpy(arr + i, typeName);
765  else
766  {
767  memcpy(arr + i, typeName, NAMEDATALEN - i);
768  truncate_identifier(arr, NAMEDATALEN, false);
769  }
771  CStringGetDatum(arr),
772  ObjectIdGetDatum(typeNamespace)))
773  break;
774  }
775 
776  heap_close(pg_type_desc, AccessShareLock);
777 
778  if (i >= NAMEDATALEN - 1)
779  ereport(ERROR,
781  errmsg("could not form array type name for type \"%s\"",
782  typeName)));
783 
784  return arr;
785 }
786 
787 
788 /*
789  * moveArrayTypeName
790  * - try to reassign an array type name that the user wants to use.
791  *
792  * The given type name has been discovered to already exist (with the given
793  * OID). If it is an autogenerated array type, change the array type's name
794  * to not conflict. This allows the user to create type "foo" followed by
795  * type "_foo" without problems. (Of course, there are race conditions if
796  * two backends try to create similarly-named types concurrently, but the
797  * worst that can happen is an unnecessary failure --- anything we do here
798  * will be rolled back if the type creation fails due to conflicting names.)
799  *
800  * Note that this must be called *before* calling makeArrayTypeName to
801  * determine the new type's own array type name; else the latter will
802  * certainly pick the same name.
803  *
804  * Returns TRUE if successfully moved the type, FALSE if not.
805  *
806  * We also return TRUE if the given type is a shell type. In this case
807  * the type has not been renamed out of the way, but nonetheless it can
808  * be expected that TypeCreate will succeed. This behavior is convenient
809  * for most callers --- those that need to distinguish the shell-type case
810  * must do their own typisdefined test.
811  */
812 bool
813 moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
814 {
815  Oid elemOid;
816  char *newname;
817 
818  /* We need do nothing if it's a shell type. */
819  if (!get_typisdefined(typeOid))
820  return true;
821 
822  /* Can't change it if it's not an autogenerated array type. */
823  elemOid = get_element_type(typeOid);
824  if (!OidIsValid(elemOid) ||
825  get_array_type(elemOid) != typeOid)
826  return false;
827 
828  /*
829  * OK, use makeArrayTypeName to pick an unused modification of the name.
830  * Note that since makeArrayTypeName is an iterative process, this will
831  * produce a name that it might have produced the first time, had the
832  * conflicting type we are about to create already existed.
833  */
834  newname = makeArrayTypeName(typeName, typeNamespace);
835 
836  /* Apply the rename */
837  RenameTypeInternal(typeOid, newname, typeNamespace);
838 
839  /*
840  * We must bump the command counter so that any subsequent use of
841  * makeArrayTypeName sees what we just did and doesn't pick the same name.
842  */
844 
845  pfree(newname);
846 
847  return true;
848 }
#define Anum_pg_type_typndims
Definition: pg_type.h:265
signed short int16
Definition: c.h:252
#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:603
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:747
#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:425
#define Anum_pg_type_typarray
Definition: pg_type.h:252
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2452
#define Anum_pg_type_typmodout
Definition: pg_type.h:258
#define PointerGetDatum(X)
Definition: postgres.h:564
#define Anum_pg_type_typname
Definition: pg_type.h:240
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2480
#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:459
#define AccessShareLock
Definition: lockdefs.h:36
#define Anum_pg_type_typcategory
Definition: pg_type.h:246
Definition: nodes.h:508
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:1891
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:724
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:158
#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:1374
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:217
#define OidIsValid(objectId)
Definition: c.h:534
#define Anum_pg_type_typnamespace
Definition: pg_type.h:241
bool IsBinaryUpgrade
Definition: globals.c:101
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:165
#define Anum_pg_type_typisdefined
Definition: pg_type.h:248
signed int int32
Definition: c.h:253
#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:992
#define Anum_pg_type_typispreferred
Definition: pg_type.h:247
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#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:489
#define Anum_pg_type_typstorage
Definition: pg_type.h:261
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:813
#define DEFAULT_COLLATION_OID
Definition: pg_collation.h:68
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3378
#define RowExclusiveLock
Definition: lockdefs.h:38
Acl * get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
Definition: aclchk.c:5194
#define CStringGetDatum(X)
Definition: postgres.h:586
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1332
#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:822
#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:374
void CommandCounterIncrement(void)
Definition: xact.c:921
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define CollationRelationId
Definition: pg_collation.h:30
TupleDesc rd_att
Definition: rel.h:114
#define Anum_pg_type_typelem
Definition: pg_type.h:251
#define BoolGetDatum(X)
Definition: postgres.h:410
#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:226
#define Assert(condition)
Definition: c.h:671
#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:169
const char * name
Definition: encode.c:521
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define CharGetDatum(X)
Definition: postgres.h:424
#define TYPTYPE_PSEUDO
Definition: pg_type.h:712
static Datum values[MAXATTR]
Definition: bootstrap.c:162
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:365
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:158
#define Int32GetDatum(X)
Definition: postgres.h:487
void * palloc(Size size)
Definition: mcxt.c:891
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:90
#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:160
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:793
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:34
#define PointerIsValid(pointer)
Definition: c.h:522
#define Anum_pg_type_typowner
Definition: pg_type.h:242
#define Anum_pg_type_typdefault
Definition: pg_type.h:268