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/binary_upgrade.h"
#include "catalog/catalog.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/defrem.h"
#include "commands/typecmds.h"
#include "mb/pg_wchar.h"
#include "miscadmin.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 subscriptProcedure, 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 (HeapTuple typeTuple, Relation typeCatalog, Node *defaultExpr, void *typacl, char relationKind, bool isImplicitArray, bool isDependentType, bool makeExtensionDep, 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)
 
char * makeMultirangeTypeName (const char *rangeTypeName, Oid typeNamespace)
 

Variables

Oid binary_upgrade_next_pg_type_oid = InvalidOid
 

Function Documentation

◆ GenerateTypeDependencies()

void GenerateTypeDependencies ( HeapTuple  typeTuple,
Relation  typeCatalog,
Node defaultExpr,
void *  typacl,
char  relationKind,
bool  isImplicitArray,
bool  isDependentType,
bool  makeExtensionDep,
bool  rebuild 
)

Definition at line 557 of file pg_type.c.

566 {
567  Form_pg_type typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
568  Oid typeObjectId = typeForm->oid;
569  Datum datum;
570  bool isNull;
571  ObjectAddress myself,
572  referenced;
573  ObjectAddresses *addrs_normal;
574 
575  /* Extract defaultExpr if caller didn't pass it */
576  if (defaultExpr == NULL)
577  {
578  datum = heap_getattr(typeTuple, Anum_pg_type_typdefaultbin,
579  RelationGetDescr(typeCatalog), &isNull);
580  if (!isNull)
581  defaultExpr = stringToNode(TextDatumGetCString(datum));
582  }
583  /* Extract typacl if caller didn't pass it */
584  if (typacl == NULL)
585  {
586  datum = heap_getattr(typeTuple, Anum_pg_type_typacl,
587  RelationGetDescr(typeCatalog), &isNull);
588  if (!isNull)
589  typacl = DatumGetAclPCopy(datum);
590  }
591 
592  /* If rebuild, first flush old dependencies, except extension deps */
593  if (rebuild)
594  {
595  deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true);
596  deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
597  }
598 
599  ObjectAddressSet(myself, TypeRelationId, typeObjectId);
600 
601  /*
602  * Make dependencies on namespace, owner, ACL.
603  *
604  * Skip these for a dependent type, since it will have such dependencies
605  * indirectly through its depended-on type or relation. An exception is
606  * that multiranges need their own namespace dependency, since we don't
607  * force them to be in the same schema as their range type.
608  */
609 
610  /* collects normal dependencies for bulk recording */
611  addrs_normal = new_object_addresses();
612 
613  if (!isDependentType || typeForm->typtype == TYPTYPE_MULTIRANGE)
614  {
615  ObjectAddressSet(referenced, NamespaceRelationId,
616  typeForm->typnamespace);
617  add_exact_object_address(&referenced, addrs_normal);
618  }
619 
620  if (!isDependentType)
621  {
622  recordDependencyOnOwner(TypeRelationId, typeObjectId,
623  typeForm->typowner);
624 
625  recordDependencyOnNewAcl(TypeRelationId, typeObjectId, 0,
626  typeForm->typowner, typacl);
627  }
628 
629  /*
630  * Make extension dependency if requested.
631  *
632  * We used to skip this for dependent types, but it seems better to record
633  * their extension membership explicitly; otherwise code such as
634  * postgres_fdw's shippability test will be fooled.
635  */
636  if (makeExtensionDep)
637  recordDependencyOnCurrentExtension(&myself, rebuild);
638 
639  /* Normal dependencies on the I/O and support functions */
640  if (OidIsValid(typeForm->typinput))
641  {
642  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typinput);
643  add_exact_object_address(&referenced, addrs_normal);
644  }
645 
646  if (OidIsValid(typeForm->typoutput))
647  {
648  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typoutput);
649  add_exact_object_address(&referenced, addrs_normal);
650  }
651 
652  if (OidIsValid(typeForm->typreceive))
653  {
654  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typreceive);
655  add_exact_object_address(&referenced, addrs_normal);
656  }
657 
658  if (OidIsValid(typeForm->typsend))
659  {
660  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsend);
661  add_exact_object_address(&referenced, addrs_normal);
662  }
663 
664  if (OidIsValid(typeForm->typmodin))
665  {
666  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodin);
667  add_exact_object_address(&referenced, addrs_normal);
668  }
669 
670  if (OidIsValid(typeForm->typmodout))
671  {
672  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodout);
673  add_exact_object_address(&referenced, addrs_normal);
674  }
675 
676  if (OidIsValid(typeForm->typanalyze))
677  {
678  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typanalyze);
679  add_exact_object_address(&referenced, addrs_normal);
680  }
681 
682  if (OidIsValid(typeForm->typsubscript))
683  {
684  ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsubscript);
685  add_exact_object_address(&referenced, addrs_normal);
686  }
687 
688  /* Normal dependency from a domain to its base type. */
689  if (OidIsValid(typeForm->typbasetype))
690  {
691  ObjectAddressSet(referenced, TypeRelationId, typeForm->typbasetype);
692  add_exact_object_address(&referenced, addrs_normal);
693  }
694 
695  /*
696  * Normal dependency from a domain to its collation. We know the default
697  * collation is pinned, so don't bother recording it.
698  */
699  if (OidIsValid(typeForm->typcollation) &&
700  typeForm->typcollation != DEFAULT_COLLATION_OID)
701  {
702  ObjectAddressSet(referenced, CollationRelationId, typeForm->typcollation);
703  add_exact_object_address(&referenced, addrs_normal);
704  }
705 
707  free_object_addresses(addrs_normal);
708 
709  /* Normal dependency on the default expression. */
710  if (defaultExpr)
711  recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
712 
713  /*
714  * If the type is a rowtype for a relation, mark it as internally
715  * dependent on the relation, *unless* it is a stand-alone composite type
716  * relation. For the latter case, we have to reverse the dependency.
717  *
718  * In the former case, this allows the type to be auto-dropped when the
719  * relation is, and not otherwise. And in the latter, of course we get the
720  * opposite effect.
721  */
722  if (OidIsValid(typeForm->typrelid))
723  {
724  ObjectAddressSet(referenced, RelationRelationId, typeForm->typrelid);
725 
726  if (relationKind != RELKIND_COMPOSITE_TYPE)
727  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
728  else
729  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
730  }
731 
732  /*
733  * If the type is an implicitly-created array type, mark it as internally
734  * dependent on the element type. Otherwise, if it has an element type,
735  * the dependency is a normal one.
736  */
737  if (OidIsValid(typeForm->typelem))
738  {
739  ObjectAddressSet(referenced, TypeRelationId, typeForm->typelem);
740  recordDependencyOn(&myself, &referenced,
741  isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
742  }
743 
744  /*
745  * Note: you might expect that we should record an internal dependency of
746  * a multirange on its range type here, by analogy with the cases above.
747  * But instead, that is done by RangeCreate(), which also handles
748  * recording of other range-type-specific dependencies. That's pretty
749  * bogus. It's okay for now, because there are no cases where we need to
750  * regenerate the dependencies of a range or multirange type. But someday
751  * we might need to move that logic here to allow such regeneration.
752  */
753 }
#define DatumGetAclPCopy(X)
Definition: acl.h:121
void recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, Acl *acl)
Definition: aclchk.c:4365
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define OidIsValid(objectId)
Definition: c.h:762
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2738
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1553
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2483
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2529
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2769
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:300
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:192
#define NIL
Definition: pg_list.h:68
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:997
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:160
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
uintptr_t Datum
Definition: postgres.h:64
unsigned int Oid
Definition: postgres_ext.h:31
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationGetDescr(relation)
Definition: rel.h:531

References add_exact_object_address(), DatumGetAclPCopy, deleteDependencyRecordsFor(), deleteSharedDependencyRecordsFor(), DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, free_object_addresses(), GETSTRUCT, heap_getattr(), new_object_addresses(), NIL, ObjectAddressSet, OidIsValid, record_object_address_dependencies(), recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnExpr(), recordDependencyOnNewAcl(), recordDependencyOnOwner(), RelationGetDescr, stringToNode(), and TextDatumGetCString.

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

◆ makeArrayTypeName()

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

Definition at line 840 of file pg_type.c.

841 {
842  char *arr_name;
843  int pass = 0;
844  char suffix[NAMEDATALEN];
845 
846  /*
847  * Per ancient Postgres tradition, array type names are made by prepending
848  * an underscore to the base type name. Much client code knows that
849  * convention, so don't muck with it. However, the tradition is less
850  * clear about what to do in the corner cases where the resulting name is
851  * too long or conflicts with an existing name. Our current rules are (1)
852  * truncate the base name on the right as needed, and (2) if there is a
853  * conflict, append another underscore and some digits chosen to make it
854  * unique. This is similar to what ChooseRelationName() does.
855  *
856  * The actual name generation can be farmed out to makeObjectName() by
857  * giving it an empty first name component.
858  */
859 
860  /* First, try with no numeric suffix */
861  arr_name = makeObjectName("", typeName, NULL);
862 
863  for (;;)
864  {
865  if (!SearchSysCacheExists2(TYPENAMENSP,
866  CStringGetDatum(arr_name),
867  ObjectIdGetDatum(typeNamespace)))
868  break;
869 
870  /* That attempt conflicted. Prepare a new name with some digits. */
871  pfree(arr_name);
872  snprintf(suffix, sizeof(suffix), "%d", ++pass);
873  arr_name = makeObjectName("", typeName, suffix);
874  }
875 
876  return arr_name;
877 }
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2524
void pfree(void *pointer)
Definition: mcxt.c:1508
#define NAMEDATALEN
#define snprintf
Definition: port.h:238
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:97

References CStringGetDatum(), makeObjectName(), NAMEDATALEN, ObjectIdGetDatum(), pfree(), SearchSysCacheExists2, and snprintf.

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

◆ makeMultirangeTypeName()

char* makeMultirangeTypeName ( const char *  rangeTypeName,
Oid  typeNamespace 
)

Definition at line 950 of file pg_type.c.

951 {
952  char *buf;
953  char *rangestr;
954 
955  /*
956  * If the range type name contains "range" then change that to
957  * "multirange". Otherwise add "_multirange" to the end.
958  */
959  rangestr = strstr(rangeTypeName, "range");
960  if (rangestr)
961  {
962  char *prefix = pnstrdup(rangeTypeName, rangestr - rangeTypeName);
963 
964  buf = psprintf("%s%s%s", prefix, "multi", rangestr);
965  }
966  else
967  buf = psprintf("%s_multirange", pnstrdup(rangeTypeName, NAMEDATALEN - 12));
968 
969  /* clip it at NAMEDATALEN-1 bytes */
970  buf[pg_mbcliplen(buf, strlen(buf), NAMEDATALEN - 1)] = '\0';
971 
972  if (SearchSysCacheExists2(TYPENAMENSP,
974  ObjectIdGetDatum(typeNamespace)))
975  ereport(ERROR,
977  errmsg("type \"%s\" already exists", buf),
978  errdetail("Failed while creating a multirange type for type \"%s\".", rangeTypeName),
979  errhint("You can manually specify a multirange type name using the \"multirange_type_name\" attribute.")));
980 
981  return pstrdup(buf);
982 }
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1083
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1694
char * pstrdup(const char *in)
Definition: mcxt.c:1683
static char * buf
Definition: pg_test_fsync.c:73
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32

References buf, CStringGetDatum(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errhint(), errmsg(), ERROR, NAMEDATALEN, ObjectIdGetDatum(), pg_mbcliplen(), pnstrdup(), psprintf(), pstrdup(), and SearchSysCacheExists2.

Referenced by DefineRange().

◆ moveArrayTypeName()

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

Definition at line 905 of file pg_type.c.

906 {
907  Oid elemOid;
908  char *newname;
909 
910  /* We need do nothing if it's a shell type. */
911  if (!get_typisdefined(typeOid))
912  return true;
913 
914  /* Can't change it if it's not an autogenerated array type. */
915  elemOid = get_element_type(typeOid);
916  if (!OidIsValid(elemOid) ||
917  get_array_type(elemOid) != typeOid)
918  return false;
919 
920  /*
921  * OK, use makeArrayTypeName to pick an unused modification of the name.
922  * Note that since makeArrayTypeName is an iterative process, this will
923  * produce a name that it might have produced the first time, had the
924  * conflicting type we are about to create already existed.
925  */
926  newname = makeArrayTypeName(typeName, typeNamespace);
927 
928  /* Apply the rename */
929  RenameTypeInternal(typeOid, newname, typeNamespace);
930 
931  /*
932  * We must bump the command counter so that any subsequent use of
933  * makeArrayTypeName sees what we just did and doesn't pick the same name.
934  */
936 
937  pfree(newname);
938 
939  return true;
940 }
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2715
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:2129
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2743
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:765
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:840
void CommandCounterIncrement(void)
Definition: xact.c:1079

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().

◆ RenameTypeInternal()

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

Definition at line 765 of file pg_type.c.

766 {
767  Relation pg_type_desc;
768  HeapTuple tuple;
769  Form_pg_type typ;
770  Oid arrayOid;
771  Oid oldTypeOid;
772 
773  pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
774 
775  tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
776  if (!HeapTupleIsValid(tuple))
777  elog(ERROR, "cache lookup failed for type %u", typeOid);
778  typ = (Form_pg_type) GETSTRUCT(tuple);
779 
780  /* We are not supposed to be changing schemas here */
781  Assert(typeNamespace == typ->typnamespace);
782 
783  arrayOid = typ->typarray;
784 
785  /* Check for a conflicting type name. */
786  oldTypeOid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
787  CStringGetDatum(newTypeName),
788  ObjectIdGetDatum(typeNamespace));
789 
790  /*
791  * If there is one, see if it's an autogenerated array type, and if so
792  * rename it out of the way. (But we must skip that for a shell type
793  * because moveArrayTypeName will do the wrong thing in that case.)
794  * Otherwise, we can at least give a more friendly error than unique-index
795  * violation.
796  */
797  if (OidIsValid(oldTypeOid))
798  {
799  if (get_typisdefined(oldTypeOid) &&
800  moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace))
801  /* successfully dodged the problem */ ;
802  else
803  ereport(ERROR,
805  errmsg("type \"%s\" already exists", newTypeName)));
806  }
807 
808  /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
809  namestrcpy(&(typ->typname), newTypeName);
810 
811  CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple);
812 
813  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
814 
815  heap_freetuple(tuple);
816  table_close(pg_type_desc, RowExclusiveLock);
817 
818  /*
819  * If the type has an array type, recurse to handle that. But we don't
820  * need to do anything more if we already renamed that array type above
821  * (which would happen when, eg, renaming "foo" to "_foo").
822  */
823  if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
824  {
825  char *arrname = makeArrayTypeName(newTypeName, typeNamespace);
826 
827  RenameTypeInternal(arrayOid, arrname, typeNamespace);
828  pfree(arrname);
829  }
830 }
#define elog(elevel,...)
Definition: elog.h:224
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
Assert(fmt[strlen(fmt) - 1] !='\n')
#define RowExclusiveLock
Definition: lockdefs.h:38
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:905
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:106
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

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(), RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

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

◆ 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  subscriptProcedure,
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 195 of file pg_type.c.

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

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, storage, stringToNode(), HeapTupleData::t_self, table_close(), table_open(), and values.

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

◆ TypeShellMake()

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

Definition at line 57 of file pg_type.c.

58 {
59  Relation pg_type_desc;
60  TupleDesc tupDesc;
61  int i;
62  HeapTuple tup;
63  Datum values[Natts_pg_type];
64  bool nulls[Natts_pg_type];
65  Oid typoid;
66  NameData name;
67  ObjectAddress address;
68 
69  Assert(PointerIsValid(typeName));
70 
71  /*
72  * open pg_type
73  */
74  pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
75  tupDesc = pg_type_desc->rd_att;
76 
77  /*
78  * initialize our *nulls and *values arrays
79  */
80  for (i = 0; i < Natts_pg_type; ++i)
81  {
82  nulls[i] = false;
83  values[i] = (Datum) NULL; /* redundant, but safe */
84  }
85 
86  /*
87  * initialize *values with the type name and dummy values
88  *
89  * The representational details are the same as int4 ... it doesn't really
90  * matter what they are so long as they are consistent. Also note that we
91  * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
92  * mistaken for a usable type.
93  */
94  namestrcpy(&name, typeName);
95  values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
96  values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
97  values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
98  values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32));
99  values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true);
100  values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO);
101  values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE);
102  values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false);
103  values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false);
104  values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM);
105  values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid);
106  values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(InvalidOid);
107  values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid);
108  values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid);
109  values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN);
110  values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT);
111  values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid);
112  values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid);
113  values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid);
114  values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid);
115  values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid);
116  values[Anum_pg_type_typalign - 1] = CharGetDatum(TYPALIGN_INT);
117  values[Anum_pg_type_typstorage - 1] = CharGetDatum(TYPSTORAGE_PLAIN);
118  values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false);
119  values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid);
120  values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
121  values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
122  values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
123  nulls[Anum_pg_type_typdefaultbin - 1] = true;
124  nulls[Anum_pg_type_typdefault - 1] = true;
125  nulls[Anum_pg_type_typacl - 1] = true;
126 
127  /* Use binary-upgrade override for pg_type.oid? */
128  if (IsBinaryUpgrade)
129  {
131  ereport(ERROR,
132  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
133  errmsg("pg_type OID value not set when in binary upgrade mode")));
134 
137  }
138  else
139  {
140  typoid = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
141  Anum_pg_type_oid);
142  }
143 
144  values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typoid);
145 
146  /*
147  * create a new type tuple
148  */
149  tup = heap_form_tuple(tupDesc, values, nulls);
150 
151  /*
152  * insert the tuple in the relation and get the tuple's oid.
153  */
154  CatalogTupleInsert(pg_type_desc, tup);
155 
156  /*
157  * Create dependencies. We can/must skip this in bootstrap mode.
158  */
161  pg_type_desc,
162  NULL,
163  NULL,
164  0,
165  false,
166  false,
167  true, /* make extension dependency */
168  false);
169 
170  /* Post creation hook for new shell type */
171  InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
172 
173  ObjectAddressSet(address, TypeRelationId, typoid);
174 
175  /*
176  * clean up and return the type-oid
177  */
178  heap_freetuple(tup);
179  table_close(pg_type_desc, RowExclusiveLock);
180 
181  return address;
182 }
#define PointerIsValid(pointer)
Definition: c.h:750
TupleDesc rd_att
Definition: rel.h:112
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22

References Assert(), binary_upgrade_next_pg_type_oid, BoolGetDatum(), CatalogTupleInsert(), CharGetDatum(), DEFAULT_TYPDELIM, ereport, errcode(), errmsg(), ERROR, GenerateTypeDependencies(), GetNewOidWithIndex(), 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(), and values.

Referenced by compute_return_type(), and DefineType().

Variable Documentation

◆ binary_upgrade_next_pg_type_oid

Oid binary_upgrade_next_pg_type_oid = InvalidOid

Definition at line 41 of file pg_type.c.

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