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