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:4291
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define OidIsValid(objectId)
Definition: c.h:732
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2757
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1553
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2548
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2502
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2788
@ 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:45
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:301
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:193
#define NIL
Definition: pg_list.h:68
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:1047
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
uintptr_t Datum
Definition: postgres.h:69
unsigned int Oid
Definition: postgres_ext.h:32
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:2527
void pfree(void *pointer)
Definition: mcxt.c:1521
#define NAMEDATALEN
#define snprintf
Definition: port.h:238
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:102

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)))
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:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#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 * pstrdup(const char *in)
Definition: mcxt.c:1696
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1707
static char * buf
Definition: pg_test_fsync.c:72
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30

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:2759
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:2173
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2787
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:1099

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
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 Assert(condition)
Definition: c.h:815
#define elog(elevel,...)
Definition: elog.h:225
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
#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:91
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:111
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(), RenameTypeInternal(), RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

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

◆ 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];
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))
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)
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)
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)
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)
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
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))
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))
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)
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)
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 {
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:2622
Acl * get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
Definition: aclchk.c:4215
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
int16_t int16
Definition: c.h:483
int32_t int32
Definition: c.h:484
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
bool IsBinaryUpgrade
Definition: globals.c:120
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
#define storage
Definition: indent_codes.h:68
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
int i
Definition: isn.c:72
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:466
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
@ OBJECT_TYPE
Definition: parsenodes.h:2361
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:327
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:378
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define InvalidOid
Definition: postgres_ext.h:37
Definition: c.h:698
#define SearchSysCacheCopy2(cacheId, key1, key2)
Definition: syscache.h:93
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;
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 {
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:720
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().