PostgreSQL Source Code  git master
pg_type.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/binary_upgrade.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/typecmds.h"
#include "miscadmin.h"
#include "parser/scansup.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for pg_type.c:

Go to the source code of this file.

Functions

ObjectAddress TypeShellMake (const char *typeName, Oid typeNamespace, Oid ownerId)
 
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)
 
void GenerateTypeDependencies (Oid typeObjectId, Form_pg_type typeForm, Node *defaultExpr, void *typacl, char relationKind, bool isImplicitArray, bool isDependentType, bool rebuild)
 
void RenameTypeInternal (Oid typeOid, const char *newTypeName, Oid typeNamespace)
 
char * makeArrayTypeName (const char *typeName, Oid typeNamespace)
 
bool moveArrayTypeName (Oid typeOid, const char *typeName, Oid typeNamespace)
 

Variables

Oid binary_upgrade_next_pg_type_oid = InvalidOid
 

Function Documentation

◆ GenerateTypeDependencies()

void GenerateTypeDependencies ( Oid  typeObjectId,
Form_pg_type  typeForm,
Node defaultExpr,
void *  typacl,
char  relationKind,
bool  isImplicitArray,
bool  isDependentType,
bool  rebuild 
)

Definition at line 537 of file pg_type.c.

References ObjectAddress::classId, deleteDependencyRecordsFor(), deleteSharedDependencyRecordsFor(), DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, NIL, ObjectAddress::objectId, ObjectAddress::objectSubId, OidIsValid, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnExpr(), recordDependencyOnNewAcl(), and recordDependencyOnOwner().

Referenced by AlterDomainDefault(), TypeCreate(), and TypeShellMake().

545 {
546  ObjectAddress myself,
547  referenced;
548 
549  /* If rebuild, first flush old dependencies, except extension deps */
550  if (rebuild)
551  {
552  deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true);
553  deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
554  }
555 
556  myself.classId = TypeRelationId;
557  myself.objectId = typeObjectId;
558  myself.objectSubId = 0;
559 
560  /*
561  * Make dependencies on namespace, owner, ACL, extension.
562  *
563  * Skip these for a dependent type, since it will have such dependencies
564  * indirectly through its depended-on type or relation.
565  */
566  if (!isDependentType)
567  {
568  referenced.classId = NamespaceRelationId;
569  referenced.objectId = typeForm->typnamespace;
570  referenced.objectSubId = 0;
571  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
572 
573  recordDependencyOnOwner(TypeRelationId, typeObjectId,
574  typeForm->typowner);
575 
576  recordDependencyOnNewAcl(TypeRelationId, typeObjectId, 0,
577  typeForm->typowner, typacl);
578 
579  recordDependencyOnCurrentExtension(&myself, rebuild);
580  }
581 
582  /* Normal dependencies on the I/O functions */
583  if (OidIsValid(typeForm->typinput))
584  {
585  referenced.classId = ProcedureRelationId;
586  referenced.objectId = typeForm->typinput;
587  referenced.objectSubId = 0;
588  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
589  }
590 
591  if (OidIsValid(typeForm->typoutput))
592  {
593  referenced.classId = ProcedureRelationId;
594  referenced.objectId = typeForm->typoutput;
595  referenced.objectSubId = 0;
596  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
597  }
598 
599  if (OidIsValid(typeForm->typreceive))
600  {
601  referenced.classId = ProcedureRelationId;
602  referenced.objectId = typeForm->typreceive;
603  referenced.objectSubId = 0;
604  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
605  }
606 
607  if (OidIsValid(typeForm->typsend))
608  {
609  referenced.classId = ProcedureRelationId;
610  referenced.objectId = typeForm->typsend;
611  referenced.objectSubId = 0;
612  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
613  }
614 
615  if (OidIsValid(typeForm->typmodin))
616  {
617  referenced.classId = ProcedureRelationId;
618  referenced.objectId = typeForm->typmodin;
619  referenced.objectSubId = 0;
620  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
621  }
622 
623  if (OidIsValid(typeForm->typmodout))
624  {
625  referenced.classId = ProcedureRelationId;
626  referenced.objectId = typeForm->typmodout;
627  referenced.objectSubId = 0;
628  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
629  }
630 
631  if (OidIsValid(typeForm->typanalyze))
632  {
633  referenced.classId = ProcedureRelationId;
634  referenced.objectId = typeForm->typanalyze;
635  referenced.objectSubId = 0;
636  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
637  }
638 
639  /*
640  * If the type is a rowtype for a relation, mark it as internally
641  * dependent on the relation, *unless* it is a stand-alone composite type
642  * relation. For the latter case, we have to reverse the dependency.
643  *
644  * In the former case, this allows the type to be auto-dropped when the
645  * relation is, and not otherwise. And in the latter, of course we get the
646  * opposite effect.
647  */
648  if (OidIsValid(typeForm->typrelid))
649  {
650  referenced.classId = RelationRelationId;
651  referenced.objectId = typeForm->typrelid;
652  referenced.objectSubId = 0;
653 
654  if (relationKind != RELKIND_COMPOSITE_TYPE)
655  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
656  else
657  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
658  }
659 
660  /*
661  * If the type is an implicitly-created array type, mark it as internally
662  * dependent on the element type. Otherwise, if it has an element type,
663  * the dependency is a normal one.
664  */
665  if (OidIsValid(typeForm->typelem))
666  {
667  referenced.classId = TypeRelationId;
668  referenced.objectId = typeForm->typelem;
669  referenced.objectSubId = 0;
670  recordDependencyOn(&myself, &referenced,
671  isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
672  }
673 
674  /* Normal dependency from a domain to its base type. */
675  if (OidIsValid(typeForm->typbasetype))
676  {
677  referenced.classId = TypeRelationId;
678  referenced.objectId = typeForm->typbasetype;
679  referenced.objectSubId = 0;
680  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
681  }
682 
683  /* Normal dependency from a domain to its collation. */
684  /* We know the default collation is pinned, so don't bother recording it */
685  if (OidIsValid(typeForm->typcollation) &&
686  typeForm->typcollation != DEFAULT_COLLATION_OID)
687  {
688  referenced.classId = CollationRelationId;
689  referenced.objectId = typeForm->typcollation;
690  referenced.objectSubId = 0;
691  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
692  }
693 
694  /* Normal dependency on the default expression. */
695  if (defaultExpr)
696  recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
697 }
#define NIL
Definition: pg_list.h:65
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:190
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:165
#define OidIsValid(objectId)
Definition: c.h:638
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1586
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:908
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:138
void recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, Acl *acl)
Definition: aclchk.c:5534

◆ makeArrayTypeName()

char* makeArrayTypeName ( const char *  typeName,
Oid  typeNamespace 
)

Definition at line 784 of file pg_type.c.

References AccessShareLock, CStringGetDatum, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, i, NAMEDATALEN, ObjectIdGetDatum, palloc(), SearchSysCacheExists2, table_close(), table_open(), truncate_identifier(), and TYPENAMENSP.

Referenced by DefineDomain(), DefineEnum(), DefineRange(), DefineType(), heap_create_with_catalog(), moveArrayTypeName(), and RenameTypeInternal().

785 {
786  char *arr = (char *) palloc(NAMEDATALEN);
787  int namelen = strlen(typeName);
788  Relation pg_type_desc;
789  int i;
790 
791  /*
792  * The idea is to prepend underscores as needed until we make a name that
793  * doesn't collide with anything...
794  */
795  pg_type_desc = table_open(TypeRelationId, AccessShareLock);
796 
797  for (i = 1; i < NAMEDATALEN - 1; i++)
798  {
799  arr[i - 1] = '_';
800  if (i + namelen < NAMEDATALEN)
801  strcpy(arr + i, typeName);
802  else
803  {
804  memcpy(arr + i, typeName, NAMEDATALEN - i);
805  truncate_identifier(arr, NAMEDATALEN, false);
806  }
808  CStringGetDatum(arr),
809  ObjectIdGetDatum(typeNamespace)))
810  break;
811  }
812 
813  table_close(pg_type_desc, AccessShareLock);
814 
815  if (i >= NAMEDATALEN - 1)
816  ereport(ERROR,
818  errmsg("could not form array type name for type \"%s\"",
819  typeName)));
820 
821  return arr;
822 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:570
#define NAMEDATALEN
void truncate_identifier(char *ident, int len, bool warn)
Definition: scansup.c:187
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel, rest)
Definition: elog.h:141
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:185
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:784
int i
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33

◆ moveArrayTypeName()

bool moveArrayTypeName ( Oid  typeOid,
const char *  typeName,
Oid  typeNamespace 
)

Definition at line 850 of file pg_type.c.

References CommandCounterIncrement(), get_array_type(), get_element_type(), get_typisdefined(), makeArrayTypeName(), OidIsValid, pfree(), and RenameTypeInternal().

Referenced by DefineCompositeType(), DefineDomain(), DefineEnum(), DefineRange(), DefineType(), heap_create_with_catalog(), and RenameTypeInternal().

851 {
852  Oid elemOid;
853  char *newname;
854 
855  /* We need do nothing if it's a shell type. */
856  if (!get_typisdefined(typeOid))
857  return true;
858 
859  /* Can't change it if it's not an autogenerated array type. */
860  elemOid = get_element_type(typeOid);
861  if (!OidIsValid(elemOid) ||
862  get_array_type(elemOid) != typeOid)
863  return false;
864 
865  /*
866  * OK, use makeArrayTypeName to pick an unused modification of the name.
867  * Note that since makeArrayTypeName is an iterative process, this will
868  * produce a name that it might have produced the first time, had the
869  * conflicting type we are about to create already existed.
870  */
871  newname = makeArrayTypeName(typeName, typeNamespace);
872 
873  /* Apply the rename */
874  RenameTypeInternal(typeOid, newname, typeNamespace);
875 
876  /*
877  * We must bump the command counter so that any subsequent use of
878  * makeArrayTypeName sees what we just did and doesn't pick the same name.
879  */
881 
882  pfree(newname);
883 
884  return true;
885 }
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:784
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2526
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2554
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:1951
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:638
void pfree(void *pointer)
Definition: mcxt.c:1031
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:709
void CommandCounterIncrement(void)
Definition: xact.c:1003

◆ RenameTypeInternal()

void RenameTypeInternal ( Oid  typeOid,
const char *  newTypeName,
Oid  typeNamespace 
)

Definition at line 709 of file pg_type.c.

References Assert, CatalogTupleUpdate(), CStringGetDatum, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, get_typisdefined(), GETSTRUCT, GetSysCacheOid2, heap_freetuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, makeArrayTypeName(), moveArrayTypeName(), namestrcpy(), ObjectIdGetDatum, OidIsValid, pfree(), RenameTypeInternal(), RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), table_open(), TYPENAMENSP, and TYPEOID.

Referenced by moveArrayTypeName(), RenameRelationInternal(), RenameType(), and RenameTypeInternal().

710 {
711  Relation pg_type_desc;
712  HeapTuple tuple;
713  Form_pg_type typ;
714  Oid arrayOid;
715  Oid oldTypeOid;
716 
717  pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
718 
719  tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
720  if (!HeapTupleIsValid(tuple))
721  elog(ERROR, "cache lookup failed for type %u", typeOid);
722  typ = (Form_pg_type) GETSTRUCT(tuple);
723 
724  /* We are not supposed to be changing schemas here */
725  Assert(typeNamespace == typ->typnamespace);
726 
727  arrayOid = typ->typarray;
728 
729  /* Check for a conflicting type name. */
730  oldTypeOid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
731  CStringGetDatum(newTypeName),
732  ObjectIdGetDatum(typeNamespace));
733 
734  /*
735  * If there is one, see if it's an autogenerated array type, and if so
736  * rename it out of the way. (But we must skip that for a shell type
737  * because moveArrayTypeName will do the wrong thing in that case.)
738  * Otherwise, we can at least give a more friendly error than unique-index
739  * violation.
740  */
741  if (OidIsValid(oldTypeOid))
742  {
743  if (get_typisdefined(oldTypeOid) &&
744  moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace))
745  /* successfully dodged the problem */ ;
746  else
747  ereport(ERROR,
749  errmsg("type \"%s\" already exists", newTypeName)));
750  }
751 
752  /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
753  namestrcpy(&(typ->typname), newTypeName);
754 
755  CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple);
756 
757  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
758 
759  heap_freetuple(tuple);
760  table_close(pg_type_desc, RowExclusiveLock);
761 
762  /*
763  * If the type has an array type, recurse to handle that. But we don't
764  * need to do anything more if we already renamed that array type above
765  * (which would happen when, eg, renaming "foo" to "_foo").
766  */
767  if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
768  {
769  char *arrname = makeArrayTypeName(newTypeName, typeNamespace);
770 
771  RenameTypeInternal(arrayOid, arrname, typeNamespace);
772  pfree(arrname);
773  }
774 }
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:784
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:1951
int errcode(int sqlerrcode)
Definition: elog.c:570
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:250
#define OidIsValid(objectId)
Definition: c.h:638
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:850
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:709
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:194
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_type * Form_pg_type
Definition: pg_type.h:251
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33

◆ TypeCreate()

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 at line 192 of file pg_type.c.

References aclcheck_error(), ACLCHECK_NOT_OWNER, binary_upgrade_next_pg_type_oid, BoolGetDatum, CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum, CStringGetDatum, CStringGetTextDatum, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, GenerateTypeDependencies(), get_user_default_acl(), GetNewOidWithIndex(), GETSTRUCT, heap_form_tuple(), heap_modify_tuple(), HeapTupleIsValid, i, Int16GetDatum, Int32GetDatum, InvalidOid, InvokeObjectPostCreateHook, IsBinaryUpgrade, IsBootstrapProcessingMode, name, NameGetDatum, namestrcpy(), OBJECT_TYPE, ObjectAddressSet, ObjectIdGetDatum, OidIsValid, PointerGetDatum, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy2, stringToNode(), HeapTupleData::t_self, table_close(), table_open(), TYPENAMENSP, TypeOidIndexId, and values.

Referenced by AddNewRelationType(), DefineDomain(), DefineEnum(), DefineRange(), DefineType(), and heap_create_with_catalog().

223 {
224  Relation pg_type_desc;
225  Oid typeObjectId;
226  bool isDependentType;
227  bool rebuildDeps = false;
228  Acl *typacl;
229  HeapTuple tup;
230  bool nulls[Natts_pg_type];
231  bool replaces[Natts_pg_type];
232  Datum values[Natts_pg_type];
233  NameData name;
234  int i;
235  ObjectAddress address;
236 
237  /*
238  * We assume that the caller validated the arguments individually, but did
239  * not check for bad combinations.
240  *
241  * Validate size specifications: either positive (fixed-length) or -1
242  * (varlena) or -2 (cstring).
243  */
244  if (!(internalSize > 0 ||
245  internalSize == -1 ||
246  internalSize == -2))
247  ereport(ERROR,
248  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
249  errmsg("invalid type internal size %d",
250  internalSize)));
251 
252  if (passedByValue)
253  {
254  /*
255  * Pass-by-value types must have a fixed length that is one of the
256  * values supported by fetch_att() and store_att_byval(); and the
257  * alignment had better agree, too. All this code must match
258  * access/tupmacs.h!
259  */
260  if (internalSize == (int16) sizeof(char))
261  {
262  if (alignment != 'c')
263  ereport(ERROR,
264  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
265  errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
266  alignment, internalSize)));
267  }
268  else if (internalSize == (int16) sizeof(int16))
269  {
270  if (alignment != 's')
271  ereport(ERROR,
272  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
273  errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
274  alignment, internalSize)));
275  }
276  else if (internalSize == (int16) sizeof(int32))
277  {
278  if (alignment != 'i')
279  ereport(ERROR,
280  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
281  errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
282  alignment, internalSize)));
283  }
284 #if SIZEOF_DATUM == 8
285  else if (internalSize == (int16) sizeof(Datum))
286  {
287  if (alignment != 'd')
288  ereport(ERROR,
289  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
290  errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
291  alignment, internalSize)));
292  }
293 #endif
294  else
295  ereport(ERROR,
296  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
297  errmsg("internal size %d is invalid for passed-by-value type",
298  internalSize)));
299  }
300  else
301  {
302  /* varlena types must have int align or better */
303  if (internalSize == -1 && !(alignment == 'i' || alignment == 'd'))
304  ereport(ERROR,
305  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
306  errmsg("alignment \"%c\" is invalid for variable-length type",
307  alignment)));
308  /* cstring must have char alignment */
309  if (internalSize == -2 && !(alignment == 'c'))
310  ereport(ERROR,
311  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
312  errmsg("alignment \"%c\" is invalid for variable-length type",
313  alignment)));
314  }
315 
316  /* Only varlena types can be toasted */
317  if (storage != 'p' && internalSize != -1)
318  ereport(ERROR,
319  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
320  errmsg("fixed-size types must have storage PLAIN")));
321 
322  /*
323  * This is a dependent type if it's an implicitly-created array type, or
324  * if it's a relation rowtype that's not a composite type. For such types
325  * we'll leave the ACL empty, and we'll skip creating some dependency
326  * records because there will be a dependency already through the
327  * depended-on type or relation. (Caution: this is closely intertwined
328  * with some behavior in GenerateTypeDependencies.)
329  */
330  isDependentType = isImplicitArray ||
331  (OidIsValid(relationOid) && relationKind != RELKIND_COMPOSITE_TYPE);
332 
333  /*
334  * initialize arrays needed for heap_form_tuple or heap_modify_tuple
335  */
336  for (i = 0; i < Natts_pg_type; ++i)
337  {
338  nulls[i] = false;
339  replaces[i] = true;
340  values[i] = (Datum) 0;
341  }
342 
343  /*
344  * insert data values
345  */
346  namestrcpy(&name, typeName);
347  values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
348  values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
349  values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
350  values[Anum_pg_type_typlen - 1] = Int16GetDatum(internalSize);
351  values[Anum_pg_type_typbyval - 1] = BoolGetDatum(passedByValue);
352  values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType);
353  values[Anum_pg_type_typcategory - 1] = CharGetDatum(typeCategory);
354  values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(typePreferred);
355  values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(true);
356  values[Anum_pg_type_typdelim - 1] = CharGetDatum(typDelim);
357  values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(relationOid);
358  values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(elementType);
359  values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(arrayType);
360  values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(inputProcedure);
361  values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(outputProcedure);
362  values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(receiveProcedure);
363  values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(sendProcedure);
364  values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(typmodinProcedure);
365  values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(typmodoutProcedure);
366  values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(analyzeProcedure);
367  values[Anum_pg_type_typalign - 1] = CharGetDatum(alignment);
368  values[Anum_pg_type_typstorage - 1] = CharGetDatum(storage);
369  values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(typeNotNull);
370  values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(baseType);
371  values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod);
372  values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims);
373  values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation);
374 
375  /*
376  * initialize the default binary value for this type. Check for nulls of
377  * course.
378  */
379  if (defaultTypeBin)
380  values[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(defaultTypeBin);
381  else
382  nulls[Anum_pg_type_typdefaultbin - 1] = true;
383 
384  /*
385  * initialize the default value for this type.
386  */
387  if (defaultTypeValue)
388  values[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultTypeValue);
389  else
390  nulls[Anum_pg_type_typdefault - 1] = true;
391 
392  /*
393  * Initialize the type's ACL, too. But dependent types don't get one.
394  */
395  if (isDependentType)
396  typacl = NULL;
397  else
398  typacl = get_user_default_acl(OBJECT_TYPE, ownerId,
399  typeNamespace);
400  if (typacl != NULL)
401  values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
402  else
403  nulls[Anum_pg_type_typacl - 1] = true;
404 
405  /*
406  * open pg_type and prepare to insert or update a row.
407  *
408  * NOTE: updating will not work correctly in bootstrap mode; but we don't
409  * expect to be overwriting any shell types in bootstrap mode.
410  */
411  pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
412 
414  CStringGetDatum(typeName),
415  ObjectIdGetDatum(typeNamespace));
416  if (HeapTupleIsValid(tup))
417  {
418  Form_pg_type typform = (Form_pg_type) GETSTRUCT(tup);
419 
420  /*
421  * check that the type is not already defined. It may exist as a
422  * shell type, however.
423  */
424  if (typform->typisdefined)
425  ereport(ERROR,
427  errmsg("type \"%s\" already exists", typeName)));
428 
429  /*
430  * shell type must have been created by same owner
431  */
432  if (typform->typowner != ownerId)
434 
435  /* trouble if caller wanted to force the OID */
436  if (OidIsValid(newTypeOid))
437  elog(ERROR, "cannot assign new OID to existing shell type");
438 
439  replaces[Anum_pg_type_oid - 1] = false;
440 
441  /*
442  * Okay to update existing shell type tuple
443  */
444  tup = heap_modify_tuple(tup,
445  RelationGetDescr(pg_type_desc),
446  values,
447  nulls,
448  replaces);
449 
450  CatalogTupleUpdate(pg_type_desc, &tup->t_self, tup);
451 
452  typeObjectId = typform->oid;
453 
454  rebuildDeps = true; /* get rid of shell type's dependencies */
455  }
456  else
457  {
458  /* Force the OID if requested by caller */
459  if (OidIsValid(newTypeOid))
460  typeObjectId = newTypeOid;
461  /* Use binary-upgrade override for pg_type.oid, if supplied. */
462  else if (IsBinaryUpgrade)
463  {
465  ereport(ERROR,
466  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
467  errmsg("pg_type OID value not set when in binary upgrade mode")));
468 
469  typeObjectId = binary_upgrade_next_pg_type_oid;
471  }
472  else
473  {
474  typeObjectId = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
475  Anum_pg_type_oid);
476  }
477 
478  values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typeObjectId);
479 
480  tup = heap_form_tuple(RelationGetDescr(pg_type_desc),
481  values, nulls);
482 
483  CatalogTupleInsert(pg_type_desc, tup);
484  }
485 
486  /*
487  * Create dependencies. We can/must skip this in bootstrap mode.
488  */
490  GenerateTypeDependencies(typeObjectId,
491  (Form_pg_type) GETSTRUCT(tup),
492  (defaultTypeBin ?
493  stringToNode(defaultTypeBin) :
494  NULL),
495  typacl,
496  relationKind,
497  isImplicitArray,
498  isDependentType,
499  rebuildDeps);
500 
501  /* Post creation hook for new type */
502  InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
503 
504  ObjectAddressSet(address, TypeRelationId, typeObjectId);
505 
506  /*
507  * finish up
508  */
509  table_close(pg_type_desc, RowExclusiveLock);
510 
511  return address;
512 }
signed short int16
Definition: c.h:345
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:323
#define NameGetDatum(X)
Definition: postgres.h:595
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
#define RelationGetDescr(relation)
Definition: rel.h:442
#define PointerGetDatum(X)
Definition: postgres.h:556
#define Int16GetDatum(X)
Definition: postgres.h:451
int errcode(int sqlerrcode)
Definition: elog.c:570
void * stringToNode(const char *str)
Definition: read.c:89
void GenerateTypeDependencies(Oid typeObjectId, Form_pg_type typeForm, Node *defaultExpr, void *typacl, char relationKind, bool isImplicitArray, bool isDependentType, bool rebuild)
Definition: pg_type.c:537
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:250
#define OidIsValid(objectId)
Definition: c.h:638
bool IsBinaryUpgrade
Definition: globals.c:110
signed int int32
Definition: c.h:346
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3353
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Definition: c.h:603
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel, rest)
Definition: elog.h:141
Oid binary_upgrade_next_pg_type_oid
Definition: pg_type.c:40
uintptr_t Datum
Definition: postgres.h:367
#define BoolGetDatum(X)
Definition: postgres.h:402
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_type * Form_pg_type
Definition: pg_type.h:251
const char * name
Definition: encode.c:521
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define CharGetDatum(X)
Definition: postgres.h:416
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:374
#define Int32GetDatum(X)
Definition: postgres.h:479
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:83
#define SearchSysCacheCopy2(cacheId, key1, key2)
Definition: syscache.h:176
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
#define TypeOidIndexId
Definition: indexing.h:289
Acl * get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
Definition: aclchk.c:5458

◆ TypeShellMake()

ObjectAddress TypeShellMake ( const char *  typeName,
Oid  typeNamespace,
Oid  ownerId 
)

Definition at line 56 of file pg_type.c.

References Assert, binary_upgrade_next_pg_type_oid, BoolGetDatum, CatalogTupleInsert(), CharGetDatum, DEFAULT_TYPDELIM, ereport, errcode(), errmsg(), ERROR, GenerateTypeDependencies(), GetNewOidWithIndex(), GETSTRUCT, heap_form_tuple(), heap_freetuple(), i, Int16GetDatum, Int32GetDatum, InvalidOid, InvokeObjectPostCreateHook, IsBinaryUpgrade, IsBootstrapProcessingMode, name, NameGetDatum, namestrcpy(), ObjectAddressSet, ObjectIdGetDatum, OidIsValid, PointerIsValid, RelationData::rd_att, RowExclusiveLock, table_close(), table_open(), TypeOidIndexId, and values.

Referenced by compute_return_type(), DefineRange(), and DefineType().

57 {
58  Relation pg_type_desc;
59  TupleDesc tupDesc;
60  int i;
61  HeapTuple tup;
62  Datum values[Natts_pg_type];
63  bool nulls[Natts_pg_type];
64  Oid typoid;
65  NameData name;
66  ObjectAddress address;
67 
68  Assert(PointerIsValid(typeName));
69 
70  /*
71  * open pg_type
72  */
73  pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
74  tupDesc = pg_type_desc->rd_att;
75 
76  /*
77  * initialize our *nulls and *values arrays
78  */
79  for (i = 0; i < Natts_pg_type; ++i)
80  {
81  nulls[i] = false;
82  values[i] = (Datum) NULL; /* redundant, but safe */
83  }
84 
85  /*
86  * initialize *values with the type name and dummy values
87  *
88  * The representational details are the same as int4 ... it doesn't really
89  * matter what they are so long as they are consistent. Also note that we
90  * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
91  * mistaken for a usable type.
92  */
93  namestrcpy(&name, typeName);
94  values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
95  values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
96  values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
97  values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32));
98  values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true);
99  values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO);
100  values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE);
101  values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false);
102  values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false);
103  values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM);
104  values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid);
105  values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid);
106  values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid);
107  values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN);
108  values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT);
109  values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid);
110  values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid);
111  values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid);
112  values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid);
113  values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid);
114  values[Anum_pg_type_typalign - 1] = CharGetDatum('i');
115  values[Anum_pg_type_typstorage - 1] = CharGetDatum('p');
116  values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false);
117  values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid);
118  values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
119  values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
120  values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
121  nulls[Anum_pg_type_typdefaultbin - 1] = true;
122  nulls[Anum_pg_type_typdefault - 1] = true;
123  nulls[Anum_pg_type_typacl - 1] = true;
124 
125  /* Use binary-upgrade override for pg_type.oid? */
126  if (IsBinaryUpgrade)
127  {
129  ereport(ERROR,
130  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
131  errmsg("pg_type OID value not set when in binary upgrade mode")));
132 
135  }
136  else
137  {
138  typoid = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
139  Anum_pg_type_oid);
140  }
141 
142  values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typoid);
143 
144  /*
145  * create a new type tuple
146  */
147  tup = heap_form_tuple(tupDesc, values, nulls);
148 
149  /*
150  * insert the tuple in the relation and get the tuple's oid.
151  */
152  CatalogTupleInsert(pg_type_desc, tup);
153 
154  /*
155  * Create dependencies. We can/must skip this in bootstrap mode.
156  */
159  (Form_pg_type) GETSTRUCT(tup),
160  NULL,
161  NULL,
162  0,
163  false,
164  false,
165  false);
166 
167  /* Post creation hook for new shell type */
168  InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
169 
170  ObjectAddressSet(address, TypeRelationId, typoid);
171 
172  /*
173  * clean up and return the type-oid
174  */
175  heap_freetuple(tup);
176  table_close(pg_type_desc, RowExclusiveLock);
177 
178  return address;
179 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:323
#define NameGetDatum(X)
Definition: postgres.h:595
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
#define Int16GetDatum(X)
Definition: postgres.h:451
int errcode(int sqlerrcode)
Definition: elog.c:570
void GenerateTypeDependencies(Oid typeObjectId, Form_pg_type typeForm, Node *defaultExpr, void *typacl, char relationKind, bool isImplicitArray, bool isDependentType, bool rebuild)
Definition: pg_type.c:537
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:250
#define OidIsValid(objectId)
Definition: c.h:638
bool IsBinaryUpgrade
Definition: globals.c:110
signed int int32
Definition: c.h:346
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Definition: c.h:603
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ereport(elevel, rest)
Definition: elog.h:141
Oid binary_upgrade_next_pg_type_oid
Definition: pg_type.c:40
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:84
#define BoolGetDatum(X)
Definition: postgres.h:402
#define InvalidOid
Definition: postgres_ext.h:36
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22
#define Assert(condition)
Definition: c.h:732
FormData_pg_type * Form_pg_type
Definition: pg_type.h:251
const char * name
Definition: encode.c:521
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define CharGetDatum(X)
Definition: postgres.h:416
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:374
#define Int32GetDatum(X)
Definition: postgres.h:479
int errmsg(const char *fmt,...)
Definition: elog.c:784
int i
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define PointerIsValid(pointer)
Definition: c.h:626
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
#define TypeOidIndexId
Definition: indexing.h:289

Variable Documentation

◆ binary_upgrade_next_pg_type_oid

Oid binary_upgrade_next_pg_type_oid = InvalidOid

Definition at line 40 of file pg_type.c.

Referenced by binary_upgrade_set_next_pg_type_oid(), TypeCreate(), and TypeShellMake().